mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Changed autosave handling for better editor performance
This changes how the editors interact with the parent page-editor compontent, which handles auto-saving. Instead of blasting the full editor content upon any change to that parent compontent, the editors just alert of a change, without the content. The parent compontent then requests the editor content from the editor component when it needs that data for an autosave. For #3981
This commit is contained in:
parent
31495758a9
commit
6545afacd6
@ -137,4 +137,13 @@ export class MarkdownEditor extends Component {
|
|||||||
return drawioAttrEl.getAttribute('drawio-url') || '';
|
return drawioAttrEl.getAttribute('drawio-url') || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content of this editor.
|
||||||
|
* Used by the parent page editor component.
|
||||||
|
* @return {{html: String, markdown: String}}
|
||||||
|
*/
|
||||||
|
getContent() {
|
||||||
|
return this.editor.actions.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,11 @@ export class PageEditor extends Component {
|
|||||||
this.setChangelogText = this.$opts.setChangelogText;
|
this.setChangelogText = this.$opts.setChangelogText;
|
||||||
|
|
||||||
// State data
|
// State data
|
||||||
this.editorHTML = '';
|
|
||||||
this.editorMarkdown = '';
|
|
||||||
this.autoSave = {
|
this.autoSave = {
|
||||||
interval: null,
|
interval: null,
|
||||||
frequency: 30000,
|
frequency: 30000,
|
||||||
last: 0,
|
last: 0,
|
||||||
|
pendingChange: false,
|
||||||
};
|
};
|
||||||
this.shownWarningsCache = new Set();
|
this.shownWarningsCache = new Set();
|
||||||
|
|
||||||
@ -59,12 +58,12 @@ export class PageEditor extends Component {
|
|||||||
window.$events.listen('editor-save-page', this.savePage.bind(this));
|
window.$events.listen('editor-save-page', this.savePage.bind(this));
|
||||||
|
|
||||||
// Listen to content changes from the editor
|
// Listen to content changes from the editor
|
||||||
window.$events.listen('editor-html-change', html => {
|
const onContentChange = () => this.autoSave.pendingChange = true;
|
||||||
this.editorHTML = html;
|
window.$events.listen('editor-html-change', onContentChange);
|
||||||
});
|
window.$events.listen('editor-markdown-change', onContentChange);
|
||||||
window.$events.listen('editor-markdown-change', markdown => {
|
|
||||||
this.editorMarkdown = markdown;
|
// Listen to changes on the title input
|
||||||
});
|
this.titleElem.addEventListener('input', onContentChange);
|
||||||
|
|
||||||
// Changelog controls
|
// Changelog controls
|
||||||
const updateChangelogDebounced = debounce(this.updateChangelogDisplay.bind(this), 300, false);
|
const updateChangelogDebounced = debounce(this.updateChangelogDisplay.bind(this), 300, false);
|
||||||
@ -89,18 +88,17 @@ export class PageEditor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startAutoSave() {
|
startAutoSave() {
|
||||||
let lastContent = this.titleElem.value.trim() + '::' + this.editorHTML;
|
this.autoSave.interval = window.setInterval(this.runAutoSave.bind(this), this.autoSave.frequency);
|
||||||
this.autoSaveInterval = window.setInterval(() => {
|
|
||||||
// Stop if manually saved recently to prevent bombarding the server
|
|
||||||
let savedRecently = (Date.now() - this.autoSave.last < (this.autoSave.frequency)/2);
|
|
||||||
if (savedRecently) return;
|
|
||||||
const newContent = this.titleElem.value.trim() + '::' + this.editorHTML;
|
|
||||||
if (newContent !== lastContent) {
|
|
||||||
lastContent = newContent;
|
|
||||||
this.saveDraft();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, this.autoSave.frequency);
|
runAutoSave() {
|
||||||
|
// Stop if manually saved recently to prevent bombarding the server
|
||||||
|
const savedRecently = (Date.now() - this.autoSave.last < (this.autoSave.frequency)/2);
|
||||||
|
if (savedRecently || !this.autoSave.pendingChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveDraft()
|
||||||
}
|
}
|
||||||
|
|
||||||
savePage() {
|
savePage() {
|
||||||
@ -108,14 +106,10 @@ export class PageEditor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async saveDraft() {
|
async saveDraft() {
|
||||||
const data = {
|
const data = {name: this.titleElem.value.trim()};
|
||||||
name: this.titleElem.value.trim(),
|
|
||||||
html: this.editorHTML,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.editorType === 'markdown') {
|
const editorContent = this.getEditorComponent().getContent();
|
||||||
data.markdown = this.editorMarkdown;
|
Object.assign(data, editorContent);
|
||||||
}
|
|
||||||
|
|
||||||
let didSave = false;
|
let didSave = false;
|
||||||
try {
|
try {
|
||||||
@ -132,6 +126,7 @@ export class PageEditor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
didSave = true;
|
didSave = true;
|
||||||
|
this.autoSave.pendingChange = false;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Save the editor content in LocalStorage as a last resort, just in case.
|
// Save the editor content in LocalStorage as a last resort, just in case.
|
||||||
try {
|
try {
|
||||||
@ -207,4 +202,11 @@ export class PageEditor extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MarkdownEditor|WysiwygEditor
|
||||||
|
*/
|
||||||
|
getEditorComponent() {
|
||||||
|
return window.$components.first('markdown-editor') || window.$components.first('wysiwyg-editor');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@ export class WysiwygEditor extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.$events.emitPublic(this.elem, 'editor-tinymce::pre-init', {config: this.tinyMceConfig});
|
window.$events.emitPublic(this.elem, 'editor-tinymce::pre-init', {config: this.tinyMceConfig});
|
||||||
window.tinymce.init(this.tinyMceConfig);
|
window.tinymce.init(this.tinyMceConfig).then(editors => {
|
||||||
|
this.editor = editors[0];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDrawIoUrl() {
|
getDrawIoUrl() {
|
||||||
@ -36,4 +38,15 @@ export class WysiwygEditor extends Component {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content of this editor.
|
||||||
|
* Used by the parent page editor component.
|
||||||
|
* @return {{html: String}}
|
||||||
|
*/
|
||||||
|
getContent() {
|
||||||
|
return {
|
||||||
|
html: this.editor.getContent()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -6,6 +6,10 @@ export class Actions {
|
|||||||
*/
|
*/
|
||||||
constructor(editor) {
|
constructor(editor) {
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
|
this.lastContent = {
|
||||||
|
html: '',
|
||||||
|
markdown: '',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAndRender() {
|
updateAndRender() {
|
||||||
@ -13,11 +17,17 @@ export class Actions {
|
|||||||
this.editor.config.inputEl.value = content;
|
this.editor.config.inputEl.value = content;
|
||||||
|
|
||||||
const html = this.editor.markdown.render(content);
|
const html = this.editor.markdown.render(content);
|
||||||
window.$events.emit('editor-html-change', html);
|
window.$events.emit('editor-html-change', '');
|
||||||
window.$events.emit('editor-markdown-change', content);
|
window.$events.emit('editor-markdown-change', '');
|
||||||
|
this.lastContent.html = html;
|
||||||
|
this.lastContent.markdown = content;
|
||||||
this.editor.display.patchWithHtml(html);
|
this.editor.display.patchWithHtml(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getContent() {
|
||||||
|
return this.lastContent;
|
||||||
|
}
|
||||||
|
|
||||||
insertImage() {
|
insertImage() {
|
||||||
const cursorPos = this.editor.cm.getCursor('from');
|
const cursorPos = this.editor.cm.getCursor('from');
|
||||||
/** @type {ImageManager} **/
|
/** @type {ImageManager} **/
|
||||||
|
@ -185,11 +185,10 @@ function getSetupCallback(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function editorChange() {
|
function editorChange() {
|
||||||
const content = editor.getContent();
|
|
||||||
if (options.darkMode) {
|
if (options.darkMode) {
|
||||||
editor.contentDocument.documentElement.classList.add('dark-mode');
|
editor.contentDocument.documentElement.classList.add('dark-mode');
|
||||||
}
|
}
|
||||||
window.$events.emit('editor-html-change', content);
|
window.$events.emit('editor-html-change', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom handler hook
|
// Custom handler hook
|
||||||
|
Loading…
Reference in New Issue
Block a user