diff --git a/src/public/app/types.d.ts b/src/public/app/types.d.ts index fa06ec614..8c70dc661 100644 --- a/src/public/app/types.d.ts +++ b/src/public/app/types.d.ts @@ -285,12 +285,20 @@ declare global { }); } - type TextEditorElement = {}; + interface Range { + toJSON(): object; + } interface Writer { - setAttribute(name: string, value: string, el: TextEditorElement); - createPositionAt(el: TextEditorElement, opt?: "end"); + setAttribute(name: string, value: string, el: CKNode); + createPositionAt(el: CKNode, opt?: "end" | number); setSelection(pos: number, pos?: number); insertText(text: string, opts: Record | undefined, position?: TextPosition); + addMarker(name: string, opts: { + range: Range; + usingOperation: boolean; + }); + removeMarker(name: string); + createRange(start: number, end: number): Range; } interface TextNode { previousSibling?: TextNode; @@ -308,6 +316,37 @@ declare global { offset: number; compareWith(pos: TextPosition): string; } + + interface TextRange { + + } + + interface Marker { + name: string; + } + + interface CKNode { + name: string; + childCount: number; + isEmpty: boolean; + toJSON(): object; + is(type: string, name?: string); + getAttribute(name: string): string; + getChild(index: number): CKNode; + data: string; + startOffset: number; + root: { + document: { + model: { + createRangeIn(el: CKNode): TextRange; + markers: { + getMarkersIntersectingRange(range: TextRange): Marker[]; + } + } + } + }; + } + interface TextEditor { create(el: HTMLElement, config: { removePlugins?: string[]; @@ -321,10 +360,22 @@ declare global { model: { document: { on(event: string, cb: () => void); - getRoot(): TextEditorElement; + getRoot(): CKNode; + registerPostFixer(callback: (writer: Writer) => boolean); selection: { getFirstPosition(): undefined | TextPosition; getLastPosition(): undefined | TextPosition; + }; + differ: { + getChanges(): { + type: string; + name: string; + position: { + nodeAfter: CKNode; + parent: CKNode; + toJSON(): Object; + } + }[]; } }, insertContent(modelFragment: any, selection: any); @@ -340,7 +391,7 @@ declare global { }) => void, opts?: { priority: "high" }); - getRoot(): TextEditorElement + getRoot(): CKNode }, domRoots: { values: () => { @@ -363,6 +414,16 @@ declare global { }; toModel(viewFeragment: any); }, + conversion: { + for(filter: string): { + markerToHighlight(data: { + model: string; + view: (data: { + markerName: string; + }) => void; + }) + } + } getData(): string; setData(data: string): void; getSelectedHtml(): string; diff --git a/src/public/app/widgets/type_widgets/ckeditor/syntax_highlight.js b/src/public/app/widgets/type_widgets/ckeditor/syntax_highlight.ts similarity index 94% rename from src/public/app/widgets/type_widgets/ckeditor/syntax_highlight.js rename to src/public/app/widgets/type_widgets/ckeditor/syntax_highlight.ts index ab6dd562e..36d7f0f40 100644 --- a/src/public/app/widgets/type_widgets/ckeditor/syntax_highlight.js +++ b/src/public/app/widgets/type_widgets/ckeditor/syntax_highlight.ts @@ -12,7 +12,7 @@ import library_loader from "../../../services/library_loader.js"; import mime_types from "../../../services/mime_types.js"; import { isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js"; -export async function initSyntaxHighlighting(editor) { +export async function initSyntaxHighlighting(editor: TextEditor) { if (!isSyntaxHighlightEnabled) { return; } @@ -25,39 +25,38 @@ const HIGHLIGHT_MAX_BLOCK_COUNT = 500; const tag = "SyntaxHighlightWidget"; const debugLevels = ["error", "warn", "info", "log", "debug"]; -const debugLevel = "debug"; +const debugLevel = debugLevels.indexOf("debug"); -let warn = function () {}; +let warn = function (...args: unknown[]) {}; if (debugLevel >= debugLevels.indexOf("warn")) { warn = console.warn.bind(console, tag + ": "); } -let info = function () {}; +let info = function (...args: unknown[]) {}; if (debugLevel >= debugLevels.indexOf("info")) { info = console.info.bind(console, tag + ": "); } -let log = function () {}; +let log = function (...args: unknown[]) {}; if (debugLevel >= debugLevels.indexOf("log")) { log = console.log.bind(console, tag + ": "); } -let dbg = function () {}; +let dbg = function (...args: unknown[]) {}; if (debugLevel >= debugLevels.indexOf("debug")) { dbg = console.debug.bind(console, tag + ": "); } -function assert(e, msg) { +function assert(e: boolean, msg?: string) { console.assert(e, tag + ": " + msg); } // TODO: Should this be scoped to note? let markerCounter = 0; -function initTextEditor(textEditor) { +function initTextEditor(textEditor: TextEditor) { log("initTextEditor"); - let widget = this; const document = textEditor.model.document; // Create a conversion from model to view that converts @@ -100,7 +99,7 @@ function initTextEditor(textEditor) { // See // https://github.com/ckeditor/ckeditor5/blob/b53d2a4b49679b072f4ae781ac094e7e831cfb14/packages/ckeditor5-block-quote/src/blockquoteediting.js#L54 const changes = document.differ.getChanges(); - let dirtyCodeBlocks = new Set(); + let dirtyCodeBlocks = new Set(); for (const change of changes) { dbg("change " + JSON.stringify(change)); @@ -151,7 +150,7 @@ function initTextEditor(textEditor) { * the formatting would be stored with the note and it would need a * way to remove that formatting when editing back the note. */ -function highlightCodeBlock(codeBlock, writer) { +function highlightCodeBlock(codeBlock: CKNode, writer: Writer) { log("highlighting codeblock " + JSON.stringify(codeBlock.toJSON())); const model = codeBlock.root.document.model; @@ -291,16 +290,16 @@ function highlightCodeBlock(codeBlock, writer) { iHtml = html.indexOf(">", iHtml) + 1; // push the span - let posStart = writer.createPositionAt(codeBlock, child.startOffset + iChildText); + let posStart = writer.createPositionAt(codeBlock, (child?.startOffset ?? 0) + iChildText); spanStack.push({ className: className, posStart: posStart }); } else if (html[iHtml] == "<" && html[iHtml + 1] == "/") { // Done with this span, pop the span and mark the range iHtml = html.indexOf(">", iHtml + 1) + 1; let stackTop = spanStack.pop(); - let posStart = stackTop.posStart; - let className = stackTop.className; - let posEnd = writer.createPositionAt(codeBlock, child.startOffset + iChildText); + let posStart = stackTop?.posStart; + let className = stackTop?.className; + let posEnd = writer.createPositionAt(codeBlock, (child?.startOffset ?? 0) + iChildText); let range = writer.createRange(posStart, posEnd); let markerName = "hljs:" + className + ":" + markerCounter; // Use an incrementing number for the uniqueId, random of