|
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/. */ |
|
4 |
|
5 'use strict'; |
|
6 |
|
7 const { classes: Cc, interfaces: Ci, utils: Cu } = Components; |
|
8 |
|
9 Cu.import('resource://gre/modules/XPCOMUtils.jsm'); |
|
10 Cu.import('resource://gre/modules/Services.jsm'); |
|
11 |
|
12 this.EXPORTED_SYMBOLS = ['SystemAppProxy']; |
|
13 |
|
14 let SystemAppProxy = { |
|
15 _frame: null, |
|
16 _isReady: false, |
|
17 _pendingEvents: [], |
|
18 _pendingListeners: [], |
|
19 |
|
20 // To call when a new system app iframe is created |
|
21 registerFrame: function (frame) { |
|
22 this._isReady = false; |
|
23 this._frame = frame; |
|
24 |
|
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 }, |
|
31 |
|
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; |
|
38 |
|
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 }, |
|
45 |
|
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; |
|
58 |
|
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 } |
|
65 |
|
66 let event = content.document.createEvent('CustomEvent'); |
|
67 |
|
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 } |
|
76 |
|
77 event.initCustomEvent(type, true, false, payload); |
|
78 content.dispatchEvent(event); |
|
79 |
|
80 return event; |
|
81 }, |
|
82 |
|
83 // Now deprecated, use sendCustomEvent with a custom event name |
|
84 dispatchEvent: function systemApp_sendChromeEvent(details) { |
|
85 return this._sendCustomEvent('mozChromeEvent', details); |
|
86 }, |
|
87 |
|
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 } |
|
95 |
|
96 content.addEventListener.apply(content, arguments); |
|
97 return true; |
|
98 }, |
|
99 |
|
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 } |
|
111 |
|
112 }; |
|
113 this.SystemAppProxy = SystemAppProxy; |
|
114 |