2014-04-07 06:59:48 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* 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/. */
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|
|
|
|
|
|
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
|
|
|
Cu.import('resource://gre/modules/Services.jsm');
|
|
|
|
|
|
|
|
this.EXPORTED_SYMBOLS = ['SystemAppProxy'];
|
|
|
|
|
|
|
|
let SystemAppProxy = {
|
|
|
|
_frame: null,
|
|
|
|
_isReady: false,
|
|
|
|
_pendingEvents: [],
|
|
|
|
_pendingListeners: [],
|
|
|
|
|
|
|
|
// To call when a new system app iframe is created
|
|
|
|
registerFrame: function (frame) {
|
|
|
|
this._isReady = false;
|
|
|
|
this._frame = frame;
|
|
|
|
|
|
|
|
// Register all DOM event listeners added before we got a ref to the app iframe
|
|
|
|
this._pendingListeners
|
|
|
|
.forEach((args) =>
|
|
|
|
this.addEventListener.apply(this, args));
|
|
|
|
this._pendingListeners = [];
|
|
|
|
},
|
|
|
|
|
2015-03-10 22:35:00 -07:00
|
|
|
// Get the system app frame
|
|
|
|
getFrame: function () {
|
|
|
|
return this._frame;
|
|
|
|
},
|
|
|
|
|
2014-04-07 06:59:48 -07:00
|
|
|
// To call when it is ready to receive events
|
|
|
|
setIsReady: function () {
|
|
|
|
if (this._isReady) {
|
|
|
|
Cu.reportError('SystemApp has already been declared as being ready.');
|
|
|
|
}
|
|
|
|
this._isReady = true;
|
|
|
|
|
|
|
|
// Dispatch all events being queued while the system app was still loading
|
|
|
|
this._pendingEvents
|
|
|
|
.forEach(([type, details]) =>
|
|
|
|
this._sendCustomEvent(type, details));
|
|
|
|
this._pendingEvents = [];
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common way to send an event to the system app.
|
|
|
|
*
|
|
|
|
* // In gecko code:
|
|
|
|
* SystemAppProxy.sendCustomEvent('foo', { data: 'bar' });
|
|
|
|
* // In system app:
|
|
|
|
* window.addEventListener('foo', function (event) {
|
|
|
|
* event.details == 'bar'
|
|
|
|
* });
|
2014-05-30 00:48:25 -07:00
|
|
|
*
|
|
|
|
* @param type The custom event type.
|
|
|
|
* @param details The event details.
|
|
|
|
* @param noPending Set to true to emit this event even before the system
|
|
|
|
* app is ready.
|
2014-04-07 06:59:48 -07:00
|
|
|
*/
|
2014-06-04 11:11:06 -07:00
|
|
|
_sendCustomEvent: function systemApp_sendCustomEvent(type,
|
|
|
|
details,
|
|
|
|
noPending,
|
|
|
|
target) {
|
2014-04-07 06:59:48 -07:00
|
|
|
let content = this._frame ? this._frame.contentWindow : null;
|
|
|
|
|
|
|
|
// If the system app isn't ready yet,
|
2014-05-30 00:48:25 -07:00
|
|
|
// queue events until someone calls setIsReady
|
|
|
|
if (!content || (!this._isReady && !noPending)) {
|
2014-04-07 06:59:48 -07:00
|
|
|
this._pendingEvents.push([type, details]);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
let event = content.document.createEvent('CustomEvent');
|
|
|
|
|
|
|
|
let payload;
|
|
|
|
// If the root object already has __exposedProps__,
|
|
|
|
// we consider the caller already wrapped (correctly) the object.
|
|
|
|
if ('__exposedProps__' in details) {
|
|
|
|
payload = details;
|
|
|
|
} else {
|
|
|
|
payload = details ? Cu.cloneInto(details, content) : {};
|
|
|
|
}
|
|
|
|
|
|
|
|
event.initCustomEvent(type, true, false, payload);
|
2014-06-04 11:11:06 -07:00
|
|
|
(target || content).dispatchEvent(event);
|
2014-04-07 06:59:48 -07:00
|
|
|
|
|
|
|
return event;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Now deprecated, use sendCustomEvent with a custom event name
|
2014-11-20 07:48:00 -08:00
|
|
|
dispatchEvent: function systemApp_dispatchEvent(details, target) {
|
2014-06-04 11:11:06 -07:00
|
|
|
return this._sendCustomEvent('mozChromeEvent', details, false, target);
|
2014-04-07 06:59:48 -07:00
|
|
|
},
|
|
|
|
|
2014-11-20 07:48:00 -08:00
|
|
|
dispatchKeyboardEvent: function systemApp_dispatchKeyboardEvent(type, details) {
|
|
|
|
let content = this._frame ? this._frame.contentWindow : null;
|
|
|
|
let e = new content.KeyboardEvent(type, details);
|
|
|
|
content.dispatchEvent(e);
|
|
|
|
},
|
|
|
|
|
2014-04-07 06:59:48 -07:00
|
|
|
// Listen for dom events on the system app
|
|
|
|
addEventListener: function systemApp_addEventListener() {
|
|
|
|
let content = this._frame ? this._frame.contentWindow : null;
|
|
|
|
if (!content) {
|
|
|
|
this._pendingListeners.push(arguments);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
content.addEventListener.apply(content, arguments);
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
removeEventListener: function systemApp_removeEventListener(name, listener) {
|
|
|
|
let content = this._frame ? this._frame.contentWindow : null;
|
|
|
|
if (content) {
|
|
|
|
content.removeEventListener.apply(content, arguments);
|
|
|
|
} else {
|
2014-09-03 18:04:00 -07:00
|
|
|
this._pendingListeners = this._pendingListeners.filter(
|
|
|
|
args => {
|
|
|
|
return args[0] != name || args[1] != listener;
|
|
|
|
});
|
2014-04-07 06:59:48 -07:00
|
|
|
}
|
2014-06-30 03:16:00 -07:00
|
|
|
},
|
|
|
|
|
2014-10-12 23:43:00 -07:00
|
|
|
getFrames: function systemApp_getFrames() {
|
2014-06-30 03:16:00 -07:00
|
|
|
let systemAppFrame = this._frame;
|
|
|
|
if (!systemAppFrame) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
let list = [systemAppFrame];
|
2014-10-12 23:43:00 -07:00
|
|
|
let frames = systemAppFrame.contentDocument.querySelectorAll('iframe');
|
2014-06-30 03:16:00 -07:00
|
|
|
for (let i = 0; i < frames.length; i++) {
|
|
|
|
list.push(frames[i]);
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
2014-04-07 06:59:48 -07:00
|
|
|
};
|
|
|
|
this.SystemAppProxy = SystemAppProxy;
|
|
|
|
|