Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
261 changes: 193 additions & 68 deletions calendar/experiments/calendar/parent/ext-calendarItemAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,34 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var { ExtensionCommon: { makeWidgetId } } = ChromeUtils.importESModule("resource://gre/modules/ExtensionCommon.sys.mjs");
/* global ExtensionCommon */

var { ExtensionParent } = ChromeUtils.importESModule("resource://gre/modules/ExtensionParent.sys.mjs");
var { ExtensionSupport } = ChromeUtils.importESModule("resource:///modules/ExtensionSupport.sys.mjs");
var { ToolbarButtonAPI } = ChromeUtils.importESModule("resource:///modules/ExtensionToolbarButtons.sys.mjs");

var { makeWidgetId } = ExtensionCommon;

const calendarItemActionMap = new WeakMap();

this.calendarItemAction = class extends ToolbarButtonAPI {
#removeFromXulStoreSet(windowUrl, toolbarId, setName) {
const set = Services.xulStore.getValue(
windowUrl,
toolbarId,
setName
).split(",");
const newSet = set.filter(e => e != this.id);
if (newSet.length < set.length) {
Services.xulStore.setValue(
windowUrl,
toolbarId,
setName,
newSet.join(",")
);
}
}

static for(extension) {
return calendarItemActionMap.get(extension);
}
Expand Down Expand Up @@ -53,36 +72,6 @@ this.calendarItemAction = class extends ToolbarButtonAPI {
async onManifestEntry(entryName) {
await super.onManifestEntry(entryName);
calendarItemActionMap.set(this.extension, this);

// Core code only works for one toolbox/toolbarId. Calendar uses different ones. When porting
// you can leave all of this out by either using the same ids, or adapting parent class code to
// deal with ids per window url.
if (this.extension.startupReason == "ADDON_INSTALL") {
// Add it to the messenger window, the other one is already covered by parent code.
this.addToCurrentSet("chrome://messenger/content/messenger.xhtml", "event-tab-toolbar");
}
}

addToCurrentSet(windowURL, toolbarId) {
let currentSet = Services.xulStore.getValue(
windowURL,
toolbarId,
"currentset"
);
if (!currentSet) {
return;
}
currentSet = currentSet.split(",");
if (currentSet.includes(this.id)) {
return;
}
currentSet.push(this.id);
Services.xulStore.setValue(
windowURL,
toolbarId,
"currentset",
currentSet.join(",")
);
}

close() {
Expand All @@ -92,26 +81,187 @@ this.calendarItemAction = class extends ToolbarButtonAPI {

constructor(extension) {
super(extension, ExtensionParent.apiManager.global);

this.manifest_name = "calendar_item_action";
this.manifestName = "calendarItemAction";
this.moduleName = this.manifestName;

// TODO: This could be removed, as the new toolboxData has this info as well.
this.windowURLs = [
"chrome://messenger/content/messenger.xhtml",
"chrome://calendar/content/calendar-event-dialog.xhtml"
];

this.toolboxId = "event-toolbox";
this.toolbarId = "event-toolbar";
// For reference, the current core approach.
//this.toolboxId = "event-toolbox";
//this.toolbarId = "event-toolbar";

this.toolboxData = [
{
windowUrl: "chrome://calendar/content/calendar-event-dialog.xhtml",
toolboxId: "event-toolbox",
toolbarId: "event-toolbar",
allowedToolbarIds: ["event-toolbar"],
},
{
windowUrl: "chrome://messenger/content/messenger.xhtml",
toolboxId: "event-toolbox",
toolbarId: "event-tab-toolbar",
allowedToolbarIds: ["event-tab-toolbar"],
}
];

// Core code generates these only in onManifestEntry, which is too late for
// the cleanup (it is async and paint may already be fired).
this.widgetId = makeWidgetId(extension.id);
this.id = `${this.widgetId}-${this.moduleName}-toolbarbutton`;

// Core code can clean up extension buttons (most notably the XUL store
// extensionset) in onUninstall(), but an Experiment cannot. Let's cleanup on
// a fresh install (as early as possible). We might even stick with this
// approach, as onUninstall() needs hardcoded values.
if (this.extension.startupReason == "ADDON_INSTALL") {
for (const { windowUrl, allowedToolbarIds } of this.toolboxData) {
const defaultToolbarId = allowedToolbarIds[0];
this.#removeFromXulStoreSet(windowUrl, defaultToolbarId, "extensionset");
for (const toolbarId of allowedToolbarIds) {
this.#removeFromXulStoreSet(windowUrl, toolbarId, "currentset");
}
}
}
}

// This is only necessary as part of the experiment, refactor when moving to core.
// This is a proposed implementation for toolbarbuttons on a customizable
// toolbar, where buttons can be added to different toolbars in different pages
// (see ToolbarButtonAPI::customizableToolbarPaint).
paint(window) {
if (window.location.href == "chrome://calendar/content/calendar-event-dialog.xhtml") {
this.toolbarId = "event-toolbar";
const { document } = window;
if (document.getElementById(this.id)) {
return;
}

const windowURL = window.location.href;
const toolboxData = this.toolboxData.find(t => t.windowUrl == windowURL);

if (!toolboxData) {
return;
}

const toolbox = document.getElementById(toolboxData.toolboxId);
if (!toolbox) {
return;
}

// Get all toolbars which link to or are children of toolboxData.toolboxId and
// check if the button has been moved to the XUL store currentset of a non-default
// toolbar.
const toolbars = document.querySelectorAll(
`#${toolboxData.toolboxId} toolbar, toolbar[toolboxid="${toolboxData.toolboxId}"]`
);
for (const toolbar of toolbars) {
const currentSet = Services.xulStore
.getValue(windowURL, toolbar.id, "currentset")
.split(",")
.filter(Boolean);
if (currentSet.includes(this.id)) {
toolboxData.toolbarId = toolbar.id;
break;
}
}

const toolbar = document.getElementById(toolboxData.toolbarId);
const button = this.makeButton(window);
if (toolbox.palette) {
toolbox.palette.appendChild(button);
} else {
this.toolbarId = "event-tab-toolbar";
toolbar.appendChild(button);
}

// Handle the special case where this toolbar does not yet have a currentset
// defined.
if (!Services.xulStore.hasValue(windowURL, toolboxData.toolbarId, "currentset")) {
const defaultSet = toolbar
.getAttribute("defaultset")
.split(",")
.filter(Boolean);
Services.xulStore.setValue(
windowURL,
toolboxData.toolbarId,
"currentset",
defaultSet.join(",")
);
}

// Add new buttons to the XUL store currentset: If the extensionset of the
// default toolbar does not include the button, it is a new one which needs
// to be added.
const defaultToolbarId = toolboxData.allowedToolbarIds[0];
const extensionSet = Services.xulStore
.getValue(windowURL, defaultToolbarId, "extensionset")
.split(",")
.filter(Boolean);
if (!extensionSet.includes(this.id)) {
extensionSet.push(this.id);
Services.xulStore.setValue(
windowURL,
defaultToolbarId,
"extensionset",
extensionSet.join(",")
);
const currentSet = Services.xulStore
.getValue(windowURL, toolboxData.toolbarId, "currentset")
.split(",")
.filter(Boolean);
if (!currentSet.includes(this.id)) {
currentSet.push(this.id);
Services.xulStore.setValue(
windowURL,
toolboxData.toolbarId,
"currentset",
currentSet.join(",")
);
}
}

const currentSet = Services.xulStore.getValue(
windowURL,
toolboxData.toolbarId,
"currentset"
);

toolbar.currentSet = currentSet;
toolbar.setAttribute("currentset", toolbar.currentSet);

if (this.extension.hasPermission("menus")) {
document.addEventListener("popupshowing", this);
}
}

unpaint(window) {
const { document } = window;
const windowURL = window.location.href;
// We assume only one toolbox per window. Could have multiple toolbars, but
// paint updates the associated toolbarId, if it was moved to a non-default
// toolbar.
const toolboxData = this.toolboxData.find(t => t.windowUrl == windowURL);

if (this.extension.hasPermission("menus")) {
document.removeEventListener("popupshowing", this);
}

if (!toolboxData) {
return;
}

const toolbar = document.getElementById(toolboxData.toolbarId);
if (toolbar.hasAttribute("customizable")) {
// New code, Bug 2020584.
//toolbar.removeButton(this.id);
document.getElementById(this.id)?.remove();
toolbar.toolbox?.palette?.querySelector(`#${this.id}`)?.remove();
} else {
document.getElementById(this.id)?.remove();
}
return super.paint(window);
}

handleEvent(event) {
Expand All @@ -132,7 +282,7 @@ this.calendarItemAction = class extends ToolbarButtonAPI {
tab: window,
pageUrl: window.browser.currentURI.spec,
extension: this.extension,
onComposeAction: true,
onCalendarItemAction: true,
menu,
});
}
Expand All @@ -141,37 +291,12 @@ this.calendarItemAction = class extends ToolbarButtonAPI {
}
}

onShutdown() {
// TODO browserAction uses static onUninstall, this doesn't work in an experiment.
onShutdown(isAppShutdown) {
if (isAppShutdown) {
return;
}
const extensionId = this.extension.id;
ExtensionSupport.unregisterWindowListener("ext-calendar-itemAction-" + extensionId);

const widgetId = makeWidgetId(extensionId);
const id = `${widgetId}-calendarItemAction-toolbarbutton`;

const windowURLs = [
"chrome://messenger/content/messenger.xhtml",
"chrome://calendar/content/calendar-event-dialog.xhtml"
];

for (const windowURL of windowURLs) {
let currentSet = Services.xulStore.getValue(
windowURL,
"event-toolbar",
"currentset"
);
currentSet = currentSet.split(",");
const index = currentSet.indexOf(id);
if (index >= 0) {
currentSet.splice(index, 1);
Services.xulStore.setValue(
windowURL,
"event-toolbar",
"currentset",
currentSet.join(",")
);
}
}
Comment thread
jobisoft marked this conversation as resolved.
}
};

Expand Down