fix: race condition when editor values read could belong to newly selected note as opposed to note for which save was triggered
This commit is contained in:
@@ -88,11 +88,15 @@ type EditorState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type EditorValues = {
|
type EditorValues = {
|
||||||
title?: string;
|
title: string;
|
||||||
text?: string;
|
text: string;
|
||||||
tagsInputValue?: string;
|
tagsInputValue?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function copyEditorValues(values: EditorValues) {
|
||||||
|
return Object.assign({}, values);
|
||||||
|
}
|
||||||
|
|
||||||
function sortAlphabetically(array: SNComponent[]): SNComponent[] {
|
function sortAlphabetically(array: SNComponent[]): SNComponent[] {
|
||||||
return array.sort((a, b) =>
|
return array.sort((a, b) =>
|
||||||
a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1
|
a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1
|
||||||
@@ -110,7 +114,7 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
private saveTimeout?: ng.IPromise<void>;
|
private saveTimeout?: ng.IPromise<void>;
|
||||||
private statusTimeout?: ng.IPromise<void>;
|
private statusTimeout?: ng.IPromise<void>;
|
||||||
private lastEditorFocusEventSource?: EventSource;
|
private lastEditorFocusEventSource?: EventSource;
|
||||||
public editorValues: EditorValues = {};
|
public editorValues: EditorValues = { title: '', text: '' };
|
||||||
onEditorLoad?: () => void;
|
onEditorLoad?: () => void;
|
||||||
|
|
||||||
private tags: SNTag[] = [];
|
private tags: SNTag[] = [];
|
||||||
@@ -464,26 +468,30 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
* close the editor (if we closed the editor before sync began, we'd get an exception,
|
* close the editor (if we closed the editor before sync began, we'd get an exception,
|
||||||
* since the debouncer will be triggered on a non-existent editor)
|
* since the debouncer will be triggered on a non-existent editor)
|
||||||
*/
|
*/
|
||||||
async saveNote(
|
async save(
|
||||||
|
note: SNNote,
|
||||||
|
editorValues: EditorValues,
|
||||||
bypassDebouncer = false,
|
bypassDebouncer = false,
|
||||||
isUserModified = false,
|
isUserModified = false,
|
||||||
dontUpdatePreviews = false,
|
dontUpdatePreviews = false,
|
||||||
customMutate?: (mutator: NoteMutator) => void,
|
customMutate?: (mutator: NoteMutator) => void,
|
||||||
closeAfterSync = false
|
closeAfterSync = false
|
||||||
) {
|
) {
|
||||||
|
const title = editorValues.title;
|
||||||
|
const text = editorValues.text;
|
||||||
|
const isTemplate = this.editor.isTemplateNote;
|
||||||
|
const selectedTag = this.appState.selectedTag;
|
||||||
if (document.hidden) {
|
if (document.hidden) {
|
||||||
this.application.alertService!.alert(STRING_SAVING_WHILE_DOCUMENT_HIDDEN);
|
this.application.alertService.alert(STRING_SAVING_WHILE_DOCUMENT_HIDDEN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const note = this.note;
|
|
||||||
if (note.deleted) {
|
if (note.deleted) {
|
||||||
this.application.alertService!.alert(STRING_DELETED_NOTE);
|
this.application.alertService.alert(STRING_DELETED_NOTE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.editor.isTemplateNote) {
|
if (isTemplate) {
|
||||||
await this.editor.insertTemplatedNote();
|
await this.editor.insertTemplatedNote();
|
||||||
}
|
}
|
||||||
const selectedTag = this.appState.selectedTag;
|
|
||||||
if (
|
if (
|
||||||
!selectedTag?.isSmartTag &&
|
!selectedTag?.isSmartTag &&
|
||||||
!selectedTag?.hasRelationshipWithItem(note)
|
!selectedTag?.hasRelationshipWithItem(note)
|
||||||
@@ -493,7 +501,7 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!this.application.findItem(note.uuid)) {
|
if (!this.application.findItem(note.uuid)) {
|
||||||
this.application.alertService!.alert(STRING_INVALID_NOTE);
|
this.application.alertService.alert(STRING_INVALID_NOTE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.application.changeItem(
|
await this.application.changeItem(
|
||||||
@@ -503,12 +511,12 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
if (customMutate) {
|
if (customMutate) {
|
||||||
customMutate(noteMutator);
|
customMutate(noteMutator);
|
||||||
}
|
}
|
||||||
noteMutator.title = this.editorValues.title!;
|
noteMutator.title = title;
|
||||||
noteMutator.text = this.editorValues.text!;
|
noteMutator.text = text;
|
||||||
if (!dontUpdatePreviews) {
|
if (!dontUpdatePreviews) {
|
||||||
const text = this.editorValues.text || '';
|
const noteText = text || '';
|
||||||
const truncate = text.length > NOTE_PREVIEW_CHAR_LIMIT;
|
const truncate = noteText.length > NOTE_PREVIEW_CHAR_LIMIT;
|
||||||
const substring = text.substring(0, NOTE_PREVIEW_CHAR_LIMIT);
|
const substring = noteText.substring(0, NOTE_PREVIEW_CHAR_LIMIT);
|
||||||
const previewPlain = substring + (truncate ? STRING_ELLIPSES : '');
|
const previewPlain = substring + (truncate ? STRING_ELLIPSES : '');
|
||||||
noteMutator.preview_plain = previewPlain;
|
noteMutator.preview_plain = previewPlain;
|
||||||
noteMutator.preview_html = undefined;
|
noteMutator.preview_html = undefined;
|
||||||
@@ -541,7 +549,8 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
syncTakingTooLong: false,
|
syncTakingTooLong: false,
|
||||||
});
|
});
|
||||||
this.setStatus({
|
this.setStatus({
|
||||||
message: 'All changes saved' + (this.application.noAccount() ? ' offline' : ''),
|
message:
|
||||||
|
'All changes saved' + (this.application.noAccount() ? ' offline' : ''),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,7 +592,7 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentChanged() {
|
contentChanged() {
|
||||||
this.saveNote(false, true);
|
this.save(this.note, copyEditorValues(this.editorValues), false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
onTitleEnter($event: Event) {
|
onTitleEnter($event: Event) {
|
||||||
@@ -593,7 +602,13 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTitleChange() {
|
onTitleChange() {
|
||||||
this.saveNote(false, true, true);
|
this.save(
|
||||||
|
this.note,
|
||||||
|
copyEditorValues(this.editorValues),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
focusEditor() {
|
focusEditor() {
|
||||||
@@ -653,9 +668,16 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
if (permanently) {
|
if (permanently) {
|
||||||
this.performNoteDeletion(this.note);
|
this.performNoteDeletion(this.note);
|
||||||
} else {
|
} else {
|
||||||
this.saveNote(true, false, true, (mutator) => {
|
this.save(
|
||||||
mutator.trashed = true;
|
this.note,
|
||||||
});
|
copyEditorValues(this.editorValues),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
(mutator) => {
|
||||||
|
mutator.trashed = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,7 +687,9 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
restoreTrashedNote() {
|
restoreTrashedNote() {
|
||||||
this.saveNote(
|
this.save(
|
||||||
|
this.note,
|
||||||
|
copyEditorValues(this.editorValues),
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
@@ -698,15 +722,31 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
togglePin() {
|
togglePin() {
|
||||||
this.saveNote(true, false, true, (mutator) => {
|
const note = this.note;
|
||||||
mutator.pinned = !this.note.pinned;
|
this.save(
|
||||||
});
|
note,
|
||||||
|
copyEditorValues(this.editorValues),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
(mutator) => {
|
||||||
|
mutator.pinned = !note.pinned;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLockNote() {
|
toggleLockNote() {
|
||||||
this.saveNote(true, false, true, (mutator) => {
|
const note = this.note;
|
||||||
mutator.locked = !this.note.locked;
|
this.save(
|
||||||
});
|
note,
|
||||||
|
copyEditorValues(this.editorValues),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
(mutator) => {
|
||||||
|
mutator.locked = !note.locked;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleProtectNote() {
|
async toggleProtectNote() {
|
||||||
@@ -723,29 +763,40 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleNotePreview() {
|
toggleNotePreview() {
|
||||||
this.saveNote(true, false, true, (mutator) => {
|
const note = this.note;
|
||||||
mutator.hidePreview = !this.note.hidePreview;
|
this.save(
|
||||||
});
|
note,
|
||||||
|
copyEditorValues(this.editorValues),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
(mutator) => {
|
||||||
|
mutator.hidePreview = !note.hidePreview;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleArchiveNote() {
|
toggleArchiveNote() {
|
||||||
if (this.note.locked) {
|
const note = this.note;
|
||||||
|
if (note.locked) {
|
||||||
alertDialog({
|
alertDialog({
|
||||||
text: this.note.archived
|
text: note.archived
|
||||||
? STRING_UNARCHIVE_LOCKED_ATTEMPT
|
? STRING_UNARCHIVE_LOCKED_ATTEMPT
|
||||||
: STRING_ARCHIVE_LOCKED_ATTEMPT,
|
: STRING_ARCHIVE_LOCKED_ATTEMPT,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.saveNote(
|
this.save(
|
||||||
|
note,
|
||||||
|
copyEditorValues(this.editorValues),
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
(mutator) => {
|
(mutator) => {
|
||||||
mutator.archived = !this.note.archived;
|
mutator.archived = !note.archived;
|
||||||
},
|
},
|
||||||
/** If we are unarchiving, and we are in the archived tag, close the editor */
|
/** If we are unarchiving, and we are in the archived tag, close the editor */
|
||||||
this.note.archived && this.appState.selectedTag?.isArchiveTag
|
note.archived && this.appState.selectedTag?.isArchiveTag
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1176,7 +1227,7 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
|||||||
editor.selectionStart = editor.selectionEnd = start + 4;
|
editor.selectionStart = editor.selectionEnd = start + 4;
|
||||||
}
|
}
|
||||||
this.editorValues.text = editor.value;
|
this.editorValues.text = editor.value;
|
||||||
this.saveNote(true);
|
this.save(this.note, copyEditorValues(this.editorValues), true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user