696 lines
20 KiB
TypeScript
696 lines
20 KiB
TypeScript
import { AddonBase, EditorMessage, OutlineType } from "./base";
|
|
|
|
const TreeModel = require("./treemodel");
|
|
|
|
class Knowledge extends AddonBase {
|
|
currentLine: number;
|
|
currentNodeID: number;
|
|
workspaceWindow: Window;
|
|
constructor(parent: Knowledge4Zotero) {
|
|
super(parent);
|
|
this.currentLine = -1;
|
|
this.currentNodeID = -1;
|
|
}
|
|
|
|
getWorkspaceNote() {
|
|
return Zotero.Items.get(
|
|
Zotero.Prefs.get("Knowledge4Zotero.mainKnowledgeID")
|
|
);
|
|
}
|
|
|
|
getWorkspaceWindow(): Window | boolean {
|
|
if (this.workspaceWindow && !this.workspaceWindow.closed) {
|
|
return this.workspaceWindow;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async openWorkspaceWindow() {
|
|
if (this.getWorkspaceWindow()) {
|
|
(this.getWorkspaceWindow() as Window).focus();
|
|
} else {
|
|
this._Addon.views._initIframe = Zotero.Promise.defer();
|
|
let win = window.open(
|
|
"chrome://Knowledge4Zotero/content/workspace.xul",
|
|
"_blank",
|
|
"chrome,extrachrome,menubar,resizable,scrollbars,status,width=1000,height=600"
|
|
);
|
|
this.workspaceWindow = win;
|
|
await this.waitWorkspaceReady();
|
|
win.addEventListener("resize", (e) => {
|
|
this._Addon.views.setTreeViewSize();
|
|
});
|
|
this._Addon.views.bindTreeViewResize();
|
|
this.setWorkspaceNote("main");
|
|
this.currentLine = -1;
|
|
this._Addon.views.initKnowledgeWindow(win);
|
|
this._Addon.views.switchView(OutlineType.treeView);
|
|
this._Addon.views.buildOutline();
|
|
// this._Addon.views.buildMindMap();
|
|
}
|
|
}
|
|
|
|
async waitWorkspaceReady() {
|
|
let _window = this.getWorkspaceWindow() as Window;
|
|
if (!_window) {
|
|
return false;
|
|
}
|
|
let t = 0;
|
|
while (_window.document.readyState !== "complete" && t < 500) {
|
|
t += 1;
|
|
await Zotero.Promise.delay(10);
|
|
}
|
|
return t < 500;
|
|
}
|
|
|
|
async getWorkspaceEditor(type: "main" | "preview" = "main") {
|
|
let _window = this.getWorkspaceWindow() as Window;
|
|
if (!_window) {
|
|
return;
|
|
}
|
|
await this.waitWorkspaceReady();
|
|
return _window.document.getElementById(`zotero-note-editor-${type}`);
|
|
}
|
|
|
|
async getWorkspaceEditorInstance(
|
|
type: "main" | "preview" = "main"
|
|
): Promise<EditorInstance> {
|
|
let noteEditor = (await this.getWorkspaceEditor(type)) as any;
|
|
let t = 0;
|
|
while (!noteEditor.getCurrentInstance() && t < 500) {
|
|
t += 1;
|
|
await Zotero.Promise.delay(10);
|
|
}
|
|
return noteEditor.getCurrentInstance() as EditorInstance;
|
|
}
|
|
|
|
async setWorkspaceNote(
|
|
type: "main" | "preview" = "main",
|
|
note: ZoteroItem = undefined
|
|
) {
|
|
let _window = this.getWorkspaceWindow() as Window;
|
|
note = note || this.getWorkspaceNote();
|
|
if (!_window) {
|
|
return;
|
|
}
|
|
if (type === "preview") {
|
|
_window.document
|
|
.getElementById("preview-splitter")
|
|
.setAttribute("state", "open");
|
|
} else {
|
|
// Set line to default
|
|
this.currentLine = -1;
|
|
}
|
|
await this.waitWorkspaceReady();
|
|
let noteEditor: any = await this.getWorkspaceEditor(type);
|
|
noteEditor.mode = "edit";
|
|
noteEditor.viewMode = "library";
|
|
noteEditor.parent = null;
|
|
noteEditor.item = note;
|
|
|
|
await noteEditor._initPromise;
|
|
let t = 0;
|
|
while (!noteEditor.getCurrentInstance() && t < 500) {
|
|
t += 1;
|
|
await Zotero.Promise.delay(10);
|
|
}
|
|
await this._Addon.events.onEditorEvent(
|
|
new EditorMessage("enterWorkspace", {
|
|
editorInstance: noteEditor.getCurrentInstance(),
|
|
params: type,
|
|
})
|
|
);
|
|
this._Addon.views.buildOutline();
|
|
}
|
|
|
|
getLinesInNote(note: ZoteroItem): string[] {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return [];
|
|
}
|
|
let noteText: string = note.getNote();
|
|
let containerIndex = noteText.search(/data-schema-version="8">/g);
|
|
if (containerIndex != -1) {
|
|
noteText = noteText.substring(
|
|
containerIndex + 'data-schema-version="8">'.length,
|
|
noteText.length - "</div>".length
|
|
);
|
|
}
|
|
let noteLines: string[] = noteText.split("\n");
|
|
|
|
const cacheStart = [/<ol>/g, /<ul>/g, /<li>/g, /<blockquote>/g, /<pre>/g];
|
|
const cacheEnd = [
|
|
/<\/ol>/g,
|
|
/<\/ul>/g,
|
|
/<\/li>/g,
|
|
/<\/blockquote>/g,
|
|
/<\/pre>/g,
|
|
];
|
|
let parsedLines: string[] = [];
|
|
let appendLater: boolean = false;
|
|
let cacheStartLine = false;
|
|
let cachedLines: string = "";
|
|
for (let line of noteLines) {
|
|
cacheStartLine = false;
|
|
if (
|
|
cachedLines ||
|
|
cacheStart.filter((e) => {
|
|
return line.search(e) !== -1;
|
|
}).length > 0
|
|
) {
|
|
appendLater = true;
|
|
cachedLines += `${cachedLines.length > 0 ? "\n" : ""}${line}`;
|
|
cacheStartLine = true;
|
|
}
|
|
if (
|
|
cacheEnd.filter((e) => {
|
|
return line.search(e) !== -1;
|
|
}).length > 0
|
|
) {
|
|
appendLater = false;
|
|
// If already added to cache
|
|
if (!cacheStartLine) {
|
|
cachedLines += `\n${line}`;
|
|
}
|
|
line = cachedLines;
|
|
cachedLines = "";
|
|
}
|
|
if (!appendLater) {
|
|
parsedLines.push(line);
|
|
}
|
|
}
|
|
return parsedLines;
|
|
}
|
|
|
|
setLinesToNote(note: ZoteroItem, noteLines: string[]) {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return [];
|
|
}
|
|
let noteText: string = note.getNote();
|
|
let containerIndex = noteText.search(/data-schema-version="8">/g);
|
|
if (containerIndex === -1) {
|
|
note.setNote(
|
|
`<div data-schema-version="8">${noteLines.join("\n")}</div>`
|
|
);
|
|
} else {
|
|
let noteHead = noteText.substring(0, containerIndex);
|
|
note.setNote(
|
|
`${noteHead}data-schema-version="8">${noteLines.join("\n")}</div>`
|
|
);
|
|
}
|
|
|
|
note.saveTx();
|
|
}
|
|
|
|
getLineParentInNote(
|
|
note: ZoteroItem,
|
|
lineIndex: number = -1
|
|
): TreeModel.Node<object> {
|
|
if (lineIndex < 0) {
|
|
lineIndex = this.currentLine;
|
|
}
|
|
let nodes = this.getNoteTreeAsList(note);
|
|
if (!nodes.length || nodes[0].model.lineIndex > lineIndex) {
|
|
// There is no parent node
|
|
return undefined;
|
|
} else if (nodes[nodes.length - 1].model.lineIndex <= lineIndex) {
|
|
return nodes[nodes.length - 1];
|
|
} else {
|
|
for (let i = 0; i < nodes.length - 1; i++) {
|
|
if (
|
|
nodes[i].model.lineIndex <= lineIndex &&
|
|
nodes[i + 1].model.lineIndex > lineIndex
|
|
) {
|
|
return nodes[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async scrollWithRefresh(lineIndex: number) {
|
|
await Zotero.Promise.delay(500);
|
|
let editorInstance = await this.getWorkspaceEditorInstance();
|
|
this._Addon.views.scrollToLine(
|
|
editorInstance,
|
|
// Scroll to 6 lines before the inserted line
|
|
lineIndex - 5
|
|
);
|
|
this._Addon.events.onEditorEvent(
|
|
new EditorMessage("enterWorkspace", {
|
|
editorInstance: editorInstance,
|
|
params: "main",
|
|
})
|
|
);
|
|
}
|
|
|
|
private addLineToNote(
|
|
note: ZoteroItem,
|
|
text: string,
|
|
lineIndex: number,
|
|
newLine: boolean
|
|
) {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return;
|
|
}
|
|
let noteLines = this.getLinesInNote(note);
|
|
if (newLine) {
|
|
noteLines.splice(lineIndex, 0, "<p> </p>", text);
|
|
} else {
|
|
noteLines.splice(lineIndex, 0, text);
|
|
}
|
|
this.setLinesToNote(note, noteLines);
|
|
}
|
|
|
|
async addSubLineToNote(
|
|
note: ZoteroItem,
|
|
text: string,
|
|
lineIndex: number = -1,
|
|
newLine: boolean = false
|
|
) {
|
|
if (lineIndex < 0) {
|
|
lineIndex =
|
|
this.currentLine >= 0
|
|
? this.currentLine + 2
|
|
: this.getLinesInNote(note).length + 1;
|
|
}
|
|
// let parentNode = this.getLineParentInNote(note, lineIndex);
|
|
// if (!parentNode) {
|
|
// this.addLineToNote(note, text, lineIndex);
|
|
// return;
|
|
// }
|
|
// let nodes = this.getNoteTreeAsList(note);
|
|
// let i = 0;
|
|
// for (let node of nodes) {
|
|
// if (node.model.lineIndex === parentNode.model.lineIndex) {
|
|
// break;
|
|
// }
|
|
// i++;
|
|
// }
|
|
// // Get next header line index
|
|
// i++;
|
|
// if (i >= nodes.length) {
|
|
// i = nodes.length - 1;
|
|
// }
|
|
// Add to next line
|
|
this.addLineToNote(note, text, lineIndex, newLine);
|
|
await this.scrollWithRefresh(lineIndex);
|
|
}
|
|
|
|
addLinkToNote(
|
|
targetNote: ZoteroItem,
|
|
lineIndex: number,
|
|
linkedNoteID: number
|
|
) {
|
|
targetNote = targetNote || this.getWorkspaceNote();
|
|
if (!targetNote) {
|
|
return;
|
|
}
|
|
let linkedNote = Zotero.Items.get(linkedNoteID);
|
|
let libraryID = linkedNote.libraryID;
|
|
let library = Zotero.Libraries.get(libraryID);
|
|
let groupID: string;
|
|
if (library.libraryType === "user") {
|
|
groupID = "u";
|
|
} else if (library.libraryType === "group") {
|
|
groupID = `${library.id}`;
|
|
}
|
|
let noteKey = linkedNote.key;
|
|
let linkText = linkedNote.getNoteTitle().trim();
|
|
this.addSubLineToNote(
|
|
targetNote,
|
|
`<a href="zotero://note/${groupID}/${noteKey}" rel="noopener noreferrer nofollow">${
|
|
linkText ? linkText : `zotero://note/${groupID}/${noteKey}`
|
|
}</a>`,
|
|
lineIndex,
|
|
true
|
|
);
|
|
this._Addon.views.showProgressWindow(
|
|
"Knowledge",
|
|
"Link is added to workspace"
|
|
);
|
|
}
|
|
|
|
async modifyLineInNote(note: ZoteroItem, text: string, lineIndex: number) {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return;
|
|
}
|
|
let noteLines = this.getLinesInNote(note);
|
|
if (lineIndex < 0 || lineIndex >= noteLines.length) {
|
|
return;
|
|
}
|
|
noteLines[lineIndex] = text;
|
|
this.setLinesToNote(note, noteLines);
|
|
await this.scrollWithRefresh(lineIndex);
|
|
}
|
|
|
|
async changeHeadingLineInNote(
|
|
note: ZoteroItem,
|
|
rankChange: number,
|
|
lineIndex: number
|
|
) {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return;
|
|
}
|
|
const noteLines = this.getLinesInNote(note);
|
|
if (lineIndex < 0 || lineIndex >= noteLines.length) {
|
|
return;
|
|
}
|
|
const headerStartReg = new RegExp("<h[1-6]>");
|
|
const headerStopReg = new RegExp("</h[1-6]>");
|
|
let headerStart = noteLines[lineIndex].search(headerStartReg);
|
|
if (headerStart === -1) {
|
|
return;
|
|
}
|
|
let lineRank = parseInt(noteLines[lineIndex][headerStart + 2]) + rankChange;
|
|
if (lineRank > 6) {
|
|
lineRank = 6;
|
|
} else if (lineRank < 1) {
|
|
lineRank = 1;
|
|
}
|
|
noteLines[lineIndex] = noteLines[lineIndex]
|
|
.replace(headerStartReg, `<h${lineRank}>`)
|
|
.replace(headerStopReg, `</h${lineRank}>`);
|
|
this.setLinesToNote(note, noteLines);
|
|
await this.scrollWithRefresh(lineIndex);
|
|
}
|
|
|
|
moveHeaderLineInNote(
|
|
note: ZoteroItem,
|
|
currentNode: TreeModel.Node<object>,
|
|
targetNode: TreeModel.Node<object>,
|
|
as: "child" | "before" | "after"
|
|
) {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note || targetNode.getPath().indexOf(currentNode) >= 0) {
|
|
return undefined;
|
|
}
|
|
|
|
let currentLineRange = this.getNodeLineRangeInNoteTree(note, currentNode);
|
|
let targetLineRange = this.getNodeLineRangeInNoteTree(note, targetNode);
|
|
let targetIndex = 0;
|
|
let targetRank = 1;
|
|
|
|
let lines = this.getLinesInNote(note);
|
|
|
|
if (as === "child") {
|
|
targetIndex = targetLineRange[1];
|
|
targetRank = targetNode.model.rank === 6 ? 6 : targetNode.model.rank + 1;
|
|
} else if (as === "before") {
|
|
targetIndex = targetLineRange[0];
|
|
targetRank = targetNode.model.rank;
|
|
} else if (as === "after") {
|
|
targetIndex = targetLineRange[1];
|
|
targetRank = targetNode.model.rank;
|
|
}
|
|
|
|
if (targetIndex > currentLineRange[1]) {
|
|
targetIndex -= currentLineRange[1] - currentLineRange[0];
|
|
}
|
|
|
|
let rankChange = targetRank - currentNode.model.rank;
|
|
|
|
let movedLines = lines.splice(
|
|
currentLineRange[0],
|
|
currentLineRange[1] - currentLineRange[0]
|
|
);
|
|
|
|
let headerStartReg = new RegExp("<h[1-6]>");
|
|
let headerStopReg = new RegExp("</h[1-6]>");
|
|
for (let i = 0; i < movedLines.length; i++) {
|
|
let headerStart = movedLines[i].search(headerStartReg);
|
|
if (headerStart === -1) {
|
|
continue;
|
|
}
|
|
let lineRank = parseInt(movedLines[i][headerStart + 2]) + rankChange;
|
|
if (lineRank > 6) {
|
|
lineRank = 6;
|
|
} else if (lineRank < 1) {
|
|
lineRank = 1;
|
|
}
|
|
movedLines[i] = movedLines[i]
|
|
.replace(headerStartReg, `<h${lineRank}>`)
|
|
.replace(headerStopReg, `</h${lineRank}>`);
|
|
}
|
|
let newLines = lines
|
|
.slice(0, targetIndex)
|
|
.concat(movedLines, lines.slice(targetIndex));
|
|
this.setLinesToNote(note, newLines);
|
|
}
|
|
|
|
getNoteTree(note: ZoteroItem = undefined): TreeModel.Node<object> {
|
|
// See http://jnuno.com/tree-model-js
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return undefined;
|
|
}
|
|
const noteLines = this.getLinesInNote(note);
|
|
let tree = new TreeModel();
|
|
/*
|
|
tree-model/index.js: line 40
|
|
TreeModel.prototype.parse = function (model) {
|
|
var i, childCount, node;
|
|
Annotate the line 40 of:
|
|
|
|
// if (!(model instanceof Object)) {
|
|
// throw new TypeError('Model must be of type object.');
|
|
// }
|
|
*/
|
|
let root = tree.parse({
|
|
id: -1,
|
|
rank: 0,
|
|
lineIndex: -1,
|
|
endIndex: -1,
|
|
});
|
|
let id = 0;
|
|
let currentNode = root;
|
|
let lastNode = undefined;
|
|
let headerStartReg = new RegExp("<h[1-6]>");
|
|
let headerStopReg = new RegExp("</h[1-6]>");
|
|
for (let i in noteLines) {
|
|
let currentRank = 7;
|
|
let lineElement = noteLines[i];
|
|
const isHeading = lineElement.search(headerStartReg) !== -1;
|
|
const isLink = lineElement.search(/zotero:\/\/note\//g) !== -1;
|
|
if (isHeading || isLink) {
|
|
let name = "";
|
|
let link = "";
|
|
if (isHeading) {
|
|
const startIndex = lineElement.search(headerStartReg);
|
|
const stopIndex = lineElement.search(headerStopReg);
|
|
currentRank = parseInt(
|
|
lineElement.slice(startIndex + 2, startIndex + 3)
|
|
);
|
|
name = lineElement.slice(startIndex + 4, stopIndex);
|
|
} else {
|
|
name = lineElement.slice(lineElement.search(/">/g) + 2);
|
|
name = name.slice(0, name.search(/<\//g));
|
|
link = lineElement.slice(lineElement.search(/href="/g) + 6);
|
|
link = link.slice(0, link.search(/"/g));
|
|
}
|
|
while (currentNode.model.rank >= currentRank) {
|
|
currentNode = currentNode.parent;
|
|
}
|
|
if (lastNode) {
|
|
lastNode.model.endIndex = i;
|
|
}
|
|
lastNode = tree.parse({
|
|
id: id++,
|
|
rank: currentRank,
|
|
// @ts-ignore
|
|
name: name,
|
|
lineIndex: i,
|
|
endIndex: noteLines.length,
|
|
link: link,
|
|
});
|
|
currentNode.addChild(lastNode);
|
|
currentNode = lastNode;
|
|
}
|
|
}
|
|
return root;
|
|
}
|
|
|
|
getNoteTreeAsList(
|
|
note: ZoteroItem,
|
|
filterRoot: boolean = true,
|
|
filterLink: boolean = true
|
|
): TreeModel.Node<object>[] {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return;
|
|
}
|
|
return this.getNoteTree(note).all(
|
|
(node) =>
|
|
(!filterRoot || node.model.lineIndex >= 0) &&
|
|
(!filterLink || node.model.rank <= 6)
|
|
);
|
|
}
|
|
|
|
getNoteTreeNodeById(
|
|
note: ZoteroItem,
|
|
id: number,
|
|
root: TreeModel.Node<object> = undefined
|
|
) {
|
|
root = root || this.getNoteTree(note);
|
|
return root.first(function (node) {
|
|
return node.model.id === id;
|
|
});
|
|
}
|
|
|
|
getNoteTreeNodesByRank(
|
|
note: ZoteroItem,
|
|
rank: number,
|
|
root: TreeModel.Node<object> = undefined
|
|
) {
|
|
root = root || this.getNoteTree(note);
|
|
return root.all(function (node) {
|
|
return node.model.rank === rank;
|
|
});
|
|
}
|
|
|
|
getNodeLineRangeInNoteTree(
|
|
note: ZoteroItem,
|
|
node: TreeModel.Node<object>
|
|
): number[] {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return;
|
|
}
|
|
let nodes = this.getNoteTreeAsList(note);
|
|
let endIndex = node.model.endIndex;
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
if (
|
|
nodes[i].model.lineIndex >= node.model.lineIndex &&
|
|
nodes[i].model.rank > node.model.rank
|
|
) {
|
|
endIndex = nodes[i].model.endIndex;
|
|
}
|
|
}
|
|
return [node.model.lineIndex, endIndex];
|
|
}
|
|
|
|
async exportNoteToFile(
|
|
note: ZoteroItem,
|
|
convertNoteLinks: boolean = true,
|
|
saveFile: boolean = true,
|
|
saveNote: boolean = false,
|
|
saveCopy: boolean = false
|
|
) {
|
|
if (convertNoteLinks) {
|
|
let item: ZoteroItem = new Zotero.Item("note");
|
|
item.setNote(note.getNote());
|
|
item.saveTx();
|
|
let noteLines = this.getLinesInNote(note);
|
|
let newLines = [];
|
|
for (let i in noteLines) {
|
|
newLines.push(noteLines[i]);
|
|
let linkIndex = noteLines[i].search(/zotero:\/\/note\//g);
|
|
while (linkIndex >= 0) {
|
|
let link = noteLines[i].substring(linkIndex);
|
|
link = link.substring(0, link.search('"'));
|
|
let res = await this.getNoteFromLink(link);
|
|
if (res.item && res.item.id !== note.id) {
|
|
Zotero.debug(`Knowledge4Zotero: Exporting sub-note ${link}`);
|
|
newLines.push("<blockquote>");
|
|
newLines.push(
|
|
`<p><strong>Linked Note: <a href="${link}" rel="noopener noreferrer nofollow">${res.item.getNoteTitle()}</a></strong></p>`
|
|
);
|
|
let linkedLines = this.getLinesInNote(res.item);
|
|
newLines = newLines.concat(linkedLines);
|
|
newLines.push("</blockquote>");
|
|
}
|
|
noteLines[i] = noteLines[i].substring(
|
|
noteLines[i].search(/zotero:\/\/note\//g)
|
|
);
|
|
noteLines[i] = noteLines[i].substring(
|
|
noteLines[i].search(/<\/a>/g) + "</a>".length
|
|
);
|
|
linkIndex = noteLines[i].search(/zotero:\/\/note\//g);
|
|
}
|
|
}
|
|
this.setLinesToNote(item, newLines);
|
|
if (saveFile) {
|
|
const exporter = new Zotero_File_Exporter();
|
|
exporter.items = [item];
|
|
await exporter.save();
|
|
}
|
|
if (saveCopy) {
|
|
Zotero_File_Interface.exportItemsToClipboard(
|
|
[item],
|
|
Zotero.Translators.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT
|
|
);
|
|
this._Addon.views.showProgressWindow("Knowledge", "Note Copied");
|
|
}
|
|
if (!saveNote) {
|
|
if (saveCopy) {
|
|
// Wait copy finish
|
|
await Zotero.Promise.delay(500);
|
|
}
|
|
await Zotero.Items.erase(item.id);
|
|
}
|
|
} else {
|
|
if (saveFile) {
|
|
const exporter = new Zotero_File_Exporter();
|
|
exporter.items = [note];
|
|
exporter.save();
|
|
}
|
|
}
|
|
}
|
|
|
|
async getNoteFromLink(uri: string) {
|
|
let [groupID, noteKey] = uri.substring("zotero://note/".length).split("/");
|
|
|
|
// User libraryID by defaultx
|
|
let libraryID = 1;
|
|
|
|
if (groupID !== "u") {
|
|
// Not a user item
|
|
let _groupID = parseInt(groupID);
|
|
libraryID = Zotero.Groups.getLibraryIDFromGroupID(_groupID);
|
|
}
|
|
|
|
if (!libraryID) {
|
|
return {
|
|
item: false,
|
|
infoText: "Library does not exist or access denied.",
|
|
};
|
|
}
|
|
let item = await Zotero.Items.getByLibraryAndKeyAsync(libraryID, noteKey);
|
|
if (!item || !item.isNote()) {
|
|
return {
|
|
item: false,
|
|
infoText: "Note does not exist or is not a note.",
|
|
};
|
|
}
|
|
return {
|
|
item: item,
|
|
infoText: "OK",
|
|
};
|
|
}
|
|
|
|
parseNoteHTML(note: ZoteroItem): Element {
|
|
note = note || this.getWorkspaceNote();
|
|
if (!note) {
|
|
return undefined;
|
|
}
|
|
let noteText = note.getNote();
|
|
if (noteText.search(/data-schema-version/g) === -1) {
|
|
noteText = `<div data-schema-version="8">${noteText}\n</div>`;
|
|
}
|
|
let parser = Components.classes[
|
|
"@mozilla.org/xmlextras/domparser;1"
|
|
].createInstance(Components.interfaces.nsIDOMParser);
|
|
let doc = parser.parseFromString(noteText, "text/html");
|
|
|
|
let metadataContainer: Element = doc.querySelector(
|
|
"body > div[data-schema-version]"
|
|
);
|
|
return metadataContainer;
|
|
}
|
|
}
|
|
|
|
export default Knowledge;
|