mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-08-11 19:22:31 +08:00
feat(client): support temporarily disabling read-only note when read-only threshold is triggered
feat(client): stop the cursor from going to the top of the note when note transitions to read-only but we're still editing feat(client): stop the cursor from going to the top of the note when note transitions to read-only but we're still editing, take 2
This commit is contained in:
parent
ae83f0a1c7
commit
f07ad03343
@ -128,11 +128,50 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if note is read-only before attempting to save
|
||||||
|
const isReadOnlyBefore = await this.noteContext.isReadOnly();
|
||||||
|
|
||||||
|
// If the note is read-only due to size but user is still editing,
|
||||||
|
// we need to temporarily disable read-only mode
|
||||||
|
if (isReadOnlyBefore && !this.noteContext.viewScope?.readOnlyTemporarilyDisabled) {
|
||||||
|
// Auto-enable temporary edit mode (same as "Edit this note" button)
|
||||||
|
if (this.noteContext.viewScope) {
|
||||||
|
this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||||
|
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protectedSessionHolder.touchProtectedSessionIfNecessary(note);
|
protectedSessionHolder.touchProtectedSessionIfNecessary(note);
|
||||||
|
|
||||||
|
try {
|
||||||
await server.put(`notes/${noteId}/data`, data, this.componentId);
|
await server.put(`notes/${noteId}/data`, data, this.componentId);
|
||||||
|
|
||||||
this.getTypeWidget().dataSaved();
|
this.getTypeWidget().dataSaved();
|
||||||
|
|
||||||
|
// Check if this save operation made the note cross the threshold
|
||||||
|
if (!isReadOnlyBefore && (await this.noteContext.isReadOnly())) {
|
||||||
|
// Note just became read-only after this save - enable temporary edit mode
|
||||||
|
if (this.noteContext.viewScope) {
|
||||||
|
this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||||
|
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// If save failed because the note just became read-only,
|
||||||
|
// enable temporary edit mode and try again
|
||||||
|
if (!isReadOnlyBefore && (await this.noteContext.isReadOnly())) {
|
||||||
|
if (this.noteContext.viewScope) {
|
||||||
|
this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||||
|
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext });
|
||||||
|
|
||||||
|
// Try saving again with temporary edit mode enabled
|
||||||
|
await server.put(`notes/${noteId}/data`, data, this.componentId);
|
||||||
|
this.getTypeWidget().dataSaved();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For other errors, just rethrow
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
appContext.addBeforeUnloadListener(this);
|
appContext.addBeforeUnloadListener(this);
|
||||||
@ -364,9 +403,73 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
|
|||||||
return this.spacedUpdate.isAllSavedAndTriggerUpdate();
|
return this.spacedUpdate.isAllSavedAndTriggerUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
readOnlyTemporarilyDisabledEvent({ noteContext }: EventData<"readOnlyTemporarilyDisabled">) {
|
async readOnlyTemporarilyDisabledEvent({ noteContext }: EventData<"readOnlyTemporarilyDisabled">) {
|
||||||
if (this.isNoteContext(noteContext.ntxId)) {
|
if (this.isNoteContext(noteContext.ntxId)) {
|
||||||
this.refresh();
|
// Check if we're dealing with a text note/editor type
|
||||||
|
const isTextNote = this.type === "editableText" || this.type === "readOnlyText";
|
||||||
|
|
||||||
|
if (isTextNote) {
|
||||||
|
// Get current editor and selection before refresh
|
||||||
|
const currentEditor = await this.noteContext?.getTextEditor();
|
||||||
|
let cursorInfo = null;
|
||||||
|
|
||||||
|
if (currentEditor) {
|
||||||
|
try {
|
||||||
|
const selection = currentEditor.model.document.selection;
|
||||||
|
if (selection) {
|
||||||
|
const cursorPos = selection.getFirstPosition();
|
||||||
|
if (cursorPos) {
|
||||||
|
// Store minimal info about cursor position to restore later
|
||||||
|
cursorInfo = {
|
||||||
|
// Store paragraph index and character offset
|
||||||
|
paraIndex: cursorPos.path[0] || 0,
|
||||||
|
offset: cursorPos.offset
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore errors in getting selection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform refresh to transition editor
|
||||||
|
await this.refresh();
|
||||||
|
|
||||||
|
// Immediately attempt to restore cursor position without delay
|
||||||
|
if (cursorInfo) {
|
||||||
|
const newEditor = await this.noteContext?.getTextEditor();
|
||||||
|
if (newEditor) {
|
||||||
|
try {
|
||||||
|
newEditor.model.change(writer => {
|
||||||
|
const root = newEditor.model.document.getRoot();
|
||||||
|
if (!root) return;
|
||||||
|
|
||||||
|
// Find the paragraph at the same index or closest available
|
||||||
|
const targetParaIndex = Math.min(cursorInfo.paraIndex, root.childCount - 1);
|
||||||
|
const paragraph = root.getChild(targetParaIndex);
|
||||||
|
|
||||||
|
if (paragraph) {
|
||||||
|
// Use an explicit cast to access maxOffset
|
||||||
|
const maxOffset = (paragraph as any).maxOffset || 0;
|
||||||
|
const safeOffset = Math.min(cursorInfo.offset, maxOffset);
|
||||||
|
|
||||||
|
// Set cursor at the preserved position
|
||||||
|
const position = writer.createPositionAt(paragraph, safeOffset);
|
||||||
|
writer.setSelection(position);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Focus editor to make cursor visible immediately
|
||||||
|
newEditor.editing.view.focus();
|
||||||
|
} catch (e) {
|
||||||
|
// Silently fail if we can't restore cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not a text editor, just do a regular refresh
|
||||||
|
await this.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user