chore(client/ts): port more dialogs

This commit is contained in:
Elian Doran 2025-03-19 23:06:16 +02:00
parent fac575bd4a
commit d0e33f8aaa
No known key found for this signature in database
4 changed files with 69 additions and 21 deletions

View File

@ -283,6 +283,7 @@ declare global {
getLastPosition(): undefined | TextPosition; getLastPosition(): undefined | TextPosition;
} }
}, },
insertContent(modelFragment: any, selection: any);
change(cb: (writer: Writer) => void) change(cb: (writer: Writer) => void)
}, },
editing: { editing: {
@ -311,6 +312,12 @@ declare global {
plugins: { plugins: {
get(command: string) get(command: string)
}, },
data: {
processor: {
toView(html: string);
};
toModel(viewFeragment: any);
},
getData(): string; getData(): string;
setData(data: string): void; setData(data: string): void;
getSelectedHtml(): string; getSelectedHtml(): string;

View File

@ -28,6 +28,13 @@ const TPL = `<div class="jump-to-note-dialog modal mx-auto" tabindex="-1" role="
const KEEP_LAST_SEARCH_FOR_X_SECONDS = 120; const KEEP_LAST_SEARCH_FOR_X_SECONDS = 120;
export default class JumpToNoteDialog extends BasicWidget { export default class JumpToNoteDialog extends BasicWidget {
private lastOpenedTs: number;
private modal!: bootstrap.Modal;
private $autoComplete!: JQuery<HTMLElement>;
private $results!: JQuery<HTMLElement>;
private $showInFullTextButton!: JQuery<HTMLElement>;
constructor() { constructor() {
super(); super();
@ -36,7 +43,7 @@ export default class JumpToNoteDialog extends BasicWidget {
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.modal = Modal.getOrCreateInstance(this.$widget); this.modal = Modal.getOrCreateInstance(this.$widget[0]);
this.$autoComplete = this.$widget.find(".jump-to-note-autocomplete"); this.$autoComplete = this.$widget.find(".jump-to-note-autocomplete");
this.$results = this.$widget.find(".jump-to-note-results"); this.$results = this.$widget.find(".jump-to-note-results");
@ -54,17 +61,17 @@ export default class JumpToNoteDialog extends BasicWidget {
function reposition() { function reposition() {
const offset = 100; const offset = 100;
const modalHeight = window.visualViewport.height - offset; const modalHeight = (window.visualViewport?.height ?? 0) - offset;
const safeAreaInsetBottom = window.visualViewport.height - window.innerHeight; const safeAreaInsetBottom = (window.visualViewport?.height ?? 0) - window.innerHeight;
el.style.height = `${modalHeight}px`; el.style.height = `${modalHeight}px`;
el.style.bottom = `${window.visualViewport.height - modalHeight - safeAreaInsetBottom - offset}px`; el.style.bottom = `${(window.visualViewport?.height ?? 0) - modalHeight - safeAreaInsetBottom - offset}px`;
} }
this.$autoComplete.on("focus", () => { this.$autoComplete.on("focus", () => {
reposition(); reposition();
}); });
window.visualViewport.addEventListener("resize", () => { window.visualViewport?.addEventListener("resize", () => {
reposition(); reposition();
}); });
@ -84,7 +91,7 @@ export default class JumpToNoteDialog extends BasicWidget {
allowCreatingNotes: true, allowCreatingNotes: true,
hideGoToSelectedNoteButton: true, hideGoToSelectedNoteButton: true,
allowJumpToSearchNotes: true, allowJumpToSearchNotes: true,
container: this.$results container: this.$results[0]
}) })
// clear any event listener added in previous invocation of this function // clear any event listener added in previous invocation of this function
.off("autocomplete:noteselected") .off("autocomplete:noteselected")
@ -93,7 +100,7 @@ export default class JumpToNoteDialog extends BasicWidget {
return false; return false;
} }
appContext.tabManager.getActiveContext().setNote(suggestion.notePath); appContext.tabManager.getActiveContext()?.setNote(suggestion.notePath);
}); });
// if you open the Jump To dialog soon after using it previously, it can often mean that you // if you open the Jump To dialog soon after using it previously, it can often mean that you
@ -112,15 +119,14 @@ export default class JumpToNoteDialog extends BasicWidget {
} }
} }
showInFullText(e) { showInFullText(e: JQuery.TriggeredEvent) {
// stop from propagating upwards (dangerous, especially with ctrl+enter executable javascript notes) // stop from propagating upwards (dangerous, especially with ctrl+enter executable javascript notes)
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
const searchString = this.$autoComplete.val(); const searchString = String(this.$autoComplete.val());
this.triggerCommand("searchNotes", { searchString }); this.triggerCommand("searchNotes", { searchString });
this.modal.hide(); this.modal.hide();
} }
} }

View File

@ -27,7 +27,17 @@ const TPL = `
</div> </div>
</div>`; </div>`;
interface RenderMarkdownResponse {
htmlContent: string;
}
export default class MarkdownImportDialog extends BasicWidget { export default class MarkdownImportDialog extends BasicWidget {
private lastOpenedTs: number;
private modal!: bootstrap.Modal;
private $importTextarea!: JQuery<HTMLElement>;
private $importButton!: JQuery<HTMLElement>;
constructor() { constructor() {
super(); super();
@ -36,7 +46,7 @@ export default class MarkdownImportDialog extends BasicWidget {
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.modal = Modal.getOrCreateInstance(this.$widget); this.modal = Modal.getOrCreateInstance(this.$widget[0]);
this.$importTextarea = this.$widget.find(".markdown-import-textarea"); this.$importTextarea = this.$widget.find(".markdown-import-textarea");
this.$importButton = this.$widget.find(".markdown-import-button"); this.$importButton = this.$widget.find(".markdown-import-button");
@ -47,10 +57,13 @@ export default class MarkdownImportDialog extends BasicWidget {
shortcutService.bindElShortcut(this.$widget, "ctrl+return", () => this.sendForm()); shortcutService.bindElShortcut(this.$widget, "ctrl+return", () => this.sendForm());
} }
async convertMarkdownToHtml(markdownContent) { async convertMarkdownToHtml(markdownContent: string) {
const { htmlContent } = await server.post("other/render-markdown", { markdownContent }); const { htmlContent } = await server.post<RenderMarkdownResponse>("other/render-markdown", { markdownContent });
const textEditor = await appContext.tabManager.getActiveContext().getTextEditor(); const textEditor = await appContext.tabManager.getActiveContext()?.getTextEditor();
if (!textEditor) {
return;
}
const viewFragment = textEditor.data.processor.toView(htmlContent); const viewFragment = textEditor.data.processor.toView(htmlContent);
const modelFragment = textEditor.data.toModel(viewFragment); const modelFragment = textEditor.data.toModel(viewFragment);
@ -80,7 +93,7 @@ export default class MarkdownImportDialog extends BasicWidget {
} }
async sendForm() { async sendForm() {
const text = this.$importTextarea.val(); const text = String(this.$importTextarea.val());
this.modal.hide(); this.modal.hide();

View File

@ -6,6 +6,7 @@ import branchService from "../../services/branches.js";
import treeService from "../../services/tree.js"; import treeService from "../../services/tree.js";
import BasicWidget from "../basic_widget.js"; import BasicWidget from "../basic_widget.js";
import { t } from "../../services/i18n.js"; import { t } from "../../services/i18n.js";
import type { EventData } from "../../components/app_context.js";
const TPL = ` const TPL = `
<div class="move-to-dialog modal mx-auto" tabindex="-1" role="dialog"> <div class="move-to-dialog modal mx-auto" tabindex="-1" role="dialog">
@ -39,6 +40,12 @@ const TPL = `
</div>`; </div>`;
export default class MoveToDialog extends BasicWidget { export default class MoveToDialog extends BasicWidget {
private movedBranchIds: string[] | null;
private $form!: JQuery<HTMLElement>;
private $noteAutoComplete!: JQuery<HTMLElement>;
private $noteList!: JQuery<HTMLElement>;
constructor() { constructor() {
super(); super();
@ -58,7 +65,13 @@ export default class MoveToDialog extends BasicWidget {
this.$widget.modal("hide"); this.$widget.modal("hide");
const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath); const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath);
froca.getBranchId(parentNoteId, noteId).then((branchId) => this.moveNotesTo(branchId)); if (parentNoteId) {
froca.getBranchId(parentNoteId, noteId).then((branchId) => {
if (branchId) {
this.moveNotesTo(branchId);
}
});
}
} else { } else {
logError(t("move_to.error_no_path")); logError(t("move_to.error_no_path"));
} }
@ -67,7 +80,7 @@ export default class MoveToDialog extends BasicWidget {
}); });
} }
async moveBranchIdsToEvent({ branchIds }) { async moveBranchIdsToEvent({ branchIds }: EventData<"moveBranchIdsTo">) {
this.movedBranchIds = branchIds; this.movedBranchIds = branchIds;
utils.openDialog(this.$widget); utils.openDialog(this.$widget);
@ -78,7 +91,14 @@ export default class MoveToDialog extends BasicWidget {
for (const branchId of this.movedBranchIds) { for (const branchId of this.movedBranchIds) {
const branch = froca.getBranch(branchId); const branch = froca.getBranch(branchId);
if (!branch) {
continue;
}
const note = await froca.getNote(branch.noteId); const note = await froca.getNote(branch.noteId);
if (!note) {
continue;
}
this.$noteList.append($("<li>").text(note.title)); this.$noteList.append($("<li>").text(note.title));
} }
@ -87,12 +107,14 @@ export default class MoveToDialog extends BasicWidget {
noteAutocompleteService.showRecentNotes(this.$noteAutoComplete); noteAutocompleteService.showRecentNotes(this.$noteAutoComplete);
} }
async moveNotesTo(parentBranchId) { async moveNotesTo(parentBranchId: string) {
if (this.movedBranchIds) {
await branchService.moveToParentNote(this.movedBranchIds, parentBranchId); await branchService.moveToParentNote(this.movedBranchIds, parentBranchId);
}
const parentBranch = froca.getBranch(parentBranchId); const parentBranch = froca.getBranch(parentBranchId);
const parentNote = await parentBranch.getNote(); const parentNote = await parentBranch?.getNote();
toastService.showMessage(`${t("move_to.move_success_message")} ${parentNote.title}`); toastService.showMessage(`${t("move_to.move_success_message")} ${parentNote?.title}`);
} }
} }