zotero-better-notes/addon/chrome/content/treeView.html

370 lines
12 KiB
HTML

<!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;
animation: append-animate 0.3s ease-in-out;
}
@keyframes append-animate {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.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;
}
#outline-container {
color: -moz-DialogText;
}
</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(),
displayExpr: "name",
noDataText: "Outline is Empty",
onItemClick: jumpNode,
});
}
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;
}
window._e = e;
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.level === 7
) {
return;
}
window.parent.postMessage(
{
type: "moveNode",
fromID: parseInt(fromNode.itemData.id),
toID: toNode
? parseInt(toNode.itemData.id)
: toItems[toItems.length - 1].itemData.id,
moveType: e.dropInsideItem ? "child" : "before",
},
"*"
);
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() {
try {
return $("#treeview").dxTreeView("instance");
} catch {
return undefined;
}
}
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);
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"><defs><style>path{fill:currentColor;}</style></defs><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 walkNode(node, callback) {
if (!node) {
return;
}
callback(node);
node.children.forEach((child) => walkNode(child, callback));
}
function setData(nodes, expandLevel) {
console.log(nodes);
const tree = getTreeView();
const expandedStatus = {};
if (tree) {
const rootNodes = tree.getNodes();
console.log(tree, rootNodes);
rootNodes.forEach((root) => {
walkNode(root, (node) => {
expandedStatus[node.itemData.name] = node.itemData.expanded;
});
});
}
console.log(expandedStatus);
const treeData = [];
nodes.map((node) => {
treeData.push({
id: String(node.model.id),
name: node.model.name,
level: node.model.level,
icon: node.model.level === 7 ? noteIcon : undefined,
lineIndex: node.model.lineIndex,
endIndex: node.model.endIndex,
isDirectory: node.children.length > 0,
expanded:
node.model.name in expandedStatus
? expandedStatus[node.model.name]
: node.model.level < expandLevel,
parentId:
node.model.level > 1 ? String(node.parent.model.id) : undefined,
});
});
$(() => {
createTreeView("#treeview", treeData);
createSortable("#treeview", "treeData");
});
}
function jumpNode(e) {
var itemData = e.itemData;
if (itemData.noteLink) {
window.parent.postMessage(
{
type: "openNote",
link: itemData.noteLink,
id: parseInt(itemData.id),
},
"*"
);
} else {
window.parent.postMessage(
{
type: "jumpNode",
lineIndex: itemData.lineIndex,
id: parseInt(itemData.id),
workspaceType: window.workspaceType || "tab",
},
"*"
);
}
}
function handler(e) {
console.log(e);
if (e.data.type === "setMindMapData") {
setData(e.data.nodes, e.data.expandLevel);
window.workspaceType = e.data.workspaceType;
}
}
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" style="color: currentColor"></div>
</div>
</div>
</div>
</div>
</body>
</html>