|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 module.metadata = { |
|
8 "stability": "stable" |
|
9 }; |
|
10 |
|
11 const { Cc, Ci, Cr } = require("chrome"); |
|
12 const apiUtils = require("./deprecated/api-utils"); |
|
13 const errors = require("./deprecated/errors"); |
|
14 const { isString, isUndefined, instanceOf } = require('./lang/type'); |
|
15 const { URL } = require('./url'); |
|
16 |
|
17 const NOTIFICATION_DIRECTIONS = ["auto", "ltr", "rtl"]; |
|
18 |
|
19 try { |
|
20 let alertServ = Cc["@mozilla.org/alerts-service;1"]. |
|
21 getService(Ci.nsIAlertsService); |
|
22 |
|
23 // The unit test sets this to a mock notification function. |
|
24 var notify = alertServ.showAlertNotification.bind(alertServ); |
|
25 } |
|
26 catch (err) { |
|
27 // An exception will be thrown if the platform doesn't provide an alert |
|
28 // service, e.g., if Growl is not installed on OS X. In that case, use a |
|
29 // mock notification function that just logs to the console. |
|
30 notify = notifyUsingConsole; |
|
31 } |
|
32 |
|
33 exports.notify = function notifications_notify(options) { |
|
34 let valOpts = validateOptions(options); |
|
35 let clickObserver = !valOpts.onClick ? null : { |
|
36 observe: function notificationClickObserved(subject, topic, data) { |
|
37 if (topic === "alertclickcallback") |
|
38 errors.catchAndLog(valOpts.onClick).call(exports, valOpts.data); |
|
39 } |
|
40 }; |
|
41 function notifyWithOpts(notifyFn) { |
|
42 notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver, |
|
43 valOpts.data, clickObserver, valOpts.tag, valOpts.dir, valOpts.lang); |
|
44 } |
|
45 try { |
|
46 notifyWithOpts(notify); |
|
47 } |
|
48 catch (err) { |
|
49 if (err instanceof Ci.nsIException && err.result == Cr.NS_ERROR_FILE_NOT_FOUND) { |
|
50 console.warn("The notification icon named by " + valOpts.iconURL + |
|
51 " does not exist. A default icon will be used instead."); |
|
52 delete valOpts.iconURL; |
|
53 notifyWithOpts(notify); |
|
54 } |
|
55 else { |
|
56 notifyWithOpts(notifyUsingConsole); |
|
57 } |
|
58 } |
|
59 }; |
|
60 |
|
61 function notifyUsingConsole(iconURL, title, text) { |
|
62 title = title ? "[" + title + "]" : ""; |
|
63 text = text || ""; |
|
64 let str = [title, text].filter(function (s) s).join(" "); |
|
65 console.log(str); |
|
66 } |
|
67 |
|
68 function validateOptions(options) { |
|
69 return apiUtils.validateOptions(options, { |
|
70 data: { |
|
71 is: ["string", "undefined"] |
|
72 }, |
|
73 iconURL: { |
|
74 is: ["string", "undefined", "object"], |
|
75 ok: function(value) { |
|
76 return isUndefined(value) || isString(value) || (value instanceof URL); |
|
77 }, |
|
78 msg: "`iconURL` must be a string or an URL instance." |
|
79 }, |
|
80 onClick: { |
|
81 is: ["function", "undefined"] |
|
82 }, |
|
83 text: { |
|
84 is: ["string", "undefined", "number"] |
|
85 }, |
|
86 title: { |
|
87 is: ["string", "undefined", "number"] |
|
88 }, |
|
89 tag: { |
|
90 is: ["string", "undefined", "number"] |
|
91 }, |
|
92 dir: { |
|
93 is: ["string", "undefined"], |
|
94 ok: function(value) { |
|
95 return isUndefined(value) || ~NOTIFICATION_DIRECTIONS.indexOf(value); |
|
96 }, |
|
97 msg: '`dir` option must be one of: "auto", "ltr" or "rtl".' |
|
98 }, |
|
99 lang: { |
|
100 is: ["string", "undefined"] |
|
101 } |
|
102 }); |
|
103 } |