Skip to content

Commit 7ba504f

Browse files
committed
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
1 parent 7544879 commit 7ba504f

File tree

1 file changed

+44
-92
lines changed

1 file changed

+44
-92
lines changed

apps/client/src/widgets/note_detail.ts

+44-92
Original file line numberDiff line numberDiff line change
@@ -405,114 +405,66 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
405405

406406
async readOnlyTemporarilyDisabledEvent({ noteContext }: EventData<"readOnlyTemporarilyDisabled">) {
407407
if (this.isNoteContext(noteContext.ntxId)) {
408-
// First check if we're dealing with a text editor
409-
const isTextWidget = this.type === "editableText" || this.type === "readOnlyText";
408+
// Check if we're dealing with a text note/editor type
409+
const isTextNote = this.type === "editableText" || this.type === "readOnlyText";
410410

411-
// Only attempt to preserve cursor position for text editors
412-
if (isTextWidget) {
413-
// Store selection state before refresh
414-
let selectionData = null;
415-
const editor = await this.noteContext?.getTextEditor();
411+
if (isTextNote) {
412+
// Get current editor and selection before refresh
413+
const currentEditor = await this.noteContext?.getTextEditor();
414+
let cursorInfo = null;
416415

417-
if (editor) {
416+
if (currentEditor) {
418417
try {
419-
// CKEditor stores selection in the model document
420-
const selection = editor.model.document.selection;
421-
422-
// Store the path to the position and selection direction
423-
if (selection && !selection.isCollapsed) {
424-
// For a range selection
425-
const firstPos = selection.getFirstPosition();
426-
const lastPos = selection.getLastPosition();
427-
428-
if (firstPos && lastPos) {
429-
selectionData = {
430-
// Store path arrays that can be used to find the position again
431-
firstPath: firstPos.path.map(p => p),
432-
firstOffset: firstPos.offset,
433-
lastPath: lastPos.path.map(p => p),
434-
lastOffset: lastPos.offset,
435-
isBackward: selection.isBackward
436-
};
437-
}
438-
} else if (selection) {
439-
// For a collapsed selection (just cursor)
418+
const selection = currentEditor.model.document.selection;
419+
if (selection) {
440420
const cursorPos = selection.getFirstPosition();
441-
442421
if (cursorPos) {
443-
selectionData = {
444-
firstPath: cursorPos.path.map(p => p),
445-
firstOffset: cursorPos.offset,
446-
isCollapsed: true
422+
// Store minimal info about cursor position to restore later
423+
cursorInfo = {
424+
// Store paragraph index and character offset
425+
paraIndex: cursorPos.path[0] || 0,
426+
offset: cursorPos.offset
447427
};
448428
}
449429
}
450430
} catch (e) {
451-
console.warn("Failed to capture selection before refresh", e);
431+
// Ignore errors in getting selection
452432
}
453433
}
454434

455-
// Perform the normal refresh operation
435+
// Perform refresh to transition editor
456436
await this.refresh();
457437

458-
// Restore cursor/selection after refresh if we captured valid data
459-
if (selectionData) {
460-
// Need to wait a bit for the editor to be fully initialized
461-
setTimeout(async () => {
462-
const newEditor = await this.noteContext?.getTextEditor();
463-
464-
if (newEditor) {
465-
try {
466-
newEditor.model.change(writer => {
467-
const root = newEditor.model.document.getRoot();
468-
469-
if (!root) return;
438+
// Immediately attempt to restore cursor position without delay
439+
if (cursorInfo) {
440+
const newEditor = await this.noteContext?.getTextEditor();
441+
if (newEditor) {
442+
try {
443+
newEditor.model.change(writer => {
444+
const root = newEditor.model.document.getRoot();
445+
if (!root) return;
446+
447+
// Find the paragraph at the same index or closest available
448+
const targetParaIndex = Math.min(cursorInfo.paraIndex, root.childCount - 1);
449+
const paragraph = root.getChild(targetParaIndex);
450+
451+
if (paragraph) {
452+
// Use an explicit cast to access maxOffset
453+
const maxOffset = (paragraph as any).maxOffset || 0;
454+
const safeOffset = Math.min(cursorInfo.offset, maxOffset);
470455

471-
// Try to restore the cursor position or selection after refresh
472-
// This is a simpler approach that works well without complex path traversal
473-
try {
474-
if (selectionData) {
475-
// Get the stored paragraph index and character offset
476-
const paragraphIndex = selectionData.firstPath?.[0] || 0;
477-
const charOffset = selectionData.firstOffset || 0;
478-
479-
// First try to get the paragraph at the original index
480-
const childCount = root.childCount;
481-
const safeParaIndex = Math.min(paragraphIndex, childCount - 1);
482-
const paragraph = root.getChild(safeParaIndex);
483-
484-
if (paragraph) {
485-
// Find a safe offset to place the cursor
486-
// Use the getMaxOffset() method to get the maximum allowed offset
487-
// TypeScript doesn't know this method exists, but CKEditor models have it
488-
const maxOffset = (paragraph as any).maxOffset || 0;
489-
const safeOffset = Math.min(charOffset, maxOffset);
490-
491-
// Set the cursor position
492-
const position = writer.createPositionAt(paragraph, safeOffset);
493-
writer.setSelection(position);
494-
} else {
495-
// If we can't find the paragraph, just position at the root start
496-
const position = writer.createPositionAt(root, 0);
497-
writer.setSelection(position);
498-
}
499-
}
500-
} catch (e) {
501-
console.warn("Could not restore cursor position", e);
502-
// Still try a basic cursor position as a last resort
503-
try {
504-
const position = writer.createPositionAt(root, 0);
505-
writer.setSelection(position);
506-
} catch {
507-
// Give up silently if nothing works
508-
}
509-
}
510-
});
511-
} catch (e) {
512-
console.warn("Failed to restore cursor/selection after refresh", e);
513-
}
456+
// Set cursor at the preserved position
457+
const position = writer.createPositionAt(paragraph, safeOffset);
458+
writer.setSelection(position);
459+
}
460+
});
461+
462+
// Focus editor to make cursor visible immediately
463+
newEditor.editing.view.focus();
464+
} catch (e) {
465+
// Silently fail if we can't restore cursor
514466
}
515-
}, 50); // Small delay to ensure editor is ready
467+
}
516468
}
517469
} else {
518470
// Not a text editor, just do a regular refresh

0 commit comments

Comments
 (0)