add: note tabs
This commit is contained in:
parent
c035fc6e01
commit
415705a3bf
|
|
@ -172,12 +172,12 @@
|
|||
),
|
||||
$(go.Panel, "Auto"),
|
||||
);
|
||||
window.parent.postMessage({ type: "ready" }, "*");
|
||||
window.postMessage({ type: "ready" }, "*");
|
||||
getData();
|
||||
}
|
||||
|
||||
function getData() {
|
||||
window.parent.postMessage({ type: "getMindMapData" }, "*");
|
||||
window.postMessage({ type: "getMindMapData" }, "*");
|
||||
}
|
||||
|
||||
function setData(nodes) {
|
||||
|
|
@ -219,17 +219,16 @@
|
|||
var oldnode = adorn.adornedPart;
|
||||
var olddata = oldnode.data;
|
||||
if (olddata.noteLink) {
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{ type: "openNote", link: olddata.noteLink, id: olddata.key },
|
||||
"*",
|
||||
);
|
||||
} else {
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "jumpNode",
|
||||
lineIndex: olddata.lineIndex,
|
||||
id: olddata.key,
|
||||
workspaceType: window.workspaceType || "tab",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
|
@ -243,12 +242,11 @@
|
|||
alert("Link cannot be edited in mind map");
|
||||
return false;
|
||||
}
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "editNode",
|
||||
lineIndex: data.lineIndex,
|
||||
text: data.text,
|
||||
workspaceType: window.workspaceType || "tab",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
|
@ -259,30 +257,31 @@
|
|||
switch (e.data.type) {
|
||||
case "setMindMapData":
|
||||
setData(e.data.nodes);
|
||||
window.workspaceType = e.data.workspaceType;
|
||||
break;
|
||||
case "saveImage":
|
||||
const imgString = Diagram.makeImageData({
|
||||
scale: 1,
|
||||
});
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "saveImageReturn",
|
||||
image: imgString,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
break;
|
||||
case "saveSVG":
|
||||
const svgElement = Diagram.makeSvg({
|
||||
scale: 1,
|
||||
});
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "saveSVGReturn",
|
||||
image: svgElement.outerHTML,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
<svg t="1710401595942" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4073"
|
||||
width="20" height="20">
|
||||
<path
|
||||
d="M512 521.216c-24.064 0-45.568-4.608-65.024-9.216l-2.048-0.512-296.96-124.928c-31.232-13.824-50.176-39.424-50.176-66.56s19.456-52.736 50.176-66.56l1.024-0.512L445.44 131.072c39.424-15.872 96.768-15.872 136.192 0L877.056 250.88c31.232 13.824 50.176 39.424 50.176 66.56 0 28.672-19.456 54.272-51.2 66.56l-295.424 123.904c-21.504 8.704-46.592 13.312-68.608 13.312z m-48.128-68.096c14.336 3.584 30.72 7.168 48.128 7.168 14.336 0 31.744-3.072 46.08-8.704L852.48 327.68c8.704-3.584 12.288-7.68 12.8-9.728-1.024-2.048-5.12-6.656-13.312-10.752L558.08 188.416c-24.576-9.728-65.024-9.728-90.112 0L172.032 309.76c-7.68 3.584-11.776 8.192-13.312 10.24 1.024 2.048 5.632 6.656 13.312 10.24l291.84 122.88z"
|
||||
p-id="4074" fill="context-fill"></path>
|
||||
<path
|
||||
d="M512 712.192c-26.624 0-50.176-4.608-69.632-9.216l-2.048-0.512-2.048-1.024-321.024-123.904c-15.872-6.144-23.552-24.064-17.408-39.936 6.144-15.872 24.064-23.552 39.936-17.408l318.976 122.88c15.872 3.584 34.304 7.168 53.76 7.168 16.384 0 35.84-3.072 52.224-8.704l320.512-123.392c15.872-6.144 33.792 1.536 39.936 17.408s-1.536 33.792-17.408 39.936l-322.048 123.904c-23.552 8.192-50.176 12.8-73.728 12.8z"
|
||||
p-id="4075" fill="context-fill"></path>
|
||||
<path
|
||||
d="M512 889.856c-26.624 0-50.176-4.608-69.632-9.216l-2.048-0.512-2.048-1.024-321.024-123.904c-15.872-6.144-23.552-24.064-17.408-39.936 6.144-15.872 24.064-23.552 39.936-17.408l318.976 122.88c15.872 3.584 34.304 7.168 53.76 7.168 16.384 0 35.84-3.072 52.224-8.704l320.512-123.392c15.872-6.144 33.792 1.536 39.936 17.408s-1.536 33.792-17.408 39.936l-322.048 123.904c-23.552 8.704-50.176 12.8-73.728 12.8z"
|
||||
p-id="4076" fill="context-fill"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
<svg t="1710402054079" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="16029" width="20" height="20">
|
||||
<path
|
||||
d="M246.153846 194.166154h59.076923v111.064615a118.153846 118.153846 0 0 0 118.153846 118.153846h177.23077a118.153846 118.153846 0 0 0 118.153846-118.153846v-111.064615h59.076923a51.987692 51.987692 0 0 1 51.987692 51.987692v262.301539a33.083077 33.083077 0 1 0 66.166154 0v-262.301539a118.153846 118.153846 0 0 0-118.153846-118.153846h-531.692308a118.153846 118.153846 0 0 0-118.153846 118.153846v531.692308a118.153846 118.153846 0 0 0 118.153846 118.153846h203.224616a33.083077 33.083077 0 1 0 0-66.166154h-203.224616a51.987692 51.987692 0 0 1-51.987692-51.987692v-531.692308a51.987692 51.987692 0 0 1 51.987692-51.987692z m125.243077 111.064615v-111.064615h281.206154v111.064615a51.987692 51.987692 0 0 1-51.987692 51.987693h-177.23077a51.987692 51.987692 0 0 1-51.987692-51.987693z"
|
||||
p-id="16030" fill="context-fill"></path>
|
||||
<path
|
||||
d="M478.916923 692.460308h290.500923l-45.449846-45.449846a33.083077 33.083077 0 1 1 46.788923-46.710154l97.437539 97.437538a39.384615 39.384615 0 0 1 0 55.689846l-97.437539 97.516308a33.083077 33.083077 0 0 1-46.788923-46.788923l45.449846-45.528615H478.916923a33.083077 33.083077 0 1 1 0-66.166154z"
|
||||
p-id="16031" fill="context-fill"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -146,7 +146,7 @@
|
|||
});
|
||||
|
||||
// read in the predefined graph using the JSON format data held in the "mySavedModel" textarea
|
||||
window.parent.postMessage({ type: "ready" }, "*");
|
||||
window.postMessage({ type: "ready" }, "*");
|
||||
getData();
|
||||
}
|
||||
|
||||
|
|
@ -240,7 +240,7 @@
|
|||
}
|
||||
|
||||
function getData() {
|
||||
window.parent.postMessage({ type: "getMindMapData" }, "*");
|
||||
window.postMessage({ type: "getMindMapData" }, "*");
|
||||
}
|
||||
|
||||
function setData(nodes) {
|
||||
|
|
@ -281,17 +281,16 @@
|
|||
var oldnode = adorn.adornedPart;
|
||||
var olddata = oldnode.data;
|
||||
if (olddata.noteLink) {
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{ type: "openNote", link: olddata.noteLink, id: olddata.key },
|
||||
"*",
|
||||
);
|
||||
} else {
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "jumpNode",
|
||||
lineIndex: olddata.lineIndex,
|
||||
id: olddata.key,
|
||||
workspaceType: window.workspaceType || "tab",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
|
@ -305,12 +304,11 @@
|
|||
alert("Link cannot be edited in mind map");
|
||||
return false;
|
||||
}
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "editNode",
|
||||
lineIndex: data.lineIndex,
|
||||
text: data.text,
|
||||
workspaceType: window.workspaceType || "tab",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
|
@ -321,30 +319,31 @@
|
|||
switch (e.data.type) {
|
||||
case "setMindMapData":
|
||||
setData(e.data.nodes);
|
||||
window.workspaceType = e.data.workspaceType;
|
||||
break;
|
||||
case "saveImage":
|
||||
const imgString = Diagram.makeImageData({
|
||||
scale: 1,
|
||||
});
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "saveImageReturn",
|
||||
image: imgString,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
break;
|
||||
case "saveSVG":
|
||||
const svgElement = Diagram.makeSvg({
|
||||
scale: 1,
|
||||
});
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "saveSVGReturn",
|
||||
image: svgElement.outerHTML,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -354,7 +353,7 @@
|
|||
try {
|
||||
init();
|
||||
} catch (e) {
|
||||
window.parent.postMessage({ type: "error", event: e }, "*");
|
||||
window.postMessage({ type: "error", event: e }, "*");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
bn-context {
|
||||
min-width: 182px;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
bn-details pane-header {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
.primary-editor > h1::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3E%E6%9C%AA%E6%A0%87%E9%A2%98-1%3C%2Ftitle%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M12.29%2C16.8H11.14V12.33H6.07V16.8H4.92V7H6.07v4.3h5.07V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M18.05%2C16.8H16.93V8.41a4%2C4%2C0%2C0%2C1-.9.53%2C6.52%2C6.52%2C0%2C0%2C1-1.14.44l-.32-1a8.2%2C8.2%2C0%2C0%2C0%2C1.67-.67%2C6.31%2C6.31%2C0%2C0%2C0%2C1.39-1h.42Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h2::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.a%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22a%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22a%22%20d%3D%22M14.14%2C16.8v-.48a4.1%2C4.1%2C0%2C0%2C1%2C.14-1.11%2C2.86%2C2.86%2C0%2C0%2C1%2C.45-.91%2C5.49%2C5.49%2C0%2C0%2C1%2C.83-.86c.33-.29.75-.61%2C1.24-1a7.43%2C7.43%2C0%2C0%2C0%2C.9-.73%2C3.9%2C3.9%2C0%2C0%2C0%2C.57-.7%2C2.22%2C2.22%2C0%2C0%2C0%2C.3-.66%2C2.87%2C2.87%2C0%2C0%2C0%2C.11-.77%2C1.89%2C1.89%2C0%2C0%2C0-.47-1.32%2C1.66%2C1.66%2C0%2C0%2C0-1.28-.5A3.17%2C3.17%2C0%2C0%2C0%2C15.7%2C8a3.49%2C3.49%2C0%2C0%2C0-1.08.76l-.68-.65a4.26%2C4.26%2C0%2C0%2C1%2C1.39-1A4%2C4%2C0%2C0%2C1%2C17%2C6.84a2.62%2C2.62%2C0%2C0%2C1%2C2.83%2C2.67%2C3.58%2C3.58%2C0%2C0%2C1-.15%2C1%2C3.09%2C3.09%2C0%2C0%2C1-.41.9%2C5.53%2C5.53%2C0%2C0%2C1-.67.81%2C9%2C9%2C0%2C0%2C1-.95.79c-.46.32-.84.59-1.13.82a4.68%2C4.68%2C0%2C0%2C0-.71.64%2C2%2C2%2C0%2C0%2C0-.38.6%2C2.08%2C2.08%2C0%2C0%2C0-.11.69h4.88v1Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22a%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h3::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M14%2C16.14l.51-.8a4.75%2C4.75%2C0%2C0%2C0%2C1.1.52%2C4.27%2C4.27%2C0%2C0%2C0%2C1.12.16%2C2.29%2C2.29%2C0%2C0%2C0%2C1.64-.52A1.77%2C1.77%2C0%2C0%2C0%2C19%2C14.17a1.7%2C1.7%2C0%2C0%2C0-.68-1.48%2C3.6%2C3.6%2C0%2C0%2C0-2.06-.48H15.4v-1h.77A3%2C3%2C0%2C0%2C0%2C18%2C10.81a1.65%2C1.65%2C0%2C0%2C0%2C.6-1.41%2C1.47%2C1.47%2C0%2C0%2C0-.47-1.19A1.67%2C1.67%2C0%2C0%2C0%2C17%2C7.79a3.33%2C3.33%2C0%2C0%2C0-2.08.73l-.59-.75a4.4%2C4.4%2C0%2C0%2C1%2C1.28-.71A4.35%2C4.35%2C0%2C0%2C1%2C17%2C6.84a2.84%2C2.84%2C0%2C0%2C1%2C2%2C.65%2C2.21%2C2.21%2C0%2C0%2C1%2C.74%2C1.78%2C2.35%2C2.35%2C0%2C0%2C1-.49%2C1.5%2C2.7%2C2.7%2C0%2C0%2C1-1.46.89v0a2.74%2C2.74%2C0%2C0%2C1%2C1.65.74%2C2.15%2C2.15%2C0%2C0%2C1%2C.66%2C1.65%2C2.64%2C2.64%2C0%2C0%2C1-.9%2C2.12%2C3.44%2C3.44%2C0%2C0%2C1-2.34.78%2C5.3%2C5.3%2C0%2C0%2C1-1.48-.2A5%2C5%2C0%2C0%2C1%2C14%2C16.14Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h4::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M19.43%2C6.92v6.59h1.05v1.05H19.43V16.9H18.31V14.56H13.66v-1c.43-.49.87-1%2C1.31-1.57s.87-1.13%2C1.27-1.7S17%2C9.14%2C17.36%2C8.57a16.51%2C16.51%2C0%2C0%2C0%2C.86-1.65Zm-4.49%2C6.59h3.37V8.63c-.34.61-.67%2C1.15-1%2C1.63s-.6.91-.87%2C1.3-.56.74-.81%2C1Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h5::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M14%2C16l.58-.76a3.67%2C3.67%2C0%2C0%2C0%2C1%2C.58A3.44%2C3.44%2C0%2C0%2C0%2C16.8%2C16a2.17%2C2.17%2C0%2C0%2C0%2C1.58-.6A2%2C2%2C0%2C0%2C0%2C19%2C13.88a1.85%2C1.85%2C0%2C0%2C0-.64-1.5%2C2.83%2C2.83%2C0%2C0%2C0-1.86-.54c-.27%2C0-.55%2C0-.86%2C0s-.58%2C0-.81.06L15.17%2C7H19.7V8H16.14l-.2%2C2.88.47%2C0h.43a3.5%2C3.5%2C0%2C0%2C1%2C2.43.79%2C2.74%2C2.74%2C0%2C0%2C1%2C.88%2C2.16%2C3%2C3%2C0%2C0%2C1-.94%2C2.3%2C3.41%2C3.41%2C0%2C0%2C1-2.4.87%2C4.45%2C4.45%2C0%2C0%2C1-1.5-.24A4.81%2C4.81%2C0%2C0%2C1%2C14%2C16Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h6::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M20.18%2C13.7a3.24%2C3.24%2C0%2C0%2C1-.88%2C2.38%2C2.94%2C2.94%2C0%2C0%2C1-2.2.9%2C2.69%2C2.69%2C0%2C0%2C1-2.31-1.17A5.59%2C5.59%2C0%2C0%2C1%2C14%2C12.49a12.18%2C12.18%2C0%2C0%2C1%2C.2-2.14%2C5.16%2C5.16%2C0%2C0%2C1%2C.84-2A3.65%2C3.65%2C0%2C0%2C1%2C16.27%2C7.2%2C3.71%2C3.71%2C0%2C0%2C1%2C18%2C6.84%2C3.14%2C3.14%2C0%2C0%2C1%2C19%2C7a3.59%2C3.59%2C0%2C0%2C1%2C1%2C.5l-.56.77a2.3%2C2.3%2C0%2C0%2C0-1.49-.48A2.3%2C2.3%2C0%2C0%2C0%2C16.79%2C8a3%2C3%2C0%2C0%2C0-.92.85%2C3.79%2C3.79%2C0%2C0%2C0-.56%2C1.25%2C6.56%2C6.56%2C0%2C0%2C0-.19%2C1.65h0a2.61%2C2.61%2C0%2C0%2C1%2C1-.84%2C2.91%2C2.91%2C0%2C0%2C1%2C1.23-.28%2C2.63%2C2.63%2C0%2C0%2C1%2C2%2C.85A3.09%2C3.09%2C0%2C0%2C1%2C20.18%2C13.7ZM19%2C13.78a2.28%2C2.28%2C0%2C0%2C0-.5-1.62%2C1.67%2C1.67%2C0%2C0%2C0-1.29-.54%2C2%2C2%2C0%2C0%2C0-1.5.58%2C2%2C2%2C0%2C0%2C0-.56%2C1.4%2C2.65%2C2.65%2C0%2C0%2C0%2C.55%2C1.74%2C1.85%2C1.85%2C0%2C0%2C0%2C2.78.1A2.38%2C2.38%2C0%2C0%2C0%2C19%2C13.78Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > p,
|
||||
.primary-editor h1,
|
||||
.primary-editor h2,
|
||||
.primary-editor h3,
|
||||
.primary-editor h4,
|
||||
.primary-editor h5,
|
||||
.primary-editor h6,
|
||||
.primary-editor pre,
|
||||
.primary-editor blockquote,
|
||||
.primary-editor table,
|
||||
.primary-editor ul,
|
||||
.primary-editor ol,
|
||||
.primary-editor hr {
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
body[no-bn-toolbar] #BetterNotes-toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
bn-outline,
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--material-sidepane);
|
||||
}
|
||||
|
||||
bn-outline {
|
||||
min-width: 100px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (-moz-platform: macos) {
|
||||
#__addonRef__-left-toolbar {
|
||||
-moz-window-dragging: drag;
|
||||
}
|
||||
}
|
||||
|
||||
#__addonRef__-left-toolbar {
|
||||
background: var(--material-toolbar);
|
||||
border-bottom: var(--material-panedivider);
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
bn-outline .zotero-tb-button {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin: 0px 4px 0px 4px;
|
||||
fill: currentColor;
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
}
|
||||
|
||||
#__addonRef__-setOutline {
|
||||
list-style-image: url("chrome://__addonRef__/content/icons/outline-20.svg");
|
||||
}
|
||||
|
||||
#__addonRef__-saveOutline {
|
||||
list-style-image: url("chrome://__addonRef__/content/icons/save-20.svg");
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
bn-workspace,
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--material-sidepane);
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
bn-workspace #__addonRef__-editor-main #links-container {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
}
|
||||
|
||||
#treeview {
|
||||
padding: 20px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.drive-header {
|
||||
|
|
@ -72,13 +72,18 @@
|
|||
color: var(--fill-primary);
|
||||
}
|
||||
|
||||
.dx-treeview-item {
|
||||
border-radius: 5px;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.dx-treeview-toggle-item-visibility {
|
||||
color: var(--fill-primary);
|
||||
}
|
||||
|
||||
:not(.dx-state-focused) > .dx-treeview-item.dx-state-hover {
|
||||
color: var(--fill-primary);
|
||||
background-color: var(--fill-quinary);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.dx-state-focused > .dx-treeview-item {
|
||||
|
|
@ -94,7 +99,7 @@
|
|||
var cachedNodes = null;
|
||||
function init() {
|
||||
window.addEventListener("message", handler, false);
|
||||
window.parent.postMessage({ type: "ready" }, "*");
|
||||
window.postMessage({ type: "ready" }, "*");
|
||||
getData();
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +156,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "moveNode",
|
||||
fromID: parseInt(fromNode.itemData.id),
|
||||
|
|
@ -295,7 +300,7 @@
|
|||
function jumpNode(e) {
|
||||
var itemData = e.itemData;
|
||||
if (itemData.noteLink) {
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "openNote",
|
||||
link: itemData.noteLink,
|
||||
|
|
@ -304,12 +309,11 @@
|
|||
"*",
|
||||
);
|
||||
} else {
|
||||
window.parent.postMessage(
|
||||
window.postMessage(
|
||||
{
|
||||
type: "jumpNode",
|
||||
lineIndex: itemData.lineIndex,
|
||||
id: parseInt(itemData.id),
|
||||
workspaceType: window.workspaceType || "tab",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
|
@ -319,7 +323,7 @@
|
|||
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" }, "*");
|
||||
window.postMessage({ type: "getMindMapData" }, "*");
|
||||
}
|
||||
|
||||
function setData(nodes, expandLevel) {
|
||||
|
|
@ -384,7 +388,6 @@
|
|||
console.log(e);
|
||||
if (e.data.type === "setMindMapData") {
|
||||
setData(e.data.nodes, e.data.expandLevel);
|
||||
window.workspaceType = e.data.workspaceType;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -392,7 +395,7 @@
|
|||
try {
|
||||
init();
|
||||
} catch (e) {
|
||||
window.parent.postMessage({ type: "error", event: e }, "*");
|
||||
window.postMessage({ type: "error", event: e }, "*");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
setOutline =
|
||||
.tooltiptext = Change outline mode
|
||||
useTreeView =
|
||||
.label = Tree View
|
||||
useMindMap =
|
||||
.label = Mind Map
|
||||
useBubbleMap =
|
||||
.label = Bubble Map
|
||||
saveOutline =
|
||||
.tooltiptext = Save as...
|
||||
saveOutlineImage =
|
||||
.label = Outline image
|
||||
.tooltiptext = Only in mind map/bubble map mode
|
||||
saveOutlineSVG =
|
||||
.label = Outline SVG
|
||||
.tooltiptext = Only in mind map/bubble map mode
|
||||
saveOutlineFreeMind =
|
||||
.label = Outline FreeMind
|
||||
saveMore =
|
||||
.label = MarkDown, Docx, PDF...
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
"unist-util-visit": "^5.0.0",
|
||||
"unist-util-visit-parents": "^6.0.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"zotero-plugin-toolkit": "^2.3.23"
|
||||
"zotero-plugin-toolkit": "^2.3.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||
|
|
|
|||
|
|
@ -5,19 +5,9 @@ const buildDir = "build";
|
|||
|
||||
export async function main() {
|
||||
await build({
|
||||
entryPoints: ["src/extras/editorScript.ts"],
|
||||
entryPoints: ["./src/extras/*.ts"],
|
||||
outdir: path.join(buildDir, "addon/chrome/content/scripts"),
|
||||
bundle: true,
|
||||
outfile: path.join(
|
||||
buildDir,
|
||||
"addon/chrome/content/scripts/editorScript.js",
|
||||
),
|
||||
target: ["firefox102"],
|
||||
}).catch(() => exit(1));
|
||||
|
||||
await build({
|
||||
entryPoints: ["src/extras/docxWorker.ts"],
|
||||
bundle: true,
|
||||
outfile: path.join(buildDir, "addon/chrome/content/scripts/docxWorker.js"),
|
||||
target: ["firefox102"],
|
||||
}).catch(() => exit(1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ function replaceString(buildTime) {
|
|||
`${buildDir}/addon/**/*.xhtml`,
|
||||
`${buildDir}/addon/**/*.html`,
|
||||
`${buildDir}/addon/**/*.json`,
|
||||
`${buildDir}/addon/**/*.css`,
|
||||
`${buildDir}/addon/prefs.js`,
|
||||
`${buildDir}/addon/manifest.json`,
|
||||
`${buildDir}/addon/bootstrap.js`,
|
||||
|
|
|
|||
48
src/addon.ts
48
src/addon.ts
|
|
@ -7,7 +7,6 @@ import { LargePrefHelper } from "zotero-plugin-toolkit/dist/helpers/largePref";
|
|||
import ToolkitGlobal from "zotero-plugin-toolkit/dist/managers/toolkitGlobal";
|
||||
|
||||
import { getPref, setPref } from "./utils/prefs";
|
||||
import { OutlineType } from "./utils/workspace";
|
||||
import { SyncDataType } from "./modules/sync/managerWindow";
|
||||
import hooks from "./hooks";
|
||||
import api from "./api";
|
||||
|
|
@ -46,21 +45,6 @@ class Addon {
|
|||
};
|
||||
};
|
||||
notify: Array<Parameters<_ZoteroTypes.Notifier.Notify>>;
|
||||
workspace: {
|
||||
mainId: number;
|
||||
previewId: number;
|
||||
tab: {
|
||||
active: boolean;
|
||||
id?: string;
|
||||
container?: XUL.Box;
|
||||
};
|
||||
window: {
|
||||
active: boolean;
|
||||
window?: Window;
|
||||
container?: XUL.Box;
|
||||
};
|
||||
outline: OutlineType;
|
||||
};
|
||||
imageViewer: {
|
||||
window?: Window;
|
||||
srcList: string[];
|
||||
|
|
@ -105,38 +89,6 @@ class Addon {
|
|||
diff: {},
|
||||
},
|
||||
notify: [],
|
||||
workspace: {
|
||||
get mainId(): number {
|
||||
return parseInt(getPref("mainKnowledgeID") as string);
|
||||
},
|
||||
set mainId(id: number) {
|
||||
setPref("mainKnowledgeID", id);
|
||||
const recentMainNoteIds = getPref("recentMainNoteIds") as string;
|
||||
const recentMainNoteIdsArr = recentMainNoteIds
|
||||
? recentMainNoteIds.split(",").map((id) => parseInt(id))
|
||||
: [];
|
||||
const idx = recentMainNoteIdsArr.indexOf(id);
|
||||
if (idx !== -1) {
|
||||
recentMainNoteIdsArr.splice(idx, 1);
|
||||
}
|
||||
recentMainNoteIdsArr.unshift(id);
|
||||
setPref(
|
||||
"recentMainNoteIds",
|
||||
recentMainNoteIdsArr
|
||||
.slice(0, 10)
|
||||
.filter((id) => Zotero.Items.get(id).isNote())
|
||||
.join(","),
|
||||
);
|
||||
},
|
||||
previewId: -1,
|
||||
tab: {
|
||||
active: false,
|
||||
},
|
||||
window: {
|
||||
active: false,
|
||||
},
|
||||
outline: OutlineType.treeView,
|
||||
},
|
||||
imageViewer: {
|
||||
window: undefined,
|
||||
srcList: [],
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ import {
|
|||
DEFAULT_TEMPLATES,
|
||||
} from "./modules/template/data";
|
||||
import { renderTemplatePreview } from "./modules/template/preview";
|
||||
import { getWorkspaceEditor } from "./modules/workspace/content";
|
||||
import { parseCitationHTML } from "./utils/citation";
|
||||
import {
|
||||
getEditorInstance,
|
||||
|
|
@ -65,11 +64,10 @@ import {
|
|||
addLineToNote,
|
||||
updateRelatedNotes,
|
||||
getRelatedNoteIds,
|
||||
getNoteTreeFlattened,
|
||||
} from "./utils/note";
|
||||
|
||||
const workspace = {
|
||||
getWorkspaceEditor,
|
||||
};
|
||||
const workspace = {};
|
||||
|
||||
const sync = {
|
||||
isSyncNote,
|
||||
|
|
@ -148,6 +146,7 @@ const note = {
|
|||
insert: addLineToNote,
|
||||
updateRelatedNotes,
|
||||
getRelatedNoteIds,
|
||||
getNoteTreeFlattened,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
import { config } from "../../package.json";
|
||||
|
||||
export class PluginCEBase extends XULElementBase {
|
||||
_addon!: typeof addon;
|
||||
|
||||
connectedCallback(): void {
|
||||
this._addon = Zotero[config.addonInstance];
|
||||
Zotero.UIProperties.registerRoot(this);
|
||||
super.connectedCallback();
|
||||
}
|
||||
|
||||
_wrapID(key: string) {
|
||||
if (key.startsWith(config.addonRef)) {
|
||||
return key;
|
||||
}
|
||||
return `${config.addonRef}-${key}`;
|
||||
}
|
||||
|
||||
_unwrapID(id: string) {
|
||||
if (id.startsWith(config.addonRef)) {
|
||||
return id.slice(config.addonRef.length + 1);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
_queryID(key: string) {
|
||||
return this.querySelector(`#${this._wrapID(key)}`) as XUL.Element | null;
|
||||
}
|
||||
|
||||
_parseContentID(dom: DocumentFragment) {
|
||||
dom.querySelectorAll("*[id]").forEach(elem => {
|
||||
elem.id = this._wrapID(elem.id);
|
||||
})
|
||||
return dom;
|
||||
}
|
||||
|
||||
_loadPersist() {
|
||||
const persistValues = Zotero.Prefs.get("pane.persist") as string;
|
||||
if (!persistValues) return;
|
||||
const serializedValues = JSON.parse(persistValues) as Record<
|
||||
string,
|
||||
Record<string, string>
|
||||
>;
|
||||
|
||||
for (const id in serializedValues) {
|
||||
const el = this.querySelector(`#${id}`) as HTMLElement;
|
||||
if (!el) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const elValues = serializedValues[id];
|
||||
for (const attr in elValues) {
|
||||
el.setAttribute(attr, elValues[attr]);
|
||||
if (["width", "height"].includes(attr)) {
|
||||
el.style[attr as any] = `${elValues[attr]}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { config } from "../../package.json";
|
||||
import { PluginCEBase } from "./base";
|
||||
|
||||
export class ContextPane extends PluginCEBase {
|
||||
_item?: Zotero.Item;
|
||||
|
||||
_details!: any;
|
||||
_sidenav: any;
|
||||
|
||||
get item() {
|
||||
return this._item;
|
||||
}
|
||||
|
||||
set item(val) {
|
||||
this._item = val;
|
||||
}
|
||||
|
||||
get content() {
|
||||
return this._parseContentID(
|
||||
MozXULElement.parseXULToFragment(`
|
||||
<linkset>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://${config.addonRef}/content/styles/context.css"
|
||||
></html:link>
|
||||
</linkset>
|
||||
<bn-details id="container" class="container"></bn-details>
|
||||
<item-pane-sidenav id="sidenav"></item-pane-sidenav>
|
||||
`),
|
||||
);
|
||||
}
|
||||
|
||||
init(): void {
|
||||
this._details = this._queryID("container");
|
||||
this._sidenav = this._queryID("sidenav");
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.item) return;
|
||||
this._details.mode = this.item.isEditable() ? null : "view";
|
||||
this._details.item = this.item;
|
||||
this._details.parentID = this.item.parentID;
|
||||
this._details.sidenav = this._sidenav;
|
||||
this._details.render();
|
||||
this._sidenav.toggleDefaultStatus();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { config } from "../../package.json";
|
||||
const ItemDetails = customElements.get("item-details")! as any;
|
||||
|
||||
export class NoteDetails extends ItemDetails {
|
||||
content = MozXULElement.parseXULToFragment(`
|
||||
<linkset>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://${config.addonRef}/content/styles/details.css"
|
||||
></html:link>
|
||||
</linkset>
|
||||
<hbox id="zotero-view-item-container" class="zotero-view-item-container" flex="1">
|
||||
<html:div class="zotero-view-item-main">
|
||||
<pane-header id="zotero-item-pane-header" />
|
||||
<html:div id="zotero-view-item" class="zotero-view-item" tabindex="0">
|
||||
<tags-box id="zotero-editpane-tags" class="zotero-editpane-tags" data-pane="tags" />
|
||||
|
||||
<related-box id="zotero-editpane-related" class="zotero-editpane-related"
|
||||
data-pane="related" />
|
||||
</html:div>
|
||||
</html:div>
|
||||
</hbox>`);
|
||||
|
||||
forceUpdateSideNav() {
|
||||
this._sidenav
|
||||
.querySelectorAll("toolbarbutton")
|
||||
.forEach((elem: HTMLElement) => (elem.parentElement!.hidden = true));
|
||||
super.forceUpdateSideNav();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,379 @@
|
|||
import { FilePickerHelper } from "zotero-plugin-toolkit/dist/helpers/filePicker";
|
||||
import { config } from "../../package.json";
|
||||
import { showHintWithLink } from "../utils/hint";
|
||||
import { formatPath } from "../utils/str";
|
||||
import { waitUtilAsync } from "../utils/wait";
|
||||
import { OutlineType } from "../utils/workspace";
|
||||
import { PluginCEBase } from "./base";
|
||||
import {
|
||||
getEditorInstance,
|
||||
moveHeading,
|
||||
updateHeadingTextAtLine,
|
||||
} from "../utils/editor";
|
||||
import { getNoteLinkParams } from "../utils/link";
|
||||
import { getNoteTree, getNoteTreeNodeById } from "../utils/note";
|
||||
import { getPref } from "../utils/prefs";
|
||||
|
||||
export class OutlinePane extends PluginCEBase {
|
||||
_outlineType: OutlineType = OutlineType.empty;
|
||||
_item?: Zotero.Item;
|
||||
_editorElement!: EditorElement;
|
||||
|
||||
_outlineContainer!: HTMLIFrameElement;
|
||||
_notifierID!: string;
|
||||
|
||||
static outlineSources = [
|
||||
"",
|
||||
`chrome://${config.addonRef}/content/treeView.html`,
|
||||
`chrome://${config.addonRef}/content/mindMap.html`,
|
||||
`chrome://${config.addonRef}/content/bubbleMap.html`,
|
||||
];
|
||||
|
||||
static outlineMenuIDs = {
|
||||
"": OutlineType.empty,
|
||||
useTreeView: OutlineType.treeView,
|
||||
useMindMap: OutlineType.mindMap,
|
||||
useBubbleMap: OutlineType.bubbleMap,
|
||||
};
|
||||
|
||||
get content() {
|
||||
return this._parseContentID(
|
||||
MozXULElement.parseXULToFragment(`
|
||||
<linkset>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://${config.addonRef}/content/styles/outline.css"
|
||||
></html:link>
|
||||
</linkset>
|
||||
<hbox id="left-toolbar">
|
||||
<toolbarbutton
|
||||
id="setOutline"
|
||||
class="zotero-tb-button"
|
||||
data-l10n-id="${config.addonRef}-setOutline"
|
||||
type="menu"
|
||||
wantdropmarker="true"
|
||||
>
|
||||
<menupopup id="setOutlinePopup">
|
||||
<menuitem
|
||||
id="useTreeView"
|
||||
type="radio"
|
||||
data-l10n-id="${config.addonRef}-useTreeView"
|
||||
></menuitem>
|
||||
<menuitem
|
||||
id="useMindMap"
|
||||
type="radio"
|
||||
data-l10n-id="${config.addonRef}-useMindMap"
|
||||
></menuitem>
|
||||
<menuitem
|
||||
id="useBubbleMap"
|
||||
type="radio"
|
||||
data-l10n-id="${config.addonRef}-useBubbleMap"
|
||||
></menuitem>
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
<toolbarbutton
|
||||
id="saveOutline"
|
||||
class="zotero-tb-button"
|
||||
data-l10n-id="${config.addonRef}-saveOutline"
|
||||
type="menu"
|
||||
wantdropmarker="true"
|
||||
>
|
||||
<menupopup id="saveOutlinePopup">
|
||||
<menuitem
|
||||
id="saveImage"
|
||||
data-l10n-id="${config.addonRef}-saveOutlineImage"
|
||||
></menuitem>
|
||||
<menuitem
|
||||
id="saveSVG"
|
||||
data-l10n-id="${config.addonRef}-saveOutlineSVG"
|
||||
></menuitem>
|
||||
<menuitem
|
||||
id="saveFreeMind"
|
||||
data-l10n-id="${config.addonRef}-saveOutlineFreeMind"
|
||||
></menuitem>
|
||||
<menuitem
|
||||
id="saveMore"
|
||||
data-l10n-id="${config.addonRef}-saveMore"
|
||||
></menuitem>
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
</hbox>
|
||||
<iframe id="outline" class="container"></iframe>`),
|
||||
);
|
||||
}
|
||||
|
||||
get outlineType() {
|
||||
return this._outlineType;
|
||||
}
|
||||
|
||||
set outlineType(newType) {
|
||||
if (newType === OutlineType.empty) {
|
||||
newType = OutlineType.treeView;
|
||||
}
|
||||
if (newType > OutlineType.bubbleMap) {
|
||||
newType = OutlineType.treeView;
|
||||
}
|
||||
|
||||
this._outlineType = newType;
|
||||
}
|
||||
|
||||
get item() {
|
||||
return this._item;
|
||||
}
|
||||
|
||||
set item(val) {
|
||||
this._item = val;
|
||||
}
|
||||
|
||||
get editor() {
|
||||
return this._editorElement._editorInstance;
|
||||
}
|
||||
|
||||
init(): void {
|
||||
MozXULElement.insertFTLIfNeeded(`${config.addonRef}-outline.ftl`);
|
||||
|
||||
this._outlineContainer = this._queryID("outline") as unknown as HTMLIFrameElement;
|
||||
|
||||
this._queryID("left-toolbar")?.addEventListener(
|
||||
"command",
|
||||
this.toolbarButtonCommandHandler,
|
||||
);
|
||||
|
||||
this._notifierID = Zotero.Notifier.registerObserver(
|
||||
this,
|
||||
["item"],
|
||||
"attachmentsBox",
|
||||
);
|
||||
|
||||
this._loadPersist();
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
Zotero.Notifier.unregisterObserver(this._notifierID);
|
||||
this._outlineContainer.contentWindow?.removeEventListener(
|
||||
"message",
|
||||
this.messageHandler,
|
||||
);
|
||||
}
|
||||
|
||||
notify(
|
||||
event: string,
|
||||
type: string,
|
||||
ids: number[] | string[],
|
||||
extraData: { [key: string]: any },
|
||||
) {
|
||||
if (!this.item) return;
|
||||
if (event === "modify" && type === "item") {
|
||||
if ((ids as number[]).includes(this.item.id)) {
|
||||
this.updateOutline();
|
||||
if (getPref("workspace.autoUpdateRelatedNotes")) {
|
||||
this._addon.api.note.updateRelatedNotes(this.item.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async render() {
|
||||
if (this.outlineType === OutlineType.empty) {
|
||||
this.outlineType = OutlineType.treeView;
|
||||
}
|
||||
await this.updateOutline();
|
||||
}
|
||||
|
||||
async updateOutline() {
|
||||
if (!this.item) return;
|
||||
|
||||
this._outlineContainer.contentWindow?.removeEventListener(
|
||||
"message",
|
||||
this.messageHandler,
|
||||
);
|
||||
|
||||
this._outlineContainer.setAttribute("src", OutlinePane.outlineSources[this.outlineType]);
|
||||
|
||||
await waitUtilAsync(
|
||||
() => this._outlineContainer.contentWindow?.document.readyState === "complete",
|
||||
);
|
||||
this._outlineContainer.contentWindow?.addEventListener(
|
||||
"message",
|
||||
this.messageHandler,
|
||||
);
|
||||
this._outlineContainer.contentWindow?.postMessage(
|
||||
{
|
||||
type: "setMindMapData",
|
||||
nodes: this._addon.api.note.getNoteTreeFlattened(this.item, {
|
||||
keepLink: !!getPref("workspace.outline.keepLinks"),
|
||||
}),
|
||||
expandLevel: getPref("workspace.outline.expandLevel"),
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
||||
// Update button hidden
|
||||
const isTreeView = this.outlineType === OutlineType.treeView;
|
||||
for (const key of ["saveImage", "saveSVG"]) {
|
||||
const elem = this._queryID(key);
|
||||
if (isTreeView) {
|
||||
elem?.setAttribute("disabled", "true");
|
||||
} else {
|
||||
elem?.removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
// Update set outline menu
|
||||
this._queryID("setOutlinePopup")?.childNodes.forEach((elem) =>
|
||||
(elem as XUL.MenuItem).removeAttribute("checked"),
|
||||
);
|
||||
this._queryID(
|
||||
Object.keys(OutlinePane.outlineMenuIDs)[this.outlineType],
|
||||
)?.setAttribute("checked", "true");
|
||||
}
|
||||
|
||||
saveImage(type: "saveSVG" | "saveImage") {
|
||||
this._outlineContainer.contentWindow?.postMessage(
|
||||
{
|
||||
type,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
|
||||
async saveFreeMind() {
|
||||
if (!this.item?.id) return;
|
||||
// TODO: uncouple this part
|
||||
const filename = await new FilePickerHelper(
|
||||
`${Zotero.getString("fileInterface.export")} FreeMind XML`,
|
||||
"save",
|
||||
[["FreeMind XML File(*.mm)", "*.mm"]],
|
||||
`${this.item.getNoteTitle()}.mm`,
|
||||
).open();
|
||||
if (filename) {
|
||||
await addon.api.$export.saveFreeMind(filename, this.item.id);
|
||||
}
|
||||
}
|
||||
|
||||
toolbarButtonCommandHandler = async (ev: Event) => {
|
||||
if (!this.item) return;
|
||||
const type = this._unwrapID((ev.target as XUL.ToolBarButton).id);
|
||||
switch (type) {
|
||||
case "useTreeView":
|
||||
case "useMindMap":
|
||||
case "useBubbleMap": {
|
||||
this.outlineType = OutlinePane.outlineMenuIDs[type];
|
||||
await this.updateOutline();
|
||||
break;
|
||||
}
|
||||
case "saveImage":
|
||||
case "saveSVG": {
|
||||
this.saveImage(type);
|
||||
break;
|
||||
}
|
||||
case "saveFreeMind": {
|
||||
this.saveFreeMind();
|
||||
break;
|
||||
}
|
||||
case "saveMore": {
|
||||
this._addon.hooks.onShowExportNoteOptions([this.item.id]);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
messageHandler = async (ev: MessageEvent) => {
|
||||
switch (ev.data.type) {
|
||||
case "jumpNode": {
|
||||
if (!this.editor) {
|
||||
return;
|
||||
}
|
||||
this._addon.api.editor.scroll(this.editor, ev.data.lineIndex);
|
||||
return;
|
||||
}
|
||||
case "openNote": {
|
||||
const linkParams = getNoteLinkParams(ev.data.link);
|
||||
if (!linkParams.noteItem) {
|
||||
return;
|
||||
}
|
||||
this._addon.hooks.onOpenNote(linkParams.noteItem.id, "preview", {
|
||||
lineIndex: linkParams.lineIndex || undefined,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case "moveNode": {
|
||||
if (!this.item) return;
|
||||
const tree = getNoteTree(this.item);
|
||||
const fromNode = getNoteTreeNodeById(this.item, ev.data.fromID, tree);
|
||||
const toNode = getNoteTreeNodeById(this.item, ev.data.toID, tree);
|
||||
moveHeading(
|
||||
getEditorInstance(this.item.id),
|
||||
fromNode!,
|
||||
toNode!,
|
||||
ev.data.moveType,
|
||||
);
|
||||
return;
|
||||
}
|
||||
case "editNode": {
|
||||
if (!this.editor) {
|
||||
return;
|
||||
}
|
||||
updateHeadingTextAtLine(
|
||||
this.editor,
|
||||
ev.data.lineIndex,
|
||||
ev.data.text.replace(/[\r\n]/g, ""),
|
||||
);
|
||||
return;
|
||||
}
|
||||
case "saveSVGReturn": {
|
||||
const filename = await new FilePickerHelper(
|
||||
`${Zotero.getString("fileInterface.export")} SVG Image`,
|
||||
"save",
|
||||
[["SVG File(*.svg)", "*.svg"]],
|
||||
`${this.item?.getNoteTitle()}.svg`,
|
||||
).open();
|
||||
if (filename) {
|
||||
await Zotero.File.putContentsAsync(
|
||||
formatPath(filename),
|
||||
ev.data.image,
|
||||
);
|
||||
showHintWithLink(
|
||||
`Image Saved to ${filename}`,
|
||||
"Show in Folder",
|
||||
(ev) => {
|
||||
Zotero.File.reveal(filename);
|
||||
},
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "saveImageReturn": {
|
||||
const filename = await new FilePickerHelper(
|
||||
`${Zotero.getString("fileInterface.export")} PNG Image`,
|
||||
"save",
|
||||
[["PNG File(*.png)", "*.png"]],
|
||||
`${this.item?.getNoteTitle()}.png`,
|
||||
).open();
|
||||
if (filename) {
|
||||
const parts = ev.data.image.split(",");
|
||||
const bstr = atob(parts[1]);
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
await IOUtils.write(formatPath(filename), u8arr);
|
||||
showHintWithLink(
|
||||
`Image Saved to ${filename}`,
|
||||
"Show in Folder",
|
||||
(ev) => {
|
||||
Zotero.File.reveal(filename);
|
||||
},
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
import { config } from "../../package.json";
|
||||
import { waitUtilAsync } from "../utils/wait";
|
||||
import { PluginCEBase } from "./base";
|
||||
import { ContextPane } from "./context";
|
||||
import { OutlinePane } from "./outlinePane";
|
||||
|
||||
export class Workspace extends PluginCEBase {
|
||||
_item?: Zotero.Item;
|
||||
|
||||
_editorElement!: EditorElement;
|
||||
_outline!: OutlinePane;
|
||||
_context!: ContextPane;
|
||||
|
||||
get content() {
|
||||
return this._parseContentID(
|
||||
MozXULElement.parseXULToFragment(`
|
||||
<linkset>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://${config.addonRef}/content/styles/workspace.css"
|
||||
></html:link>
|
||||
</linkset>
|
||||
<hbox id="top-container" class="container">
|
||||
<bn-outline id="left-container" class="container" zotero-persist="width">
|
||||
</bn-outline>
|
||||
<splitter
|
||||
id="left-splitter"
|
||||
collapse="before"
|
||||
zotero-persist="state"
|
||||
></splitter>
|
||||
<vbox id="center-container" class="container" zotero-persist="width">
|
||||
<note-editor id="editor-main" class="container"></note-editor>
|
||||
</vbox>
|
||||
<splitter
|
||||
id="right-splitter"
|
||||
collapse="after"
|
||||
zotero-persist="state"
|
||||
></splitter>
|
||||
<bn-context id="right-container" class="container" zotero-persist="width"></bn-context>
|
||||
</hbox>
|
||||
`),
|
||||
);
|
||||
}
|
||||
|
||||
get containerType() {
|
||||
return this.getAttribute("container-type") || "";
|
||||
}
|
||||
|
||||
set containerType(val: string) {
|
||||
this.setAttribute("container-type", val);
|
||||
}
|
||||
|
||||
get item() {
|
||||
return this._item;
|
||||
}
|
||||
|
||||
set item(val) {
|
||||
this._item = val;
|
||||
this._outline.item = val;
|
||||
this._context.item = val;
|
||||
}
|
||||
|
||||
get editor() {
|
||||
return this._editorElement._editorInstance;
|
||||
}
|
||||
|
||||
init(): void {
|
||||
// MozXULElement.insertFTLIfNeeded(`${config.addonRef}-workspace.ftl`);
|
||||
|
||||
this._outline = this._queryID("left-container") as unknown as OutlinePane;
|
||||
this._editorElement = this._queryID("editor-main") as EditorElement;
|
||||
this._outline._editorElement = this._editorElement;
|
||||
|
||||
this._context = this._queryID("right-container") as unknown as ContextPane;
|
||||
|
||||
this._loadPersist();
|
||||
}
|
||||
|
||||
destroy(): void {}
|
||||
|
||||
async render() {
|
||||
await this._outline.render();
|
||||
await this.updateEditor();
|
||||
await this._context.render();
|
||||
}
|
||||
|
||||
async updateEditor() {
|
||||
const editorElem = this._queryID("editor-main") as EditorElement;
|
||||
await waitUtilAsync(() => Boolean(editorElem._initialized));
|
||||
if (!editorElem._initialized) {
|
||||
throw new Error("initNoteEditor: waiting initialization failed");
|
||||
}
|
||||
editorElem.mode = "edit";
|
||||
editorElem.viewMode = "library";
|
||||
editorElem.parent = this.item?.parentItem;
|
||||
editorElem.item = this.item;
|
||||
await waitUtilAsync(() => Boolean(editorElem._editorInstance));
|
||||
await editorElem._editorInstance._initPromise;
|
||||
// Hide BN toolbar
|
||||
editorElem._editorInstance._iframeWindow.document.body.setAttribute(
|
||||
"no-bn-toolbar",
|
||||
"true",
|
||||
);
|
||||
// TODO: implement jump to
|
||||
// if (typeof options.lineIndex === "number") {
|
||||
// addon.api.editor.scroll(editorElem._editorInstance, options.lineIndex);
|
||||
// }
|
||||
// if (typeof options.sectionName === "string") {
|
||||
// addon.api.editor.scrollToSection(
|
||||
// editorElem._editorInstance,
|
||||
// options.sectionName,
|
||||
// );
|
||||
// }
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { ContextPane } from "../elements/context";
|
||||
import { NoteDetails } from "../elements/detailsPane";
|
||||
import { OutlinePane } from "../elements/outlinePane";
|
||||
import { Workspace } from "../elements/workspace";
|
||||
|
||||
const elements = {
|
||||
"bn-context": ContextPane,
|
||||
"bn-outline": OutlinePane,
|
||||
"bn-details": NoteDetails,
|
||||
"bn-workspace": Workspace,
|
||||
};
|
||||
|
||||
for (const [key, constructor] of Object.entries(elements)) {
|
||||
if (!customElements.get(key)) {
|
||||
customElements.define(key, constructor);
|
||||
}
|
||||
}
|
||||
148
src/hooks.ts
148
src/hooks.ts
|
|
@ -11,15 +11,9 @@ import { registerMenus } from "./modules/menu";
|
|||
import {
|
||||
registerWorkspaceTab,
|
||||
openWorkspaceTab,
|
||||
onTabSelect,
|
||||
} from "./modules/workspace/tab";
|
||||
import {
|
||||
initWorkspace,
|
||||
initWorkspaceEditor,
|
||||
toggleNotesPane,
|
||||
toggleOutlinePane,
|
||||
togglePreviewPane,
|
||||
updateOutline,
|
||||
} from "./modules/workspace/content";
|
||||
import { initWorkspace } from "./modules/workspace/content";
|
||||
import { registerNotify } from "./modules/notify";
|
||||
import { openWorkspaceWindow } from "./modules/workspace/window";
|
||||
import { registerReaderAnnotationButton } from "./modules/reader";
|
||||
|
|
@ -34,16 +28,12 @@ import { showSyncDiff } from "./modules/sync/diffWindow";
|
|||
import { showSyncInfo } from "./modules/sync/infoWindow";
|
||||
import { showSyncManager } from "./modules/sync/managerWindow";
|
||||
import { showTemplateEditor } from "./modules/template/editorWindow";
|
||||
import {
|
||||
createNoteFromTemplate,
|
||||
createWorkspaceNote,
|
||||
createNoteFromMD,
|
||||
} from "./modules/createNote";
|
||||
import { annotationTagAction } from "./modules/annotationTagAction";
|
||||
import { createNoteFromTemplate, createNoteFromMD } from "./modules/createNote";
|
||||
import { createZToolkit } from "./utils/ztoolkit";
|
||||
import { waitUtilAsync } from "./utils/wait";
|
||||
import { initSyncList } from "./modules/sync/api";
|
||||
import { getPref } from "./utils/prefs";
|
||||
import { patchViewItems } from "./modules/viewItems";
|
||||
|
||||
async function onStartup() {
|
||||
await Promise.all([
|
||||
|
|
@ -74,6 +64,11 @@ async function onStartup() {
|
|||
|
||||
async function onMainWindowLoad(win: Window): Promise<void> {
|
||||
await waitUtilAsync(() => document.readyState === "complete");
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
`chrome://${config.addonRef}/content/scripts/workspace.js`,
|
||||
win,
|
||||
);
|
||||
// Create ztoolkit for every window
|
||||
addon.data.ztoolkit = createZToolkit();
|
||||
|
||||
|
|
@ -84,6 +79,8 @@ async function onMainWindowLoad(win: Window): Promise<void> {
|
|||
registerWorkspaceTab(win);
|
||||
|
||||
initTemplates();
|
||||
|
||||
patchViewItems(win);
|
||||
}
|
||||
|
||||
async function onMainWindowUnload(win: Window): Promise<void> {
|
||||
|
|
@ -102,25 +99,16 @@ function onShutdown(): void {
|
|||
* Any operations should be placed in a function to keep this funcion clear.
|
||||
*/
|
||||
function onNotify(
|
||||
event: string,
|
||||
type: string,
|
||||
ids: number[] | string[],
|
||||
extraData: { [key: string]: any },
|
||||
event: Parameters<_ZoteroTypes.Notifier.Notify>["0"],
|
||||
type: Parameters<_ZoteroTypes.Notifier.Notify>["1"],
|
||||
ids: Parameters<_ZoteroTypes.Notifier.Notify>["2"],
|
||||
extraData: Parameters<_ZoteroTypes.Notifier.Notify>["3"],
|
||||
) {
|
||||
if (extraData.skipBN) {
|
||||
return;
|
||||
}
|
||||
// Workspace main note update
|
||||
if (event === "modify" && type === "item") {
|
||||
if ((ids as number[]).includes(addon.data.workspace.mainId)) {
|
||||
addon.data.workspace.tab.active &&
|
||||
updateOutline(addon.data.workspace.tab.container!);
|
||||
addon.data.workspace.window.active &&
|
||||
updateOutline(addon.data.workspace.window.container!);
|
||||
if (getPref("workspace.autoUpdateRelatedNotes")) {
|
||||
addon.api.note.updateRelatedNotes(addon.data.workspace.mainId);
|
||||
}
|
||||
}
|
||||
if (event === "select" && type === "tab") {
|
||||
onTabSelect(extraData[ids[0]].type);
|
||||
}
|
||||
if (event === "modify" && type === "item") {
|
||||
const modifiedNotes = Zotero.Items.get(ids).filter((item) => item.isNote());
|
||||
|
|
@ -131,10 +119,6 @@ function onNotify(
|
|||
reason: "item-modify",
|
||||
});
|
||||
}
|
||||
}
|
||||
// Insert annotation when assigning tag starts with @
|
||||
if (event === "add" && type === "item-tag") {
|
||||
annotationTagAction(ids as number[], extraData);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
|
@ -170,23 +154,14 @@ function onOpenNote(
|
|||
return;
|
||||
}
|
||||
if (mode === "auto") {
|
||||
if (noteId === addon.data.workspace.mainId) {
|
||||
mode = "workspace";
|
||||
} else if (
|
||||
addon.data.workspace.tab.active ||
|
||||
addon.data.workspace.window.active
|
||||
) {
|
||||
mode = "preview";
|
||||
} else {
|
||||
mode = "standalone";
|
||||
}
|
||||
mode = "workspace";
|
||||
}
|
||||
switch (mode) {
|
||||
case "preview":
|
||||
addon.hooks.onSetWorkspaceNote(noteId, "preview", options);
|
||||
// addon.hooks.onSetWorkspaceNote(noteId, "preview", options);
|
||||
break;
|
||||
case "workspace":
|
||||
addon.hooks.onSetWorkspaceNote(noteId, "main", options);
|
||||
// addon.hooks.onSetWorkspaceNote(noteId, "main", options);
|
||||
break;
|
||||
case "standalone":
|
||||
ZoteroPane.openNoteWindow(noteId);
|
||||
|
|
@ -196,60 +171,13 @@ function onOpenNote(
|
|||
}
|
||||
}
|
||||
|
||||
function onSetWorkspaceNote(
|
||||
noteId: number,
|
||||
type: "main" | "preview" = "main",
|
||||
options: {
|
||||
lineIndex?: number;
|
||||
sectionName?: string;
|
||||
} = {},
|
||||
) {
|
||||
if (type === "main") {
|
||||
addon.data.workspace.mainId = noteId;
|
||||
addon.data.workspace.tab.active &&
|
||||
updateOutline(addon.data.workspace.tab.container!);
|
||||
addon.data.workspace.window.active &&
|
||||
updateOutline(addon.data.workspace.window.container!);
|
||||
}
|
||||
if (addon.data.workspace.window.active) {
|
||||
initWorkspaceEditor(
|
||||
addon.data.workspace.window.container!,
|
||||
type,
|
||||
noteId,
|
||||
options,
|
||||
);
|
||||
type === "preview" &&
|
||||
addon.hooks.onToggleWorkspacePane(
|
||||
"preview",
|
||||
true,
|
||||
addon.data.workspace.window.container,
|
||||
);
|
||||
addon.data.workspace.window.window?.focus();
|
||||
}
|
||||
if (addon.data.workspace.tab.active) {
|
||||
initWorkspaceEditor(
|
||||
addon.data.workspace.tab.container!,
|
||||
type,
|
||||
noteId,
|
||||
options,
|
||||
);
|
||||
type === "preview" &&
|
||||
addon.hooks.onToggleWorkspacePane(
|
||||
"preview",
|
||||
true,
|
||||
addon.data.workspace.tab.container,
|
||||
);
|
||||
Zotero_Tabs.select(addon.data.workspace.tab.id!);
|
||||
}
|
||||
}
|
||||
|
||||
function onOpenWorkspace(type: "tab" | "window" = "tab") {
|
||||
function onOpenWorkspace(item: Zotero.Item, type: "tab" | "window" = "tab") {
|
||||
if (type === "window") {
|
||||
openWorkspaceWindow();
|
||||
openWorkspaceWindow(item);
|
||||
return;
|
||||
}
|
||||
if (type === "tab") {
|
||||
openWorkspaceTab();
|
||||
openWorkspaceTab(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -261,19 +189,19 @@ function onToggleWorkspacePane(
|
|||
visibility?: boolean,
|
||||
container?: XUL.Box,
|
||||
) {
|
||||
switch (type) {
|
||||
case "outline":
|
||||
toggleOutlinePane(visibility, container);
|
||||
break;
|
||||
case "preview":
|
||||
togglePreviewPane(visibility, container);
|
||||
break;
|
||||
case "notes":
|
||||
toggleNotesPane(visibility);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// switch (type) {
|
||||
// case "outline":
|
||||
// toggleOutlinePane(visibility, container);
|
||||
// break;
|
||||
// case "preview":
|
||||
// togglePreviewPane(visibility, container);
|
||||
// break;
|
||||
// case "notes":
|
||||
// toggleNotesPane(visibility);
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
const onSyncing = callSyncing;
|
||||
|
|
@ -296,8 +224,6 @@ const onShowSyncDiff = showSyncDiff;
|
|||
|
||||
const onShowTemplateEditor = showTemplateEditor;
|
||||
|
||||
const onCreateWorkspaceNote = createWorkspaceNote;
|
||||
|
||||
const onCreateNoteFromTemplate = createNoteFromTemplate;
|
||||
|
||||
const onCreateNoteFromMD = createNoteFromMD;
|
||||
|
|
@ -315,7 +241,6 @@ export default {
|
|||
onPrefsEvent,
|
||||
onOpenNote,
|
||||
onInitWorkspace,
|
||||
onSetWorkspaceNote,
|
||||
onOpenWorkspace,
|
||||
onToggleWorkspacePane,
|
||||
onSyncing,
|
||||
|
|
@ -328,7 +253,6 @@ export default {
|
|||
onShowSyncInfo,
|
||||
onShowSyncManager,
|
||||
onShowTemplateEditor,
|
||||
onCreateWorkspaceNote,
|
||||
onCreateNoteFromTemplate,
|
||||
onCreateNoteFromMD,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
import { addLineToNote, getNoteTreeFlattened } from "../utils/note";
|
||||
|
||||
export { annotationTagAction };
|
||||
|
||||
async function annotationTagAction(
|
||||
ids: Array<number | string>,
|
||||
extraData: Record<string, any>,
|
||||
) {
|
||||
const workspaceNote = Zotero.Items.get(addon.data.workspace.mainId);
|
||||
if (!workspaceNote || !workspaceNote.isNote()) {
|
||||
return;
|
||||
}
|
||||
const nodes = getNoteTreeFlattened(workspaceNote);
|
||||
const headings: string[] = nodes.map((node) => node.model.name);
|
||||
|
||||
for (const tagId of ids.filter((t) =>
|
||||
(extraData[t].tag as string).startsWith("@"),
|
||||
)) {
|
||||
const tagName = (extraData[tagId].tag as string).slice(1).trim();
|
||||
if (headings.includes(tagName) || tagName === "@") {
|
||||
let lineIndex: number;
|
||||
if (tagName === "@") {
|
||||
lineIndex = -1;
|
||||
} else {
|
||||
const targetNode = nodes.find((node) => node.model.name === tagName);
|
||||
lineIndex = targetNode?.model.endIndex;
|
||||
}
|
||||
|
||||
const annotationItem = Zotero.Items.get((tagId as string).split("-")[0]);
|
||||
if (!annotationItem.isAnnotation()) {
|
||||
continue;
|
||||
}
|
||||
await addLineToNote(
|
||||
workspaceNote,
|
||||
await addon.api.convert.annotations2html([annotationItem], {
|
||||
noteItem: workspaceNote,
|
||||
}),
|
||||
lineIndex,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +1,7 @@
|
|||
import { getString } from "../utils/locale";
|
||||
import { config } from "../../package.json";
|
||||
import { formatPath } from "../utils/str";
|
||||
|
||||
export { createWorkspaceNote, createNoteFromTemplate, createNoteFromMD };
|
||||
|
||||
async function createWorkspaceNote() {
|
||||
const currentCollection = ZoteroPane.getSelectedCollection();
|
||||
if (!currentCollection) {
|
||||
window.alert(getString("alert.notValidCollectionError"));
|
||||
return;
|
||||
}
|
||||
const confirmOperation = window.confirm(
|
||||
`${getString(
|
||||
"menuAddNote.newMainNote.confirmHead",
|
||||
// @ts-ignore
|
||||
)} '${currentCollection.getName()}' ${getString(
|
||||
"menuAddNote.newMainNote.confirmTail",
|
||||
)}`,
|
||||
);
|
||||
if (!confirmOperation) {
|
||||
return;
|
||||
}
|
||||
const header = window.prompt(
|
||||
getString("menuAddNote.newMainNote.enterNoteTitle"),
|
||||
`New Note ${new Date().toLocaleString()}`,
|
||||
);
|
||||
const noteID = await ZoteroPane.newNote();
|
||||
const noteItem = Zotero.Items.get(noteID);
|
||||
noteItem.setNote(
|
||||
`<div data-schema-version="${config.dataSchemaVersion}"><h1>${header}</h1>\n</div>`,
|
||||
);
|
||||
await noteItem.saveTx();
|
||||
addon.hooks.onSetWorkspaceNote(noteID, "main");
|
||||
if (
|
||||
!addon.data.workspace.tab.active &&
|
||||
!addon.data.workspace.window.active &&
|
||||
window.confirm(getString("menuAddNote.newMainNote.openWorkspaceTab"))
|
||||
) {
|
||||
addon.hooks.onOpenWorkspace("tab");
|
||||
}
|
||||
}
|
||||
export { createNoteFromTemplate, createNoteFromMD };
|
||||
|
||||
function getLibraryParentId() {
|
||||
return ZoteroPane.getSelectedItems().filter((item) => item.isRegularItem())[0]
|
||||
|
|
|
|||
|
|
@ -16,47 +16,13 @@ export async function injectEditorScripts(win: Window) {
|
|||
);
|
||||
}
|
||||
|
||||
export function injectEditorCSS(win: Window) {
|
||||
export async function injectEditorCSS(win: Window) {
|
||||
ztoolkit.UI.appendElement(
|
||||
{
|
||||
tag: "style",
|
||||
id: "betternotes-style",
|
||||
properties: {
|
||||
innerHTML: `
|
||||
.primary-editor > h1::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3E%E6%9C%AA%E6%A0%87%E9%A2%98-1%3C%2Ftitle%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M12.29%2C16.8H11.14V12.33H6.07V16.8H4.92V7H6.07v4.3h5.07V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M18.05%2C16.8H16.93V8.41a4%2C4%2C0%2C0%2C1-.9.53%2C6.52%2C6.52%2C0%2C0%2C1-1.14.44l-.32-1a8.2%2C8.2%2C0%2C0%2C0%2C1.67-.67%2C6.31%2C6.31%2C0%2C0%2C0%2C1.39-1h.42Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h2::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.a%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22a%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22a%22%20d%3D%22M14.14%2C16.8v-.48a4.1%2C4.1%2C0%2C0%2C1%2C.14-1.11%2C2.86%2C2.86%2C0%2C0%2C1%2C.45-.91%2C5.49%2C5.49%2C0%2C0%2C1%2C.83-.86c.33-.29.75-.61%2C1.24-1a7.43%2C7.43%2C0%2C0%2C0%2C.9-.73%2C3.9%2C3.9%2C0%2C0%2C0%2C.57-.7%2C2.22%2C2.22%2C0%2C0%2C0%2C.3-.66%2C2.87%2C2.87%2C0%2C0%2C0%2C.11-.77%2C1.89%2C1.89%2C0%2C0%2C0-.47-1.32%2C1.66%2C1.66%2C0%2C0%2C0-1.28-.5A3.17%2C3.17%2C0%2C0%2C0%2C15.7%2C8a3.49%2C3.49%2C0%2C0%2C0-1.08.76l-.68-.65a4.26%2C4.26%2C0%2C0%2C1%2C1.39-1A4%2C4%2C0%2C0%2C1%2C17%2C6.84a2.62%2C2.62%2C0%2C0%2C1%2C2.83%2C2.67%2C3.58%2C3.58%2C0%2C0%2C1-.15%2C1%2C3.09%2C3.09%2C0%2C0%2C1-.41.9%2C5.53%2C5.53%2C0%2C0%2C1-.67.81%2C9%2C9%2C0%2C0%2C1-.95.79c-.46.32-.84.59-1.13.82a4.68%2C4.68%2C0%2C0%2C0-.71.64%2C2%2C2%2C0%2C0%2C0-.38.6%2C2.08%2C2.08%2C0%2C0%2C0-.11.69h4.88v1Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22a%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h3::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M14%2C16.14l.51-.8a4.75%2C4.75%2C0%2C0%2C0%2C1.1.52%2C4.27%2C4.27%2C0%2C0%2C0%2C1.12.16%2C2.29%2C2.29%2C0%2C0%2C0%2C1.64-.52A1.77%2C1.77%2C0%2C0%2C0%2C19%2C14.17a1.7%2C1.7%2C0%2C0%2C0-.68-1.48%2C3.6%2C3.6%2C0%2C0%2C0-2.06-.48H15.4v-1h.77A3%2C3%2C0%2C0%2C0%2C18%2C10.81a1.65%2C1.65%2C0%2C0%2C0%2C.6-1.41%2C1.47%2C1.47%2C0%2C0%2C0-.47-1.19A1.67%2C1.67%2C0%2C0%2C0%2C17%2C7.79a3.33%2C3.33%2C0%2C0%2C0-2.08.73l-.59-.75a4.4%2C4.4%2C0%2C0%2C1%2C1.28-.71A4.35%2C4.35%2C0%2C0%2C1%2C17%2C6.84a2.84%2C2.84%2C0%2C0%2C1%2C2%2C.65%2C2.21%2C2.21%2C0%2C0%2C1%2C.74%2C1.78%2C2.35%2C2.35%2C0%2C0%2C1-.49%2C1.5%2C2.7%2C2.7%2C0%2C0%2C1-1.46.89v0a2.74%2C2.74%2C0%2C0%2C1%2C1.65.74%2C2.15%2C2.15%2C0%2C0%2C1%2C.66%2C1.65%2C2.64%2C2.64%2C0%2C0%2C1-.9%2C2.12%2C3.44%2C3.44%2C0%2C0%2C1-2.34.78%2C5.3%2C5.3%2C0%2C0%2C1-1.48-.2A5%2C5%2C0%2C0%2C1%2C14%2C16.14Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h4::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M19.43%2C6.92v6.59h1.05v1.05H19.43V16.9H18.31V14.56H13.66v-1c.43-.49.87-1%2C1.31-1.57s.87-1.13%2C1.27-1.7S17%2C9.14%2C17.36%2C8.57a16.51%2C16.51%2C0%2C0%2C0%2C.86-1.65Zm-4.49%2C6.59h3.37V8.63c-.34.61-.67%2C1.15-1%2C1.63s-.6.91-.87%2C1.3-.56.74-.81%2C1Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h5::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M14%2C16l.58-.76a3.67%2C3.67%2C0%2C0%2C0%2C1%2C.58A3.44%2C3.44%2C0%2C0%2C0%2C16.8%2C16a2.17%2C2.17%2C0%2C0%2C0%2C1.58-.6A2%2C2%2C0%2C0%2C0%2C19%2C13.88a1.85%2C1.85%2C0%2C0%2C0-.64-1.5%2C2.83%2C2.83%2C0%2C0%2C0-1.86-.54c-.27%2C0-.55%2C0-.86%2C0s-.58%2C0-.81.06L15.17%2C7H19.7V8H16.14l-.2%2C2.88.47%2C0h.43a3.5%2C3.5%2C0%2C0%2C1%2C2.43.79%2C2.74%2C2.74%2C0%2C0%2C1%2C.88%2C2.16%2C3%2C3%2C0%2C0%2C1-.94%2C2.3%2C3.41%2C3.41%2C0%2C0%2C1-2.4.87%2C4.45%2C4.45%2C0%2C0%2C1-1.5-.24A4.81%2C4.81%2C0%2C0%2C1%2C14%2C16Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > h6::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M20.18%2C13.7a3.24%2C3.24%2C0%2C0%2C1-.88%2C2.38%2C2.94%2C2.94%2C0%2C0%2C1-2.2.9%2C2.69%2C2.69%2C0%2C0%2C1-2.31-1.17A5.59%2C5.59%2C0%2C0%2C1%2C14%2C12.49a12.18%2C12.18%2C0%2C0%2C1%2C.2-2.14%2C5.16%2C5.16%2C0%2C0%2C1%2C.84-2A3.65%2C3.65%2C0%2C0%2C1%2C16.27%2C7.2%2C3.71%2C3.71%2C0%2C0%2C1%2C18%2C6.84%2C3.14%2C3.14%2C0%2C0%2C1%2C19%2C7a3.59%2C3.59%2C0%2C0%2C1%2C1%2C.5l-.56.77a2.3%2C2.3%2C0%2C0%2C0-1.49-.48A2.3%2C2.3%2C0%2C0%2C0%2C16.79%2C8a3%2C3%2C0%2C0%2C0-.92.85%2C3.79%2C3.79%2C0%2C0%2C0-.56%2C1.25%2C6.56%2C6.56%2C0%2C0%2C0-.19%2C1.65h0a2.61%2C2.61%2C0%2C0%2C1%2C1-.84%2C2.91%2C2.91%2C0%2C0%2C1%2C1.23-.28%2C2.63%2C2.63%2C0%2C0%2C1%2C2%2C.85A3.09%2C3.09%2C0%2C0%2C1%2C20.18%2C13.7ZM19%2C13.78a2.28%2C2.28%2C0%2C0%2C0-.5-1.62%2C1.67%2C1.67%2C0%2C0%2C0-1.29-.54%2C2%2C2%2C0%2C0%2C0-1.5.58%2C2%2C2%2C0%2C0%2C0-.56%2C1.4%2C2.65%2C2.65%2C0%2C0%2C0%2C.55%2C1.74%2C1.85%2C1.85%2C0%2C0%2C0%2C2.78.1A2.38%2C2.38%2C0%2C0%2C0%2C19%2C13.78Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > p, .primary-editor h1, .primary-editor h2, .primary-editor h3, .primary-editor h4, .primary-editor h5, .primary-editor h6, .primary-editor pre, .primary-editor blockquote, .primary-editor table, .primary-editor ul, .primary-editor ol, .primary-editor hr{
|
||||
max-width: unset
|
||||
}
|
||||
`,
|
||||
innerHTML: await getFileContent(rootURI + "chrome/content/styles/editor.css"),
|
||||
},
|
||||
ignoreIfExists: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,17 +4,12 @@ import { getLineAtCursor, getSectionAtCursor } from "../../utils/editor";
|
|||
import { showHint } from "../../utils/hint";
|
||||
import { getNoteLink, getNoteLinkParams } from "../../utils/link";
|
||||
import { getString } from "../../utils/locale";
|
||||
import {
|
||||
addLineToNote,
|
||||
getNoteTreeFlattened,
|
||||
getNoteType,
|
||||
} from "../../utils/note";
|
||||
import { addLineToNote, getNoteTreeFlattened } from "../../utils/note";
|
||||
import { getPref } from "../../utils/prefs";
|
||||
import { slice } from "../../utils/str";
|
||||
|
||||
export async function initEditorToolbar(editor: Zotero.EditorInstance) {
|
||||
const noteItem = editor._item;
|
||||
const noteType = getNoteType(noteItem.id);
|
||||
const toolbar = await registerEditorToolbar(editor, makeId("toolbar"));
|
||||
|
||||
// Settings
|
||||
|
|
@ -56,22 +51,7 @@ export async function initEditorToolbar(editor: Zotero.EditorInstance) {
|
|||
id: makeId("settings-openWorkspace"),
|
||||
text: getString("editor.toolbar.settings.openWorkspace"),
|
||||
callback: (e) => {
|
||||
addon.hooks.onOpenWorkspace("tab");
|
||||
},
|
||||
},
|
||||
{
|
||||
id: makeId("settings-setWorkspace"),
|
||||
text: getString("editor.toolbar.settings.setWorkspace"),
|
||||
callback: (e) => {
|
||||
addon.hooks.onSetWorkspaceNote(e.editor._item.id, "main");
|
||||
},
|
||||
},
|
||||
{
|
||||
id: makeId("settings-previewInWorkspace"),
|
||||
text: getString("editor.toolbar.settings.previewInWorkspace"),
|
||||
callback: (e) => {
|
||||
addon.hooks.onOpenWorkspace("tab");
|
||||
addon.hooks.onSetWorkspaceNote(e.editor._item.id, "preview");
|
||||
addon.hooks.onOpenWorkspace(noteItem, "tab");
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -221,103 +201,95 @@ export async function initEditorToolbar(editor: Zotero.EditorInstance) {
|
|||
});
|
||||
|
||||
// Center button
|
||||
if (noteType === "main") {
|
||||
registerEditorToolbarElement(
|
||||
|
||||
const onTriggerMenu = (ev: MouseEvent) => {
|
||||
editor._iframeWindow.focus();
|
||||
const linkMenu: PopupData[] = getLinkMenuData(editor);
|
||||
editor._iframeWindow.document
|
||||
.querySelector(`#${makeId("link")}`)!
|
||||
.querySelector(".toolbar-button")!.innerHTML = ICONS.linkAfter;
|
||||
|
||||
const popup = registerEditorToolbarPopup(
|
||||
editor,
|
||||
toolbar,
|
||||
linkButton,
|
||||
`${config.addonRef}-link-popup`,
|
||||
"middle",
|
||||
ztoolkit.UI.createElement(editor._iframeWindow.document, "div", {
|
||||
properties: { innerHTML: getString("editor.toolbar.main") },
|
||||
}),
|
||||
linkMenu,
|
||||
);
|
||||
} else {
|
||||
const onTriggerMenu = (ev: MouseEvent) => {
|
||||
editor._iframeWindow.focus();
|
||||
const linkMenu: PopupData[] = getLinkMenuData(editor);
|
||||
editor._iframeWindow.document
|
||||
.querySelector(`#${makeId("link")}`)!
|
||||
.querySelector(".toolbar-button")!.innerHTML = ICONS.linkAfter;
|
||||
};
|
||||
|
||||
const popup = registerEditorToolbarPopup(
|
||||
editor,
|
||||
linkButton,
|
||||
`${config.addonRef}-link-popup`,
|
||||
"middle",
|
||||
linkMenu,
|
||||
);
|
||||
};
|
||||
const onExitMenu = (ev: MouseEvent) => {
|
||||
editor._iframeWindow.document
|
||||
.querySelector(`#${makeId("link-popup")}`)
|
||||
?.remove();
|
||||
editor._iframeWindow.document
|
||||
.querySelector(`#${makeId("link")}`)!
|
||||
.querySelector(".toolbar-button")!.innerHTML = ICONS.addon;
|
||||
};
|
||||
|
||||
const onExitMenu = (ev: MouseEvent) => {
|
||||
editor._iframeWindow.document
|
||||
.querySelector(`#${makeId("link-popup")}`)
|
||||
?.remove();
|
||||
editor._iframeWindow.document
|
||||
.querySelector(`#${makeId("link")}`)!
|
||||
.querySelector(".toolbar-button")!.innerHTML = ICONS.addon;
|
||||
};
|
||||
|
||||
const onClickMenu = async (ev: MouseEvent) => {
|
||||
const mainNote = Zotero.Items.get(addon.data.workspace.mainId) || null;
|
||||
if (!mainNote?.isNote()) {
|
||||
return;
|
||||
}
|
||||
const lineIndex = parseInt(
|
||||
(ev.target as HTMLDivElement).id.split("-").pop() || "-1",
|
||||
);
|
||||
const forwardLink = getNoteLink(noteItem);
|
||||
const backLink = getNoteLink(mainNote, { ignore: true, lineIndex });
|
||||
addLineToNote(
|
||||
mainNote,
|
||||
await addon.api.template.runTemplate(
|
||||
"[QuickInsertV2]",
|
||||
"link, linkText, subNoteItem, noteItem",
|
||||
[
|
||||
forwardLink,
|
||||
noteItem.getNoteTitle().trim() || forwardLink,
|
||||
noteItem,
|
||||
mainNote,
|
||||
],
|
||||
),
|
||||
lineIndex,
|
||||
);
|
||||
addLineToNote(
|
||||
noteItem,
|
||||
await addon.api.template.runTemplate(
|
||||
"[QuickBackLinkV2]",
|
||||
"link, linkText, subNoteItem, noteItem",
|
||||
[
|
||||
backLink,
|
||||
mainNote.getNoteTitle().trim() || "Workspace Note",
|
||||
noteItem,
|
||||
mainNote,
|
||||
"",
|
||||
],
|
||||
),
|
||||
);
|
||||
onExitMenu(ev);
|
||||
ev.stopPropagation();
|
||||
};
|
||||
|
||||
const linkButton = await registerEditorToolbarDropdown(
|
||||
editor,
|
||||
toolbar,
|
||||
makeId("link"),
|
||||
ICONS.addon,
|
||||
getString("editor.toolbar.link.title"),
|
||||
"middle",
|
||||
onClickMenu,
|
||||
const onClickMenu = async (ev: MouseEvent) => {
|
||||
// TODO: fix link
|
||||
return;
|
||||
const mainNote = Zotero.Items.get(addon.data.workspace.mainId) || null;
|
||||
if (!mainNote?.isNote()) {
|
||||
return;
|
||||
}
|
||||
const lineIndex = parseInt(
|
||||
(ev.target as HTMLDivElement).id.split("-").pop() || "-1",
|
||||
);
|
||||
const forwardLink = getNoteLink(noteItem);
|
||||
const backLink = getNoteLink(mainNote, { ignore: true, lineIndex });
|
||||
addLineToNote(
|
||||
mainNote,
|
||||
await addon.api.template.runTemplate(
|
||||
"[QuickInsertV2]",
|
||||
"link, linkText, subNoteItem, noteItem",
|
||||
[
|
||||
forwardLink,
|
||||
noteItem.getNoteTitle().trim() || forwardLink,
|
||||
noteItem,
|
||||
mainNote,
|
||||
],
|
||||
),
|
||||
lineIndex,
|
||||
);
|
||||
addLineToNote(
|
||||
noteItem,
|
||||
await addon.api.template.runTemplate(
|
||||
"[QuickBackLinkV2]",
|
||||
"link, linkText, subNoteItem, noteItem",
|
||||
[
|
||||
backLink,
|
||||
mainNote.getNoteTitle().trim() || "Workspace Note",
|
||||
noteItem,
|
||||
mainNote,
|
||||
"",
|
||||
],
|
||||
),
|
||||
);
|
||||
onExitMenu(ev);
|
||||
ev.stopPropagation();
|
||||
};
|
||||
|
||||
linkButton.addEventListener("mouseenter", onTriggerMenu);
|
||||
linkButton.addEventListener("mouseleave", onExitMenu);
|
||||
linkButton.addEventListener("mouseleave", onExitMenu);
|
||||
linkButton.addEventListener("click", (ev) => {
|
||||
if ((ev.target as HTMLElement).classList.contains("option")) {
|
||||
onClickMenu(ev);
|
||||
}
|
||||
});
|
||||
editor._iframeWindow.document.addEventListener("click", onExitMenu);
|
||||
}
|
||||
const linkButton = await registerEditorToolbarDropdown(
|
||||
editor,
|
||||
toolbar,
|
||||
makeId("link"),
|
||||
ICONS.addon,
|
||||
getString("editor.toolbar.link.title"),
|
||||
"middle",
|
||||
onClickMenu,
|
||||
);
|
||||
|
||||
linkButton.addEventListener("mouseenter", onTriggerMenu);
|
||||
linkButton.addEventListener("mouseleave", onExitMenu);
|
||||
linkButton.addEventListener("mouseleave", onExitMenu);
|
||||
linkButton.addEventListener("click", (ev) => {
|
||||
if ((ev.target as HTMLElement).classList.contains("option")) {
|
||||
onClickMenu(ev);
|
||||
}
|
||||
});
|
||||
editor._iframeWindow.document.addEventListener("click", onExitMenu);
|
||||
|
||||
// Export
|
||||
// const exportButton = await registerEditorToolbarDropdown(
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ async function toFreeMind(noteItem: Zotero.Item) {
|
|||
}
|
||||
|
||||
async function embedLinkedNotes(noteItem: Zotero.Item): Promise<string> {
|
||||
const parser = ztoolkit.getDOMParser();
|
||||
const parser = new DOMParser();
|
||||
|
||||
const globalCitationData = getNoteCitationData(noteItem as Zotero.Item);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,22 +17,6 @@ export function registerMenus() {
|
|||
);
|
||||
},
|
||||
});
|
||||
ztoolkit.Menu.register("item", {
|
||||
tag: "menuitem",
|
||||
label: getString("menuItem.setMainNote"),
|
||||
icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
|
||||
commandListener: (ev) => {
|
||||
addon.hooks.onSetWorkspaceNote(ZoteroPane.getSelectedItems()[0].id);
|
||||
},
|
||||
getVisibility: (elem, ev) => {
|
||||
const items = ZoteroPane.getSelectedItems();
|
||||
return (
|
||||
items.length == 1 &&
|
||||
items[0].isNote() &&
|
||||
items[0].id !== addon.data.workspace.mainId
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// menuEdit
|
||||
const menuEditAnchor = document.querySelector(
|
||||
|
|
@ -133,88 +117,66 @@ export function registerMenus() {
|
|||
menuFileAnchor,
|
||||
);
|
||||
|
||||
document
|
||||
.querySelector(`#${recentMainNotesMenuId}`)
|
||||
?.addEventListener("popupshowing", () => {
|
||||
const popup = document.querySelector(`#${recentMainNotesMenuPopupId}`)!;
|
||||
removeChildren(popup);
|
||||
const children = Zotero.Items.get(
|
||||
((getPref("recentMainNoteIds") as string) || "")
|
||||
.split(",")
|
||||
.map((id) => parseInt(id))
|
||||
.filter((id) => id !== addon.data.workspace.mainId),
|
||||
)
|
||||
.filter((item) => item.isNote())
|
||||
.map((item) => ({
|
||||
tag: "menuitem",
|
||||
attributes: {
|
||||
label: slice(
|
||||
`${slice(item.getNoteTitle().trim() || item.key, 30)} - ${
|
||||
item.parentItem
|
||||
? "📄" + item.parentItem.getField("title")
|
||||
: "📁" +
|
||||
Zotero.Collections.get(item.getCollections())
|
||||
.map(
|
||||
(collection) => (collection as Zotero.Collection).name,
|
||||
)
|
||||
.join(", ")
|
||||
}`,
|
||||
200,
|
||||
),
|
||||
},
|
||||
listeners: [
|
||||
{
|
||||
type: "command",
|
||||
listener: () => {
|
||||
addon.hooks.onSetWorkspaceNote(item.id, "main");
|
||||
addon.hooks.onOpenWorkspace();
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
const defaultChildren = [
|
||||
{
|
||||
tag: "menuitem",
|
||||
attributes: {
|
||||
label: getString("menuFile-openRecent-empty"),
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
// document
|
||||
// .querySelector(`#${recentMainNotesMenuId}`)
|
||||
// ?.addEventListener("popupshowing", () => {
|
||||
// const popup = document.querySelector(`#${recentMainNotesMenuPopupId}`)!;
|
||||
// removeChildren(popup);
|
||||
// const children = Zotero.Items.get(
|
||||
// ((getPref("recentMainNoteIds") as string) || "")
|
||||
// .split(",")
|
||||
// .map((id) => parseInt(id))
|
||||
// .filter((id) => id !== addon.data.workspace.mainId),
|
||||
// )
|
||||
// .filter((item) => item.isNote())
|
||||
// .map((item) => ({
|
||||
// tag: "menuitem",
|
||||
// attributes: {
|
||||
// label: slice(
|
||||
// `${slice(item.getNoteTitle().trim() || item.key, 30)} - ${
|
||||
// item.parentItem
|
||||
// ? "📄" + item.parentItem.getField("title")
|
||||
// : "📁" +
|
||||
// Zotero.Collections.get(item.getCollections())
|
||||
// .map(
|
||||
// (collection) => (collection as Zotero.Collection).name,
|
||||
// )
|
||||
// .join(", ")
|
||||
// }`,
|
||||
// 200,
|
||||
// ),
|
||||
// },
|
||||
// listeners: [
|
||||
// {
|
||||
// type: "command",
|
||||
// listener: () => {
|
||||
// addon.hooks.onSetWorkspaceNote(item.id, "main");
|
||||
// addon.hooks.onOpenWorkspace();
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// }));
|
||||
// const defaultChildren = [
|
||||
// {
|
||||
// tag: "menuitem",
|
||||
// attributes: {
|
||||
// label: getString("menuFile-openRecent-empty"),
|
||||
// disabled: true,
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
|
||||
ztoolkit.UI.appendElement(
|
||||
{
|
||||
tag: "fragment",
|
||||
children: children.length === 0 ? defaultChildren : children,
|
||||
enableElementRecord: false,
|
||||
},
|
||||
popup,
|
||||
);
|
||||
return true;
|
||||
});
|
||||
// ztoolkit.UI.appendElement(
|
||||
// {
|
||||
// tag: "fragment",
|
||||
// children: children.length === 0 ? defaultChildren : children,
|
||||
// enableElementRecord: false,
|
||||
// },
|
||||
// popup,
|
||||
// );
|
||||
// return true;
|
||||
// });
|
||||
|
||||
ztoolkit.Menu.register(
|
||||
"menuFile",
|
||||
{
|
||||
tag: "menuitem",
|
||||
label: getString("menuFile-openMainNote"),
|
||||
icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
|
||||
commandListener: async (ev) => {
|
||||
const selectedIds = await itemPicker();
|
||||
if (
|
||||
selectedIds?.length === 1 &&
|
||||
Zotero.Items.get(selectedIds[0]).isNote()
|
||||
) {
|
||||
addon.hooks.onSetWorkspaceNote(selectedIds[0], "main");
|
||||
addon.hooks.onOpenWorkspace();
|
||||
} else {
|
||||
window.alert(getString("menuFile-openMainNote-error"));
|
||||
}
|
||||
},
|
||||
},
|
||||
"after",
|
||||
menuFileAnchor,
|
||||
);
|
||||
ztoolkit.Menu.register(
|
||||
"menuFile",
|
||||
{ tag: "menuseparator" },
|
||||
|
|
@ -256,28 +218,11 @@ export function registerMenus() {
|
|||
"after",
|
||||
menuFileAnchor,
|
||||
);
|
||||
ztoolkit.Menu.register(
|
||||
"menuFile",
|
||||
{
|
||||
tag: "menuitem",
|
||||
label: getString("menuAddNote.newMainNote"),
|
||||
icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
|
||||
commandListener: addon.hooks.onCreateWorkspaceNote,
|
||||
},
|
||||
"after",
|
||||
menuFileAnchor,
|
||||
);
|
||||
|
||||
// create note menu in library
|
||||
const newNoteMenu = document
|
||||
.querySelector("#zotero-tb-note-add")
|
||||
?.querySelector("menupopup") as XUL.MenuPopup;
|
||||
ztoolkit.Menu.register(newNoteMenu, {
|
||||
tag: "menuitem",
|
||||
label: getString("menuAddNote.newMainNote"),
|
||||
icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
|
||||
commandListener: addon.hooks.onCreateWorkspaceNote,
|
||||
});
|
||||
ztoolkit.Menu.register(newNoteMenu, {
|
||||
tag: "menuitem",
|
||||
label: getString("menuAddNote.newTemplateStandaloneNote"),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
import { PatchHelper } from "zotero-plugin-toolkit/dist/helpers/patch";
|
||||
|
||||
export function patchViewItems(win: Window) {
|
||||
// @ts-ignore
|
||||
const ZoteroPane = win.ZoteroPane;
|
||||
new PatchHelper().setData({
|
||||
target: ZoteroPane,
|
||||
funcSign: "viewItems",
|
||||
patcher: (origin) =>
|
||||
function (items: Zotero.Item[], event?: KeyboardEvent) {
|
||||
if (!addon.data.alive || event?.shiftKey) {
|
||||
// @ts-ignore
|
||||
return origin.apply(this, [items, event]);
|
||||
}
|
||||
const otherItems = [];
|
||||
for (const item of items) {
|
||||
if (item.isNote()) {
|
||||
addon.hooks.onOpenWorkspace(item, "tab");
|
||||
continue;
|
||||
}
|
||||
otherItems.push(item);
|
||||
}
|
||||
// @ts-ignore
|
||||
return origin.apply(this, [otherItems, event]);
|
||||
},
|
||||
enabled: true,
|
||||
});
|
||||
}
|
||||
|
|
@ -1,489 +1,20 @@
|
|||
import { config } from "../../../package.json";
|
||||
import { ICONS } from "../../utils/config";
|
||||
import { itemPicker } from "../../utils/itemPicker";
|
||||
import { getString } from "../../utils/locale";
|
||||
import { getNoteTreeFlattened } from "../../utils/note";
|
||||
import { getPref } from "../../utils/prefs";
|
||||
import { waitUtilAsync } from "../../utils/wait";
|
||||
import { OutlineType } from "../../utils/workspace";
|
||||
import { saveFreeMind as _saveFreeMind } from "../export/freemind";
|
||||
|
||||
function makeId(key: string) {
|
||||
return `betternotes-workspace-${key}`;
|
||||
}
|
||||
|
||||
export function initWorkspace(container: XUL.Box | undefined) {
|
||||
export function initWorkspace(container: XUL.Box, item: Zotero.Item) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
function makeTooltipProp(
|
||||
id: string,
|
||||
content: string,
|
||||
title: string,
|
||||
callback: (ev: Event) => void,
|
||||
) {
|
||||
return {
|
||||
id,
|
||||
tag: "button",
|
||||
namespace: "html",
|
||||
classList: ["tool-button"],
|
||||
properties: {
|
||||
innerHTML: content,
|
||||
title,
|
||||
},
|
||||
listeners: [
|
||||
{
|
||||
type: "click",
|
||||
listener: callback,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
ztoolkit.UI.appendElement(
|
||||
{
|
||||
tag: "hbox",
|
||||
id: makeId("top-container"),
|
||||
styles: { width: "100%", height: "100%" },
|
||||
properties: {},
|
||||
attributes: {
|
||||
flex: "1",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
tag: "vbox",
|
||||
id: makeId("outline-container"),
|
||||
styles: {
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
},
|
||||
attributes: {
|
||||
width: "330",
|
||||
minwidth: "300",
|
||||
flex: "1",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
tag: "link",
|
||||
properties: {
|
||||
rel: "stylesheet",
|
||||
href: `chrome://${config.addonRef}/content/toolbutton.css`,
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: "div",
|
||||
id: makeId("outline-content"),
|
||||
styles: {
|
||||
height: "100%",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
tag: "iframe",
|
||||
id: makeId("outline-iframe"),
|
||||
properties: {
|
||||
width: "100%",
|
||||
},
|
||||
styles: {
|
||||
border: "0",
|
||||
height: "100%",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "div",
|
||||
id: makeId("outline-buttons"),
|
||||
styles: {
|
||||
height: "50px",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
margin: "10px 20px 10px 20px",
|
||||
},
|
||||
children: [
|
||||
makeTooltipProp(
|
||||
makeId("switchOutline"),
|
||||
ICONS.switchOutline,
|
||||
getString("workspace.switchOutline"),
|
||||
(ev) => {
|
||||
setOutline(container);
|
||||
},
|
||||
),
|
||||
makeTooltipProp(
|
||||
makeId("saveOutlineImage"),
|
||||
ICONS.saveOutlineImage,
|
||||
getString("workspace.saveOutlineImage"),
|
||||
(ev) => {
|
||||
saveImage(container);
|
||||
},
|
||||
),
|
||||
makeTooltipProp(
|
||||
makeId("saveOutlineFreeMind"),
|
||||
ICONS.saveOutlineFreeMind,
|
||||
getString("workspace.saveOutlineFreeMind"),
|
||||
(ev) => {
|
||||
saveFreeMind();
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "splitter",
|
||||
id: makeId("outline-splitter"),
|
||||
attributes: { collapse: "before" },
|
||||
children: [
|
||||
{
|
||||
tag: "grippy",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "vbox",
|
||||
id: makeId("editor-main-container"),
|
||||
attributes: {
|
||||
flex: "1",
|
||||
width: "700",
|
||||
},
|
||||
styles: {
|
||||
background: "var(--material-background50)",
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: "splitter",
|
||||
id: makeId("preview-splitter"),
|
||||
attributes: { collapse: "after", state: "collapsed" },
|
||||
children: [
|
||||
{
|
||||
tag: "grippy",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "vbox",
|
||||
id: makeId("editor-preview-container"),
|
||||
attributes: {
|
||||
flex: "1",
|
||||
width: "500",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
container,
|
||||
);
|
||||
// Manually add custom editor items in Zotero 7
|
||||
|
||||
container.style.minWidth = "0px";
|
||||
container.style.minHeight = "0px";
|
||||
|
||||
// @ts-ignore
|
||||
const customElements = container.ownerGlobal
|
||||
.customElements as CustomElementRegistry;
|
||||
const mainEditorContainer = container.querySelector(
|
||||
`#${makeId("editor-main-container")}`,
|
||||
);
|
||||
const previewEditorContainer = container.querySelector(
|
||||
`#${makeId("editor-preview-container")}`,
|
||||
);
|
||||
const mainEditor = new (customElements.get("note-editor")!)();
|
||||
mainEditor.id = makeId("editor-main");
|
||||
mainEditor.setAttribute("flex", "1");
|
||||
const previewEditor = new (customElements.get("note-editor")!)();
|
||||
previewEditor.id = makeId("editor-preview");
|
||||
previewEditor.setAttribute("flex", "1");
|
||||
mainEditorContainer?.append(mainEditor);
|
||||
previewEditorContainer?.append(previewEditor);
|
||||
|
||||
const outlineContainer = container.querySelector(
|
||||
`#${makeId("outline-container")}`,
|
||||
) as XUL.Box;
|
||||
outlineContainer.style.background = "var(--material-sidepane)";
|
||||
const outlineMut = new (ztoolkit.getGlobal("MutationObserver"))(
|
||||
(mutations) => {
|
||||
if (outlineContainer.getAttribute("collapsed") === "true") {
|
||||
outlineContainer.style.removeProperty("display");
|
||||
} else {
|
||||
outlineContainer.style.display = "flex";
|
||||
}
|
||||
},
|
||||
);
|
||||
outlineMut.observe(outlineContainer, {
|
||||
attributes: true,
|
||||
attributeFilter: ["collapsed"],
|
||||
});
|
||||
|
||||
setOutline(container, OutlineType.treeView);
|
||||
initWorkspaceEditor(container, "main", addon.data.workspace.mainId);
|
||||
}
|
||||
|
||||
export async function initWorkspaceEditor(
|
||||
container: XUL.Box,
|
||||
type: "main" | "preview",
|
||||
noteId: number,
|
||||
options: {
|
||||
lineIndex?: number;
|
||||
sectionName?: string;
|
||||
} = {},
|
||||
) {
|
||||
const noteItem = Zotero.Items.get(noteId);
|
||||
if (!noteItem || !noteItem.isNote()) {
|
||||
ztoolkit.UI.appendElement(
|
||||
{
|
||||
tag: "div",
|
||||
id: makeId("emptyWorkspaceGuide"),
|
||||
styles: {
|
||||
position: "absolute",
|
||||
top: "0",
|
||||
left: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
backgroundColor: "rgba(255,255,255,0.8)",
|
||||
zIndex: "100",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
tag: "div",
|
||||
properties: {
|
||||
innerHTML: getString("workspace-emptyWorkspaceGuideInfo"),
|
||||
},
|
||||
styles: {
|
||||
fontSize: "20px",
|
||||
fontWeight: "bold",
|
||||
color: "gray",
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: "button",
|
||||
namespace: "xul",
|
||||
properties: {
|
||||
label: getString("workspace-emptyWorkspaceGuideOpen"),
|
||||
},
|
||||
styles: {
|
||||
fontSize: "16px",
|
||||
},
|
||||
listeners: [
|
||||
{
|
||||
type: "command",
|
||||
listener: async (ev) => {
|
||||
const selectedIds = await itemPicker();
|
||||
if (
|
||||
selectedIds?.length === 1 &&
|
||||
Zotero.Items.get(selectedIds[0]).isNote()
|
||||
) {
|
||||
addon.hooks.onSetWorkspaceNote(selectedIds[0], "main");
|
||||
addon.hooks.onOpenWorkspace();
|
||||
} else {
|
||||
window.alert(getString("menuFile-openMainNote-error"));
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "div",
|
||||
properties: {
|
||||
innerHTML: getString("workspace-emptyWorkspaceGuideOr"),
|
||||
},
|
||||
styles: {
|
||||
fontSize: "16px",
|
||||
color: "gray",
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: "button",
|
||||
namespace: "xul",
|
||||
properties: {
|
||||
label: getString("workspace-emptyWorkspaceGuideCreate"),
|
||||
},
|
||||
styles: {
|
||||
fontSize: "16px",
|
||||
},
|
||||
listeners: [
|
||||
{
|
||||
type: "command",
|
||||
listener: () => {
|
||||
addon.hooks.onCreateWorkspaceNote();
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
container,
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
container.querySelector(`#${makeId("emptyWorkspaceGuide")}`)?.remove();
|
||||
}
|
||||
const editorElem = container.querySelector(
|
||||
`#${makeId("editor-" + type)}`,
|
||||
) as EditorElement;
|
||||
await waitUtilAsync(() => Boolean(editorElem._initialized))
|
||||
.then(() => ztoolkit.log("ok"))
|
||||
.catch(() => ztoolkit.log("fail"));
|
||||
if (!editorElem._initialized) {
|
||||
throw new Error("initNoteEditor: waiting initialization failed");
|
||||
}
|
||||
editorElem.mode = "edit";
|
||||
editorElem.viewMode = "library";
|
||||
editorElem.parent = undefined;
|
||||
editorElem.item = noteItem;
|
||||
await waitUtilAsync(() => Boolean(editorElem._editorInstance));
|
||||
await editorElem._editorInstance._initPromise;
|
||||
if (typeof options.lineIndex === "number") {
|
||||
addon.api.editor.scroll(editorElem._editorInstance, options.lineIndex);
|
||||
}
|
||||
if (typeof options.sectionName === "string") {
|
||||
addon.api.editor.scrollToSection(
|
||||
editorElem._editorInstance,
|
||||
options.sectionName,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
function getContainerType(
|
||||
container: XUL.Box | undefined,
|
||||
): "tab" | "window" | "unknown" {
|
||||
if (!container) {
|
||||
return "unknown";
|
||||
}
|
||||
return (container.getAttribute("workspace-type") || "unknown") as
|
||||
| "tab"
|
||||
| "window"
|
||||
| "unknown";
|
||||
}
|
||||
|
||||
export function toggleOutlinePane(visibility?: boolean, container?: XUL.Box) {
|
||||
const splitter = container?.querySelector(`#${makeId("outline-splitter")}`);
|
||||
if (typeof visibility === "undefined") {
|
||||
visibility = splitter?.getAttribute("state") === "collapsed";
|
||||
}
|
||||
splitter?.setAttribute("state", visibility ? "open" : "collapsed");
|
||||
}
|
||||
|
||||
export function togglePreviewPane(visibility?: boolean, container?: XUL.Box) {
|
||||
const splitter = container?.querySelector(`#${makeId("preview-splitter")}`);
|
||||
if (typeof visibility === "undefined") {
|
||||
visibility = splitter?.getAttribute("state") === "collapsed";
|
||||
}
|
||||
splitter?.setAttribute("state", visibility ? "open" : "collapsed");
|
||||
}
|
||||
|
||||
export function toggleNotesPane(visibility?: boolean) {
|
||||
const splitter = document?.querySelector("#zotero-context-splitter");
|
||||
if (typeof visibility === "undefined") {
|
||||
visibility = splitter?.getAttribute("state") === "collapsed";
|
||||
}
|
||||
splitter?.setAttribute("state", visibility ? "open" : "collapsed");
|
||||
}
|
||||
|
||||
export function getWorkspaceEditor(
|
||||
workspaceType: "tab" | "window",
|
||||
editorType: "main" | "preview" = "main",
|
||||
) {
|
||||
const container =
|
||||
workspaceType === "tab"
|
||||
? addon.data.workspace.tab.container
|
||||
: addon.data.workspace.window.container;
|
||||
return (
|
||||
container?.querySelector(`#${makeId(`editor-${editorType}`)}`) as
|
||||
| EditorElement
|
||||
| undefined
|
||||
)?._editorInstance;
|
||||
}
|
||||
|
||||
const SRC_LIST = [
|
||||
"",
|
||||
`chrome://${config.addonRef}/content/treeView.html`,
|
||||
`chrome://${config.addonRef}/content/mindMap.html`,
|
||||
`chrome://${config.addonRef}/content/bubbleMap.html`,
|
||||
];
|
||||
|
||||
function setOutline(
|
||||
container: XUL.Box,
|
||||
newType: OutlineType = OutlineType.empty,
|
||||
) {
|
||||
if (newType === OutlineType.empty) {
|
||||
newType = addon.data.workspace.outline + 1;
|
||||
}
|
||||
if (newType > OutlineType.bubbleMap) {
|
||||
newType = OutlineType.treeView;
|
||||
}
|
||||
addon.data.workspace.outline = newType;
|
||||
(
|
||||
container.querySelector(`#${makeId("saveOutlineImage")}`) as HTMLDivElement
|
||||
).hidden = newType === OutlineType.treeView;
|
||||
(
|
||||
container.querySelector(
|
||||
`#${makeId("saveOutlineFreeMind")}`,
|
||||
) as HTMLDivElement
|
||||
).hidden = newType === OutlineType.treeView;
|
||||
const iframe = container.querySelector(
|
||||
`#${makeId("outline-iframe")}`,
|
||||
) as HTMLIFrameElement;
|
||||
iframe.setAttribute("src", SRC_LIST[addon.data.workspace.outline]);
|
||||
updateOutline(container);
|
||||
updateOutlineButtons(container);
|
||||
}
|
||||
|
||||
export async function updateOutline(container: XUL.Box) {
|
||||
const iframe = container.querySelector(
|
||||
`#${makeId("outline-iframe")}`,
|
||||
) as HTMLIFrameElement;
|
||||
await waitUtilAsync(
|
||||
() => iframe.contentWindow?.document.readyState === "complete",
|
||||
);
|
||||
iframe.contentWindow?.postMessage(
|
||||
{
|
||||
type: "setMindMapData",
|
||||
nodes: getNoteTreeFlattened(
|
||||
Zotero.Items.get(addon.data.workspace.mainId),
|
||||
{ keepLink: !!getPref("workspace.outline.keepLinks") },
|
||||
),
|
||||
workspaceType: getContainerType(container),
|
||||
expandLevel: getPref("workspace.outline.expandLevel"),
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
|
||||
function updateOutlineButtons(container: XUL.Box) {
|
||||
const outlineType = addon.data.workspace.outline;
|
||||
const isTreeView = outlineType === OutlineType.treeView;
|
||||
(
|
||||
container.querySelector(`#${makeId("saveOutlineImage")}`) as HTMLDivElement
|
||||
).style.visibility = isTreeView ? "hidden" : "visible";
|
||||
(
|
||||
container.querySelector(
|
||||
`#${makeId("saveOutlineFreeMind")}`,
|
||||
) as HTMLDivElement
|
||||
).style.visibility = isTreeView ? "hidden" : "visible";
|
||||
}
|
||||
|
||||
function saveImage(container: XUL.Box) {
|
||||
const iframe = container.querySelector(
|
||||
`#${makeId("outline-iframe")}`,
|
||||
) as HTMLIFrameElement;
|
||||
iframe.contentWindow?.postMessage(
|
||||
{
|
||||
type: "saveSVG",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
|
||||
async function saveFreeMind() {
|
||||
// TODO: uncouple this part
|
||||
const filename = await new ztoolkit.FilePicker(
|
||||
`${Zotero.getString("fileInterface.export")} FreeMind XML`,
|
||||
"save",
|
||||
[["FreeMind XML File(*.mm)", "*.mm"]],
|
||||
`${Zotero.Items.get(addon.data.workspace.mainId).getNoteTitle()}.mm`,
|
||||
).open();
|
||||
if (filename) {
|
||||
await _saveFreeMind(filename, addon.data.workspace.mainId);
|
||||
}
|
||||
const workspace = new (customElements.get("bn-workspace")!)() as any;
|
||||
container.append(workspace);
|
||||
workspace.item = item;
|
||||
workspace.containerType = "tab";
|
||||
workspace.render();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
import {
|
||||
getEditorInstance,
|
||||
moveHeading,
|
||||
updateHeadingTextAtLine,
|
||||
} from "../../utils/editor";
|
||||
import { showHintWithLink } from "../../utils/hint";
|
||||
import { getNoteLinkParams } from "../../utils/link";
|
||||
import { getNoteTree, getNoteTreeNodeById } from "../../utils/note";
|
||||
import { formatPath } from "../../utils/str";
|
||||
|
||||
export async function messageHandler(ev: MessageEvent) {
|
||||
switch (ev.data.type) {
|
||||
case "jumpNode": {
|
||||
const editor = addon.api.workspace.getWorkspaceEditor(
|
||||
ev.data.workspaceType,
|
||||
"main",
|
||||
);
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
addon.api.editor.scroll(editor, ev.data.lineIndex);
|
||||
return;
|
||||
}
|
||||
case "openNote": {
|
||||
const linkParams = getNoteLinkParams(ev.data.link);
|
||||
if (!linkParams.noteItem) {
|
||||
return;
|
||||
}
|
||||
addon.hooks.onOpenNote(linkParams.noteItem.id, "preview", {
|
||||
lineIndex: linkParams.lineIndex || undefined,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case "moveNode": {
|
||||
const noteItem = Zotero.Items.get(addon.data.workspace.mainId);
|
||||
const tree = getNoteTree(noteItem);
|
||||
const fromNode = getNoteTreeNodeById(noteItem, ev.data.fromID, tree);
|
||||
const toNode = getNoteTreeNodeById(noteItem, ev.data.toID, tree);
|
||||
moveHeading(
|
||||
getEditorInstance(noteItem.id),
|
||||
fromNode!,
|
||||
toNode!,
|
||||
ev.data.moveType,
|
||||
);
|
||||
return;
|
||||
}
|
||||
case "editNode": {
|
||||
const editor = addon.api.workspace.getWorkspaceEditor(
|
||||
ev.data.workspaceType,
|
||||
"main",
|
||||
);
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
updateHeadingTextAtLine(
|
||||
editor,
|
||||
ev.data.lineIndex,
|
||||
ev.data.text.replace(/[\r\n]/g, ""),
|
||||
);
|
||||
return;
|
||||
}
|
||||
case "saveSVGReturn": {
|
||||
const filename = await new ztoolkit.FilePicker(
|
||||
`${Zotero.getString("fileInterface.export")} SVG Image`,
|
||||
"save",
|
||||
[["SVG File(*.svg)", "*.svg"]],
|
||||
`${Zotero.Items.get(addon.data.workspace.mainId).getNoteTitle()}.svg`,
|
||||
).open();
|
||||
if (filename) {
|
||||
await Zotero.File.putContentsAsync(formatPath(filename), ev.data.image);
|
||||
showHintWithLink(
|
||||
`Image Saved to ${filename}`,
|
||||
"Show in Folder",
|
||||
(ev) => {
|
||||
Zotero.File.reveal(filename);
|
||||
},
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,7 @@
|
|||
import { config } from "../../../package.json";
|
||||
import { ICONS } from "../../utils/config";
|
||||
import { showHint } from "../../utils/hint";
|
||||
import { getString } from "../../utils/locale";
|
||||
import { getPref, setPref } from "../../utils/prefs";
|
||||
import { waitUtilAsync } from "../../utils/wait";
|
||||
// TODO: uncouple these imports
|
||||
import { messageHandler } from "./message";
|
||||
import { initWorkspace } from "./content";
|
||||
|
||||
export const TAB_TYPE = "betternotes";
|
||||
export const TAB_TYPE = "note";
|
||||
|
||||
export function registerWorkspaceTab(win: Window) {
|
||||
const doc = win.document;
|
||||
|
|
@ -29,18 +23,17 @@ export function registerWorkspaceTab(win: Window) {
|
|||
{
|
||||
type: "command",
|
||||
listener: (ev) => {
|
||||
if ((ev as MouseEvent).shiftKey) {
|
||||
addon.hooks.onOpenWorkspace("window");
|
||||
} else {
|
||||
addon.hooks.onOpenWorkspace("tab");
|
||||
}
|
||||
// if ((ev as MouseEvent).shiftKey) {
|
||||
// addon.hooks.onOpenWorkspace("window");
|
||||
// } else {
|
||||
// addon.hooks.onOpenWorkspace("tab");
|
||||
// }
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
spacer,
|
||||
) as XUL.ToolBarButton;
|
||||
win.addEventListener("message", messageHandler, false);
|
||||
const collectionSearch = doc.querySelector("#zotero-collections-search")!;
|
||||
const ob = new (ztoolkit.getGlobal("MutationObserver"))((muts) => {
|
||||
tabButton.hidden = !!collectionSearch?.classList.contains("visible");
|
||||
|
|
@ -54,347 +47,47 @@ export function registerWorkspaceTab(win: Window) {
|
|||
"unload",
|
||||
() => {
|
||||
ob.disconnect();
|
||||
win.removeEventListener("message", messageHandler);
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
}
|
||||
|
||||
export async function openWorkspaceTab() {
|
||||
if (addon.data.workspace.tab.active) {
|
||||
Zotero_Tabs.select(addon.data.workspace.tab.id!);
|
||||
export async function openWorkspaceTab(item: Zotero.Item) {
|
||||
const currentTab = Zotero_Tabs._tabs.find(
|
||||
(tab) => tab.data?.itemID == item.id,
|
||||
);
|
||||
if (currentTab) {
|
||||
Zotero_Tabs.select(currentTab.id);
|
||||
return;
|
||||
}
|
||||
const { id, container } = Zotero_Tabs.add({
|
||||
type: TAB_TYPE,
|
||||
title: getString("tab.name"),
|
||||
title: item.getNoteTitle(),
|
||||
index: 1,
|
||||
data: {
|
||||
itemID: addon.data.workspace.mainId,
|
||||
itemID: item.id,
|
||||
},
|
||||
select: false,
|
||||
onClose: () => {
|
||||
deActivateWorkspaceTab();
|
||||
},
|
||||
onClose: () => {},
|
||||
});
|
||||
addon.data.workspace.tab.id = id;
|
||||
container.setAttribute("workspace-type", "tab");
|
||||
addon.data.workspace.tab.container = container;
|
||||
|
||||
await activateWorkspaceTab();
|
||||
initWorkspace(container, item);
|
||||
Zotero_Tabs.select(id);
|
||||
}
|
||||
|
||||
function hoverWorkspaceTab(hovered: boolean) {
|
||||
Array.from(document.querySelectorAll(".tab-toggle")).forEach((elem) => {
|
||||
(elem as HTMLDivElement).style.visibility = hovered ? "visible" : "hidden";
|
||||
});
|
||||
const tabElem = document.querySelector(
|
||||
`.tabs-wrapper .tab[data-id=${addon.data.workspace.tab.id}]`,
|
||||
) as HTMLDivElement;
|
||||
const content = tabElem.querySelector(".tab-name") as HTMLDivElement;
|
||||
content.removeAttribute("style");
|
||||
if (hovered) {
|
||||
content.style["-moz-box-pack" as any] = "start";
|
||||
}
|
||||
}
|
||||
let contextPaneOpen: boolean | undefined = undefined;
|
||||
|
||||
function updateWorkspaceTabToggleButton(
|
||||
type: "outline" | "preview" | "notes",
|
||||
state: "open" | "collapsed",
|
||||
) {
|
||||
const elem = document.querySelector(
|
||||
`#betternotes-tab-toggle-${type}`,
|
||||
) as HTMLDivElement;
|
||||
if (!elem) {
|
||||
export function onTabSelect(tabType: string) {
|
||||
const ZoteroContextPane = ztoolkit.getGlobal("ZoteroContextPane");
|
||||
const splitter = ZoteroContextPane.getSplitter();
|
||||
|
||||
if (tabType === TAB_TYPE) {
|
||||
contextPaneOpen = splitter.getAttribute("state") != "collapsed";
|
||||
splitter.setAttribute("state", "collapsed");
|
||||
} else if (typeof contextPaneOpen !== "undefined") {
|
||||
splitter.setAttribute("state", contextPaneOpen ? "open" : "collapsed");
|
||||
contextPaneOpen = undefined;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (state !== "collapsed") {
|
||||
state = "open";
|
||||
}
|
||||
elem.innerHTML = ICONS[`workspace_${type}_${state}`];
|
||||
}
|
||||
|
||||
function registerWorkspaceTabPaneObserver() {
|
||||
const outlineSplitter = document.querySelector(
|
||||
"#betternotes-workspace-outline-splitter",
|
||||
);
|
||||
const outlineMut = new (ztoolkit.getGlobal("MutationObserver"))((muts) => {
|
||||
updateWorkspaceTabToggleButton(
|
||||
"outline",
|
||||
outlineSplitter!.getAttribute("state")! as "open" | "collapsed",
|
||||
);
|
||||
});
|
||||
outlineMut.observe(outlineSplitter!, {
|
||||
attributes: true,
|
||||
attributeFilter: ["state"],
|
||||
});
|
||||
const previewSplitter = document.querySelector(
|
||||
"#betternotes-workspace-preview-splitter",
|
||||
);
|
||||
const previeweMut = new (ztoolkit.getGlobal("MutationObserver"))((muts) => {
|
||||
updateWorkspaceTabToggleButton(
|
||||
"preview",
|
||||
previewSplitter!.getAttribute("state")! as "open" | "collapsed",
|
||||
);
|
||||
});
|
||||
previeweMut.observe(previewSplitter!, {
|
||||
attributes: true,
|
||||
attributeFilter: ["state"],
|
||||
});
|
||||
const notesSplitter = document.querySelector("#zotero-context-splitter");
|
||||
const notesMut = new (ztoolkit.getGlobal("MutationObserver"))((muts) => {
|
||||
updateWorkspaceTabToggleButton(
|
||||
"notes",
|
||||
notesSplitter!.getAttribute("state")! as "open" | "collapsed",
|
||||
);
|
||||
});
|
||||
notesMut.observe(notesSplitter!, {
|
||||
attributes: true,
|
||||
attributeFilter: ["state"],
|
||||
});
|
||||
}
|
||||
|
||||
function isContextPaneInitialized() {
|
||||
return (
|
||||
(document.querySelector(".notes-pane-deck")?.childElementCount || 0) > 0
|
||||
);
|
||||
}
|
||||
|
||||
export async function activateWorkspaceTab() {
|
||||
if (Zotero_Tabs.selectedType === TAB_TYPE && isContextPaneInitialized()) {
|
||||
const tabToolbar = document.querySelector("#zotero-tab-toolbar") as XUL.Box;
|
||||
tabToolbar && (tabToolbar.style.visibility = "collapse");
|
||||
const toolbar = document.querySelector(
|
||||
"#zotero-context-toolbar-extension",
|
||||
) as XUL.Box;
|
||||
if (toolbar) {
|
||||
toolbar.style.visibility = "collapse";
|
||||
toolbar.nextElementSibling?.setAttribute("selectedIndex", "1");
|
||||
}
|
||||
}
|
||||
|
||||
if (addon.data.workspace.tab.active) {
|
||||
ztoolkit.log("workspace tab is already active");
|
||||
return;
|
||||
}
|
||||
setWorkspaceTabStatus(true);
|
||||
// reset tab style
|
||||
await waitUtilAsync(() =>
|
||||
Boolean(
|
||||
document.querySelector(
|
||||
`.tabs-wrapper .tab[data-id=${addon.data.workspace.tab.id}]`,
|
||||
),
|
||||
),
|
||||
);
|
||||
const tabElem = document.querySelector(
|
||||
`.tabs-wrapper .tab[data-id=${addon.data.workspace.tab.id}]`,
|
||||
) as HTMLDivElement;
|
||||
tabElem.removeAttribute("style");
|
||||
const content = tabElem.querySelector(".tab-name") as HTMLDivElement;
|
||||
const close = tabElem.querySelector(".tab-close") as HTMLDivElement;
|
||||
content.removeAttribute("style");
|
||||
content.append(document.createTextNode(getString("tab.name")));
|
||||
close.style.removeProperty("visibility");
|
||||
ztoolkit.UI.insertElementBefore(
|
||||
{
|
||||
tag: "fragment",
|
||||
children: [
|
||||
{
|
||||
tag: "div",
|
||||
id: "betternotes-tab-toggle-outline",
|
||||
classList: ["tab-close", "tab-toggle"],
|
||||
styles: {
|
||||
right: "56px",
|
||||
},
|
||||
properties: {
|
||||
innerHTML: ICONS.workspace_outline_open,
|
||||
},
|
||||
listeners: [
|
||||
{
|
||||
type: "click",
|
||||
listener: (ev) => {
|
||||
addon.hooks.onToggleWorkspacePane(
|
||||
"outline",
|
||||
undefined,
|
||||
addon.data.workspace.tab.container,
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "div",
|
||||
id: "betternotes-tab-toggle-preview",
|
||||
classList: ["tab-close", "tab-toggle"],
|
||||
styles: {
|
||||
right: "40px",
|
||||
},
|
||||
properties: {
|
||||
innerHTML: ICONS.workspace_preview_collapsed,
|
||||
},
|
||||
listeners: [
|
||||
{
|
||||
type: "click",
|
||||
listener: (ev) => {
|
||||
addon.hooks.onToggleWorkspacePane(
|
||||
"preview",
|
||||
undefined,
|
||||
addon.data.workspace.tab.container,
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "div",
|
||||
id: "betternotes-tab-toggle-notes",
|
||||
classList: ["tab-close", "tab-toggle"],
|
||||
styles: {
|
||||
right: "24px",
|
||||
},
|
||||
properties: {
|
||||
innerHTML:
|
||||
document
|
||||
.querySelector("#zotero-context-splitter")
|
||||
?.getAttribute("state") === "open"
|
||||
? ICONS.workspace_notes_open
|
||||
: ICONS.workspace_notes_collapsed,
|
||||
},
|
||||
listeners: [
|
||||
{
|
||||
type: "click",
|
||||
listener: (ev) => {
|
||||
if (isContextPaneInitialized()) {
|
||||
addon.hooks.onToggleWorkspacePane("notes");
|
||||
return;
|
||||
}
|
||||
showHint(getString("workspace.notesPane.hint"));
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
close,
|
||||
);
|
||||
hoverWorkspaceTab(false);
|
||||
tabElem.addEventListener("mouseenter", () => {
|
||||
if (Zotero_Tabs.selectedType !== "betternotes") {
|
||||
return;
|
||||
}
|
||||
hoverWorkspaceTab(true);
|
||||
});
|
||||
tabElem.addEventListener("mousedown", () => hoverWorkspaceTab(true));
|
||||
tabElem.addEventListener("mouseleave", () => hoverWorkspaceTab(false));
|
||||
tabElem.addEventListener("mousedown", async (ev) => {
|
||||
if (ev.button !== 2) {
|
||||
return;
|
||||
}
|
||||
await Zotero.Promise.delay(300);
|
||||
const menu = document
|
||||
.querySelector("#zotero-itemmenu")
|
||||
?.parentElement?.lastElementChild?.querySelector("menu")
|
||||
?.querySelector("menupopup")?.lastElementChild;
|
||||
menu?.addEventListener("click", () => {
|
||||
addon.hooks.onOpenWorkspace("window");
|
||||
});
|
||||
});
|
||||
// load workspace content
|
||||
const container = addon.data.workspace.tab.container;
|
||||
initWorkspaceTabDragDrop(container, tabElem);
|
||||
addon.hooks.onInitWorkspace(container);
|
||||
registerWorkspaceTabPaneObserver();
|
||||
setWorkspaceTabStatus(true);
|
||||
}
|
||||
|
||||
export function deActivateWorkspaceTab() {
|
||||
const tabToolbar = document.querySelector("#zotero-tab-toolbar") as XUL.Box;
|
||||
tabToolbar && tabToolbar.style.removeProperty("visibility");
|
||||
const toolbar = document.querySelector(
|
||||
"#zotero-context-toolbar-extension",
|
||||
) as XUL.Box;
|
||||
toolbar?.style.removeProperty("visibility");
|
||||
setWorkspaceTabStatus(false);
|
||||
}
|
||||
|
||||
function setWorkspaceTabStatus(status: boolean) {
|
||||
addon.data.workspace.tab.active = status;
|
||||
setPref("workspace.tab.active", status);
|
||||
}
|
||||
|
||||
function initWorkspaceTabDragDrop(
|
||||
container?: XUL.Box,
|
||||
tabElem?: HTMLDivElement,
|
||||
) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const rect = tabElem?.getBoundingClientRect();
|
||||
ztoolkit.UI.appendElement(
|
||||
{
|
||||
tag: "div",
|
||||
id: "bn-workspace-tab-drop",
|
||||
styles: {
|
||||
background: "#252526",
|
||||
opacity: "0.6",
|
||||
width: "100%",
|
||||
height: "100px",
|
||||
position: "fixed",
|
||||
left: "0px",
|
||||
top: `${rect?.bottom}px`,
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
visibility: "hidden",
|
||||
zIndex: "65535",
|
||||
},
|
||||
properties: {
|
||||
hidden: true,
|
||||
ondrop: (ev: DragEvent) => {
|
||||
addon.hooks.onOpenWorkspace("window");
|
||||
},
|
||||
ondragenter: (ev: DragEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
dropElem.style.opacity = "0.9";
|
||||
if (ev.dataTransfer) {
|
||||
ev.dataTransfer.dropEffect = "move";
|
||||
}
|
||||
},
|
||||
ondragover: (ev: DragEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
},
|
||||
ondragleave: (ev: DragEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
dropElem.style.opacity = "0.6";
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
tag: "div",
|
||||
styles: {
|
||||
margin: "auto",
|
||||
textAlign: "center",
|
||||
color: "#fff",
|
||||
},
|
||||
properties: {
|
||||
innerHTML: getString("tab.openInWindow"),
|
||||
},
|
||||
},
|
||||
],
|
||||
enableElementRecord: false,
|
||||
},
|
||||
container,
|
||||
);
|
||||
const dropElem = container.querySelector(
|
||||
"#bn-workspace-tab-drop",
|
||||
) as HTMLDivElement;
|
||||
tabElem?.addEventListener("dragstart", (ev) => {
|
||||
dropElem.style.visibility = "visible";
|
||||
});
|
||||
tabElem?.addEventListener("dragend", (ev) => {
|
||||
dropElem.style.visibility = "hidden";
|
||||
});
|
||||
ZoteroContextPane.update();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
import { config } from "../../../package.json";
|
||||
import { isWindowAlive } from "../../utils/window";
|
||||
import { messageHandler } from "./message";
|
||||
|
||||
export async function openWorkspaceWindow() {
|
||||
if (isWindowAlive(addon.data.workspace.window.window)) {
|
||||
addon.data.workspace.window.window?.focus();
|
||||
return;
|
||||
}
|
||||
export async function openWorkspaceWindow(item: Zotero.Item) {
|
||||
const windowArgs = {
|
||||
_initPromise: Zotero.Promise.defer(),
|
||||
};
|
||||
|
|
@ -17,16 +11,9 @@ export async function openWorkspaceWindow() {
|
|||
windowArgs,
|
||||
)!;
|
||||
await windowArgs._initPromise.promise;
|
||||
addon.data.workspace.window.active = true;
|
||||
addon.data.workspace.window.window = win;
|
||||
addon.data.workspace.window.container = win.document.querySelector(
|
||||
|
||||
const container = win.document.querySelector(
|
||||
"#workspace-container",
|
||||
) as XUL.Box;
|
||||
addon.hooks.onInitWorkspace(addon.data.workspace.window.container);
|
||||
win.addEventListener("message", messageHandler, false);
|
||||
win.addEventListener("unload", function onWindowUnload(ev) {
|
||||
addon.data.workspace.window.active = false;
|
||||
this.window.removeEventListener("unload", onWindowUnload, false);
|
||||
this.window.removeEventListener("message", messageHandler, false);
|
||||
});
|
||||
addon.hooks.onInitWorkspace(container, item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ export {
|
|||
parseHTMLLines,
|
||||
getLinesInNote,
|
||||
addLineToNote,
|
||||
getNoteType,
|
||||
getNoteTree,
|
||||
getNoteTreeFlattened,
|
||||
getNoteTreeNodeById,
|
||||
|
|
@ -197,7 +196,7 @@ async function renderNoteHTML(
|
|||
refNotes = [noteItem];
|
||||
}
|
||||
|
||||
const parser = ztoolkit.getDOMParser();
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, "text/html");
|
||||
const imageAttachments = refNotes.reduce((acc, note) => {
|
||||
acc.push(...Zotero.Items.get(note.getAttachments()));
|
||||
|
|
@ -269,22 +268,12 @@ async function renderNoteHTML(
|
|||
return doc.body.innerHTML;
|
||||
}
|
||||
|
||||
function getNoteType(id: number) {
|
||||
if (id === addon.data.workspace.mainId) {
|
||||
return "main";
|
||||
} else if (id === addon.data.workspace.previewId) {
|
||||
return "preview";
|
||||
} else {
|
||||
return "default";
|
||||
}
|
||||
}
|
||||
|
||||
function getNoteTree(
|
||||
note: Zotero.Item,
|
||||
parseLink: boolean = true,
|
||||
): TreeModel.Node<NoteNodeData> {
|
||||
const noteLines = getLinesInNote(note);
|
||||
const parser = ztoolkit.getDOMParser();
|
||||
const parser = new DOMParser();
|
||||
const tree = new TreeModel();
|
||||
const root = tree.parse({
|
||||
id: -1,
|
||||
|
|
@ -422,7 +411,7 @@ async function copyEmbeddedImagesInHTML(
|
|||
|
||||
ztoolkit.log(attachments);
|
||||
|
||||
const doc = ztoolkit.getDOMParser().parseFromString(html, "text/html");
|
||||
const doc = new DOMParser().parseFromString(html, "text/html");
|
||||
|
||||
// Copy note image attachments and replace keys in the new note
|
||||
for (const attachment of attachments) {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ export function waitUntil(
|
|||
timeout = 10000,
|
||||
) {
|
||||
const start = Date.now();
|
||||
const intervalId = ztoolkit.getGlobal("setInterval")(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
if (condition()) {
|
||||
ztoolkit.getGlobal("clearInterval")(intervalId);
|
||||
clearInterval(intervalId);
|
||||
callback();
|
||||
} else if (Date.now() - start > timeout) {
|
||||
ztoolkit.getGlobal("clearInterval")(intervalId);
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
}, interval);
|
||||
}
|
||||
|
|
@ -22,12 +22,12 @@ export function waitUtilAsync(
|
|||
) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const start = Date.now();
|
||||
const intervalId = ztoolkit.getGlobal("setInterval")(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
if (condition()) {
|
||||
ztoolkit.getGlobal("clearInterval")(intervalId);
|
||||
clearInterval(intervalId);
|
||||
resolve();
|
||||
} else if (Date.now() - start > timeout) {
|
||||
ztoolkit.getGlobal("clearInterval")(intervalId);
|
||||
clearInterval(intervalId);
|
||||
reject();
|
||||
}
|
||||
}, interval);
|
||||
|
|
|
|||
|
|
@ -33,3 +33,22 @@ declare const addon: import("../src/addon").default;
|
|||
declare const __env__: "production" | "development";
|
||||
|
||||
declare class Localization {}
|
||||
|
||||
declare class XULElementBase extends HTMLElement {
|
||||
get content(): DocumentFragment;
|
||||
init(): void;
|
||||
destroy(): void;
|
||||
connectedCallback(): void;
|
||||
disconnectedCallback(): void;
|
||||
attributeChangedCallback(
|
||||
name: string,
|
||||
oldValue: string,
|
||||
newValue: string,
|
||||
): void;
|
||||
static get observedAttributes(): string[];
|
||||
}
|
||||
|
||||
declare class MozXULElement {
|
||||
static parseXULToFragment(xul: string): Fragment;
|
||||
static insertFTLIfNeeded(ftl: string): void;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue