diff --git a/app/assets/javascripts/protocols/steps.js.erb b/app/assets/javascripts/protocols/steps.js.erb index 2cc5cf49b..a78c48d95 100644 --- a/app/assets/javascripts/protocols/steps.js.erb +++ b/app/assets/javascripts/protocols/steps.js.erb @@ -366,6 +366,7 @@ }); toggleButtons(true); DragNDropSteps.clearFiles(); + tinyMCE.editors.step_description_textarea.remove(); }); } diff --git a/app/assets/javascripts/sitewide/tiny_mce.js b/app/assets/javascripts/sitewide/tiny_mce.js index 86a415a74..e25701ebe 100644 --- a/app/assets/javascripts/sitewide/tiny_mce.js +++ b/app/assets/javascripts/sitewide/tiny_mce.js @@ -16,6 +16,65 @@ var TinyMCE = (function() { }); } + function makeItDirty(editor) { + var editorForm = $(editor.getContainer()).closest('form'); + editorForm.find('.tinymce-status-badge').addClass('hidden'); + $(editor.getContainer()) + .find('.tinymce-save-button').removeClass('hidden'); + } + + + // Get LocalStorage auto save path + function getAutoSavePrefix(editor) { + var prefix = editor.getParam('autosave_prefix', 'tinymce-autosave-{path}{query}{hash}-{id}-'); + + prefix = prefix.replace(/\{path\}/g, document.location.pathname); + prefix = prefix.replace(/\{query\}/g, document.location.search); + prefix = prefix.replace(/\{hash\}/g, document.location.hash); + prefix = prefix.replace(/\{id\}/g, editor.id); + + return prefix; + } + + // Handles autosave notification if draft is available in the local storage + function restoreDraftNotification(selector, editor) { + var prefix = getAutoSavePrefix(editor); + var lastDraftTime = parseInt(tinyMCE.util.LocalStorage.getItem(prefix + 'time'), 10); + var lastUpdated = $(selector).data('last-updated'); + + var restoreBtn = $(''); + var cancelBtn = $(`
`); + + // Check whether we have draft stored + if (editor.plugins.autosave.hasDraft()) { + var notificationBar = $(''); + + if (lastDraftTime < lastUpdated) { + notificationBar.text(I18n.t('tiny_mce.older_version_available')); + } else { + notificationBar.text(I18n.t('tiny_mce.newer_version_available')); + } + + // Add notification bar + $(notificationBar).append(cancelBtn).append(restoreBtn); + $(editor.contentAreaContainer).before(notificationBar); + + $(restoreBtn).click(function() { + editor.plugins.autosave.restoreDraft(); + makeItDirty(editor); + notificationBar.remove(); + }); + + $(cancelBtn).click(function() { + notificationBar.remove(); + }); + } + } + // returns a public API for TinyMCE editor return Object.freeze({ init: function(selector, onSaveCallback) { @@ -30,16 +89,16 @@ var TinyMCE = (function() { .before(''); tinyMceContainer.addClass('hidden'); - if (textAreaObject.data('objectType') === 'step') { + if (textAreaObject.data('objectType') === 'step' + || textAreaObject.data('objectType') === 'result_text') { document.location.hash = textAreaObject.data('objectType') + '_' + textAreaObject.data('objectId'); } - tinyMCE.init({ cache_suffix: '?v=4.9.3', // This suffix should be changed any time library is updated selector: selector, menubar: 'file edit view insert format table', - toolbar: 'undo redo restoredraft | insert | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link | forecolor backcolor | customimageuploader | codesample | table tabledelete | tableprops tablerowprops tablecellprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol ', + toolbar: 'undo redo | insert | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link | forecolor backcolor | customimageuploader | codesample | table tabledelete | tableprops tablerowprops tablecellprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol', plugins: 'autosave autoresize customimageuploader link advlist codesample autolink lists charmap hr anchor searchreplace wordcount visualblocks visualchars insertdatetime nonbreaking save directionality paste textcolor placeholder colorpicker textpattern table', autoresize_bottom_margin: 20, codesample_languages: [ @@ -60,7 +119,8 @@ var TinyMCE = (function() { browser_spellcheck: true, branding: false, fixed_toolbar_container: '#mytoolbar', - autosave_interval: '15s', + autosave_restore_when_empty: false, + autosave_interval: '1s', autosave_retention: '1440m', removed_menuitems: 'newdocument', object_resizing: true, @@ -117,6 +177,7 @@ var TinyMCE = (function() { var editorForm = $(editor.getContainer()).closest('form'); var menuBar = editorForm.find('.mce-menubar.mce-toolbar.mce-first .mce-flow-layout'); var editorToolbar = editorForm.find('.mce-top-part'); + var editorToolbaroffset; $('.tinymce-placeholder').css('height', $(editor.editorContainer).height() + 'px'); @@ -226,10 +287,7 @@ var TinyMCE = (function() { }); editor.on('Dirty', function() { - var editorForm = $(editor.getContainer()).closest('form'); - editorForm.find('.tinymce-status-badge').addClass('hidden'); - $(editor.getContainer()) - .find('.tinymce-save-button').removeClass('hidden'); + makeItDirty(editor); }); editor.on('remove', function() { @@ -237,6 +295,10 @@ var TinyMCE = (function() { menuBar.find('.tinymce-save-button').remove(); menuBar.find('.tinymce-cancel-button').remove(); }); + + editor.on('init', function(e) { + restoreDraftNotification(selector, editor); + }); }, codesample_content_css: $(selector).data('highlightjs-path') }); diff --git a/app/assets/javascripts/tinymce/plugins/placeholder/plugin.js b/app/assets/javascripts/tinymce/plugins/placeholder/plugin.js index be5c209bf..efae49143 100644 --- a/app/assets/javascripts/tinymce/plugins/placeholder/plugin.js +++ b/app/assets/javascripts/tinymce/plugins/placeholder/plugin.js @@ -27,12 +27,26 @@ tinymce.PluginManager.add('placeholder', function(editor) { editor.on('init', function() { var label = new Label(); + // Correct top css property due to notification bar + function calculatePlaceholderPosition() { + var editorForm = $(editor.getContainer()).closest('form'); + var editorToolbar = editorForm.find('.mce-top-part'); + + var restoreDraftNotification = $(editorForm).find('.restore-draft-notification'); + var restoreDraftHeight = restoreDraftNotification.context ? restoreDraftNotification.height() : 0; + var newTop = $(editorToolbar).height() + restoreDraftHeight; + $(label.el).css('top', newTop + 'px'); + } + function checkPlaceholder() { + // Show/hide depending on the content if (editor.getContent() === '') { label.show(); } else { label.hide(); } + + calculatePlaceholderPosition(); } function onKeydown() { diff --git a/app/assets/stylesheets/tiny_mce.scss b/app/assets/stylesheets/tiny_mce.scss index 40aa5b53b..cc8101097 100644 --- a/app/assets/stylesheets/tiny_mce.scss +++ b/app/assets/stylesheets/tiny_mce.scss @@ -66,4 +66,30 @@ .mce-toolbar { background: $color-white !important; } + +.tinymce-cancel-notification-button { + cursor: pointer; + + .fas { + color: $color-silver-chalice; + font-family: 'Font Awesome 5 Free'; + font-weight: 501; + margin-left: 10px; + margin-top: 4px; + } +} + +.restore-draft-notification { + background: $state-info-bg !important; + height: 25px !important; + padding: 5px 10px 0 !important; + + .restore-draft-btn { + border: 1px solid $color-silver-chalice; + font-size: 12px; + margin-top: -2px; + padding: 3px 10px 3px 10px; + } +} + // scss-lint:enable ImportantRule diff --git a/app/views/my_modules/_description_form.html.erb b/app/views/my_modules/_description_form.html.erb index 83abbc2bb..9750fa0cf 100644 --- a/app/views/my_modules/_description_form.html.erb +++ b/app/views/my_modules/_description_form.html.erb @@ -23,5 +23,6 @@ data: { object_type: 'my_module', object_id: @my_module.id, - highlightjs_path: asset_path('highlightjs-github-theme.css') } ) %> + highlightjs_path: asset_path('highlightjs-github-theme.css'), + last_updated: @my_module.updated_at.to_i * 1000 } ) %> <% end %> diff --git a/app/views/my_modules/protocols/_protocol_description_form.html.erb b/app/views/my_modules/protocols/_protocol_description_form.html.erb index fe8af693a..cc3f1180a 100644 --- a/app/views/my_modules/protocols/_protocol_description_form.html.erb +++ b/app/views/my_modules/protocols/_protocol_description_form.html.erb @@ -23,5 +23,6 @@ data: { object_type: 'protocol', object_id: protocol.id, - highlightjs_path: asset_path('highlightjs-github-theme.css') } ) %> + highlightjs_path: asset_path('highlightjs-github-theme.css'), + last_updated: protocol.updated_at.to_i * 1000 } ) %> <% end %> diff --git a/app/views/result_texts/_edit.html.erb b/app/views/result_texts/_edit.html.erb index e11c24eb6..636c66d16 100644 --- a/app/views/result_texts/_edit.html.erb +++ b/app/views/result_texts/_edit.html.erb @@ -7,7 +7,8 @@ value: @result.result_text.tinymce_render(:text), data: { object_type: 'result_text', object_id: @result.result_text.id, - highlightjs_path: asset_path('highlightjs-github-theme.css') }) %> + highlightjs_path: asset_path('highlightjs-github-theme.css'), + last_updated: @result.updated_at.to_i * 1000 }) %> <% end %>