mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
saving note detail
This commit is contained in:
parent
562c729ed6
commit
423a70d102
@ -27,8 +27,6 @@ async function openInTab(notePath, activate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function switchToNote(notePath) {
|
async function switchToNote(notePath) {
|
||||||
await saveNotesIfChanged();
|
|
||||||
|
|
||||||
await loadNoteDetail(notePath);
|
await loadNoteDetail(notePath);
|
||||||
|
|
||||||
appContext.openTabsChanged();
|
appContext.openTabsChanged();
|
||||||
@ -38,15 +36,6 @@ function onNoteChange(func) {
|
|||||||
return appContext.getActiveTabContext().getComponent().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() {
|
function getActiveEditor() {
|
||||||
const activeTabContext = appContext.getActiveTabContext();
|
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 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
|
// 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
|
$(window).on('beforeunload', () => { saveNotesIfChanged(); }); // don't convert to short form, handler doesn't like returned promise
|
||||||
|
|
||||||
setInterval(saveNotesIfChanged, 3000);
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
reload,
|
reload,
|
||||||
openInTab,
|
openInTab,
|
||||||
@ -222,7 +210,6 @@ export default {
|
|||||||
loadNoteDetail,
|
loadNoteDetail,
|
||||||
focusOnTitle,
|
focusOnTitle,
|
||||||
focusAndSelectTitle,
|
focusAndSelectTitle,
|
||||||
saveNotesIfChanged,
|
|
||||||
onNoteChange,
|
onNoteChange,
|
||||||
addDetailLoadedListener,
|
addDetailLoadedListener,
|
||||||
getActiveEditor,
|
getActiveEditor,
|
||||||
|
36
src/public/javascripts/services/spaced_update.js
Normal file
36
src/public/javascripts/services/spaced_update.js
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,6 @@ class TabContext extends Component {
|
|||||||
|
|
||||||
this.tabRow = tabRow;
|
this.tabRow = tabRow;
|
||||||
this.tabId = state.tabId || utils.randomString(4);
|
this.tabId = state.tabId || utils.randomString(4);
|
||||||
this.$tab = $(this.tabRow.addTab(this.tabId));
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
|
||||||
this.attributes = new Attributes(this.appContext, this);
|
this.attributes = new Attributes(this.appContext, this);
|
||||||
|
@ -374,6 +374,7 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
|
|||||||
window.cutToNote.removeSelection();
|
window.cutToNote.removeSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME
|
||||||
await noteDetailService.saveNotesIfChanged();
|
await noteDetailService.saveNotesIfChanged();
|
||||||
|
|
||||||
noteDetailService.addDetailLoadedListener(note.noteId, noteDetailService.focusAndSelectTitle);
|
noteDetailService.addDetailLoadedListener(note.noteId, noteDetailService.focusAndSelectTitle);
|
||||||
|
@ -2,6 +2,8 @@ import TabAwareWidget from "./tab_aware_widget.js";
|
|||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
import protectedSessionHolder from "../services/protected_session_holder.js";
|
import protectedSessionHolder from "../services/protected_session_holder.js";
|
||||||
import appContext from "../services/app_context.js";
|
import appContext from "../services/app_context.js";
|
||||||
|
import SpacedUpdate from "../services/spaced_update.js";
|
||||||
|
import server from "../services/server.js";
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
<div class="note-detail">
|
<div class="note-detail">
|
||||||
@ -32,6 +34,19 @@ export default class NoteDetailWidget extends TabAwareWidget {
|
|||||||
|
|
||||||
this.typeWidgets = {};
|
this.typeWidgets = {};
|
||||||
this.typeWidgetPromises = {};
|
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() {
|
doRender() {
|
||||||
@ -114,12 +129,14 @@ export default class NoteDetailWidget extends TabAwareWidget {
|
|||||||
async initWidgetType(type) {
|
async initWidgetType(type) {
|
||||||
const clazz = await import(typeWidgetClasses[type]);
|
const clazz = await import(typeWidgetClasses[type]);
|
||||||
|
|
||||||
this.typeWidgets[this.type] = new clazz.default(this.appContext);
|
const typeWidget = this.typeWidgets[this.type] = new clazz.default(this.appContext);
|
||||||
this.children.push(this.typeWidgets[this.type]);
|
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) {
|
getWidgetType(disableAutoBook) {
|
||||||
@ -153,4 +170,16 @@ export default class NoteDetailWidget extends TabAwareWidget {
|
|||||||
widget.focus();
|
widget.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async beforeNoteSwitchListener({tabId}) {
|
||||||
|
if (this.isTab(tabId)) {
|
||||||
|
await this.spacedUpdate.updateNowIfNecessary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async beforeTabRemoveListener({tabId}) {
|
||||||
|
if (this.isTab(tabId)) {
|
||||||
|
await this.spacedUpdate.updateNowIfNecessary();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ import utils from "../services/utils.js";
|
|||||||
import protectedSessionHolder from "../services/protected_session_holder.js";
|
import protectedSessionHolder from "../services/protected_session_holder.js";
|
||||||
import treeCache from "../services/tree_cache.js";
|
import treeCache from "../services/tree_cache.js";
|
||||||
import server from "../services/server.js";
|
import server from "../services/server.js";
|
||||||
|
import SpacedUpdate from "../services/spaced_update.js";
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
<div class="note-title-container">
|
<div class="note-title-container">
|
||||||
@ -24,43 +25,6 @@ const TPL = `
|
|||||||
<input autocomplete="off" value="" class="note-title" tabindex="1">
|
<input autocomplete="off" value="" class="note-title" tabindex="1">
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
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 {
|
export default class NoteTitleWidget extends TabAwareWidget {
|
||||||
constructor(appContext) {
|
constructor(appContext) {
|
||||||
super(appContext);
|
super(appContext);
|
||||||
|
@ -109,6 +109,7 @@ class CodeTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure note is saved so we load latest changes
|
// make sure note is saved so we load latest changes
|
||||||
|
// FIXME
|
||||||
await noteDetailService.saveNotesIfChanged();
|
await noteDetailService.saveNotesIfChanged();
|
||||||
|
|
||||||
if (this.tabContext.note.mime.endsWith("env=frontend")) {
|
if (this.tabContext.note.mime.endsWith("env=frontend")) {
|
||||||
@ -122,7 +123,9 @@ class CodeTypeWidget extends TypeWidget {
|
|||||||
toastService.showMessage("Note executed");
|
toastService.showMessage("Note executed");
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoteChange(func) {
|
async onNoteChange(func) {
|
||||||
|
await this.initialized;
|
||||||
|
|
||||||
this.codeEditor.on('change', func);
|
this.codeEditor.on('change', func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ class NoteDetailSearch {
|
|||||||
this.$refreshButton = ctx.$tabContent.find('.note-detail-search-refresh-results-button');
|
this.$refreshButton = ctx.$tabContent.find('.note-detail-search-refresh-results-button');
|
||||||
|
|
||||||
this.$refreshButton.on('click', async () => {
|
this.$refreshButton.on('click', async () => {
|
||||||
|
// FIXME
|
||||||
await noteDetailService.saveNotesIfChanged();
|
await noteDetailService.saveNotesIfChanged();
|
||||||
|
|
||||||
await searchNotesService.refreshSearch();
|
await searchNotesService.refreshSearch();
|
||||||
|
@ -174,7 +174,9 @@ class TextTypeWidget extends TypeWidget {
|
|||||||
return this.textEditor;
|
return this.textEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoteChange(func) {
|
async onNoteChange(func) {
|
||||||
|
await this.initialized;
|
||||||
|
|
||||||
this.textEditor.model.document.on('change:data', func);
|
this.textEditor.model.document.on('change:data', func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user