Improved debouncing for plain editor
This commit is contained in:
@@ -183,7 +183,7 @@ angular.module('app')
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(oldNote && oldNote != note) {
|
if(oldNote && oldNote != note) {
|
||||||
if(oldNote.hasChanges) {
|
if(oldNote.dirty) {
|
||||||
this.saveNote(oldNote);
|
this.saveNote(oldNote);
|
||||||
} else if(oldNote.dummy) {
|
} else if(oldNote.dummy) {
|
||||||
this.remove()(oldNote);
|
this.remove()(oldNote);
|
||||||
@@ -270,12 +270,23 @@ angular.module('app')
|
|||||||
this.showMenu = false;
|
this.showMenu = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// var statusTimeout;
|
this.EditorNgDebounce = 200;
|
||||||
|
const SyncDebouce = 1000;
|
||||||
|
const SyncNoDebounce = 100;
|
||||||
|
|
||||||
|
this.saveNote = function({bypassDebouncer, updateClientModified, dontUpdatePreviews}) {
|
||||||
|
let note = this.note;
|
||||||
|
note.dummy = false;
|
||||||
|
|
||||||
|
if(!modelManager.findItem(note.uuid)) {
|
||||||
|
alert("The note you are attempting to save can not be found or has been deleted. Changes you make will not be synced. Please copy this note's text and start a new note.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.saveNote = function(note, callback, updateClientModified, dontUpdatePreviews) {
|
|
||||||
// We don't want to update the client modified date if toggling lock for note.
|
|
||||||
modelManager.setItemDirty(note, true, updateClientModified);
|
modelManager.setItemDirty(note, true, updateClientModified);
|
||||||
|
|
||||||
|
this.showSavingStatus();
|
||||||
|
|
||||||
if(!dontUpdatePreviews) {
|
if(!dontUpdatePreviews) {
|
||||||
let limit = 80;
|
let limit = 80;
|
||||||
var text = note.text || "";
|
var text = note.text || "";
|
||||||
@@ -286,53 +297,20 @@ angular.module('app')
|
|||||||
note.content.preview_html = null;
|
note.content.preview_html = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showSavingStatus();
|
if(this.saveTimeout) {
|
||||||
syncManager.sync().then((response) => {
|
$timeout.cancel(this.saveTimeout);
|
||||||
if(response && response.error) {
|
}
|
||||||
if(!this.didShowErrorAlert) {
|
|
||||||
|
let syncDebouceMs = bypassDebouncer ? SyncNoDebounce : SyncDebouce;
|
||||||
|
|
||||||
|
this.saveTimeout = $timeout(() => {
|
||||||
|
syncManager.sync().then((response) => {
|
||||||
|
if(response && response.error && !this.didShowErrorAlert) {
|
||||||
this.didShowErrorAlert = true;
|
this.didShowErrorAlert = true;
|
||||||
alert("There was an error saving your note. Please try again.");
|
alert("There was an error saving your note. Please try again.");
|
||||||
}
|
}
|
||||||
$timeout(() => {
|
})
|
||||||
callback && callback(false);
|
}, syncDebouceMs)
|
||||||
})
|
|
||||||
} else {
|
|
||||||
note.hasChanges = false;
|
|
||||||
$timeout(() => {
|
|
||||||
callback && callback(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveTimeout;
|
|
||||||
this.changesMade = function({bypassDebouncer, updateClientModified, dontUpdatePreviews} = {}) {
|
|
||||||
let note = this.note;
|
|
||||||
note.dummy = false;
|
|
||||||
|
|
||||||
/* In the case of keystrokes, saving should go through a debouncer to avoid frequent calls.
|
|
||||||
In the case of deleting or archiving a note, it should happen immediately before the note is switched out
|
|
||||||
*/
|
|
||||||
let delay = bypassDebouncer ? 0 : 275;
|
|
||||||
|
|
||||||
// In the case of archiving a note, the note is saved immediately, then switched to another note.
|
|
||||||
// Usually note.hasChanges is set back to false after the saving delay, but in this case, because there is no delay,
|
|
||||||
// we set it to false immediately so that it is not saved twice: once now, and the other on setNote in oldNote.hasChanges.
|
|
||||||
note.hasChanges = bypassDebouncer ? false : true;
|
|
||||||
|
|
||||||
if(saveTimeout) $timeout.cancel(saveTimeout);
|
|
||||||
// if(statusTimeout) $timeout.cancel(statusTimeout);
|
|
||||||
saveTimeout = $timeout(() => {
|
|
||||||
note.dummy = false;
|
|
||||||
// Make sure the note exists. A safety measure, as toggling between tags triggers deletes for dummy notes.
|
|
||||||
// Race conditions have been fixed, but we'll keep this here just in case.
|
|
||||||
if(!modelManager.findItem(note.uuid)) {
|
|
||||||
alert("The note you are attempting to save can not be found or has been deleted. Changes you make will not be synced. Please copy this note's text and start a new note.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.saveNote(note, null, updateClientModified, dontUpdatePreviews);
|
|
||||||
}, delay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showSavingStatus = function() {
|
this.showSavingStatus = function() {
|
||||||
@@ -380,8 +358,7 @@ angular.module('app')
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.contentChanged = function() {
|
this.contentChanged = function() {
|
||||||
// content changes should bypass manual debouncer as we use the built in ng-model-options debouncer
|
this.saveNote({updateClientModified: true});
|
||||||
this.changesMade({bypassDebouncer: true, updateClientModified: true});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onTitleEnter = function($event) {
|
this.onTitleEnter = function($event) {
|
||||||
@@ -391,7 +368,7 @@ angular.module('app')
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.onTitleChange = function() {
|
this.onTitleChange = function() {
|
||||||
this.changesMade({dontUpdatePreviews: true, updateClientModified: true});
|
this.saveNote({dontUpdatePreviews: true, updateClientModified: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onNameFocus = function() {
|
this.onNameFocus = function() {
|
||||||
@@ -428,7 +405,7 @@ angular.module('app')
|
|||||||
this.remove()(this.note);
|
this.remove()(this.note);
|
||||||
} else {
|
} else {
|
||||||
this.note.content.trashed = true;
|
this.note.content.trashed = true;
|
||||||
this.changesMade({bypassDebouncer: true, dontUpdatePreviews: true});
|
this.saveNote({bypassDebouncer: true, dontUpdatePreviews: true});
|
||||||
}
|
}
|
||||||
this.showMenu = false;
|
this.showMenu = false;
|
||||||
}
|
}
|
||||||
@@ -446,7 +423,7 @@ angular.module('app')
|
|||||||
|
|
||||||
this.restoreTrashedNote = function() {
|
this.restoreTrashedNote = function() {
|
||||||
this.note.content.trashed = false;
|
this.note.content.trashed = false;
|
||||||
this.changesMade({bypassDebouncer: true, dontUpdatePreviews: true});
|
this.saveNote({bypassDebouncer: true, dontUpdatePreviews: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.deleteNotePermanantely = function() {
|
this.deleteNotePermanantely = function() {
|
||||||
@@ -467,17 +444,17 @@ angular.module('app')
|
|||||||
|
|
||||||
this.togglePin = function() {
|
this.togglePin = function() {
|
||||||
this.note.setAppDataItem("pinned", !this.note.pinned);
|
this.note.setAppDataItem("pinned", !this.note.pinned);
|
||||||
this.changesMade({bypassDebouncer: true, dontUpdatePreviews: true});
|
this.saveNote({bypassDebouncer: true, dontUpdatePreviews: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.toggleLockNote = function() {
|
this.toggleLockNote = function() {
|
||||||
this.note.setAppDataItem("locked", !this.note.locked);
|
this.note.setAppDataItem("locked", !this.note.locked);
|
||||||
this.changesMade({bypassDebouncer: true, dontUpdatePreviews: true});
|
this.saveNote({bypassDebouncer: true, dontUpdatePreviews: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.toggleProtectNote = function() {
|
this.toggleProtectNote = function() {
|
||||||
this.note.content.protected = !this.note.content.protected;
|
this.note.content.protected = !this.note.content.protected;
|
||||||
this.changesMade({bypassDebouncer: true, dontUpdatePreviews: true});
|
this.saveNote({bypassDebouncer: true, dontUpdatePreviews: true});
|
||||||
|
|
||||||
// Show privilegesManager if Protection is not yet set up
|
// Show privilegesManager if Protection is not yet set up
|
||||||
privilegesManager.actionHasPrivilegesConfigured(PrivilegesManager.ActionViewProtectedNotes).then((configured) => {
|
privilegesManager.actionHasPrivilegesConfigured(PrivilegesManager.ActionViewProtectedNotes).then((configured) => {
|
||||||
@@ -489,12 +466,12 @@ angular.module('app')
|
|||||||
|
|
||||||
this.toggleNotePreview = function() {
|
this.toggleNotePreview = function() {
|
||||||
this.note.content.hidePreview = !this.note.content.hidePreview;
|
this.note.content.hidePreview = !this.note.content.hidePreview;
|
||||||
this.changesMade({bypassDebouncer: true, dontUpdatePreviews: true});
|
this.saveNote({bypassDebouncer: true, dontUpdatePreviews: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.toggleArchiveNote = function() {
|
this.toggleArchiveNote = function() {
|
||||||
this.note.setAppDataItem("archived", !this.note.archived);
|
this.note.setAppDataItem("archived", !this.note.archived);
|
||||||
this.changesMade({bypassDebouncer: true, dontUpdatePreviews: true});
|
this.saveNote({bypassDebouncer: true, dontUpdatePreviews: true});
|
||||||
$rootScope.$broadcast("noteArchived");
|
$rootScope.$broadcast("noteArchived");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,11 +703,9 @@ angular.module('app')
|
|||||||
this.removeTag(tag);
|
this.removeTag(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(action === "save-items" || action === "save-success" || action == "save-error") {
|
else if(action === "save-items") {
|
||||||
if(data.items.map((item) => {return item.uuid}).includes(this.note.uuid)) {
|
if(data.items.map((item) => {return item.uuid}).includes(this.note.uuid)) {
|
||||||
if(action == "save-items") {
|
this.showSavingStatus();
|
||||||
this.showSavingStatus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}});
|
}});
|
||||||
@@ -898,7 +873,7 @@ angular.module('app')
|
|||||||
|
|
||||||
$timeout(() => {
|
$timeout(() => {
|
||||||
this.note.text = editor.value;
|
this.note.text = editor.value;
|
||||||
this.changesMade({bypassDebouncer: true});
|
this.saveNote({bypassDebouncer: true});
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -79,7 +79,8 @@
|
|||||||
|
|
||||||
%textarea.editable#note-text-editor{"ng-if" => "!ctrl.selectedEditor", "ng-model" => "ctrl.note.text", "ng-readonly" => "ctrl.note.locked",
|
%textarea.editable#note-text-editor{"ng-if" => "!ctrl.selectedEditor", "ng-model" => "ctrl.note.text", "ng-readonly" => "ctrl.note.locked",
|
||||||
"ng-change" => "ctrl.contentChanged()", "ng-trim" => "false", "ng-click" => "ctrl.clickedTextArea()",
|
"ng-change" => "ctrl.contentChanged()", "ng-trim" => "false", "ng-click" => "ctrl.clickedTextArea()",
|
||||||
"ng-focus" => "ctrl.onContentFocus()", "dir" => "auto", "ng-attr-spellcheck" => "{{ctrl.spellcheck}}", "ng-model-options"=>"{ debounce: 300 }"}
|
"ng-focus" => "ctrl.onContentFocus()", "dir" => "auto", "ng-attr-spellcheck" => "{{ctrl.spellcheck}}",
|
||||||
|
"ng-model-options"=>"{ debounce: ctrl.EditorNgDebounce }"}
|
||||||
{{ctrl.onSystemEditorLoad()}}
|
{{ctrl.onSystemEditorLoad()}}
|
||||||
|
|
||||||
%panel-resizer{"ng-if" => "ctrl.marginResizersEnabled", "panel-id" => "'editor-content'", "on-resize-finish" => "ctrl.onPanelResizeFinish", "control" => "ctrl.rightResizeControl", "min-width" => 300, "hoverable" => "true", "property" => "'right'"}
|
%panel-resizer{"ng-if" => "ctrl.marginResizersEnabled", "panel-id" => "'editor-content'", "on-resize-finish" => "ctrl.onPanelResizeFinish", "control" => "ctrl.rightResizeControl", "min-width" => 300, "hoverable" => "true", "property" => "'right'"}
|
||||||
|
|||||||
Reference in New Issue
Block a user