diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js
index 72e429bae..9fa0d49cc 100644
--- a/src/public/javascripts/services/note_detail.js
+++ b/src/public/javascripts/services/note_detail.js
@@ -27,8 +27,6 @@ async function openInTab(notePath, activate) {
}
async function switchToNote(notePath) {
- await saveNotesIfChanged();
-
await loadNoteDetail(notePath);
appContext.openTabsChanged();
@@ -38,15 +36,6 @@ function onNoteChange(func) {
return appContext.getActiveTabContext().getComponent().onNoteChange(func);
}
-async function saveNotesIfChanged() {
- for (const ctx of appContext.getTabContexts()) {
- await ctx.saveNoteIfChanged();
- }
-
- // make sure indicator is visible in a case there was some race condition.
- $savedIndicator.fadeIn();
-}
-
function getActiveEditor() {
const activeTabContext = appContext.getActiveTabContext();
@@ -210,10 +199,9 @@ function noteChanged() {
// this makes sure that when user e.g. reloads the page or navigates away from the page, the note's content is saved
// this sends the request asynchronously and doesn't wait for result
+// FIXME
$(window).on('beforeunload', () => { saveNotesIfChanged(); }); // don't convert to short form, handler doesn't like returned promise
-setInterval(saveNotesIfChanged, 3000);
-
export default {
reload,
openInTab,
@@ -222,7 +210,6 @@ export default {
loadNoteDetail,
focusOnTitle,
focusAndSelectTitle,
- saveNotesIfChanged,
onNoteChange,
addDetailLoadedListener,
getActiveEditor,
diff --git a/src/public/javascripts/services/spaced_update.js b/src/public/javascripts/services/spaced_update.js
new file mode 100644
index 000000000..d3686a6d7
--- /dev/null
+++ b/src/public/javascripts/services/spaced_update.js
@@ -0,0 +1,36 @@
+export default class SpacedUpdate {
+ constructor(updater, updateInterval = 1000) {
+ this.updater = updater;
+ this.lastUpdated = Date.now();
+ this.changed = false;
+ this.updateInterval = updateInterval;
+ }
+
+ scheduleUpdate() {
+ this.changed = true;
+ setTimeout(() => this.triggerUpdate())
+ }
+
+ async updateNowIfNecessary() {
+ if (this.changed) {
+ this.changed = false;
+ await this.updater();
+ }
+ }
+
+ triggerUpdate() {
+ if (!this.changed) {
+ return;
+ }
+
+ if (Date.now() - this.lastUpdated > this.updateInterval) {
+ this.updater();
+ this.lastUpdated = Date.now();
+ this.changed = false;
+ }
+ else {
+ // update not triggered but changes are still pending so we need to schedule another check
+ this.scheduleUpdate();
+ }
+ }
+}
diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js
index 980cdf672..5199f75fd 100644
--- a/src/public/javascripts/services/tab_context.js
+++ b/src/public/javascripts/services/tab_context.js
@@ -26,7 +26,6 @@ class TabContext extends Component {
this.tabRow = tabRow;
this.tabId = state.tabId || utils.randomString(4);
- this.$tab = $(this.tabRow.addTab(this.tabId));
this.state = state;
this.attributes = new Attributes(this.appContext, this);
diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js
index 0c2c21a73..931a38892 100644
--- a/src/public/javascripts/services/tree.js
+++ b/src/public/javascripts/services/tree.js
@@ -374,6 +374,7 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
window.cutToNote.removeSelection();
}
+ // FIXME
await noteDetailService.saveNotesIfChanged();
noteDetailService.addDetailLoadedListener(note.noteId, noteDetailService.focusAndSelectTitle);
diff --git a/src/public/javascripts/widgets/note_detail.js b/src/public/javascripts/widgets/note_detail.js
index 9d9c22d73..98e303a83 100644
--- a/src/public/javascripts/widgets/note_detail.js
+++ b/src/public/javascripts/widgets/note_detail.js
@@ -2,6 +2,8 @@ import TabAwareWidget from "./tab_aware_widget.js";
import utils from "../services/utils.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import appContext from "../services/app_context.js";
+import SpacedUpdate from "../services/spaced_update.js";
+import server from "../services/server.js";
const TPL = `
@@ -32,6 +34,19 @@ export default class NoteDetailWidget extends TabAwareWidget {
this.typeWidgets = {};
this.typeWidgetPromises = {};
+
+ this.spacedUpdate = new SpacedUpdate(async () => {
+ const note = this.tabContext.note;
+ note.content = this.getTypeWidget().getContent();
+
+ const resp = await server.put('notes/' + note.noteId, note.dto);
+
+ // FIXME: minor - does not propagate to other tab contexts with this note though
+ note.dateModified = resp.dateModified;
+ note.utcDateModified = resp.utcDateModified;
+
+ this.trigger('noteChangesSaved', {noteId: note.noteId})
+ });
}
doRender() {
@@ -114,12 +129,14 @@ export default class NoteDetailWidget extends TabAwareWidget {
async initWidgetType(type) {
const clazz = await import(typeWidgetClasses[type]);
- this.typeWidgets[this.type] = new clazz.default(this.appContext);
- this.children.push(this.typeWidgets[this.type]);
+ const typeWidget = this.typeWidgets[this.type] = new clazz.default(this.appContext);
+ this.children.push(typeWidget);
- this.$widget.append(this.typeWidgets[this.type].render());
+ this.$widget.append(typeWidget.render());
- this.typeWidgets[this.type].eventReceived('setTabContext', {tabContext: this.tabContext});
+ typeWidget.onNoteChange(() => this.spacedUpdate.scheduleUpdate());
+
+ typeWidget.eventReceived('setTabContext', {tabContext: this.tabContext});
}
getWidgetType(disableAutoBook) {
@@ -153,4 +170,16 @@ export default class NoteDetailWidget extends TabAwareWidget {
widget.focus();
}
}
+
+ async beforeNoteSwitchListener({tabId}) {
+ if (this.isTab(tabId)) {
+ await this.spacedUpdate.updateNowIfNecessary();
+ }
+ }
+
+ async beforeTabRemoveListener({tabId}) {
+ if (this.isTab(tabId)) {
+ await this.spacedUpdate.updateNowIfNecessary();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/public/javascripts/widgets/note_title.js b/src/public/javascripts/widgets/note_title.js
index 48309efbc..8ff63180f 100644
--- a/src/public/javascripts/widgets/note_title.js
+++ b/src/public/javascripts/widgets/note_title.js
@@ -3,6 +3,7 @@ import utils from "../services/utils.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import treeCache from "../services/tree_cache.js";
import server from "../services/server.js";
+import SpacedUpdate from "../services/spaced_update.js";
const TPL = `
@@ -24,43 +25,6 @@ const TPL = `
`;
-class SpacedUpdate {
- constructor(updater, updateInterval = 1000) {
- this.updater = updater;
- this.lastUpdated = Date.now();
- this.changed = false;
- this.updateInterval = updateInterval;
- }
-
- scheduleUpdate() {
- this.changed = true;
- setTimeout(() => this.triggerUpdate())
- }
-
- async updateNowIfNecessary() {
- if (this.changed) {
- this.changed = false;
- await this.updater();
- }
- }
-
- triggerUpdate() {
- if (!this.changed) {
- return;
- }
-
- if (Date.now() - this.lastUpdated > this.updateInterval) {
- this.updater();
- this.lastUpdated = Date.now();
- this.changed = false;
- }
- else {
- // update not triggered but changes are still pending so we need to schedule another check
- this.scheduleUpdate();
- }
- }
-}
-
export default class NoteTitleWidget extends TabAwareWidget {
constructor(appContext) {
super(appContext);
diff --git a/src/public/javascripts/widgets/type_widgets/code.js b/src/public/javascripts/widgets/type_widgets/code.js
index 072b7f381..66ab4ee4f 100644
--- a/src/public/javascripts/widgets/type_widgets/code.js
+++ b/src/public/javascripts/widgets/type_widgets/code.js
@@ -109,6 +109,7 @@ class CodeTypeWidget extends TypeWidget {
}
// make sure note is saved so we load latest changes
+ // FIXME
await noteDetailService.saveNotesIfChanged();
if (this.tabContext.note.mime.endsWith("env=frontend")) {
@@ -122,7 +123,9 @@ class CodeTypeWidget extends TypeWidget {
toastService.showMessage("Note executed");
}
- onNoteChange(func) {
+ async onNoteChange(func) {
+ await this.initialized;
+
this.codeEditor.on('change', func);
}
diff --git a/src/public/javascripts/widgets/type_widgets/note_detail_search.js b/src/public/javascripts/widgets/type_widgets/note_detail_search.js
index 61b088c44..46e19292f 100644
--- a/src/public/javascripts/widgets/type_widgets/note_detail_search.js
+++ b/src/public/javascripts/widgets/type_widgets/note_detail_search.js
@@ -13,6 +13,7 @@ class NoteDetailSearch {
this.$refreshButton = ctx.$tabContent.find('.note-detail-search-refresh-results-button');
this.$refreshButton.on('click', async () => {
+ // FIXME
await noteDetailService.saveNotesIfChanged();
await searchNotesService.refreshSearch();
diff --git a/src/public/javascripts/widgets/type_widgets/text.js b/src/public/javascripts/widgets/type_widgets/text.js
index 46842564f..dd66494c0 100644
--- a/src/public/javascripts/widgets/type_widgets/text.js
+++ b/src/public/javascripts/widgets/type_widgets/text.js
@@ -174,7 +174,9 @@ class TextTypeWidget extends TypeWidget {
return this.textEditor;
}
- onNoteChange(func) {
+ async onNoteChange(func) {
+ await this.initialized;
+
this.textEditor.model.document.on('change:data', func);
}