mirror of
https://github.com/indentlabs/notebook.git
synced 2025-10-26 11:19:22 +00:00
Merge branch 'master' of github.com:indentlabs/notebook
This commit is contained in:
commit
4e76e21000
@ -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)
|
||||
|
||||
@ -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()
|
||||
27
app/assets/javascripts/_initialization.js
Normal file
27
app/assets/javascripts/_initialization.js
Normal 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());
|
||||
@ -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
|
||||
5
app/assets/javascripts/collaboration.js
Normal file
5
app/assets/javascripts/collaboration.js
Normal 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
|
||||
});
|
||||
@ -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")
|
||||
128
app/assets/javascripts/document_editor.js
Normal file
128
app/assets/javascripts/document_editor.js
Normal 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")));
|
||||
41
app/assets/javascripts/generators.js
Normal file
41
app/assets/javascripts/generators.js
Normal 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;
|
||||
});
|
||||
});
|
||||
@ -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
|
||||
@ -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/
|
||||
@ -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
|
||||
5
app/assets/javascripts/image_uploads.js
Normal file
5
app/assets/javascripts/image_uploads.js
Normal 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
|
||||
});
|
||||
4
app/assets/javascripts/pickers.js
Normal file
4
app/assets/javascripts/pickers.js
Normal 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);
|
||||
}));
|
||||
@ -1,4 +0,0 @@
|
||||
$(document).ready ->
|
||||
$('.dropdown-picker li a').click ->
|
||||
val = $(this).text()
|
||||
$(this).closest('.row').find('input[type=text]').val(val)
|
||||
@ -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")
|
||||
39
app/assets/javascripts/stripe.js
Normal file
39
app/assets/javascripts/stripe.js
Normal 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")));
|
||||
@ -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/
|
||||
Loading…
Reference in New Issue
Block a user