Merge branch 'master' of github.com:indentlabs/notebook

This commit is contained in:
Andrew Brown 2020-10-15 00:50:52 -07:00
commit 4e76e21000
17 changed files with 251 additions and 239 deletions

View File

@ -1013,7 +1013,7 @@ GEM
multi_json (~> 1)
statsd-ruby (~> 1.1)
bcrypt (3.1.16)
better_errors (2.7.1)
better_errors (2.8.3)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
@ -1041,7 +1041,7 @@ GEM
cocoon (1.2.15)
codeclimate-test-reporter (1.0.9)
simplecov (<= 0.13)
coderay (1.1.2)
coderay (1.1.3)
coffee-rails (5.0.0)
coffee-script (>= 2.2.0)
railties (>= 5.2.0)

View File

@ -1,29 +0,0 @@
## This file is prepended with an underscore to ensure it comes alphabetically-first
## when application.js includes all JS files in the directory with require_tree.
## Here be dragons.
window.Notebook ||= {}
Notebook.init = ->
# Initialize MaterializeCSS stuff
M.AutoInit()
$('.sidenav').sidenav()
$('.quick-reference-sidenav').sidenav {
closeOnClick: true,
edge: 'right',
draggable: false
}
$('#recent-edits-sidenav').sidenav {
closeOnClick: true,
edge: 'right',
draggable: false
}
$('.slider').slider { height: 200, indicators: false }
$('.dropdown-trigger').dropdown { coverTrigger: false }
$('.tooltipped').tooltip { enterDelay: 50 }
$('.with-character-counter').characterCounter();
$('.materialboxed').materialbox();
# We're using $ -> here for document readiness, but if we ever use Turbolinks we'd want:
# $(document).on "turbolinks:load", ->
$ ->
Notebook.init()

View File

@ -0,0 +1,27 @@
//# This file is prepended with an underscore to ensure it comes alphabetically-first
//# when application.js includes all JS files in the directory with require_tree.
//# Here be dragons.
if (!window.Notebook) { window.Notebook = {}; }
Notebook.init = function() {
// Initialize MaterializeCSS stuff
M.AutoInit();
$('.sidenav').sidenav();
$('.quick-reference-sidenav').sidenav({
closeOnClick: true,
edge: 'right',
draggable: false
});
$('#recent-edits-sidenav').sidenav({
closeOnClick: true,
edge: 'right',
draggable: false
});
$('.slider').slider({ height: 200, indicators: false });
$('.dropdown-trigger').dropdown({ coverTrigger: false });
$('.tooltipped').tooltip({ enterDelay: 50 });
$('.with-character-counter').characterCounter();
$('.materialboxed').materialbox();
};
$(() => Notebook.init());

View File

@ -1,8 +0,0 @@
$ ->
# When a user clicks to remove a collaborator, we should remove them from the list of collaborators after the remote request finishes
$('a.js-remove-contributor[data-remote]').on 'ajax:success', (e, data, status, xhr) ->
# Remove the image from the UI
$(this).closest('.collection-item').fadeOut().remove() # todo use animate.css for something more fun
return

View File

@ -0,0 +1,5 @@
// When a user clicks to remove a collaborator, we should remove them from the list of collaborators after the remote request finishes
$('a.js-remove-contributor[data-remote]').on('ajax:success', function(e, data, status, xhr) {
// Remove the image from the UI
$(this).closest('.collection-item').fadeOut().remove(); // todo use animate.css for something more fun
});

View File

@ -1,117 +0,0 @@
class Notebook.DocumentEditor
constructor: (@el) ->
return unless @el.length > 0
window.editor = new MediumEditor('#editor',
targetBlank: true
autoLink: false
buttonLabels: 'fontawesome'
toolbar: buttons: [
'bold'
'italic'
'underline'
'strikethrough'
{
name: 'h1'
action: 'append-h2'
aria: 'header type 1'
tagNames: [ 'h2' ]
contentDefault: '<b>H1</b>'
classList: [ 'custom-class-h1' ]
attrs: 'data-custom-attr': 'attr-value-h1'
}
{
name: 'h2'
action: 'append-h3'
aria: 'header type 2'
tagNames: [ 'h3' ]
contentDefault: '<b>H2</b>'
classList: [ 'custom-class-h2' ]
attrs: 'data-custom-attr': 'attr-value-h2'
}
{
name: 'h3'
action: 'append-h4'
aria: 'header type 3'
tagNames: [ 'h4' ]
contentDefault: '<b>H3</b>'
classList: [ 'custom-class-h3' ]
attrs: 'data-custom-attr': 'attr-value-h3'
}
'justifyLeft'
'justifyCenter'
'justifyRight'
'justifyFull'
'orderedlist'
'unorderedlist'
'quote'
'anchor'
'removeFormat'
]
anchorPreview: hideDelay: 0
placeholder: text: 'Write as little or as much as you want!'
paste: forcePlainText: false)
# Autosave
autosave_event = null
last_autosave = null
autosave = ->
if autosave_event == null
console.log 'Queueing autosave'
$('.js-autosave-icon').addClass 'grey-text'
$('.js-autosave-icon').removeClass 'black-text'
$('.js-autosave-icon').removeClass 'red-text'
$('.js-autosave-status').text 'Saving changes...'
autosave_event = setTimeout((->
console.log 'Autosaving...'
$('.js-autosave-status').text 'Saving...'
autosave_event = null
# Do the autosave
last_autosave = $.ajax(
type: 'PATCH'
url: $('#editor').data('save-url'),
data: document:
title: $('#document_title').val()
body: $('#editor').html()
)
last_autosave.fail (jqXHR, textStatus) ->
$('.js-autosave-status').text 'There was a problem saving! We will try to save again, but please make sure you back up any changes.'
$('.js-autosave-status').addClass 'red-text'
$('.js-autosave-status').removeClass 'grey-text'
$('.js-autosave-status').removeClass 'black-text'
return
# Done!
$('.js-autosave-icon').addClass 'black-text'
$('.js-autosave-icon').removeClass 'grey-text'
$('.js-autosave-icon').removeClass 'red-text'
$('.js-autosave-status').text 'Saved!'
return
), 2500)
else
console.log 'Waiting for existing autosave'
return
editor.subscribe 'editableInput', autosave
$('#document_title').on 'change', autosave
$('#document_title').on 'keydown', autosave
$('.js-autosave-status').on 'click', autosave
# Allow entering `tab` into the editor
$(document).delegate '#editor', 'keydown', (e) ->
keyCode = e.keyCode or e.which
if keyCode == 9
e.preventDefault()
return
$ ->
new Notebook.DocumentEditor $("body.documents.edit")

View File

@ -0,0 +1,128 @@
Notebook.DocumentEditor = class DocumentEditor {
constructor(el) {
this.el = el;
if (!(this.el.length > 0)) { return; }
window.editor = new MediumEditor('#editor', {
targetBlank: true,
autoLink: false,
buttonLabels: 'fontawesome',
toolbar: { buttons: [
'bold',
'italic',
'underline',
'strikethrough',
{
name: 'h1',
action: 'append-h2',
aria: 'header type 1',
tagNames: [ 'h2' ],
contentDefault: '<b>H1</b>',
classList: [ 'custom-class-h1' ],
attrs: { 'data-custom-attr': 'attr-value-h1'
}
},
{
name: 'h2',
action: 'append-h3',
aria: 'header type 2',
tagNames: [ 'h3' ],
contentDefault: '<b>H2</b>',
classList: [ 'custom-class-h2' ],
attrs: { 'data-custom-attr': 'attr-value-h2'
}
},
{
name: 'h3',
action: 'append-h4',
aria: 'header type 3',
tagNames: [ 'h4' ],
contentDefault: '<b>H3</b>',
classList: [ 'custom-class-h3' ],
attrs: { 'data-custom-attr': 'attr-value-h3'
}
},
'justifyLeft',
'justifyCenter',
'justifyRight',
'justifyFull',
'orderedlist',
'unorderedlist',
'quote',
'anchor',
'removeFormat'
]
},
anchorPreview: { hideDelay: 0
},
placeholder: { text: 'Write as little or as much as you want!'
},
paste: { forcePlainText: false
}
});
// Autosave
let autosave_event = null;
let last_autosave = null;
const autosave = function() {
if (autosave_event === null) {
console.log('Queueing autosave');
$('.js-autosave-icon').addClass('grey-text');
$('.js-autosave-icon').removeClass('black-text');
$('.js-autosave-icon').removeClass('red-text');
$('.js-autosave-status').text('Saving changes...');
autosave_event = setTimeout((function() {
console.log('Autosaving...');
$('.js-autosave-status').text('Saving...');
autosave_event = null;
// Do the autosave
last_autosave = $.ajax({
type: 'PATCH',
url: $('#editor').data('save-url'),
data: { document: {
title: $('#document_title').val(),
body: $('#editor').html()
}
}
});
last_autosave.fail(function(jqXHR, textStatus) {
$('.js-autosave-status').text('There was a problem saving! We will try to save again, but please make sure you back up any changes.');
$('.js-autosave-status').addClass('red-text');
$('.js-autosave-status').removeClass('grey-text');
$('.js-autosave-status').removeClass('black-text');
});
// Done!
$('.js-autosave-icon').addClass('black-text');
$('.js-autosave-icon').removeClass('grey-text');
$('.js-autosave-icon').removeClass('red-text');
$('.js-autosave-status').text('Saved!');
}), 2500);
} else {
console.log('Waiting for existing autosave');
}
};
editor.subscribe('editableInput', autosave);
$('#document_title').on('change', autosave);
$('#document_title').on('keydown', autosave);
$('.js-autosave-status').on('click', autosave);
// Allow entering `tab` into the editor
$(document).delegate('#editor', 'keydown', function(e) {
const keyCode = e.keyCode || e.which;
if (keyCode === 9) {
e.preventDefault();
}
});
}
};
$(() => new Notebook.DocumentEditor($("body.documents.edit")));

View File

@ -0,0 +1,41 @@
$(document).ready(function() {
// Character name generator
$('.character_name_generator').click(function() {
const target = $(this).closest('.row').find('input[type=text]');
$.ajax({
dataType: 'text',
url: '/generate/character/name',
success(data) {
target.val(data);
}
});
return 0;
});
// Character age generator
$('.character_age_generator').click(function() {
const target = $(this).closest('.row').find('input[type=text]');
$.ajax({
dataType: 'text',
url: '/generate/character/age',
success(data) {
target.val(data);
}
});
return 0;
});
// Location name generator
$('.location_name_generator').click(function() {
const target = $(this).closest('.row').find('input[type=text]');
$.ajax({
dataType: 'text',
url: '/generate/location/name',
success(data) {
target.val(data);
}
});
return 0;
});
});

View File

@ -1,31 +0,0 @@
$(document).ready ->
# Character name generator
$('.character_name_generator').click ->
target = $(this).closest('.row').find('input[type=text]')
$.ajax
dataType: 'text'
url: '/generate/character/name'
success: (data) ->
target.val data
0
# Character age generator
$('.character_age_generator').click ->
target = $(this).closest('.row').find('input[type=text]')
$.ajax
dataType: 'text'
url: '/generate/character/age'
success: (data) ->
target.val data
0
# Location name generator
$('.location_name_generator').click ->
target = $(this).closest('.row').find('input[type=text]')
$.ajax
dataType: 'text'
url: '/generate/location/name'
success: (data) ->
target.val data
0

View File

@ -1,3 +0,0 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View File

@ -1,6 +0,0 @@
$ ->
# When a user clicks to delete an image, we should remove it from the list of images after the remote request finishes
$('a.js-remove-image[data-remote]').on 'ajax:success', (e, data, status, xhr) ->
# Remove the image from the UI
$(this).closest('.row').fadeOut().remove() # todo use animate.css for something more fun
return

View File

@ -0,0 +1,5 @@
// When a user clicks to delete an image, we should remove it from the list of images after the remote request finishes
$('a.js-remove-image[data-remote]').on('ajax:success', function(e, data, status, xhr) {
// Remove the image from the UI
$(this).closest('.row').fadeOut().remove(); // todo use animate.css for something more fun
});

View File

@ -0,0 +1,4 @@
$(document).ready(() => $('.dropdown-picker li a').click(function() {
const val = $(this).text();
$(this).closest('.row').find('input[type=text]').val(val);
}));

View File

@ -1,4 +0,0 @@
$(document).ready ->
$('.dropdown-picker li a').click ->
val = $(this).text()
$(this).closest('.row').find('input[type=text]').val(val)

View File

@ -1,36 +0,0 @@
class Notebook.StripeHandler
constructor: (@el) ->
return unless @el.length > 0
$form = $('#payment-form')
stripeResponseHandler = (status, response) ->
$form = $('#payment-form')
if response.error
# Show the errors on the form:
$form.find('.payment-errors').text response.error.message
$form.find('.submit').prop 'disabled', false
else
# Insert the created token ID into the form so it gets submitted to the server:
token = response.id
$form.append $('<input type="hidden" name="stripeToken">').val(token)
# Submit the form:
$form.get(0).submit()
return
$form.submit (event) ->
# Disable the submit button to prevent repeated clicks:
$form.find('.submit').prop 'disabled', true
# Request a token from Stripe:
Stripe.card.createToken $form, stripeResponseHandler
# Prevent the form from being submitted:
false
return
$ ->
new Notebook.StripeHandler $("body.subscriptions.information")

View File

@ -0,0 +1,39 @@
Notebook.StripeHandler = class StripeHandler {
constructor(el) {
this.el = el;
if (!(this.el.length > 0)) { return; }
let $form = $('#payment-form');
const stripeResponseHandler = function(status, response) {
$form = $('#payment-form');
if (response.error) {
// Show the errors on the form:
$form.find('.payment-errors').text(response.error.message);
$form.find('.submit').prop('disabled', false);
} else {
// Insert the created token ID into the form so it gets submitted to the server:
const token = response.id;
$form.append($('<input type="hidden" name="stripeToken">').val(token));
// Submit the form:
$form.get(0).submit();
}
};
$form.submit(function(event) {
// Disable the submit button to prevent repeated clicks:
$form.find('.submit').prop('disabled', true);
// Request a token from Stripe:
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from being submitted:
return false;
});
}
};
$(() => new Notebook.StripeHandler($("body.subscriptions.information")));

View File

@ -1,3 +0,0 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/