Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 'use strict';
7 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
9 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
10 Cu.import('resource://gre/modules/Services.jsm');
12 this.EXPORTED_SYMBOLS = ['SystemAppProxy'];
14 let SystemAppProxy = {
15 _frame: null,
16 _isReady: false,
17 _pendingEvents: [],
18 _pendingListeners: [],
20 // To call when a new system app iframe is created
21 registerFrame: function (frame) {
22 this._isReady = false;
23 this._frame = frame;
25 // Register all DOM event listeners added before we got a ref to the app iframe
26 this._pendingListeners
27 .forEach((args) =>
28 this.addEventListener.apply(this, args));
29 this._pendingListeners = [];
30 },
32 // To call when it is ready to receive events
33 setIsReady: function () {
34 if (this._isReady) {
35 Cu.reportError('SystemApp has already been declared as being ready.');
36 }
37 this._isReady = true;
39 // Dispatch all events being queued while the system app was still loading
40 this._pendingEvents
41 .forEach(([type, details]) =>
42 this._sendCustomEvent(type, details));
43 this._pendingEvents = [];
44 },
46 /*
47 * Common way to send an event to the system app.
48 *
49 * // In gecko code:
50 * SystemAppProxy.sendCustomEvent('foo', { data: 'bar' });
51 * // In system app:
52 * window.addEventListener('foo', function (event) {
53 * event.details == 'bar'
54 * });
55 */
56 _sendCustomEvent: function systemApp_sendCustomEvent(type, details) {
57 let content = this._frame ? this._frame.contentWindow : null;
59 // If the system app isn't ready yet,
60 // queue events until someone calls setIsLoaded
61 if (!this._isReady || !content) {
62 this._pendingEvents.push([type, details]);
63 return null;
64 }
66 let event = content.document.createEvent('CustomEvent');
68 let payload;
69 // If the root object already has __exposedProps__,
70 // we consider the caller already wrapped (correctly) the object.
71 if ('__exposedProps__' in details) {
72 payload = details;
73 } else {
74 payload = details ? Cu.cloneInto(details, content) : {};
75 }
77 event.initCustomEvent(type, true, false, payload);
78 content.dispatchEvent(event);
80 return event;
81 },
83 // Now deprecated, use sendCustomEvent with a custom event name
84 dispatchEvent: function systemApp_sendChromeEvent(details) {
85 return this._sendCustomEvent('mozChromeEvent', details);
86 },
88 // Listen for dom events on the system app
89 addEventListener: function systemApp_addEventListener() {
90 let content = this._frame ? this._frame.contentWindow : null;
91 if (!content) {
92 this._pendingListeners.push(arguments);
93 return false;
94 }
96 content.addEventListener.apply(content, arguments);
97 return true;
98 },
100 removeEventListener: function systemApp_removeEventListener(name, listener) {
101 let content = this._frame ? this._frame.contentWindow : null;
102 if (content) {
103 content.removeEventListener.apply(content, arguments);
104 } else {
105 let idx = this._pendingListeners.indexOf(listener);
106 if (idx != -1) {
107 this._pendingListeners.splice(idx, 1);
108 }
109 }
110 }
112 };
113 this.SystemAppProxy = SystemAppProxy;