From 7036073ed12f43db231ea9cf11a1c4a7f0f70fbd Mon Sep 17 00:00:00 2001 From: Abe Jellinek Date: Fri, 28 Jul 2023 00:16:58 -0400 Subject: [PATCH] Resolve plugin-provided URIs relative to rootURI (#3235) --- chrome/content/zotero/xpcom/plugins.js | 15 +++++++++++++ .../content/zotero/xpcom/preferencePanes.js | 21 +++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/chrome/content/zotero/xpcom/plugins.js b/chrome/content/zotero/xpcom/plugins.js index e1e76ec6c5..c8b5a96388 100644 --- a/chrome/content/zotero/xpcom/plugins.js +++ b/chrome/content/zotero/xpcom/plugins.js @@ -220,6 +220,21 @@ Zotero.Plugins = new function () { }; + /** + * Resolve a URI in the context of a plugin. If the passed URI is relative, it will be resolved relative to the + * plugin root URI. If it's absolute, it will be returned unchanged. + * + * @param {String} id Plugin ID + * @param {String | URL} uri + * @throws {TypeError} On an invalid URI + * @return {Promise} + */ + this.resolveURI = async function (id, uri) { + // We can't use addon.getResourceURI(path) here because that only accepts a relative path + return new URL(uri, await this.getRootURI(id)).href; + }; + + this.getName = async function (id) { var addon = await AddonManager.getAddonByID(id); return addon.name; diff --git a/chrome/content/zotero/xpcom/preferencePanes.js b/chrome/content/zotero/xpcom/preferencePanes.js index 16077306e9..a695a77de7 100644 --- a/chrome/content/zotero/xpcom/preferencePanes.js +++ b/chrome/content/zotero/xpcom/preferencePanes.js @@ -96,15 +96,17 @@ Zotero.PreferencePanes = { * * @param {Object} options * @param {String} options.pluginID ID of the plugin registering the pane - * @param {String} options.src URI of an XHTML fragment + * @param {String} options.src URI of an XHTML fragment, optionally relative to the plugin's root * @param {String} [options.id] Represents the pane and must be unique. Automatically generated if not provided * @param {String} [options.parent] ID of parent pane (if provided, pane is hidden from the sidebar) * @param {String} [options.label] Displayed as the pane's label in the sidebar. * If not provided, the plugin's name is used - * @param {String} [options.image] URI of an icon to be displayed in the navigation sidebar. - * If not provided, the plugin's icon (from manifest.json) is used - * @param {String[]} [options.scripts] Array of URIs of scripts to load along with the pane - * @param {String[]} [options.stylesheets] Array of URIs of CSS stylesheets to load along with the pane + * @param {String} [options.image] URI of an icon to be displayed in the navigation sidebar, optionally relative to + * the plugin's root. If not provided, the plugin's icon (from manifest.json) is used. + * @param {String[]} [options.scripts] Array of URIs of scripts to load along with the pane, optionally relative to + * the plugin's root + * @param {String[]} [options.stylesheets] Array of URIs of CSS stylesheets to load along with the pane, optionally + * 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} Resolves to the ID of the pane if successfully added @@ -123,10 +125,11 @@ Zotero.PreferencePanes = { pluginID: options.pluginID, parent: options.parent, rawLabel: options.label || await Zotero.Plugins.getName(options.pluginID), - image: options.image || await Zotero.Plugins.getIconURI(options.pluginID, 24), - src: options.src, - scripts: options.scripts, - stylesheets: options.stylesheets, + image: options.image && await Zotero.Plugins.resolveURI(options.pluginID, options.image) + || await Zotero.Plugins.getIconURI(options.pluginID, 24), + src: await Zotero.Plugins.resolveURI(options.pluginID, options.src), + scripts: await Promise.all(options.scripts.map(uri => Zotero.Plugins.resolveURI(options.pluginID, uri))), + stylesheets: await Promise.all(options.stylesheets.map(uri => Zotero.Plugins.resolveURI(options.pluginID, uri))), helpURL: options.helpURL, defaultXUL: true, };