mirror of
https://github.com/zotero/zotero.git
synced 2026-10-03 02:21:49 +00:00
Update JSDoc for itemPaneManager and itemTreeManager
This commit is contained in:
parent
51dae17314
commit
8a76aac83f
4 changed files with 524 additions and 172 deletions
|
|
@ -29,109 +29,167 @@
|
|||
|
||||
|
||||
/**
|
||||
* @typedef SectionIcon
|
||||
* @type {object}
|
||||
* @property {string} icon - Icon URI
|
||||
* @property {string} [darkIcon] - Icon URI in dark mode. If not set, use `icon`
|
||||
* @typedef SectionL10n
|
||||
* @type {object}
|
||||
* @property {string} l10nID - data-l10n-id for localization of section header label
|
||||
* @property {string} [l10nArgs] - data-l10n-args for localization
|
||||
* @typedef SectionButton
|
||||
* @type {object}
|
||||
* @property {string} type - Button type, must be valid DOMString and without ","
|
||||
* @property {string} icon - Icon URI
|
||||
* @property {string} [darkIcon] - Icon URI in dark mode. If not set, use `icon`
|
||||
* @property {string} [l10nID] - data-l10n-id for localization of button tooltiptext
|
||||
* @property {(props: SectionEventHookArgs) => void} onClick - Button click callback
|
||||
* @typedef SectionBasicHookArgs
|
||||
* @type {object}
|
||||
* @property {string} paneID - Registered pane id
|
||||
* @property {Document} doc - Document of section
|
||||
* @property {HTMLDivElement} body - Section body
|
||||
* @typedef SectionUIHookArgs
|
||||
* @type {object}
|
||||
* @property {Zotero.Item} item - Current item
|
||||
* @property {string} tabType - Current tab type
|
||||
* @property {boolean} editable - Whether the section is in edit mode
|
||||
* @property {(l10nArgs: string) => void} setL10nArgs - Set l10n args for section header
|
||||
* @property {(l10nArgs: string) => void} setEnabled - Set pane enabled state
|
||||
* @property {(summary: string) => void} setSectionSummary - Set pane section summary,
|
||||
* the text shown in the section header when the section is collapsed.
|
||||
*
|
||||
* See the Abstract section as an example
|
||||
* @property {(buttonType: string, options: {disabled?: boolean; hidden?: boolean}) => void} setSectionButtonStatus - Set pane section button status
|
||||
* @typedef SectionHookArgs
|
||||
* @type {SectionBasicHookArgs & SectionUIHookArgs}
|
||||
* @typedef {SectionHookArgs & { refresh: () => Promise<void> }} SectionInitHookArgs
|
||||
* @namespace Zotero
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionIcon
|
||||
* @property {string} icon - Icon URI.
|
||||
* @property {string} [darkIcon] - Icon URI in dark mode. If not set, use `icon`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionL10n
|
||||
* @property {string} l10nID - data-l10n-id for localization of section header label.
|
||||
* @property {string} [l10nArgs] - data-l10n-args for localization.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionButton
|
||||
* @property {string} type - Button type, must be valid DOMString and without ",".
|
||||
* @property {string} icon - Icon URI.
|
||||
* @property {string} [darkIcon] - Icon URI in dark mode. If not set, use `icon`.
|
||||
* @property {string} [l10nID] - data-l10n-id for localization of button tooltiptext.
|
||||
* @property {SectionEventHook} onClick - Button click callback.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionBasicHookArgs
|
||||
* @property {string} paneID - Registered pane id.
|
||||
* @property {Document} doc - Document of section.
|
||||
* @property {HTMLDivElement} body - Section body.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionUIHookArgs
|
||||
* @property {Zotero.Item} item - Current item.
|
||||
* @property {string} tabType - Current tab type.
|
||||
* @property {boolean} editable - Whether the section is in edit mode.
|
||||
* @property {SetSectionL10nArgs} setL10nArgs - Set l10n args for section header.
|
||||
* @property {SetEnabled} setEnabled - Set pane enabled state.
|
||||
* @property {SetSectionSummary} setSectionSummary - Set pane section summary, shown in collapsed header.
|
||||
* @property {SetSectionButtonStatus} setSectionButtonStatus - Set pane section button status.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionHookArgs
|
||||
* @property {string} paneID - Registered pane id.
|
||||
* @property {Document} doc - Document of section.
|
||||
* @property {HTMLDivElement} body - Section body.
|
||||
* @property {Zotero.Item} item - Current item.
|
||||
* @property {string} tabType - Current tab type.
|
||||
* @property {boolean} editable - Whether the section is in edit mode.
|
||||
* @property {SetSectionL10nArgs} setL10nArgs - Set l10n args for section header.
|
||||
* @property {SetEnabled} setEnabled - Set pane enabled state.
|
||||
* @property {SetSectionSummary} setSectionSummary - Set pane section summary, shown in collapsed header.
|
||||
* @property {SetSectionButtonStatus} setSectionButtonStatus - Set pane section button status.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionInitHookArgs
|
||||
* @property {string} paneID - Registered pane id.
|
||||
* @property {Document} doc - Document of section.
|
||||
* @property {HTMLDivElement} body - Section body.
|
||||
* @property {Zotero.Item} item - Current item.
|
||||
* @property {string} tabType - Current tab type.
|
||||
* @property {boolean} editable - Whether the section is in edit mode.
|
||||
* @property {SetSectionL10nArgs} setL10nArgs - Set l10n args for section header.
|
||||
* @property {SetEnabled} setEnabled - Set pane enabled state.
|
||||
* @property {SetSectionSummary} setSectionSummary - Set pane section summary, shown in collapsed header.
|
||||
* @property {SetSectionButtonStatus} setSectionButtonStatus - Set pane section button status.
|
||||
* @property {SectionRefresh} refresh - Refresh the section.
|
||||
* A `refresh` is exposed to plugins to allows plugins to refresh the section when necessary,
|
||||
* e.g. item modify notifier callback. Note that calling `refresh` during initialization
|
||||
* have no effect.
|
||||
* @typedef {SectionHookArgs & { event: Event }} SectionEventHookArgs
|
||||
* @typedef ItemDetailsSectionOptions
|
||||
* @type {object}
|
||||
* @property {string} paneID - Unique pane ID
|
||||
* @property {string} pluginID - Set plugin ID to auto remove section when plugin is disabled/removed
|
||||
* @property {SectionL10n & SectionIcon} header - Header options. Icon should be 16*16 and `label` need to be localized
|
||||
* @property {SectionL10n & SectionIcon} sidenav - Sidenav options. Icon should be 20*20 and `tooltiptext` need to be localized
|
||||
* @property {string} [bodyXHTML] - Pane body's innerHTML, default to XUL namespace
|
||||
* @property {(props: SectionInitHookArgs) => void} [onInit]
|
||||
* Lifecycle hook called when section is initialized.
|
||||
* You can use destructuring assignment to get the props:
|
||||
* ```js
|
||||
* onInit({ paneID, doc, body, item, editable, tabType, setL10nArgs, setEnabled,
|
||||
* setSectionSummary, setSectionButtonStatus, refresh }) {
|
||||
* // Your code here
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Do:
|
||||
* 1. Initialize data if necessary
|
||||
* 2. Set up hooks, e.g. notifier callback
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* @property {(props: SectionBasicHookArgs) => void} [onDestroy]
|
||||
* Lifecycle hook called when section is destroyed
|
||||
*
|
||||
* Do:
|
||||
* 1. Remove data and release resource
|
||||
* 2. Remove hooks, e.g. notifier callback
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* @property {(props: SectionHookArgs) => boolean} [onItemChange]
|
||||
* Lifecycle hook called when section's item change received
|
||||
*
|
||||
* Do:
|
||||
* 1. Update data (no need to render or refresh);
|
||||
* 2. Update the section enabled state with `props.setEnabled`. For example, if the section
|
||||
* is only enabled in the readers, you can use:
|
||||
* ```js
|
||||
* onItemChange({ setEnabled }) {
|
||||
* setEnabled(newData.value === "reader");
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* @property {(props: SectionHookArgs) => void} onRender
|
||||
* Lifecycle hook called when section should do initial render. Cannot be async.
|
||||
*
|
||||
* Create elements and append them to `props.body`.
|
||||
*
|
||||
* If the rendering is slow, you should make the bottleneck async and move it to `onAsyncRender`.
|
||||
*
|
||||
* > Note that the rendering of section is fully controlled by Zotero to minimize resource usage.
|
||||
* > Only render UI things when you are told to.
|
||||
* @property {(props: SectionHookArgs) => void | Promise<void>} [onAsyncRender]
|
||||
* [Optional] Lifecycle hook called when section should do async render
|
||||
*
|
||||
* The best practice to time-consuming rendering with runtime decided section height is:
|
||||
* 1. Compute height and create a box in sync `onRender`;
|
||||
* 2. Render actual contents in async `onAsyncRender`.
|
||||
* @property {(props: SectionEventHookArgs) => void} [onToggle] - Called when section is toggled
|
||||
* @property {SectionButton[]} [sectionButtons] - Section button options
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SectionEventHookArgs
|
||||
* @property {string} paneID - Registered pane id.
|
||||
* @property {Document} doc - Document of section.
|
||||
* @property {HTMLDivElement} body - Section body.
|
||||
* @property {Zotero.Item} item - Current item.
|
||||
* @property {string} tabType - Current tab type.
|
||||
* @property {boolean} editable - Whether the section is in edit mode.
|
||||
* @property {SetSectionL10nArgs} setL10nArgs - Set l10n args for section header.
|
||||
* @property {SetEnabled} setEnabled - Set pane enabled state.
|
||||
* @property {SetSectionSummary} setSectionSummary - Set pane section summary, shown in collapsed header.
|
||||
* @property {SetSectionButtonStatus} setSectionButtonStatus - Set pane section button status.
|
||||
* @property {Event} event - Event object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionInitHook
|
||||
* @param {SectionInitHookArgs} props - Props provided during section initialization.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionBasicHook
|
||||
* @param {SectionBasicHookArgs} props - Basic hook arguments.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionItemChangeHook
|
||||
* @param {SectionHookArgs} props - Hook arguments for item changes.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionRenderHook
|
||||
* @param {SectionHookArgs} props - Hook arguments for rendering.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionAsyncRenderHook
|
||||
* @param {SectionHookArgs} props - Hook arguments for asynchronous rendering.
|
||||
* @returns {void | Promise<void>}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionToggleHook
|
||||
* @param {SectionEventHookArgs} props - Event hook arguments.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionEventHook
|
||||
* @param {SectionEventHookArgs} props - Event hook arguments.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SetSectionL10nArgs
|
||||
* @param {string} l10nArgs - Localization arguments.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SetEnabled
|
||||
* @param {boolean} enabled - Enabled state.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SetSectionSummary
|
||||
* @param {string} summary - The summary for the section header.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SetSectionButtonStatus
|
||||
* @param {string} buttonType - The button type.
|
||||
* @param {Object} options - Options for the button status.
|
||||
* @param {boolean} [options.disabled] - Whether the button is disabled.
|
||||
* @param {boolean} [options.hidden] - Whether the button is hidden.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback SectionRefresh
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -250,6 +308,73 @@
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} InfoRowL10n
|
||||
* @property {string} l10nID - data-l10n-id for localization of row label.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {"start" | "afterCreators" | "end"} InfoRowPosition - Position of the row.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} InfoRowGetDataHookArgs
|
||||
* @property {string} rowID - Row ID.
|
||||
* @property {Zotero.Item} item - Current item.
|
||||
* @property {string} tabType - Current tab type.
|
||||
* @property {boolean} editable - Whether the row is in edit mode.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} InfoRowSetDataHookArgs
|
||||
* @property {string} rowID - Row ID.
|
||||
* @property {Zotero.Item} item - Current item.
|
||||
* @property {string} tabType - Current tab type.
|
||||
* @property {string} editable - Whether the row is in edit mode.
|
||||
* @property {string} value - New value.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} InfoRowItemChangeHookArgs
|
||||
* @property {string} rowID - Row ID.
|
||||
* @property {Zotero.Item} item - Current item.
|
||||
* @property {string} tabType - Current tab type.
|
||||
* @property {boolean} editable - Whether the row is in edit mode.
|
||||
* @property {SetInfoRowEnabled} setEnabled - Set row enabled state.
|
||||
* @property {SetInfoRowEditable} setEditable - Set row editable state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {function} InfoRowGetDataHook
|
||||
* @param {InfoRowGetDataHookArgs} props - Hook arguments for getting data.
|
||||
* @returns {string} - Row data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {function} InfoRowSetDataHook
|
||||
* @param {InfoRowSetDataHookArgs} props - Hook arguments for setting data.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {function} InfoRowItemChangeHook
|
||||
* @param {InfoRowItemChangeHookArgs} props - Hook arguments for item changes.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {function} SetInfoRowEnabled
|
||||
* @param {boolean} enabled - Enabled state.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {function} SetInfoRowEditable
|
||||
* @param {boolean} editable - Editable state.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
|
||||
class ItemPaneInfoRowManagerInternal extends PluginAPIBase {
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -315,22 +440,127 @@
|
|||
}
|
||||
|
||||
|
||||
class ItemPaneManager {
|
||||
_sectionManager = new ItemPaneSectionManagerInternal();
|
||||
/**
|
||||
* Manages item pane APIs.
|
||||
*
|
||||
* @memberof Zotero
|
||||
*/
|
||||
Zotero.ItemPaneManager = {
|
||||
_sectionManager: new ItemPaneSectionManagerInternal(),
|
||||
|
||||
_infoRowManager = new ItemPaneInfoRowManagerInternal();
|
||||
_infoRowManager: new ItemPaneInfoRowManagerInternal(),
|
||||
|
||||
/**
|
||||
* Register a custom item pane section.
|
||||
* @param {Object} options - Section options.
|
||||
* @param {string} options.paneID - Unique pane ID.
|
||||
* @param {string} options.pluginID - Set plugin ID to auto-remove section when the plugin is disabled or removed.
|
||||
* @param {SectionL10n | SectionIcon} options.header - Header options. Icon should be 16*16 and `label` need to be localized.
|
||||
* @param {SectionL10n | SectionIcon} options.sidenav - Sidenav options. Icon should be 20*20 and `tooltiptext` need to be localized.
|
||||
* @param {string} [options.bodyXHTML] - Pane body's innerHTML, defaults to XUL namespace.
|
||||
* @param {SectionInitHook} [options.onInit] - Lifecycle hook called when section is initialized.
|
||||
*
|
||||
* Do:
|
||||
* 1. Initialize data if necessary
|
||||
* 2. Set up hooks, e.g. notifier callback
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* @param {SectionBasicHook} [options.onDestroy] - Lifecycle hook called when section is destroyed.
|
||||
*
|
||||
* Do:
|
||||
* 1. Remove data and release resource
|
||||
* 2. Remove hooks, e.g. notifier callback
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* @param {SectionItemChangeHook} [options.onItemChange] - Lifecycle hook called when the section's target item is changed.
|
||||
*
|
||||
* Do:
|
||||
* 1. Update data (no need to render or refresh);
|
||||
* 2. Update the section enabled state with `props.setEnabled`.
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* @param {SectionRenderHook} options.onRender - Lifecycle hook called for initial render.
|
||||
*
|
||||
* Cannot be async.
|
||||
*
|
||||
* Create elements and append them to `props.body`.
|
||||
*
|
||||
* If the rendering is slow, you should make the bottleneck async and move it to `onAsyncRender`.
|
||||
* @param {SectionAsyncRenderHook} [options.onAsyncRender] - Lifecycle hook for asynchronous rendering.
|
||||
*
|
||||
* The best practice to time-consuming rendering with runtime decided section height is:
|
||||
* 1. Compute height and create a box in sync `onRender`;
|
||||
* 2. Render actual contents in async `onAsyncRender`.
|
||||
* @param {SectionToggleHook} [options.onToggle] - Called when section is toggled.
|
||||
* @param {SectionButton[]} [options.sectionButtons] - Section button options.
|
||||
* @returns {string | false} - The registered pane ID or false if failed.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* Zotero.ItemPaneManager.registerSection({
|
||||
* paneID: 'my-plugin-pane',
|
||||
* pluginID: 'my-plugin@my-namespace.com',
|
||||
* header: {
|
||||
* l10nID: 'my-plugin-pane-header', // Must inject the corresponding `ftl` file
|
||||
* icon: 'chrome://my-plugin/content/icon16.svg',
|
||||
* },
|
||||
* sidenav: {
|
||||
* l10nID: 'my-plugin-pane-sidenav', // Must inject the corresponding `ftl` file
|
||||
* icon: 'chrome://my-plugin/content/icon20.svg',
|
||||
* },
|
||||
* onInit: ({paneID, doc, body}) => {
|
||||
* // Initialize data
|
||||
* Zotero.debug('Section initialized');
|
||||
* },
|
||||
* onDestroy: ({paneID, doc, body}) => {
|
||||
* // Release resource
|
||||
* Zotero.debug('Section destroyed');
|
||||
* },
|
||||
* onItemChange: ({paneID, doc, body, item, tabType, editable, setEnabled}) => {
|
||||
* // In this example, the section is enabled only for regular items
|
||||
* setEnabled(item.isRegularItem());
|
||||
* },
|
||||
* onRender: ({doc, body, item}) => {
|
||||
* // Create elements and append them to `body`
|
||||
* const div = doc.createElement('div');
|
||||
* div.classList.add('my-plugin-section');
|
||||
* div.textContent = item.getField('title');
|
||||
* body.appendChild(div);
|
||||
* },
|
||||
* onAsyncRender: async ({body}) => {
|
||||
* // Put time-consuming rendering here
|
||||
* await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
* body.querySelector('.my-plugin-section')?.style.setProperty('color', 'red');
|
||||
* },
|
||||
* onToggle: ({paneID, doc, body, item, tabType, editable, setEnabled}) => {
|
||||
* // Handle section toggle
|
||||
* Zotero.debug('Section toggled');
|
||||
* },
|
||||
* sectionButtons: [
|
||||
* // Section button will appear in the header
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
registerSection(options) {
|
||||
return this._sectionManager.register(options);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregister a custom item pane section.
|
||||
* @param {string} paneID - Pane ID to unregister. This is the value returned by `registerSection`.
|
||||
* @returns {boolean} - True if the section is successfully unregistered, false if the paneID is not found.
|
||||
*/
|
||||
unregisterSection(paneID) {
|
||||
return this._sectionManager.unregister(paneID);
|
||||
}
|
||||
},
|
||||
|
||||
get customSectionData() {
|
||||
return this._sectionManager.data;
|
||||
}
|
||||
},
|
||||
|
||||
isSectionOrderable(paneID) {
|
||||
let option = this._sectionManager._optionsCache[paneID];
|
||||
|
|
@ -338,23 +568,88 @@
|
|||
return false;
|
||||
}
|
||||
return option.sidenav.orderable ?? true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Register a custom item pane info section row.
|
||||
* @param {Object} options - Row options.
|
||||
* @param {string} options.rowID - Unique row ID.
|
||||
* @param {string} options.pluginID - Set plugin ID to auto-remove row when the plugin is disabled or removed.
|
||||
* @param {InfoRowL10n} options.label - Label options. `label` need to be localized.
|
||||
* @param {InfoRowPosition} [options.position] - Position of the row.
|
||||
* @param {boolean} [options.multiline] - Whether the row is multiline.
|
||||
* @param {boolean} [options.nowrap] - Whether the row is nowrap.
|
||||
* @param {boolean} [options.editable] - Whether the row is editable.
|
||||
* @param {InfoRowGetDataHook} options.onGetData - Lifecycle hook for getting row data for rendering.
|
||||
*
|
||||
* This is called when the row is rendered or refreshed.
|
||||
* @param {InfoRowSetDataHook} [options.onSetData] - Lifecycle hook for saving row data changes after editing.
|
||||
*
|
||||
* Do:
|
||||
* 1. Save the new value of the row
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* 2. Change the value in this hook
|
||||
* @param {InfoRowItemChangeHook} [options.onItemChange] - Lifecycle hook for target item changes.
|
||||
*
|
||||
* Do:
|
||||
* 1. Update the row attribute, e.g. enabled, editable
|
||||
*
|
||||
* Don't:
|
||||
* 1. Render/refresh UI
|
||||
* @returns {string | false} - The registered row ID or false if failed.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* Zotero.ItemPaneManager.registerInfoRow({
|
||||
* rowID: 'my-plugin-row',
|
||||
* pluginID: 'my-plugin@my-namespace.com',
|
||||
* label: {
|
||||
* l10nID: 'my-plugin-row-label', // Must inject the corresponding `ftl` file
|
||||
* },
|
||||
* position: 'afterCreators',
|
||||
* multiline: true,
|
||||
* nowrap: false,
|
||||
* editable: true,
|
||||
* onGetData: ({rowID, item, tabType, editable}) => {
|
||||
* return item.getField('title').toUpperCase();
|
||||
* },
|
||||
* onSetData: ({rowID, item, tabType, editable, value}) => {
|
||||
* Zotero.debug('Info row data changed:', value);
|
||||
* },
|
||||
* onItemChange: ({rowID, item, tabType, editable, setEnabled, setEditable}) => {
|
||||
* // In this example, the row is enabled only for library tab
|
||||
* setEnabled(tabType === 'library');
|
||||
* },
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
registerInfoRow(options) {
|
||||
return this._infoRowManager.register(options);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregister a custom item pane info section row.
|
||||
* @param {string} rowID - Row ID to unregister. This is the value returned by `registerInfoRow`.
|
||||
* @returns {boolean} - True if the row is successfully unregistered, false if the rowID is not found.
|
||||
*/
|
||||
unregisterInfoRow(rowID) {
|
||||
return this._infoRowManager.unregister(rowID);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh a custom item pane info section row.
|
||||
* @param {string} rowID - Row ID to refresh. This is the value returned by `registerInfoRow`.
|
||||
* @returns {void}
|
||||
*/
|
||||
refreshInfoRow(rowID) {
|
||||
return this._infoRowManager.refresh(rowID);
|
||||
}
|
||||
},
|
||||
|
||||
get customInfoRowData() {
|
||||
return this._infoRowManager.data;
|
||||
}
|
||||
},
|
||||
|
||||
getInfoRowHook(rowID, type) {
|
||||
let option = this._infoRowManager._optionsCache[rowID];
|
||||
|
|
@ -362,9 +657,6 @@
|
|||
return undefined;
|
||||
}
|
||||
return option[type];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zotero.ItemPaneManager = new ItemPaneManager();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,12 +32,25 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
|
||||
|
||||
/**
|
||||
* @typedef {import("../../itemTreeColumns.jsx").ItemTreeColumnOptions} ItemTreeColumnOptions
|
||||
* @typedef {"dataKey" | "label" | "pluginID"} RequiredCustomColumnOptionKeys
|
||||
* @typedef {Required<Pick<ItemTreeColumnOptions, RequiredCustomColumnOptionKeys>>} RequiredCustomColumnOptionsPartial
|
||||
* @typedef {Omit<ItemTreeColumnOptions, RequiredCustomColumnOptionKeys>} CustomColumnOptionsPartial
|
||||
* @typedef {RequiredCustomColumnOptionsPartial & CustomColumnOptionsPartial} ItemTreeCustomColumnOptions
|
||||
* @typedef {Partial<Omit<ItemTreeCustomColumnOptions, "enabledTreeIDs">>} ItemTreeCustomColumnFilters
|
||||
* @namespace Zotero
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {function} ItemTreeColumnDataProvider
|
||||
* @param {Zotero.Item} item - The item to get data from
|
||||
* @param {string} dataKey - The dataKey of the column
|
||||
* @returns {string} - The data to display in the column
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {function} ItemTreeColumnRenderCell
|
||||
* @param {number} index - The index of the row
|
||||
* @param {string} data - The data to display in the column
|
||||
* @param {ItemTreeColumnOptions | {className: string}} column - The column options
|
||||
* @param {boolean} isFirstColumn - true if this is the first column
|
||||
* @param {Document} doc - The document of the item tree
|
||||
* @returns {HTMLElement} - The HTML to display in the cell
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -165,25 +178,53 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
}
|
||||
|
||||
|
||||
class ItemTreeManager {
|
||||
_columnManager = new ItemTreeColumnManagerInternal();
|
||||
/**
|
||||
* Manages item tree APIs.
|
||||
*
|
||||
* @memberof Zotero
|
||||
*/
|
||||
Zotero.ItemTreeManager = {
|
||||
_columnManager: new ItemTreeColumnManagerInternal(),
|
||||
|
||||
/**
|
||||
* Register a custom column, must be valid with a unique dataKey.
|
||||
*
|
||||
* Note that the `dataKey` you use here may be different from the one returned by the function.
|
||||
* This is because the `dataKey` is prefixed with the `pluginID` to avoid conflicts after the column is registered.
|
||||
* @param {ItemTreeCustomColumnOptions} option - An option or array of options to register
|
||||
* @param {Object} option - An option or array of options to register
|
||||
* @param {string} option.dataKey - Required, see use in ItemTree#_getRowData()
|
||||
* @param {string} option.label - The column label. Either a string or the id to an i18n string.
|
||||
* @param {string} option.pluginID - Set plugin ID to auto remove column when plugin is removed.
|
||||
* @param {string[]} [option.enabledTreeIDs=[]] - Which tree ids the column should be enabled in. If undefined, enabled in main tree. If ["*"], enabled in all trees.
|
||||
* @param {string[]} [option.defaultIn] - Will be deprecated. Types of trees the column is default in. Can be [default, feed];
|
||||
* @param {string[]} [option.disabledIn] - Will be deprecated. Types of trees where the column is not available
|
||||
* @param {boolean} [option.sortReverse=false] - Default: false. Set to true to reverse the sort order
|
||||
* @param {number} [option.flex=1] - Default: 1. When the column is added to the tree how much space it should occupy as a flex ratio
|
||||
* @param {string} [option.width] - A column width instead of flex ratio. See above.
|
||||
* @param {boolean} [option.fixedWidth] - Default: false. Set to true to disable column resizing
|
||||
* @param {boolean} [option.staticWidth] - Default: false. Set to true to prevent columns from changing width when the width of the tree increases or decreases
|
||||
* @param {boolean} [option.noPadding] - Set to true for columns with padding disabled in stylesheet
|
||||
* @param {number} [option.minWidth] - Override the default [20px] column min-width for resizing
|
||||
* @param {React.Component} [option.iconLabel] - Set an Icon label instead of a text-based one
|
||||
* @param {string} [option.iconPath] - Set an Icon path, overrides {iconLabel}
|
||||
* @param {string | React.Component} [option.htmlLabel] - Set an HTML label, overrides {iconLabel} and {label}. Can be a HTML string or a React component.
|
||||
* @param {boolean} [option.showInColumnPicker=true] - Default: true. Set to true to show in column picker.
|
||||
* @param {boolean} [option.columnPickerSubMenu=false] - Default: false. Set to true to display the column in "More Columns" submenu of column picker.
|
||||
* @param {boolean} [option.primary] - Should only be one column at the time. Title is the primary column
|
||||
* @param {ItemTreeColumnDataProvider} [option.dataProvider] - Custom data provider that is called when rendering cells
|
||||
* @param {ItemTreeColumnRenderCell} [option.renderCell] - The cell renderer function
|
||||
* @param {string[]} [option.zoteroPersist] - Which column properties should be persisted between zotero close
|
||||
* @returns {string | false} - The dataKey of the added column or false if no column is added
|
||||
*
|
||||
* @example
|
||||
* A minimal custom column:
|
||||
* ```js
|
||||
* ```javascript
|
||||
* // You can unregister the column later with Zotero.ItemTreeManager.unregisterColumn(registeredDataKey);
|
||||
* const registeredDataKey = Zotero.ItemTreeManager.registerColumn(
|
||||
* {
|
||||
* dataKey: 'rtitle',
|
||||
* label: 'Reversed Title',
|
||||
* pluginID: 'make-it-red@zotero.org', // Replace with your plugin ID
|
||||
* pluginID: 'my-plugin@my-namespace.com', // Replace with your plugin ID
|
||||
* dataProvider: (item, dataKey) => {
|
||||
* return item.getField('title').split('').reverse().join('');
|
||||
* },
|
||||
|
|
@ -192,7 +233,7 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
* @example
|
||||
* A custom column using all available options.
|
||||
* Note that the column will only be shown in the main item tree.
|
||||
* ```js
|
||||
* ```javascript
|
||||
* const registeredDataKey = Zotero.ItemTreeManager.registerColumn(
|
||||
* {
|
||||
* dataKey: 'rtitle',
|
||||
|
|
@ -208,7 +249,7 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
* htmlLabel: '<span style="color: red;">reversed title</span>', // use HTML in the label. This will override the label and iconPath property
|
||||
* showInColumnPicker: true, // show in the column picker
|
||||
* columnPickerSubMenu: true, // show in the column picker submenu
|
||||
* pluginID: 'make-it-red@zotero.org', // plugin ID, which will be used to unregister the column when the plugin is unloaded
|
||||
* pluginID: 'my-plugin@my-namespace.com', // plugin ID
|
||||
* dataProvider: (item, dataKey) => {
|
||||
* // item: the current item in the row
|
||||
* // dataKey: the dataKey of the column
|
||||
|
|
@ -234,7 +275,7 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
*/
|
||||
registerColumn(option) {
|
||||
return this._columnManager.register(option);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated Use `registerColumn` instead.
|
||||
|
|
@ -244,21 +285,16 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
options = [options];
|
||||
}
|
||||
return options.map(option => this.registerColumn(option));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregister a custom column.
|
||||
* @param {string} dataKey - The dataKey of the column to unregister
|
||||
* @returns {boolean} true if the column is unregistered
|
||||
* @example
|
||||
* The `registeredDataKey` is returned by the `registerColumn` function.
|
||||
* ```js
|
||||
* Zotero.ItemTreeManager.unregisterColumn(registeredDataKey);
|
||||
* ```
|
||||
* @returns {boolean} - true if the column was unregistered, false if the column was not found
|
||||
*/
|
||||
unregisterColumn(dataKey) {
|
||||
return this._columnManager.unregister(dataKey);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated Use `unregisterColumn` instead.
|
||||
|
|
@ -268,18 +304,20 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
dataKeys = [dataKeys];
|
||||
}
|
||||
return dataKeys.map(dataKey => this.unregisterColumn(dataKey));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh the columns in the item tree
|
||||
* @returns {void}
|
||||
*/
|
||||
refreshColumns() {
|
||||
this._columnManager.refresh();
|
||||
},
|
||||
|
||||
get customColumnUpdateID() {
|
||||
return this._columnManager.updateID;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get column(s) that matches the properties of option
|
||||
* @param {string | string[]} [filterTreeIDs] - The tree IDs to match
|
||||
* @param {ItemTreeCustomColumnFilters} [options] - An option or array of options to match
|
||||
* @returns {ItemTreeCustomColumnOptions[]}
|
||||
*/
|
||||
getCustomColumns(filterTreeIDs, options) {
|
||||
const allColumns = this._columnManager.options;
|
||||
if (!filterTreeIDs && !options) {
|
||||
|
|
@ -312,36 +350,18 @@ import { COLUMNS } from 'zotero/itemTreeColumns';
|
|||
});
|
||||
}
|
||||
return filteredColumns;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a column is registered as a custom column
|
||||
* @param {string} dataKey - The dataKey of the column
|
||||
* @returns {boolean} true if the column is registered as a custom column
|
||||
*/
|
||||
isCustomColumn(dataKey) {
|
||||
return !!this._columnManager._optionsCache[dataKey];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A centralized data source for custom columns. This is used by the ItemTreeRow to get data.
|
||||
* @param {Zotero.Item} item - The item to get data from
|
||||
* @param {string} dataKey - The dataKey of the column
|
||||
* @returns {string}
|
||||
*/
|
||||
getCustomCellData(item, dataKey) {
|
||||
const option = this._columnManager._optionsCache[dataKey];
|
||||
if (option && option.dataProvider) {
|
||||
return option.dataProvider(item, dataKey);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
refreshColumns() {
|
||||
this._columnManager.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zotero.ItemTreeManager = new ItemTreeManager();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,19 @@ Zotero.PreferencePanes = {
|
|||
* relative to the plugin's root
|
||||
* @param {String} [options.helpURL] If provided, a help button will be displayed under the pane
|
||||
* and the provided URL will open when it is clicked
|
||||
* @return {Promise<String>} Resolves to the ID of the pane if successfully added
|
||||
* @return {Promise<string>} Resolves to the ID of the pane if successfully added
|
||||
*
|
||||
* @example
|
||||
* Register a pane with a script and stylesheet:
|
||||
* ```javascript
|
||||
* Zotero.PreferencePanes.register({
|
||||
* pluginID: 'my-plugin@my-namespace.com',
|
||||
* src: rootURI + 'my-pane.xhtml',
|
||||
* id: 'my-plugin-pane',
|
||||
* scripts: [rootURI + 'my-pane.js'],
|
||||
* stylesheets: [rootURI + 'my-pane.css']
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
register: async function (options) {
|
||||
if (!options.pluginID || !options.src) {
|
||||
|
|
|
|||
|
|
@ -2087,6 +2087,32 @@ class Reader {
|
|||
}
|
||||
|
||||
/**
|
||||
* @typedef {"renderTextSelectionPopup" | "renderSidebarAnnotationHeader" | "renderToolbar" |
|
||||
* "createColorContextMenu" | "createViewContextMenu" | "createAnnotationContextMenu" |
|
||||
* "createThumbnailContextMenu" | "createSelectorContextMenu"} ReaderEventType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ReaderEvent
|
||||
* @property {ReaderInstance} reader - Reader instance
|
||||
* @property {Document} doc - Document
|
||||
* @property {Object} params - Event parameters
|
||||
* @property {function(...Element): void} append - Append function
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {function} ReaderEventHandler
|
||||
* @param {ReaderEvent} event - Event
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {ReaderEventType} type - Event type
|
||||
* @param {ReaderEventHandler} handler - Event handler
|
||||
* @param {string} [pluginID] - Plugin ID
|
||||
* @returns {void}
|
||||
*
|
||||
* @example
|
||||
* Inject DOM nodes to reader UI parts:
|
||||
* - renderTextSelectionPopup
|
||||
* - renderSidebarAnnotationHeader
|
||||
|
|
@ -2098,9 +2124,10 @@ class Reader {
|
|||
* container.append('Loading…');
|
||||
* append(container);
|
||||
* setTimeout(() => container.replaceChildren('Translated text: ' + params.annotation.text), 1000);
|
||||
* });
|
||||
*
|
||||
* }, 'my-plugin@my-namespace.com');
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Add options to context menus:
|
||||
* - createColorContextMenu
|
||||
* - createViewContextMenu
|
||||
|
|
@ -2114,7 +2141,8 @@ class Reader {
|
|||
* label: 'Test',
|
||||
* onCommand(){ reader._iframeWindow.alert('Selected annotations: ' + params.ids.join(', ')); }
|
||||
* });
|
||||
* });
|
||||
* }, 'my-plugin@my-namespace.com');
|
||||
* ```
|
||||
*/
|
||||
registerEventListener(type, handler, pluginID = undefined) {
|
||||
this._registeredListeners.push({ pluginID, type, handler });
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue