--- a/addon-sdk/moz.build
+++ b/addon-sdk/moz.build
@@ -16,47 +16,36 @@ EXTRA_JS_MODULES.sdk += [
'source/app-extension/bootstrap.js',
]
EXTRA_JS_MODULES.sdk.system += [
'source/modules/system/Startup.js',
]
modules = [
- 'framescript/FrameScriptManager.jsm',
- 'framescript/content.jsm',
- 'framescript/manager.js',
- 'framescript/util.js',
'index.js',
'jetpack-id/index.js',
'method/core.js',
'method/test/browser.js',
'method/test/common.js',
'mozilla-toolkit-versioning/index.js',
'mozilla-toolkit-versioning/lib/utils.js',
'node/os.js',
'sdk/addon/installer.js',
'sdk/addon/window.js',
'sdk/base64.js',
'sdk/browser/events.js',
'sdk/clipboard.js',
'sdk/console/plain-text.js',
'sdk/console/traceback.js',
- 'sdk/content/content-worker.js',
- 'sdk/content/content.js',
'sdk/content/events.js',
'sdk/content/loader.js',
'sdk/content/mod.js',
- 'sdk/content/sandbox.js',
- 'sdk/content/sandbox/events.js',
- 'sdk/content/tab-events.js',
'sdk/content/thumbnail.js',
'sdk/content/utils.js',
- 'sdk/content/worker-child.js',
- 'sdk/content/worker.js',
'sdk/core/disposable.js',
'sdk/core/heritage.js',
'sdk/core/namespace.js',
'sdk/core/observer.js',
'sdk/core/promise.js',
'sdk/core/reference.js',
'sdk/deprecated/api-utils.js',
'sdk/deprecated/events/assembler.js',
@@ -97,50 +86,32 @@ modules = [
'sdk/passwords/utils.js',
'sdk/platform/xpcom.js',
'sdk/preferences/event-target.js',
'sdk/preferences/service.js',
'sdk/preferences/utils.js',
'sdk/private-browsing.js',
'sdk/private-browsing/utils.js',
'sdk/querystring.js',
- 'sdk/remote/child.js',
- 'sdk/remote/core.js',
- 'sdk/remote/parent.js',
- 'sdk/remote/utils.js',
'sdk/request.js',
- 'sdk/selection.js',
'sdk/self.js',
'sdk/simple-prefs.js',
'sdk/simple-storage.js',
'sdk/stylesheet/style.js',
'sdk/stylesheet/utils.js',
'sdk/system.js',
'sdk/system/environment.js',
'sdk/system/events-shimmed.js',
'sdk/system/events.js',
'sdk/system/globals.js',
'sdk/system/process.js',
'sdk/system/runtime.js',
'sdk/system/unload.js',
'sdk/system/xul-app.js',
'sdk/system/xul-app.jsm',
- 'sdk/tab/events.js',
- 'sdk/tabs.js',
- 'sdk/tabs/common.js',
- 'sdk/tabs/events.js',
- 'sdk/tabs/helpers.js',
- 'sdk/tabs/namespace.js',
- 'sdk/tabs/observer.js',
- 'sdk/tabs/tab-fennec.js',
- 'sdk/tabs/tab-firefox.js',
- 'sdk/tabs/tab.js',
- 'sdk/tabs/tabs-firefox.js',
- 'sdk/tabs/utils.js',
- 'sdk/tabs/worker.js',
'sdk/test.js',
'sdk/test/assert.js',
'sdk/test/harness.js',
'sdk/test/httpd.js',
'sdk/test/loader.js',
'sdk/test/memory.js',
'sdk/test/options.js',
'sdk/test/runner.js',
@@ -154,27 +125,17 @@ modules = [
'sdk/util/contract.js',
'sdk/util/deprecate.js',
'sdk/util/dispatcher.js',
'sdk/util/list.js',
'sdk/util/object.js',
'sdk/util/sequence.js',
'sdk/util/uuid.js',
'sdk/view/core.js',
- 'sdk/window/browser.js',
- 'sdk/window/events.js',
- 'sdk/window/helpers.js',
- 'sdk/window/namespace.js',
'sdk/window/utils.js',
- 'sdk/windows.js',
- 'sdk/windows/fennec.js',
- 'sdk/windows/firefox.js',
- 'sdk/windows/observer.js',
- 'sdk/windows/tabs-fennec.js',
- 'sdk/worker/utils.js',
'sdk/zip/utils.js',
'test.js',
'toolkit/loader.js',
'toolkit/require.js',
]
commonjs = EXTRA_JS_MODULES.commonjs
deleted file mode 100644
--- a/addon-sdk/source/lib/framescript/FrameScriptManager.jsm
+++ /dev/null
@@ -1,27 +0,0 @@
-/* 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 globalMM = Components.classes["@mozilla.org/globalmessagemanager;1"].
- getService(Components.interfaces.nsIMessageListenerManager);
-
-// Load frame scripts from the same dir as this module.
-// Since this JSM will be loaded using require(), PATH will be
-// overridden while running tests, just like any other module.
-const PATH = __URI__.replace('framescript/FrameScriptManager.jsm', '');
-
-// Builds a unique loader ID for this runtime. We prefix with the SDK path so
-// overriden versions of the SDK don't conflict
-var LOADER_ID = 0;
-this.getNewLoaderID = () => {
- return PATH + ":" + LOADER_ID++;
-}
-
-const frame_script = function(contentFrame, PATH) {
- let { registerContentFrame } = Components.utils.import(PATH + 'framescript/content.jsm', {});
- registerContentFrame(contentFrame);
-}
-globalMM.loadFrameScript("data:,(" + frame_script.toString() + ")(this, " + JSON.stringify(PATH) + ");", true);
-
-this.EXPORTED_SYMBOLS = ['getNewLoaderID'];
deleted file mode 100644
--- a/addon-sdk/source/lib/framescript/content.jsm
+++ /dev/null
@@ -1,94 +0,0 @@
-/* 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 { utils: Cu, classes: Cc, interfaces: Ci } = Components;
-const { Services } = Cu.import('resource://gre/modules/Services.jsm');
-
-const cpmm = Cc['@mozilla.org/childprocessmessagemanager;1'].
- getService(Ci.nsISyncMessageSender);
-
-this.EXPORTED_SYMBOLS = ["registerContentFrame"];
-
-// This may be an overriden version of the SDK so use the PATH as a key for the
-// initial messages before we have a loaderID.
-const PATH = __URI__.replace('framescript/content.jsm', '');
-
-const { Loader } = Cu.import(PATH + 'toolkit/loader.js', {});
-
-// one Loader instance per addon (per @loader/options to be precise)
-var addons = new Map();
-
-// Tell the parent that a new process is ready
-cpmm.sendAsyncMessage('sdk/remote/process/start', {
- modulePath: PATH
-});
-
-// Load a child process module loader with the given loader options
-cpmm.addMessageListener('sdk/remote/process/load', ({ data: { modulePath, loaderID, options, reason } }) => {
- if (modulePath != PATH)
- return;
-
- // During startup races can mean we get a second load message
- if (addons.has(loaderID))
- return;
-
- options.waiveInterposition = true;
-
- let loader = Loader.Loader(options);
- let addon = {
- loader,
- require: Loader.Require(loader, { id: 'LoaderHelper' }),
- }
- addons.set(loaderID, addon);
-
- cpmm.sendAsyncMessage('sdk/remote/process/attach', {
- loaderID,
- processID: Services.appinfo.processID,
- isRemote: Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT
- });
-
- addon.child = addon.require('sdk/remote/child');
-
- for (let contentFrame of frames.values())
- addon.child.registerContentFrame(contentFrame);
-});
-
-// Unload a child process loader
-cpmm.addMessageListener('sdk/remote/process/unload', ({ data: { loaderID, reason } }) => {
- if (!addons.has(loaderID))
- return;
-
- let addon = addons.get(loaderID);
- Loader.unload(addon.loader, reason);
-
- // We want to drop the reference to the loader but never allow creating a new
- // loader with the same ID
- addons.set(loaderID, {});
-})
-
-
-var frames = new Set();
-
-this.registerContentFrame = contentFrame => {
- contentFrame.addEventListener("unload", () => {
- unregisterContentFrame(contentFrame);
- });
-
- frames.add(contentFrame);
-
- for (let addon of addons.values()) {
- if ("child" in addon)
- addon.child.registerContentFrame(contentFrame);
- }
-};
-
-function unregisterContentFrame(contentFrame) {
- frames.delete(contentFrame);
-
- for (let addon of addons.values()) {
- if ("child" in addon)
- addon.child.unregisterContentFrame(contentFrame);
- }
-}
deleted file mode 100644
--- a/addon-sdk/source/lib/framescript/manager.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const mime = "application/javascript";
-const requireURI = module.uri.replace("framescript/manager.js",
- "toolkit/require.js");
-
-const requireLoadURI = `data:${mime},this["Components"].utils.import("${requireURI}")`
-
-// Loads module with given `id` into given `messageManager` via shared module loader. If `init`
-// string is passed, will call module export with that name and pass frame script environment
-// of the `messageManager` into it. Since module will load only once per process (which is
-// once for chrome proces & second for content process) it is useful to have an init function
-// to setup event listeners on each content frame.
-const loadModule = (messageManager, id, allowDelayed, init) => {
- const moduleLoadURI = `${requireLoadURI}.require("${id}")`
- const uri = init ? `${moduleLoadURI}.${init}(this)` : moduleLoadURI;
- messageManager.loadFrameScript(uri, allowDelayed);
-};
-exports.loadModule = loadModule;
deleted file mode 100644
--- a/addon-sdk/source/lib/framescript/util.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-
-const { Ci } = require("chrome");
-
-const windowToMessageManager = window =>
- window.
- QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDocShell).
- sameTypeRootTreeItem.
- QueryInterface(Ci.nsIDocShell).
- QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIContentFrameMessageManager);
-exports.windowToMessageManager = windowToMessageManager;
-
-const nodeToMessageManager = node =>
- windowToMessageManager(node.ownerGlobal);
-exports.nodeToMessageManager = nodeToMessageManager;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/content/content-worker.js
+++ /dev/null
@@ -1,305 +0,0 @@
-/* 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/. */
-
-Object.freeze({
- // TODO: Bug 727854 Use same implementation than common JS modules,
- // i.e. EventEmitter module
-
- /**
- * Create an EventEmitter instance.
- */
- createEventEmitter: function createEventEmitter(emit) {
- let listeners = Object.create(null);
- let eventEmitter = Object.freeze({
- emit: emit,
- on: function on(name, callback) {
- if (typeof callback !== "function")
- return this;
- if (!(name in listeners))
- listeners[name] = [];
- listeners[name].push(callback);
- return this;
- },
- once: function once(name, callback) {
- eventEmitter.on(name, function onceCallback() {
- eventEmitter.removeListener(name, onceCallback);
- callback.apply(callback, arguments);
- });
- },
- removeListener: function removeListener(name, callback) {
- if (!(name in listeners))
- return;
- let index = listeners[name].indexOf(callback);
- if (index == -1)
- return;
- listeners[name].splice(index, 1);
- }
- });
- function onEvent(name) {
- if (!(name in listeners))
- return [];
- let args = Array.slice(arguments, 1);
- let results = [];
- for (let callback of listeners[name]) {
- results.push(callback.apply(null, args));
- }
- return results;
- }
- return {
- eventEmitter: eventEmitter,
- emit: onEvent
- };
- },
-
- /**
- * Create an EventEmitter instance to communicate with chrome module
- * by passing only strings between compartments.
- * This function expects `emitToChrome` function, that allows to send
- * events to the chrome module. It returns the EventEmitter as `pipe`
- * attribute, and, `onChromeEvent` a function that allows chrome module
- * to send event into the EventEmitter.
- *
- * pipe.emit --> emitToChrome
- * onChromeEvent --> callback registered through pipe.on
- */
- createPipe: function createPipe(emitToChrome) {
- let ContentWorker = this;
- function onEvent(type, ...args) {
- // JSON.stringify is buggy with cross-sandbox values,
- // it may return "{}" on functions. Use a replacer to match them correctly.
- let replacer = (k, v) =>
- typeof(v) === "function"
- ? (type === "console" ? Function.toString.call(v) : void(0))
- : v;
-
- let str = JSON.stringify([type, ...args], replacer);
- emitToChrome(str);
- }
-
- let { eventEmitter, emit } =
- ContentWorker.createEventEmitter(onEvent);
-
- return {
- pipe: eventEmitter,
- onChromeEvent: function onChromeEvent(array) {
- // We either receive a stringified array, or a real array.
- // We still allow to pass an array of objects, in WorkerSandbox.emitSync
- // in order to allow sending DOM node reference between content script
- // and modules (only used for context-menu API)
- let args = typeof array == "string" ? JSON.parse(array) : array;
- return emit.apply(null, args);
- }
- };
- },
-
- injectConsole: function injectConsole(exports, pipe) {
- exports.console = Object.freeze({
- log: pipe.emit.bind(null, "console", "log"),
- info: pipe.emit.bind(null, "console", "info"),
- warn: pipe.emit.bind(null, "console", "warn"),
- error: pipe.emit.bind(null, "console", "error"),
- debug: pipe.emit.bind(null, "console", "debug"),
- exception: pipe.emit.bind(null, "console", "exception"),
- trace: pipe.emit.bind(null, "console", "trace"),
- time: pipe.emit.bind(null, "console", "time"),
- timeEnd: pipe.emit.bind(null, "console", "timeEnd")
- });
- },
-
- injectTimers: function injectTimers(exports, chromeAPI, pipe, console) {
- // wrapped functions from `'timer'` module.
- // Wrapper adds `try catch` blocks to the callbacks in order to
- // emit `error` event if exception is thrown in
- // the Worker global scope.
- // @see http://www.w3.org/TR/workers/#workerutils
-
- // List of all living timeouts/intervals
- let _timers = Object.create(null);
-
- // Keep a reference to original timeout functions
- let {
- setTimeout: chromeSetTimeout,
- setInterval: chromeSetInterval,
- clearTimeout: chromeClearTimeout,
- clearInterval: chromeClearInterval
- } = chromeAPI.timers;
-
- function registerTimer(timer) {
- let registerMethod = null;
- if (timer.kind == "timeout")
- registerMethod = chromeSetTimeout;
- else if (timer.kind == "interval")
- registerMethod = chromeSetInterval;
- else
- throw new Error("Unknown timer kind: " + timer.kind);
-
- if (typeof timer.fun == 'string') {
- let code = timer.fun;
- timer.fun = () => chromeAPI.sandbox.evaluate(exports, code);
- } else if (typeof timer.fun != 'function') {
- throw new Error('Unsupported callback type' + typeof timer.fun);
- }
-
- let id = registerMethod(onFire, timer.delay);
- function onFire() {
- try {
- if (timer.kind == "timeout")
- delete _timers[id];
- timer.fun.apply(null, timer.args);
- } catch(e) {
- console.exception(e);
- let wrapper = {
- instanceOfError: instanceOf(e, Error),
- value: e,
- };
- if (wrapper.instanceOfError) {
- wrapper.value = {
- message: e.message,
- fileName: e.fileName,
- lineNumber: e.lineNumber,
- stack: e.stack,
- name: e.name,
- };
- }
- pipe.emit('error', wrapper);
- }
- }
- _timers[id] = timer;
- return id;
- }
-
- // copied from sdk/lang/type.js since modules are not available here
- function instanceOf(value, Type) {
- var isConstructorNameSame;
- var isConstructorSourceSame;
-
- // If `instanceof` returned `true` we know result right away.
- var isInstanceOf = value instanceof Type;
-
- // If `instanceof` returned `false` we do ducktype check since `Type` may be
- // from a different sandbox. If a constructor of the `value` or a constructor
- // of the value's prototype has same name and source we assume that it's an
- // instance of the Type.
- if (!isInstanceOf && value) {
- isConstructorNameSame = value.constructor.name === Type.name;
- isConstructorSourceSame = String(value.constructor) == String(Type);
- isInstanceOf = (isConstructorNameSame && isConstructorSourceSame) ||
- instanceOf(Object.getPrototypeOf(value), Type);
- }
- return isInstanceOf;
- }
-
- function unregisterTimer(id) {
- if (!(id in _timers))
- return;
- let { kind } = _timers[id];
- delete _timers[id];
- if (kind == "timeout")
- chromeClearTimeout(id);
- else if (kind == "interval")
- chromeClearInterval(id);
- else
- throw new Error("Unknown timer kind: " + kind);
- }
-
- function disableAllTimers() {
- Object.keys(_timers).forEach(unregisterTimer);
- }
-
- exports.setTimeout = function ContentScriptSetTimeout(callback, delay) {
- return registerTimer({
- kind: "timeout",
- fun: callback,
- delay: delay,
- args: Array.slice(arguments, 2)
- });
- };
- exports.clearTimeout = function ContentScriptClearTimeout(id) {
- unregisterTimer(id);
- };
-
- exports.setInterval = function ContentScriptSetInterval(callback, delay) {
- return registerTimer({
- kind: "interval",
- fun: callback,
- delay: delay,
- args: Array.slice(arguments, 2)
- });
- };
- exports.clearInterval = function ContentScriptClearInterval(id) {
- unregisterTimer(id);
- };
-
- // On page-hide, save a list of all existing timers before disabling them,
- // in order to be able to restore them on page-show.
- // These events are fired when the page goes in/out of bfcache.
- // https://developer.mozilla.org/En/Working_with_BFCache
- let frozenTimers = [];
- pipe.on("pageshow", function onPageShow() {
- frozenTimers.forEach(registerTimer);
- });
- pipe.on("pagehide", function onPageHide() {
- frozenTimers = [];
- for (let id in _timers)
- frozenTimers.push(_timers[id]);
- disableAllTimers();
- // Some other pagehide listeners may register some timers that won't be
- // frozen as this particular pagehide listener is called first.
- // So freeze these timers on next cycle.
- chromeSetTimeout(function () {
- for (let id in _timers)
- frozenTimers.push(_timers[id]);
- disableAllTimers();
- }, 0);
- });
-
- // Unregister all timers when the page is destroyed
- // (i.e. when it is removed from bfcache)
- pipe.on("detach", function clearTimeouts() {
- disableAllTimers();
- _timers = {};
- frozenTimers = [];
- });
- },
-
- injectMessageAPI: function injectMessageAPI(exports, pipe, console) {
-
- let ContentWorker = this;
- let { eventEmitter: port, emit : portEmit } =
- ContentWorker.createEventEmitter(pipe.emit.bind(null, "event"));
- pipe.on("event", portEmit);
-
- let self = {
- port: port,
- postMessage: pipe.emit.bind(null, "message"),
- on: pipe.on.bind(null),
- once: pipe.once.bind(null),
- removeListener: pipe.removeListener.bind(null),
- };
- Object.defineProperty(exports, "self", {
- value: self
- });
- },
-
- injectOptions: function (exports, options) {
- Object.defineProperty( exports.self, "options", { value: JSON.parse( options ) });
- },
-
- inject: function (exports, chromeAPI, emitToChrome, options) {
- let ContentWorker = this;
- let { pipe, onChromeEvent } =
- ContentWorker.createPipe(emitToChrome);
-
- ContentWorker.injectConsole(exports, pipe);
- ContentWorker.injectTimers(exports, chromeAPI, pipe, exports.console);
- ContentWorker.injectMessageAPI(exports, pipe, exports.console);
- if ( options !== undefined ) {
- ContentWorker.injectOptions(exports, options);
- }
-
- Object.freeze( exports.self );
-
- return onChromeEvent;
- }
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/content/content.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "deprecated"
-};
-
-const { deprecateUsage } = require('../util/deprecate');
-
-Object.defineProperty(exports, "Worker", {
- get: function() {
- deprecateUsage('`sdk/content/content` is deprecated. Please use `sdk/content/worker` directly.');
- return require('./worker').Worker;
- }
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/content/sandbox.js
+++ /dev/null
@@ -1,426 +0,0 @@
-/* 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';
-
-module.metadata = {
- 'stability': 'unstable'
-};
-
-const { Class } = require('../core/heritage');
-const { EventTarget } = require('../event/target');
-lazyRequire(this, '../event/core', "on", "off", "emit");
-lazyRequire(this, './sandbox/events', "events");
-lazyRequire(this, './utils', "requiresAddonGlobal");
-lazyRequire(this, '../lang/functional', {"delay": "async"});
-const { Ci, Cu, Cc } = require('chrome');
-lazyRequireModule(this, "../timers", "timer");
-lazyRequire(this, '../url', "URL");
-lazyRequire(this, '../loader/sandbox', "sandbox", "evaluate", "load");
-lazyRequire(this, '../util/object', "merge");
-lazyRequire(this, '../tabs/utils', "getTabForContentWindowNoShim");
-lazyRequire(this, '../window/utils', "getInnerId");
-lazyRequire(this, '../console/plain-text', "PlainTextConsole");
-
-lazyRequire(this, '../self', "data");
-lazyRequire(this, '../remote/core', "isChildLoader");
-
-// WeakMap of sandboxes so we can access private values
-const sandboxes = new WeakMap();
-
-/* Trick the linker in order to ensure shipping these files in the XPI.
- require('./content-worker.js');
- Then, retrieve URL of these files in the XPI:
-*/
-var prefix = module.uri.split('sandbox.js')[0];
-const CONTENT_WORKER_URL = prefix + 'content-worker.js';
-const metadata = require('@loader/options').metadata;
-
-// Fetch additional list of domains to authorize access to for each content
-// script. It is stored in manifest `metadata` field which contains
-// package.json data. This list is originaly defined by authors in
-// `permissions` attribute of their package.json addon file.
-const permissions = (metadata && metadata['permissions']) || {};
-const EXPANDED_PRINCIPALS = permissions['cross-domain-content'] || [];
-
-const waiveSecurityMembrane = !!permissions['unsafe-content-script'];
-
-const nsIScriptSecurityManager = Ci.nsIScriptSecurityManager;
-const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
- getService(Ci.nsIScriptSecurityManager);
-
-const JS_VERSION = '1.8';
-
-// Tests whether this window is loaded in a tab
-function isWindowInTab(window) {
- if (isChildLoader) {
- let { frames } = require('../remote/child');
- let frame = frames.getFrameForWindow(window.top);
- return frame && frame.isTab;
- }
- else {
- // The deprecated sync worker API still does everything in the main process
- return getTabForContentWindowNoShim(window);
- }
-}
-
-const WorkerSandbox = Class({
- implements: [ EventTarget ],
-
- /**
- * Emit a message to the worker content sandbox
- */
- emit: function emit(type, ...args) {
- // JSON.stringify is buggy with cross-sandbox values,
- // it may return "{}" on functions. Use a replacer to match them correctly.
- let replacer = (k, v) =>
- typeof(v) === "function"
- ? (type === "console" ? Function.toString.call(v) : void(0))
- : v;
-
- // Ensure having an asynchronous behavior
- async(() =>
- emitToContent(this, JSON.stringify([type, ...args], replacer))
- );
- },
-
- /**
- * Synchronous version of `emit`.
- * /!\ Should only be used when it is strictly mandatory /!\
- * Doesn't ensure passing only JSON values.
- * Mainly used by context-menu in order to avoid breaking it.
- */
- emitSync: function emitSync(...args) {
- // because the arguments could be also non JSONable values,
- // we need to ensure the array instance is created from
- // the content's sandbox
- return emitToContent(this, new modelFor(this).sandbox.Array(...args));
- },
-
- /**
- * Configures sandbox and loads content scripts into it.
- * @param {Worker} worker
- * content worker
- */
- initialize: function WorkerSandbox(worker, window) {
- let model = {};
- sandboxes.set(this, model);
- model.worker = worker;
- // We receive a wrapped window, that may be an xraywrapper if it's content
- let proto = window;
-
- // TODO necessary?
- // Ensure that `emit` has always the right `this`
- this.emit = this.emit.bind(this);
- this.emitSync = this.emitSync.bind(this);
-
- // Use expanded principal for content-script if the content is a
- // regular web content for better isolation.
- // (This behavior can be turned off for now with the unsafe-content-script
- // flag to give addon developers time for making the necessary changes)
- // But prevent it when the Worker isn't used for a content script but for
- // injecting `addon` object into a Panel scope, for example.
- // That's because:
- // 1/ It is useless to use multiple domains as the worker is only used
- // to communicate with the addon,
- // 2/ By using it it would prevent the document to have access to any JS
- // value of the worker. As JS values coming from multiple domain principals
- // can't be accessed by 'mono-principals' (principal with only one domain).
- // Even if this principal is for a domain that is specified in the multiple
- // domain principal.
- let principals = window;
- let wantGlobalProperties = [];
- let isSystemPrincipal = secMan.isSystemPrincipal(
- window.document.nodePrincipal);
- if (!isSystemPrincipal && !requiresAddonGlobal(worker)) {
- if (EXPANDED_PRINCIPALS.length > 0) {
- // We have to replace XHR constructor of the content document
- // with a custom cross origin one, automagically added by platform code:
- delete proto.XMLHttpRequest;
- wantGlobalProperties.push('XMLHttpRequest');
- }
- if (!waiveSecurityMembrane)
- principals = EXPANDED_PRINCIPALS.concat(window);
- }
-
- // Create the sandbox and bind it to window in order for content scripts to
- // have access to all standard globals (window, document, ...)
- let content = sandbox(principals, {
- sandboxPrototype: proto,
- wantXrays: !requiresAddonGlobal(worker),
- wantGlobalProperties: wantGlobalProperties,
- wantExportHelpers: true,
- sameZoneAs: window,
- metadata: {
- SDKContentScript: true,
- 'inner-window-id': getInnerId(window)
- }
- });
- model.sandbox = content;
-
- // We have to ensure that window.top and window.parent are the exact same
- // object than window object, i.e. the sandbox global object. But not
- // always, in case of iframes, top and parent are another window object.
- let top = window.top === window ? content : content.top;
- let parent = window.parent === window ? content : content.parent;
- merge(content, {
- // We need 'this === window === top' to be true in toplevel scope:
- get window() {
- return content;
- },
- get top() {
- return top;
- },
- get parent() {
- return parent;
- }
- });
-
- // Use the Greasemonkey naming convention to provide access to the
- // unwrapped window object so the content script can access document
- // JavaScript values.
- // NOTE: this functionality is experimental and may change or go away
- // at any time!
- //
- // Note that because waivers aren't propagated between origins, we
- // need the unsafeWindow getter to live in the sandbox.
- var unsafeWindowGetter =
- new content.Function('return window.wrappedJSObject || window;');
- Object.defineProperty(content, 'unsafeWindow', {get: unsafeWindowGetter});
-
- // Load trusted code that will inject content script API.
- let ContentWorker = load(content, CONTENT_WORKER_URL);
-
- // prepare a clean `self.options`
- let options = 'contentScriptOptions' in worker ?
- JSON.stringify(worker.contentScriptOptions) :
- undefined;
-
- // Then call `inject` method and communicate with this script
- // by trading two methods that allow to send events to the other side:
- // - `onEvent` called by content script
- // - `result.emitToContent` called by addon script
- let onEvent = Cu.exportFunction(onContentEvent.bind(null, this), ContentWorker);
- let chromeAPI = createChromeAPI(ContentWorker);
- let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options);
-
- // Merge `emitToContent` into our private model of the
- // WorkerSandbox so we can communicate with content script
- model.emitToContent = result;
-
- let console = new PlainTextConsole(null, getInnerId(window));
-
- // Handle messages send by this script:
- setListeners(this, console);
-
- // Inject `addon` global into target document if document is trusted,
- // `addon` in document is equivalent to `self` in content script.
- if (requiresAddonGlobal(worker)) {
- Object.defineProperty(getUnsafeWindow(window), 'addon', {
- value: content.self,
- configurable: true
- }
- );
- }
-
- // Inject our `console` into target document if worker doesn't have a tab
- // (e.g Panel, PageWorker).
- // `worker.tab` can't be used because bug 804935.
- if (!isWindowInTab(window)) {
- let win = getUnsafeWindow(window);
-
- // export our chrome console to content window, as described here:
- // https://developer.mozilla.org/en-US/docs/Components.utils.createObjectIn
- let con = Cu.createObjectIn(win);
-
- let genPropDesc = function genPropDesc(fun) {
- return { enumerable: true, configurable: true, writable: true,
- value: console[fun] };
- }
-
- const properties = {
- log: genPropDesc('log'),
- info: genPropDesc('info'),
- warn: genPropDesc('warn'),
- error: genPropDesc('error'),
- debug: genPropDesc('debug'),
- trace: genPropDesc('trace'),
- dir: genPropDesc('dir'),
- group: genPropDesc('group'),
- groupCollapsed: genPropDesc('groupCollapsed'),
- groupEnd: genPropDesc('groupEnd'),
- time: genPropDesc('time'),
- timeEnd: genPropDesc('timeEnd'),
- profile: genPropDesc('profile'),
- profileEnd: genPropDesc('profileEnd'),
- exception: genPropDesc('exception'),
- assert: genPropDesc('assert'),
- count: genPropDesc('count'),
- table: genPropDesc('table'),
- clear: genPropDesc('clear'),
- dirxml: genPropDesc('dirxml'),
- timeStamp: genPropDesc('timeStamp'),
- };
-
- Object.defineProperties(con, properties);
- Cu.makeObjectPropsNormal(con);
-
- win.console = con;
- };
-
- emit(events, "content-script-before-inserted", {
- window: window,
- worker: worker
- });
-
- // The order of `contentScriptFile` and `contentScript` evaluation is
- // intentional, so programs can load libraries like jQuery from script URLs
- // and use them in scripts.
- let contentScriptFile = ('contentScriptFile' in worker)
- ? worker.contentScriptFile
- : null,
- contentScript = ('contentScript' in worker)
- ? worker.contentScript
- : null;
-
- if (contentScriptFile)
- importScripts.apply(null, [this].concat(contentScriptFile));
-
- if (contentScript) {
- evaluateIn(
- this,
- Array.isArray(contentScript) ? contentScript.join(';\n') : contentScript
- );
- }
- },
- destroy: function destroy(reason) {
- if (typeof reason != 'string')
- reason = '';
- this.emitSync('event', 'detach', reason);
- let model = modelFor(this);
- model.sandbox = null
- model.worker = null;
- },
-
-});
-
-exports.WorkerSandbox = WorkerSandbox;
-
-/**
- * Imports scripts to the sandbox by reading files under urls and
- * evaluating its source. If exception occurs during evaluation
- * `'error'` event is emitted on the worker.
- * This is actually an analog to the `importScript` method in web
- * workers but in our case it's not exposed even though content
- * scripts may be able to do it synchronously since IO operation
- * takes place in the UI process.
- */
-function importScripts (workerSandbox, ...urls) {
- let { worker, sandbox } = modelFor(workerSandbox);
- for (let i in urls) {
- let contentScriptFile = data.url(urls[i]);
-
- try {
- let uri = URL(contentScriptFile);
- if (uri.scheme === 'resource')
- load(sandbox, String(uri));
- else
- throw Error('Unsupported `contentScriptFile` url: ' + String(uri));
- }
- catch(e) {
- emit(worker, 'error', e);
- }
- }
-}
-
-function setListeners (workerSandbox, console) {
- let { worker } = modelFor(workerSandbox);
- // console.xxx calls
- workerSandbox.on('console', function consoleListener (kind, ...args) {
- console[kind].apply(console, args);
- });
-
- // self.postMessage calls
- workerSandbox.on('message', function postMessage(data) {
- // destroyed?
- if (worker)
- emit(worker, 'message', data);
- });
-
- // self.port.emit calls
- workerSandbox.on('event', function portEmit (...eventArgs) {
- // If not destroyed, emit event information to worker
- // `eventArgs` has the event name as first element,
- // and remaining elements are additional arguments to pass
- if (worker)
- emit.apply(null, [worker.port].concat(eventArgs));
- });
-
- // unwrap, recreate and propagate async Errors thrown from content-script
- workerSandbox.on('error', function onError({instanceOfError, value}) {
- if (worker) {
- let error = value;
- if (instanceOfError) {
- error = new Error(value.message, value.fileName, value.lineNumber);
- error.stack = value.stack;
- error.name = value.name;
- }
- emit(worker, 'error', error);
- }
- });
-}
-
-/**
- * Evaluates code in the sandbox.
- * @param {String} code
- * JavaScript source to evaluate.
- * @param {String} [filename='javascript:' + code]
- * Name of the file
- */
-function evaluateIn (workerSandbox, code, filename) {
- let { worker, sandbox } = modelFor(workerSandbox);
- try {
- evaluate(sandbox, code, filename || 'javascript:' + code);
- }
- catch(e) {
- emit(worker, 'error', e);
- }
-}
-
-/**
- * Method called by the worker sandbox when it needs to send a message
- */
-function onContentEvent (workerSandbox, args) {
- // As `emit`, we ensure having an asynchronous behavior
- async(function () {
- // We emit event to chrome/addon listeners
- emit.apply(null, [workerSandbox].concat(JSON.parse(args)));
- });
-}
-
-
-function modelFor (workerSandbox) {
- return sandboxes.get(workerSandbox);
-}
-
-function getUnsafeWindow (win) {
- return win.wrappedJSObject || win;
-}
-
-function emitToContent (workerSandbox, args) {
- return modelFor(workerSandbox).emitToContent(args);
-}
-
-function createChromeAPI (scope) {
- return Cu.cloneInto({
- timers: {
- setTimeout: timer.setTimeout.bind(timer),
- setInterval: timer.setInterval.bind(timer),
- clearTimeout: timer.clearTimeout.bind(timer),
- clearInterval: timer.clearInterval.bind(timer),
- },
- sandbox: {
- evaluate: evaluate,
- },
- }, scope, {cloneFunctions: true});
-}
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/content/sandbox/events.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const events = {};
-exports.events = events;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/content/tab-events.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* 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 { Ci } = require('chrome');
-const system = require('sdk/system/events');
-const { frames } = require('sdk/remote/child');
-const { WorkerChild } = require('sdk/content/worker-child');
-
-// map observer topics to tab event names
-const EVENTS = {
- 'content-document-global-created': 'create',
- 'chrome-document-global-created': 'create',
- 'content-document-interactive': 'ready',
- 'chrome-document-interactive': 'ready',
- 'content-document-loaded': 'load',
- 'chrome-document-loaded': 'load',
-// 'content-page-shown': 'pageshow', // bug 1024105
-}
-
-function topicListener({ subject, type }) {
- // NOTE detect the window from the subject:
- // - on *-global-created the subject is the window
- // - in the other cases it is the document object
- let window = subject instanceof Ci.nsIDOMWindow ? subject : subject.defaultView;
- if (!window){
- return;
- }
- let frame = frames.getFrameForWindow(window);
- if (frame) {
- let readyState = frame.content.document.readyState;
- frame.port.emit('sdk/tab/event', EVENTS[type], { readyState });
- }
-}
-
-for (let topic in EVENTS)
- system.on(topic, topicListener, true);
-
-// bug 1024105 - content-page-shown notification doesn't pass persisted param
-function eventListener({target, type, persisted}) {
- let frame = this;
- if (target === frame.content.document) {
- frame.port.emit('sdk/tab/event', type, persisted);
- }
-}
-frames.addEventListener('pageshow', eventListener, true);
-
-frames.port.on('sdk/tab/attach', (frame, options) => {
- options.window = frame.content;
- new WorkerChild(options);
-});
-
-// Forward the existent frames's readyState.
-for (let frame of frames) {
- let readyState = frame.content.document.readyState;
- frame.port.emit('sdk/tab/event', 'init', { readyState });
-}
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/content/worker-child.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/* 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';
-
-lazyRequire(this, '../util/object', 'merge');
-const { Class } = require('../core/heritage');
-lazyRequire(this, '../event/core', 'emit');
-const { EventTarget } = require('../event/target');
-lazyRequire(this, '../window/utils', 'getInnerId');
-lazyRequire(this, '../lang/type', 'instanceOf', 'isObject');
-lazyRequireModule(this, '../system/events', 'system');
-const { when } = require('../system/unload');
-lazyRequire(this, './sandbox', 'WorkerSandbox');
-const { Ci } = require('chrome');
-const { process, frames } = require('../remote/child');
-
-const EVENTS = {
- 'chrome-page-shown': 'pageshow',
- 'content-page-shown': 'pageshow',
- 'chrome-page-hidden': 'pagehide',
- 'content-page-hidden': 'pagehide',
- 'inner-window-destroyed': 'detach',
-}
-
-// The parent Worker must have been created (or an async message sent to spawn
-// its creation) before creating the WorkerChild or messages from the content
-// script to the parent will get lost.
-const WorkerChild = Class({
- implements: [EventTarget],
-
- initialize(options) {
- merge(this, options);
- keepAlive.set(this.id, this);
-
- this.windowId = getInnerId(this.window);
- if (this.contentScriptOptions)
- this.contentScriptOptions = JSON.parse(this.contentScriptOptions);
-
- this.port = EventTarget();
- this.port.on('*', this.send.bind(this, 'event'));
- this.on('*', this.send.bind(this));
-
- this.observe = this.observe.bind(this);
-
- for (let topic in EVENTS)
- system.on(topic, this.observe);
-
- this.receive = this.receive.bind(this);
- process.port.on('sdk/worker/message', this.receive);
-
- this.sandbox = WorkerSandbox(this, this.window);
-
- // If the document has an unexpected readyState, its worker-child instance is initialized
- // as frozen until one of the known readyState is reached.
- let initialDocumentReadyState = this.window.document.readyState;
- this.frozen = [
- "loading", "interactive", "complete"
- ].includes(initialDocumentReadyState) ? false : true;
-
- if (this.frozen) {
- console.warn("SDK worker-child started as frozen on unexpected initial document.readyState", {
- initialDocumentReadyState, windowLocation: this.window.location.href,
- });
- }
-
- this.frozenMessages = [];
- this.on('pageshow', () => {
- this.frozen = false;
- this.frozenMessages.forEach(args => this.sandbox.emit(...args));
- this.frozenMessages = [];
- });
- this.on('pagehide', () => {
- this.frozen = true;
- });
- },
-
- // messages
- receive(process, id, args) {
- if (id !== this.id)
- return;
- args = JSON.parse(args);
-
- if (this.frozen)
- this.frozenMessages.push(args);
- else
- this.sandbox.emit(...args);
-
- if (args[0] === 'detach')
- this.destroy(args[1]);
- },
-
- send(...args) {
- process.port.emit('sdk/worker/event', this.id, JSON.stringify(args, exceptions));
- },
-
- // notifications
- observe({ type, subject }) {
- if (!this.sandbox)
- return;
-
- if (subject.defaultView && getInnerId(subject.defaultView) === this.windowId) {
- this.sandbox.emitSync(EVENTS[type]);
- emit(this, EVENTS[type]);
- }
-
- if (type === 'inner-window-destroyed' &&
- subject.QueryInterface(Ci.nsISupportsPRUint64).data === this.windowId) {
- this.destroy();
- }
- },
-
- get frame() {
- return frames.getFrameForWindow(this.window.top);
- },
-
- // detach/destroy: unload and release the sandbox
- destroy(reason) {
- if (!this.sandbox)
- return;
-
- for (let topic in EVENTS)
- system.off(topic, this.observe);
- process.port.off('sdk/worker/message', this.receive);
-
- this.sandbox.destroy(reason);
- this.sandbox = null;
- keepAlive.delete(this.id);
-
- this.send('detach');
- }
-})
-exports.WorkerChild = WorkerChild;
-
-// Error instances JSON poorly
-function exceptions(key, value) {
- if (!isObject(value) || !instanceOf(value, Error))
- return value;
- let _errorType = value.constructor.name;
- let { message, fileName, lineNumber, stack, name } = value;
- return { _errorType, message, fileName, lineNumber, stack, name };
-}
-
-// workers for windows in this tab
-var keepAlive = new Map();
-
-process.port.on('sdk/worker/create', (process, options, cpows) => {
- options.window = cpows.window;
- let worker = new WorkerChild(options);
-
- let frame = frames.getFrameForWindow(options.window.top);
- frame.port.emit('sdk/worker/connect', options.id, options.window.location.href);
-});
-
-when(reason => {
- for (let worker of keepAlive.values())
- worker.destroy(reason);
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/content/worker.js
+++ /dev/null
@@ -1,180 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-lazyRequire(this, '../event/core', "emit");
-const { omit, merge } = require('../util/object');
-const { Class } = require('../core/heritage');
-const { method } = require('../lang/functional');
-lazyRequire(this, '../window/utils', "getInnerId");
-const { EventTarget } = require('../event/target');
-lazyRequire(this, '../private-browsing/utils', "isPrivate");
-lazyRequire(this, '../tabs/utils', "getTabForBrowser", "getTabForContentWindowNoShim", "getBrowserForTab");
-lazyRequire(this, './utils', "attach", "connect", "detach", "destroy", "makeChildOptions");
-const { ensure } = require('../system/unload');
-lazyRequire(this, '../system/events', {"on": "observe"});
-const { Ci, Cu } = require('chrome');
-lazyRequire(this, 'sdk/model/core', {"modelFor": "tabFor"});
-const { remoteRequire, processes, frames } = require('../remote/parent');
-remoteRequire('sdk/content/worker-child');
-
-const workers = new WeakMap();
-var modelFor = (worker) => workers.get(worker);
-
-const ERR_DESTROYED = "Couldn't find the worker to receive this message. " +
- "The script may not be initialized yet, or may already have been unloaded.";
-
-// a handle for communication between content script and addon code
-const Worker = Class({
- implements: [EventTarget],
-
- initialize(options = {}) {
- ensure(this, 'detach');
-
- let model = {
- attached: false,
- destroyed: false,
- earlyEvents: [], // fired before worker was attached
- frozen: true, // document is not yet active
- options,
- };
- workers.set(this, model);
-
- this.on('detach', this.detach);
- EventTarget.prototype.initialize.call(this, options);
-
- this.receive = this.receive.bind(this);
-
- this.port = EventTarget();
- this.port.emit = this.send.bind(this, 'event');
- this.postMessage = this.send.bind(this, 'message');
-
- if ('window' in options) {
- let window = options.window;
- delete options.window;
- attach(this, window);
- }
- },
-
- // messages
- receive(process, id, args) {
- let model = modelFor(this);
- if (id !== model.id || !model.attached)
- return;
- args = JSON.parse(args);
- if (model.destroyed && args[0] != 'detach')
- return;
-
- if (args[0] === 'event')
- emit(this.port, ...args.slice(1))
- else
- emit(this, ...args);
- },
-
- send(...args) {
- let model = modelFor(this);
- if (model.destroyed && args[0] !== 'detach')
- throw new Error(ERR_DESTROYED);
-
- if (!model.attached) {
- model.earlyEvents.push(args);
- return;
- }
-
- processes.port.emit('sdk/worker/message', model.id, JSON.stringify(args));
- },
-
- // properties
- get url() {
- let { url } = modelFor(this);
- return url;
- },
-
- get contentURL() {
- return this.url;
- },
-
- get tab() {
- require('sdk/tabs');
- let { frame } = modelFor(this);
- if (!frame)
- return null;
- let rawTab = getTabForBrowser(frame.frameElement);
- return rawTab && tabFor(rawTab);
- },
-
- toString: () => '[object Worker]',
-
- detach: method(detach),
- destroy: method(destroy),
-})
-exports.Worker = Worker;
-
-attach.define(Worker, function(worker, window) {
- let model = modelFor(worker);
- if (model.attached)
- detach(worker);
-
- let childOptions = makeChildOptions(model.options);
- processes.port.emitCPOW('sdk/worker/create', [childOptions], { window });
-
- let listener = (frame, id, url) => {
- if (id != childOptions.id)
- return;
- frames.port.off('sdk/worker/connect', listener);
- connect(worker, frame, { id, url });
- };
- frames.port.on('sdk/worker/connect', listener);
-});
-
-connect.define(Worker, function(worker, frame, { id, url }) {
- let model = modelFor(worker);
- if (model.attached)
- detach(worker);
-
- model.id = id;
- model.frame = frame;
- model.url = url;
-
- // Messages from content -> chrome come through the process message manager
- // since that lives longer than the frame message manager
- processes.port.on('sdk/worker/event', worker.receive);
-
- model.attached = true;
- model.destroyed = false;
- model.frozen = false;
-
- model.earlyEvents.forEach(args => worker.send(...args));
- model.earlyEvents = [];
- emit(worker, 'attach');
-});
-
-// unload and release the child worker, release window reference
-detach.define(Worker, function(worker) {
- let model = modelFor(worker);
- if (!model.attached)
- return;
-
- processes.port.off('sdk/worker/event', worker.receive);
- model.attached = false;
- model.destroyed = true;
- emit(worker, 'detach');
-});
-
-isPrivate.define(Worker, ({ tab }) => isPrivate(tab));
-
-// Something in the parent side has destroyed the worker, tell the child to
-// detach, the child will respond when it has detached
-destroy.define(Worker, function(worker, reason) {
- let model = modelFor(worker);
- model.destroyed = true;
- if (!model.attached)
- return;
-
- worker.send('detach', reason);
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/deprecated/sync-worker.js
+++ /dev/null
@@ -1,288 +0,0 @@
-/* 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/. */
-
-/**
- *
- * `deprecated/sync-worker` was previously `content/worker`, that was
- * incompatible with e10s. we are in the process of switching to the new
- * asynchronous `Worker`, which behaves slightly differently in some edge
- * cases, so we are keeping this one around for a short period.
- * try to switch to the new one as soon as possible..
- *
- */
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { Class } = require('../core/heritage');
-const { EventTarget } = require('../event/target');
-const { on, off, emit, setListeners } = require('../event/core');
-const {
- attach, detach, destroy
-} = require('../content/utils');
-const { method } = require('../lang/functional');
-const { Ci, Cu, Cc } = require('chrome');
-const unload = require('../system/unload');
-const events = require('../system/events');
-const { getInnerId } = require("../window/utils");
-const { WorkerSandbox } = require('../content/sandbox');
-const { isPrivate } = require('../private-browsing/utils');
-
-// A weak map of workers to hold private attributes that
-// should not be exposed
-const workers = new WeakMap();
-
-var modelFor = (worker) => workers.get(worker);
-
-const ERR_DESTROYED =
- "Couldn't find the worker to receive this message. " +
- "The script may not be initialized yet, or may already have been unloaded.";
-
-const ERR_FROZEN = "The page is currently hidden and can no longer be used " +
- "until it is visible again.";
-
-/**
- * Message-passing facility for communication between code running
- * in the content and add-on process.
- * @see https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/content_worker
- */
-const Worker = Class({
- implements: [EventTarget],
- initialize: function WorkerConstructor (options) {
- // Save model in weak map to not expose properties
- let model = createModel();
- workers.set(this, model);
-
- options = options || {};
-
- if ('contentScriptFile' in options)
- this.contentScriptFile = options.contentScriptFile;
- if ('contentScriptOptions' in options)
- this.contentScriptOptions = options.contentScriptOptions;
- if ('contentScript' in options)
- this.contentScript = options.contentScript;
- if ('injectInDocument' in options)
- this.injectInDocument = !!options.injectInDocument;
-
- setListeners(this, options);
-
- unload.ensure(this, "destroy");
-
- // Ensure that worker.port is initialized for contentWorker to be able
- // to send events during worker initialization.
- this.port = createPort(this);
-
- model.documentUnload = documentUnload.bind(this);
- model.pageShow = pageShow.bind(this);
- model.pageHide = pageHide.bind(this);
-
- if ('window' in options)
- attach(this, options.window);
- },
-
- /**
- * Sends a message to the worker's global scope. Method takes single
- * argument, which represents data to be sent to the worker. The data may
- * be any primitive type value or `JSON`. Call of this method asynchronously
- * emits `message` event with data value in the global scope of this
- * worker.
- *
- * `message` event listeners can be set either by calling
- * `self.on` with a first argument string `"message"` or by
- * implementing `onMessage` function in the global scope of this worker.
- * @param {Number|String|JSON} data
- */
- postMessage: function (...data) {
- let model = modelFor(this);
- let args = ['message'].concat(data);
- if (!model.inited) {
- model.earlyEvents.push(args);
- return;
- }
- processMessage.apply(null, [this].concat(args));
- },
-
- get url () {
- let model = modelFor(this);
- // model.window will be null after detach
- return model.window ? model.window.document.location.href : null;
- },
-
- get contentURL () {
- let model = modelFor(this);
- return model.window ? model.window.document.URL : null;
- },
-
- // Implemented to provide some of the previous features of exposing sandbox
- // so that Worker can be extended
- getSandbox: function () {
- return modelFor(this).contentWorker;
- },
-
- toString: function () { return '[object Worker]'; },
- attach: method(attach),
- detach: method(detach),
- destroy: method(destroy)
-});
-exports.Worker = Worker;
-
-attach.define(Worker, function (worker, window) {
- let model = modelFor(worker);
- model.window = window;
- // Track document unload to destroy this worker.
- // We can't watch for unload event on page's window object as it
- // prevents bfcache from working:
- // https://developer.mozilla.org/En/Working_with_BFCache
- model.windowID = getInnerId(model.window);
- events.on("inner-window-destroyed", model.documentUnload);
-
- // will set model.contentWorker pointing to the private API:
- model.contentWorker = WorkerSandbox(worker, model.window);
-
- // Listen to pagehide event in order to freeze the content script
- // while the document is frozen in bfcache:
- model.window.addEventListener("pageshow", model.pageShow, true);
- model.window.addEventListener("pagehide", model.pageHide, true);
-
- // Mainly enable worker.port.emit to send event to the content worker
- model.inited = true;
- model.frozen = false;
-
- // Fire off `attach` event
- emit(worker, 'attach', window);
-
- // Process all events and messages that were fired before the
- // worker was initialized.
- model.earlyEvents.forEach(args => processMessage.apply(null, [worker].concat(args)));
-});
-
-/**
- * Remove all internal references to the attached document
- * Tells _port to unload itself and removes all the references from itself.
- */
-detach.define(Worker, function (worker, reason) {
- let model = modelFor(worker);
-
- // maybe unloaded before content side is created
- if (model.contentWorker) {
- model.contentWorker.destroy(reason);
- }
-
- model.contentWorker = null;
- if (model.window) {
- model.window.removeEventListener("pageshow", model.pageShow, true);
- model.window.removeEventListener("pagehide", model.pageHide, true);
- }
- model.window = null;
- // This method may be called multiple times,
- // avoid dispatching `detach` event more than once
- if (model.windowID) {
- model.windowID = null;
- events.off("inner-window-destroyed", model.documentUnload);
- model.earlyEvents.length = 0;
- emit(worker, 'detach');
- }
- model.inited = false;
-});
-
-isPrivate.define(Worker, ({ tab }) => isPrivate(tab));
-
-/**
- * Tells content worker to unload itself and
- * removes all the references from itself.
- */
-destroy.define(Worker, function (worker, reason) {
- detach(worker, reason);
- modelFor(worker).inited = true;
- // Specifying no type or listener removes all listeners
- // from target
- off(worker);
- off(worker.port);
-});
-
-/**
- * Events fired by workers
- */
-function documentUnload ({ subject, data }) {
- let model = modelFor(this);
- let innerWinID = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
- if (innerWinID != model.windowID) return false;
- detach(this);
- return true;
-}
-
-function pageShow () {
- let model = modelFor(this);
- model.contentWorker.emitSync('pageshow');
- emit(this, 'pageshow');
- model.frozen = false;
-}
-
-function pageHide () {
- let model = modelFor(this);
- model.contentWorker.emitSync('pagehide');
- emit(this, 'pagehide');
- model.frozen = true;
-}
-
-/**
- * Fired from postMessage and emitEventToContent, or from the earlyMessage
- * queue when fired before the content is loaded. Sends arguments to
- * contentWorker if able
- */
-
-function processMessage (worker, ...args) {
- let model = modelFor(worker) || {};
- if (!model.contentWorker)
- throw new Error(ERR_DESTROYED);
- if (model.frozen)
- throw new Error(ERR_FROZEN);
- model.contentWorker.emit.apply(null, args);
-}
-
-function createModel () {
- return {
- // List of messages fired before worker is initialized
- earlyEvents: [],
- // Is worker connected to the content worker sandbox ?
- inited: false,
- // Is worker being frozen? i.e related document is frozen in bfcache.
- // Content script should not be reachable if frozen.
- frozen: true,
- /**
- * Reference to the content side of the worker.
- * @type {WorkerGlobalScope}
- */
- contentWorker: null,
- /**
- * Reference to the window that is accessible from
- * the content scripts.
- * @type {Object}
- */
- window: null
- };
-}
-
-function createPort (worker) {
- let port = EventTarget();
- port.emit = emitEventToContent.bind(null, worker);
- return port;
-}
-
-/**
- * Emit a custom event to the content script,
- * i.e. emit this event on `self.port`
- */
-function emitEventToContent (worker, ...eventArgs) {
- let model = modelFor(worker);
- let args = ['event'].concat(eventArgs);
- if (!model.inited) {
- model.earlyEvents.push(args);
- return;
- }
- processMessage.apply(null, [worker].concat(args));
-}
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
@@ -29,25 +29,23 @@ const findAndRunTests = function findAnd
stopOnError: options.stopOnError,
onDone: options.onDone
});
});
};
exports.findAndRunTests = findAndRunTests;
var runnerWindows = new WeakMap();
-var runnerTabs = new WeakMap();
const TestRunner = function TestRunner(options) {
options = options || {};
// remember the id's for the open window and tab
let window = getMostRecentBrowserWindow();
runnerWindows.set(this, getInnerId(window));
- runnerTabs.set(this, getTabId(getSelectedTab(window)));
this.fs = options.fs;
this.console = options.console || console;
this.passed = 0;
this.failed = 0;
this.testRunSummary = [];
this.expectFailNesting = 0;
this.done = TestRunner.prototype.done.bind(this);
@@ -325,41 +323,28 @@ TestRunner.prototype = {
});
PromiseDebugging.flushUncaughtErrors();
PromiseDebugging.removeUncaughtErrorObserver(this._uncaughtErrorObserver);
return all(winPromises).then(() => {
let browserWins = wins.filter(isBrowser);
- let tabs = browserWins.reduce((tabs, window) => tabs.concat(getTabs(window)), []);
- let newTabID = getTabId(getSelectedTab(wins[0]));
- let oldTabID = runnerTabs.get(this);
- let hasMoreTabsOpen = browserWins.length && tabs.length != 1;
let failure = false;
if (wins.length != 1 || getInnerId(wins[0]) !== runnerWindows.get(this)) {
failure = true;
this.fail("Should not be any unexpected windows open");
}
- else if (hasMoreTabsOpen) {
- failure = true;
- this.fail("Should not be any unexpected tabs open");
- }
- else if (oldTabID != newTabID) {
- failure = true;
- runnerTabs.set(this, newTabID);
- this.fail("Should not be any new tabs left open, old id: " + oldTabID + " new id: " + newTabID);
- }
if (failure) {
console.log("Windows open:");
for (let win of wins) {
if (isBrowser(win)) {
- tabs = getTabs(win);
+ tabs = [];
console.log(win.location + " - " + tabs.map(getURI).join(", "));
}
else {
console.log(win.location);
}
}
}
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/loader/sandbox.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const { Cc, Ci, CC, Cu } = require('chrome');
-const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
-const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
- getService(Ci.mozIJSSubScriptLoader);
-const self = require('sdk/self');
-const { getTabId } = require('../tabs/utils');
-const { getInnerId } = require('../window/utils');
-
-/**
- * Make a new sandbox that inherits given `source`'s principals. Source can be
- * URI string, DOMWindow or `null` for system principals.
- */
-function sandbox(target, options) {
- options = options || {};
- options.metadata = options.metadata ? options.metadata : {};
- options.metadata.addonID = options.metadata.addonID ?
- options.metadata.addonID : self.id;
-
- let sandbox = Cu.Sandbox(target || systemPrincipal, options);
- Cu.setSandboxMetadata(sandbox, options.metadata);
- return sandbox;
-}
-exports.sandbox = sandbox;
-
-/**
- * Evaluates given `source` in a given `sandbox` and returns result.
- */
-function evaluate(sandbox, code, uri, line, version) {
- return Cu.evalInSandbox(code, sandbox, version || '1.8', uri || '', line || 1);
-}
-exports.evaluate = evaluate;
-
-/**
- * Evaluates code under the given `uri` in the given `sandbox`.
- *
- * @param {String} uri
- * The URL pointing to the script to load.
- * It must be a local chrome:, resource:, file: or data: URL.
- */
-function load(sandbox, uri) {
- if (uri.indexOf('data:') === 0) {
- let source = uri.substr(uri.indexOf(',') + 1);
-
- return evaluate(sandbox, decodeURIComponent(source), '1.8', uri, 0);
- } else {
- return scriptLoader.loadSubScriptWithOptions(uri, {target: sandbox,
- charset: 'UTF-8',
- wantReturnValue: true});
- }
-}
-exports.load = load;
-
-/**
- * Forces the given `sandbox` to be freed immediately.
- */
-exports.nuke = Cu.nukeSandbox
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/remote/child.js
+++ /dev/null
@@ -1,284 +0,0 @@
-/* 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 { isChildLoader } = require('./core');
-if (!isChildLoader)
- throw new Error("Cannot load sdk/remote/child in a main process loader.");
-
-const { Ci, Cc, Cu } = require('chrome');
-const runtime = require('../system/runtime');
-const { Class } = require('../core/heritage');
-const { Namespace } = require('../core/namespace');
-const { omit } = require('../util/object');
-const { when } = require('../system/unload');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const { Disposable } = require('../core/disposable');
-const { EventParent } = require('./utils');
-const { addListItem, removeListItem } = require('../util/list');
-
-const loaderID = require('@loader/options').loaderID;
-
-const MAIN_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-
-const mm = Cc['@mozilla.org/childprocessmessagemanager;1'].
- getService(Ci.nsISyncMessageSender);
-
-const ns = Namespace();
-
-const process = {
- port: new EventTarget(),
- get id() {
- return runtime.processID;
- },
- get isRemote() {
- return runtime.processType != MAIN_PROCESS;
- }
-};
-exports.process = process;
-
-function definePort(obj, name) {
- obj.port.emit = (event, ...args) => {
- let manager = ns(obj).messageManager;
- if (!manager)
- return;
-
- manager.sendAsyncMessage(name, { loaderID, event, args });
- };
-}
-
-function messageReceived({ data, objects }) {
- // Ignore messages from other loaders
- if (data.loaderID != loaderID)
- return;
-
- let keys = Object.keys(objects);
- if (keys.length) {
- // If any objects are CPOWs then ignore this message. We don't want child
- // processes interracting with CPOWs
- if (!keys.every(name => !Cu.isCrossProcessWrapper(objects[name])))
- return;
-
- data.args.push(objects);
- }
-
- emit(this.port, data.event, this, ...data.args);
-}
-
-ns(process).messageManager = mm;
-definePort(process, 'sdk/remote/process/message');
-let processMessageReceived = messageReceived.bind(process);
-mm.addMessageListener('sdk/remote/process/message', processMessageReceived);
-
-when(() => {
- mm.removeMessageListener('sdk/remote/process/message', processMessageReceived);
- frames = null;
-});
-
-process.port.on('sdk/remote/require', (process, uri) => {
- require(uri);
-});
-
-function listenerEquals(a, b) {
- for (let prop of ["type", "callback", "isCapturing"]) {
- if (a[prop] != b[prop])
- return false;
- }
- return true;
-}
-
-function listenerFor(type, callback, isCapturing = false) {
- return {
- type,
- callback,
- isCapturing,
- registeredCallback: undefined,
- get args() {
- return [
- this.type,
- this.registeredCallback ? this.registeredCallback : this.callback,
- this.isCapturing
- ];
- }
- };
-}
-
-function removeListenerFromArray(array, listener) {
- let index = array.findIndex(l => listenerEquals(l, listener));
- if (index < 0)
- return;
- array.splice(index, 1);
-}
-
-function getListenerFromArray(array, listener) {
- return array.find(l => listenerEquals(l, listener));
-}
-
-function arrayContainsListener(array, listener) {
- return !!getListenerFromArray(array, listener);
-}
-
-function makeFrameEventListener(frame, callback) {
- return callback.bind(frame);
-}
-
-var FRAME_ID = 0;
-var tabMap = new Map();
-
-const Frame = Class({
- implements: [ Disposable ],
- extends: EventTarget,
- setup: function(contentFrame) {
- // This ID should be unique for this loader across all processes
- let priv = ns(this);
-
- priv.id = runtime.processID + ":" + FRAME_ID++;
-
- priv.contentFrame = contentFrame;
- priv.messageManager = contentFrame;
- priv.domListeners = [];
-
- tabMap.set(contentFrame.docShell, this);
-
- priv.messageReceived = messageReceived.bind(this);
- priv.messageManager.addMessageListener('sdk/remote/frame/message', priv.messageReceived);
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/frame/message');
-
- priv.messageManager.sendAsyncMessage('sdk/remote/frame/attach', {
- loaderID,
- frameID: priv.id,
- processID: runtime.processID
- });
-
- frames.attachItem(this);
- },
-
- dispose: function() {
- let priv = ns(this);
-
- emit(this, 'detach', this);
-
- for (let listener of priv.domListeners)
- priv.contentFrame.removeEventListener(...listener.args);
-
- priv.messageManager.removeMessageListener('sdk/remote/frame/message', priv.messageReceived);
- tabMap.delete(priv.contentFrame.docShell);
- priv.contentFrame = null;
- },
-
- get content() {
- return ns(this).contentFrame.content;
- },
-
- get isTab() {
- let docShell = ns(this).contentFrame.docShell;
- if (process.isRemote) {
- // We don't want to roundtrip to the main process to get this property.
- // This hack relies on the host app having defined webBrowserChrome only
- // in frames that are part of the tabs. Since only Firefox has remote
- // processes right now and does this this works.
- let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsITabChild);
- return !!tabchild.webBrowserChrome;
- }
- else {
- // This is running in the main process so we can break out to the browser
- // And check we can find a tab for the browser element directly.
- let browser = docShell.chromeEventHandler;
- let tab = require('../tabs/utils').getTabForBrowser(browser);
- return !!tab;
- }
- },
-
- addEventListener: function(...args) {
- let priv = ns(this);
-
- let listener = listenerFor(...args);
- if (arrayContainsListener(priv.domListeners, listener))
- return;
-
- listener.registeredCallback = makeFrameEventListener(this, listener.callback);
-
- priv.domListeners.push(listener);
- priv.contentFrame.addEventListener(...listener.args);
- },
-
- removeEventListener: function(...args) {
- let priv = ns(this);
-
- let listener = getListenerFromArray(priv.domListeners, listenerFor(...args));
- if (!listener)
- return;
-
- removeListenerFromArray(priv.domListeners, listener);
- priv.contentFrame.removeEventListener(...listener.args);
- }
-});
-
-const FrameList = Class({
- implements: [ EventParent, Disposable ],
- extends: EventTarget,
- setup: function() {
- EventParent.prototype.initialize.call(this);
-
- this.port = new EventTarget();
- ns(this).domListeners = [];
-
- this.on('attach', frame => {
- for (let listener of ns(this).domListeners)
- frame.addEventListener(...listener.args);
- });
- },
-
- dispose: function() {
- // The only case where we get destroyed is when the loader is unloaded in
- // which case each frame will clean up its own event listeners.
- ns(this).domListeners = null;
- },
-
- getFrameForWindow: function(window) {
- let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDocShell);
-
- return tabMap.get(docShell) || null;
- },
-
- addEventListener: function(...args) {
- let listener = listenerFor(...args);
- if (arrayContainsListener(ns(this).domListeners, listener))
- return;
-
- ns(this).domListeners.push(listener);
- for (let frame of this)
- frame.addEventListener(...listener.args);
- },
-
- removeEventListener: function(...args) {
- let listener = listenerFor(...args);
- if (!arrayContainsListener(ns(this).domListeners, listener))
- return;
-
- removeListenerFromArray(ns(this).domListeners, listener);
- for (let frame of this)
- frame.removeEventListener(...listener.args);
- }
-});
-var frames = exports.frames = new FrameList();
-
-function registerContentFrame(contentFrame) {
- let frame = new Frame(contentFrame);
-}
-exports.registerContentFrame = registerContentFrame;
-
-function unregisterContentFrame(contentFrame) {
- let frame = tabMap.get(contentFrame.docShell);
- if (!frame)
- return;
-
- frame.destroy();
-}
-exports.unregisterContentFrame = unregisterContentFrame;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/remote/core.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/* 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 options = require("@loader/options");
-
-exports.isChildLoader = options.childLoader;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/remote/parent.js
+++ /dev/null
@@ -1,334 +0,0 @@
-/* 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 { isChildLoader } = require('./core');
-if (isChildLoader)
- throw new Error("Cannot load sdk/remote/parent in a child loader.");
-
-const { Cu, Ci, Cc } = require('chrome');
-const runtime = require('../system/runtime');
-
-const MAIN_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-
-if (runtime.processType != MAIN_PROCESS) {
- throw new Error('Cannot use sdk/remote/parent in a child process.');
-}
-
-const { Class } = require('../core/heritage');
-const { Namespace } = require('../core/namespace');
-const { Disposable } = require('../core/disposable');
-const { omit } = require('../util/object');
-const { when } = require('../system/unload');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const system = require('../system/events');
-const { EventParent } = require('./utils');
-const options = require('@loader/options');
-const loaderModule = require('toolkit/loader');
-
-lazyRequire(this, '../tabs/utils', "getTabForBrowser");
-
-const appInfo = Cc["@mozilla.org/xre/app-info;1"].
- getService(Ci.nsIXULRuntime);
-
-exports.useRemoteProcesses = appInfo.browserTabsRemoteAutostart;
-
-// Chose the right function for resolving relative a module id
-var moduleResolve;
-if (options.isNative) {
- moduleResolve = (id, requirer) => loaderModule.nodeResolve(id, requirer, { rootURI: options.rootURI });
-}
-else {
- moduleResolve = loaderModule.resolve;
-}
-
-// Load the scripts in the child processes
-var { getNewLoaderID } = require('../../framescript/FrameScriptManager.jsm');
-var PATH = options.paths[''];
-
-const childOptions = omit(options, ['modules', 'globals', 'resolve', 'load']);
-childOptions.modules = {};
-// @l10n/data is just JSON data and can be safely sent across to the child loader
-try {
- childOptions.modules["@l10n/data"] = require("@l10n/data");
-}
-catch (e) {
- // There may be no l10n data
-}
-const loaderID = getNewLoaderID();
-childOptions.loaderID = loaderID;
-childOptions.childLoader = true;
-
-const ppmm = Cc['@mozilla.org/parentprocessmessagemanager;1'].
- getService(Ci.nsIMessageBroadcaster);
-const gmm = Cc['@mozilla.org/globalmessagemanager;1'].
- getService(Ci.nsIMessageBroadcaster);
-
-const ns = Namespace();
-
-var processMap = new Map();
-
-function definePort(obj, name) {
- obj.port.emitCPOW = (event, args, cpows = {}) => {
- let manager = ns(obj).messageManager;
- if (!manager)
- return;
-
- let method = manager instanceof Ci.nsIMessageBroadcaster ?
- "broadcastAsyncMessage" : "sendAsyncMessage";
-
- manager[method](name, { loaderID, event, args }, cpows);
- };
-
- obj.port.emit = (event, ...args) => obj.port.emitCPOW(event, args);
-}
-
-function messageReceived({ target, data }) {
- // Ignore messages from other loaders
- if (data.loaderID != loaderID)
- return;
-
- emit(this.port, data.event, this, ...data.args);
-}
-
-// Process represents a gecko process that can load webpages. Each process
-// contains a number of Frames. This class is used to send and receive messages
-// from a single process.
-const Process = Class({
- implements: [ Disposable ],
- extends: EventTarget,
- setup: function(id, messageManager, isRemote) {
- ns(this).id = id;
- ns(this).isRemote = isRemote;
- ns(this).messageManager = messageManager;
- ns(this).messageReceived = messageReceived.bind(this);
- this.destroy = this.destroy.bind(this);
- ns(this).messageManager.addMessageListener('sdk/remote/process/message', ns(this).messageReceived);
- ns(this).messageManager.addMessageListener('child-process-shutdown', this.destroy);
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/process/message');
-
- // Load any remote modules
- for (let module of remoteModules.values())
- this.port.emit('sdk/remote/require', module);
-
- processMap.set(ns(this).id, this);
- processes.attachItem(this);
- },
-
- dispose: function() {
- emit(this, 'detach', this);
- processMap.delete(ns(this).id);
- ns(this).messageManager.removeMessageListener('sdk/remote/process/message', ns(this).messageReceived);
- ns(this).messageManager.removeMessageListener('child-process-shutdown', this.destroy);
- ns(this).messageManager = null;
- },
-
- // Returns true if this process is a child process
- get isRemote() {
- return ns(this).isRemote;
- }
-});
-
-// Processes gives an API for enumerating an sending and receiving messages from
-// all processes as well as detecting when a new process starts.
-const Processes = Class({
- implements: [ EventParent ],
- extends: EventTarget,
- initialize: function() {
- EventParent.prototype.initialize.call(this);
- ns(this).messageManager = ppmm;
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/process/message');
- },
-
- getById: function(id) {
- return processMap.get(id);
- }
-});
-var processes = exports.processes = new Processes();
-
-var frameMap = new Map();
-
-function setFrameProcess(frame, process) {
- ns(frame).process = process;
- frames.attachItem(frame);
-}
-
-// Frames display webpages in a process. In the main process every Frame is
-// linked with a <browser> or <iframe> element.
-const Frame = Class({
- implements: [ Disposable ],
- extends: EventTarget,
- setup: function(id, node) {
- ns(this).id = id;
- ns(this).node = node;
-
- let frameLoader = node.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
- ns(this).messageManager = frameLoader.messageManager;
-
- ns(this).messageReceived = messageReceived.bind(this);
- ns(this).messageManager.addMessageListener('sdk/remote/frame/message', ns(this).messageReceived);
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/frame/message');
-
- frameMap.set(ns(this).messageManager, this);
- },
-
- dispose: function() {
- emit(this, 'detach', this);
- ns(this).messageManager.removeMessageListener('sdk/remote/frame/message', ns(this).messageReceived);
-
- frameMap.delete(ns(this).messageManager);
- ns(this).messageManager = null;
- },
-
- // Returns the browser or iframe element this frame displays in
- get frameElement() {
- return ns(this).node;
- },
-
- // Returns the process that this frame loads in
- get process() {
- return ns(this).process;
- },
-
- // Returns true if this frame is a tab in a main browser window
- get isTab() {
- let tab = getTabForBrowser(ns(this).node);
- return !!tab;
- }
-});
-
-function managerDisconnected({ subject: manager }) {
- let frame = frameMap.get(manager);
- if (frame)
- frame.destroy();
-}
-system.on('message-manager-disconnect', managerDisconnected);
-
-// Provides an API for enumerating and sending and receiving messages from all
-// Frames
-const FrameList = Class({
- implements: [ EventParent ],
- extends: EventTarget,
- initialize: function() {
- EventParent.prototype.initialize.call(this);
- ns(this).messageManager = gmm;
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/frame/message');
- },
-
- // Returns the frame for a browser element
- getFrameForBrowser: function(browser) {
- for (let frame of this) {
- if (frame.frameElement == browser)
- return frame;
- }
- return null;
- },
-});
-var frames = exports.frames = new FrameList();
-
-// Create the module loader in any existing processes
-ppmm.broadcastAsyncMessage('sdk/remote/process/load', {
- modulePath: PATH,
- loaderID,
- options: childOptions,
- reason: "broadcast"
-});
-
-// A loader has started in a remote process
-function processLoaderStarted({ target, data }) {
- if (data.loaderID != loaderID)
- return;
-
- if (processMap.has(data.processID)) {
- console.error("Saw the same process load the same loader twice. This is a bug in the SDK.");
- return;
- }
-
- let process = new Process(data.processID, target, data.isRemote);
-
- if (pendingFrames.has(data.processID)) {
- for (let frame of pendingFrames.get(data.processID))
- setFrameProcess(frame, process);
- pendingFrames.delete(data.processID);
- }
-}
-
-// A new process has started
-function processStarted({ target, data: { modulePath } }) {
- if (modulePath != PATH)
- return;
-
- // Have it load a loader if it hasn't already
- target.sendAsyncMessage('sdk/remote/process/load', {
- modulePath,
- loaderID,
- options: childOptions,
- reason: "response"
- });
-}
-
-var pendingFrames = new Map();
-
-// A new frame has been created in the remote process
-function frameAttached({ target, data }) {
- if (data.loaderID != loaderID)
- return;
-
- let frame = new Frame(data.frameID, target);
-
- let process = processMap.get(data.processID);
- if (process) {
- setFrameProcess(frame, process);
- return;
- }
-
- // In some cases frame messages can arrive earlier than process messages
- // causing us to see a new frame appear before its process. In this case
- // cache the frame data until we see the process. See bug 1131375.
- if (!pendingFrames.has(data.processID))
- pendingFrames.set(data.processID, [frame]);
- else
- pendingFrames.get(data.processID).push(frame);
-}
-
-// Wait for new processes and frames
-ppmm.addMessageListener('sdk/remote/process/attach', processLoaderStarted);
-ppmm.addMessageListener('sdk/remote/process/start', processStarted);
-gmm.addMessageListener('sdk/remote/frame/attach', frameAttached);
-
-when(reason => {
- ppmm.removeMessageListener('sdk/remote/process/attach', processLoaderStarted);
- ppmm.removeMessageListener('sdk/remote/process/start', processStarted);
- gmm.removeMessageListener('sdk/remote/frame/attach', frameAttached);
-
- ppmm.broadcastAsyncMessage('sdk/remote/process/unload', { loaderID, reason });
-});
-
-var remoteModules = new Set();
-
-// Ensures a module is loaded in every child process. It is safe to send
-// messages to this module immediately after calling this.
-// Pass a module to resolve the id relatively.
-function remoteRequire(id, module = null) {
- // Resolve relative to calling module if passed
- if (module)
- id = moduleResolve(id, module.id);
-
- // Don't reload the same module
- if (remoteModules.has(id))
- return;
-
- remoteModules.add(id);
- processes.port.emit('sdk/remote/require', id);
-}
-exports.remoteRequire = remoteRequire;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/remote/utils.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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 { Class } = require('../core/heritage');
-const { List, addListItem, removeListItem } = require('../util/list');
-lazyRequire(this, '../event/core', 'emit');
-lazyRequire(this, '../event/utils', 'pipe');
-
-// A helper class that maintains a list of EventTargets. Any events emitted
-// to an EventTarget are also emitted by the EventParent. Likewise for an
-// EventTarget's port property.
-const EventParent = Class({
- implements: [ List ],
-
- attachItem: function(item) {
- addListItem(this, item);
-
- pipe(item.port, this.port);
- pipe(item, this);
-
- item.once('detach', () => {
- removeListItem(this, item);
- })
-
- emit(this, 'attach', item);
- },
-
- // Calls listener for every object already in the list and every object
- // subsequently added to the list.
- forEvery: function(listener) {
- for (let item of this)
- listener(item);
-
- this.on('attach', listener);
- }
-});
-exports.EventParent = EventParent;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/selection.js
+++ /dev/null
@@ -1,469 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "stable",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Ci, Cc } = require("chrome");
-lazyRequire(this, "./timers", "setTimeout");
-lazyRequire(this, "./event/core", "emit", "off");
-const { Class, obscure } = require("./core/heritage");
-const { EventTarget } = require("./event/target");
-const { ns } = require("./core/namespace");
-const { when: unload } = require("./system/unload");
-lazyRequire(this, './private-browsing/utils', "ignoreWindow");
-lazyRequire(this, './tabs/utils', "getTabs", "getTabForContentWindow", "getAllTabContentWindows");
-lazyRequireModule(this, "./window/utils", "winUtils");
-const events = require("./system/events");
-
-// The selection types
-const HTML = 0x01,
- TEXT = 0x02,
- DOM = 0x03; // internal use only
-
-// A more developer-friendly message than the caught exception when is not
-// possible change a selection.
-const ERR_CANNOT_CHANGE_SELECTION =
- "It isn't possible to change the selection, as there isn't currently a selection";
-
-const selections = ns();
-
-const Selection = Class({
- /**
- * Creates an object from which a selection can be set, get, etc. Each
- * object has an associated with a range number. Range numbers are the
- * 0-indexed counter of selection ranges as explained at
- * https://developer.mozilla.org/en/DOM/Selection.
- *
- * @param rangeNumber
- * The zero-based range index into the selection
- */
- initialize: function initialize(rangeNumber) {
- // In order to hide the private `rangeNumber` argument from API consumers
- // while still enabling Selection getters/setters to access it, we define
- // it as non enumerable, non configurable property. While consumers still
- // may discover it they won't be able to do any harm which is good enough
- // in this case.
- Object.defineProperties(this, {
- rangeNumber: {
- enumerable: false,
- configurable: false,
- value: rangeNumber
- }
- });
- },
- get text() { return getSelection(TEXT, this.rangeNumber); },
- set text(value) { setSelection(TEXT, value, this.rangeNumber); },
- get html() { return getSelection(HTML, this.rangeNumber); },
- set html(value) { setSelection(HTML, value, this.rangeNumber); },
- get isContiguous() {
-
- // If there are multiple non empty ranges, the selection is definitely
- // discontiguous. It returns `false` also if there are no valid selection.
- let count = 0;
- for (let sel in selectionIterator)
- if (++count > 1)
- break;
-
- return count === 1;
- }
-});
-
-const selectionListener = {
- notifySelectionChanged: function (document, selection, reason) {
- if (!["SELECTALL", "KEYPRESS", "MOUSEUP"].some(type => reason &
- Ci.nsISelectionListener[type + "_REASON"]) || selection.toString() == "")
- return;
-
- this.onSelect();
- },
-
- onSelect: function() {
- emit(module.exports, "select");
- }
-}
-
-/**
- * Defines iterators so that discontiguous selections can be iterated.
- * Empty selections are skipped - see `safeGetRange` for further details.
- *
- * If discontiguous selections are in a text field, only the first one
- * is returned because the text field selection APIs doesn't support
- * multiple selections.
- */
-function* forOfIterator() {
- let selection = getSelection(DOM);
- let count = 0;
-
- if (selection)
- count = selection.rangeCount || (getElementWithSelection() ? 1 : 0);
-
- for (let i = 0; i < count; i++) {
- let sel = Selection(i);
-
- if (sel.text)
- yield Selection(i);
- }
-}
-
-const selectionIteratorOptions = {
- __iterator__: function() {
- for (let item of this)
- yield item;
- }
-}
-selectionIteratorOptions[Symbol.iterator] = forOfIterator;
-const selectionIterator = obscure(selectionIteratorOptions);
-
-/**
- * Returns the most recent focused window.
- * if private browsing window is most recent and not supported,
- * then ignore it and return `null`, because the focused window
- * can't be targeted.
- */
-function getFocusedWindow() {
- let window = winUtils.getFocusedWindow();
-
- return ignoreWindow(window) ? null : window;
-}
-
-/**
- * Returns the focused element in the most recent focused window
- * if private browsing window is most recent and not supported,
- * then ignore it and return `null`, because the focused element
- * can't be targeted.
- */
-function getFocusedElement() {
- let element = winUtils.getFocusedElement();
-
- if (!element || ignoreWindow(element.ownerGlobal))
- return null;
-
- return element;
-}
-
-/**
- * Returns the current selection from most recent content window. Depending on
- * the specified |type|, the value returned can be a string of text, stringified
- * HTML, or a DOM selection object as described at
- * https://developer.mozilla.org/en/DOM/Selection.
- *
- * @param type
- * Specifies the return type of the selection. Valid values are the one
- * of the constants HTML, TEXT, or DOM.
- *
- * @param rangeNumber
- * Specifies the zero-based range index of the returned selection.
- */
-function getSelection(type, rangeNumber) {
- let window, selection;
- try {
- window = getFocusedWindow();
- selection = window.getSelection();
- }
- catch (e) {
- return null;
- }
-
- // Get the selected content as the specified type
- if (type == DOM) {
- return selection;
- }
- else if (type == TEXT) {
- let range = safeGetRange(selection, rangeNumber);
-
- if (range)
- return range.toString();
-
- let node = getElementWithSelection();
-
- if (!node)
- return null;
-
- return node.value.substring(node.selectionStart, node.selectionEnd);
- }
- else if (type == HTML) {
- let range = safeGetRange(selection, rangeNumber);
- // Another way, but this includes the xmlns attribute for all elements in
- // Gecko 1.9.2+ :
- // return Cc["@mozilla.org/xmlextras/xmlserializer;1"].
- // createInstance(Ci.nsIDOMSerializer).serializeToSTring(range.
- // cloneContents());
- if (!range)
- return null;
-
- let node = window.document.createElement("span");
- node.appendChild(range.cloneContents());
- return node.innerHTML;
- }
-
- throw new Error("Type " + type + " is unrecognized.");
-}
-
-/**
- * Sets the current selection of the most recent content document by changing
- * the existing selected text/HTML range to the specified value.
- *
- * @param val
- * The value for the new selection
- *
- * @param rangeNumber
- * The zero-based range index of the selection to be set
- *
- */
-function setSelection(type, val, rangeNumber) {
- // Make sure we have a window context & that there is a current selection.
- // Selection cannot be set unless there is an existing selection.
- let window, selection;
-
- try {
- window = getFocusedWindow();
- selection = window.getSelection();
- }
- catch (e) {
- throw new Error(ERR_CANNOT_CHANGE_SELECTION);
- }
-
- let range = safeGetRange(selection, rangeNumber);
-
- if (range) {
- let fragment;
-
- if (type === HTML)
- fragment = range.createContextualFragment(val);
- else {
- fragment = range.createContextualFragment("");
- fragment.textContent = val;
- }
-
- range.deleteContents();
- range.insertNode(fragment);
- }
- else {
- let node = getElementWithSelection();
-
- if (!node)
- throw new Error(ERR_CANNOT_CHANGE_SELECTION);
-
- let { value, selectionStart, selectionEnd } = node;
-
- let newSelectionEnd = selectionStart + val.length;
-
- node.value = value.substring(0, selectionStart) +
- val +
- value.substring(selectionEnd, value.length);
-
- node.setSelectionRange(selectionStart, newSelectionEnd);
- }
-}
-
-/**
- * Returns the specified range in a selection without throwing an exception.
- *
- * @param selection
- * A selection object as described at
- * https://developer.mozilla.org/en/DOM/Selection
- *
- * @param [rangeNumber]
- * Specifies the zero-based range index of the returned selection.
- * If it's not provided the function will return the first non empty
- * range, if any.
- */
-function safeGetRange(selection, rangeNumber) {
- try {
- let { rangeCount } = selection;
- let range = null;
-
- if (typeof rangeNumber === "undefined")
- rangeNumber = 0;
- else
- rangeCount = rangeNumber + 1;
-
- for (; rangeNumber < rangeCount; rangeNumber++ ) {
- range = selection.getRangeAt(rangeNumber);
-
- if (range && range.toString())
- break;
-
- range = null;
- }
-
- return range;
- }
- catch (e) {
- return null;
- }
-}
-
-/**
- * Returns a reference of the DOM's active element for the window given, if it
- * supports the text field selection API and has a text selected.
- *
- * Note:
- * we need this method because window.getSelection doesn't return a selection
- * for text selected in a form field (see bug 85686)
- */
-function getElementWithSelection() {
- let element = getFocusedElement();
-
- if (!element)
- return null;
-
- try {
- // Accessing selectionStart and selectionEnd on e.g. a button
- // results in an exception thrown as per the HTML5 spec. See
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#textFieldSelection
-
- let { value, selectionStart, selectionEnd } = element;
-
- let hasSelection = typeof value === "string" &&
- !isNaN(selectionStart) &&
- !isNaN(selectionEnd) &&
- selectionStart !== selectionEnd;
-
- return hasSelection ? element : null;
- }
- catch (err) {
- return null;
- }
-
-}
-
-/**
- * Adds the Selection Listener to the content's window given
- */
-function addSelectionListener(window) {
- let selection = window.getSelection();
-
- // Don't add the selection's listener more than once to the same window,
- // if the selection object is the same
- if ("selection" in selections(window) && selections(window).selection === selection)
- return;
-
- // We ensure that the current selection is an instance of
- // `nsISelectionPrivate` before working on it, in case is `null`.
- //
- // If it's `null` it's likely too early to add the listener, and we demand
- // that operation to `document-shown` - it can easily happens for frames
- if (selection instanceof Ci.nsISelectionPrivate)
- selection.addSelectionListener(selectionListener);
-
- // nsISelectionListener implementation seems not fire a notification if
- // a selection is in a text field, therefore we need to add a listener to
- // window.onselect, that is fired only for text fields.
- // For consistency, we add it only when the nsISelectionListener is added.
- //
- // https://developer.mozilla.org/en/DOM/window.onselect
- window.addEventListener("select", selectionListener.onSelect, true);
-
- selections(window).selection = selection;
-};
-
-/**
- * Removes the Selection Listener to the content's window given
- */
-function removeSelectionListener(window) {
- // Don't remove the selection's listener to a window that wasn't handled.
- if (!("selection" in selections(window)))
- return;
-
- let selection = window.getSelection();
- let isSameSelection = selection === selections(window).selection;
-
- // Before remove the listener, we ensure that the current selection is an
- // instance of `nsISelectionPrivate` (it could be `null`), and that is still
- // the selection we managed for this window (it could be detached).
- if (selection instanceof Ci.nsISelectionPrivate && isSameSelection)
- selection.removeSelectionListener(selectionListener);
-
- window.removeEventListener("select", selectionListener.onSelect, true);
-
- delete selections(window).selection;
-};
-
-function onContent(event) {
- let window = event.subject.defaultView;
-
- // We are not interested in documents without valid defaultView (e.g. XML)
- // that aren't in a tab (e.g. Panel); or in private windows
- if (window && getTabForContentWindow(window) && !ignoreWindow(window)) {
- addSelectionListener(window);
- }
-}
-
-// Adds Selection listener to new documents
-// Note that strong reference is needed for documents that are loading slowly or
-// where the server didn't close the connection (e.g. "comet").
-events.on("document-element-inserted", onContent, true);
-
-// Adds Selection listeners to existing documents
-getAllTabContentWindows().forEach(addSelectionListener);
-
-// When a document is not visible anymore the selection object is detached, and
-// a new selection object is created when it becomes visible again.
-// That makes the previous selection's listeners added previously totally
-// useless – the listeners are not notified anymore.
-// To fix that we're listening for `document-shown` event in order to add
-// the listeners to the new selection object created.
-//
-// See bug 665386 for further details.
-
-function onShown(event) {
- let window = event.subject.defaultView;
-
- // We are not interested in documents without valid defaultView.
- // For example XML documents don't have windows and we don't yet support them.
- if (!window)
- return;
-
- // We want to handle only the windows where we added selection's listeners
- if ("selection" in selections(window)) {
- let currentSelection = window.getSelection();
- let { selection } = selections(window);
-
- // If the current selection for the window given is different from the one
- // stored in the namespace, we need to add the listeners again, and replace
- // the previous selection in our list with the new one.
- //
- // Notice that we don't have to remove the listeners from the old selection,
- // because is detached. An attempt to remove the listener, will raise an
- // error (see http://mxr.mozilla.org/mozilla-central/source/layout/generic/nsSelection.cpp#5343 )
- //
- // We ensure that the current selection is an instance of
- // `nsISelectionPrivate` before working on it, in case is `null`.
- if (currentSelection instanceof Ci.nsISelectionPrivate &&
- currentSelection !== selection) {
-
- window.addEventListener("select", selectionListener.onSelect, true);
- currentSelection.addSelectionListener(selectionListener);
- selections(window).selection = currentSelection;
- }
- }
-}
-
-events.on("document-shown", onShown, true);
-
-// Removes Selection listeners when the add-on is unloaded
-unload(function(){
- getAllTabContentWindows().forEach(removeSelectionListener);
-
- events.off("document-element-inserted", onContent);
- events.off("document-shown", onShown);
-
- off(exports);
-});
-
-const selection = Class({
- extends: EventTarget,
- implements: [ Selection, selectionIterator ]
-})();
-
-module.exports = selection;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tab/events.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/* 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";
-
-// This module provides temporary shim until Bug 843901 is shipped.
-// It basically registers tab event listeners on all windows that get
-// opened and forwards them through observer notifications.
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const { Ci } = require("chrome");
-const { windows, isInteractive } = require("../window/utils");
-const { events } = require("../browser/events");
-const { open } = require("../event/dom");
-const { filter, map, merge, expand } = require("../event/utils");
-const isFennec = require("sdk/system/xul-app").is("Fennec");
-
-// Module provides event stream (in nodejs style) that emits data events
-// for all the tab events that happen in running firefox. At the moment
-// it does it by registering listeners on all browser windows and then
-// forwarding events when they occur to a stream. This will become obsolete
-// once Bug 843901 is fixed, and we'll just leverage observer notifications.
-
-// Set of tab events that this module going to aggregate and expose.
-const TYPES = ["TabOpen","TabClose","TabSelect","TabMove","TabPinned",
- "TabUnpinned"];
-
-// Utility function that given a browser `window` returns stream of above
-// defined tab events for all tabs on the given window.
-function tabEventsFor(window) {
- // Map supported event types to a streams of those events on the given
- // `window` and than merge these streams into single form stream off
- // all events.
- let channels = TYPES.map(type => open(window, type));
- return merge(channels);
-}
-
-// Create our event channels. We do this in a separate function to
-// minimize the chance of leaking intermediate objects on the global.
-function makeEvents() {
- // Filter DOMContentLoaded events from all the browser events.
- var readyEvents = filter(events, e => e.type === "DOMContentLoaded");
- // Map DOMContentLoaded events to it's target browser windows.
- var futureWindows = map(readyEvents, e => e.target);
- // Expand all browsers that will become interactive to supported tab events
- // on these windows. Result will be a tab events from all tabs of all windows
- // that will become interactive.
- var eventsFromFuture = expand(futureWindows, tabEventsFor);
-
- // Above covers only windows that will become interactive in a future, but some
- // windows may already be interactive so we pick those and expand to supported
- // tab events for them too.
- var interactiveWindows = windows("navigator:browser", { includePrivate: true }).
- filter(isInteractive);
- var eventsFromInteractive = merge(interactiveWindows.map(tabEventsFor));
-
-
- // Finally merge stream of tab events from future windows and current windows
- // to cover all tab events on all windows that will open.
- return merge([eventsFromInteractive, eventsFromFuture]);
-}
-
-// Map events to Fennec format if necessary
-exports.events = map(makeEvents(), function (event) {
- return !isFennec ? event : {
- type: event.type,
- target: event.target.ownerGlobal.BrowserApp
- .getTabForBrowser(event.target)
- };
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-if (require("./system/xul-app").is("Fennec")) {
- module.exports = require("./windows/tabs-fennec").tabs;
-}
-else {
- module.exports = require("./tabs/tabs-firefox");
-}
-
-const tabs = module.exports;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/common.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* 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 { validateOptions } = require("../deprecated/api-utils");
-const { data } = require("../self");
-
-function Options(options) {
- if ('string' === typeof options)
- options = { url: options };
-
- return validateOptions(options, {
- url: {
- is: ["string"],
- map: (v) => v ? data.url(v) : v
- },
- inBackground: {
- map: Boolean,
- is: ["undefined", "boolean"]
- },
- isPinned: { is: ["undefined", "boolean"] },
- isPrivate: { is: ["undefined", "boolean"] },
- inNewWindow: { is: ["undefined", "boolean"] },
- onOpen: { is: ["undefined", "function"] },
- onClose: { is: ["undefined", "function"] },
- onReady: { is: ["undefined", "function"] },
- onLoad: { is: ["undefined", "function"] },
- onPageShow: { is: ["undefined", "function"] },
- onActivate: { is: ["undefined", "function"] },
- onDeactivate: { is: ["undefined", "function"] }
- });
-}
-exports.Options = Options;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/events.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const ON_PREFIX = "on";
-const TAB_PREFIX = "Tab";
-
-const EVENTS = {
- ready: "DOMContentLoaded",
- load: "load", // Used for non-HTML content
- pageshow: "pageshow", // Used for cached content
- open: "TabOpen",
- close: "TabClose",
- activate: "TabSelect",
- deactivate: null,
- pinned: "TabPinned",
- unpinned: "TabUnpinned"
-}
-exports.EVENTS = EVENTS;
-
-Object.keys(EVENTS).forEach(function(name) {
- EVENTS[name] = {
- name: name,
- listener: createListenerName(name),
- dom: EVENTS[name]
- }
-});
-
-function createListenerName (name) {
- if (name === 'pageshow')
- return 'onPageShow';
- else
- return ON_PREFIX + name.charAt(0).toUpperCase() + name.substr(1);
-}
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/helpers.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/* 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';
-
-module.metadata = {
- 'stability': 'unstable'
-};
-
-
-// NOTE: This file should only export Tab instances
-
-
-lazyRequire(this, './utils', { "getTabForBrowser": "getRawTabForBrowser" });
-const { modelFor } = require('../model/core');
-
-exports.getTabForRawTab = modelFor;
-
-function getTabForBrowser(browser) {
- return modelFor(getRawTabForBrowser(browser)) || null;
-}
-exports.getTabForBrowser = getTabForBrowser;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/namespace.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/* 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';
-
-var { ns } = require('../core/namespace');
-
-exports.tabsNS = ns();
-exports.tabNS = ns();
-exports.rawTabNS = ns();
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/observer.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/* 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';
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { EventTarget } = require("../event/target");
-const { emit } = require("../event/core");
-const { DOMEventAssembler } = require("../deprecated/events/assembler");
-const { Class } = require("../core/heritage");
-const { getActiveTab, getTabs } = require("./utils");
-const { browserWindowIterator } = require("../deprecated/window-utils");
-const { isBrowser, windows, getMostRecentBrowserWindow } = require("../window/utils");
-const { observer: windowObserver } = require("../windows/observer");
-const { when } = require("../system/unload");
-
-const EVENTS = {
- "TabOpen": "open",
- "TabClose": "close",
- "TabSelect": "select",
- "TabMove": "move",
- "TabPinned": "pinned",
- "TabUnpinned": "unpinned"
-};
-
-const selectedTab = Symbol("observer/state/selectedTab");
-
-// Event emitter objects used to register listeners and emit events on them
-// when they occur.
-const Observer = Class({
- implements: [EventTarget, DOMEventAssembler],
- initialize() {
- this[selectedTab] = null;
- // Currently Gecko does not dispatch any event on the previously selected
- // tab before / after "TabSelect" is dispatched. In order to work around this
- // limitation we keep track of selected tab and emit "deactivate" event with
- // that before emitting "activate" on selected tab.
- this.on("select", tab => {
- const selected = this[selectedTab];
- if (selected !== tab) {
- if (selected) {
- emit(this, 'deactivate', selected);
- }
-
- if (tab) {
- this[selectedTab] = tab;
- emit(this, 'activate', this[selectedTab]);
- }
- }
- });
-
-
- // We also observe opening / closing windows in order to add / remove it's
- // containers to the observed list.
- windowObserver.on("open", chromeWindow => {
- if (isBrowser(chromeWindow)) {
- this.observe(chromeWindow);
- }
- });
-
- windowObserver.on("close", chromeWindow => {
- if (isBrowser(chromeWindow)) {
- // Bug 751546: Emit `deactivate` event on window close immediatly
- // Otherwise we are going to face "dead object" exception on `select` event
- if (getActiveTab(chromeWindow) === this[selectedTab]) {
- emit(this, "deactivate", this[selectedTab]);
- this[selectedTab] = null;
- }
- this.ignore(chromeWindow);
- }
- });
-
-
- // Currently gecko does not dispatches "TabSelect" events when different
- // window gets activated. To work around this limitation we emulate "select"
- // event for this case.
- windowObserver.on("activate", chromeWindow => {
- if (isBrowser(chromeWindow)) {
- emit(this, "select", getActiveTab(chromeWindow));
- }
- });
-
- // We should synchronize state, since probably we already have at least one
- // window open.
- for (let chromeWindow of browserWindowIterator()) {
- this.observe(chromeWindow);
- }
-
- when(_ => {
- // Don't dispatch a deactivate event during unload.
- this[selectedTab] = null;
- });
- },
- /**
- * Events that are supported and emitted by the module.
- */
- supportedEventsTypes: Object.keys(EVENTS),
- /**
- * Function handles all the supported events on all the windows that are
- * observed. Method is used to proxy events to the listeners registered on
- * this event emitter.
- * @param {Event} event
- * Keyboard event being emitted.
- */
- handleEvent: function handleEvent(event) {
- emit(this, EVENTS[event.type], event.target, event);
- }
-});
-
-exports.observer = new Observer();
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
+++ /dev/null
@@ -1,249 +0,0 @@
-/* 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 { Cc, Ci } = require('chrome');
-const { Class } = require('../core/heritage');
-const { tabNS, rawTabNS } = require('./namespace');
-const { EventTarget } = require('../event/target');
-const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL,
- getTabContentWindow, getTabForBrowser, setTabURL, getOwnerWindow,
- getTabContentDocument, getTabContentType, getTabId, isTab } = require('./utils');
-const { emit } = require('../event/core');
-const { isPrivate } = require('../private-browsing/utils');
-const { isWindowPrivate } = require('../window/utils');
-const { when: unload } = require('../system/unload');
-const { BLANK } = require('../content/thumbnail');
-const { viewFor } = require('../view/core');
-const { EVENTS } = require('./events');
-const { modelFor } = require('../model/core');
-
-const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
-
-const Tab = Class({
- extends: EventTarget,
- initialize: function initialize(options) {
- options = options.tab ? options : { tab: options };
- let tab = options.tab;
-
- EventTarget.prototype.initialize.call(this, options);
- let tabInternals = tabNS(this);
- rawTabNS(tab).tab = this;
-
- let window = tabInternals.window = options.window || getOwnerWindow(tab);
- tabInternals.tab = tab;
-
- // TabReady
- let onReady = tabInternals.onReady = onTabReady.bind(this);
- tab.browser.addEventListener(EVENTS.ready.dom, onReady);
-
- // TabPageShow
- let onPageShow = tabInternals.onPageShow = onTabPageShow.bind(this);
- tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow);
-
- // TabLoad
- let onLoad = tabInternals.onLoad = onTabLoad.bind(this);
- tab.browser.addEventListener(EVENTS.load.dom, onLoad, true);
-
- // TabClose
- let onClose = tabInternals.onClose = onTabClose.bind(this);
- window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onClose);
-
- unload(cleanupTab.bind(null, this));
- },
-
- /**
- * The title of the page currently loaded in the tab.
- * Changing this property changes an actual title.
- * @type {String}
- */
- get title() {
- return getTabTitle(tabNS(this).tab);
- },
- set title(title) {
- setTabTitle(tabNS(this).tab, title);
- },
-
- /**
- * Location of the page currently loaded in this tab.
- * Changing this property will loads page under under the specified location.
- * @type {String}
- */
- get url() {
- return tabNS(this).closed ? undefined : getTabURL(tabNS(this).tab);
- },
- set url(url) {
- setTabURL(tabNS(this).tab, url);
- },
-
- getThumbnail: function() {
- // TODO: implement!
- console.error(ERR_FENNEC_MSG);
-
- // return 80x45 blank default
- return BLANK;
- },
-
- /**
- * tab's document readyState, or 'uninitialized' if it doesn't even exist yet.
- */
- get readyState() {
- let doc = getTabContentDocument(tabNS(this).tab);
- return doc && doc.readyState || 'uninitialized';
- },
-
- get id() {
- return getTabId(tabNS(this).tab);
- },
-
- /**
- * The index of the tab relative to other tabs in the application window.
- * Changing this property will change order of the actual position of the tab.
- * @type {Number}
- */
- get index() {
- if (tabNS(this).closed) return undefined;
-
- let tabs = tabNS(this).window.BrowserApp.tabs;
- let tab = tabNS(this).tab;
- for (var i = tabs.length; i >= 0; i--) {
- if (tabs[i] === tab)
- return i;
- }
- return null;
- },
- set index(value) {
- console.error(ERR_FENNEC_MSG); // TODO
- },
-
- /**
- * Whether or not tab is pinned (Is an app-tab).
- * @type {Boolean}
- */
- get isPinned() {
- console.error(ERR_FENNEC_MSG); // TODO
- return false; // TODO
- },
- pin: function pin() {
- console.error(ERR_FENNEC_MSG); // TODO
- },
- unpin: function unpin() {
- console.error(ERR_FENNEC_MSG); // TODO
- },
-
- /**
- * Returns the MIME type that the document loaded in the tab is being
- * rendered as.
- * @type {String}
- */
- get contentType() {
- return getTabContentType(tabNS(this).tab);
- },
-
- /**
- * Create a worker for this tab, first argument is options given to Worker.
- * @type {Worker}
- */
- attach: function attach(options) {
- // BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946
- // TODO: fix this circular dependency
- let { Worker } = require('./worker');
- return Worker(options, getTabContentWindow(tabNS(this).tab));
- },
-
- /**
- * Make this tab active.
- */
- activate: function activate() {
- activateTab(tabNS(this).tab, tabNS(this).window);
- },
-
- /**
- * Close the tab
- */
- close: function close(callback) {
- let tab = this;
- this.once(EVENTS.close.name, function () {
- tabNS(tab).closed = true;
- if (callback) callback();
- });
-
- closeTab(tabNS(this).tab);
- },
-
- /**
- * Reload the tab
- */
- reload: function reload() {
- tabNS(this).tab.browser.reload();
- }
-});
-exports.Tab = Tab;
-
-// Implement `viewFor` polymorphic function for the Tab
-// instances.
-viewFor.define(Tab, x => tabNS(x).tab);
-
-function cleanupTab(tab) {
- let tabInternals = tabNS(tab);
- if (!tabInternals.tab)
- return;
-
- if (tabInternals.tab.browser) {
- tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady);
- tabInternals.tab.browser.removeEventListener(EVENTS.pageshow.dom, tabInternals.onPageShow);
- tabInternals.tab.browser.removeEventListener(EVENTS.load.dom, tabInternals.onLoad, true);
- }
- tabInternals.onReady = null;
- tabInternals.onPageShow = null;
- tabInternals.onLoad = null;
- tabInternals.window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, tabInternals.onClose);
- tabInternals.onClose = null;
- rawTabNS(tabInternals.tab).tab = null;
- tabInternals.tab = null;
- tabInternals.window = null;
-}
-
-function onTabReady(event) {
- let win = event.target.defaultView;
-
- // ignore frames
- if (win === win.top) {
- emit(this, 'ready', this);
- }
-}
-
-function onTabLoad (event) {
- let win = event.target.defaultView;
-
- // ignore frames
- if (win === win.top) {
- emit(this, 'load', this);
- }
-}
-
-function onTabPageShow(event) {
- let win = event.target.defaultView;
- if (win === win.top)
- emit(this, 'pageshow', this, event.persisted);
-}
-
-// TabClose
-function onTabClose(event) {
- let rawTab = getTabForBrowser(event.target);
- if (tabNS(this).tab !== rawTab)
- return;
-
- emit(this, EVENTS.close.name, this);
- cleanupTab(this);
-};
-
-isPrivate.implement(Tab, tab => {
- return isWindowPrivate(getTabContentWindow(tabNS(tab).tab));
-});
-
-// Implement `modelFor` function for the Tab instances.
-modelFor.when(isTab, rawTab => {
- return rawTabNS(rawTab).tab;
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
+++ /dev/null
@@ -1,353 +0,0 @@
-/* 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 { Class } = require('../core/heritage');
-const { observer } = require('./observer');
-const { observer: windowObserver } = require('../windows/observer');
-const { addListItem, removeListItem } = require('../util/list');
-const { viewFor } = require('../view/core');
-const { modelFor } = require('../model/core');
-const { emit, setListeners } = require('../event/core');
-const { EventTarget } = require('../event/target');
-const { getBrowserForTab, setTabURL, getTabId, getTabURL, getTabForBrowser,
- getTabs, getTabTitle, setTabTitle, getIndex, closeTab, reload, move,
- activateTab, pin, unpin, isTab } = require('./utils');
-const { isBrowser, getInnerId, isWindowPrivate } = require('../window/utils');
-const { getThumbnailURIForWindow, BLANK } = require("../content/thumbnail");
-const { when } = require('../system/unload');
-const { ignoreWindow, isPrivate } = require('../private-browsing/utils')
-const { defer } = require('../lang/functional');
-const { getURL } = require('../url/utils');
-const { frames, remoteRequire } = require('../remote/parent');
-remoteRequire('sdk/content/tab-events');
-
-const modelsFor = new WeakMap();
-const viewsFor = new WeakMap();
-const destroyed = new WeakMap();
-
-const tabEvents = {};
-exports.tabEvents = tabEvents;
-
-function browser(tab) {
- return getBrowserForTab(viewsFor.get(tab));
-}
-
-function isDestroyed(tab) {
- return destroyed.has(tab);
-}
-
-function isClosed(tab) {
- if (!viewsFor.has(tab))
- return true;
- return viewsFor.get(tab).closing;
-}
-
-// private tab attribute where the remote cached value is stored
-const remoteReadyStateCached = Symbol("remoteReadyStateCached");
-
-const Tab = Class({
- implements: [EventTarget],
- initialize: function(tabElement, options = null) {
- modelsFor.set(tabElement, this);
- viewsFor.set(this, tabElement);
-
- if (options) {
- EventTarget.prototype.initialize.call(this, options);
-
- if (options.isPinned)
- this.pin();
-
- // Note that activate is defered and so will run after any open event
- // is sent out
- if (!options.inBackground)
- this.activate();
- }
-
- getURL.implement(this, tab => tab.url);
- isPrivate.implement(this, tab => {
- return isWindowPrivate(viewsFor.get(tab).ownerGlobal);
- });
- },
-
- get id() {
- return isDestroyed(this) ? undefined : getTabId(viewsFor.get(this));
- },
-
- get title() {
- return isDestroyed(this) ? undefined : getTabTitle(viewsFor.get(this));
- },
-
- set title(val) {
- if (isDestroyed(this))
- return;
-
- setTabTitle(viewsFor.get(this), val);
- },
-
- get url() {
- return isDestroyed(this) ? undefined : getTabURL(viewsFor.get(this));
- },
-
- set url(val) {
- if (isDestroyed(this))
- return;
-
- setTabURL(viewsFor.get(this), val);
- },
-
- get contentType() {
- return isDestroyed(this) ? undefined : browser(this).documentContentType;
- },
-
- get index() {
- return isDestroyed(this) ? undefined : getIndex(viewsFor.get(this));
- },
-
- set index(val) {
- if (isDestroyed(this))
- return;
-
- move(viewsFor.get(this), val);
- },
-
- get isPinned() {
- return isDestroyed(this) ? undefined : viewsFor.get(this).pinned;
- },
-
- get window() {
- if (isClosed(this))
- return undefined;
-
- // TODO: Remove the dependency on the windows module, see bug 792670
- require('../windows');
- let tabElement = viewsFor.get(this);
- let domWindow = tabElement.ownerGlobal;
- return modelFor(domWindow);
- },
-
- get readyState() {
- return isDestroyed(this) ? undefined : this[remoteReadyStateCached] || "uninitialized";
- },
-
- pin: function() {
- if (isDestroyed(this))
- return;
-
- pin(viewsFor.get(this));
- },
-
- unpin: function() {
- if (isDestroyed(this))
- return;
-
- unpin(viewsFor.get(this));
- },
-
- close: function(callback) {
- let tabElement = viewsFor.get(this);
-
- if (isDestroyed(this) || !tabElement || !tabElement.parentNode) {
- if (callback)
- callback();
- return;
- }
-
- this.once('close', () => {
- this.destroy();
- if (callback)
- callback();
- });
-
- closeTab(tabElement);
- },
-
- reload: function() {
- if (isDestroyed(this))
- return;
-
- reload(viewsFor.get(this));
- },
-
- activate: defer(function() {
- if (isDestroyed(this))
- return;
-
- activateTab(viewsFor.get(this));
- }),
-
- getThumbnail: function() {
- if (isDestroyed(this))
- return BLANK;
-
- // TODO: This is unimplemented in e10s: bug 1148601
- if (browser(this).isRemoteBrowser) {
- console.error('This method is not supported with E10S');
- return BLANK;
- }
- return getThumbnailURIForWindow(browser(this).contentWindow);
- },
-
- attach: function(options) {
- if (isDestroyed(this))
- return;
-
- let { Worker } = require('../content/worker');
- let { connect, makeChildOptions } = require('../content/utils');
-
- let worker = Worker(options);
- worker.once("detach", () => {
- worker.destroy();
- });
-
- let attach = frame => {
- let childOptions = makeChildOptions(options);
- frame.port.emit("sdk/tab/attach", childOptions);
- connect(worker, frame, { id: childOptions.id, url: this.url });
- };
-
- // Do this synchronously if possible
- let frame = frames.getFrameForBrowser(browser(this));
- if (frame) {
- attach(frame);
- }
- else {
- let listener = (frame) => {
- if (frame.frameElement != browser(this))
- return;
-
- frames.off("attach", listener);
- attach(frame);
- };
- frames.on("attach", listener);
- }
-
- return worker;
- },
-
- destroy: function() {
- if (isDestroyed(this))
- return;
-
- destroyed.set(this, true);
- }
-});
-exports.Tab = Tab;
-
-viewFor.define(Tab, tab => viewsFor.get(tab));
-
-// Returns the high-level window for this DOM window if the windows module has
-// ever been loaded otherwise returns null
-function maybeWindowFor(domWindow) {
- try {
- return modelFor(domWindow);
- }
- catch (e) {
- return null;
- }
-}
-
-function tabEmit(tab, event, ...args) {
- // Don't emit events for destroyed tabs
- if (isDestroyed(tab))
- return;
-
- // If the windows module was never loaded this will return null. We don't need
- // to emit to the window.tabs object in this case as nothing can be listening.
- let tabElement = viewsFor.get(tab);
- let window = maybeWindowFor(tabElement.ownerGlobal);
- if (window)
- emit(window.tabs, event, tab, ...args);
-
- emit(tabEvents, event, tab, ...args);
- emit(tab, event, tab, ...args);
-}
-
-function windowClosed(domWindow) {
- if (!isBrowser(domWindow))
- return;
-
- for (let tabElement of getTabs(domWindow)) {
- tabEventListener("close", tabElement);
- }
-}
-windowObserver.on('close', windowClosed);
-
-// Don't want to send close events after unloaded
-when(_ => {
- windowObserver.off('close', windowClosed);
-});
-
-// Listen for tabbrowser events
-function tabEventListener(event, tabElement, ...args) {
- let domWindow = tabElement.ownerGlobal;
-
- if (ignoreWindow(domWindow))
- return;
-
- // Don't send events for tabs that are already closing
- if (event != "close" && (tabElement.closing || !tabElement.parentNode))
- return;
-
- let tab = modelsFor.get(tabElement);
- if (!tab)
- tab = new Tab(tabElement);
-
- let window = maybeWindowFor(domWindow);
-
- if (event == "open") {
- // Note, add to the window tabs first because if this is the first access to
- // window.tabs it will be prefilling itself with everything from tabs
- if (window)
- addListItem(window.tabs, tab);
- // The tabs module will take care of adding to its internal list
- }
- else if (event == "close") {
- if (window)
- removeListItem(window.tabs, tab);
- // The tabs module will take care of removing from its internal list
- }
- else if (event == "init" || event == "create" || event == "ready" || event == "load") {
- // Ignore load events from before browser windows have fully loaded, these
- // are for about:blank in the initial tab
- if (isBrowser(domWindow) && !domWindow.gBrowserInit.delayedStartupFinished)
- return;
-
- // update the cached remote readyState value
- let { readyState } = args[0] || {};
- tab[remoteReadyStateCached] = readyState;
- }
-
- if (event == "init") {
- // Do not emit events for the detected existent tabs, we only need to cache
- // their current document.readyState value.
- return;
- }
-
- tabEmit(tab, event, ...args);
-
- // The tab object shouldn't be reachable after closed
- if (event == "close") {
- viewsFor.delete(tab);
- modelsFor.delete(tabElement);
- }
-}
-observer.on('*', tabEventListener);
-
-// Listen for tab events from content
-frames.port.on('sdk/tab/event', (frame, event, ...args) => {
- if (!frame.isTab)
- return;
-
- let tabElement = getTabForBrowser(frame.frameElement);
- if (!tabElement)
- return;
-
- tabEventListener(event, tabElement, ...args);
-});
-
-// Implement `modelFor` function for the Tab instances..
-modelFor.when(isTab, view => {
- return modelsFor.get(view);
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/tab.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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';
-
-module.metadata = {
- 'stability': 'unstable'
-};
-
-const { getTargetWindow } = require("../content/mod");
-lazyRequire(this, "./utils", "getTabContentWindow", "isTab");
-lazyRequire(this, "../view/core", "viewFor");
-
-if (require('../system/xul-app').name == 'Fennec') {
- module.exports = require('./tab-fennec');
-}
-else {
- module.exports = require('./tab-firefox');
-}
-
-getTargetWindow.when(isTab, tab => getTabContentWindow(tab));
-
-getTargetWindow.when(x => x instanceof module.exports.Tab,
- tab => getTabContentWindow(viewFor(tab)));
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/tabs-firefox.js
+++ /dev/null
@@ -1,133 +0,0 @@
-/* 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 { Class } = require('../core/heritage');
-const { Tab, tabEvents } = require('./tab');
-const { EventTarget } = require('../event/target');
-lazyRequire(this, '../event/core', "emit", "setListeners");
-const { pipe } = require('../event/utils');
-const { observer: windowObserver } = require('../windows/observer');
-const { List, addListItem, removeListItem } = require('../util/list');
-lazyRequire(this, '../model/core', "modelFor");
-lazyRequire(this, '../view/core', "viewFor");
-lazyRequire(this, './utils', "getTabs", "getSelectedTab");
-lazyRequire(this, '../window/utils', "getMostRecentBrowserWindow", "isBrowser");
-lazyRequire(this, './common', "Options");
-lazyRequire(this, '../private-browsing', "isPrivate");
-lazyRequire(this, '../private-browsing/utils', "ignoreWindow", "isWindowPBSupported")
-const { isPrivateBrowsingSupported } = require('sdk/self');
-
-const supportPrivateTabs = isPrivateBrowsingSupported && isWindowPBSupported;
-
-const Tabs = Class({
- implements: [EventTarget],
- extends: List,
- initialize: function() {
- List.prototype.initialize.call(this);
-
- // We must do the list manipulation here where the object is extensible
- this.on("open", tab => {
- addListItem(this, tab);
- });
-
- this.on("close", tab => {
- removeListItem(this, tab);
- });
- },
-
- get activeTab() {
- let activeDomWin = getMostRecentBrowserWindow();
- if (!activeDomWin)
- return null;
- return modelFor(getSelectedTab(activeDomWin));
- },
-
- open: function(options) {
- options = Options(options);
-
- // TODO: Remove the dependency on the windows module: bug 792670
- let windows = require('../windows').browserWindows;
- let activeWindow = windows.activeWindow;
-
- let privateState = supportPrivateTabs && options.isPrivate;
- // When no isPrivate option was passed use the private state of the active
- // window
- if (activeWindow && privateState === undefined)
- privateState = isPrivate(activeWindow);
-
- function getWindow(privateState) {
- for (let window of windows) {
- if (privateState === isPrivate(window)) {
- return window;
- }
- }
- return null;
- }
-
- function openNewWindowWithTab() {
- windows.open({
- url: options.url,
- isPrivate: privateState,
- onOpen: function(newWindow) {
- let tab = newWindow.tabs[0];
- setListeners(tab, options);
-
- if (options.isPinned)
- tab.pin();
-
- // We don't emit the open event for the first tab in a new window so
- // do it now the listeners are attached
- emit(tab, "open", tab);
- }
- });
- }
-
- if (options.inNewWindow)
- return openNewWindowWithTab();
-
- // if the active window is in the state that we need then use it
- if (activeWindow && (privateState === isPrivate(activeWindow)))
- return activeWindow.tabs.open(options);
-
- // find a window in the state that we need
- let window = getWindow(privateState);
- if (window)
- return window.tabs.open(options);
-
- return openNewWindowWithTab();
- }
-});
-
-const allTabs = new Tabs();
-module.exports = allTabs;
-pipe(tabEvents, allTabs);
-
-function addWindowTab(window, tabElement) {
- let tab = new Tab(tabElement);
- if (window)
- addListItem(window.tabs, tab);
- addListItem(allTabs, tab);
- emit(allTabs, "open", tab);
-}
-
-// Find tabs in already open windows
-for (let tabElement of getTabs())
- addWindowTab(null, tabElement);
-
-// Detect tabs in new windows
-windowObserver.on('open', domWindow => {
- if (!isBrowser(domWindow) || ignoreWindow(domWindow))
- return;
-
- let window = null;
- try {
- modelFor(domWindow);
- }
- catch (e) { }
-
- for (let tabElement of getTabs(domWindow)) {
- addWindowTab(window, tabElement);
- }
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/utils.js
+++ /dev/null
@@ -1,370 +0,0 @@
-/* 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';
-
-module.metadata = {
- 'stability': 'unstable'
-};
-
-
-// NOTE: This file should only deal with xul/native tabs
-
-
-const { Ci, Cu } = require('chrome');
-lazyRequire(this, "../lang/functional", "defer");
-lazyRequire(this, '../window/utils', "windows", "isBrowser");
-lazyRequire(this, '../self', "isPrivateBrowsingSupported");
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-
-// Bug 834961: ignore private windows when they are not supported
-function getWindows() {
- return windows(null, { includePrivate: isPrivateBrowsingSupported });
-}
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-// Define predicate functions that can be used to detech weather
-// we deal with fennec tabs or firefox tabs.
-
-// Predicate to detect whether tab is XUL "Tab" node.
-const isXULTab = tab =>
- tab instanceof Ci.nsIDOMNode &&
- tab.nodeName === "tab" &&
- tab.namespaceURI === XUL_NS;
-exports.isXULTab = isXULTab;
-
-// Predicate to detecet whether given tab is a fettec tab.
-// Unfortunately we have to guess via duck typinng of:
-// http://mxr.mozilla.org/mozilla-central/source/mobile/android/chrome/content/browser.js#2583
-const isFennecTab = tab =>
- tab &&
- tab.QueryInterface &&
- Ci.nsIBrowserTab &&
- tab.QueryInterface(Ci.nsIBrowserTab) === tab;
-exports.isFennecTab = isFennecTab;
-
-const isTab = x => isXULTab(x) || isFennecTab(x);
-exports.isTab = isTab;
-
-function activateTab(tab, window) {
- let gBrowser = getTabBrowserForTab(tab);
-
- // normal case
- if (gBrowser) {
- gBrowser.selectedTab = tab;
- }
- // fennec ?
- else if (window && window.BrowserApp) {
- window.BrowserApp.selectTab(tab);
- }
- return null;
-}
-exports.activateTab = activateTab;
-
-function getTabBrowser(window) {
- // bug 1009938 - may be null in SeaMonkey
- return window.gBrowser || window.getBrowser();
-}
-exports.getTabBrowser = getTabBrowser;
-
-function getTabContainer(window) {
- return getTabBrowser(window).tabContainer;
-}
-exports.getTabContainer = getTabContainer;
-
-/**
- * Returns the tabs for the `window` if given, or the tabs
- * across all the browser's windows otherwise.
- *
- * @param {nsIWindow} [window]
- * A reference to a window
- *
- * @returns {Array} an array of Tab objects
- */
-function getTabs(window) {
- if (arguments.length === 0) {
- return getWindows().
- filter(isBrowser).
- reduce((tabs, window) => tabs.concat(getTabs(window)), []);
- }
-
- // fennec
- if (window.BrowserApp)
- return window.BrowserApp.tabs;
-
- // firefox - default
- return Array.filter(getTabContainer(window).children, t => !t.closing);
-}
-exports.getTabs = getTabs;
-
-function getActiveTab(window) {
- return getSelectedTab(window);
-}
-exports.getActiveTab = getActiveTab;
-
-function getOwnerWindow(tab) {
- // normal case
- if (tab.ownerDocument)
- return tab.ownerGlobal;
-
- // try fennec case
- return getWindowHoldingTab(tab);
-}
-exports.getOwnerWindow = getOwnerWindow;
-
-// fennec
-function getWindowHoldingTab(rawTab) {
- for (let window of getWindows()) {
- // this function may be called when not using fennec,
- // but BrowserApp is only defined on Fennec
- if (!window.BrowserApp)
- continue;
-
- for (let tab of window.BrowserApp.tabs) {
- if (tab === rawTab)
- return window;
- }
- }
-
- return null;
-}
-
-function openTab(window, url, options) {
- options = options || {};
-
- // fennec?
- if (window.BrowserApp) {
- return window.BrowserApp.addTab(url, {
- selected: options.inBackground ? false : true,
- pinned: options.isPinned || false,
- isPrivate: options.isPrivate || false,
- parentId: window.BrowserApp.selectedTab.id
- });
- }
-
- // firefox
- let newTab = window.gBrowser.addTab(url);
- if (!options.inBackground) {
- activateTab(newTab);
- }
- return newTab;
-};
-exports.openTab = openTab;
-
-function isTabOpen(tab) {
- // try normal case then fennec case
- return !!((tab.linkedBrowser) || getWindowHoldingTab(tab));
-}
-exports.isTabOpen = isTabOpen;
-
-function closeTab(tab) {
- let gBrowser = getTabBrowserForTab(tab);
- // normal case?
- if (gBrowser) {
- // Bug 699450: the tab may already have been detached
- if (!tab.parentNode)
- return;
- return gBrowser.removeTab(tab);
- }
-
- let window = getWindowHoldingTab(tab);
- // fennec?
- if (window && window.BrowserApp) {
- // Bug 699450: the tab may already have been detached
- if (!tab.browser)
- return;
- return window.BrowserApp.closeTab(tab);
- }
- return null;
-}
-exports.closeTab = closeTab;
-
-function getURI(tab) {
- if (tab.browser) // fennec
- return tab.browser.currentURI.spec;
- return tab.linkedBrowser.currentURI.spec;
-}
-exports.getURI = getURI;
-
-function getTabBrowserForTab(tab) {
- let outerWin = getOwnerWindow(tab);
- if (outerWin)
- return getOwnerWindow(tab).gBrowser;
- return null;
-}
-exports.getTabBrowserForTab = getTabBrowserForTab;
-
-function getBrowserForTab(tab) {
- if (tab.browser) // fennec
- return tab.browser;
-
- return tab.linkedBrowser;
-}
-exports.getBrowserForTab = getBrowserForTab;
-
-function getTabId(tab) {
- if (tab.browser) // fennec
- return tab.id
-
- return String(tab.linkedPanel).split('panel').pop();
-}
-exports.getTabId = getTabId;
-
-function getTabForId(id) {
- return getTabs().find(tab => getTabId(tab) === id) || null;
-}
-exports.getTabForId = getTabForId;
-
-function getTabTitle(tab) {
- return getBrowserForTab(tab).contentTitle || tab.label || "";
-}
-exports.getTabTitle = getTabTitle;
-
-function setTabTitle(tab, title) {
- title = String(title);
- if (tab.browser) {
- // Fennec
- tab.browser.contentDocument.title = title;
- }
- else {
- let browser = getBrowserForTab(tab);
- // Note that we aren't actually setting the document title in e10s, just
- // the title the browser thinks the content has
- if (browser.isRemoteBrowser)
- browser._contentTitle = title;
- else
- browser.contentDocument.title = title;
- }
- tab.label = String(title);
-}
-exports.setTabTitle = setTabTitle;
-
-function getTabContentDocument(tab) {
- return getBrowserForTab(tab).contentDocument;
-}
-exports.getTabContentDocument = getTabContentDocument;
-
-function getTabContentWindow(tab) {
- return getBrowserForTab(tab).contentWindow;
-}
-exports.getTabContentWindow = getTabContentWindow;
-
-/**
- * Returns all tabs' content windows across all the browsers' windows
- */
-function getAllTabContentWindows() {
- return getTabs().map(getTabContentWindow);
-}
-exports.getAllTabContentWindows = getAllTabContentWindows;
-
-// gets the tab containing the provided window
-function getTabForContentWindow(window) {
- return getTabs().find(tab => getTabContentWindow(tab) === window.top) || null;
-}
-exports.getTabForContentWindow = getTabForContentWindow;
-
-// only sdk/selection.js is relying on shims
-function getTabForContentWindowNoShim(window) {
- function getTabContentWindowNoShim(tab) {
- let browser = getBrowserForTab(tab);
- return ShimWaiver.getProperty(browser, "contentWindow");
- }
- return getTabs().find(tab => getTabContentWindowNoShim(tab) === window.top) || null;
-}
-exports.getTabForContentWindowNoShim = getTabForContentWindowNoShim;
-
-function getTabURL(tab) {
- return String(getBrowserForTab(tab).currentURI.spec);
-}
-exports.getTabURL = getTabURL;
-
-function setTabURL(tab, url) {
- let browser = getBrowserForTab(tab);
- browser.loadURI(String(url));
-}
-// "TabOpen" event is fired when it's still "about:blank" is loaded in the
-// changing `location` property of the `contentDocument` has no effect since
-// seems to be either ignored or overridden by internal listener, there for
-// location change is enqueued for the next turn of event loop.
-exports.setTabURL = defer(setTabURL);
-
-function getTabContentType(tab) {
- return getBrowserForTab(tab).contentDocument.contentType;
-}
-exports.getTabContentType = getTabContentType;
-
-function getSelectedTab(window) {
- if (window.BrowserApp) // fennec?
- return window.BrowserApp.selectedTab;
- if (window.gBrowser)
- return window.gBrowser.selectedTab;
- return null;
-}
-exports.getSelectedTab = getSelectedTab;
-
-
-function getTabForBrowser(browser) {
- for (let window of getWindows()) {
- // this function may be called when not using fennec
- if (!window.BrowserApp)
- continue;
-
- for (let tab of window.BrowserApp.tabs) {
- if (tab.browser === browser)
- return tab;
- }
- }
-
- let tabbrowser = browser.getTabBrowser && browser.getTabBrowser()
- return !!tabbrowser && tabbrowser.getTabForBrowser(browser);
-}
-exports.getTabForBrowser = getTabForBrowser;
-
-function pin(tab) {
- let gBrowser = getTabBrowserForTab(tab);
- // TODO: Implement Fennec support
- if (gBrowser) gBrowser.pinTab(tab);
-}
-exports.pin = pin;
-
-function unpin(tab) {
- let gBrowser = getTabBrowserForTab(tab);
- // TODO: Implement Fennec support
- if (gBrowser) gBrowser.unpinTab(tab);
-}
-exports.unpin = unpin;
-
-function isPinned(tab) {
- return !!tab.pinned;
-}
-exports.isPinned = isPinned;
-
-function reload(tab) {
- getBrowserForTab(tab).reload();
-}
-exports.reload = reload
-
-function getIndex(tab) {
- let gBrowser = getTabBrowserForTab(tab);
- // Firefox
- if (gBrowser) {
- return tab._tPos;
- }
- // Fennec
- else {
- let window = getWindowHoldingTab(tab)
- let tabs = window.BrowserApp.tabs;
- for (let i = tabs.length; i >= 0; i--)
- if (tabs[i] === tab) return i;
- }
-}
-exports.getIndex = getIndex;
-
-function move(tab, index) {
- let gBrowser = getTabBrowserForTab(tab);
- // Firefox
- if (gBrowser) gBrowser.moveTabTo(tab, index);
- // TODO: Implement fennec support
-}
-exports.move = move;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/tabs/worker.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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 ContentWorker = require('../content/worker').Worker;
-
-function Worker(options, window) {
- options.window = window;
-
- let worker = ContentWorker(options);
- worker.once("detach", function detach() {
- worker.destroy();
- });
- return worker;
-}
-exports.Worker = Worker;
\ No newline at end of file
--- a/addon-sdk/source/lib/sdk/test/utils.js
+++ b/addon-sdk/source/lib/sdk/test/utils.js
@@ -178,22 +178,15 @@ function waitUntil (predicate, delay) {
}, delay || 10);
return promise;
}
exports.waitUntil = waitUntil;
var cleanUI = function cleanUI() {
let { promise, resolve } = defer();
- let windows = getWindows(null, { includePrivate: true });
- if (windows.length > 1) {
- return closeWindow(windows[1]).then(cleanUI);
- }
-
- getTabs(windows[0]).slice(1).forEach(closeTab);
-
resolve();
return promise;
}
exports.cleanUI = cleanUI;
exports.isTravisCI = ("TRAVIS" in env && "CI" in env);
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/window/browser.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/* 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 { Class } = require('../core/heritage');
-const { windowNS } = require('./namespace');
-const { on, off, once } = require('../event/core');
-const { method } = require('../lang/functional');
-const { getWindowTitle } = require('./utils');
-const unload = require('../system/unload');
-const { EventTarget } = require('../event/target');
-const { isPrivate } = require('../private-browsing/utils');
-const { isWindowPrivate, isFocused } = require('../window/utils');
-const { viewFor } = require('../view/core');
-
-const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec, consider using require("sdk/tabs") instead';
-
-const BrowserWindow = Class({
- initialize: function initialize(options) {
- EventTarget.prototype.initialize.call(this, options);
- windowNS(this).window = options.window;
- },
- activate: function activate() {
- // TODO
- return null;
- },
- close: function() {
- throw new Error(ERR_FENNEC_MSG);
- return null;
- },
- get title() {
- return getWindowTitle(windowNS(this).window);
- },
- // NOTE: Fennec only has one window, which is assumed below
- // TODO: remove assumption below
- // NOTE: tabs requires windows
- get tabs() {
- return require('../tabs');
- },
- get activeTab() {
- return require('../tabs').activeTab;
- },
- on: method(on),
- removeListener: method(off),
- once: method(once)
-});
-exports.BrowserWindow = BrowserWindow;
-
-const getWindowView = window => windowNS(window).window;
-
-viewFor.define(BrowserWindow, getWindowView);
-isPrivate.define(BrowserWindow, (window) => isWindowPrivate(viewFor(window).window));
-isFocused.define(BrowserWindow, (window) => isFocused(viewFor(window).window));
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/window/events.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { Ci, Cu } = require("chrome");
-const { observe } = require("../event/chrome");
-const { open } = require("../event/dom");
-const { windows } = require("../window/utils");
-const { filter, merge, map, expand } = require("../event/utils");
-
-function documentMatches(weakWindow, event) {
- let window = weakWindow.get();
- return window && event.target === window.document;
-}
-
-function makeStrictDocumentFilter(window) {
- // Note: Do not define a closure within this function. Otherwise
- // you may leak the window argument.
- let weak = Cu.getWeakReference(window);
- return documentMatches.bind(null, weak);
-}
-
-function toEventWithDefaultViewTarget({type, target}) {
- return { type: type, target: target.defaultView }
-}
-
-// Function registers single shot event listeners for relevant window events
-// that forward events to exported event stream.
-function eventsFor(window) {
- // NOTE: Do no use pass a closure from this function into a stream
- // transform function. You will capture the window in the
- // closure and leak the window until the event stream is
- // completely closed.
- let interactive = open(window, "DOMContentLoaded", { capture: true });
- let complete = open(window, "load", { capture: true });
- let states = merge([interactive, complete]);
- let changes = filter(states, makeStrictDocumentFilter(window));
- return map(changes, toEventWithDefaultViewTarget);
-}
-
-// Create our event channels. We do this in a separate function to
-// minimize the chance of leaking intermediate objects on the global.
-function makeEvents() {
- // In addition to observing windows that are open we also observe windows
- // that are already already opened in case they're in process of loading.
- var opened = windows(null, { includePrivate: true });
- var currentEvents = merge(opened.map(eventsFor));
-
- // Register system event listeners for top level window open / close.
- function rename({type, target, data}) {
- return { type: rename[type], target: target, data: data }
- }
- rename.domwindowopened = "open";
- rename.domwindowclosed = "close";
-
- var openEvents = map(observe("domwindowopened"), rename);
- var closeEvents = map(observe("domwindowclosed"), rename);
- var futureEvents = expand(openEvents, ({target}) => eventsFor(target));
-
- return merge([currentEvents, futureEvents, openEvents, closeEvents]);
-}
-
-exports.events = makeEvents();
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/window/helpers.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/* 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 { defer, all } = require('../core/promise');
-const events = require('../system/events');
-const { open: openWindow, onFocus, getToplevelWindow,
- isInteractive, isStartupFinished, getOuterId } = require('./utils');
-const { Ci } = require("chrome");
-
-function open(uri, options) {
- return promise(openWindow.apply(null, arguments), 'load').then(focus);
-}
-exports.open = open;
-
-function close(window) {
- let deferred = defer();
- let toplevelWindow = getToplevelWindow(window);
- let outerId = getOuterId(toplevelWindow);
- events.on("outer-window-destroyed", function onclose({subject}) {
- let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
- if (id == outerId) {
- events.off("outer-window-destroyed", onclose);
- deferred.resolve();
- }
- }, true);
- window.close();
- return deferred.promise;
-}
-exports.close = close;
-
-function focus(window) {
- let p = onFocus(window);
- window.focus();
- return p;
-}
-exports.focus = focus;
-
-function ready(window) {
- let { promise: result, resolve } = defer();
-
- if (isInteractive(window))
- resolve(window);
- else
- resolve(promise(window, 'DOMContentLoaded'));
-
- return result;
-}
-exports.ready = ready;
-
-function startup(window) {
- let { promise: result, resolve } = defer();
-
- if (isStartupFinished(window)) {
- resolve(window);
- } else {
- events.on("browser-delayed-startup-finished", function listener({subject}) {
- if (subject === window) {
- events.off("browser-delayed-startup-finished", listener);
- resolve(window);
- }
- });
- }
-
- return result;
-}
-exports.startup = startup;
-
-function promise(target, evt, capture) {
- let deferred = defer();
- capture = !!capture;
-
- target.addEventListener(evt, function() {
- deferred.resolve(target);
- }, {capture, once: true});
-
- return deferred.promise;
-}
-exports.promise = promise;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/window/namespace.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/* 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";
-
-exports.windowNS = require('../core/namespace').ns();
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/windows.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 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';
-
-module.metadata = {
- 'stability': 'stable'
-};
-
-const { isBrowser } = require('./window/utils');
-const { modelFor } = require('./model/core');
-const { viewFor } = require('./view/core');
-
-
-if (require('./system/xul-app').is('Fennec')) {
- module.exports = require('./windows/fennec');
-}
-else {
- module.exports = require('./windows/firefox');
-}
-
-
-const browsers = module.exports.browserWindows;
-
-//
-modelFor.when(isBrowser, view => {
- for (let model of browsers) {
- if (viewFor(model) === view)
- return model;
- }
- return null;
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/windows/fennec.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/* 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 { Class } = require('../core/heritage');
-const { BrowserWindow } = require('../window/browser');
-const { WindowTracker } = require('../deprecated/window-utils');
-const { isBrowser, getMostRecentBrowserWindow } = require('../window/utils');
-const { windowNS } = require('../window/namespace');
-const { on, off, once, emit } = require('../event/core');
-const { method } = require('../lang/functional');
-const { EventTarget } = require('../event/target');
-const { List, addListItem } = require('../util/list');
-
-const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec, consider using require("sdk/tabs") instead';
-
-// NOTE: On Fennec there is only one window.
-
-var BrowserWindows = Class({
- implements: [ List ],
- extends: EventTarget,
- initialize: function() {
- List.prototype.initialize.apply(this);
- },
- get activeWindow() {
- let window = getMostRecentBrowserWindow();
- return window ? getBrowserWindow({window: window}) : null;
- },
- open: function open(options) {
- throw new Error(ERR_FENNEC_MSG);
- return null;
- }
-});
-const browserWindows = exports.browserWindows = BrowserWindows();
-
-
-/**
- * Gets a `BrowserWindow` for the given `chromeWindow` if previously
- * registered, `null` otherwise.
- */
-function getRegisteredWindow(chromeWindow) {
- for (let window of browserWindows) {
- if (chromeWindow === windowNS(window).window)
- return window;
- }
-
- return null;
-}
-
-/**
- * Gets a `BrowserWindow` for the provided window options obj
- * @params {Object} options
- * Options that are passed to the the `BrowserWindow`
- * @returns {BrowserWindow}
- */
-function getBrowserWindow(options) {
- let window = null;
-
- // if we have a BrowserWindow already then use it
- if ('window' in options)
- window = getRegisteredWindow(options.window);
- if (window)
- return window;
-
- // we don't have a BrowserWindow yet, so create one
- window = BrowserWindow(options);
- addListItem(browserWindows, window);
- return window;
-}
-
-WindowTracker({
- onTrack: function onTrack(chromeWindow) {
- if (!isBrowser(chromeWindow)) return;
- let window = getBrowserWindow({ window: chromeWindow });
- emit(browserWindows, 'open', window);
- },
- onUntrack: function onUntrack(chromeWindow) {
- if (!isBrowser(chromeWindow)) return;
- let window = getBrowserWindow({ window: chromeWindow });
- emit(browserWindows, 'close', window);
- }
-});
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/windows/firefox.js
+++ /dev/null
@@ -1,224 +0,0 @@
-/* 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 { Class } = require('../core/heritage');
-const { observer } = require('./observer');
-const { isBrowser, getMostRecentBrowserWindow, windows, open, getInnerId,
- getWindowTitle, getToplevelWindow, isFocused, isWindowPrivate } = require('../window/utils');
-const { List, addListItem, removeListItem } = require('../util/list');
-const { viewFor } = require('../view/core');
-const { modelFor } = require('../model/core');
-const { emit, emitOnObject, setListeners } = require('../event/core');
-const { once } = require('../dom/events');
-const { EventTarget } = require('../event/target');
-const { getSelectedTab } = require('../tabs/utils');
-const { Cc, Ci } = require('chrome');
-const { Options } = require('../tabs/common');
-const system = require('../system/events');
-const { ignoreWindow, isPrivate, isWindowPBSupported } = require('../private-browsing/utils');
-const { data, isPrivateBrowsingSupported } = require('../self');
-const { setImmediate } = require('../timers');
-
-const supportPrivateWindows = isPrivateBrowsingSupported && isWindowPBSupported;
-
-const modelsFor = new WeakMap();
-const viewsFor = new WeakMap();
-
-const Window = Class({
- implements: [EventTarget],
- initialize: function(domWindow) {
- modelsFor.set(domWindow, this);
- viewsFor.set(this, domWindow);
- },
-
- get title() {
- return getWindowTitle(viewsFor.get(this));
- },
-
- activate: function() {
- viewsFor.get(this).focus();
- },
-
- close: function(callback) {
- let domWindow = viewsFor.get(this);
-
- if (callback) {
- // We want to catch the close event immediately after the close events are
- // emitted everywhere but without letting the event loop spin. Registering
- // for the same events as windowEventListener but afterwards does this
- let listener = (event, closedWin) => {
- if (event != "close" || closedWin != domWindow)
- return;
-
- observer.off("*", listener);
- callback();
- }
-
- observer.on("*", listener);
- }
-
- domWindow.close();
- }
-});
-
-const windowTabs = new WeakMap();
-
-const BrowserWindow = Class({
- extends: Window,
-
- get tabs() {
- let tabs = windowTabs.get(this);
- if (tabs)
- return tabs;
-
- return new WindowTabs(this);
- }
-});
-
-const WindowTabs = Class({
- implements: [EventTarget],
- extends: List,
- initialize: function(window) {
- List.prototype.initialize.call(this);
- windowTabs.set(window, this);
- viewsFor.set(this, viewsFor.get(window));
-
- // Make sure the tabs module has loaded and found all existing tabs
- const tabs = require('../tabs');
-
- for (let tab of tabs) {
- if (tab.window == window)
- addListItem(this, tab);
- }
- },
-
- get activeTab() {
- return modelFor(getSelectedTab(viewsFor.get(this)));
- },
-
- open: function(options) {
- options = Options(options);
-
- let domWindow = viewsFor.get(this);
- let { Tab } = require('../tabs/tab-firefox');
-
- // The capturing listener will see the TabOpen event before
- // sdk/tabs/observer giving us time to set up the tab and listeners before
- // the real open event is fired
- let listener = event => {
- new Tab(event.target, options);
- };
-
- once(domWindow, "TabOpen", listener, true);
- domWindow.gBrowser.addTab(options.url);
- }
-});
-
-const BrowserWindows = Class({
- implements: [EventTarget],
- extends: List,
- initialize: function() {
- List.prototype.initialize.call(this);
- },
-
- get activeWindow() {
- let domWindow = getMostRecentBrowserWindow();
- if (ignoreWindow(domWindow))
- return null;
- return modelsFor.get(domWindow);
- },
-
- open: function(options) {
- if (typeof options == "string")
- options = { url: options };
-
- let { url, isPrivate } = options;
- if (url)
- url = data.url(url);
-
- let args = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- args.data = url;
-
- let features = {
- chrome: true,
- all: true,
- dialog: false
- };
- features.private = supportPrivateWindows && isPrivate;
-
- let domWindow = open(null, {
- parent: null,
- name: "_blank",
- features,
- args
- })
-
- let window = makeNewWindow(domWindow, true);
- setListeners(window, options);
- return window;
- }
-});
-
-const browserWindows = new BrowserWindows();
-exports.browserWindows = browserWindows;
-
-function windowEmit(window, event, ...args) {
- if (window instanceof BrowserWindow && (event == "open" || event == "close"))
- emitOnObject(window, event, browserWindows, window, ...args);
- else
- emit(window, event, window, ...args);
-
- if (window instanceof BrowserWindow)
- emit(browserWindows, event, window, ...args);
-}
-
-function makeNewWindow(domWindow, browserHint = false) {
- if (browserHint || isBrowser(domWindow))
- return new BrowserWindow(domWindow);
- else
- return new Window(domWindow);
-}
-
-for (let domWindow of windows(null, {includePrivate: supportPrivateWindows})) {
- let window = makeNewWindow(domWindow);
- if (window instanceof BrowserWindow)
- addListItem(browserWindows, window);
-}
-
-var windowEventListener = (event, domWindow, ...args) => {
- let toplevelWindow = getToplevelWindow(domWindow);
-
- if (ignoreWindow(toplevelWindow))
- return;
-
- let window = modelsFor.get(toplevelWindow);
- if (!window)
- window = makeNewWindow(toplevelWindow);
-
- if (isBrowser(toplevelWindow)) {
- if (event == "open")
- addListItem(browserWindows, window);
- else if (event == "close")
- removeListItem(browserWindows, window);
- }
-
- windowEmit(window, event, ...args);
-
- // The window object shouldn't be reachable after closed
- if (event == "close") {
- viewsFor.delete(window);
- modelsFor.delete(toplevelWindow);
- }
-};
-observer.on("*", windowEventListener);
-
-viewFor.define(BrowserWindow, window => {
- return viewsFor.get(window);
-})
-
-const isBrowserWindow = (x) => x instanceof BrowserWindow;
-isPrivate.when(isBrowserWindow, (w) => isWindowPrivate(viewsFor.get(w)));
-isFocused.when(isBrowserWindow, (w) => isFocused(viewsFor.get(w)));
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/windows/observer.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/* 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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { EventTarget } = require("../event/target");
-const { emit } = require("../event/core");
-const { WindowTracker, windowIterator } = require("../deprecated/window-utils");
-const { DOMEventAssembler } = require("../deprecated/events/assembler");
-const { Class } = require("../core/heritage");
-const { Cu } = require("chrome");
-
-// Event emitter objects used to register listeners and emit events on them
-// when they occur.
-const Observer = Class({
- initialize() {
- // Using `WindowTracker` to track window events.
- WindowTracker({
- onTrack: chromeWindow => {
- emit(this, "open", chromeWindow);
- this.observe(chromeWindow);
- },
- onUntrack: chromeWindow => {
- emit(this, "close", chromeWindow);
- this.ignore(chromeWindow);
- }
- });
- },
- implements: [EventTarget, DOMEventAssembler],
- /**
- * Events that are supported and emitted by the module.
- */
- supportedEventsTypes: [ "activate", "deactivate" ],
- /**
- * Function handles all the supported events on all the windows that are
- * observed. Method is used to proxy events to the listeners registered on
- * this event emitter.
- * @param {Event} event
- * Keyboard event being emitted.
- */
- handleEvent(event) {
- // Ignore events from windows in the child process as they can't be top-level
- if (Cu.isCrossProcessWrapper(event.target))
- return;
- emit(this, event.type, event.target, event);
- }
-});
-
-exports.observer = new Observer();
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
+++ /dev/null
@@ -1,172 +0,0 @@
-/* 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 { Class } = require('../core/heritage');
-const { Tab } = require('../tabs/tab');
-const { browserWindows } = require('./fennec');
-const { windowNS } = require('../window/namespace');
-const { tabsNS, tabNS } = require('../tabs/namespace');
-const { openTab, getTabs, getSelectedTab, getTabForBrowser: getRawTabForBrowser,
- getTabContentWindow } = require('../tabs/utils');
-const { Options } = require('../tabs/common');
-const { getTabForBrowser, getTabForRawTab } = require('../tabs/helpers');
-const { on, once, off, emit } = require('../event/core');
-const { method } = require('../lang/functional');
-const { EVENTS } = require('../tabs/events');
-const { EventTarget } = require('../event/target');
-const { when: unload } = require('../system/unload');
-const { windowIterator } = require('../deprecated/window-utils');
-const { List, addListItem, removeListItem } = require('../util/list');
-const { isPrivateBrowsingSupported, data } = require('../self');
-const { isTabPBSupported, ignoreWindow } = require('../private-browsing/utils');
-
-const mainWindow = windowNS(browserWindows.activeWindow).window;
-
-const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
-
-const supportPrivateTabs = isPrivateBrowsingSupported && isTabPBSupported;
-
-const Tabs = Class({
- implements: [ List ],
- extends: EventTarget,
- initialize: function initialize(options) {
- let tabsInternals = tabsNS(this);
- let window = tabsNS(this).window = options.window || mainWindow;
-
- EventTarget.prototype.initialize.call(this, options);
- List.prototype.initialize.apply(this, getTabs(window).map(Tab));
-
- // TabOpen event
- window.BrowserApp.deck.addEventListener(EVENTS.open.dom, onTabOpen);
-
- // TabSelect
- window.BrowserApp.deck.addEventListener(EVENTS.activate.dom, onTabSelect);
- },
- get activeTab() {
- return getTabForRawTab(getSelectedTab(tabsNS(this).window));
- },
- open: function(options) {
- options = Options(options);
- let activeWin = browserWindows.activeWindow;
-
- if (options.isPinned) {
- console.error(ERR_FENNEC_MSG); // TODO
- }
-
- let url = options.url ? data.url(options.url) : options.url;
- let rawTab = openTab(windowNS(activeWin).window, url, {
- inBackground: options.inBackground,
- isPrivate: supportPrivateTabs && options.isPrivate
- });
-
- // by now the tab has been created
- let tab = getTabForRawTab(rawTab);
-
- if (options.onClose)
- tab.on('close', options.onClose);
-
- if (options.onOpen) {
- // NOTE: on Fennec this will be true
- if (tabNS(tab).opened)
- options.onOpen(tab);
-
- tab.on('open', options.onOpen);
- }
-
- if (options.onReady)
- tab.on('ready', options.onReady);
-
- if (options.onLoad)
- tab.on('load', options.onLoad);
-
- if (options.onPageShow)
- tab.on('pageshow', options.onPageShow);
-
- if (options.onActivate)
- tab.on('activate', options.onActivate);
-
- return tab;
- }
-});
-var gTabs = exports.tabs = Tabs(mainWindow);
-
-function tabsUnloader(event, window) {
- window = window || (event && event.target);
- if (!(window && window.BrowserApp))
- return;
- window.BrowserApp.deck.removeEventListener(EVENTS.open.dom, onTabOpen);
- window.BrowserApp.deck.removeEventListener(EVENTS.activate.dom, onTabSelect);
-}
-
-// unload handler
-unload(function() {
- for (let window in windowIterator()) {
- tabsUnloader(null, window);
- }
-});
-
-function addTab(tab) {
- addListItem(gTabs, tab);
- return tab;
-}
-
-function removeTab(tab) {
- removeListItem(gTabs, tab);
- return tab;
-}
-
-// TabOpen
-function onTabOpen(event) {
- let browser = event.target;
-
- // Eventually ignore private tabs
- if (ignoreWindow(browser.contentWindow))
- return;
-
- let tab = getTabForBrowser(browser);
- if (tab === null) {
- let rawTab = getRawTabForBrowser(browser);
-
- // create a Tab instance for this new tab
- tab = addTab(Tab(rawTab));
- }
-
- tabNS(tab).opened = true;
-
- tab.on('ready', () => emit(gTabs, 'ready', tab));
- tab.once('close', onTabClose);
-
- tab.on('pageshow', (_tab, persisted) =>
- emit(gTabs, 'pageshow', tab, persisted));
-
- emit(tab, 'open', tab);
- emit(gTabs, 'open', tab);
-}
-
-// TabSelect
-function onTabSelect(event) {
- let browser = event.target;
-
- // Eventually ignore private tabs
- if (ignoreWindow(browser.contentWindow))
- return;
-
- // Set value whenever new tab becomes active.
- let tab = getTabForBrowser(browser);
- emit(tab, 'activate', tab);
- emit(gTabs, 'activate', tab);
-
- for (let t of gTabs) {
- if (t === tab) continue;
- emit(t, 'deactivate', t);
- emit(gTabs, 'deactivate', t);
- }
-}
-
-// TabClose
-function onTabClose(tab) {
- removeTab(tab);
- emit(gTabs, EVENTS.close.name, tab);
-}
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/worker/utils.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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';
-
-module.metadata = {
- 'stability': 'deprecated'
-};
-
-const {
- requiresAddonGlobal, attach, detach, destroy, WorkerHost
-} = require('../content/utils');
-
-exports.WorkerHost = WorkerHost;
-exports.detach = detach;
-exports.attach = attach;
-exports.destroy = destroy;
-exports.requiresAddonGlobal = requiresAddonGlobal;