diff --git a/src/events.ts b/src/events.ts index 9fd3e95..28c6f9e 100644 --- a/src/events.ts +++ b/src/events.ts @@ -202,10 +202,10 @@ class AddonEvents extends AddonBase { message: EditorMessage ) { await instance._initPromise; - let editor: Element = this._Addon.views.getEditor( + let editorElement: Element = this._Addon.views.getEditorElement( instance._iframeWindow.document ); - editor.addEventListener(event, (e: XULEvent) => { + editorElement.addEventListener(event, (e: XULEvent) => { message.content.event = e; message.content.editorInstance = instance; this.onEditorEvent(message); diff --git a/src/knowledge.ts b/src/knowledge.ts index 5a1476b..9798c3b 100644 --- a/src/knowledge.ts +++ b/src/knowledge.ts @@ -212,67 +212,79 @@ class Knowledge extends AddonBase { } let noteLines = noteText.split("\n").filter((e) => e); - let tagStack = []; - let toPush = []; - let toRemove = 0; + // A cache for temporarily stored lines + let previousLineCache = []; + let nextLineCache = []; - let nextAppend = false; - - const forceInline = ["table", "blockquote", "pre", "li"]; - const selfInline = ["ol", "ul"]; + const forceInline = ["table", "blockquote", "pre"]; + const selfInline = ["ol", "ul", "li"]; + let forceInlineStack = []; + let forceInlineFlag = false; + let selfInlineFlag = false; const parsedLines = []; for (let line of noteLines) { + // restore self inline flag + selfInlineFlag = false; + + // For self inline tags, cache start as previous line and end as next line for (const tag of forceInline) { const startReg = `<${tag}>`; + const isStart = line.includes(startReg); + if (isStart) { + forceInlineStack.push(tag); + forceInlineFlag = true; + break; + } const endReg = ``; - const startIdx = line.search(startReg); - const endIdx = line.search(endReg); - if (startIdx !== -1 && endIdx === -1) { - toPush.push(tag); - } else if (endIdx !== -1) { - toRemove += 1; - } - } - - if (tagStack.filter((e) => forceInline.indexOf(e) !== -1).length === 0) { - let nextLoop = false; - for (const tag of selfInline) { - const startReg = new RegExp(`<${tag}>`); - const endReg = new RegExp(``); - const startIdx = line.search(startReg); - const endIdx = line.search(endReg); - if (startIdx !== -1 && endIdx === -1) { - nextAppend = true; - nextLoop = true; - parsedLines.push(line); - break; + const isEnd = line.includes(endReg); + if (isEnd) { + forceInlineStack.pop(); + // Exit force inline mode if the stack is empty + if (forceInlineStack.length === 0) { + forceInlineFlag = false; } - if (endIdx !== -1) { - parsedLines[parsedLines.length - 1] += `\n${line}`; - nextLoop = true; - break; - } - } - if (nextLoop) { - continue; + break; } } - if (tagStack.length === 0 && !nextAppend) { - parsedLines.push(line); - } else { - parsedLines[parsedLines.length - 1] += `\n${line}`; - nextAppend = false; + // For self inline tags, cache start as previous line and end as next line + for (const tag of selfInline) { + const isStart = line.includes(`<${tag}>`); + if (isStart) { + selfInlineFlag = true; + nextLineCache.push(line); + break; + } + const isEnd = line.includes(``); + if (isEnd) { + selfInlineFlag = true; + previousLineCache.push(line); + break; + } } - if (toPush.length > 0) { - tagStack = tagStack.concat(toPush); - toPush = []; - } - while (toRemove > 0) { - tagStack.pop(); - toRemove -= 1; + if (!selfInlineFlag && !forceInlineFlag) { + // Append cache to previous line + if (previousLineCache.length) { + parsedLines[parsedLines.length - 1] += `\n${previousLineCache.join( + "\n" + )}`; + previousLineCache = []; + } + let nextLine = ""; + // Append cache to next line + if (nextLineCache.length) { + nextLine = nextLineCache.join("\n"); + nextLineCache = []; + } + if (nextLine) { + nextLine += "\n"; + } + nextLine += `${line}`; + parsedLines.push(nextLine); + } else if (forceInlineFlag) { + nextLineCache.push(line); } } return parsedLines; @@ -327,10 +339,7 @@ class Knowledge extends AddonBase { async scrollWithRefresh(lineIndex: number) { await Zotero.Promise.delay(500); let editorInstance = await this.getWorkspaceEditorInstance(); - this._Addon.views.scrollToLine( - editorInstance, - lineIndex - ); + this._Addon.views.scrollToLine(editorInstance, lineIndex); this._Addon.events.onEditorEvent( new EditorMessage("enterWorkspace", { editorInstance: editorInstance, diff --git a/src/views.ts b/src/views.ts index b3e0cac..ae72cf0 100644 --- a/src/views.ts +++ b/src/views.ts @@ -34,7 +34,7 @@ class AddonViews extends AddonBase { this._texNotes = []; } - getEditor(_document: Document) { + getEditorElement(_document: Document): Element { let editor = _document.getElementsByClassName("primary-editor")[0]; return editor; } @@ -257,27 +257,23 @@ class AddonViews extends AddonBase { async scrollToLine(instance: EditorInstance, lineIndex: number) { await instance._initPromise; - let editor = this.getEditor(instance._iframeWindow.document); + let editorElement = this.getEditorElement(instance._iframeWindow.document); const eleList = []; const diveTagNames = ["OL", "UL", "LI"]; function dive(e: Element, targetIndex: string) { - if (diveTagNames.indexOf(e.tagName) !== -1) { - if ( - e.tagName === "LI" && - e.parentElement.parentElement.className.includes("primary-editor") - ) { + for (let _e of e.children) { + if (diveTagNames.includes(_e.tagName)) { + dive(_e, targetIndex); + } else { eleList.push(e); } - for (let i in e.children) { - dive(e.children[i], targetIndex); - } } } - const nodes = Array.from(editor.children); + const nodes = Array.from(editorElement.children); for (let i in nodes) { const ele = nodes[i]; - if (diveTagNames.indexOf(ele.tagName) !== -1) { + if (diveTagNames.includes(ele.tagName)) { dive(ele, i); } else { eleList.push(ele); @@ -292,7 +288,7 @@ class AddonViews extends AddonBase { // @ts-ignore const scrollNum = eleList[lineIndex].offsetTop; - (editor.parentNode as HTMLElement).scrollTo(0, scrollNum); + (editorElement.parentNode as HTMLElement).scrollTo(0, scrollNum); const texView = instance._iframeWindow.document.getElementById("texView"); if (texView) {