diff --git a/src/addon.ts b/src/addon.ts index 5028ec0..cf6d93c 100644 --- a/src/addon.ts +++ b/src/addon.ts @@ -1,11 +1,13 @@ import AddonEvents from "./events"; import AddonViews from "./views"; import AddonPrefs from "./prefs"; +import { Knowledge } from "./knowledge"; class Knowledge4Zotero { public events: AddonEvents; public views: AddonViews; public prefs: AddonPrefs; + public knowledge: Knowledge; constructor() { this.events = new AddonEvents(this); diff --git a/src/base.ts b/src/base.ts index de707b5..ef9381a 100644 --- a/src/base.ts +++ b/src/base.ts @@ -8,9 +8,8 @@ class AddonBase { class EditorMessage { public type: string; public content: { - itemID?: string; event?: XULEvent; - editorInstance?: EditorInstance + editorInstance?: EditorInstance; }; constructor(type: string, content: object) { this.type = type; diff --git a/src/events.ts b/src/events.ts index ab10267..054fc3e 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,4 +1,5 @@ import { AddonBase, EditorMessage } from "./base"; +import { Knowledge } from "./knowledge"; class AddonEvents extends AddonBase { constructor(parent: Knowledge4Zotero) { @@ -7,11 +8,12 @@ class AddonEvents extends AddonBase { public async onInit() { Zotero.debug("Knowledge4Zotero: init called"); - this.addNoteInstanceListener(); + this._Addon.knowledge = new Knowledge(undefined); + this.addEditorInstanceListener(); this.resetState(); } - public addNoteInstanceListener() { + public addEditorInstanceListener() { Zotero.Notes._registerEditorInstance = Zotero.Notes.registerEditorInstance; Zotero.Notes.registerEditorInstance = (instance: EditorInstance) => { Zotero.Notes._registerEditorInstance(instance); @@ -28,7 +30,10 @@ class AddonEvents extends AddonBase { event: string, message: EditorMessage ) { - let editor: Element = await this._Addon.views.getEditor(instance); + await instance._initPromise; + let editor: Element = this._Addon.views.getEditor( + instance._iframeWindow.document + ); editor.addEventListener(event, (e: XULEvent) => { message.content.event = e; message.content.editorInstance = instance; @@ -36,6 +41,21 @@ class AddonEvents extends AddonBase { }); } + public async addEditorDocumentEventListener( + instance: EditorInstance, + event: string, + message: EditorMessage + ) { + await instance._initPromise; + let doc: Document = instance._iframeWindow.document; + + doc.addEventListener(event, (e: XULEvent) => { + message.content.event = e; + message.content.editorInstance = instance; + this.onEditorEvent(message); + }); + } + public async onEditorEvent(message: EditorMessage) { Zotero.debug( `Knowledge4Zotero: onEditorEvent\n${message.type}\n${message.content}` @@ -64,21 +84,34 @@ class AddonEvents extends AddonBase { "addToKnowledge", "addToKnowledge", "Add Note Link to Knowledge Workspace", - new EditorMessage("addToKnowledge", {}) + new EditorMessage("addToKnowledge", { + itemID: message.content.editorInstance._item.id, + }) ); this.addEditorEventListener( message.content.editorInstance, "click", new EditorMessage("noteEditorClick", {}) ); + if (!message.content.editorInstance._knowledgeSelectionInitialized) { + this.addEditorDocumentEventListener( + message.content.editorInstance, + "selectionchange", + new EditorMessage("noteEditorSelectionChange", {}) + ); + message.content.editorInstance._knowledgeSelectionInitialized = true; + } } else if (message.type === "addToKnowledge") { /* message.content = { editorInstance } */ - // TODO: Complete this part Zotero.debug("Knowledge4Zotero: addToKnowledge"); + this._Addon.knowledge.addLink( + -1, + message.content.editorInstance._item.id + ); } else if (message.type === "setMainKnowledge") { /* message.content = { @@ -128,19 +161,58 @@ class AddonEvents extends AddonBase { } else if (message.type === "noteEditorClick") { let el: XUL.Element = message.content.event.target; if (el.children.length !== 0) { + // This is not a line element return; } - let urlIndex = el.innerHTML.search(/zotero:\/\/note\//g); - if (urlIndex >= 0) { - let noteID = parseInt( - el.innerHTML.substring(urlIndex + "zotero://note/".length) + if ( + el.tagName === "A" && + (el as HTMLLinkElement).href.search(/zotero:\/\/note\//g) >= 0 + ) { + let urlIndex = (el as HTMLLinkElement).href.search( + /zotero:\/\/note\//g ); - let note = Zotero.Items.get(noteID); - if (note && note.isNote()) { - // TODO: Open note - Zotero.debug(`Knowledge4Zotero: noteEditorClick ${note.id}`); + if (urlIndex >= 0) { + let noteID = parseInt( + (el as HTMLLinkElement).href.substring( + urlIndex + "zotero://note/".length + ) + ); + let note = Zotero.Items.get(noteID); + if (note && note.isNote()) { + // TODO: Open note + Zotero.debug(`Knowledge4Zotero: noteEditorClick ${note.id}`); + } } } + } else if (message.type === "noteEditorSelectionChange") { + if ( + message.content.editorInstance._item.id === + Zotero.Prefs.get("Knowledge4Zotero.mainKnowledgeID") + ) { + // Update current line index + let focusNode = + message.content.editorInstance._iframeWindow.document.getSelection() + .focusNode; + if (!focusNode) { + return; + } + + function getChildIndex(node: Node) { + return Array.prototype.indexOf.call(node.parentNode.childNodes, node); + } + + // Make sure this is a direct child node of editor + while ( + !focusNode.parentElement.className || + focusNode.parentElement.className.indexOf("primary-editor") === -1 + ) { + focusNode = focusNode.parentNode; + } + + let currentLineIndex = getChildIndex(focusNode); + this._Addon.knowledge.currentLine = currentLineIndex; + Zotero.debug(`Knowledge4Zotero: line ${currentLineIndex} selected.`); + } } else { Zotero.debug(`Knowledge4Zotero: message not handled.`); } diff --git a/src/knowledge.ts b/src/knowledge.ts index b8f4c50..7a6d27c 100644 --- a/src/knowledge.ts +++ b/src/knowledge.ts @@ -1,27 +1,104 @@ const TreeModel = require("./treemodel"); class Knowledge { - _note: ZoteroItem; + currentLine: number; constructor(noteItem: ZoteroItem) { - this._note = noteItem; + this.currentLine = 0; // this.createKnowledgeItem(); } // createKnowledgeItem() { // return; // } - addNoteLink(noteItem: ZoteroItem) {} - - getOutline(): Node { - let parser = Components.classes[ - "@mozilla.org/xmlextras/domparser;1" - ].createInstance(Components.interfaces.nsIDOMParser); - let doc = parser.parseFromString(this._note.getNote(), "text/html"); - - let metadataContainer: Element = doc.querySelector( - "body > div[data-schema-version]" + getWorkspaceNote() { + return Zotero.Items.get( + Zotero.Prefs.get("Knowledge4Zotero.mainKnowledgeID") ); + } + getLines(): string[] { + let note = this.getWorkspaceNote(); + if (!note) { + return []; + } + let noteText: string = note.getNote(); + let containerIndex = noteText.search(/