refactor: template picker
Use picker window to replace the PromptManager from toolkit
This commit is contained in:
parent
afab600f53
commit
98fa74ed89
|
|
@ -0,0 +1,19 @@
|
|||
dialog {
|
||||
-moz-window-dragging: drag;
|
||||
max-height: 700px;
|
||||
}
|
||||
|
||||
.viewport-container {
|
||||
-moz-window-dragging: no-drag;
|
||||
}
|
||||
|
||||
.viewport {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#table-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background: var(--material-background);
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- prettier-ignore -->
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<!-- prettier-ignore -->
|
||||
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
|
||||
<!-- prettier-ignore -->
|
||||
<?xml-stylesheet href="chrome://zotero-platform/content/zotero.css" type="text/css"?>
|
||||
<!-- prettier-ignore -->
|
||||
<?xml-stylesheet href="chrome://__addonRef__/content/styles/templatePicker.css" type="text/css"?>
|
||||
<!-- prettier-ignore -->
|
||||
<!DOCTYPE window>
|
||||
<window
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
id="bn-note-picker"
|
||||
data-l10n-id="title"
|
||||
windowtype="__addonRef__-templatePicker"
|
||||
persist="screenX screenY width height sizemode"
|
||||
style="min-width: 20em"
|
||||
drawintitlebar-platforms="mac"
|
||||
>
|
||||
<xul:linkset>
|
||||
<html:link rel="localization" href="browser/menubar.ftl" />
|
||||
<html:link rel="localization" href="browser/browserSets.ftl" />
|
||||
<html:link rel="localization" href="toolkit/global/textActions.ftl" />
|
||||
<html:link rel="localization" href="zotero.ftl" />
|
||||
<html:link rel="localization" href="__addonRef__-templatePicker.ftl" />
|
||||
</xul:linkset>
|
||||
|
||||
<xul:commandset id="mainCommandSet">
|
||||
<xul:command id="cmd_close" oncommand="window.close();" />
|
||||
</xul:commandset>
|
||||
<xul:keyset id="mainKeyset">
|
||||
<xul:key
|
||||
id="key_close"
|
||||
data-l10n-id="close-shortcut"
|
||||
command="cmd_close"
|
||||
modifiers="accel"
|
||||
reserved="true"
|
||||
/>
|
||||
</xul:keyset>
|
||||
|
||||
<script src="chrome://zotero/content/include.js"></script>
|
||||
<script src="chrome://zotero/content/titlebar.js"></script>
|
||||
<script src="resource://zotero/require.js"></script>
|
||||
<script src="chrome://zotero/content/customElements.js"></script>
|
||||
<script src="chrome://__addonRef__/content/scripts/customElements.js"></script>
|
||||
<script src="chrome://__addonRef__/content/scripts/templatePicker.js"></script>
|
||||
|
||||
<dialog buttons="accept, cancel">
|
||||
<hbox class="viewport-container">
|
||||
<hbox id="list-container" class="viewport list-viewport">
|
||||
<html:div id="table-container"></html:div>
|
||||
</hbox>
|
||||
</hbox>
|
||||
</dialog>
|
||||
</window>
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
"unist-util-visit": "^5.0.0",
|
||||
"unist-util-visit-parents": "^6.0.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"zotero-plugin-toolkit": "^4.0.4"
|
||||
"zotero-plugin-toolkit": "^4.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||
|
|
@ -13588,14 +13588,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/zotero-plugin-toolkit": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/zotero-plugin-toolkit/-/zotero-plugin-toolkit-4.0.4.tgz",
|
||||
"integrity": "sha512-FjuyVt6q5uPmQiYCkT9LjvAMpDBAvPfVGsYAhFNN6tTJbiE9YsHIl2XZIfinEAIVAqYd+YPglXaK1pw/TUNuFQ==",
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/zotero-plugin-toolkit/-/zotero-plugin-toolkit-4.0.6.tgz",
|
||||
"integrity": "sha512-juxIrSrUYTxk+efQJAH7OpfQHSboErMd0Ygu2eZs/xKA1177XlCYhe0sdxlTxI8Y/4UGtRwLicThUddaOfArMQ==",
|
||||
"dependencies": {
|
||||
"zotero-types": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/zotero-types": {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
"unist-util-visit": "^5.0.0",
|
||||
"unist-util-visit-parents": "^6.0.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"zotero-plugin-toolkit": "^4.0.4"
|
||||
"zotero-plugin-toolkit": "^4.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { Prompt, PromptManager } from "zotero-plugin-toolkit";
|
||||
import { VirtualizedTableHelper } from "zotero-plugin-toolkit";
|
||||
import { LargePrefHelper } from "zotero-plugin-toolkit";
|
||||
|
||||
|
|
@ -72,7 +71,6 @@ class Addon {
|
|||
worker?: Worker;
|
||||
};
|
||||
imageCache: Record<number, string>;
|
||||
readonly prompt?: Prompt;
|
||||
hint: {
|
||||
silent: boolean;
|
||||
};
|
||||
|
|
@ -120,9 +118,6 @@ class Addon {
|
|||
},
|
||||
relation: {},
|
||||
imageCache: {},
|
||||
get prompt() {
|
||||
return new PromptManager().prompt;
|
||||
},
|
||||
hint: {
|
||||
silent: false,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ import {
|
|||
updateNoteLinkRelation,
|
||||
} from "./utils/relation";
|
||||
import { getWorkspaceByTabID, getWorkspaceByUID } from "./utils/workspace";
|
||||
import { getString } from "./utils/locale";
|
||||
|
||||
const workspace = {
|
||||
getWorkspaceByTabID,
|
||||
|
|
@ -178,6 +179,10 @@ const relation = {
|
|||
getAnnotationByLinkTarget,
|
||||
};
|
||||
|
||||
const utils = {
|
||||
getString,
|
||||
};
|
||||
|
||||
export default {
|
||||
workspace,
|
||||
sync,
|
||||
|
|
@ -188,4 +193,5 @@ export default {
|
|||
editor,
|
||||
note,
|
||||
relation,
|
||||
utils,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
import { VirtualizedTableHelper } from "zotero-plugin-toolkit";
|
||||
import { config } from "../../package.json";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (ev) => {
|
||||
init();
|
||||
});
|
||||
|
||||
document.addEventListener("dialogaccept", () => accept());
|
||||
|
||||
const args = window.arguments[0] as any;
|
||||
const templateData = args.templates;
|
||||
const multiSelect = args.multiSelect;
|
||||
let tableHelper: VirtualizedTableHelper;
|
||||
|
||||
function init() {
|
||||
args._initPromise.resolve();
|
||||
initTable();
|
||||
}
|
||||
|
||||
function accept() {
|
||||
const selected = tableHelper.treeInstance.selection.selected;
|
||||
args.selected = Array.from(selected).map(
|
||||
(index: number) => templateData[index],
|
||||
);
|
||||
}
|
||||
|
||||
const getString = (Zotero[config.addonRef] as typeof addon).api.utils.getString;
|
||||
|
||||
function initTable() {
|
||||
tableHelper = new VirtualizedTableHelper(window)
|
||||
.setContainerId("table-container")
|
||||
.setProp({
|
||||
id: "templates-table",
|
||||
// Do not use setLocale, as it modifies the Zotero.Intl.strings
|
||||
// Set locales directly to columns
|
||||
columns: [
|
||||
{
|
||||
dataKey: "type",
|
||||
label: "templateEditor-templateType",
|
||||
width: 60,
|
||||
fixedWidth: true,
|
||||
},
|
||||
{
|
||||
dataKey: "name",
|
||||
label: "templateEditor-templateName",
|
||||
fixedWidth: false,
|
||||
},
|
||||
].map((column) =>
|
||||
Object.assign(column, {
|
||||
label: getString(column.label),
|
||||
}),
|
||||
),
|
||||
showHeader: true,
|
||||
multiSelect: multiSelect,
|
||||
staticColumns: true,
|
||||
disableFontSizeScaling: true,
|
||||
})
|
||||
.setProp("getRowCount", () => templateData.length)
|
||||
.setProp("getRowData", getRowData)
|
||||
.setProp("getRowString", (index) => templateData[index] || "")
|
||||
.setProp("renderItem", (index, selection, oldElem, columns) => {
|
||||
let div;
|
||||
if (oldElem) {
|
||||
div = oldElem;
|
||||
div.innerHTML = "";
|
||||
} else {
|
||||
div = document.createElement("div");
|
||||
div.className = "row";
|
||||
}
|
||||
|
||||
div.classList.toggle("selected", selection.isSelected(index));
|
||||
div.classList.toggle("focused", selection.focused == index);
|
||||
const rowData = getRowData(index);
|
||||
|
||||
for (const column of columns) {
|
||||
const span = document.createElement("span");
|
||||
// @ts-ignore
|
||||
span.className = `cell ${column?.className}`;
|
||||
const cellData = rowData[column.dataKey as keyof typeof rowData];
|
||||
span.textContent = cellData;
|
||||
if (column.dataKey === "type") {
|
||||
span.style.backgroundColor = getRowLabelColor(cellData);
|
||||
span.style.borderRadius = "4px";
|
||||
span.style.paddingInline = "4px";
|
||||
span.style.marginInline = "2px -2px";
|
||||
span.style.textAlign = "center";
|
||||
span.textContent = getString(
|
||||
"templateEditor-templateDisplayType",
|
||||
cellData,
|
||||
);
|
||||
}
|
||||
div.append(span);
|
||||
}
|
||||
return div;
|
||||
})
|
||||
.render();
|
||||
}
|
||||
|
||||
function getRowData(index: number) {
|
||||
const rowData = templateData[index];
|
||||
if (!rowData) {
|
||||
return {
|
||||
name: "",
|
||||
type: "unknown",
|
||||
};
|
||||
}
|
||||
let templateType = "unknown";
|
||||
let templateDisplayName = rowData;
|
||||
if (rowData.toLowerCase().startsWith("[item]")) {
|
||||
templateType = "item";
|
||||
templateDisplayName = rowData.slice(6);
|
||||
} else if (rowData.toLowerCase().startsWith("[text]")) {
|
||||
templateType = "text";
|
||||
templateDisplayName = rowData.slice(6);
|
||||
}
|
||||
return {
|
||||
name: templateDisplayName,
|
||||
type: templateType,
|
||||
};
|
||||
}
|
||||
|
||||
function getRowLabelColor(type: string) {
|
||||
switch (type) {
|
||||
case "system":
|
||||
return "var(--accent-yellow)";
|
||||
case "item":
|
||||
return "var(--accent-green)";
|
||||
case "text":
|
||||
return "var(--accent-azure)";
|
||||
default:
|
||||
return "var(--accent-red)";
|
||||
}
|
||||
}
|
||||
|
|
@ -23,10 +23,7 @@ import {
|
|||
syncAnnotationNoteTags,
|
||||
} from "./modules/annotationNote";
|
||||
import { setSyncing, callSyncing } from "./modules/sync/hooks";
|
||||
import {
|
||||
showTemplatePicker,
|
||||
updateTemplatePicker,
|
||||
} from "./modules/template/picker";
|
||||
import { showTemplatePicker } from "./modules/template/picker";
|
||||
import { showImageViewer } from "./modules/imageViewer";
|
||||
import { showExportNoteOptions } from "./modules/export/exportWindow";
|
||||
import { showSyncDiff } from "./modules/sync/diffWindow";
|
||||
|
|
@ -241,8 +238,6 @@ const onSyncing = callSyncing;
|
|||
|
||||
const onShowTemplatePicker = showTemplatePicker;
|
||||
|
||||
const onUpdateTemplatePicker = updateTemplatePicker;
|
||||
|
||||
const onImportTemplateFromClipboard = importTemplateFromClipboard;
|
||||
|
||||
const onRefreshTemplatesInNote = refreshTemplatesInNote;
|
||||
|
|
@ -280,7 +275,6 @@ export default {
|
|||
onInitWorkspace,
|
||||
onSyncing,
|
||||
onShowTemplatePicker,
|
||||
onUpdateTemplatePicker,
|
||||
onImportTemplateFromClipboard,
|
||||
onRefreshTemplatesInNote,
|
||||
onShowImageViewer,
|
||||
|
|
|
|||
|
|
@ -34,10 +34,9 @@ function initTemplates() {
|
|||
const templateKeys = getTemplateKeys();
|
||||
for (const defaultTemplate of addon.api.template.DEFAULT_TEMPLATES) {
|
||||
if (!templateKeys.includes(defaultTemplate.name)) {
|
||||
setTemplate(defaultTemplate, false);
|
||||
setTemplate(defaultTemplate);
|
||||
}
|
||||
}
|
||||
addon.hooks.onUpdateTemplatePicker();
|
||||
}
|
||||
|
||||
function getTemplateKeys(): string[] {
|
||||
|
|
@ -52,27 +51,15 @@ function getTemplateText(keyName: string): string {
|
|||
return addon.data.template.data?.getValue(keyName) || "";
|
||||
}
|
||||
|
||||
function setTemplate(
|
||||
template: NoteTemplate,
|
||||
updatePrompt: boolean = true,
|
||||
): void {
|
||||
function setTemplate(template: NoteTemplate): void {
|
||||
addon.data.template.data?.setValue(template.name, template.text);
|
||||
if (updatePrompt) {
|
||||
addon.hooks.onUpdateTemplatePicker();
|
||||
}
|
||||
}
|
||||
|
||||
function removeTemplate(
|
||||
keyName: string | undefined,
|
||||
updatePrompt: boolean = true,
|
||||
): void {
|
||||
function removeTemplate(keyName: string | undefined): void {
|
||||
if (!keyName) {
|
||||
return;
|
||||
}
|
||||
addon.data.template.data?.deleteKey(keyName);
|
||||
if (updatePrompt) {
|
||||
addon.hooks.onUpdateTemplatePicker();
|
||||
}
|
||||
}
|
||||
|
||||
function importTemplateFromClipboard(text?: string) {
|
||||
|
|
|
|||
|
|
@ -1,78 +1,57 @@
|
|||
import { Prompt } from "zotero-plugin-toolkit";
|
||||
import { addLineToNote } from "../../utils/note";
|
||||
import { getString } from "../../utils/locale";
|
||||
import { openTemplatePicker } from "../../utils/templatePicker";
|
||||
|
||||
export { updateTemplatePicker, showTemplatePicker };
|
||||
export { showTemplatePicker };
|
||||
|
||||
function showTemplatePicker(
|
||||
async function showTemplatePicker(
|
||||
mode: "insert",
|
||||
data?: { noteId?: number; lineIndex?: number },
|
||||
): void;
|
||||
function showTemplatePicker(
|
||||
): Promise<void>;
|
||||
async function showTemplatePicker(
|
||||
mode: "create",
|
||||
data?: {
|
||||
noteType?: "standalone" | "item";
|
||||
parentItemId?: number;
|
||||
topItemIds?: number[];
|
||||
},
|
||||
): void;
|
||||
function showTemplatePicker(mode: "export", data?: Record<string, never>): void;
|
||||
function showTemplatePicker(): void;
|
||||
function showTemplatePicker(
|
||||
): Promise<void>;
|
||||
async function showTemplatePicker(
|
||||
mode: "export",
|
||||
data?: Record<string, never>,
|
||||
): Promise<void>;
|
||||
async function showTemplatePicker(): Promise<void>;
|
||||
async function showTemplatePicker(
|
||||
mode: typeof addon.data.template.picker.mode = "insert",
|
||||
data: Record<string, any> = {},
|
||||
) {
|
||||
if (addon.data.prompt) {
|
||||
addon.data.template.picker.mode = mode;
|
||||
addon.data.template.picker.data = data;
|
||||
addon.data.prompt.promptNode.style.display = "flex";
|
||||
addon.data.prompt.showCommands(
|
||||
addon.data.prompt.commands.filter(
|
||||
(cmd) => cmd.label === "BNotes Template",
|
||||
),
|
||||
);
|
||||
addon.data.template.picker.mode = mode;
|
||||
addon.data.template.picker.data = data;
|
||||
const selected = await openTemplatePicker();
|
||||
if (!selected.length) {
|
||||
return;
|
||||
}
|
||||
const name = selected[0];
|
||||
await handleTemplateOperation(name);
|
||||
}
|
||||
|
||||
function updateTemplatePicker() {
|
||||
ztoolkit.Prompt.unregisterAll();
|
||||
const templateKeys = addon.api.template.getTemplateKeys();
|
||||
ztoolkit.Prompt.register(
|
||||
templateKeys
|
||||
.filter(
|
||||
(template) =>
|
||||
!addon.api.template.SYSTEM_TEMPLATE_NAMES.includes(template),
|
||||
)
|
||||
.map((template) => {
|
||||
return {
|
||||
name: `Template: ${template}`,
|
||||
label: "BNotes Template",
|
||||
callback: getTemplatePromptHandler(template),
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function getTemplatePromptHandler(name: string) {
|
||||
return async (prompt: Prompt) => {
|
||||
ztoolkit.log(prompt, name);
|
||||
prompt.promptNode.style.display = "none";
|
||||
// TODO: add preview when command is selected
|
||||
switch (addon.data.template.picker.mode) {
|
||||
case "create":
|
||||
await createTemplateNoteCallback(name);
|
||||
break;
|
||||
case "export":
|
||||
await exportTemplateCallback(name);
|
||||
break;
|
||||
case "insert":
|
||||
default:
|
||||
await insertTemplateCallback(name);
|
||||
break;
|
||||
}
|
||||
addon.data.template.picker.mode = "insert";
|
||||
addon.data.template.picker.data = {};
|
||||
};
|
||||
async function handleTemplateOperation(name: string) {
|
||||
ztoolkit.log(name);
|
||||
// TODO: add preview when command is selected
|
||||
switch (addon.data.template.picker.mode) {
|
||||
case "create":
|
||||
await createTemplateNoteCallback(name);
|
||||
break;
|
||||
case "export":
|
||||
await exportTemplateCallback(name);
|
||||
break;
|
||||
case "insert":
|
||||
default:
|
||||
await insertTemplateCallback(name);
|
||||
break;
|
||||
}
|
||||
addon.data.template.picker.mode = "insert";
|
||||
addon.data.template.picker.data = {};
|
||||
}
|
||||
|
||||
async function insertTemplateCallback(name: string) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import { config } from "../../package.json";
|
||||
|
||||
export async function openTemplatePicker(
|
||||
options: {
|
||||
multiSelect?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
const { multiSelect = false } = options;
|
||||
const templates = addon.api.template
|
||||
.getTemplateKeys()
|
||||
.filter(
|
||||
(template) =>
|
||||
!addon.api.template.SYSTEM_TEMPLATE_NAMES.includes(template),
|
||||
);
|
||||
const args = {
|
||||
templates,
|
||||
multiSelect,
|
||||
selected: [] as string[],
|
||||
_initPromise: Zotero.Promise.defer(),
|
||||
};
|
||||
Zotero.getMainWindow().openDialog(
|
||||
`chrome://${config.addonRef}/content/templatePicker.xhtml`,
|
||||
"_blank",
|
||||
"chrome,modal,centerscreen,resizable=yes",
|
||||
args,
|
||||
);
|
||||
await args._initPromise.promise;
|
||||
return args.selected;
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import {
|
||||
BasicTool,
|
||||
UITool,
|
||||
PromptManager,
|
||||
MenuManager,
|
||||
ClipboardHelper,
|
||||
FilePickerHelper,
|
||||
|
|
@ -43,7 +42,6 @@ function initZToolkit(_ztoolkit: ReturnType<typeof createZToolkit>) {
|
|||
|
||||
class MyToolkit extends BasicTool {
|
||||
UI: UITool;
|
||||
Prompt: PromptManager;
|
||||
Menu: MenuManager;
|
||||
Clipboard: typeof ClipboardHelper;
|
||||
FilePicker: typeof FilePickerHelper;
|
||||
|
|
@ -56,7 +54,6 @@ class MyToolkit extends BasicTool {
|
|||
constructor() {
|
||||
super();
|
||||
this.UI = new UITool(this);
|
||||
this.Prompt = new PromptManager(this);
|
||||
this.Menu = new MenuManager(this);
|
||||
this.Clipboard = ClipboardHelper;
|
||||
this.FilePicker = FilePickerHelper;
|
||||
|
|
|
|||
Loading…
Reference in New Issue