gecko-dev/toolkit/components/extensions/parent/ext-notifications.js
Andrew Swan e71d1d5a82 Bug 1450388 Part 1 Refactor EventManager r=kmag
As we add more behaviors to EventManager, the signature of the constructor
is going to get really clumsy.  Head that off by converting it to take a
general parameters object.

This introduces a compatibility problem for existing webextension experiments,
put in a backward-compatibility shim for now.

MozReview-Commit-ID: 72QDfiwRm5j

--HG--
extra : rebase_source : 31c3fd561f373a5d75c4336de830aa5a2abfe797
2018-03-14 14:52:44 -07:00

171 lines
4.7 KiB
JavaScript

"use strict";
const ToolkitModules = {};
ChromeUtils.defineModuleGetter(ToolkitModules, "EventEmitter",
"resource://gre/modules/EventEmitter.jsm");
var {
ignoreEvent,
} = ExtensionCommon;
// Manages a notification popup (notifications API) created by the extension.
function Notification(extension, notificationsMap, id, options) {
this.notificationsMap = notificationsMap;
this.id = id;
this.options = options;
let imageURL;
if (options.iconUrl) {
imageURL = extension.baseURI.resolve(options.iconUrl);
}
try {
let svc = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
svc.showAlertNotification(imageURL,
options.title,
options.message,
true, // textClickable
this.id,
this,
this.id);
} catch (e) {
// This will fail if alerts aren't available on the system.
}
}
Notification.prototype = {
clear() {
try {
let svc = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
svc.closeAlert(this.id);
} catch (e) {
// This will fail if the OS doesn't support this function.
}
this.notificationsMap.delete(this.id);
},
observe(subject, topic, data) {
let emitAndDelete = event => {
this.notificationsMap.emit(event, data);
this.notificationsMap.delete(this.id);
};
switch (topic) {
case "alertclickcallback":
emitAndDelete("clicked");
break;
case "alertfinished":
emitAndDelete("closed");
break;
case "alertshow":
this.notificationsMap.emit("shown", data);
break;
}
},
};
this.notifications = class extends ExtensionAPI {
constructor(extension) {
super(extension);
this.nextId = 0;
this.notificationsMap = new Map();
ToolkitModules.EventEmitter.decorate(this.notificationsMap);
}
onShutdown() {
for (let notification of this.notificationsMap.values()) {
notification.clear();
}
}
getAPI(context) {
let {extension} = context;
let notificationsMap = this.notificationsMap;
return {
notifications: {
create: (notificationId, options) => {
if (!notificationId) {
notificationId = String(this.nextId++);
}
if (notificationsMap.has(notificationId)) {
notificationsMap.get(notificationId).clear();
}
let notification = new Notification(extension, notificationsMap, notificationId, options);
notificationsMap.set(notificationId, notification);
return Promise.resolve(notificationId);
},
clear: function(notificationId) {
if (notificationsMap.has(notificationId)) {
notificationsMap.get(notificationId).clear();
return Promise.resolve(true);
}
return Promise.resolve(false);
},
getAll: function() {
let result = {};
notificationsMap.forEach((value, key) => {
result[key] = value.options;
});
return Promise.resolve(result);
},
onClosed: new EventManager({
context,
name: "notifications.onClosed",
register: fire => {
let listener = (event, notificationId) => {
// TODO Bug 1413188, Support the byUser argument.
fire.async(notificationId, true);
};
notificationsMap.on("closed", listener);
return () => {
notificationsMap.off("closed", listener);
};
},
}).api(),
onClicked: new EventManager({
context,
name: "notifications.onClicked",
register: fire => {
let listener = (event, notificationId) => {
fire.async(notificationId, true);
};
notificationsMap.on("clicked", listener);
return () => {
notificationsMap.off("clicked", listener);
};
},
}).api(),
onShown: new EventManager({
context,
name: "notifications.onShown",
register: fire => {
let listener = (event, notificationId) => {
fire.async(notificationId, true);
};
notificationsMap.on("shown", listener);
return () => {
notificationsMap.off("shown", listener);
};
},
}).api(),
// TODO Bug 1190681, implement button support.
onButtonClicked: ignoreEvent(context, "notifications.onButtonClicked"),
},
};
}
};