fix: note parse logical bugs

fix: treeview ui bug
This commit is contained in:
xiangyu 2022-05-11 20:29:40 +08:00
parent b8f2d1324c
commit 326101ed36
8 changed files with 487 additions and 386 deletions

View File

@ -157,7 +157,7 @@
const parent = node.parent.model.id === -1? 999:node.parent.model.id;
nodeDataArray.push({
key: node.model.id,
text: `${node.model.rank===7?'🔗':''}${node.model.name.slice(0,15)}${node.model.name.length>=15?'...':''}`,
text: `${node.model.rank===7?'🔗':''}${node.model.name.slice(0,50)}${node.model.name.length>=50?'...':''}`,
lineIndex: node.model.lineIndex,
noteLink: node.model.rank===7?node.model.link:'',
});
@ -174,9 +174,9 @@
var oldnode = adorn.adornedPart;
var olddata = oldnode.data;
if(olddata.noteLink){
window.parent.postMessage({type: "jumpNote", link: olddata.noteLink}, "*");
window.parent.postMessage({type: "jumpNote", link: olddata.noteLink, id: olddata.key}, "*");
}else{
window.parent.postMessage({type: "jumpNode", lineIndex: olddata.lineIndex}, "*");
window.parent.postMessage({type: "jumpNode", lineIndex: olddata.lineIndex, id: olddata.key}, "*");
}
}

View File

@ -248,7 +248,7 @@
const parent = node.parent.model.id === -1? 999:node.parent.model.id;
data.nodeDataArray.push({
key: node.model.id,
text: `${node.model.rank===7?'🔗':''}${node.model.name.slice(0,10)}${node.model.name.length>=10?'...':''}`,
text: `${node.model.rank===7?'🔗':''}${node.model.name.slice(0,50)}${node.model.name.length>=50?'...':''}`,
parent: parent,
lineIndex: node.model.lineIndex,
noteLink: node.model.rank===7?node.model.link:'',
@ -264,9 +264,9 @@
var oldnode = adorn.adornedPart;
var olddata = oldnode.data;
if(olddata.noteLink){
window.parent.postMessage({type: "jumpNote", link: olddata.noteLink}, "*");
window.parent.postMessage({type: "jumpNote", link: olddata.noteLink, id: olddata.key}, "*");
}else{
window.parent.postMessage({type: "jumpNode", lineIndex: olddata.lineIndex}, "*");
window.parent.postMessage({type: "jumpNode", lineIndex: olddata.lineIndex, id: olddata.key}, "*");
}
}

View File

@ -0,0 +1,327 @@
<!DOCTYPE html>
<html lang="en">
<body>
<script src="chrome://__addonRef__/content/lib/js/jquery.min.js"></script>
<script src="chrome://__addonRef__/content/lib/js/dx.all.js"></script>
<style>
html,
body,
div {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
.form {
display: flex;
}
.form > div {
display: inline-block;
vertical-align: top;
}
#treeview {
padding: 20px 0 0 20px;
}
.drive-header {
min-height: auto;
padding: 0;
cursor: default;
}
.drive-panel {
font-size: 115%;
font-weight: bold;
border-right: 1px solid rgba(165, 165, 165, 0.4);
height: 100%;
}
.drive-panel:last-of-type {
border-right: none;
}
ul,
li {
display: list-item;
}
</style>
<link
rel="stylesheet"
type="text/css"
href="chrome://__addonRef__/content/lib/css/dx.light.css"
/>
<div
class="dx-viewport"
id="outline-container"
style="background-color: inherit; overflow: hidden"
>
<script id="code">
function init() {
window.addEventListener("message", handler, false);
window.parent.postMessage({ type: "ready" }, "*");
getData();
}
function createTreeView(selector, items) {
$(selector).dxTreeView({
items,
expandNodesRecursive: false,
dataStructure: "plain",
height: $("window").height() - 100,
displayExpr: "name",
noDataText: "Create a heading with '+'",
onItemClick: (e) => {
window.parent.postMessage(
{ type: "jumpNode", lineIndex: e.itemData.lineIndex },
"*"
);
},
});
}
function createSortable(selector, driveName) {
$(selector).dxSortable({
filter: ".dx-treeview-item",
group: "shared",
data: driveName,
allowDropInsideItem: true,
allowReordering: true,
onDragChange: (e) => {
if (e.fromComponent === e.toComponent) {
const $nodes = e.element.find(".dx-treeview-node");
const isDragIntoChild =
$nodes.eq(e.fromIndex).find($nodes.eq(e.toIndex)).length > 0;
if (isDragIntoChild) {
e.cancel = true;
}
}
},
onDragEnd: (e) => {
if (
e.fromComponent === e.toComponent &&
e.fromIndex === e.toIndex
) {
return;
}
const fromTreeView = getTreeView();
const toTreeView = getTreeView();
const fromNode = findNode(fromTreeView, e.fromIndex);
const toNode = findNode(toTreeView, calculateToIndex(e));
if (
e.dropInsideItem &&
toNode !== null &&
// !toNode.itemData.isDirectory &&
toNode.itemData.rank === 7
) {
return;
}
const fromTopVisibleNode = getTopVisibleNode(fromTreeView);
const toTopVisibleNode = getTopVisibleNode(toTreeView);
const fromItems = fromTreeView.option("items");
const toItems = toTreeView.option("items");
moveNode(fromNode, toNode, fromItems, toItems, e.dropInsideItem);
fromTreeView.option("items", fromItems);
toTreeView.option("items", toItems);
fromTreeView.scrollToItem(fromTopVisibleNode);
toTreeView.scrollToItem(toTopVisibleNode);
},
});
}
function getTreeView() {
return $("#treeview").dxTreeView("instance");
}
function calculateToIndex(e) {
if (e.fromComponent !== e.toComponent || e.dropInsideItem) {
return e.toIndex;
}
return e.fromIndex >= e.toIndex ? e.toIndex : e.toIndex + 1;
}
function findNode(treeView, index) {
const nodeElement = treeView.element().find(".dx-treeview-node")[
index
];
if (nodeElement) {
return findNodeById(
treeView.getNodes(),
nodeElement.getAttribute("data-item-id")
);
}
return null;
}
function findNodeById(nodes, id) {
for (let i = 0; i < nodes.length; i += 1) {
if (nodes[i].itemData.id === id) {
return nodes[i];
}
if (nodes[i].children) {
const node = findNodeById(nodes[i].children, id);
if (node != null) {
return node;
}
}
}
return null;
}
function moveNode(
fromNode,
toNode,
fromItems,
toItems,
isDropInsideItem
) {
const fromIndex = findIndex(fromItems, fromNode.itemData.id);
fromItems.splice(fromIndex, 1);
const toIndex =
toNode === null || isDropInsideItem
? toItems.length
: findIndex(toItems, toNode.itemData.id);
window.parent.postMessage(
{
type: "moveNode",
fromID: parseInt(fromNode.itemData.id),
toID: toNode
? parseInt(toNode.itemData.id)
: toItems[toItems.length - 1].itemData.id,
type: toNode ? "before" : "after",
},
"*"
);
toItems.splice(toIndex, 0, fromNode.itemData);
moveChildren(fromNode, fromItems, toItems);
if (isDropInsideItem) {
fromNode.itemData.parentId = toNode.itemData.id;
} else {
fromNode.itemData.parentId =
toNode != null ? toNode.itemData.parentId : undefined;
}
}
function moveChildren(node, fromItems, toItems) {
if (!node.itemData.isDirectory) {
return;
}
node.children.forEach((child) => {
if (child.itemData.isDirectory) {
moveChildren(child, fromItems, toItems);
}
const fromIndex = findIndex(fromItems, child.itemData.id);
fromItems.splice(fromIndex, 1);
toItems.splice(toItems.length, 0, child.itemData);
});
}
function findIndex(array, id) {
const idsArray = array.map((elem) => elem.id);
return idsArray.indexOf(id);
}
function getTopVisibleNode(component) {
const treeViewElement = component.element().get(0);
const treeViewTopPosition =
treeViewElement.getBoundingClientRect().top;
const nodes = treeViewElement.querySelectorAll(".dx-treeview-node");
for (let i = 0; i < nodes.length; i += 1) {
const nodeTopPosition = nodes[i].getBoundingClientRect().top;
if (nodeTopPosition >= treeViewTopPosition) {
return nodes[i];
}
}
return null;
}
const noteIcon = `<svg t="1652008007954" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10521" width="18" height="18"><path d="M574.3 896H159.7c-17.6 0-31.9-14.3-31.9-32V160c0-17.7 14.3-32 31.9-32h382.7v160c0 35.3 28.6 64 63.8 64h159.5v192c0 17.7 14.3 32 31.9 32 17.6 0 31.9-14.3 31.9-32V270.2c0-8.5-3.3-16.6-9.3-22.6L647.4 73.4c-6-6-14.1-9.4-22.6-9.4h-497C92.6 64 64 92.7 64 128v768c0 35.3 28.6 64 63.8 64h446.5c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM638.1 288c-17.6 0-31.9-14.3-31.9-32V128l159.5 160H638.1z" p-id="10522"></path><path d="M418.8 673H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32h193.3c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM608.2 481H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32h382.7c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM225.5 353h191.4c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32zM862.7 959.4c-23.6 0-47-8.8-64.8-26.6l-24.4-24.4c-12.5-12.5-12.5-32.8 0-45.3s32.7-12.5 45.1 0l24.4 24.4c11.3 11.4 30.7 10.4 43.2-2.1 12.5-12.5 13.4-31.9 2.1-43.3L749.2 702.6c-11.3-11.4-30.7-10.4-43.2 2.1-6.2 6.3-9.8 14.4-10 22.8-0.2 7.9 2.6 15.1 7.9 20.4 12.5 12.5 12.5 32.8 0 45.3s-32.7 12.5-45.1 0c-36.2-36.3-35.2-96.3 2.1-133.8 37.4-37.5 97.2-38.4 133.4-2.1l139.1 139.5c36.2 36.3 35.2 96.3-2.1 133.8-19 19.2-43.9 28.8-68.6 28.8z" p-id="10523"></path><path d="M696.3 883.1c-23.6 0-47-8.8-64.8-26.6l-139-139.6c-17.7-17.8-27.2-41.7-26.6-67.2 0.6-25 10.8-48.6 28.7-66.6 17.9-17.9 41.5-28.2 66.4-28.8 25.5-0.6 49.3 8.9 67 26.6l24.4 24.4c12.5 12.5 12.5 32.8 0 45.3s-32.7 12.5-45.1 0l-24.4-24.4c-5.3-5.3-12.5-8.1-20.4-7.9-8.4 0.2-16.5 3.8-22.8 10-6.2 6.3-9.8 14.4-10 22.8-0.2 7.9 2.6 15.1 7.9 20.4L676.7 811c11.3 11.4 30.7 10.4 43.2-2.1 12.5-12.5 13.4-31.9 2.1-43.3-12.5-12.5-12.5-32.8 0-45.3s32.7-12.5 45.1 0c36.2 36.3 35.3 96.3-2.1 133.8-19.1 19.3-44 29-68.7 29z" p-id="10524"></path></svg>`;
function getData() {
window.parent.postMessage({ type: "getMindMapData" }, "*");
}
function setData(nodes) {
console.log(nodes);
const treeData = [];
nodes.map((node) => {
treeData.push({
id: String(node.model.id),
name: node.model.name,
rank: node.model.rank,
icon: node.model.rank === 7 ? noteIcon : undefined,
lineIndex: node.model.lineIndex,
endIndex: node.model.endIndex,
isDirectory: node.children.length > 0,
expanded: true,
parentId:
node.model.rank > 1 ? String(node.parent.model.id) : undefined,
});
});
$(() => {
createTreeView("#treeview", treeData);
createSortable("#treeview", "treeData");
});
}
function jumpNode(e, obj) {
var adorn = obj.part;
var oldnode = adorn.adornedPart;
var olddata = oldnode.data;
if (olddata.noteLink) {
window.parent.postMessage(
{ type: "jumpNote", link: olddata.noteLink },
"*"
);
} else {
window.parent.postMessage(
{
type: "jumpNode",
lineIndex: olddata.lineIndex,
id: parseInt(olddata.id),
},
"*"
);
}
}
function handler(e) {
console.log(e);
if (e.data.type === "setMindMapData") {
setData(e.data.nodes);
}
}
window.addEventListener("DOMContentLoaded", () => {
try {
init();
} catch (e) {
window.parent.postMessage({ type: "error", event: e }, "*");
}
});
</script>
<div class="demo-container">
<div class="form">
<div class="drive-panel">
<div id="treeview"></div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -22,7 +22,6 @@
<script src="chrome://__addonRef__/content/lib/js/go.js"></script>
<script type="application/javascript">
Zotero.Knowledge4Zotero.views.$ = $;
Zotero.Knowledge4Zotero.views.go = go;
</script>
<keyset>
@ -32,15 +31,6 @@
<hbox flex="1">
<vbox id="zotero-knowledge-outline" flex="1" width="330" minwidth="300" style="overflow: hidden;">
<html:div class="dx-viewport" id="outline-container">
<div class="demo-container">
<div class="form">
<div class="drive-panel">
<div id="treeview"></div>
</div>
</div>
</div>
</html:div>
<html:div id="mindmap-container">
<!-- Inser Here -->
</html:div>

View File

@ -1,39 +1,3 @@
.form {
display: flex;
}
.form > div {
display: inline-block;
vertical-align: top;
}
#treeview {
margin-top: 10px;
}
.drive-header {
min-height: auto;
padding: 0;
cursor: default;
}
.drive-panel {
padding: 20px 0px 20px 10px;
font-size: 115%;
font-weight: bold;
border-right: 1px solid rgba(165, 165, 165, 0.4);
height: 100%;
}
.drive-panel:last-of-type {
border-right: none;
}
ul,
li {
display: list-item;
}
.tooltip {
position: relative;
display: inline-block;
@ -81,4 +45,4 @@ li {
.tool-button:active {
background: #b3b3b3;
text-decoration: none;
}
}

View File

@ -69,15 +69,19 @@ class AddonEvents extends AddonBase {
}
public addEditorInstanceListener() {
Zotero.Notes._registerEditorInstance = Zotero.Notes.registerEditorInstance;
Zotero.Notes.registerEditorInstance = (instance: EditorInstance) => {
Zotero.Notes._registerEditorInstance(instance);
this.onEditorEvent(
new EditorMessage("addNoteInstance", {
editorInstance: instance,
})
);
};
if (!Zotero.Notes._knowledgeInit) {
Zotero.Notes._knowledgeInit = true;
Zotero.Notes._registerEditorInstance =
Zotero.Notes.registerEditorInstance;
Zotero.Notes.registerEditorInstance = (instance: EditorInstance) => {
Zotero.Notes._registerEditorInstance(instance);
this.onEditorEvent(
new EditorMessage("addNoteInstance", {
editorInstance: instance,
})
);
};
}
}
public async addEditorEventListener(
@ -388,7 +392,6 @@ class AddonEvents extends AddonBase {
type
}
*/
// if(message.content.)
Zotero.debug("Knowledge4Zotero: addToKnowledgeLine");
Zotero.debug(message.content.event.target.id);
const idSplit = message.content.event.target.id.split("-");
@ -398,24 +401,22 @@ class AddonEvents extends AddonBase {
lineIndex,
message.content.editorInstance._item.id
);
} else if (message.type === "clickOutlineHeading") {
} else if (message.type === "jumpNode") {
/*
message.content = {
event: {itemData}
params: {id, lineIndex}
}
*/
let editorInstance =
await this._Addon.knowledge.getWorkspaceEditorInstance();
// Set node id
this._Addon.knowledge.currentNodeID = parseInt(
(message.content.event as any).itemData.id
);
this._Addon.knowledge.currentNodeID = parseInt(message.content.params.id);
this._Addon.views.scrollToLine(
editorInstance,
// Scroll to 6 lines before the inserted line
(message.content.event as any).itemData.lineIndex - 5
// Scroll to 1 lines before the inserted line
message.content.params.lineIndex - 1
);
} else if (message.type === "moveOutlineHeading") {
} else if (message.type === "moveNode") {
/*
message.content = {
params: {

View File

@ -37,16 +37,11 @@ class Knowledge extends AddonBase {
);
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();
}
}
@ -136,47 +131,69 @@ class Knowledge extends AddonBase {
noteText.length - "</div>".length
);
}
let noteLines: string[] = noteText.split("\n");
let noteLines = noteText.split("\n").filter((e) => e);
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 = "";
let tagStack = [];
let toPush = [];
let toRemove = 0;
let nextAppend = false;
const forceInline = ["table", "blockquote", "pre", "li"];
const selfInline = ["ol", "ul"];
const parsedLines = [];
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}`;
for (const tag of forceInline) {
const startReg = `<${tag}>`;
const endReg = `</${tag}>`;
const startIdx = line.search(startReg);
const endIdx = line.search(endReg);
if (startIdx !== -1 && endIdx === -1) {
toPush.push(tag);
} else if (endIdx !== -1) {
toRemove += 1;
}
line = cachedLines;
cachedLines = "";
}
if (!appendLater) {
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(`</${tag}>`);
const startIdx = line.search(startReg);
const endIdx = line.search(endReg);
if (startIdx !== -1 && endIdx === -1) {
nextAppend = true;
nextLoop = true;
parsedLines.push(line);
break;
}
if (endIdx !== -1) {
parsedLines[parsedLines.length - 1] += `\n${line}`;
nextLoop = true;
break;
}
}
if (nextLoop) {
continue;
}
}
if (tagStack.length === 0 && !nextAppend) {
parsedLines.push(line);
} else {
parsedLines[parsedLines.length - 1] += `\n${line}`;
nextAppend = false;
}
if (toPush.length > 0) {
tagStack = tagStack.concat(toPush);
toPush = [];
}
while (toRemove > 0) {
tagStack.pop();
toRemove -= 1;
}
}
return parsedLines;
@ -255,11 +272,20 @@ class Knowledge extends AddonBase {
return;
}
let noteLines = this.getLinesInNote(note);
if (newLine) {
noteLines.splice(lineIndex, 0, "<p> </p>", text);
} else {
noteLines.splice(lineIndex, 0, text);
Zotero.debug(
`insert to ${lineIndex}, it used to be ${noteLines[lineIndex]}`
);
// Force links not to appear in one line
if (lineIndex > 0 && noteLines[lineIndex - 1].search(/<a href/g) !== -1) {
text = `<p> </p>\n${text}`;
}
if (
lineIndex < noteLines.length &&
noteLines[lineIndex].search(/<a href/g)
) {
text = `${text}\n<p> </p>`;
}
noteLines.splice(lineIndex, 0, text);
this.setLinesToNote(note, noteLines);
}
@ -272,8 +298,8 @@ class Knowledge extends AddonBase {
if (lineIndex < 0) {
lineIndex =
this.currentLine >= 0
? this.currentLine + 2
: this.getLinesInNote(note).length + 1;
? this.currentLine
: this.getLinesInNote(note).length;
}
// let parentNode = this.getLineParentInNote(note, lineIndex);
// if (!parentNode) {
@ -466,8 +492,7 @@ class Knowledge extends AddonBase {
endIndex: -1,
});
let id = 0;
let currentNode = root;
let lastNode = undefined;
let lastNode = root;
let headerStartReg = new RegExp("<h[1-6]>");
let headerStopReg = new RegExp("</h[1-6]>");
for (let i in noteLines) {
@ -488,23 +513,35 @@ class Knowledge extends AddonBase {
link = link.slice(0, link.search(/"/g));
}
name = this.parseLineText(lineElement);
while (currentNode.model.rank >= currentRank) {
currentNode = currentNode.parent;
// Find parent node
let parentNode = lastNode;
while (parentNode.model.rank >= currentRank) {
parentNode = parentNode.parent;
}
if (lastNode) {
lastNode.model.endIndex = i;
}
lastNode = tree.parse({
const currentNode = tree.parse({
id: id++,
rank: currentRank,
// @ts-ignore
name: name,
lineIndex: i,
lineIndex: parseInt(i),
endIndex: noteLines.length,
link: link,
});
currentNode.addChild(lastNode);
currentNode = lastNode;
parentNode.addChild(currentNode);
const currentIndex = parentNode.children.indexOf(currentNode);
if (currentIndex > 0) {
const previousNode = parentNode.children[currentIndex - 1];
// Traverse the previous node tree and set the end index
previousNode.walk((node) => {
if (node.model.endIndex > parseInt(i)) {
node.model.endIndex = parseInt(i);
}
return true;
});
previousNode.model.endIndex = parseInt(i);
}
lastNode = currentNode;
}
}
return root;

View File

@ -3,7 +3,6 @@ import { AddonBase, EditorMessage, OutlineType } from "./base";
class AddonViews extends AddonBase {
progressWindowIcon: object;
editorIcon: object;
$: any;
currentOutline: OutlineType;
_initIframe: any;
@ -23,7 +22,6 @@ class AddonViews extends AddonBase {
export: `<svg t="1651322116327" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11894" width="24" height="24"><path d="M849.2 599v217H178.5V599c-0.7-23.7-20.1-42.7-44-42.7s-43.3 19-44 42.7v252.5c0 28.9 23.6 52.5 52.5 52.5h741.7c28.9 0 52.5-23.6 52.5-52.5V599c-0.7-23.7-20.1-42.7-44-42.7s-43.3 19-44 42.7z" p-id="11895"></path><path d="M482.7 135.4l-164 164c-17.1 17.1-17.1 45.1 0 62.2s45.1 17.1 62.2 0l85.7-85.7v314.8c0 26 21.3 47.2 47.2 47.2 26 0 47.2-21.3 47.2-47.2V276l85.7 85.7c17.1 17.1 45.1 17.1 62.2 0s17.1-45.1 0-62.2l-164-164c-17.1-17.2-45.1-17.2-62.2-0.1z" p-id="11896"></path></svg>`,
close: `<svg t="1651331457107" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12754" width="24" height="24"><path d="M557.311759 513.248864l265.280473-263.904314c12.54369-12.480043 12.607338-32.704421 0.127295-45.248112-12.512727-12.576374-32.704421-12.607338-45.248112-0.127295L512.127295 467.904421 249.088241 204.063755c-12.447359-12.480043-32.704421-12.54369-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.280796l262.975407 263.775299-265.151458 263.744335c-12.54369 12.480043-12.607338 32.704421-0.127295 45.248112 6.239161 6.271845 14.463432 9.440452 22.687703 9.440452 8.160624 0 16.319527-3.103239 22.560409-9.311437l265.216826-263.807983 265.440452 266.240344c6.239161 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.311759 513.248864z" p-id="12755"></path></svg>`,
openWorkspaceCollectionView: `<svg t="1651317033804" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2432" width="100%" height="100%"><path d="M874.9 459.4c-18.8 0-34 15.2-34 34v355.7c0 18.6-15.5 33.7-34.5 33.7H181.5c-19 0-34.5-15.1-34.5-33.7V232.3c0-18.6 15.5-33.7 34.5-33.7H541c18.8 0 34-15.2 34-34s-15.2-34-34-34H181.5C125 130.6 79 176.2 79 232.3v616.8c0 56 46 101.7 102.5 101.7h624.9c56.5 0 102.5-45.6 102.5-101.7V493.4c0-18.8-15.2-34-34-34z" fill="#b6b6b6" p-id="2433"></path><path d="M885.5 82.7H657.1c-18.8 0-34 15.2-34 34s15.2 34 34 34h169.7L358.5 619.1c-13.3 13.3-13.3 34.8 0 48.1 6.6 6.6 15.3 10 24 10s17.4-3.3 24-10l470-470v169.7c0 18.8 15.2 34 34 34s34-15.2 34-34V141.5c0.1-32.4-26.4-58.8-59-58.8z" fill="#b6b6b6" p-id="2434"></path></svg>`,
note: `<svg t="1652008007954" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10521" width="18" height="18"><path d="M574.3 896H159.7c-17.6 0-31.9-14.3-31.9-32V160c0-17.7 14.3-32 31.9-32h382.7v160c0 35.3 28.6 64 63.8 64h159.5v192c0 17.7 14.3 32 31.9 32 17.6 0 31.9-14.3 31.9-32V270.2c0-8.5-3.3-16.6-9.3-22.6L647.4 73.4c-6-6-14.1-9.4-22.6-9.4h-497C92.6 64 64 92.7 64 128v768c0 35.3 28.6 64 63.8 64h446.5c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM638.1 288c-17.6 0-31.9-14.3-31.9-32V128l159.5 160H638.1z" p-id="10522"></path><path d="M418.8 673H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32h193.3c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM608.2 481H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32h382.7c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM225.5 353h191.4c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32zM862.7 959.4c-23.6 0-47-8.8-64.8-26.6l-24.4-24.4c-12.5-12.5-12.5-32.8 0-45.3s32.7-12.5 45.1 0l24.4 24.4c11.3 11.4 30.7 10.4 43.2-2.1 12.5-12.5 13.4-31.9 2.1-43.3L749.2 702.6c-11.3-11.4-30.7-10.4-43.2 2.1-6.2 6.3-9.8 14.4-10 22.8-0.2 7.9 2.6 15.1 7.9 20.4 12.5 12.5 12.5 32.8 0 45.3s-32.7 12.5-45.1 0c-36.2-36.3-35.2-96.3 2.1-133.8 37.4-37.5 97.2-38.4 133.4-2.1l139.1 139.5c36.2 36.3 35.2 96.3-2.1 133.8-19 19.2-43.9 28.8-68.6 28.8z" p-id="10523"></path><path d="M696.3 883.1c-23.6 0-47-8.8-64.8-26.6l-139-139.6c-17.7-17.8-27.2-41.7-26.6-67.2 0.6-25 10.8-48.6 28.7-66.6 17.9-17.9 41.5-28.2 66.4-28.8 25.5-0.6 49.3 8.9 67 26.6l24.4 24.4c12.5 12.5 12.5 32.8 0 45.3s-32.7 12.5-45.1 0l-24.4-24.4c-5.3-5.3-12.5-8.1-20.4-7.9-8.4 0.2-16.5 3.8-22.8 10-6.2 6.3-9.8 14.4-10 22.8-0.2 7.9 2.6 15.1 7.9 20.4L676.7 811c11.3 11.4 30.7 10.4 43.2-2.1 12.5-12.5 13.4-31.9 2.1-43.3-12.5-12.5-12.5-32.8 0-45.3s32.7-12.5 45.1 0c36.2 36.3 35.3 96.3-2.1 133.8-19.1 19.3-44 29-68.7 29z" p-id="10524"></path></svg>`,
};
this.currentOutline = OutlineType.treeView;
this._initIframe = Zotero.Promise.defer();
@ -490,18 +488,22 @@ class AddonViews extends AddonBase {
new EditorMessage("openUserGuide", {})
);
});
_window.addEventListener("resize", (e) => this.resizeOutline(_window));
}
async messageHandler(e) {
const _window = this._Addon.knowledge.getWorkspaceWindow();
Zotero.debug(`Knowledge4Zotero: view message ${e.data.type}`);
console.log(`Knowledge4Zotero: view message ${e.data.type}`);
if (e.data.type === "ready") {
this._initIframe.resolve();
} else if (e.data.type === "getMindMapData") {
this.updateMindMap();
} else if (e.data.type === "jumpNode") {
this.scrollToLine(
await this._Addon.knowledge.getWorkspaceEditorInstance(),
e.data.lineIndex
this._Addon.events.onEditorEvent(
new EditorMessage("jumpNode", {
params: e.data,
})
);
} else if (e.data.type === "jumpNote") {
Zotero.debug(e.data);
@ -510,6 +512,12 @@ class AddonViews extends AddonBase {
params: await this._Addon.knowledge.getNoteFromLink(e.data.link),
})
);
} else if (e.data.type === "moveNode") {
this._Addon.events.onEditorEvent(
new EditorMessage("moveNode", {
params: e.data,
})
);
}
}
@ -522,36 +530,23 @@ class AddonViews extends AddonBase {
}
const _window = this._Addon.knowledge.getWorkspaceWindow();
const mindmap = _window.document.getElementById("mindmap-container");
const outline = _window.document.getElementById("outline-container");
this.currentOutline = newType;
if (this.currentOutline === OutlineType.treeView) {
_window.document.getElementById("mindmapIframe").remove();
mindmap.setAttribute("hidden", "hidden");
outline.removeAttribute("hidden");
} else if (this.currentOutline === OutlineType.mindMap) {
const iframe = _window.document.createElement("iframe");
iframe.setAttribute("id", "mindmapIframe");
iframe.setAttribute(
"src",
"chrome://Knowledge4Zotero/content/mindMap.html"
);
outline.setAttribute("hidden", "hidden");
mindmap.removeAttribute("hidden");
mindmap.append(iframe);
this.setTreeViewSize();
} else if (this.currentOutline === OutlineType.bubbleMap) {
_window.document.getElementById("mindmapIframe").remove();
const iframe = _window.document.createElement("iframe");
iframe.setAttribute("id", "mindmapIframe");
iframe.setAttribute(
"src",
"chrome://Knowledge4Zotero/content/bubbleMap.html"
);
outline.setAttribute("hidden", "hidden");
mindmap.removeAttribute("hidden");
mindmap.append(iframe);
this.setTreeViewSize();
const oldIframe = _window.document.getElementById("mindmapIframe");
if (oldIframe) {
oldIframe.remove();
}
this.currentOutline = newType;
const srcList = [
"",
"chrome://Knowledge4Zotero/content/treeView.html",
"chrome://Knowledge4Zotero/content/mindMap.html",
"chrome://Knowledge4Zotero/content/bubbleMap.html",
];
const iframe = _window.document.createElement("iframe");
iframe.setAttribute("id", "mindmapIframe");
iframe.setAttribute("src", srcList[this.currentOutline]);
mindmap.append(iframe);
this.resizeOutline(_window);
this.buildOutline(this._Addon.knowledge.getWorkspaceNote());
}
@ -571,236 +566,23 @@ class AddonViews extends AddonBase {
);
}
/*
* Outline Code Start
*/
// TODO: change this
async buildOutline(note: ZoteroItem) {
Zotero.debug(this.currentOutline);
if (this.currentOutline === OutlineType.treeView) {
this._Addon.knowledge.currentNodeID = -1;
let treeList = this._Addon.knowledge.getNoteTreeAsList(note, true, false);
const treeData = [];
treeList.map((node: TreeModel.Node<object>) => {
treeData.push({
id: String(node.model.id),
name: node.model.name,
rank: node.model.rank,
icon: node.model.rank === 7 ? this.editorIcon["note"] : undefined,
lineIndex: node.model.lineIndex,
endIndex: node.model.endIndex,
isDirectory: node.hasChildren(),
expanded: true,
parentId:
node.model.rank > 1 ? String(node.parent.model.id) : undefined,
});
});
this.$(() => {
this.createTreeView("#treeview", treeData);
this.createSortable("#treeview", "treeData");
});
} else {
this.updateMindMap();
}
this.updateMindMap();
}
createTreeView(selector, items) {
// @ts-ignore
this.$(selector).dxTreeView({
items,
expandNodesRecursive: false,
dataStructure: "plain",
height: this.$("window").height() - 100,
displayExpr: "name",
noDataText: "Create a heading with '+'",
onItemClick: (e) => {
this._Addon.events.onEditorEvent(
new EditorMessage("clickOutlineHeading", {
event: e,
})
);
},
});
}
bindTreeViewResize() {
this.$("#zotero-knowledge-outline").on("resize", (e) => {
this.setTreeViewSize();
});
}
setTreeViewSize() {
this.$("#treeview").css({
height: `${this.$("window").height() - 100}px`,
width: `${this.$("#zotero-knowledge-outline").width() - 10}px`,
});
this.$("#mindmapIframe").css({
height: `${this.$("window").height() - 58}px`,
width: `${this.$("#zotero-knowledge-outline").width() - 10}px`,
});
}
createSortable(selector, driveName) {
// @ts-ignore
this.$(selector).dxSortable({
filter: ".dx-treeview-item",
group: "shared",
data: driveName,
allowDropInsideItem: true,
allowReordering: true,
onDragChange: (e) => {
if (e.fromComponent === e.toComponent) {
const $nodes = e.element.find(".dx-treeview-node");
const isDragIntoChild =
$nodes.eq(e.fromIndex).find($nodes.eq(e.toIndex)).length > 0;
if (isDragIntoChild) {
e.cancel = true;
}
}
},
onDragEnd: (e) => {
if (e.fromComponent === e.toComponent && e.fromIndex === e.toIndex) {
return;
}
const fromTreeView = this.getTreeView();
const toTreeView = this.getTreeView();
const fromNode = this.findNode(fromTreeView, e.fromIndex);
const toNode = this.findNode(toTreeView, this.calculateToIndex(e));
if (
e.dropInsideItem &&
toNode !== null &&
!toNode.itemData.isDirectory
) {
return;
}
const fromTopVisibleNode = this.getTopVisibleNode(fromTreeView);
const toTopVisibleNode = this.getTopVisibleNode(toTreeView);
const fromItems = fromTreeView.option("items");
const toItems = toTreeView.option("items");
this.moveNode(fromNode, toNode, fromItems, toItems, e.dropInsideItem);
fromTreeView.option("items", fromItems);
toTreeView.option("items", toItems);
fromTreeView.scrollToItem(fromTopVisibleNode);
toTreeView.scrollToItem(toTopVisibleNode);
},
});
}
getTreeView() {
// @ts-ignore
return this.$("#treeview").dxTreeView("instance");
}
calculateToIndex(e) {
if (e.fromComponent !== e.toComponent || e.dropInsideItem) {
return e.toIndex;
}
return e.fromIndex >= e.toIndex ? e.toIndex : e.toIndex + 1;
}
findNode(treeView, index) {
const nodeElement = treeView.element().find(".dx-treeview-node")[index];
if (nodeElement) {
return this.findNodeById(
treeView.getNodes(),
nodeElement.getAttribute("data-item-id")
);
}
return null;
}
findNodeById(nodes, id) {
for (let i = 0; i < nodes.length; i += 1) {
if (nodes[i].itemData.id === id) {
return nodes[i];
}
if (nodes[i].children) {
const node = this.findNodeById(nodes[i].children, id);
if (node != null) {
return node;
}
}
}
return null;
}
moveNode(fromNode, toNode, fromItems, toItems, isDropInsideItem) {
const fromIndex = this.findIndex(fromItems, fromNode.itemData.id);
fromItems.splice(fromIndex, 1);
const toIndex =
toNode === null || isDropInsideItem
? toItems.length
: this.findIndex(toItems, toNode.itemData.id);
this._Addon.events.onEditorEvent(
new EditorMessage("moveOutlineHeading", {
params: {
fromID: parseInt(fromNode.itemData.id),
toID: toNode
? parseInt(toNode.itemData.id)
: toItems[toItems.length - 1].itemData.id,
type: toNode ? "before" : "after",
},
})
resizeOutline(_window: Window) {
const iframe = _window.document.getElementById("mindmapIframe");
const container = _window.document.getElementById(
"zotero-knowledge-outline"
);
toItems.splice(toIndex, 0, fromNode.itemData);
this.moveChildren(fromNode, fromItems, toItems);
if (isDropInsideItem) {
fromNode.itemData.parentId = toNode.itemData.id;
} else {
fromNode.itemData.parentId =
toNode != null ? toNode.itemData.parentId : undefined;
if (iframe) {
iframe.style.height = `${container.clientHeight - 60}px`;
iframe.style.width = `${container.clientWidth - 10}px`;
}
}
moveChildren(node, fromItems, toItems) {
if (!node.itemData.isDirectory) {
return;
}
node.children.forEach((child) => {
if (child.itemData.isDirectory) {
this.moveChildren(child, fromItems, toItems);
}
const fromIndex = this.findIndex(fromItems, child.itemData.id);
fromItems.splice(fromIndex, 1);
toItems.splice(toItems.length, 0, child.itemData);
});
}
findIndex(array, id) {
const idsArray = array.map((elem) => elem.id);
return idsArray.indexOf(id);
}
getTopVisibleNode(component) {
const treeViewElement = component.element().get(0);
const treeViewTopPosition = treeViewElement.getBoundingClientRect().top;
const nodes = treeViewElement.querySelectorAll(".dx-treeview-node");
for (let i = 0; i < nodes.length; i += 1) {
const nodeTopPosition = nodes[i].getBoundingClientRect().top;
if (nodeTopPosition >= treeViewTopPosition) {
return nodes[i];
}
}
return null;
}
/*
* Outline Code End
*/
showProgressWindow(
header: string,
context: string,