[SCI-3751] Improve the auto-save functionality on RTF fields (#2086)

[SCI-3751] Improve the auto-save functionality on RTF fields
This commit is contained in:
Jure Grabnar 2019-09-30 15:09:32 +02:00 committed by GitHub
commit 4b605d357a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 123 additions and 13 deletions

View file

@ -366,6 +366,7 @@
});
toggleButtons(true);
DragNDropSteps.clearFiles();
tinyMCE.editors.step_description_textarea.remove();
});
}

View file

@ -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 = $('<button class="btn restore-draft-btn pull-right">Restore Draft</button>');
var cancelBtn = $(`<div class="tinymce-cancel-notification-button pull-right">
<button type="button">
<span class="fas fa-times"></span>
</button>
</div>`);
// Check whether we have draft stored
if (editor.plugins.autosave.hasDraft()) {
var notificationBar = $('<div class="restore-draft-notification"></div>');
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('<div class="tinymce-placeholder" style="height:' + tinyMceInitSize + 'px"></div>');
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')
});

View file

@ -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() {

View file

@ -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

View file

@ -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 %>

View file

@ -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 %>

View file

@ -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 %><br />
<div class="align-right">
<button type="button" class="btn btn-default cancel-edit">

View file

@ -6,7 +6,8 @@
id: :result_text_attributes_textarea,
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 %><br />
<div class="align-right">
<button type="button" class="btn btn-default cancel-new">

View file

@ -36,7 +36,8 @@
data: {
object_type: 'step',
object_id: @step.id,
highlightjs_path: asset_path('highlightjs-github-theme.css') } ) %>
highlightjs_path: asset_path('highlightjs-github-theme.css'),
last_updated: @step.updated_at.to_i * 1000 }) %>
</div>
</div>
<div class="tab-pane" role="tabpanel" id="new-step-checklists">

View file

@ -2007,6 +2007,8 @@ en:
server_not_respond: "Didn't get a response from the server"
saved_label: "Saved"
leaving_warning: "You have made some changes, are you sure you want to leave this page?"
older_version_available: "Older version of the text below has been saved in the browser. Do you want to restore it?"
newer_version_available: "Newer version of the text below has been saved in the browser. Do you want to restore it?"
general:
save: "Save"
update: "Update"