summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/lib/sdk
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2018-02-09 06:46:43 -0500
committerMatt A. Tobin <email@mattatobin.com>2018-02-09 06:46:43 -0500
commitac46df8daea09899ce30dc8fd70986e258c746bf (patch)
tree2750d3125fc253fd5b0671e4bd268eff1fd97296 /addon-sdk/source/lib/sdk
parent8cecf8d5208f3945b35f879bba3015bb1a11bec6 (diff)
downloadUXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.gz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.lz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.xz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.zip
Move Add-on SDK source to toolkit/jetpack
Diffstat (limited to 'addon-sdk/source/lib/sdk')
-rw-r--r--addon-sdk/source/lib/sdk/addon/bootstrap.js182
-rw-r--r--addon-sdk/source/lib/sdk/addon/events.js56
-rw-r--r--addon-sdk/source/lib/sdk/addon/host.js12
-rw-r--r--addon-sdk/source/lib/sdk/addon/installer.js121
-rw-r--r--addon-sdk/source/lib/sdk/addon/manager.js18
-rw-r--r--addon-sdk/source/lib/sdk/addon/runner.js180
-rw-r--r--addon-sdk/source/lib/sdk/addon/window.js66
-rw-r--r--addon-sdk/source/lib/sdk/base64.js47
-rw-r--r--addon-sdk/source/lib/sdk/browser/events.js20
-rw-r--r--addon-sdk/source/lib/sdk/clipboard.js337
-rw-r--r--addon-sdk/source/lib/sdk/console/plain-text.js78
-rw-r--r--addon-sdk/source/lib/sdk/console/traceback.js86
-rw-r--r--addon-sdk/source/lib/sdk/content/content-worker.js305
-rw-r--r--addon-sdk/source/lib/sdk/content/content.js17
-rw-r--r--addon-sdk/source/lib/sdk/content/context-menu.js408
-rw-r--r--addon-sdk/source/lib/sdk/content/events.js57
-rw-r--r--addon-sdk/source/lib/sdk/content/l10n-html.js133
-rw-r--r--addon-sdk/source/lib/sdk/content/loader.js74
-rw-r--r--addon-sdk/source/lib/sdk/content/mod.js68
-rw-r--r--addon-sdk/source/lib/sdk/content/page-mod.js236
-rw-r--r--addon-sdk/source/lib/sdk/content/page-worker.js154
-rw-r--r--addon-sdk/source/lib/sdk/content/sandbox.js426
-rw-r--r--addon-sdk/source/lib/sdk/content/sandbox/events.js12
-rw-r--r--addon-sdk/source/lib/sdk/content/tab-events.js58
-rw-r--r--addon-sdk/source/lib/sdk/content/thumbnail.js51
-rw-r--r--addon-sdk/source/lib/sdk/content/utils.js105
-rw-r--r--addon-sdk/source/lib/sdk/content/worker-child.js158
-rw-r--r--addon-sdk/source/lib/sdk/content/worker.js180
-rw-r--r--addon-sdk/source/lib/sdk/context-menu.js1188
-rw-r--r--addon-sdk/source/lib/sdk/context-menu/context.js147
-rw-r--r--addon-sdk/source/lib/sdk/context-menu/core.js384
-rw-r--r--addon-sdk/source/lib/sdk/context-menu/readers.js112
-rw-r--r--addon-sdk/source/lib/sdk/context-menu@2.js32
-rw-r--r--addon-sdk/source/lib/sdk/core/disposable.js186
-rw-r--r--addon-sdk/source/lib/sdk/core/heritage.js184
-rw-r--r--addon-sdk/source/lib/sdk/core/namespace.js43
-rw-r--r--addon-sdk/source/lib/sdk/core/observer.js89
-rw-r--r--addon-sdk/source/lib/sdk/core/promise.js118
-rw-r--r--addon-sdk/source/lib/sdk/core/reference.js29
-rw-r--r--addon-sdk/source/lib/sdk/deprecated/api-utils.js197
-rw-r--r--addon-sdk/source/lib/sdk/deprecated/events/assembler.js54
-rw-r--r--addon-sdk/source/lib/sdk/deprecated/sync-worker.js288
-rw-r--r--addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js199
-rw-r--r--addon-sdk/source/lib/sdk/deprecated/unit-test.js584
-rw-r--r--addon-sdk/source/lib/sdk/deprecated/window-utils.js193
-rw-r--r--addon-sdk/source/lib/sdk/dom/events-shimmed.js18
-rw-r--r--addon-sdk/source/lib/sdk/dom/events.js192
-rw-r--r--addon-sdk/source/lib/sdk/dom/events/keys.js63
-rw-r--r--addon-sdk/source/lib/sdk/event/chrome.js65
-rw-r--r--addon-sdk/source/lib/sdk/event/core.js193
-rw-r--r--addon-sdk/source/lib/sdk/event/dom.js78
-rw-r--r--addon-sdk/source/lib/sdk/event/target.js74
-rw-r--r--addon-sdk/source/lib/sdk/event/utils.js328
-rw-r--r--addon-sdk/source/lib/sdk/frame/hidden-frame.js115
-rw-r--r--addon-sdk/source/lib/sdk/frame/utils.js94
-rw-r--r--addon-sdk/source/lib/sdk/fs/path.js500
-rw-r--r--addon-sdk/source/lib/sdk/hotkeys.js40
-rw-r--r--addon-sdk/source/lib/sdk/indexed-db.js79
-rw-r--r--addon-sdk/source/lib/sdk/input/browser.js73
-rw-r--r--addon-sdk/source/lib/sdk/input/customizable-ui.js28
-rw-r--r--addon-sdk/source/lib/sdk/input/frame.js85
-rw-r--r--addon-sdk/source/lib/sdk/input/system.js113
-rw-r--r--addon-sdk/source/lib/sdk/io/buffer.js351
-rw-r--r--addon-sdk/source/lib/sdk/io/byte-streams.js104
-rw-r--r--addon-sdk/source/lib/sdk/io/file.js196
-rw-r--r--addon-sdk/source/lib/sdk/io/fs.js984
-rw-r--r--addon-sdk/source/lib/sdk/io/stream.js440
-rw-r--r--addon-sdk/source/lib/sdk/io/text-streams.js235
-rw-r--r--addon-sdk/source/lib/sdk/keyboard/hotkeys.js110
-rw-r--r--addon-sdk/source/lib/sdk/keyboard/observer.js58
-rw-r--r--addon-sdk/source/lib/sdk/keyboard/utils.js189
-rw-r--r--addon-sdk/source/lib/sdk/l10n.js91
-rw-r--r--addon-sdk/source/lib/sdk/l10n/core.js9
-rw-r--r--addon-sdk/source/lib/sdk/l10n/html.js32
-rw-r--r--addon-sdk/source/lib/sdk/l10n/json/core.js36
-rw-r--r--addon-sdk/source/lib/sdk/l10n/loader.js70
-rw-r--r--addon-sdk/source/lib/sdk/l10n/locale.js127
-rw-r--r--addon-sdk/source/lib/sdk/l10n/plural-rules.js407
-rw-r--r--addon-sdk/source/lib/sdk/l10n/prefs.js51
-rw-r--r--addon-sdk/source/lib/sdk/l10n/properties/core.js87
-rw-r--r--addon-sdk/source/lib/sdk/lang/functional.js47
-rw-r--r--addon-sdk/source/lib/sdk/lang/functional/concurrent.js110
-rw-r--r--addon-sdk/source/lib/sdk/lang/functional/core.js290
-rw-r--r--addon-sdk/source/lib/sdk/lang/functional/helpers.js29
-rw-r--r--addon-sdk/source/lib/sdk/lang/type.js388
-rw-r--r--addon-sdk/source/lib/sdk/lang/weak-set.js75
-rw-r--r--addon-sdk/source/lib/sdk/loader/cuddlefish.js102
-rw-r--r--addon-sdk/source/lib/sdk/loader/sandbox.js74
-rw-r--r--addon-sdk/source/lib/sdk/messaging.js12
-rw-r--r--addon-sdk/source/lib/sdk/model/core.js23
-rw-r--r--addon-sdk/source/lib/sdk/net/url.js94
-rw-r--r--addon-sdk/source/lib/sdk/net/xhr.js36
-rw-r--r--addon-sdk/source/lib/sdk/notifications.js112
-rw-r--r--addon-sdk/source/lib/sdk/output/system.js71
-rw-r--r--addon-sdk/source/lib/sdk/page-mod.js190
-rw-r--r--addon-sdk/source/lib/sdk/page-mod/match-pattern.js10
-rw-r--r--addon-sdk/source/lib/sdk/page-worker.js194
-rw-r--r--addon-sdk/source/lib/sdk/panel.js427
-rw-r--r--addon-sdk/source/lib/sdk/panel/events.js27
-rw-r--r--addon-sdk/source/lib/sdk/panel/utils.js451
-rw-r--r--addon-sdk/source/lib/sdk/passwords.js61
-rw-r--r--addon-sdk/source/lib/sdk/passwords/utils.js107
-rw-r--r--addon-sdk/source/lib/sdk/places/bookmarks.js395
-rw-r--r--addon-sdk/source/lib/sdk/places/contract.js73
-rw-r--r--addon-sdk/source/lib/sdk/places/events.js128
-rw-r--r--addon-sdk/source/lib/sdk/places/favicon.js49
-rw-r--r--addon-sdk/source/lib/sdk/places/history.js65
-rw-r--r--addon-sdk/source/lib/sdk/places/host/host-bookmarks.js238
-rw-r--r--addon-sdk/source/lib/sdk/places/host/host-query.js179
-rw-r--r--addon-sdk/source/lib/sdk/places/host/host-tags.js92
-rw-r--r--addon-sdk/source/lib/sdk/places/utils.js268
-rw-r--r--addon-sdk/source/lib/sdk/platform/xpcom.js241
-rw-r--r--addon-sdk/source/lib/sdk/preferences/event-target.js61
-rw-r--r--addon-sdk/source/lib/sdk/preferences/native-options.js193
-rw-r--r--addon-sdk/source/lib/sdk/preferences/service.js137
-rw-r--r--addon-sdk/source/lib/sdk/preferences/utils.js42
-rw-r--r--addon-sdk/source/lib/sdk/private-browsing.js12
-rw-r--r--addon-sdk/source/lib/sdk/private-browsing/utils.js54
-rw-r--r--addon-sdk/source/lib/sdk/querystring.js121
-rw-r--r--addon-sdk/source/lib/sdk/remote/child.js284
-rw-r--r--addon-sdk/source/lib/sdk/remote/core.js8
-rw-r--r--addon-sdk/source/lib/sdk/remote/parent.js338
-rw-r--r--addon-sdk/source/lib/sdk/remote/utils.js39
-rw-r--r--addon-sdk/source/lib/sdk/request.js248
-rw-r--r--addon-sdk/source/lib/sdk/selection.js470
-rw-r--r--addon-sdk/source/lib/sdk/self.js61
-rw-r--r--addon-sdk/source/lib/sdk/simple-prefs.js26
-rw-r--r--addon-sdk/source/lib/sdk/simple-storage.js235
-rw-r--r--addon-sdk/source/lib/sdk/stylesheet/style.js71
-rw-r--r--addon-sdk/source/lib/sdk/stylesheet/utils.js75
-rw-r--r--addon-sdk/source/lib/sdk/system.js172
-rw-r--r--addon-sdk/source/lib/sdk/system/child_process.js332
-rw-r--r--addon-sdk/source/lib/sdk/system/child_process/subprocess.js186
-rw-r--r--addon-sdk/source/lib/sdk/system/environment.js33
-rw-r--r--addon-sdk/source/lib/sdk/system/events-shimmed.js16
-rw-r--r--addon-sdk/source/lib/sdk/system/events.js181
-rw-r--r--addon-sdk/source/lib/sdk/system/globals.js46
-rw-r--r--addon-sdk/source/lib/sdk/system/process.js62
-rw-r--r--addon-sdk/source/lib/sdk/system/runtime.js28
-rw-r--r--addon-sdk/source/lib/sdk/system/unload.js104
-rw-r--r--addon-sdk/source/lib/sdk/system/xul-app.js12
-rw-r--r--addon-sdk/source/lib/sdk/system/xul-app.jsm242
-rw-r--r--addon-sdk/source/lib/sdk/tab/events.js74
-rw-r--r--addon-sdk/source/lib/sdk/tabs.js17
-rw-r--r--addon-sdk/source/lib/sdk/tabs/common.js34
-rw-r--r--addon-sdk/source/lib/sdk/tabs/events.js39
-rw-r--r--addon-sdk/source/lib/sdk/tabs/helpers.js22
-rw-r--r--addon-sdk/source/lib/sdk/tabs/namespace.js10
-rw-r--r--addon-sdk/source/lib/sdk/tabs/observer.js113
-rw-r--r--addon-sdk/source/lib/sdk/tabs/tab-fennec.js249
-rw-r--r--addon-sdk/source/lib/sdk/tabs/tab-firefox.js353
-rw-r--r--addon-sdk/source/lib/sdk/tabs/tab.js24
-rw-r--r--addon-sdk/source/lib/sdk/tabs/tabs-firefox.js135
-rw-r--r--addon-sdk/source/lib/sdk/tabs/utils.js370
-rw-r--r--addon-sdk/source/lib/sdk/tabs/worker.js17
-rw-r--r--addon-sdk/source/lib/sdk/test.js114
-rw-r--r--addon-sdk/source/lib/sdk/test/assert.js366
-rw-r--r--addon-sdk/source/lib/sdk/test/harness.js645
-rw-r--r--addon-sdk/source/lib/sdk/test/httpd.js6
-rw-r--r--addon-sdk/source/lib/sdk/test/loader.js123
-rw-r--r--addon-sdk/source/lib/sdk/test/memory.js11
-rw-r--r--addon-sdk/source/lib/sdk/test/options.js23
-rw-r--r--addon-sdk/source/lib/sdk/test/runner.js131
-rw-r--r--addon-sdk/source/lib/sdk/test/utils.js199
-rw-r--r--addon-sdk/source/lib/sdk/timers.js105
-rw-r--r--addon-sdk/source/lib/sdk/ui.js17
-rw-r--r--addon-sdk/source/lib/sdk/ui/button/action.js114
-rw-r--r--addon-sdk/source/lib/sdk/ui/button/contract.js73
-rw-r--r--addon-sdk/source/lib/sdk/ui/button/toggle.js127
-rw-r--r--addon-sdk/source/lib/sdk/ui/button/view.js243
-rw-r--r--addon-sdk/source/lib/sdk/ui/button/view/events.js18
-rw-r--r--addon-sdk/source/lib/sdk/ui/component.js182
-rw-r--r--addon-sdk/source/lib/sdk/ui/frame.js16
-rw-r--r--addon-sdk/source/lib/sdk/ui/frame/model.js154
-rw-r--r--addon-sdk/source/lib/sdk/ui/frame/view.html18
-rw-r--r--addon-sdk/source/lib/sdk/ui/frame/view.js150
-rw-r--r--addon-sdk/source/lib/sdk/ui/id.js27
-rw-r--r--addon-sdk/source/lib/sdk/ui/sidebar.js311
-rw-r--r--addon-sdk/source/lib/sdk/ui/sidebar/actions.js10
-rw-r--r--addon-sdk/source/lib/sdk/ui/sidebar/contract.js27
-rw-r--r--addon-sdk/source/lib/sdk/ui/sidebar/namespace.js15
-rw-r--r--addon-sdk/source/lib/sdk/ui/sidebar/utils.js8
-rw-r--r--addon-sdk/source/lib/sdk/ui/sidebar/view.js214
-rw-r--r--addon-sdk/source/lib/sdk/ui/state.js239
-rw-r--r--addon-sdk/source/lib/sdk/ui/state/events.js18
-rw-r--r--addon-sdk/source/lib/sdk/ui/toolbar.js16
-rw-r--r--addon-sdk/source/lib/sdk/ui/toolbar/model.js151
-rw-r--r--addon-sdk/source/lib/sdk/ui/toolbar/view.js248
-rw-r--r--addon-sdk/source/lib/sdk/uri/resource.js37
-rw-r--r--addon-sdk/source/lib/sdk/url.js349
-rw-r--r--addon-sdk/source/lib/sdk/url/utils.js29
-rw-r--r--addon-sdk/source/lib/sdk/util/array.js123
-rw-r--r--addon-sdk/source/lib/sdk/util/collection.js115
-rw-r--r--addon-sdk/source/lib/sdk/util/contract.js55
-rw-r--r--addon-sdk/source/lib/sdk/util/deprecate.js40
-rw-r--r--addon-sdk/source/lib/sdk/util/dispatcher.js54
-rw-r--r--addon-sdk/source/lib/sdk/util/list.js90
-rw-r--r--addon-sdk/source/lib/sdk/util/match-pattern.js113
-rw-r--r--addon-sdk/source/lib/sdk/util/object.js104
-rw-r--r--addon-sdk/source/lib/sdk/util/rules.js53
-rw-r--r--addon-sdk/source/lib/sdk/util/sequence.js593
-rw-r--r--addon-sdk/source/lib/sdk/util/uuid.js19
-rw-r--r--addon-sdk/source/lib/sdk/view/core.js26
-rw-r--r--addon-sdk/source/lib/sdk/webextension.js43
-rw-r--r--addon-sdk/source/lib/sdk/window/browser.js54
-rw-r--r--addon-sdk/source/lib/sdk/window/events.js68
-rw-r--r--addon-sdk/source/lib/sdk/window/helpers.js81
-rw-r--r--addon-sdk/source/lib/sdk/window/namespace.js6
-rw-r--r--addon-sdk/source/lib/sdk/window/utils.js460
-rw-r--r--addon-sdk/source/lib/sdk/windows.js32
-rw-r--r--addon-sdk/source/lib/sdk/windows/fennec.js83
-rw-r--r--addon-sdk/source/lib/sdk/windows/firefox.js224
-rw-r--r--addon-sdk/source/lib/sdk/windows/observer.js53
-rw-r--r--addon-sdk/source/lib/sdk/windows/tabs-fennec.js172
-rw-r--r--addon-sdk/source/lib/sdk/worker/utils.js19
-rw-r--r--addon-sdk/source/lib/sdk/zip/utils.js16
216 files changed, 0 insertions, 30621 deletions
diff --git a/addon-sdk/source/lib/sdk/addon/bootstrap.js b/addon-sdk/source/lib/sdk/addon/bootstrap.js
deleted file mode 100644
index 0397d91e5..000000000
--- a/addon-sdk/source/lib/sdk/addon/bootstrap.js
+++ /dev/null
@@ -1,182 +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 { Cu } = require("chrome");
-const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
-const { Task: { spawn } } = require("resource://gre/modules/Task.jsm");
-const { readURI } = require("sdk/net/url");
-const { mount, unmount } = require("sdk/uri/resource");
-const { setTimeout } = require("sdk/timers");
-const { Loader, Require, Module, main, unload } = require("toolkit/loader");
-const prefs = require("sdk/preferences/service");
-
-// load below now, so that it can be used by sdk/addon/runner
-// see bug https://bugzilla.mozilla.org/show_bug.cgi?id=1042239
-const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {});
-
-const REASON = [ "unknown", "startup", "shutdown", "enable", "disable",
- "install", "uninstall", "upgrade", "downgrade" ];
-
-const UUID_PATTERN = /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/;
-// Takes add-on ID and normalizes it to a domain name so that add-on
-// can be mapped to resource://domain/
-const readDomain = id =>
- // If only `@` character is the first one, than just substract it,
- // otherwise fallback to legacy normalization code path. Note: `.`
- // is valid character for resource substitutaiton & we intend to
- // make add-on URIs intuitive, so it's best to just stick to an
- // add-on author typed input.
- id.lastIndexOf("@") === 0 ? id.substr(1).toLowerCase() :
- id.toLowerCase().
- replace(/@/g, "-at-").
- replace(/\./g, "-dot-").
- replace(UUID_PATTERN, "$1");
-
-const readPaths = id => {
- const base = `extensions.modules.${id}.path.`;
- const domain = readDomain(id);
- return prefs.keys(base).reduce((paths, key) => {
- const value = prefs.get(key);
- const name = key.replace(base, "");
- const path = name.split(".").join("/");
- const prefix = path.length ? `${path}/` : path;
- const uri = value.endsWith("/") ? value : `${value}/`;
- const root = `extensions.modules.${domain}.commonjs.path.${name}`;
-
- mount(root, uri);
-
- paths[prefix] = `resource://${root}/`;
- return paths;
- }, {});
-};
-
-const Bootstrap = function(mountURI) {
- this.mountURI = mountURI;
- this.install = this.install.bind(this);
- this.uninstall = this.uninstall.bind(this);
- this.startup = this.startup.bind(this);
- this.shutdown = this.shutdown.bind(this);
-};
-Bootstrap.prototype = {
- constructor: Bootstrap,
- mount(domain, rootURI) {
- mount(domain, rootURI);
- this.domain = domain;
- },
- unmount() {
- if (this.domain) {
- unmount(this.domain);
- this.domain = null;
- }
- },
- install(addon, reason) {
- return new Promise(resolve => resolve());
- },
- uninstall(addon, reason) {
- return new Promise(resolve => {
- const {id} = addon;
-
- prefs.reset(`extensions.${id}.sdk.domain`);
- prefs.reset(`extensions.${id}.sdk.version`);
- prefs.reset(`extensions.${id}.sdk.rootURI`);
- prefs.reset(`extensions.${id}.sdk.baseURI`);
- prefs.reset(`extensions.${id}.sdk.load.reason`);
-
- resolve();
- });
- },
- startup(addon, reasonCode) {
- const { id, version, resourceURI: { spec: addonURI } } = addon;
- const rootURI = this.mountURI || addonURI;
- const reason = REASON[reasonCode];
- const self = this;
-
- return spawn(function*() {
- const metadata = JSON.parse(yield readURI(`${rootURI}package.json`));
- const domain = readDomain(id);
- const baseURI = `resource://${domain}/`;
-
- this.mount(domain, rootURI);
-
- prefs.set(`extensions.${id}.sdk.domain`, domain);
- prefs.set(`extensions.${id}.sdk.version`, version);
- prefs.set(`extensions.${id}.sdk.rootURI`, rootURI);
- prefs.set(`extensions.${id}.sdk.baseURI`, baseURI);
- prefs.set(`extensions.${id}.sdk.load.reason`, reason);
-
- const command = prefs.get(`extensions.${id}.sdk.load.command`);
-
- const loader = Loader({
- id,
- isNative: true,
- checkCompatibility: true,
- prefixURI: baseURI,
- rootURI: baseURI,
- name: metadata.name,
- paths: Object.assign({
- "": "resource://gre/modules/commonjs/",
- "devtools/": "resource://devtools/",
- "./": baseURI
- }, readPaths(id)),
- manifest: metadata,
- metadata: metadata,
- modules: {
- "@test/options": {},
- },
- noQuit: prefs.get(`extensions.${id}.sdk.test.no-quit`, false)
- });
- self.loader = loader;
-
- const module = Module("package.json", `${baseURI}package.json`);
- const require = Require(loader, module);
- const main = command === "test" ? "sdk/test/runner" : null;
- const prefsURI = `${baseURI}defaults/preferences/prefs.js`;
-
- // Init the 'sdk/webextension' module from the bootstrap addon parameter.
- require("sdk/webextension").initFromBootstrapAddonParam(addon);
-
- const { startup } = require("sdk/addon/runner");
- startup(reason, {loader, main, prefsURI});
- }.bind(this)).catch(error => {
- console.error(`Failed to start ${id} addon`, error);
- throw error;
- });
- },
- shutdown(addon, code) {
- this.unmount();
- return this.unload(REASON[code]);
- },
- unload(reason) {
- return new Promise(resolve => {
- const { loader } = this;
- if (loader) {
- this.loader = null;
- unload(loader, reason);
-
- setTimeout(() => {
- for (let uri of Object.keys(loader.sandboxes)) {
- let sandbox = loader.sandboxes[uri];
- if (Cu.getClassName(sandbox, true) == "Sandbox")
- Cu.nukeSandbox(sandbox);
- delete loader.sandboxes[uri];
- delete loader.modules[uri];
- }
-
- try {
- Cu.nukeSandbox(loader.sharedGlobalSandbox);
- } catch (e) {
- Cu.reportError(e);
- }
-
- resolve();
- }, 1000);
- }
- else {
- resolve();
- }
- });
- }
-};
-exports.Bootstrap = Bootstrap;
diff --git a/addon-sdk/source/lib/sdk/addon/events.js b/addon-sdk/source/lib/sdk/addon/events.js
deleted file mode 100644
index 45bada6e1..000000000
--- a/addon-sdk/source/lib/sdk/addon/events.js
+++ /dev/null
@@ -1,56 +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'
-};
-
-var { request: hostReq, response: hostRes } = require('./host');
-var { defer: async } = require('../lang/functional');
-var { defer } = require('../core/promise');
-var { emit: emitSync, on, off } = require('../event/core');
-var { uuid } = require('../util/uuid');
-var emit = async(emitSync);
-
-// Map of IDs to deferreds
-var requests = new Map();
-
-// May not be necessary to wrap this in `async`
-// once promises are async via bug 881047
-var receive = async(function ({data, id, error}) {
- let request = requests.get(id);
- if (request) {
- if (error) request.reject(error);
- else request.resolve(clone(data));
- requests.delete(id);
- }
-});
-on(hostRes, 'data', receive);
-
-/*
- * Send is a helper to be used in client APIs to send
- * a request to host
- */
-function send (eventName, data) {
- let id = uuid();
- let deferred = defer();
- requests.set(id, deferred);
- emit(hostReq, 'data', {
- id: id,
- data: clone(data),
- event: eventName
- });
- return deferred.promise;
-}
-exports.send = send;
-
-/*
- * Implement internal structured cloning algorithm in the future?
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#internal-structured-cloning-algorithm
- */
-function clone (obj) {
- return JSON.parse(JSON.stringify(obj || {}));
-}
diff --git a/addon-sdk/source/lib/sdk/addon/host.js b/addon-sdk/source/lib/sdk/addon/host.js
deleted file mode 100644
index 91aa0e869..000000000
--- a/addon-sdk/source/lib/sdk/addon/host.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"
-};
-
-exports.request = {};
-exports.response = {};
diff --git a/addon-sdk/source/lib/sdk/addon/installer.js b/addon-sdk/source/lib/sdk/addon/installer.js
deleted file mode 100644
index bb8cf8d16..000000000
--- a/addon-sdk/source/lib/sdk/addon/installer.js
+++ /dev/null
@@ -1,121 +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/. */
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const { Cc, Ci, Cu } = require("chrome");
-const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
-const { defer } = require("../core/promise");
-const { setTimeout } = require("../timers");
-
-/**
- * `install` method error codes:
- *
- * https://developer.mozilla.org/en/Addons/Add-on_Manager/AddonManager#AddonInstall_errors
- */
-exports.ERROR_NETWORK_FAILURE = AddonManager.ERROR_NETWORK_FAILURE;
-exports.ERROR_INCORRECT_HASH = AddonManager.ERROR_INCORRECT_HASH;
-exports.ERROR_CORRUPT_FILE = AddonManager.ERROR_CORRUPT_FILE;
-exports.ERROR_FILE_ACCESS = AddonManager.ERROR_FILE_ACCESS;
-
-/**
- * Immediatly install an addon.
- *
- * @param {String} xpiPath
- * file path to an xpi file to install
- * @return {Promise}
- * A promise resolved when the addon is finally installed.
- * Resolved with addon id as value or rejected with an error code.
- */
-exports.install = function install(xpiPath) {
- let { promise, resolve, reject } = defer();
-
- // Create nsIFile for the xpi file
- let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
- try {
- file.initWithPath(xpiPath);
- }
- catch(e) {
- reject(exports.ERROR_FILE_ACCESS);
- return promise;
- }
-
- // Listen for installation end
- let listener = {
- onInstallEnded: function(aInstall, aAddon) {
- aInstall.removeListener(listener);
- // Bug 749745: on FF14+, onInstallEnded is called just before `startup()`
- // is called, but we expect to resolve the promise only after it.
- // As startup is called synchronously just after onInstallEnded,
- // a simple setTimeout(0) is enough
- setTimeout(resolve, 0, aAddon.id);
- },
- onInstallFailed: function (aInstall) {
- aInstall.removeListener(listener);
- reject(aInstall.error);
- },
- onDownloadFailed: function(aInstall) {
- this.onInstallFailed(aInstall);
- }
- };
-
- // Order AddonManager to install the addon
- AddonManager.getInstallForFile(file, function(install) {
- if (install.error == 0) {
- install.addListener(listener);
- install.install();
- } else {
- reject(install.error);
- }
- });
-
- return promise;
-};
-
-exports.uninstall = function uninstall(addonId) {
- let { promise, resolve, reject } = defer();
-
- // Listen for uninstallation end
- let listener = {
- onUninstalled: function onUninstalled(aAddon) {
- if (aAddon.id != addonId)
- return;
- AddonManager.removeAddonListener(listener);
- resolve();
- }
- };
- AddonManager.addAddonListener(listener);
-
- // Order Addonmanager to uninstall the addon
- getAddon(addonId).then(addon => addon.uninstall(), reject);
-
- return promise;
-};
-
-exports.disable = function disable(addonId) {
- return getAddon(addonId).then(addon => {
- addon.userDisabled = true;
- return addonId;
- });
-};
-
-exports.enable = function enabled(addonId) {
- return getAddon(addonId).then(addon => {
- addon.userDisabled = false;
- return addonId;
- });
-};
-
-exports.isActive = function isActive(addonId) {
- return getAddon(addonId).then(addon => addon.isActive && !addon.appDisabled);
-};
-
-const getAddon = function getAddon (id) {
- let { promise, resolve, reject } = defer();
- AddonManager.getAddonByID(id, addon => addon ? resolve(addon) : reject());
- return promise;
-}
-exports.getAddon = getAddon;
diff --git a/addon-sdk/source/lib/sdk/addon/manager.js b/addon-sdk/source/lib/sdk/addon/manager.js
deleted file mode 100644
index 7ac0a7d6e..000000000
--- a/addon-sdk/source/lib/sdk/addon/manager.js
+++ /dev/null
@@ -1,18 +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 { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
-const { defer } = require("../core/promise");
-
-function getAddonByID(id) {
- let { promise, resolve } = defer();
- AddonManager.getAddonByID(id, resolve);
- return promise;
-}
-exports.getAddonByID = getAddonByID;
diff --git a/addon-sdk/source/lib/sdk/addon/runner.js b/addon-sdk/source/lib/sdk/addon/runner.js
deleted file mode 100644
index 3977a04e4..000000000
--- a/addon-sdk/source/lib/sdk/addon/runner.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/. */
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const { Cc, Ci, Cu } = require('chrome');
-const { rootURI, metadata, isNative } = require('@loader/options');
-const { id, loadReason } = require('../self');
-const { descriptor, Sandbox, evaluate, main, resolveURI } = require('toolkit/loader');
-const { once } = require('../system/events');
-const { exit, env, staticArgs } = require('../system');
-const { when: unload } = require('../system/unload');
-const globals = require('../system/globals');
-const xulApp = require('../system/xul-app');
-const { get } = require('../preferences/service');
-const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
- getService(Ci.nsIAppShellService);
-const { preferences } = metadata;
-
-const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () {
- return Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {}).
- BrowserToolboxProcess;
-});
-
-// Initializes default preferences
-function setDefaultPrefs(prefsURI) {
- const prefs = Cc['@mozilla.org/preferences-service;1'].
- getService(Ci.nsIPrefService).
- QueryInterface(Ci.nsIPrefBranch2);
- const branch = prefs.getDefaultBranch('');
- const sandbox = Sandbox({
- name: prefsURI,
- prototype: {
- pref: function(key, val) {
- switch (typeof val) {
- case 'boolean':
- branch.setBoolPref(key, val);
- break;
- case 'number':
- if (val % 1 == 0) // number must be a integer, otherwise ignore it
- branch.setIntPref(key, val);
- break;
- case 'string':
- branch.setCharPref(key, val);
- break;
- }
- }
- }
- });
- // load preferences.
- evaluate(sandbox, prefsURI);
-}
-
-function definePseudo(loader, id, exports) {
- let uri = resolveURI(id, loader.mapping);
- loader.modules[uri] = { exports: exports };
-}
-
-function startup(reason, options) {
- return Startup.onceInitialized.then(() => {
- // Inject globals ASAP in order to have console API working ASAP
- Object.defineProperties(options.loader.globals, descriptor(globals));
-
- // NOTE: Module is intentionally required only now because it relies
- // on existence of hidden window, which does not exists until startup.
- let { ready } = require('../addon/window');
- // Load localization manifest and .properties files.
- // Run the addon even in case of error (best effort approach)
- require('../l10n/loader').
- load(rootURI).
- then(null, function failure(error) {
- if (!isNative)
- console.info("Error while loading localization: " + error.message);
- }).
- then(function onLocalizationReady(data) {
- // Exports data to a pseudo module so that api-utils/l10n/core
- // can get access to it
- definePseudo(options.loader, '@l10n/data', data ? data : null);
- return ready;
- }).then(function() {
- run(options);
- }).then(null, console.exception);
- return void 0; // otherwise we raise a warning, see bug 910304
- });
-}
-
-function run(options) {
- try {
- // Try initializing HTML localization before running main module. Just print
- // an exception in case of error, instead of preventing addon to be run.
- try {
- // Do not enable HTML localization while running test as it is hard to
- // disable. Because unit tests are evaluated in a another Loader who
- // doesn't have access to this current loader.
- if (options.main !== 'sdk/test/runner') {
- require('../l10n/html').enable();
- }
- }
- catch(error) {
- console.exception(error);
- }
-
- // native-options does stuff directly with preferences key from package.json
- if (preferences && preferences.length > 0) {
- try {
- require('../preferences/native-options').
- enable({ preferences: preferences, id: id }).
- catch(console.exception);
- }
- catch (error) {
- console.exception(error);
- }
- }
- else {
- // keeping support for addons packaged with older SDK versions,
- // when cfx didn't include the 'preferences' key in @loader/options
-
- // Initialize inline options localization, without preventing addon to be
- // run in case of error
- try {
- require('../l10n/prefs').enable();
- }
- catch(error) {
- console.exception(error);
- }
-
- // TODO: When bug 564675 is implemented this will no longer be needed
- // Always set the default prefs, because they disappear on restart
- if (options.prefsURI) {
- // Only set if `prefsURI` specified
- try {
- setDefaultPrefs(options.prefsURI);
- }
- catch (err) {
- // cfx bootstrap always passes prefsURI, even in addons without prefs
- }
- }
- }
-
- // this is where the addon's main.js finally run.
- let program = main(options.loader, options.main);
-
- if (typeof(program.onUnload) === 'function')
- unload(program.onUnload);
-
- if (typeof(program.main) === 'function') {
- program.main({
- loadReason: loadReason,
- staticArgs: staticArgs
- }, {
- print: function print(_) { dump(_ + '\n') },
- quit: exit
- });
- }
-
- if (get("extensions." + id + ".sdk.debug.show", false)) {
- BrowserToolboxProcess.init({ addonID: id });
- }
- } catch (error) {
- console.exception(error);
- throw error;
- }
-}
-exports.startup = startup;
-
-// If add-on is lunched via `cfx run` we need to use `system.exit` to let
-// cfx know we're done (`cfx test` will take care of exit so we don't do
-// anything here).
-if (env.CFX_COMMAND === 'run') {
- unload(function(reason) {
- if (reason === 'shutdown')
- exit(0);
- });
-}
diff --git a/addon-sdk/source/lib/sdk/addon/window.js b/addon-sdk/source/lib/sdk/addon/window.js
deleted file mode 100644
index 93ed1d8dc..000000000
--- a/addon-sdk/source/lib/sdk/addon/window.js
+++ /dev/null
@@ -1,66 +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 { Ci, Cc } = require("chrome");
-const { make: makeWindow, getHiddenWindow } = require("../window/utils");
-const { create: makeFrame, getDocShell } = require("../frame/utils");
-const { defer } = require("../core/promise");
-const { when: unload } = require("../system/unload");
-const cfxArgs = require("../test/options");
-
-var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"].
- createInstance(Ci.nsIPrincipal);
-
-var hiddenWindow = getHiddenWindow();
-
-if (cfxArgs.parseable) {
- console.info("hiddenWindow document.documentURI:" +
- hiddenWindow.document.documentURI);
- console.info("hiddenWindow document.readyState:" +
- hiddenWindow.document.readyState);
-}
-
-// Once Bug 565388 is fixed and shipped we'll be able to make invisible,
-// permanent docShells. Meanwhile we create hidden top level window and
-// use it's docShell.
-var frame = makeFrame(hiddenWindow.document, {
- nodeName: "iframe",
- namespaceURI: "http://www.w3.org/1999/xhtml",
- allowJavascript: true,
- allowPlugins: true
-})
-var docShell = getDocShell(frame);
-var eventTarget = docShell.chromeEventHandler;
-
-// We need to grant docShell system principals in order to load XUL document
-// from data URI into it.
-docShell.createAboutBlankContentViewer(addonPrincipal);
-
-// Get a reference to the DOM window of the given docShell and load
-// such document into that would allow us to create XUL iframes, that
-// are necessary for hidden frames etc..
-var window = docShell.contentViewer.DOMDocument.defaultView;
-window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>";
-
-// Create a promise that is delivered once add-on window is interactive,
-// used by add-on runner to defer add-on loading until window is ready.
-var { promise, resolve } = defer();
-eventTarget.addEventListener("DOMContentLoaded", function handler(event) {
- eventTarget.removeEventListener("DOMContentLoaded", handler, false);
- resolve();
-}, false);
-
-exports.ready = promise;
-exports.window = window;
-
-// Still close window on unload to claim memory back early.
-unload(function() {
- window.close()
- frame.parentNode.removeChild(frame);
-});
diff --git a/addon-sdk/source/lib/sdk/base64.js b/addon-sdk/source/lib/sdk/base64.js
deleted file mode 100644
index a07b302e0..000000000
--- a/addon-sdk/source/lib/sdk/base64.js
+++ /dev/null
@@ -1,47 +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 { Cu } = require("chrome");
-
-// Passing an empty object as second argument to avoid scope's pollution
-// (devtools loader injects these symbols as global and prevent using
-// const here)
-var { atob, btoa } = Cu.import("resource://gre/modules/Services.jsm", {});
-
-function isUTF8(charset) {
- let type = typeof charset;
-
- if (type === "undefined")
- return false;
-
- if (type === "string" && charset.toLowerCase() === "utf-8")
- return true;
-
- throw new Error("The charset argument can be only 'utf-8'");
-}
-
-function toOctetChar(c) {
- return String.fromCharCode(c.charCodeAt(0) & 0xFF);
-}
-
-exports.decode = function (data, charset) {
- if (isUTF8(charset))
- return decodeURIComponent(escape(atob(data)))
-
- return atob(data);
-}
-
-exports.encode = function (data, charset) {
- if (isUTF8(charset))
- return btoa(unescape(encodeURIComponent(data)))
-
- data = data.replace(/[^\x00-\xFF]/g, toOctetChar);
- return btoa(data);
-}
diff --git a/addon-sdk/source/lib/sdk/browser/events.js b/addon-sdk/source/lib/sdk/browser/events.js
deleted file mode 100644
index f91119031..000000000
--- a/addon-sdk/source/lib/sdk/browser/events.js
+++ /dev/null
@@ -1,20 +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 { events } = require("../window/events");
-const { filter } = require("../event/utils");
-const { isBrowser } = require("../window/utils");
-
-// TODO: `isBrowser` detects weather window is a browser by checking
-// `windowtype` attribute, which means that all 'open' events will be
-// filtered out since document is not loaded yet. Maybe we can find a better
-// implementation for `isBrowser`. Either way it's not really needed yet
-// neither window tracker provides this event.
-
-exports.events = filter(events, ({target}) => isBrowser(target));
diff --git a/addon-sdk/source/lib/sdk/clipboard.js b/addon-sdk/source/lib/sdk/clipboard.js
deleted file mode 100644
index 048d5f2f1..000000000
--- a/addon-sdk/source/lib/sdk/clipboard.js
+++ /dev/null
@@ -1,337 +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": {
- // TODO Fennec Support 789757
- "Firefox": "*",
- "SeaMonkey": "*",
- "Thunderbird": "*"
- }
-};
-
-const { Cc, Ci } = require("chrome");
-const { DataURL } = require("./url");
-const apiUtils = require("./deprecated/api-utils");
-/*
-While these data flavors resemble Internet media types, they do
-no directly map to them.
-*/
-const kAllowableFlavors = [
- "text/unicode",
- "text/html",
- "image/png"
- /* CURRENTLY UNSUPPORTED FLAVORS
- "text/plain",
- "image/jpg",
- "image/jpeg",
- "image/gif",
- "text/x-moz-text-internal",
- "AOLMAIL",
- "application/x-moz-file",
- "text/x-moz-url",
- "text/x-moz-url-data",
- "text/x-moz-url-desc",
- "text/x-moz-url-priv",
- "application/x-moz-nativeimage",
- "application/x-moz-nativehtml",
- "application/x-moz-file-promise-url",
- "application/x-moz-file-promise-dest-filename",
- "application/x-moz-file-promise",
- "application/x-moz-file-promise-dir"
- */
-];
-
-/*
-Aliases for common flavors. Not all flavors will
-get an alias. New aliases must be approved by a
-Jetpack API druid.
-*/
-const kFlavorMap = [
- { short: "text", long: "text/unicode" },
- { short: "html", long: "text/html" },
- { short: "image", long: "image/png" }
-];
-
-var clipboardService = Cc["@mozilla.org/widget/clipboard;1"].
- getService(Ci.nsIClipboard);
-
-var clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].
- getService(Ci.nsIClipboardHelper);
-
-var imageTools = Cc["@mozilla.org/image/tools;1"].
- getService(Ci.imgITools);
-
-exports.set = function(aData, aDataType) {
-
- let options = {
- data: aData,
- datatype: aDataType || "text"
- };
-
- // If `aDataType` is not given or if it's "image", the data is parsed as
- // data URL to detect a better datatype
- if (aData && (!aDataType || aDataType === "image")) {
- try {
- let dataURL = new DataURL(aData);
-
- options.datatype = dataURL.mimeType;
- options.data = dataURL.data;
- }
- catch (e) {
- // Ignore invalid URIs
- if (e.name !== "URIError") {
- throw e;
- }
- }
- }
-
- options = apiUtils.validateOptions(options, {
- data: {
- is: ["string"]
- },
- datatype: {
- is: ["string"]
- }
- });
-
- let flavor = fromJetpackFlavor(options.datatype);
-
- if (!flavor)
- throw new Error("Invalid flavor for " + options.datatype);
-
- // Additional checks for using the simple case
- if (flavor == "text/unicode") {
- clipboardHelper.copyString(options.data);
- return true;
- }
-
- // Below are the more complex cases where we actually have to work with a
- // nsITransferable object
- var xferable = Cc["@mozilla.org/widget/transferable;1"].
- createInstance(Ci.nsITransferable);
- if (!xferable)
- throw new Error("Couldn't set the clipboard due to an internal error " +
- "(couldn't create a Transferable object).");
- // Bug 769440: Starting with FF16, transferable have to be inited
- if ("init" in xferable)
- xferable.init(null);
-
- switch (flavor) {
- case "text/html":
- // add text/html flavor
- let str = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
-
- str.data = options.data;
- xferable.addDataFlavor(flavor);
- xferable.setTransferData(flavor, str, str.data.length * 2);
-
- // add a text/unicode flavor (html converted to plain text)
- str = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- let converter = Cc["@mozilla.org/feed-textconstruct;1"].
- createInstance(Ci.nsIFeedTextConstruct);
-
- converter.type = "html";
- converter.text = options.data;
- str.data = converter.plainText();
- xferable.addDataFlavor("text/unicode");
- xferable.setTransferData("text/unicode", str, str.data.length * 2);
- break;
-
- // Set images to the clipboard is not straightforward, to have an idea how
- // it works on platform side, see:
- // http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsCopySupport.cpp?rev=7857c5bff017#530
- case "image/png":
- let image = options.data;
-
- let container = {};
-
- try {
- let input = Cc["@mozilla.org/io/string-input-stream;1"].
- createInstance(Ci.nsIStringInputStream);
-
- input.setData(image, image.length);
-
- imageTools.decodeImageData(input, flavor, container);
- }
- catch (e) {
- throw new Error("Unable to decode data given in a valid image.");
- }
-
- // Store directly the input stream makes the cliboard's data available
- // for Firefox but not to the others application or to the OS. Therefore,
- // a `nsISupportsInterfacePointer` object that reference an `imgIContainer`
- // with the image is needed.
- var imgPtr = Cc["@mozilla.org/supports-interface-pointer;1"].
- createInstance(Ci.nsISupportsInterfacePointer);
-
- imgPtr.data = container.value;
-
- xferable.addDataFlavor(flavor);
- xferable.setTransferData(flavor, imgPtr, -1);
-
- break;
- default:
- throw new Error("Unable to handle the flavor " + flavor + ".");
- }
-
- // TODO: Not sure if this will ever actually throw. -zpao
- try {
- clipboardService.setData(
- xferable,
- null,
- clipboardService.kGlobalClipboard
- );
- } catch (e) {
- throw new Error("Couldn't set clipboard data due to an internal error: " + e);
- }
- return true;
-};
-
-
-exports.get = function(aDataType) {
- let options = {
- datatype: aDataType
- };
-
- // Figure out the best data type for the clipboard's data, if omitted
- if (!aDataType) {
- if (~currentFlavors().indexOf("image"))
- options.datatype = "image";
- else
- options.datatype = "text";
- }
-
- options = apiUtils.validateOptions(options, {
- datatype: {
- is: ["string"]
- }
- });
-
- var xferable = Cc["@mozilla.org/widget/transferable;1"].
- createInstance(Ci.nsITransferable);
- if (!xferable)
- throw new Error("Couldn't set the clipboard due to an internal error " +
- "(couldn't create a Transferable object).");
- // Bug 769440: Starting with FF16, transferable have to be inited
- if ("init" in xferable)
- xferable.init(null);
-
- var flavor = fromJetpackFlavor(options.datatype);
-
- // Ensure that the user hasn't requested a flavor that we don't support.
- if (!flavor)
- throw new Error("Getting the clipboard with the flavor '" + flavor +
- "' is not supported.");
-
- // TODO: Check for matching flavor first? Probably not worth it.
-
- xferable.addDataFlavor(flavor);
- // Get the data into our transferable.
- clipboardService.getData(
- xferable,
- clipboardService.kGlobalClipboard
- );
-
- var data = {};
- var dataLen = {};
- try {
- xferable.getTransferData(flavor, data, dataLen);
- } catch (e) {
- // Clipboard doesn't contain data in flavor, return null.
- return null;
- }
-
- // There's no data available, return.
- if (data.value === null)
- return null;
-
- // TODO: Add flavors here as we support more in kAllowableFlavors.
- switch (flavor) {
- case "text/unicode":
- case "text/html":
- data = data.value.QueryInterface(Ci.nsISupportsString).data;
- break;
- case "image/png":
- let dataURL = new DataURL();
-
- dataURL.mimeType = flavor;
- dataURL.base64 = true;
-
- let image = data.value;
-
- // Due to the differences in how images could be stored in the clipboard
- // the checks below are needed. The clipboard could already provide the
- // image as byte streams, but also as pointer, or as image container.
- // If it's not possible obtain a byte stream, the function returns `null`.
- if (image instanceof Ci.nsISupportsInterfacePointer)
- image = image.data;
-
- if (image instanceof Ci.imgIContainer)
- image = imageTools.encodeImage(image, flavor);
-
- if (image instanceof Ci.nsIInputStream) {
- let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
- createInstance(Ci.nsIBinaryInputStream);
-
- binaryStream.setInputStream(image);
-
- dataURL.data = binaryStream.readBytes(binaryStream.available());
-
- data = dataURL.toString();
- }
- else
- data = null;
-
- break;
- default:
- data = null;
- }
-
- return data;
-};
-
-function currentFlavors() {
- // Loop over kAllowableFlavors, calling hasDataMatchingFlavors for each.
- // This doesn't seem like the most efficient way, but we can't get
- // confirmation for specific flavors any other way. This is supposed to be
- // an inexpensive call, so performance shouldn't be impacted (much).
- var currentFlavors = [];
- for (var flavor of kAllowableFlavors) {
- var matches = clipboardService.hasDataMatchingFlavors(
- [flavor],
- 1,
- clipboardService.kGlobalClipboard
- );
- if (matches)
- currentFlavors.push(toJetpackFlavor(flavor));
- }
- return currentFlavors;
-};
-
-Object.defineProperty(exports, "currentFlavors", { get : currentFlavors });
-
-// SUPPORT FUNCTIONS ////////////////////////////////////////////////////////
-
-function toJetpackFlavor(aFlavor) {
- for (let flavorMap of kFlavorMap)
- if (flavorMap.long == aFlavor)
- return flavorMap.short;
- // Return null in the case where we don't match
- return null;
-}
-
-function fromJetpackFlavor(aJetpackFlavor) {
- // TODO: Handle proper flavors better
- for (let flavorMap of kFlavorMap)
- if (flavorMap.short == aJetpackFlavor || flavorMap.long == aJetpackFlavor)
- return flavorMap.long;
- // Return null in the case where we don't match.
- return null;
-}
diff --git a/addon-sdk/source/lib/sdk/console/plain-text.js b/addon-sdk/source/lib/sdk/console/plain-text.js
deleted file mode 100644
index 0e44cf106..000000000
--- a/addon-sdk/source/lib/sdk/console/plain-text.js
+++ /dev/null
@@ -1,78 +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 { Cc, Ci, Cu, Cr } = require("chrome");
-const self = require("../self");
-const prefs = require("../preferences/service");
-const { merge } = require("../util/object");
-const { ConsoleAPI } = Cu.import("resource://gre/modules/Console.jsm", {});
-
-const DEFAULT_LOG_LEVEL = "error";
-const ADDON_LOG_LEVEL_PREF = "extensions." + self.id + ".sdk.console.logLevel";
-const SDK_LOG_LEVEL_PREF = "extensions.sdk.console.logLevel";
-
-var logLevel = DEFAULT_LOG_LEVEL;
-function setLogLevel() {
- logLevel = prefs.get(ADDON_LOG_LEVEL_PREF,
- prefs.get(SDK_LOG_LEVEL_PREF,
- DEFAULT_LOG_LEVEL));
-}
-setLogLevel();
-
-var logLevelObserver = {
- QueryInterface: function(iid) {
- if (!iid.equals(Ci.nsIObserver) &&
- !iid.equals(Ci.nsISupportsWeakReference) &&
- !iid.equals(Ci.nsISupports))
- throw Cr.NS_ERROR_NO_INTERFACE;
- return this;
- },
- observe: function(subject, topic, data) {
- setLogLevel();
- }
-};
-var branch = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefService).
- getBranch(null);
-branch.addObserver(ADDON_LOG_LEVEL_PREF, logLevelObserver, true);
-branch.addObserver(SDK_LOG_LEVEL_PREF, logLevelObserver, true);
-
-function PlainTextConsole(print, innerID) {
-
- let consoleOptions = {
- prefix: self.name,
- maxLogLevel: logLevel,
- dump: print,
- innerID: innerID,
- consoleID: "addon/" + self.id
- };
- let console = new ConsoleAPI(consoleOptions);
-
- // As we freeze the console object, we can't modify this property afterward
- Object.defineProperty(console, "maxLogLevel", {
- get: function() {
- return logLevel;
- }
- });
-
- // We defined the `__exposedProps__` in our console chrome object.
- //
- // Meanwhile we're investigating with the platform team if `__exposedProps__`
- // are needed, or are just a left-over.
-
- console.__exposedProps__ = Object.keys(ConsoleAPI.prototype).reduce(function(exposed, prop) {
- exposed[prop] = "r";
- return exposed;
- }, {});
-
- Object.freeze(console);
- return console;
-};
-exports.PlainTextConsole = PlainTextConsole;
diff --git a/addon-sdk/source/lib/sdk/console/traceback.js b/addon-sdk/source/lib/sdk/console/traceback.js
deleted file mode 100644
index be0fb7b94..000000000
--- a/addon-sdk/source/lib/sdk/console/traceback.js
+++ /dev/null
@@ -1,86 +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 { Ci, components } = require("chrome");
-const { parseStack, sourceURI } = require("toolkit/loader");
-const { readURISync } = require("../net/url");
-
-function safeGetFileLine(path, line) {
- try {
- var scheme = require("../url").URL(path).scheme;
- // TODO: There should be an easier, more accurate way to figure out
- // what's the case here.
- if (!(scheme == "http" || scheme == "https"))
- return readURISync(path).split("\n")[line - 1];
- } catch (e) {}
- return null;
-}
-
-function nsIStackFramesToJSON(frame) {
- var stack = [];
-
- while (frame) {
- if (frame.filename) {
- stack.unshift({
- fileName: sourceURI(frame.filename),
- lineNumber: frame.lineNumber,
- name: frame.name
- });
- }
- frame = frame.caller;
- }
-
- return stack;
-};
-
-var fromException = exports.fromException = function fromException(e) {
- if (e instanceof Ci.nsIException)
- return nsIStackFramesToJSON(e.location);
- if (e.stack && e.stack.length)
- return parseStack(e.stack);
- if (e.fileName && typeof(e.lineNumber == "number"))
- return [{fileName: sourceURI(e.fileName),
- lineNumber: e.lineNumber,
- name: null}];
- return [];
-};
-
-var get = exports.get = function get() {
- return nsIStackFramesToJSON(components.stack.caller);
-};
-
-var format = exports.format = function format(tbOrException) {
- if (tbOrException === undefined) {
- tbOrException = get();
- tbOrException.pop();
- }
-
- var tb;
- if (typeof(tbOrException) == "object" &&
- tbOrException.constructor.name == "Array")
- tb = tbOrException;
- else
- tb = fromException(tbOrException);
-
- var lines = ["Traceback (most recent call last):"];
-
- tb.forEach(
- function(frame) {
- if (!(frame.fileName || frame.lineNumber || frame.name))
- return;
-
- lines.push(' File "' + frame.fileName + '", line ' +
- frame.lineNumber + ', in ' + frame.name);
- var sourceLine = safeGetFileLine(frame.fileName, frame.lineNumber);
- if (sourceLine)
- lines.push(' ' + sourceLine.trim());
- });
-
- return lines.join("\n");
-};
diff --git a/addon-sdk/source/lib/sdk/content/content-worker.js b/addon-sdk/source/lib/sdk/content/content-worker.js
deleted file mode 100644
index 0a8225733..000000000
--- 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;
- }
-});
diff --git a/addon-sdk/source/lib/sdk/content/content.js b/addon-sdk/source/lib/sdk/content/content.js
deleted file mode 100644
index 9655223a3..000000000
--- 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;
- }
-});
diff --git a/addon-sdk/source/lib/sdk/content/context-menu.js b/addon-sdk/source/lib/sdk/content/context-menu.js
deleted file mode 100644
index 2955e2f09..000000000
--- a/addon-sdk/source/lib/sdk/content/context-menu.js
+++ /dev/null
@@ -1,408 +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 self = require("../self");
-const { WorkerChild } = require("./worker-child");
-const { getInnerId } = require("../window/utils");
-const { Ci } = require("chrome");
-const { Services } = require("resource://gre/modules/Services.jsm");
-const system = require('../system/events');
-const { process } = require('../remote/child');
-
-// These functions are roughly copied from sdk/selection which doesn't work
-// in the content process
-function getElementWithSelection(window) {
- let element = Services.focus.getFocusedElementForWindow(window, false, {});
- 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) {
- console.exception(err);
- return null;
- }
-}
-
-function safeGetRange(selection, rangeNumber) {
- try {
- let { rangeCount } = selection;
- let range = null;
-
- for (let rangeNumber = 0; rangeNumber < rangeCount; rangeNumber++ ) {
- range = selection.getRangeAt(rangeNumber);
-
- if (range && range.toString())
- break;
-
- range = null;
- }
-
- return range;
- }
- catch (e) {
- return null;
- }
-}
-
-function getSelection(window) {
- let selection = window.getSelection();
- let range = safeGetRange(selection);
- if (range)
- return range.toString();
-
- let node = getElementWithSelection(window);
- if (!node)
- return null;
-
- return node.value.substring(node.selectionStart, node.selectionEnd);
-}
-
-//These are used by PageContext.isCurrent below. If the popupNode or any of
-//its ancestors is one of these, Firefox uses a tailored context menu, and so
-//the page context doesn't apply.
-const NON_PAGE_CONTEXT_ELTS = [
- Ci.nsIDOMHTMLAnchorElement,
- Ci.nsIDOMHTMLAppletElement,
- Ci.nsIDOMHTMLAreaElement,
- Ci.nsIDOMHTMLButtonElement,
- Ci.nsIDOMHTMLCanvasElement,
- Ci.nsIDOMHTMLEmbedElement,
- Ci.nsIDOMHTMLImageElement,
- Ci.nsIDOMHTMLInputElement,
- Ci.nsIDOMHTMLMapElement,
- Ci.nsIDOMHTMLMediaElement,
- Ci.nsIDOMHTMLMenuElement,
- Ci.nsIDOMHTMLObjectElement,
- Ci.nsIDOMHTMLOptionElement,
- Ci.nsIDOMHTMLSelectElement,
- Ci.nsIDOMHTMLTextAreaElement,
-];
-
-// List all editable types of inputs. Or is it better to have a list
-// of non-editable inputs?
-var editableInputs = {
- email: true,
- number: true,
- password: true,
- search: true,
- tel: true,
- text: true,
- textarea: true,
- url: true
-};
-
-var CONTEXTS = {};
-
-var Context = Class({
- initialize: function(id) {
- this.id = id;
- },
-
- adjustPopupNode: function adjustPopupNode(popupNode) {
- return popupNode;
- },
-
- // Gets state to pass through to the parent process for the node the user
- // clicked on
- getState: function(popupNode) {
- return false;
- }
-});
-
-// Matches when the context-clicked node doesn't have any of
-// NON_PAGE_CONTEXT_ELTS in its ancestors
-CONTEXTS.PageContext = Class({
- extends: Context,
-
- getState: function(popupNode) {
- // If there is a selection in the window then this context does not match
- if (!popupNode.ownerDocument.defaultView.getSelection().isCollapsed)
- return false;
-
- // If the clicked node or any of its ancestors is one of the blocked
- // NON_PAGE_CONTEXT_ELTS then this context does not match
- while (!(popupNode instanceof Ci.nsIDOMDocument)) {
- if (NON_PAGE_CONTEXT_ELTS.some(type => popupNode instanceof type))
- return false;
-
- popupNode = popupNode.parentNode;
- }
-
- return true;
- }
-});
-
-// Matches when there is an active selection in the window
-CONTEXTS.SelectionContext = Class({
- extends: Context,
-
- getState: function(popupNode) {
- if (!popupNode.ownerDocument.defaultView.getSelection().isCollapsed)
- return true;
-
- try {
- // The node may be a text box which has selectionStart and selectionEnd
- // properties. If not this will throw.
- let { selectionStart, selectionEnd } = popupNode;
- return !isNaN(selectionStart) && !isNaN(selectionEnd) &&
- selectionStart !== selectionEnd;
- }
- catch (e) {
- return false;
- }
- }
-});
-
-// Matches when the context-clicked node or any of its ancestors matches the
-// selector given
-CONTEXTS.SelectorContext = Class({
- extends: Context,
-
- initialize: function initialize(id, selector) {
- Context.prototype.initialize.call(this, id);
- this.selector = selector;
- },
-
- adjustPopupNode: function adjustPopupNode(popupNode) {
- let selector = this.selector;
-
- while (!(popupNode instanceof Ci.nsIDOMDocument)) {
- if (popupNode.matches(selector))
- return popupNode;
-
- popupNode = popupNode.parentNode;
- }
-
- return null;
- },
-
- getState: function(popupNode) {
- return !!this.adjustPopupNode(popupNode);
- }
-});
-
-// Matches when the page url matches any of the patterns given
-CONTEXTS.URLContext = Class({
- extends: Context,
-
- getState: function(popupNode) {
- return popupNode.ownerDocument.URL;
- }
-});
-
-// Matches when the user-supplied predicate returns true
-CONTEXTS.PredicateContext = Class({
- extends: Context,
-
- getState: function(node) {
- let window = node.ownerDocument.defaultView;
- let data = {};
-
- data.documentType = node.ownerDocument.contentType;
-
- data.documentURL = node.ownerDocument.location.href;
- data.targetName = node.nodeName.toLowerCase();
- data.targetID = node.id || null ;
-
- if ((data.targetName === 'input' && editableInputs[node.type]) ||
- data.targetName === 'textarea') {
- data.isEditable = !node.readOnly && !node.disabled;
- }
- else {
- data.isEditable = node.isContentEditable;
- }
-
- data.selectionText = getSelection(window, "TEXT");
-
- data.srcURL = node.src || null;
- data.value = node.value || null;
-
- while (!data.linkURL && node) {
- data.linkURL = node.href || null;
- node = node.parentNode;
- }
-
- return data;
- },
-});
-
-function instantiateContext({ id, type, args }) {
- if (!(type in CONTEXTS)) {
- console.error("Attempt to use unknown context " + type);
- return;
- }
- return new CONTEXTS[type](id, ...args);
-}
-
-var ContextWorker = Class({
- implements: [ WorkerChild ],
-
- // Calls the context workers context listeners and returns the first result
- // that is either a string or a value that evaluates to true. If all of the
- // listeners returned false then returns false. If there are no listeners,
- // returns true (show the menu item by default).
- getMatchedContext: function getCurrentContexts(popupNode) {
- let results = this.sandbox.emitSync("context", popupNode);
- if (!results.length)
- return true;
- return results.reduce((val, result) => val || result);
- },
-
- // Emits a click event in the worker's port. popupNode is the node that was
- // context-clicked, and clickedItemData is the data of the item that was
- // clicked.
- fireClick: function fireClick(popupNode, clickedItemData) {
- this.sandbox.emitSync("click", popupNode, clickedItemData);
- }
-});
-
-// Gets the item's content script worker for a window, creating one if necessary
-// Once created it will be automatically destroyed when the window unloads.
-// If there is not content scripts for the item then null will be returned.
-function getItemWorkerForWindow(item, window) {
- if (!item.contentScript && !item.contentScriptFile)
- return null;
-
- let id = getInnerId(window);
- let worker = item.workerMap.get(id);
-
- if (worker)
- return worker;
-
- worker = ContextWorker({
- id: item.id,
- window,
- manager: item.manager,
- contentScript: item.contentScript,
- contentScriptFile: item.contentScriptFile,
- onDetach: function() {
- item.workerMap.delete(id);
- }
- });
-
- item.workerMap.set(id, worker);
-
- return worker;
-}
-
-// A very simple remote proxy for every item. It's job is to provide data for
-// the main process to use to determine visibility state and to call into
-// content scripts when clicked.
-var RemoteItem = Class({
- initialize: function(options, manager) {
- this.id = options.id;
- this.contexts = options.contexts.map(instantiateContext);
- this.contentScript = options.contentScript;
- this.contentScriptFile = options.contentScriptFile;
-
- this.manager = manager;
-
- this.workerMap = new Map();
- keepAlive.set(this.id, this);
- },
-
- destroy: function() {
- for (let worker of this.workerMap.values()) {
- worker.destroy();
- }
- keepAlive.delete(this.id);
- },
-
- activate: function(popupNode, data) {
- let worker = getItemWorkerForWindow(this, popupNode.ownerDocument.defaultView);
- if (!worker)
- return;
-
- for (let context of this.contexts)
- popupNode = context.adjustPopupNode(popupNode);
-
- worker.fireClick(popupNode, data);
- },
-
- // Fills addonInfo with state data to send through to the main process
- getContextState: function(popupNode, addonInfo) {
- if (!(self.id in addonInfo)) {
- addonInfo[self.id] = {
- processID: process.id,
- items: {}
- };
- }
-
- let worker = getItemWorkerForWindow(this, popupNode.ownerDocument.defaultView);
- let contextStates = {};
- for (let context of this.contexts)
- contextStates[context.id] = context.getState(popupNode);
-
- addonInfo[self.id].items[this.id] = {
- // It isn't ideal to create a PageContext for every item but there isn't
- // a good shared place to do it.
- pageContext: (new CONTEXTS.PageContext()).getState(popupNode),
- contextStates,
- hasWorker: !!worker,
- workerContext: worker ? worker.getMatchedContext(popupNode) : true
- }
- }
-});
-exports.RemoteItem = RemoteItem;
-
-// Holds remote items for this frame.
-var keepAlive = new Map();
-
-// Called to create remote proxies for items. If they already exist we destroy
-// and recreate. This can happen if the item changes in some way or in odd
-// timing cases where the frame script is create around the same time as the
-// item is created in the main process
-process.port.on('sdk/contextmenu/createitems', (process, items) => {
- for (let itemoptions of items) {
- let oldItem = keepAlive.get(itemoptions.id);
- if (oldItem) {
- oldItem.destroy();
- }
-
- let item = new RemoteItem(itemoptions, this);
- }
-});
-
-process.port.on('sdk/contextmenu/destroyitems', (process, items) => {
- for (let id of items) {
- let item = keepAlive.get(id);
- item.destroy();
- }
-});
-
-var lastPopupNode = null;
-
-system.on('content-contextmenu', ({ subject }) => {
- let { event: { target: popupNode }, addonInfo } = subject.wrappedJSObject;
- lastPopupNode = popupNode;
-
- for (let item of keepAlive.values()) {
- item.getContextState(popupNode, addonInfo);
- }
-}, true);
-
-process.port.on('sdk/contextmenu/activateitems', (process, items, data) => {
- for (let id of items) {
- let item = keepAlive.get(id);
- if (!item)
- continue;
-
- item.activate(lastPopupNode, data);
- }
-});
diff --git a/addon-sdk/source/lib/sdk/content/events.js b/addon-sdk/source/lib/sdk/content/events.js
deleted file mode 100644
index c085b6179..000000000
--- a/addon-sdk/source/lib/sdk/content/events.js
+++ /dev/null
@@ -1,57 +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 { Ci } = require("chrome");
-const { open } = require("../event/dom");
-const { observe } = require("../event/chrome");
-const { filter, merge, map, expand } = require("../event/utils");
-const { windows } = require("../window/utils");
-const { events: windowEvents } = require("sdk/window/events");
-
-// Note: Please note that even though pagehide event is included
-// it's not observable reliably since it's not always triggered
-// when closing tabs. Implementation can be imrpoved once that
-// event will be necessary.
-var TYPES = ["DOMContentLoaded", "load", "pageshow", "pagehide"];
-
-var insert = observe("document-element-inserted");
-var windowCreate = merge([
- observe("content-document-global-created"),
- observe("chrome-document-global-created")
-]);
-var create = map(windowCreate, function({target, data, type}) {
- return { target: target.document, type: type, data: data }
-});
-
-function streamEventsFrom({document}) {
- // Map supported event types to a streams of those events on the given
- // `window` for the inserted document and than merge these streams into
- // single form stream off all window state change events.
- let stateChanges = TYPES.map(function(type) {
- return open(document, type, { capture: true });
- });
-
- // Since load events on document occur for every loded resource
- return filter(merge(stateChanges), function({target}) {
- return target instanceof Ci.nsIDOMDocument
- })
-}
-exports.streamEventsFrom = streamEventsFrom;
-
-var opened = windows(null, { includePrivate: true });
-var state = merge(opened.map(streamEventsFrom));
-
-
-var futureReady = filter(windowEvents, ({type}) =>
- type === "DOMContentLoaded");
-var futureWindows = map(futureReady, ({target}) => target);
-var futureState = expand(futureWindows, streamEventsFrom);
-
-exports.events = merge([insert, create, state, futureState]);
diff --git a/addon-sdk/source/lib/sdk/content/l10n-html.js b/addon-sdk/source/lib/sdk/content/l10n-html.js
deleted file mode 100644
index f324623dc..000000000
--- a/addon-sdk/source/lib/sdk/content/l10n-html.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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { Ci, Cc, Cu } = require("chrome");
-const core = require("../l10n/core");
-const { loadSheet, removeSheet } = require("../stylesheet/utils");
-const { process, frames } = require("../remote/child");
-var observerService = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const addObserver = ShimWaiver.getProperty(observerService, "addObserver");
-const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver");
-
-const assetsURI = require('../self').data.url();
-
-const hideSheetUri = "data:text/css,:root {visibility: hidden !important;}";
-
-function translateElementAttributes(element) {
- // Translateable attributes
- const attrList = ['title', 'accesskey', 'alt', 'label', 'placeholder'];
- const ariaAttrMap = {
- 'ariaLabel': 'aria-label',
- 'ariaValueText': 'aria-valuetext',
- 'ariaMozHint': 'aria-moz-hint'
- };
- const attrSeparator = '.';
-
- // Try to translate each of the attributes
- for (let attribute of attrList) {
- const data = core.get(element.dataset.l10nId + attrSeparator + attribute);
- if (data)
- element.setAttribute(attribute, data);
- }
-
- // Look for the aria attribute translations that match fxOS's aliases
- for (let attrAlias in ariaAttrMap) {
- const data = core.get(element.dataset.l10nId + attrSeparator + attrAlias);
- if (data)
- element.setAttribute(ariaAttrMap[attrAlias], data);
- }
-}
-
-// Taken from Gaia:
-// https://github.com/andreasgal/gaia/blob/04fde2640a7f40314643016a5a6c98bf3755f5fd/webapi.js#L1470
-function translateElement(element) {
- element = element || document;
-
- // check all translatable children (= w/ a `data-l10n-id' attribute)
- var children = element.querySelectorAll('*[data-l10n-id]');
- var elementCount = children.length;
- for (var i = 0; i < elementCount; i++) {
- var child = children[i];
-
- // translate the child
- var key = child.dataset.l10nId;
- var data = core.get(key);
- if (data)
- child.textContent = data;
-
- translateElementAttributes(child);
- }
-}
-exports.translateElement = translateElement;
-
-function onDocumentReady2Translate(event) {
- let document = event.target;
- document.removeEventListener("DOMContentLoaded", onDocumentReady2Translate,
- false);
-
- translateElement(document);
-
- try {
- // Finally display document when we finished replacing all text content
- if (document.defaultView)
- removeSheet(document.defaultView, hideSheetUri, 'user');
- }
- catch(e) {
- console.exception(e);
- }
-}
-
-function onContentWindow(document) {
- // Accept only HTML documents
- if (!(document instanceof Ci.nsIDOMHTMLDocument))
- return;
-
- // Bug 769483: data:URI documents instanciated with nsIDOMParser
- // have a null `location` attribute at this time
- if (!document.location)
- return;
-
- // Accept only document from this addon
- if (document.location.href.indexOf(assetsURI) !== 0)
- return;
-
- try {
- // First hide content of the document in order to have content blinking
- // between untranslated and translated states
- loadSheet(document.defaultView, hideSheetUri, 'user');
- }
- catch(e) {
- console.exception(e);
- }
- // Wait for DOM tree to be built before applying localization
- document.addEventListener("DOMContentLoaded", onDocumentReady2Translate,
- false);
-}
-
-// Listen to creation of content documents in order to translate them as soon
-// as possible in their loading process
-const ON_CONTENT = "document-element-inserted";
-let enabled = false;
-function enable() {
- if (enabled)
- return;
- addObserver(onContentWindow, ON_CONTENT, false);
- enabled = true;
-}
-process.port.on("sdk/l10n/html/enable", enable);
-
-function disable() {
- if (!enabled)
- return;
- removeObserver(onContentWindow, ON_CONTENT);
- enabled = false;
-}
-process.port.on("sdk/l10n/html/disable", disable);
diff --git a/addon-sdk/source/lib/sdk/content/loader.js b/addon-sdk/source/lib/sdk/content/loader.js
deleted file mode 100644
index e4f0dd2aa..000000000
--- a/addon-sdk/source/lib/sdk/content/loader.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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { isValidURI, isLocalURL, URL } = require('../url');
-const { contract } = require('../util/contract');
-const { isString, isNil, instanceOf, isJSONable } = require('../lang/type');
-const { validateOptions,
- string, array, object, either, required } = require('../deprecated/api-utils');
-
-const isValidScriptFile = (value) =>
- (isString(value) || instanceOf(value, URL)) && isLocalURL(value);
-
-// map of property validations
-const valid = {
- contentURL: {
- is: either(string, object),
- ok: url => isNil(url) || isLocalURL(url) || isValidURI(url),
- msg: 'The `contentURL` option must be a valid URL.'
- },
- contentScriptFile: {
- is: either(string, object, array),
- ok: value => isNil(value) || [].concat(value).every(isValidScriptFile),
- msg: 'The `contentScriptFile` option must be a local URL or an array of URLs.'
- },
- contentScript: {
- is: either(string, array),
- ok: value => isNil(value) || [].concat(value).every(isString),
- msg: 'The `contentScript` option must be a string or an array of strings.'
- },
- contentScriptWhen: {
- is: required(string),
- map: value => value || 'end',
- ok: value => ~['start', 'ready', 'end'].indexOf(value),
- msg: 'The `contentScriptWhen` option must be either "start", "ready" or "end".'
- },
- contentScriptOptions: {
- ok: value => isNil(value) || isJSONable(value),
- msg: 'The contentScriptOptions should be a jsonable value.'
- }
-};
-exports.validationAttributes = valid;
-
-/**
- * Shortcut function to validate property with validation.
- * @param {Object|Number|String} suspect
- * value to validate
- * @param {Object} validation
- * validation rule passed to `api-utils`
- */
-function validate(suspect, validation) {
- return validateOptions(
- { $: suspect },
- { $: validation }
- ).$;
-}
-
-function Allow(script) {
- return {
- get script() {
- return script;
- },
- set script(value) {
- script = !!value;
- }
- };
-}
-
-exports.contract = contract(valid);
diff --git a/addon-sdk/source/lib/sdk/content/mod.js b/addon-sdk/source/lib/sdk/content/mod.js
deleted file mode 100644
index 81fe9ee42..000000000
--- a/addon-sdk/source/lib/sdk/content/mod.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": "experimental"
-};
-
-const { Ci } = require("chrome");
-const { dispatcher } = require("../util/dispatcher");
-const { add, remove, iterator } = require("../lang/weak-set");
-
-var getTargetWindow = dispatcher("getTargetWindow");
-
-getTargetWindow.define(function (target) {
- if (target instanceof Ci.nsIDOMWindow)
- return target;
- if (target instanceof Ci.nsIDOMDocument)
- return target.defaultView || null;
-
- return null;
-});
-
-exports.getTargetWindow = getTargetWindow;
-
-var attachTo = dispatcher("attachTo");
-exports.attachTo = attachTo;
-
-var detachFrom = dispatcher("detatchFrom");
-exports.detachFrom = detachFrom;
-
-function attach(modification, target) {
- if (!modification)
- return;
-
- let window = getTargetWindow(target);
-
- attachTo(modification, window);
-
- // modification are stored per content; `window` reference can still be the
- // same even if the content is changed, therefore `document` is used instead.
- add(modification, window.document);
-}
-exports.attach = attach;
-
-function detach(modification, target) {
- if (!modification)
- return;
-
- if (target) {
- let window = getTargetWindow(target);
- detachFrom(modification, window);
- remove(modification, window.document);
- }
- else {
- let documents = iterator(modification);
- for (let document of documents) {
- let window = document.defaultView;
- // The window might have already gone away
- if (!window)
- continue;
- detachFrom(modification, document.defaultView);
- remove(modification, document);
- }
- }
-}
-exports.detach = detach;
diff --git a/addon-sdk/source/lib/sdk/content/page-mod.js b/addon-sdk/source/lib/sdk/content/page-mod.js
deleted file mode 100644
index 8ff9b1e7b..000000000
--- a/addon-sdk/source/lib/sdk/content/page-mod.js
+++ /dev/null
@@ -1,236 +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 { getAttachEventType } = require('../content/utils');
-const { Class } = require('../core/heritage');
-const { Disposable } = require('../core/disposable');
-const { WeakReference } = require('../core/reference');
-const { WorkerChild } = require('./worker-child');
-const { EventTarget } = require('../event/target');
-const { on, emit, once, setListeners } = require('../event/core');
-const { on: domOn, removeListener: domOff } = require('../dom/events');
-const { isRegExp, isUndefined } = require('../lang/type');
-const { merge } = require('../util/object');
-const { isBrowser, getFrames } = require('../window/utils');
-const { getTabs, getURI: getTabURI } = require('../tabs/utils');
-const { ignoreWindow } = require('../private-browsing/utils');
-const { Style } = require("../stylesheet/style");
-const { attach, detach } = require("../content/mod");
-const { has, hasAny } = require("../util/array");
-const { Rules } = require("../util/rules");
-const { List, addListItem, removeListItem } = require('../util/list');
-const { when } = require("../system/unload");
-const { uuid } = require('../util/uuid');
-const { frames, process } = require('../remote/child');
-
-const pagemods = new Map();
-const styles = new WeakMap();
-var styleFor = (mod) => styles.get(mod);
-
-// Helper functions
-var modMatchesURI = (mod, uri) => mod.include.matchesAny(uri) && !mod.exclude.matchesAny(uri);
-
-/**
- * PageMod constructor (exported below).
- * @constructor
- */
-const ChildPageMod = Class({
- implements: [
- EventTarget,
- Disposable,
- ],
- setup: function PageMod(model) {
- merge(this, model);
-
- // Set listeners on {PageMod} itself, not the underlying worker,
- // like `onMessage`, as it'll get piped.
- setListeners(this, model);
-
- function deserializeRules(rules) {
- for (let rule of rules) {
- yield rule.type == "string" ? rule.value
- : new RegExp(rule.pattern, rule.flags);
- }
- }
-
- let include = [...deserializeRules(this.include)];
- this.include = Rules();
- this.include.add.apply(this.include, include);
-
- let exclude = [...deserializeRules(this.exclude)];
- this.exclude = Rules();
- this.exclude.add.apply(this.exclude, exclude);
-
- if (this.contentStyle || this.contentStyleFile) {
- styles.set(this, Style({
- uri: this.contentStyleFile,
- source: this.contentStyle
- }));
- }
-
- pagemods.set(this.id, this);
- this.seenDocuments = new WeakMap();
-
- // `applyOnExistingDocuments` has to be called after `pagemods.add()`
- // otherwise its calls to `onContent` method won't do anything.
- if (has(this.attachTo, 'existing'))
- applyOnExistingDocuments(this);
- },
-
- dispose: function() {
- let style = styleFor(this);
- if (style)
- detach(style);
-
- for (let i in this.include)
- this.include.remove(this.include[i]);
-
- pagemods.delete(this.id);
- }
-});
-
-function onContentWindow({ target: document }) {
- // Return if we have no pagemods
- if (pagemods.size === 0)
- return;
-
- let window = document.defaultView;
- // XML documents don't have windows, and we don't yet support them.
- if (!window)
- return;
-
- // Frame event listeners are bound to the frame the event came from by default
- let frame = this;
- // We apply only on documents in tabs of Firefox
- if (!frame.isTab)
- return;
-
- // When the tab is private, only addons with 'private-browsing' flag in
- // their package.json can apply content script to private documents
- if (ignoreWindow(window))
- return;
-
- for (let pagemod of pagemods.values()) {
- if (modMatchesURI(pagemod, window.location.href))
- onContent(pagemod, window);
- }
-}
-frames.addEventListener("DOMDocElementInserted", onContentWindow, true);
-
-function applyOnExistingDocuments (mod) {
- for (let frame of frames) {
- // Fake a newly created document
- let window = frame.content;
- // on startup with e10s, contentWindow might not exist yet,
- // in which case we will get notified by "document-element-inserted".
- if (!window || !window.frames)
- return;
- let uri = window.location.href;
- if (has(mod.attachTo, "top") && modMatchesURI(mod, uri))
- onContent(mod, window);
- if (has(mod.attachTo, "frame"))
- getFrames(window).
- filter(iframe => modMatchesURI(mod, iframe.location.href)).
- forEach(frame => onContent(mod, frame));
- }
-}
-
-function createWorker(mod, window) {
- let workerId = String(uuid());
-
- // Instruct the parent to connect to this worker. Do this first so the parent
- // side is connected before the worker attempts to send any messages there
- let frame = frames.getFrameForWindow(window.top);
- frame.port.emit('sdk/page-mod/worker-create', mod.id, {
- id: workerId,
- url: window.location.href
- });
-
- // Create a child worker and notify the parent
- let worker = WorkerChild({
- id: workerId,
- window: window,
- contentScript: mod.contentScript,
- contentScriptFile: mod.contentScriptFile,
- contentScriptOptions: mod.contentScriptOptions
- });
-
- once(worker, 'detach', () => worker.destroy());
-}
-
-function onContent (mod, window) {
- let isTopDocument = window.top === window;
- // Is a top level document and `top` is not set, ignore
- if (isTopDocument && !has(mod.attachTo, "top"))
- return;
- // Is a frame document and `frame` is not set, ignore
- if (!isTopDocument && !has(mod.attachTo, "frame"))
- return;
-
- // ensure we attach only once per document
- let seen = mod.seenDocuments;
- if (seen.has(window.document))
- return;
- seen.set(window.document, true);
-
- let style = styleFor(mod);
- if (style)
- attach(style, window);
-
- // Immediately evaluate content script if the document state is already
- // matching contentScriptWhen expectations
- if (isMatchingAttachState(mod, window)) {
- createWorker(mod, window);
- return;
- }
-
- let eventName = getAttachEventType(mod) || 'load';
- domOn(window, eventName, function onReady (e) {
- if (e.target.defaultView !== window)
- return;
- domOff(window, eventName, onReady, true);
- createWorker(mod, window);
-
- // Attaching is asynchronous so if the document is already loaded we will
- // miss the pageshow event so send a synthetic one.
- if (window.document.readyState == "complete") {
- mod.on('attach', worker => {
- try {
- worker.send('pageshow');
- emit(worker, 'pageshow');
- }
- catch (e) {
- // This can fail if an earlier attach listener destroyed the worker
- }
- });
- }
- }, true);
-}
-
-function isMatchingAttachState (mod, window) {
- let state = window.document.readyState;
- return 'start' === mod.contentScriptWhen ||
- // Is `load` event already dispatched?
- 'complete' === state ||
- // Is DOMContentLoaded already dispatched and waiting for it?
- ('ready' === mod.contentScriptWhen && state === 'interactive')
-}
-
-process.port.on('sdk/page-mod/create', (process, model) => {
- if (pagemods.has(model.id))
- return;
-
- new ChildPageMod(model);
-});
-
-process.port.on('sdk/page-mod/destroy', (process, id) => {
- let mod = pagemods.get(id);
- if (mod)
- mod.destroy();
-});
diff --git a/addon-sdk/source/lib/sdk/content/page-worker.js b/addon-sdk/source/lib/sdk/content/page-worker.js
deleted file mode 100644
index e9e741120..000000000
--- a/addon-sdk/source/lib/sdk/content/page-worker.js
+++ /dev/null
@@ -1,154 +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 { frames } = require("../remote/child");
-const { Class } = require("../core/heritage");
-const { Disposable } = require('../core/disposable');
-const { data } = require("../self");
-const { once } = require("../dom/events");
-const { getAttachEventType } = require("./utils");
-const { Rules } = require('../util/rules');
-const { uuid } = require('../util/uuid');
-const { WorkerChild } = require("./worker-child");
-const { Cc, Ci, Cu } = require("chrome");
-const { observe } = require("../event/chrome");
-const { on } = require("../event/core");
-
-const appShell = Cc["@mozilla.org/appshell/appShellService;1"].getService(Ci.nsIAppShellService);
-
-const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
-
-const pages = new Map();
-
-const DOC_INSERTED = "document-element-inserted";
-
-function isValidURL(page, url) {
- return !page.rules || page.rules.matchesAny(url);
-}
-
-const ChildPage = Class({
- implements: [ Disposable ],
- setup: function(frame, id, options) {
- this.id = id;
- this.frame = frame;
- this.options = options;
-
- this.webNav = appShell.createWindowlessBrowser(false);
- this.docShell.allowJavascript = this.options.allow.script;
-
- // Accessing the browser's window forces the initial about:blank document to
- // be created before we start listening for notifications
- this.contentWindow;
-
- this.webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION);
-
- pages.set(this.id, this);
-
- this.contentURL = options.contentURL;
-
- if (options.include) {
- this.rules = Rules();
- this.rules.add.apply(this.rules, [].concat(options.include));
- }
- },
-
- dispose: function() {
- pages.delete(this.id);
- this.webProgress.removeProgressListener(this);
- this.webNav.close();
- this.webNav = null;
- },
-
- attachWorker: function() {
- if (!isValidURL(this, this.contentWindow.location.href))
- return;
-
- this.options.id = uuid().toString();
- this.options.window = this.contentWindow;
- this.frame.port.emit("sdk/frame/connect", this.id, {
- id: this.options.id,
- url: this.contentWindow.document.documentURIObject.spec
- });
- new WorkerChild(this.options);
- },
-
- get docShell() {
- return this.webNav.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDocShell);
- },
-
- get webProgress() {
- return this.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebProgress);
- },
-
- get contentWindow() {
- return this.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
- },
-
- get contentURL() {
- return this.options.contentURL;
- },
- set contentURL(url) {
- this.options.contentURL = url;
-
- url = this.options.contentURL ? data.url(this.options.contentURL) : "about:blank";
- this.webNav.loadURI(url, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
- },
-
- onLocationChange: function(progress, request, location, flags) {
- // Ignore inner-frame events
- if (progress != this.webProgress)
- return;
- // Ignore events that don't change the document
- if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)
- return;
-
- let event = getAttachEventType(this.options);
- // Attaching at the start of the load is handled by the
- // document-element-inserted listener.
- if (event == DOC_INSERTED)
- return;
-
- once(this.contentWindow, event, () => {
- this.attachWorker();
- }, false);
- },
-
- QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener", "nsISupportsWeakReference"])
-});
-
-on(observe(DOC_INSERTED), "data", ({ target }) => {
- let page = Array.from(pages.values()).find(p => p.contentWindow.document === target);
- if (!page)
- return;
-
- if (getAttachEventType(page.options) == DOC_INSERTED)
- page.attachWorker();
-});
-
-frames.port.on("sdk/frame/create", (frame, id, options) => {
- new ChildPage(frame, id, options);
-});
-
-frames.port.on("sdk/frame/set", (frame, id, params) => {
- let page = pages.get(id);
- if (!page)
- return;
-
- if ("allowScript" in params)
- page.docShell.allowJavascript = params.allowScript;
- if ("contentURL" in params)
- page.contentURL = params.contentURL;
-});
-
-frames.port.on("sdk/frame/destroy", (frame, id) => {
- let page = pages.get(id);
- if (!page)
- return;
-
- page.destroy();
-});
diff --git a/addon-sdk/source/lib/sdk/content/sandbox.js b/addon-sdk/source/lib/sdk/content/sandbox.js
deleted file mode 100644
index 096ba5c87..000000000
--- 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');
-const { on, off, emit } = require('../event/core');
-const { events } = require('./sandbox/events');
-const { requiresAddonGlobal } = require('./utils');
-const { delay: async } = require('../lang/functional');
-const { Ci, Cu, Cc } = require('chrome');
-const timer = require('../timers');
-const { URL } = require('../url');
-const { sandbox, evaluate, load } = require('../loader/sandbox');
-const { merge } = require('../util/object');
-const { getTabForContentWindowNoShim } = require('../tabs/utils');
-const { getInnerId } = require('../window/utils');
-const { PlainTextConsole } = require('../console/plain-text');
-const { data } = require('../self');const { isChildLoader } = require('../remote/core');
-// 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'),
- markTimeline: genPropDesc('markTimeline'),
- timeline: genPropDesc('timeline'),
- timelineEnd: genPropDesc('timelineEnd'),
- 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});
-}
diff --git a/addon-sdk/source/lib/sdk/content/sandbox/events.js b/addon-sdk/source/lib/sdk/content/sandbox/events.js
deleted file mode 100644
index d6f7eb004..000000000
--- 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;
diff --git a/addon-sdk/source/lib/sdk/content/tab-events.js b/addon-sdk/source/lib/sdk/content/tab-events.js
deleted file mode 100644
index 9e244a853..000000000
--- 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 });
-}
diff --git a/addon-sdk/source/lib/sdk/content/thumbnail.js b/addon-sdk/source/lib/sdk/content/thumbnail.js
deleted file mode 100644
index 783615fc6..000000000
--- a/addon-sdk/source/lib/sdk/content/thumbnail.js
+++ /dev/null
@@ -1,51 +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 { Cc, Ci, Cu } = require('chrome');
-const AppShellService = Cc['@mozilla.org/appshell/appShellService;1'].
- getService(Ci.nsIAppShellService);
-
-const NS = 'http://www.w3.org/1999/xhtml';
-const COLOR = 'rgb(255,255,255)';
-
-/**
- * Creates canvas element with a thumbnail of the passed window.
- * @param {Window} window
- * @returns {Element}
- */
-function getThumbnailCanvasForWindow(window) {
- let aspectRatio = 0.5625; // 16:9
- let thumbnail = AppShellService.hiddenDOMWindow.document
- .createElementNS(NS, 'canvas');
- thumbnail.mozOpaque = true;
- thumbnail.width = Math.ceil(window.screen.availWidth / 5.75);
- thumbnail.height = Math.round(thumbnail.width * aspectRatio);
- let ctx = thumbnail.getContext('2d');
- let snippetWidth = window.innerWidth * .6;
- let scale = thumbnail.width / snippetWidth;
- ctx.scale(scale, scale);
- ctx.drawWindow(window, window.scrollX, window.scrollY, snippetWidth,
- snippetWidth * aspectRatio, COLOR);
- return thumbnail;
-}
-exports.getThumbnailCanvasForWindow = getThumbnailCanvasForWindow;
-
-/**
- * Creates Base64 encoded data URI of the thumbnail for the passed window.
- * @param {Window} window
- * @returns {String}
- */
-exports.getThumbnailURIForWindow = function getThumbnailURIForWindow(window) {
- return getThumbnailCanvasForWindow(window).toDataURL()
-};
-
-// default 80x45 blank when not available
-exports.BLANK = 'data:image/png;base64,' +
- 'iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQ'+
- 'EAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC';
diff --git a/addon-sdk/source/lib/sdk/content/utils.js b/addon-sdk/source/lib/sdk/content/utils.js
deleted file mode 100644
index 90995a614..000000000
--- a/addon-sdk/source/lib/sdk/content/utils.js
+++ /dev/null
@@ -1,105 +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'
-};
-
-var { merge } = require('../util/object');
-var { data } = require('../self');
-var assetsURI = data.url();
-var isArray = Array.isArray;
-var method = require('../../method/core');
-var { uuid } = require('../util/uuid');
-
-const isAddonContent = ({ contentURL }) =>
- contentURL && data.url(contentURL).startsWith(assetsURI);
-
-exports.isAddonContent = isAddonContent;
-
-function hasContentScript({ contentScript, contentScriptFile }) {
- return (isArray(contentScript) ? contentScript.length > 0 :
- !!contentScript) ||
- (isArray(contentScriptFile) ? contentScriptFile.length > 0 :
- !!contentScriptFile);
-}
-exports.hasContentScript = hasContentScript;
-
-function requiresAddonGlobal(model) {
- return model.injectInDocument || (isAddonContent(model) && !hasContentScript(model));
-}
-exports.requiresAddonGlobal = requiresAddonGlobal;
-
-function getAttachEventType(model) {
- if (!model) return null;
- let when = model.contentScriptWhen;
- return requiresAddonGlobal(model) ? 'document-element-inserted' :
- when === 'start' ? 'document-element-inserted' :
- when === 'ready' ? 'DOMContentLoaded' :
- when === 'end' ? 'load' :
- null;
-}
-exports.getAttachEventType = getAttachEventType;
-
-var attach = method('worker-attach');
-exports.attach = attach;
-
-var connect = method('worker-connect');
-exports.connect = connect;
-
-var detach = method('worker-detach');
-exports.detach = detach;
-
-var destroy = method('worker-destroy');
-exports.destroy = destroy;
-
-function WorkerHost (workerFor) {
- // Define worker properties that just proxy to underlying worker
- return ['postMessage', 'port', 'url', 'tab'].reduce(function(proto, name) {
- // Use descriptor properties instead so we can call
- // the worker function in the context of the worker so we
- // don't have to create new functions with `fn.bind(worker)`
- let descriptorProp = {
- value: function (...args) {
- let worker = workerFor(this);
- return worker[name].apply(worker, args);
- }
- };
-
- let accessorProp = {
- get: function () { return workerFor(this)[name]; },
- set: function (value) { workerFor(this)[name] = value; }
- };
-
- Object.defineProperty(proto, name, merge({
- enumerable: true,
- configurable: false,
- }, isDescriptor(name) ? descriptorProp : accessorProp));
- return proto;
- }, {});
-
- function isDescriptor (prop) {
- return ~['postMessage'].indexOf(prop);
- }
-}
-exports.WorkerHost = WorkerHost;
-
-function makeChildOptions(options) {
- function makeStringArray(arrayOrValue) {
- if (!arrayOrValue)
- return [];
- return [].concat(arrayOrValue).map(String);
- }
-
- return {
- id: String(uuid()),
- contentScript: makeStringArray(options.contentScript),
- contentScriptFile: makeStringArray(options.contentScriptFile),
- contentScriptOptions: options.contentScriptOptions ?
- JSON.stringify(options.contentScriptOptions) :
- null,
- }
-}
-exports.makeChildOptions = makeChildOptions;
diff --git a/addon-sdk/source/lib/sdk/content/worker-child.js b/addon-sdk/source/lib/sdk/content/worker-child.js
deleted file mode 100644
index dbf65a933..000000000
--- 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';
-
-const { merge } = require('../util/object');
-const { Class } = require('../core/heritage');
-const { emit } = require('../event/core');
-const { EventTarget } = require('../event/target');
-const { getInnerId, getByInnerId } = require('../window/utils');
-const { instanceOf, isObject } = require('../lang/type');
-const system = require('../system/events');
-const { when } = require('../system/unload');
-const { WorkerSandbox } = require('./sandbox');
-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);
-});
diff --git a/addon-sdk/source/lib/sdk/content/worker.js b/addon-sdk/source/lib/sdk/content/worker.js
deleted file mode 100644
index 39b940a88..000000000
--- 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"
-};
-
-const { emit } = require('../event/core');
-const { omit, merge } = require('../util/object');
-const { Class } = require('../core/heritage');
-const { method } = require('../lang/functional');
-const { getInnerId } = require('../window/utils');
-const { EventTarget } = require('../event/target');
-const { isPrivate } = require('../private-browsing/utils');
-const { getTabForBrowser, getTabForContentWindowNoShim, getBrowserForTab } = require('../tabs/utils');
-const { attach, connect, detach, destroy, makeChildOptions } = require('./utils');
-const { ensure } = require('../system/unload');
-const { on: observe } = require('../system/events');
-const { Ci, Cu } = require('chrome');
-const { modelFor: tabFor } = require('sdk/model/core');
-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);
-});
diff --git a/addon-sdk/source/lib/sdk/context-menu.js b/addon-sdk/source/lib/sdk/context-menu.js
deleted file mode 100644
index 004c642d4..000000000
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ /dev/null
@@ -1,1188 +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": {
- // TODO Fennec support Bug 788334
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Class, mix } = require("./core/heritage");
-const { addCollectionProperty } = require("./util/collection");
-const { ns } = require("./core/namespace");
-const { validateOptions, getTypeOf } = require("./deprecated/api-utils");
-const { URL, isValidURI } = require("./url");
-const { WindowTracker, browserWindowIterator } = require("./deprecated/window-utils");
-const { isBrowser, getInnerId } = require("./window/utils");
-const { MatchPattern } = require("./util/match-pattern");
-const { EventTarget } = require("./event/target");
-const { emit } = require('./event/core');
-const { when } = require('./system/unload');
-const { contract: loaderContract } = require('./content/loader');
-const { omit } = require('./util/object');
-const self = require('./self')
-const { remoteRequire, processes } = require('./remote/parent');
-remoteRequire('sdk/content/context-menu');
-
-// All user items we add have this class.
-const ITEM_CLASS = "addon-context-menu-item";
-
-// Items in the top-level context menu also have this class.
-const TOPLEVEL_ITEM_CLASS = "addon-context-menu-item-toplevel";
-
-// Items in the overflow submenu also have this class.
-const OVERFLOW_ITEM_CLASS = "addon-context-menu-item-overflow";
-
-// The class of the menu separator that separates standard context menu items
-// from our user items.
-const SEPARATOR_CLASS = "addon-context-menu-separator";
-
-// If more than this number of items are added to the context menu, all items
-// overflow into a "Jetpack" submenu.
-const OVERFLOW_THRESH_DEFAULT = 10;
-const OVERFLOW_THRESH_PREF =
- "extensions.addon-sdk.context-menu.overflowThreshold";
-
-// The label of the overflow sub-xul:menu.
-//
-// TODO: Localize these.
-const OVERFLOW_MENU_LABEL = "Add-ons";
-const OVERFLOW_MENU_ACCESSKEY = "A";
-
-// The class of the overflow sub-xul:menu.
-const OVERFLOW_MENU_CLASS = "addon-content-menu-overflow-menu";
-
-// The class of the overflow submenu's xul:menupopup.
-const OVERFLOW_POPUP_CLASS = "addon-content-menu-overflow-popup";
-
-// Holds private properties for API objects
-var internal = ns();
-
-// A little hacky but this is the last process ID that last opened the context
-// menu
-var lastContextProcessId = null;
-
-var uuidModule = require('./util/uuid');
-function uuid() {
- return uuidModule.uuid().toString();
-}
-
-function getScheme(spec) {
- try {
- return URL(spec).scheme;
- }
- catch(e) {
- return null;
- }
-}
-
-var Context = Class({
- initialize: function() {
- internal(this).id = uuid();
- },
-
- // Returns the node that made this context current
- adjustPopupNode: function adjustPopupNode(popupNode) {
- return popupNode;
- },
-
- // Returns whether this context is current for the current node
- isCurrent: function isCurrent(state) {
- return state;
- }
-});
-
-// Matches when the context-clicked node doesn't have any of
-// NON_PAGE_CONTEXT_ELTS in its ancestors
-var PageContext = Class({
- extends: Context,
-
- serialize: function() {
- return {
- id: internal(this).id,
- type: "PageContext",
- args: []
- }
- }
-});
-exports.PageContext = PageContext;
-
-// Matches when there is an active selection in the window
-var SelectionContext = Class({
- extends: Context,
-
- serialize: function() {
- return {
- id: internal(this).id,
- type: "SelectionContext",
- args: []
- }
- }
-});
-exports.SelectionContext = SelectionContext;
-
-// Matches when the context-clicked node or any of its ancestors matches the
-// selector given
-var SelectorContext = Class({
- extends: Context,
-
- initialize: function initialize(selector) {
- Context.prototype.initialize.call(this);
- let options = validateOptions({ selector: selector }, {
- selector: {
- is: ["string"],
- msg: "selector must be a string."
- }
- });
- internal(this).selector = options.selector;
- },
-
- serialize: function() {
- return {
- id: internal(this).id,
- type: "SelectorContext",
- args: [internal(this).selector]
- }
- }
-});
-exports.SelectorContext = SelectorContext;
-
-// Matches when the page url matches any of the patterns given
-var URLContext = Class({
- extends: Context,
-
- initialize: function initialize(patterns) {
- Context.prototype.initialize.call(this);
- patterns = Array.isArray(patterns) ? patterns : [patterns];
-
- try {
- internal(this).patterns = patterns.map(p => new MatchPattern(p));
- }
- catch (err) {
- throw new Error("Patterns must be a string, regexp or an array of " +
- "strings or regexps: " + err);
- }
- },
-
- isCurrent: function isCurrent(url) {
- return internal(this).patterns.some(p => p.test(url));
- },
-
- serialize: function() {
- return {
- id: internal(this).id,
- type: "URLContext",
- args: []
- }
- }
-});
-exports.URLContext = URLContext;
-
-// Matches when the user-supplied predicate returns true
-var PredicateContext = Class({
- extends: Context,
-
- initialize: function initialize(predicate) {
- Context.prototype.initialize.call(this);
- let options = validateOptions({ predicate: predicate }, {
- predicate: {
- is: ["function"],
- msg: "predicate must be a function."
- }
- });
- internal(this).predicate = options.predicate;
- },
-
- isCurrent: function isCurrent(state) {
- return internal(this).predicate(state);
- },
-
- serialize: function() {
- return {
- id: internal(this).id,
- type: "PredicateContext",
- args: []
- }
- }
-});
-exports.PredicateContext = PredicateContext;
-
-function removeItemFromArray(array, item) {
- return array.filter(i => i !== item);
-}
-
-// Converts anything that isn't false, null or undefined into a string
-function stringOrNull(val) {
- return val ? String(val) : val;
-}
-
-// Shared option validation rules for Item, Menu, and Separator
-var baseItemRules = {
- parentMenu: {
- is: ["object", "undefined"],
- ok: function (v) {
- if (!v)
- return true;
- return (v instanceof ItemContainer) || (v instanceof Menu);
- },
- msg: "parentMenu must be a Menu or not specified."
- },
- context: {
- is: ["undefined", "object", "array"],
- ok: function (v) {
- if (!v)
- return true;
- let arr = Array.isArray(v) ? v : [v];
- return arr.every(o => o instanceof Context);
- },
- msg: "The 'context' option must be a Context object or an array of " +
- "Context objects."
- },
- onMessage: {
- is: ["function", "undefined"]
- },
- contentScript: loaderContract.rules.contentScript,
- contentScriptFile: loaderContract.rules.contentScriptFile
-};
-
-var labelledItemRules = mix(baseItemRules, {
- label: {
- map: stringOrNull,
- is: ["string"],
- ok: v => !!v,
- msg: "The item must have a non-empty string label."
- },
- accesskey: {
- map: stringOrNull,
- is: ["string", "undefined", "null"],
- ok: (v) => {
- if (!v) {
- return true;
- }
- return typeof v == "string" && v.length === 1;
- },
- msg: "The item must have a single character accesskey, or no accesskey."
- },
- image: {
- map: stringOrNull,
- is: ["string", "undefined", "null"],
- ok: function (url) {
- if (!url)
- return true;
- return isValidURI(url);
- },
- msg: "Image URL validation failed"
- }
-});
-
-// Additional validation rules for Item
-var itemRules = mix(labelledItemRules, {
- data: {
- map: stringOrNull,
- is: ["string", "undefined", "null"]
- }
-});
-
-// Additional validation rules for Menu
-var menuRules = mix(labelledItemRules, {
- items: {
- is: ["array", "undefined"],
- ok: function (v) {
- if (!v)
- return true;
- return v.every(function (item) {
- return item instanceof BaseItem;
- });
- },
- msg: "items must be an array, and each element in the array must be an " +
- "Item, Menu, or Separator."
- }
-});
-
-// Returns true if any contexts match. If there are no contexts then a
-// PageContext is tested instead
-function hasMatchingContext(contexts, addonInfo) {
- for (let context of contexts) {
- if (!(internal(context).id in addonInfo.contextStates)) {
- console.error("Missing state for context " + internal(context).id + " this is an error in the SDK modules.");
- return false;
- }
- if (!context.isCurrent(addonInfo.contextStates[internal(context).id]))
- return false;
- }
-
- return true;
-}
-
-// Tests whether an item should be visible or not based on its contexts and
-// content scripts
-function isItemVisible(item, addonInfo, usePageWorker) {
- if (!item.context.length) {
- if (!addonInfo.hasWorker)
- return usePageWorker ? addonInfo.pageContext : true;
- }
-
- if (!hasMatchingContext(item.context, addonInfo))
- return false;
-
- let context = addonInfo.workerContext;
- if (typeof(context) === "string" && context != "")
- item.label = context;
-
- return !!context;
-}
-
-// Called when an item is clicked to send out click events to the content
-// scripts
-function itemActivated(item, clickedNode) {
- let items = [internal(item).id];
- let data = item.data;
-
- while (item.parentMenu) {
- item = item.parentMenu;
- items.push(internal(item).id);
- }
-
- let process = processes.getById(lastContextProcessId);
- if (process)
- process.port.emit('sdk/contextmenu/activateitems', items, data);
-}
-
-function serializeItem(item) {
- return {
- id: internal(item).id,
- contexts: item.context.map(c => c.serialize()),
- contentScript: item.contentScript,
- contentScriptFile: item.contentScriptFile,
- };
-}
-
-// All things that appear in the context menu extend this
-var BaseItem = Class({
- initialize: function initialize() {
- internal(this).id = uuid();
-
- internal(this).contexts = [];
- if ("context" in internal(this).options && internal(this).options.context) {
- let contexts = internal(this).options.context;
- if (Array.isArray(contexts)) {
- for (let context of contexts)
- internal(this).contexts.push(context);
- }
- else {
- internal(this).contexts.push(contexts);
- }
- }
-
- let parentMenu = internal(this).options.parentMenu;
- if (!parentMenu)
- parentMenu = contentContextMenu;
-
- parentMenu.addItem(this);
-
- Object.defineProperty(this, "contentScript", {
- enumerable: true,
- value: internal(this).options.contentScript
- });
-
- // Resolve URIs here as tests may have overriden self
- let files = internal(this).options.contentScriptFile;
- if (files) {
- if (!Array.isArray(files))
- files = [files];
- files = files.map(self.data.url);
- }
- internal(this).options.contentScriptFile = files;
- Object.defineProperty(this, "contentScriptFile", {
- enumerable: true,
- value: internal(this).options.contentScriptFile
- });
-
- // Notify all frames of this new item
- sendItems([serializeItem(this)]);
- },
-
- destroy: function destroy() {
- if (internal(this).destroyed)
- return;
-
- // Tell all existing frames that this item has been destroyed
- processes.port.emit("sdk/contextmenu/destroyitems", [internal(this).id]);
-
- if (this.parentMenu)
- this.parentMenu.removeItem(this);
-
- internal(this).destroyed = true;
- },
-
- get context() {
- let contexts = internal(this).contexts.slice(0);
- contexts.add = (context) => {
- internal(this).contexts.push(context);
- // Notify all frames that this item has changed
- sendItems([serializeItem(this)]);
- };
- contexts.remove = (context) => {
- internal(this).contexts = internal(this).contexts.filter(c => {
- return c != context;
- });
- // Notify all frames that this item has changed
- sendItems([serializeItem(this)]);
- };
- return contexts;
- },
-
- set context(val) {
- internal(this).contexts = val.slice(0);
- // Notify all frames that this item has changed
- sendItems([serializeItem(this)]);
- },
-
- get parentMenu() {
- return internal(this).parentMenu;
- },
-});
-
-function workerMessageReceived(process, id, args) {
- if (internal(this).id != id)
- return;
-
- emit(this, ...JSON.parse(args));
-}
-
-// All things that have a label on the context menu extend this
-var LabelledItem = Class({
- extends: BaseItem,
- implements: [ EventTarget ],
-
- initialize: function initialize(options) {
- BaseItem.prototype.initialize.call(this);
- EventTarget.prototype.initialize.call(this, options);
-
- internal(this).messageListener = workerMessageReceived.bind(this);
- processes.port.on('sdk/worker/event', internal(this).messageListener);
- },
-
- destroy: function destroy() {
- if (internal(this).destroyed)
- return;
-
- processes.port.off('sdk/worker/event', internal(this).messageListener);
-
- BaseItem.prototype.destroy.call(this);
- },
-
- get label() {
- return internal(this).options.label;
- },
-
- set label(val) {
- internal(this).options.label = val;
-
- MenuManager.updateItem(this);
- },
-
- get accesskey() {
- return internal(this).options.accesskey;
- },
-
- set accesskey(val) {
- internal(this).options.accesskey = val;
-
- MenuManager.updateItem(this);
- },
-
- get image() {
- return internal(this).options.image;
- },
-
- set image(val) {
- internal(this).options.image = val;
-
- MenuManager.updateItem(this);
- },
-
- get data() {
- return internal(this).options.data;
- },
-
- set data(val) {
- internal(this).options.data = val;
- }
-});
-
-var Item = Class({
- extends: LabelledItem,
-
- initialize: function initialize(options) {
- internal(this).options = validateOptions(options, itemRules);
-
- LabelledItem.prototype.initialize.call(this, options);
- },
-
- toString: function toString() {
- return "[object Item \"" + this.label + "\"]";
- },
-
- get data() {
- return internal(this).options.data;
- },
-
- set data(val) {
- internal(this).options.data = val;
-
- MenuManager.updateItem(this);
- },
-});
-exports.Item = Item;
-
-var ItemContainer = Class({
- initialize: function initialize() {
- internal(this).children = [];
- },
-
- destroy: function destroy() {
- // Destroys the entire hierarchy
- for (let item of internal(this).children)
- item.destroy();
- },
-
- addItem: function addItem(item) {
- let oldParent = item.parentMenu;
-
- // Don't just call removeItem here as that would remove the corresponding
- // UI element which is more costly than just moving it to the right place
- if (oldParent)
- internal(oldParent).children = removeItemFromArray(internal(oldParent).children, item);
-
- let after = null;
- let children = internal(this).children;
- if (children.length > 0)
- after = children[children.length - 1];
-
- children.push(item);
- internal(item).parentMenu = this;
-
- // If there was an old parent then we just have to move the item, otherwise
- // it needs to be created
- if (oldParent)
- MenuManager.moveItem(item, after);
- else
- MenuManager.createItem(item, after);
- },
-
- removeItem: function removeItem(item) {
- // If the item isn't a child of this menu then ignore this call
- if (item.parentMenu !== this)
- return;
-
- MenuManager.removeItem(item);
-
- internal(this).children = removeItemFromArray(internal(this).children, item);
- internal(item).parentMenu = null;
- },
-
- get items() {
- return internal(this).children.slice(0);
- },
-
- set items(val) {
- // Validate the arguments before making any changes
- if (!Array.isArray(val))
- throw new Error(menuOptionRules.items.msg);
-
- for (let item of val) {
- if (!(item instanceof BaseItem))
- throw new Error(menuOptionRules.items.msg);
- }
-
- // Remove the old items and add the new ones
- for (let item of internal(this).children)
- this.removeItem(item);
-
- for (let item of val)
- this.addItem(item);
- },
-});
-
-var Menu = Class({
- extends: LabelledItem,
- implements: [ItemContainer],
-
- initialize: function initialize(options) {
- internal(this).options = validateOptions(options, menuRules);
-
- LabelledItem.prototype.initialize.call(this, options);
- ItemContainer.prototype.initialize.call(this);
-
- if (internal(this).options.items) {
- for (let item of internal(this).options.items)
- this.addItem(item);
- }
- },
-
- destroy: function destroy() {
- ItemContainer.prototype.destroy.call(this);
- LabelledItem.prototype.destroy.call(this);
- },
-
- toString: function toString() {
- return "[object Menu \"" + this.label + "\"]";
- },
-});
-exports.Menu = Menu;
-
-var Separator = Class({
- extends: BaseItem,
-
- initialize: function initialize(options) {
- internal(this).options = validateOptions(options, baseItemRules);
-
- BaseItem.prototype.initialize.call(this);
- },
-
- toString: function toString() {
- return "[object Separator]";
- }
-});
-exports.Separator = Separator;
-
-// Holds items for the content area context menu
-var contentContextMenu = ItemContainer();
-exports.contentContextMenu = contentContextMenu;
-
-function getContainerItems(container) {
- let items = [];
- for (let item of internal(container).children) {
- items.push(serializeItem(item));
- if (item instanceof Menu)
- items = items.concat(getContainerItems(item));
- }
- return items;
-}
-
-// Notify all frames of these new or changed items
-function sendItems(items) {
- processes.port.emit("sdk/contextmenu/createitems", items);
-}
-
-// Called when a new process is created and needs to get the current list of items
-function remoteItemRequest(process) {
- let items = getContainerItems(contentContextMenu);
- if (items.length == 0)
- return;
-
- process.port.emit("sdk/contextmenu/createitems", items);
-}
-processes.forEvery(remoteItemRequest);
-
-when(function() {
- contentContextMenu.destroy();
-});
-
-// App specific UI code lives here, it should handle populating the context
-// menu and passing clicks etc. through to the items.
-
-function countVisibleItems(nodes) {
- return Array.reduce(nodes, function(sum, node) {
- return node.hidden ? sum : sum + 1;
- }, 0);
-}
-
-var MenuWrapper = Class({
- initialize: function initialize(winWrapper, items, contextMenu) {
- this.winWrapper = winWrapper;
- this.window = winWrapper.window;
- this.items = items;
- this.contextMenu = contextMenu;
- this.populated = false;
- this.menuMap = new Map();
-
- // updateItemVisibilities will run first, updateOverflowState will run after
- // all other instances of this module have run updateItemVisibilities
- this._updateItemVisibilities = this.updateItemVisibilities.bind(this);
- this.contextMenu.addEventListener("popupshowing", this._updateItemVisibilities, true);
- this._updateOverflowState = this.updateOverflowState.bind(this);
- this.contextMenu.addEventListener("popupshowing", this._updateOverflowState, false);
- },
-
- destroy: function destroy() {
- this.contextMenu.removeEventListener("popupshowing", this._updateOverflowState, false);
- this.contextMenu.removeEventListener("popupshowing", this._updateItemVisibilities, true);
-
- if (!this.populated)
- return;
-
- // If we're getting unloaded at runtime then we must remove all the
- // generated XUL nodes
- let oldParent = null;
- for (let item of internal(this.items).children) {
- let xulNode = this.getXULNodeForItem(item);
- oldParent = xulNode.parentNode;
- oldParent.removeChild(xulNode);
- }
-
- if (oldParent)
- this.onXULRemoved(oldParent);
- },
-
- get separator() {
- return this.contextMenu.querySelector("." + SEPARATOR_CLASS);
- },
-
- get overflowMenu() {
- return this.contextMenu.querySelector("." + OVERFLOW_MENU_CLASS);
- },
-
- get overflowPopup() {
- return this.contextMenu.querySelector("." + OVERFLOW_POPUP_CLASS);
- },
-
- get topLevelItems() {
- return this.contextMenu.querySelectorAll("." + TOPLEVEL_ITEM_CLASS);
- },
-
- get overflowItems() {
- return this.contextMenu.querySelectorAll("." + OVERFLOW_ITEM_CLASS);
- },
-
- getXULNodeForItem: function getXULNodeForItem(item) {
- return this.menuMap.get(item);
- },
-
- // Recurses through the item hierarchy creating XUL nodes for everything
- populate: function populate(menu) {
- for (let i = 0; i < internal(menu).children.length; i++) {
- let item = internal(menu).children[i];
- let after = i === 0 ? null : internal(menu).children[i - 1];
- this.createItem(item, after);
-
- if (item instanceof Menu)
- this.populate(item);
- }
- },
-
- // Recurses through the menu setting the visibility of items. Returns true
- // if any of the items in this menu were visible
- setVisibility: function setVisibility(menu, addonInfo, usePageWorker) {
- let anyVisible = false;
-
- for (let item of internal(menu).children) {
- let visible = isItemVisible(item, addonInfo[internal(item).id], usePageWorker);
-
- // Recurse through Menus, if none of the sub-items were visible then the
- // menu is hidden too.
- if (visible && (item instanceof Menu))
- visible = this.setVisibility(item, addonInfo, false);
-
- let xulNode = this.getXULNodeForItem(item);
- xulNode.hidden = !visible;
-
- anyVisible = anyVisible || visible;
- }
-
- return anyVisible;
- },
-
- // Works out where to insert a XUL node for an item in a browser window
- insertIntoXUL: function insertIntoXUL(item, node, after) {
- let menupopup = null;
- let before = null;
-
- let menu = item.parentMenu;
- if (menu === this.items) {
- // Insert into the overflow popup if it exists, otherwise the normal
- // context menu
- menupopup = this.overflowPopup;
- if (!menupopup)
- menupopup = this.contextMenu;
- }
- else {
- let xulNode = this.getXULNodeForItem(menu);
- menupopup = xulNode.firstChild;
- }
-
- if (after) {
- let afterNode = this.getXULNodeForItem(after);
- before = afterNode.nextSibling;
- }
- else if (menupopup === this.contextMenu) {
- let topLevel = this.topLevelItems;
- if (topLevel.length > 0)
- before = topLevel[topLevel.length - 1].nextSibling;
- else
- before = this.separator.nextSibling;
- }
-
- menupopup.insertBefore(node, before);
- },
-
- // Sets the right class for XUL nodes
- updateXULClass: function updateXULClass(xulNode) {
- if (xulNode.parentNode == this.contextMenu)
- xulNode.classList.add(TOPLEVEL_ITEM_CLASS);
- else
- xulNode.classList.remove(TOPLEVEL_ITEM_CLASS);
-
- if (xulNode.parentNode == this.overflowPopup)
- xulNode.classList.add(OVERFLOW_ITEM_CLASS);
- else
- xulNode.classList.remove(OVERFLOW_ITEM_CLASS);
- },
-
- // Creates a XUL node for an item
- createItem: function createItem(item, after) {
- if (!this.populated)
- return;
-
- // Create the separator if it doesn't already exist
- if (!this.separator) {
- let separator = this.window.document.createElement("menuseparator");
- separator.setAttribute("class", SEPARATOR_CLASS);
-
- // Insert before the separator created by the old context-menu if it
- // exists to avoid bug 832401
- let oldSeparator = this.window.document.getElementById("jetpack-context-menu-separator");
- if (oldSeparator && oldSeparator.parentNode != this.contextMenu)
- oldSeparator = null;
- this.contextMenu.insertBefore(separator, oldSeparator);
- }
-
- let type = "menuitem";
- if (item instanceof Menu)
- type = "menu";
- else if (item instanceof Separator)
- type = "menuseparator";
-
- let xulNode = this.window.document.createElement(type);
- xulNode.setAttribute("class", ITEM_CLASS);
- if (item instanceof LabelledItem) {
- xulNode.setAttribute("label", item.label);
- if (item.accesskey)
- xulNode.setAttribute("accesskey", item.accesskey);
- if (item.image) {
- xulNode.setAttribute("image", item.image);
- if (item instanceof Menu)
- xulNode.classList.add("menu-iconic");
- else
- xulNode.classList.add("menuitem-iconic");
- }
- if (item.data)
- xulNode.setAttribute("value", item.data);
-
- let self = this;
- xulNode.addEventListener("command", function(event) {
- // Only care about clicks directly on this item
- if (event.target !== xulNode)
- return;
-
- itemActivated(item, xulNode);
- }, false);
- }
-
- this.insertIntoXUL(item, xulNode, after);
- this.updateXULClass(xulNode);
- xulNode.data = item.data;
-
- if (item instanceof Menu) {
- let menupopup = this.window.document.createElement("menupopup");
- xulNode.appendChild(menupopup);
- }
-
- this.menuMap.set(item, xulNode);
- },
-
- // Updates the XUL node for an item in this window
- updateItem: function updateItem(item) {
- if (!this.populated)
- return;
-
- let xulNode = this.getXULNodeForItem(item);
-
- // TODO figure out why this requires setAttribute
- xulNode.setAttribute("label", item.label);
- xulNode.setAttribute("accesskey", item.accesskey || "");
-
- if (item.image) {
- xulNode.setAttribute("image", item.image);
- if (item instanceof Menu)
- xulNode.classList.add("menu-iconic");
- else
- xulNode.classList.add("menuitem-iconic");
- }
- else {
- xulNode.removeAttribute("image");
- xulNode.classList.remove("menu-iconic");
- xulNode.classList.remove("menuitem-iconic");
- }
-
- if (item.data)
- xulNode.setAttribute("value", item.data);
- else
- xulNode.removeAttribute("value");
- },
-
- // Moves the XUL node for an item in this window to its new place in the
- // hierarchy
- moveItem: function moveItem(item, after) {
- if (!this.populated)
- return;
-
- let xulNode = this.getXULNodeForItem(item);
- let oldParent = xulNode.parentNode;
-
- this.insertIntoXUL(item, xulNode, after);
- this.updateXULClass(xulNode);
- this.onXULRemoved(oldParent);
- },
-
- // Removes the XUL nodes for an item in every window we've ever populated.
- removeItem: function removeItem(item) {
- if (!this.populated)
- return;
-
- let xulItem = this.getXULNodeForItem(item);
-
- let oldParent = xulItem.parentNode;
-
- oldParent.removeChild(xulItem);
- this.menuMap.delete(item);
-
- this.onXULRemoved(oldParent);
- },
-
- // Called when any XUL nodes have been removed from a menupopup. This handles
- // making sure the separator and overflow are correct
- onXULRemoved: function onXULRemoved(parent) {
- if (parent == this.contextMenu) {
- let toplevel = this.topLevelItems;
-
- // If there are no more items then remove the separator
- if (toplevel.length == 0) {
- let separator = this.separator;
- if (separator)
- separator.parentNode.removeChild(separator);
- }
- }
- else if (parent == this.overflowPopup) {
- // If there are no more items then remove the overflow menu and separator
- if (parent.childNodes.length == 0) {
- let separator = this.separator;
- separator.parentNode.removeChild(separator);
- this.contextMenu.removeChild(parent.parentNode);
- }
- }
- },
-
- // Recurses through all the items owned by this module and sets their hidden
- // state
- updateItemVisibilities: function updateItemVisibilities(event) {
- try {
- if (event.type != "popupshowing")
- return;
- if (event.target != this.contextMenu)
- return;
-
- if (internal(this.items).children.length == 0)
- return;
-
- if (!this.populated) {
- this.populated = true;
- this.populate(this.items);
- }
-
- let mainWindow = event.target.ownerDocument.defaultView;
- this.contextMenuContentData = mainWindow.gContextMenuContentData
- if (!(self.id in this.contextMenuContentData.addonInfo)) {
- console.warn("No context menu state data was provided.");
- return;
- }
- let addonInfo = this.contextMenuContentData.addonInfo[self.id];
- lastContextProcessId = addonInfo.processID;
- this.setVisibility(this.items, addonInfo.items, true);
- }
- catch (e) {
- console.exception(e);
- }
- },
-
- // Counts the number of visible items across all modules and makes sure they
- // are in the right place between the top level context menu and the overflow
- // menu
- updateOverflowState: function updateOverflowState(event) {
- try {
- if (event.type != "popupshowing")
- return;
- if (event.target != this.contextMenu)
- return;
-
- // The main items will be in either the top level context menu or the
- // overflow menu at this point. Count the visible ones and if they are in
- // the wrong place move them
- let toplevel = this.topLevelItems;
- let overflow = this.overflowItems;
- let visibleCount = countVisibleItems(toplevel) +
- countVisibleItems(overflow);
-
- if (visibleCount == 0) {
- let separator = this.separator;
- if (separator)
- separator.hidden = true;
- let overflowMenu = this.overflowMenu;
- if (overflowMenu)
- overflowMenu.hidden = true;
- }
- else if (visibleCount > MenuManager.overflowThreshold) {
- this.separator.hidden = false;
- let overflowPopup = this.overflowPopup;
- if (overflowPopup)
- overflowPopup.parentNode.hidden = false;
-
- if (toplevel.length > 0) {
- // The overflow menu shouldn't exist here but let's play it safe
- if (!overflowPopup) {
- let overflowMenu = this.window.document.createElement("menu");
- overflowMenu.setAttribute("class", OVERFLOW_MENU_CLASS);
- overflowMenu.setAttribute("label", OVERFLOW_MENU_LABEL);
- overflowMenu.setAttribute("accesskey", OVERFLOW_MENU_ACCESSKEY);
- this.contextMenu.insertBefore(overflowMenu, this.separator.nextSibling);
-
- overflowPopup = this.window.document.createElement("menupopup");
- overflowPopup.setAttribute("class", OVERFLOW_POPUP_CLASS);
- overflowMenu.appendChild(overflowPopup);
- }
-
- for (let xulNode of toplevel) {
- overflowPopup.appendChild(xulNode);
- this.updateXULClass(xulNode);
- }
- }
- }
- else {
- this.separator.hidden = false;
-
- if (overflow.length > 0) {
- // Move all the overflow nodes out of the overflow menu and position
- // them immediately before it
- for (let xulNode of overflow) {
- this.contextMenu.insertBefore(xulNode, xulNode.parentNode.parentNode);
- this.updateXULClass(xulNode);
- }
- this.contextMenu.removeChild(this.overflowMenu);
- }
- }
- }
- catch (e) {
- console.exception(e);
- }
- }
-});
-
-// This wraps every window that we've seen
-var WindowWrapper = Class({
- initialize: function initialize(window) {
- this.window = window;
- this.menus = [
- new MenuWrapper(this, contentContextMenu, window.document.getElementById("contentAreaContextMenu")),
- ];
- },
-
- destroy: function destroy() {
- for (let menuWrapper of this.menus)
- menuWrapper.destroy();
- },
-
- getMenuWrapperForItem: function getMenuWrapperForItem(item) {
- let root = item.parentMenu;
- while (root.parentMenu)
- root = root.parentMenu;
-
- for (let wrapper of this.menus) {
- if (wrapper.items === root)
- return wrapper;
- }
-
- return null;
- }
-});
-
-var MenuManager = {
- windowMap: new Map(),
-
- get overflowThreshold() {
- let prefs = require("./preferences/service");
- return prefs.get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT);
- },
-
- // When a new window is added start watching it for context menu shows
- onTrack: function onTrack(window) {
- if (!isBrowser(window))
- return;
-
- // Generally shouldn't happen, but just in case
- if (this.windowMap.has(window)) {
- console.warn("Already seen this window");
- return;
- }
-
- let winWrapper = WindowWrapper(window);
- this.windowMap.set(window, winWrapper);
- },
-
- onUntrack: function onUntrack(window) {
- if (!isBrowser(window))
- return;
-
- let winWrapper = this.windowMap.get(window);
- // This shouldn't happen but protect against it anyway
- if (!winWrapper)
- return;
- winWrapper.destroy();
-
- this.windowMap.delete(window);
- },
-
- // Creates a XUL node for an item in every window we've already populated
- createItem: function createItem(item, after) {
- for (let [window, winWrapper] of this.windowMap) {
- let menuWrapper = winWrapper.getMenuWrapperForItem(item);
- if (menuWrapper)
- menuWrapper.createItem(item, after);
- }
- },
-
- // Updates the XUL node for an item in every window we've already populated
- updateItem: function updateItem(item) {
- for (let [window, winWrapper] of this.windowMap) {
- let menuWrapper = winWrapper.getMenuWrapperForItem(item);
- if (menuWrapper)
- menuWrapper.updateItem(item);
- }
- },
-
- // Moves the XUL node for an item in every window we've ever populated to its
- // new place in the hierarchy
- moveItem: function moveItem(item, after) {
- for (let [window, winWrapper] of this.windowMap) {
- let menuWrapper = winWrapper.getMenuWrapperForItem(item);
- if (menuWrapper)
- menuWrapper.moveItem(item, after);
- }
- },
-
- // Removes the XUL nodes for an item in every window we've ever populated.
- removeItem: function removeItem(item) {
- for (let [window, winWrapper] of this.windowMap) {
- let menuWrapper = winWrapper.getMenuWrapperForItem(item);
- if (menuWrapper)
- menuWrapper.removeItem(item);
- }
- }
-};
-
-WindowTracker(MenuManager);
diff --git a/addon-sdk/source/lib/sdk/context-menu/context.js b/addon-sdk/source/lib/sdk/context-menu/context.js
deleted file mode 100644
index fc5aea500..000000000
--- a/addon-sdk/source/lib/sdk/context-menu/context.js
+++ /dev/null
@@ -1,147 +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/. */
-
-const { Class } = require("../core/heritage");
-const { extend } = require("../util/object");
-const { MatchPattern } = require("../util/match-pattern");
-const readers = require("./readers");
-
-// Context class is required to implement a single `isCurrent(target)` method
-// that must return boolean value indicating weather given target matches a
-// context or not. Most context implementations below will have an associated
-// reader that way context implementation can setup a reader to extract necessary
-// information to make decision if target is matching a context.
-const Context = Class({
- isRequired: false,
- isCurrent(target) {
- throw Error("Context class must implement isCurrent(target) method");
- },
- get required() {
- Object.defineProperty(this, "required", {
- value: Object.assign(Object.create(Object.getPrototypeOf(this)),
- this,
- {isRequired: true})
- });
- return this.required;
- }
-});
-Context.required = function(...params) {
- return Object.assign(new this(...params), {isRequired: true});
-};
-exports.Context = Context;
-
-
-// Next few context implementations use an associated reader to extract info
-// from the context target and story it to a private symbol associtaed with
-// a context implementation. That way name collisions are avoided while required
-// information is still carried along.
-const isPage = Symbol("context/page?")
-const PageContext = Class({
- extends: Context,
- read: {[isPage]: new readers.isPage()},
- isCurrent: target => target[isPage]
-});
-exports.Page = PageContext;
-
-const isFrame = Symbol("context/frame?");
-const FrameContext = Class({
- extends: Context,
- read: {[isFrame]: new readers.isFrame()},
- isCurrent: target => target[isFrame]
-});
-exports.Frame = FrameContext;
-
-const selection = Symbol("context/selection")
-const SelectionContext = Class({
- read: {[selection]: new readers.Selection()},
- isCurrent: target => !!target[selection]
-});
-exports.Selection = SelectionContext;
-
-const link = Symbol("context/link");
-const LinkContext = Class({
- extends: Context,
- read: {[link]: new readers.LinkURL()},
- isCurrent: target => !!target[link]
-});
-exports.Link = LinkContext;
-
-const isEditable = Symbol("context/editable?")
-const EditableContext = Class({
- extends: Context,
- read: {[isEditable]: new readers.isEditable()},
- isCurrent: target => target[isEditable]
-});
-exports.Editable = EditableContext;
-
-
-const mediaType = Symbol("context/mediaType")
-
-const ImageContext = Class({
- extends: Context,
- read: {[mediaType]: new readers.MediaType()},
- isCurrent: target => target[mediaType] === "image"
-});
-exports.Image = ImageContext;
-
-
-const VideoContext = Class({
- extends: Context,
- read: {[mediaType]: new readers.MediaType()},
- isCurrent: target => target[mediaType] === "video"
-});
-exports.Video = VideoContext;
-
-
-const AudioContext = Class({
- extends: Context,
- read: {[mediaType]: new readers.MediaType()},
- isCurrent: target => target[mediaType] === "audio"
-});
-exports.Audio = AudioContext;
-
-const isSelectorMatch = Symbol("context/selector/mathches?")
-const SelectorContext = Class({
- extends: Context,
- initialize(selector) {
- this.selector = selector;
- // Each instance of selector context will need to store read
- // data into different field, so that case with multilpe selector
- // contexts won't cause a conflicts.
- this[isSelectorMatch] = Symbol(selector);
- this.read = {[this[isSelectorMatch]]: new readers.SelectorMatch(selector)};
- },
- isCurrent(target) {
- return target[this[isSelectorMatch]];
- }
-});
-exports.Selector = SelectorContext;
-
-const url = Symbol("context/url");
-const URLContext = Class({
- extends: Context,
- initialize(pattern) {
- this.pattern = new MatchPattern(pattern);
- },
- read: {[url]: new readers.PageURL()},
- isCurrent(target) {
- return this.pattern.test(target[url]);
- }
-});
-exports.URL = URLContext;
-
-var PredicateContext = Class({
- extends: Context,
- initialize(isMatch) {
- if (typeof(isMatch) !== "function") {
- throw TypeError("Predicate context mus be passed a function");
- }
-
- this.isMatch = isMatch
- },
- isCurrent(target) {
- return this.isMatch(target);
- }
-});
-exports.Predicate = PredicateContext;
diff --git a/addon-sdk/source/lib/sdk/context-menu/core.js b/addon-sdk/source/lib/sdk/context-menu/core.js
deleted file mode 100644
index c64cddfe8..000000000
--- a/addon-sdk/source/lib/sdk/context-menu/core.js
+++ /dev/null
@@ -1,384 +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 Contexts = require("./context");
-const Readers = require("./readers");
-const Component = require("../ui/component");
-const { Class } = require("../core/heritage");
-const { map, filter, object, reduce, keys, symbols,
- pairs, values, each, some, isEvery, count } = require("../util/sequence");
-const { loadModule } = require("framescript/manager");
-const { Cu, Cc, Ci } = require("chrome");
-const prefs = require("sdk/preferences/service");
-
-const globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
- .getService(Ci.nsIMessageListenerManager);
-const preferencesService = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefService).
- getBranch(null);
-
-
-const readTable = Symbol("context-menu/read-table");
-const nameTable = Symbol("context-menu/name-table");
-const onContext = Symbol("context-menu/on-context");
-const isMatching = Symbol("context-menu/matching-handler?");
-
-exports.onContext = onContext;
-exports.readTable = readTable;
-exports.nameTable = nameTable;
-
-
-const propagateOnContext = (item, data) =>
- each(child => child[onContext](data), item.state.children);
-
-const isContextMatch = item => !item[isMatching] || item[isMatching]();
-
-// For whatever reason addWeakMessageListener does not seems to work as our
-// instance seems to dropped even though it's alive. This is simple workaround
-// to avoid dead object excetptions.
-const WeakMessageListener = function(receiver, handler="receiveMessage") {
- this.receiver = receiver
- this.handler = handler
-};
-WeakMessageListener.prototype = {
- constructor: WeakMessageListener,
- receiveMessage(message) {
- if (Cu.isDeadWrapper(this.receiver)) {
- message.target.messageManager.removeMessageListener(message.name, this);
- }
- else {
- this.receiver[this.handler](message);
- }
- }
-};
-
-const OVERFLOW_THRESH = "extensions.addon-sdk.context-menu.overflowThreshold";
-const onMessage = Symbol("context-menu/message-listener");
-const onPreferceChange = Symbol("context-menu/preference-change");
-const ContextMenuExtension = Class({
- extends: Component,
- initialize: Component,
- setup() {
- const messageListener = new WeakMessageListener(this, onMessage);
- loadModule(globalMessageManager, "framescript/context-menu", true, "onContentFrame");
- globalMessageManager.addMessageListener("sdk/context-menu/read", messageListener);
- globalMessageManager.addMessageListener("sdk/context-menu/readers?", messageListener);
-
- preferencesService.addObserver(OVERFLOW_THRESH, this, false);
- },
- observe(_, __, name) {
- if (name === OVERFLOW_THRESH) {
- const overflowThreshold = prefs.get(OVERFLOW_THRESH, 10);
- this[Component.patch]({overflowThreshold});
- }
- },
- [onMessage]({name, data, target}) {
- if (name === "sdk/context-menu/read")
- this[onContext]({target, data});
- if (name === "sdk/context-menu/readers?")
- target.messageManager.sendAsyncMessage("sdk/context-menu/readers",
- JSON.parse(JSON.stringify(this.state.readers)));
- },
- [Component.initial](options={}, children) {
- const element = options.element || null;
- const target = options.target || null;
- const readers = Object.create(null);
- const users = Object.create(null);
- const registry = new WeakSet();
- const overflowThreshold = prefs.get(OVERFLOW_THRESH, 10);
-
- return { target, children: [], readers, users, element,
- registry, overflowThreshold };
- },
- [Component.isUpdated](before, after) {
- // Update only if target changed, since there is no point in re-rendering
- // when children are. Also new items added won't be in sync with a latest
- // context target so we should really just render before drawing context
- // menu.
- return before.target !== after.target;
- },
- [Component.render]({element, children, overflowThreshold}) {
- if (!element) return null;
-
- const items = children.filter(isContextMatch);
- const body = items.length === 0 ? items :
- items.length < overflowThreshold ? [new Separator(),
- ...items] :
- [{tagName: "menu",
- className: "sdk-context-menu-overflow-menu",
- label: "Add-ons",
- accesskey: "A",
- children: [{tagName: "menupopup",
- children: items}]}];
- return {
- element: element,
- tagName: "menugroup",
- style: "-moz-box-orient: vertical;",
- className: "sdk-context-menu-extension",
- children: body
- }
- },
- // Adds / remove child to it's own list.
- add(item) {
- this[Component.patch]({children: this.state.children.concat(item)});
- },
- remove(item) {
- this[Component.patch]({
- children: this.state.children.filter(x => x !== item)
- });
- },
- register(item) {
- const { users, registry } = this.state;
- if (registry.has(item)) return;
- registry.add(item);
-
- // Each (ContextHandler) item has a readTable that is a
- // map of keys to readers extracting them from the content.
- // During the registraction we update intrnal record of unique
- // readers and users per reader. Most context will have a reader
- // shared across all instances there for map of users per reader
- // is stored separately from the reader so that removing reader
- // will occur only when no users remain.
- const table = item[readTable];
- // Context readers store data in private symbols so we need to
- // collect both table keys and private symbols.
- const names = [...keys(table), ...symbols(table)];
- const readers = map(name => table[name], names);
- // Create delta for registered readers that will be merged into
- // internal readers table.
- const added = filter(x => !users[x.id], readers);
- const delta = object(...map(x => [x.id, x], added));
-
- const update = reduce((update, reader) => {
- const n = update[reader.id] || 0;
- update[reader.id] = n + 1;
- return update;
- }, Object.assign({}, users), readers);
-
- // Patch current state with a changes that registered item caused.
- this[Component.patch]({users: update,
- readers: Object.assign(this.state.readers, delta)});
-
- if (count(added)) {
- globalMessageManager.broadcastAsyncMessage("sdk/context-menu/readers",
- JSON.parse(JSON.stringify(delta)));
- }
- },
- unregister(item) {
- const { users, registry } = this.state;
- if (!registry.has(item)) return;
- registry.delete(item);
-
- const table = item[readTable];
- const names = [...keys(table), ...symbols(table)];
- const readers = map(name => table[name], names);
- const update = reduce((update, reader) => {
- update[reader.id] = update[reader.id] - 1;
- return update;
- }, Object.assign({}, users), readers);
- const removed = filter(id => !update[id], keys(update));
- const delta = object(...map(x => [x, null], removed));
-
- this[Component.patch]({users: update,
- readers: Object.assign(this.state.readers, delta)});
-
- if (count(removed)) {
- globalMessageManager.broadcastAsyncMessage("sdk/context-menu/readers",
- JSON.parse(JSON.stringify(delta)));
- }
- },
-
- [onContext]({data, target}) {
- propagateOnContext(this, data);
- const document = target.ownerDocument;
- const element = document.getElementById("contentAreaContextMenu");
-
- this[Component.patch]({target: data, element: element});
- }
-});this,
-exports.ContextMenuExtension = ContextMenuExtension;
-
-// Takes an item options and
-const makeReadTable = ({context, read}) => {
- // Result of this function is a tuple of all readers &
- // name, reader id pairs.
-
- // Filter down to contexts that have a reader associated.
- const contexts = filter(context => context.read, context);
- // Merge all contexts read maps to a single hash, note that there should be
- // no name collisions as context implementations expect to use private
- // symbols for storing it's read data.
- return Object.assign({}, ...map(({read}) => read, contexts), read);
-}
-
-const readTarget = (nameTable, data) =>
- object(...map(([name, id]) => [name, data[id]], nameTable))
-
-const ContextHandler = Class({
- extends: Component,
- initialize: Component,
- get context() {
- return this.state.options.context;
- },
- get read() {
- return this.state.options.read;
- },
- [Component.initial](options) {
- return {
- table: makeReadTable(options),
- requiredContext: filter(context => context.isRequired, options.context),
- optionalContext: filter(context => !context.isRequired, options.context)
- }
- },
- [isMatching]() {
- const {target, requiredContext, optionalContext} = this.state;
- return isEvery(context => context.isCurrent(target), requiredContext) &&
- (count(optionalContext) === 0 ||
- some(context => context.isCurrent(target), optionalContext));
- },
- setup() {
- const table = makeReadTable(this.state.options);
- this[readTable] = table;
- this[nameTable] = [...map(symbol => [symbol, table[symbol].id], symbols(table)),
- ...map(name => [name, table[name].id], keys(table))];
-
-
- contextMenu.register(this);
-
- each(child => contextMenu.remove(child), this.state.children);
- contextMenu.add(this);
- },
- dispose() {
- contextMenu.remove(this);
-
- each(child => contextMenu.unregister(child), this.state.children);
- contextMenu.unregister(this);
- },
- // Internal `Symbol("onContext")` method is invoked when "contextmenu" event
- // occurs in content process. Context handles with children delegate to each
- // child and patch it's internal state to reflect new contextmenu target.
- [onContext](data) {
- propagateOnContext(this, data);
- this[Component.patch]({target: readTarget(this[nameTable], data)});
- }
-});
-const isContextHandler = item => item instanceof ContextHandler;
-
-exports.ContextHandler = ContextHandler;
-
-const Menu = Class({
- extends: ContextHandler,
- [isMatching]() {
- return ContextHandler.prototype[isMatching].call(this) &&
- this.state.children.filter(isContextHandler)
- .some(isContextMatch);
- },
- [Component.render]({children, options}) {
- const items = children.filter(isContextMatch);
- return {tagName: "menu",
- className: "sdk-context-menu menu-iconic",
- label: options.label,
- accesskey: options.accesskey,
- image: options.icon,
- children: [{tagName: "menupopup",
- children: items}]};
- }
-});
-exports.Menu = Menu;
-
-const onCommand = Symbol("context-menu/item/onCommand");
-const Item = Class({
- extends: ContextHandler,
- get onClick() {
- return this.state.options.onClick;
- },
- [Component.render]({options}) {
- const {label, icon, accesskey} = options;
- return {tagName: "menuitem",
- className: "sdk-context-menu-item menuitem-iconic",
- label,
- accesskey,
- image: icon,
- oncommand: this};
- },
- handleEvent(event) {
- if (this.onClick)
- this.onClick(this.state.target);
- }
-});
-exports.Item = Item;
-
-var Separator = Class({
- extends: Component,
- initialize: Component,
- [Component.render]() {
- return {tagName: "menuseparator",
- className: "sdk-context-menu-separator"}
- },
- [onContext]() {
-
- }
-});
-exports.Separator = Separator;
-
-exports.Contexts = Contexts;
-exports.Readers = Readers;
-
-const createElement = (vnode, {document}) => {
- const node = vnode.namespace ?
- document.createElementNS(vnode.namespace, vnode.tagName) :
- document.createElement(vnode.tagName);
-
- node.setAttribute("data-component-path", vnode[Component.path]);
-
- each(([key, value]) => {
- if (key === "tagName") {
- return;
- }
- if (key === "children") {
- return;
- }
-
- if (key.startsWith("on")) {
- node.addEventListener(key.substr(2), value)
- return;
- }
-
- if (typeof(value) !== "object" &&
- typeof(value) !== "function" &&
- value !== void(0) &&
- value !== null)
- {
- if (key === "className") {
- node[key] = value;
- }
- else {
- node.setAttribute(key, value);
- }
- return;
- }
- }, pairs(vnode));
-
- each(child => node.appendChild(createElement(child, {document})), vnode.children);
- return node;
-};
-
-const htmlWriter = tree => {
- if (tree !== null) {
- const root = tree.element;
- const node = createElement(tree, {document: root.ownerDocument});
- const before = root.querySelector("[data-component-path='/']");
- if (before) {
- root.replaceChild(node, before);
- } else {
- root.appendChild(node);
- }
- }
-};
-
-
-const contextMenu = ContextMenuExtension();
-exports.contextMenu = contextMenu;
-Component.mount(contextMenu, htmlWriter);
diff --git a/addon-sdk/source/lib/sdk/context-menu/readers.js b/addon-sdk/source/lib/sdk/context-menu/readers.js
deleted file mode 100644
index 5078f8f29..000000000
--- a/addon-sdk/source/lib/sdk/context-menu/readers.js
+++ /dev/null
@@ -1,112 +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/. */
-const { Class } = require("../core/heritage");
-const { extend } = require("../util/object");
-const { memoize, method, identity } = require("../lang/functional");
-
-const serializeCategory = ({type}) => ({ category: `reader/${type}()` });
-
-const Reader = Class({
- initialize() {
- this.id = `reader/${this.type}()`
- },
- toJSON() {
- return serializeCategory(this);
- }
-});
-
-
-const MediaTypeReader = Class({ extends: Reader, type: "MediaType" });
-exports.MediaType = MediaTypeReader;
-
-const LinkURLReader = Class({ extends: Reader, type: "LinkURL" });
-exports.LinkURL = LinkURLReader;
-
-const SelectionReader = Class({ extends: Reader, type: "Selection" });
-exports.Selection = SelectionReader;
-
-const isPageReader = Class({ extends: Reader, type: "isPage" });
-exports.isPage = isPageReader;
-
-const isFrameReader = Class({ extends: Reader, type: "isFrame" });
-exports.isFrame = isFrameReader;
-
-const isEditable = Class({ extends: Reader, type: "isEditable"});
-exports.isEditable = isEditable;
-
-
-
-const ParameterizedReader = Class({
- extends: Reader,
- readParameter: function(value) {
- return value;
- },
- toJSON: function() {
- var json = serializeCategory(this);
- json[this.parameter] = this[this.parameter];
- return json;
- },
- initialize(...params) {
- if (params.length) {
- this[this.parameter] = this.readParameter(...params);
- }
- this.id = `reader/${this.type}(${JSON.stringify(this[this.parameter])})`;
- }
-});
-exports.ParameterizedReader = ParameterizedReader;
-
-
-const QueryReader = Class({
- extends: ParameterizedReader,
- type: "Query",
- parameter: "path"
-});
-exports.Query = QueryReader;
-
-
-const AttributeReader = Class({
- extends: ParameterizedReader,
- type: "Attribute",
- parameter: "name"
-});
-exports.Attribute = AttributeReader;
-
-const SrcURLReader = Class({
- extends: AttributeReader,
- name: "src",
-});
-exports.SrcURL = SrcURLReader;
-
-const PageURLReader = Class({
- extends: QueryReader,
- path: "ownerDocument.URL",
-});
-exports.PageURL = PageURLReader;
-
-const SelectorMatchReader = Class({
- extends: ParameterizedReader,
- type: "SelectorMatch",
- parameter: "selector"
-});
-exports.SelectorMatch = SelectorMatchReader;
-
-const extractors = new WeakMap();
-extractors.id = 0;
-
-
-var Extractor = Class({
- extends: ParameterizedReader,
- type: "Extractor",
- parameter: "source",
- initialize: function(f) {
- this[this.parameter] = String(f);
- if (!extractors.has(f)) {
- extractors.id = extractors.id + 1;
- extractors.set(f, extractors.id);
- }
-
- this.id = `reader/${this.type}.for(${extractors.get(f)})`
- }
-});
-exports.Extractor = Extractor;
diff --git a/addon-sdk/source/lib/sdk/context-menu@2.js b/addon-sdk/source/lib/sdk/context-menu@2.js
deleted file mode 100644
index 45ad804e9..000000000
--- a/addon-sdk/source/lib/sdk/context-menu@2.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";
-
-const shared = require("toolkit/require");
-const { Item, Separator, Menu, Contexts, Readers } = shared.require("sdk/context-menu/core");
-const { setupDisposable, disposeDisposable, Disposable } = require("sdk/core/disposable")
-const { Class } = require("sdk/core/heritage")
-
-const makeDisposable = Type => Class({
- extends: Type,
- implements: [Disposable],
- initialize: Type.prototype.initialize,
- setup(...params) {
- Type.prototype.setup.call(this, ...params);
- setupDisposable(this);
- },
- dispose(...params) {
- disposeDisposable(this);
- Type.prototype.dispose.call(this, ...params);
- }
-});
-
-exports.Separator = Separator;
-exports.Contexts = Contexts;
-exports.Readers = Readers;
-
-// Subclass Item & Menu shared classes so their items
-// will be unloaded when add-on is unloaded.
-exports.Item = makeDisposable(Item);
-exports.Menu = makeDisposable(Menu);
diff --git a/addon-sdk/source/lib/sdk/core/disposable.js b/addon-sdk/source/lib/sdk/core/disposable.js
deleted file mode 100644
index 19f7eaa9f..000000000
--- a/addon-sdk/source/lib/sdk/core/disposable.js
+++ /dev/null
@@ -1,186 +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 { Class } = require("./heritage");
-const { Observer, subscribe, unsubscribe, observe } = require("./observer");
-const { isWeak } = require("./reference");
-const SDKWeakSet = require("../lang/weak-set");
-
-const method = require("../../method/core");
-
-const unloadSubject = require('@loader/unload');
-const addonUnloadTopic = "sdk:loader:destroy";
-
-const uninstall = method("disposable/uninstall");
-exports.uninstall = uninstall;
-
-const shutdown = method("disposable/shutdown");
-exports.shutdown = shutdown;
-
-const disable = method("disposable/disable");
-exports.disable = disable;
-
-const upgrade = method("disposable/upgrade");
-exports.upgrade = upgrade;
-
-const downgrade = method("disposable/downgrade");
-exports.downgrade = downgrade;
-
-const unload = method("disposable/unload");
-exports.unload = unload;
-
-const dispose = method("disposable/dispose");
-exports.dispose = dispose;
-dispose.define(Object, object => object.dispose());
-
-const setup = method("disposable/setup");
-exports.setup = setup;
-setup.define(Object, (object, ...args) => object.setup(...args));
-
-// DisposablesUnloadObserver is the class which subscribe the
-// Observer Service to be notified when the add-on loader is
-// unloading to be able to dispose all the existent disposables.
-const DisposablesUnloadObserver = Class({
- implements: [Observer],
- initialize: function(...args) {
- // Set of the non-weak disposables registered to be disposed.
- this.disposables = new Set();
- // Target of the weak disposables registered to be disposed
- // (and tracked on this target using the SDK weak-set module).
- this.weakDisposables = {};
- },
- subscribe(disposable) {
- if (isWeak(disposable)) {
- SDKWeakSet.add(this.weakDisposables, disposable);
- } else {
- this.disposables.add(disposable);
- }
- },
- unsubscribe(disposable) {
- if (isWeak(disposable)) {
- SDKWeakSet.remove(this.weakDisposables, disposable);
- } else {
- this.disposables.delete(disposable);
- }
- },
- tryUnloadDisposable(disposable) {
- try {
- if (disposable) {
- unload(disposable);
- }
- } catch(e) {
- console.error("Error unloading a",
- isWeak(disposable) ? "weak disposable" : "disposable",
- disposable, e);
- }
- },
- unloadAll() {
- // Remove all the subscribed disposables.
- for (let disposable of this.disposables) {
- this.tryUnloadDisposable(disposable);
- }
-
- this.disposables.clear();
-
- // Remove all the subscribed weak disposables.
- for (let disposable of SDKWeakSet.iterator(this.weakDisposables)) {
- this.tryUnloadDisposable(disposable);
- }
-
- SDKWeakSet.clear(this.weakDisposables);
- }
-});
-const disposablesUnloadObserver = new DisposablesUnloadObserver();
-
-// The DisposablesUnloadObserver instance is the only object which subscribes
-// the Observer Service directly, it observes add-on unload notifications in
-// order to trigger `unload` on all its subscribed disposables.
-observe.define(DisposablesUnloadObserver, (obj, subject, topic, data) => {
- const isUnloadTopic = topic === addonUnloadTopic;
- const isUnloadSubject = subject.wrappedJSObject === unloadSubject;
- if (isUnloadTopic && isUnloadSubject) {
- unsubscribe(disposablesUnloadObserver, addonUnloadTopic);
- disposablesUnloadObserver.unloadAll();
- }
-});
-
-subscribe(disposablesUnloadObserver, addonUnloadTopic, false);
-
-// Set's up disposable instance.
-const setupDisposable = disposable => {
- disposablesUnloadObserver.subscribe(disposable);
-};
-exports.setupDisposable = setupDisposable;
-
-// Tears down disposable instance.
-const disposeDisposable = disposable => {
- disposablesUnloadObserver.unsubscribe(disposable);
-};
-exports.disposeDisposable = disposeDisposable;
-
-// Base type that takes care of disposing it's instances on add-on unload.
-// Also makes sure to remove unload listener if it's already being disposed.
-const Disposable = Class({
- initialize: function(...args) {
- // First setup instance before initializing it's disposal. If instance
- // fails to initialize then there is no instance to be disposed at the
- // unload.
- setup(this, ...args);
- setupDisposable(this);
- },
- destroy: function(reason) {
- // Destroying disposable removes unload handler so that attempt to dispose
- // won't be made at unload & delegates to dispose.
- disposeDisposable(this);
- unload(this, reason);
- },
- setup: function() {
- // Implement your initialize logic here.
- },
- dispose: function() {
- // Implement your cleanup logic here.
- }
-});
-exports.Disposable = Disposable;
-
-const unloaders = {
- destroy: dispose,
- uninstall: uninstall,
- shutdown: shutdown,
- disable: disable,
- upgrade: upgrade,
- downgrade: downgrade
-};
-
-const unloaded = new WeakMap();
-unload.define(Disposable, (disposable, reason) => {
- if (!unloaded.get(disposable)) {
- unloaded.set(disposable, true);
- // Pick an unload handler associated with an unload
- // reason (falling back to destroy if not found) and
- // delegate unloading to it.
- const unload = unloaders[reason] || unloaders.destroy;
- unload(disposable);
- }
-});
-
-// If add-on is disabled manually, it's being upgraded, downgraded
-// or uninstalled `dispose` is invoked to undo any changes that
-// has being done by it in this session.
-disable.define(Disposable, dispose);
-downgrade.define(Disposable, dispose);
-upgrade.define(Disposable, dispose);
-uninstall.define(Disposable, dispose);
-
-// If application is shut down no dispose is invoked as undo-ing
-// changes made by instance is likely to just waste of resources &
-// increase shutdown time. Although specefic components may choose
-// to implement shutdown handler that does something better.
-shutdown.define(Disposable, disposable => {});
diff --git a/addon-sdk/source/lib/sdk/core/heritage.js b/addon-sdk/source/lib/sdk/core/heritage.js
deleted file mode 100644
index fc87ba1f5..000000000
--- a/addon-sdk/source/lib/sdk/core/heritage.js
+++ /dev/null
@@ -1,184 +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"
-};
-
-var getPrototypeOf = Object.getPrototypeOf;
-var getNames = x => [...Object.getOwnPropertyNames(x),
- ...Object.getOwnPropertySymbols(x)];
-var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
-var create = Object.create;
-var freeze = Object.freeze;
-var unbind = Function.call.bind(Function.bind, Function.call);
-
-// This shortcut makes sure that we do perform desired operations, even if
-// associated methods have being overridden on the used object.
-var owns = unbind(Object.prototype.hasOwnProperty);
-var apply = unbind(Function.prototype.apply);
-var slice = Array.slice || unbind(Array.prototype.slice);
-var reduce = Array.reduce || unbind(Array.prototype.reduce);
-var map = Array.map || unbind(Array.prototype.map);
-var concat = Array.concat || unbind(Array.prototype.concat);
-
-// Utility function to get own properties descriptor map.
-function getOwnPropertyDescriptors(object) {
- return reduce(getNames(object), function(descriptor, name) {
- descriptor[name] = getOwnPropertyDescriptor(object, name);
- return descriptor;
- }, {});
-}
-
-function isDataProperty(property) {
- var value = property.value;
- var type = typeof(property.value);
- return "value" in property &&
- (type !== "object" || value === null) &&
- type !== "function";
-}
-
-function getDataProperties(object) {
- var properties = getOwnPropertyDescriptors(object);
- return getNames(properties).reduce(function(result, name) {
- var property = properties[name];
- if (isDataProperty(property)) {
- result[name] = {
- value: property.value,
- writable: true,
- configurable: true,
- enumerable: false
- };
- }
- return result;
- }, {})
-}
-
-/**
- * Takes `source` object as an argument and returns identical object
- * with the difference that all own properties will be non-enumerable
- */
-function obscure(source) {
- var descriptor = reduce(getNames(source), function(descriptor, name) {
- var property = getOwnPropertyDescriptor(source, name);
- property.enumerable = false;
- descriptor[name] = property;
- return descriptor;
- }, {});
- return create(getPrototypeOf(source), descriptor);
-}
-exports.obscure = obscure;
-
-/**
- * Takes arbitrary number of source objects and returns fresh one, that
- * inherits from the same prototype as a first argument and implements all
- * own properties of all argument objects. If two or more argument objects
- * have own properties with the same name, the property is overridden, with
- * precedence from right to left, implying, that properties of the object on
- * the left are overridden by a same named property of the object on the right.
- */
-var mix = function(source) {
- var descriptor = reduce(slice(arguments), function(descriptor, source) {
- return reduce(getNames(source), function(descriptor, name) {
- descriptor[name] = getOwnPropertyDescriptor(source, name);
- return descriptor;
- }, descriptor);
- }, {});
-
- return create(getPrototypeOf(source), descriptor);
-};
-exports.mix = mix;
-
-/**
- * Returns a frozen object with that inherits from the given `prototype` and
- * implements all own properties of the given `properties` object.
- */
-function extend(prototype, properties) {
- return create(prototype, getOwnPropertyDescriptors(properties));
-}
-exports.extend = extend;
-
-/**
- * Returns a constructor function with a proper `prototype` setup. Returned
- * constructor's `prototype` inherits from a given `options.extends` or
- * `Class.prototype` if omitted and implements all the properties of the
- * given `option`. If `options.implemens` array is passed, it's elements
- * will be mixed into prototype as well. Also, `options.extends` can be
- * a function or a prototype. If function than it's prototype is used as
- * an ancestor of the prototype, if it's an object that it's used directly.
- * Also `options.implements` may contain functions or objects, in case of
- * functions their prototypes are used for mixing.
- */
-var Class = new function() {
- function prototypeOf(input) {
- return typeof(input) === 'function' ? input.prototype : input;
- }
- var none = freeze([]);
-
- return function Class(options) {
- // Create descriptor with normalized `options.extends` and
- // `options.implements`.
- var descriptor = {
- // Normalize extends property of `options.extends` to a prototype object
- // in case it's constructor. If property is missing that fallback to
- // `Type.prototype`.
- extends: owns(options, 'extends') ?
- prototypeOf(options.extends) : Class.prototype,
- // Normalize `options.implements` to make sure that it's array of
- // prototype objects instead of constructor functions.
- implements: owns(options, 'implements') ?
- freeze(map(options.implements, prototypeOf)) : none
- };
-
- // Create array of property descriptors who's properties will be defined
- // on the resulting prototype. Note: Using reflection `concat` instead of
- // method as it may be overridden.
- var descriptors = concat(descriptor.implements, options, descriptor, {
- constructor: constructor
- });
-
- // Note: we use reflection `apply` in the constructor instead of method
- // call since later may be overridden.
- function constructor() {
- var instance = create(prototype, attributes);
- if (initialize) apply(initialize, instance, arguments);
- return instance;
- }
- // Create `prototype` that inherits from given ancestor passed as
- // `options.extends`, falling back to `Type.prototype`, implementing all
- // properties of given `options.implements` and `options` itself.
- var prototype = extend(descriptor.extends, mix.apply(mix, descriptors));
- var initialize = prototype.initialize;
-
- // Combine ancestor attributes with prototype's attributes so that
- // ancestors attributes also become initializeable.
- var attributes = mix(descriptor.extends.constructor.attributes || {},
- getDataProperties(prototype));
-
- constructor.attributes = attributes;
- Object.defineProperty(constructor, 'prototype', {
- configurable: false,
- writable: false,
- value: prototype
- });
- return constructor;
- };
-}
-Class.prototype = extend(null, obscure({
- constructor: function constructor() {
- this.initialize.apply(this, arguments);
- return this;
- },
- initialize: function initialize() {
- // Do your initialization logic here
- },
- // Copy useful properties from `Object.prototype`.
- toString: Object.prototype.toString,
- toLocaleString: Object.prototype.toLocaleString,
- toSource: Object.prototype.toSource,
- valueOf: Object.prototype.valueOf,
- isPrototypeOf: Object.prototype.isPrototypeOf
-}));
-exports.Class = freeze(Class);
diff --git a/addon-sdk/source/lib/sdk/core/namespace.js b/addon-sdk/source/lib/sdk/core/namespace.js
deleted file mode 100644
index 3ceb73b72..000000000
--- a/addon-sdk/source/lib/sdk/core/namespace.js
+++ /dev/null
@@ -1,43 +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 create = Object.create;
-const prototypeOf = Object.getPrototypeOf;
-
-/**
- * Returns a new namespace, function that may can be used to access an
- * namespaced object of the argument argument. Namespaced object are associated
- * with owner objects via weak references. Namespaced objects inherit from the
- * owners ancestor namespaced object. If owner's ancestor is `null` then
- * namespaced object inherits from given `prototype`. Namespaces can be used
- * to define internal APIs that can be shared via enclosing `namespace`
- * function.
- * @examples
- * const internals = ns();
- * internals(object).secret = secret;
- */
-function ns() {
- const map = new WeakMap();
- return function namespace(target) {
- if (!target) // If `target` is not an object return `target` itself.
- return target;
- // If target has no namespaced object yet, create one that inherits from
- // the target prototype's namespaced object.
- if (!map.has(target))
- map.set(target, create(namespace(prototypeOf(target) || null)));
-
- return map.get(target);
- };
-};
-
-// `Namespace` is a e4x function in the scope, so we export the function also as
-// `ns` as alias to avoid clashing.
-exports.ns = ns;
-exports.Namespace = ns;
diff --git a/addon-sdk/source/lib/sdk/core/observer.js b/addon-sdk/source/lib/sdk/core/observer.js
deleted file mode 100644
index 7e11bf8f9..000000000
--- a/addon-sdk/source/lib/sdk/core/observer.js
+++ /dev/null
@@ -1,89 +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, Cr, Cu } = require("chrome");
-const { Class } = require("./heritage");
-const { isWeak } = require("./reference");
-const method = require("../../method/core");
-
-const observerService = Cc['@mozilla.org/observer-service;1'].
- getService(Ci.nsIObserverService);
-
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const addObserver = ShimWaiver.getProperty(observerService, "addObserver");
-const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver");
-
-// This is a method that will be invoked when notification observer
-// subscribed to occurs.
-const observe = method("observer/observe");
-exports.observe = observe;
-
-// Method to subscribe to the observer notification.
-const subscribe = method("observe/subscribe");
-exports.subscribe = subscribe;
-
-
-// Method to unsubscribe from the observer notifications.
-const unsubscribe = method("observer/unsubscribe");
-exports.unsubscribe = unsubscribe;
-
-
-// This is wrapper class that takes a `delegate` and produces
-// instance of `nsIObserver` which will delegate to a given
-// object when observer notification occurs.
-const ObserverDelegee = Class({
- initialize: function(delegate) {
- this.delegate = delegate;
- },
- QueryInterface: function(iid) {
- if (!iid.equals(Ci.nsIObserver) &&
- !iid.equals(Ci.nsISupportsWeakReference) &&
- !iid.equals(Ci.nsISupports))
- throw Cr.NS_ERROR_NO_INTERFACE;
-
- return this;
- },
- observe: function(subject, topic, data) {
- observe(this.delegate, subject, topic, data);
- }
-});
-
-
-// Class that can be either mixed in or inherited from in
-// order to subscribe / unsubscribe for observer notifications.
-const Observer = Class({});
-exports.Observer = Observer;
-
-// Weak maps that associates instance of `ObserverDelegee` with
-// an actual observer. It ensures that `ObserverDelegee` instance
-// won't be GC-ed until given `observer` is.
-const subscribers = new WeakMap();
-
-// Implementation of `subscribe` for `Observer` type just registers
-// observer for an observer service. If `isWeak(observer)` is `true`
-// observer service won't hold strong reference to a given `observer`.
-subscribe.define(Observer, (observer, topic) => {
- if (!subscribers.has(observer)) {
- const delegee = new ObserverDelegee(observer);
- subscribers.set(observer, delegee);
- addObserver(delegee, topic, isWeak(observer));
- }
-});
-
-// Unsubscribes `observer` from observer notifications for the
-// given `topic`.
-unsubscribe.define(Observer, (observer, topic) => {
- const delegee = subscribers.get(observer);
- if (delegee) {
- subscribers.delete(observer);
- removeObserver(delegee, topic);
- }
-});
diff --git a/addon-sdk/source/lib/sdk/core/promise.js b/addon-sdk/source/lib/sdk/core/promise.js
deleted file mode 100644
index f4bd7b0f5..000000000
--- a/addon-sdk/source/lib/sdk/core/promise.js
+++ /dev/null
@@ -1,118 +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';
-
-/*
- * Uses `Promise.jsm` as a core implementation, with additional sugar
- * from previous implementation, with inspiration from `Q` and `when`
- *
- * https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm
- * https://github.com/cujojs/when
- * https://github.com/kriskowal/q
- */
-const PROMISE_URI = 'resource://gre/modules/Promise.jsm';
-
-getEnvironment.call(this, function ({ require, exports, module, Cu }) {
-
-const Promise = Cu.import(PROMISE_URI, {}).Promise;
-const { Debugging, defer, resolve, all, reject, race } = Promise;
-
-module.metadata = {
- 'stability': 'unstable'
-};
-
-var promised = (function() {
- // Note: Define shortcuts and utility functions here in order to avoid
- // slower property accesses and unnecessary closure creations on each
- // call of this popular function.
-
- var call = Function.call;
- var concat = Array.prototype.concat;
-
- // Utility function that does following:
- // execute([ f, self, args...]) => f.apply(self, args)
- function execute (args) {
- return call.apply(call, args);
- }
-
- // Utility function that takes promise of `a` array and maybe promise `b`
- // as arguments and returns promise for `a.concat(b)`.
- function promisedConcat(promises, unknown) {
- return promises.then(function (values) {
- return resolve(unknown)
- .then(value => values.concat([value]));
- });
- }
-
- return function promised(f, prototype) {
- /**
- Returns a wrapped `f`, which when called returns a promise that resolves to
- `f(...)` passing all the given arguments to it, which by the way may be
- promises. Optionally second `prototype` argument may be provided to be used
- a prototype for a returned promise.
-
- ## Example
-
- var promise = promised(Array)(1, promise(2), promise(3))
- promise.then(console.log) // => [ 1, 2, 3 ]
- **/
-
- return function promised(...args) {
- // create array of [ f, this, args... ]
- return [f, this, ...args].
- // reduce it via `promisedConcat` to get promised array of fulfillments
- reduce(promisedConcat, resolve([], prototype)).
- // finally map that to promise of `f.apply(this, args...)`
- then(execute);
- };
- };
-})();
-
-exports.promised = promised;
-exports.all = all;
-exports.defer = defer;
-exports.resolve = resolve;
-exports.reject = reject;
-exports.race = race;
-exports.Promise = Promise;
-exports.Debugging = Debugging;
-});
-
-function getEnvironment (callback) {
- let Cu, _exports, _module, _require;
-
- // CommonJS / SDK
- if (typeof(require) === 'function') {
- Cu = require('chrome').Cu;
- _exports = exports;
- _module = module;
- _require = require;
- }
- // JSM
- else if (String(this).indexOf('BackstagePass') >= 0) {
- Cu = this['Components'].utils;
- _exports = this.Promise = {};
- _module = { uri: __URI__, id: 'promise/core' };
- _require = uri => {
- let imports = {};
- Cu.import(uri, imports);
- return imports;
- };
- this.EXPORTED_SYMBOLS = ['Promise'];
- // mozIJSSubScriptLoader.loadSubscript
- } else if (~String(this).indexOf('Sandbox')) {
- Cu = this['Components'].utils;
- _exports = this;
- _module = { id: 'promise/core' };
- _require = uri => {};
- }
-
- callback({
- Cu: Cu,
- exports: _exports,
- module: _module,
- require: _require
- });
-}
-
diff --git a/addon-sdk/source/lib/sdk/core/reference.js b/addon-sdk/source/lib/sdk/core/reference.js
deleted file mode 100644
index 04549cd0f..000000000
--- a/addon-sdk/source/lib/sdk/core/reference.js
+++ /dev/null
@@ -1,29 +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 method = require("../../method/core");
-const { Class } = require("./heritage");
-
-// Object that inherit or mix WeakRefence inn will register
-// weak observes for system notifications.
-const WeakReference = Class({});
-exports.WeakReference = WeakReference;
-
-
-// If `isWeak(object)` is `true` observer installed
-// for such `object` will be weak, meaning that it will
-// be GC-ed if nothing else but observer is observing it.
-// By default everything except `WeakReference` will return
-// `false`.
-const isWeak = method("reference/weak?");
-exports.isWeak = isWeak;
-
-isWeak.define(Object, _ => false);
-isWeak.define(WeakReference, _ => true);
diff --git a/addon-sdk/source/lib/sdk/deprecated/api-utils.js b/addon-sdk/source/lib/sdk/deprecated/api-utils.js
deleted file mode 100644
index 856fc50cb..000000000
--- a/addon-sdk/source/lib/sdk/deprecated/api-utils.js
+++ /dev/null
@@ -1,197 +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 { merge } = require("../util/object");
-const { union } = require("../util/array");
-const { isNil, isRegExp } = require("../lang/type");
-
-// The possible return values of getTypeOf.
-const VALID_TYPES = [
- "array",
- "boolean",
- "function",
- "null",
- "number",
- "object",
- "string",
- "undefined",
- "regexp"
-];
-
-const { isArray } = Array;
-
-/**
- * Returns a validated options dictionary given some requirements. If any of
- * the requirements are not met, an exception is thrown.
- *
- * @param options
- * An object, the options dictionary to validate. It's not modified.
- * If it's null or otherwise falsey, an empty object is assumed.
- * @param requirements
- * An object whose keys are the expected keys in options. Any key in
- * options that is not present in requirements is ignored. Each value
- * in requirements is itself an object describing the requirements of
- * its key. There are four optional keys in this object:
- * map: A function that's passed the value of the key in options.
- * map's return value is taken as the key's value in the final
- * validated options, is, and ok. If map throws an exception
- * it's caught and discarded, and the key's value is its value in
- * options.
- * is: An array containing any number of the typeof type names. If
- * the key's value is none of these types, it fails validation.
- * Arrays, null and regexps are identified by the special type names
- * "array", "null", "regexp"; "object" will not match either. No type
- * coercion is done.
- * ok: A function that's passed the key's value. If it returns
- * false, the value fails validation.
- * msg: If the key's value fails validation, an exception is thrown.
- * This string will be used as its message. If undefined, a
- * generic message is used, unless is is defined, in which case
- * the message will state that the value needs to be one of the
- * given types.
- * @return An object whose keys are those keys in requirements that are also in
- * options and whose values are the corresponding return values of map
- * or the corresponding values in options. Note that any keys not
- * shared by both requirements and options are not in the returned
- * object.
- */
-exports.validateOptions = function validateOptions(options, requirements) {
- options = options || {};
- let validatedOptions = {};
-
- for (let key in requirements) {
- let isOptional = false;
- let mapThrew = false;
- let req = requirements[key];
- let [optsVal, keyInOpts] = (key in options) ?
- [options[key], true] :
- [undefined, false];
- if (req.map) {
- try {
- optsVal = req.map(optsVal);
- }
- catch (err) {
- if (err instanceof RequirementError)
- throw err;
-
- mapThrew = true;
- }
- }
- if (req.is) {
- let types = req.is;
-
- if (!isArray(types) && isArray(types.is))
- types = types.is;
-
- if (isArray(types)) {
- isOptional = ['undefined', 'null'].every(v => ~types.indexOf(v));
-
- // Sanity check the caller's type names.
- types.forEach(function (typ) {
- if (VALID_TYPES.indexOf(typ) < 0) {
- let msg = 'Internal error: invalid requirement type "' + typ + '".';
- throw new Error(msg);
- }
- });
- if (types.indexOf(getTypeOf(optsVal)) < 0)
- throw new RequirementError(key, req);
- }
- }
-
- if (req.ok && ((!isOptional || !isNil(optsVal)) && !req.ok(optsVal)))
- throw new RequirementError(key, req);
-
- if (keyInOpts || (req.map && !mapThrew && optsVal !== undefined))
- validatedOptions[key] = optsVal;
- }
-
- return validatedOptions;
-};
-
-exports.addIterator = function addIterator(obj, keysValsGenerator) {
- obj.__iterator__ = function(keysOnly, keysVals) {
- let keysValsIterator = keysValsGenerator.call(this);
-
- // "for (.. in ..)" gets only keys, "for each (.. in ..)" gets values,
- // and "for (.. in Iterator(..))" gets [key, value] pairs.
- let index = keysOnly ? 0 : 1;
- while (true)
- yield keysVals ? keysValsIterator.next() : keysValsIterator.next()[index];
- };
-};
-
-// Similar to typeof, except arrays, null and regexps are identified by "array" and
-// "null" and "regexp", not "object".
-var getTypeOf = exports.getTypeOf = function getTypeOf(val) {
- let typ = typeof(val);
- if (typ === "object") {
- if (!val)
- return "null";
- if (isArray(val))
- return "array";
- if (isRegExp(val))
- return "regexp";
- }
- return typ;
-}
-
-function RequirementError(key, requirement) {
- Error.call(this);
-
- this.name = "RequirementError";
-
- let msg = requirement.msg;
- if (!msg) {
- msg = 'The option "' + key + '" ';
- msg += requirement.is ?
- "must be one of the following types: " + requirement.is.join(", ") :
- "is invalid.";
- }
-
- this.message = msg;
-}
-RequirementError.prototype = Object.create(Error.prototype);
-
-var string = { is: ['string', 'undefined', 'null'] };
-exports.string = string;
-
-var number = { is: ['number', 'undefined', 'null'] };
-exports.number = number;
-
-var boolean = { is: ['boolean', 'undefined', 'null'] };
-exports.boolean = boolean;
-
-var object = { is: ['object', 'undefined', 'null'] };
-exports.object = object;
-
-var array = { is: ['array', 'undefined', 'null'] };
-exports.array = array;
-
-var isTruthyType = type => !(type === 'undefined' || type === 'null');
-var findTypes = v => { while (!isArray(v) && v.is) v = v.is; return v };
-
-function required(req) {
- let types = (findTypes(req) || VALID_TYPES).filter(isTruthyType);
-
- return merge({}, req, {is: types});
-}
-exports.required = required;
-
-function optional(req) {
- req = merge({is: []}, req);
- req.is = findTypes(req).filter(isTruthyType).concat('undefined', 'null');
-
- return req;
-}
-exports.optional = optional;
-
-function either(...types) {
- return union.apply(null, types.map(findTypes));
-}
-exports.either = either;
diff --git a/addon-sdk/source/lib/sdk/deprecated/events/assembler.js b/addon-sdk/source/lib/sdk/deprecated/events/assembler.js
deleted file mode 100644
index bb297c24f..000000000
--- a/addon-sdk/source/lib/sdk/deprecated/events/assembler.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 { removeListener, on } = require("../../dom/events");
-
-/**
- * Event targets
- * can be added / removed by calling `observe / ignore` methods. Composer should
- * provide array of event types it wishes to handle as property
- * `supportedEventsTypes` and function for handling all those events as
- * `handleEvent` property.
- */
-exports.DOMEventAssembler = Class({
- /**
- * Function that is supposed to handle all the supported events (that are
- * present in the `supportedEventsTypes`) from all the observed
- * `eventTargets`.
- * @param {Event} event
- * Event being dispatched.
- */
- handleEvent() {
- throw new TypeError("Instance of DOMEventAssembler must implement `handleEvent` method");
- },
- /**
- * Array of supported event names.
- * @type {String[]}
- */
- get supportedEventsTypes() {
- throw new TypeError("Instance of DOMEventAssembler must implement `handleEvent` field");
- },
- /**
- * Adds `eventTarget` to the list of observed `eventTarget`s. Listeners for
- * supported events will be registered on the given `eventTarget`.
- * @param {EventTarget} eventTarget
- */
- observe: function observe(eventTarget) {
- this.supportedEventsTypes.forEach(function(eventType) {
- on(eventTarget, eventType, this);
- }, this);
- },
- /**
- * Removes `eventTarget` from the list of observed `eventTarget`s. Listeners
- * for all supported events will be unregistered from the given `eventTarget`.
- * @param {EventTarget} eventTarget
- */
- ignore: function ignore(eventTarget) {
- this.supportedEventsTypes.forEach(function(eventType) {
- removeListener(eventTarget, eventType, this);
- }, this);
- }
-});
diff --git a/addon-sdk/source/lib/sdk/deprecated/sync-worker.js b/addon-sdk/source/lib/sdk/deprecated/sync-worker.js
deleted file mode 100644
index 71cadac36..000000000
--- 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));
-}
diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
deleted file mode 100644
index e38629f45..000000000
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
+++ /dev/null
@@ -1,199 +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 file = require("../io/file");
-const { Loader } = require("../test/loader");
-
-const { isNative } = require('@loader/options');
-
-const cuddlefish = isNative ? require("toolkit/loader") : require("../loader/cuddlefish");
-
-const { defer, resolve } = require("../core/promise");
-const { getAddon } = require("../addon/installer");
-const { id } = require("sdk/self");
-const { newURI } = require('sdk/url/utils');
-const { getZipReader } = require("../zip/utils");
-
-const { Cc, Ci, Cu } = require("chrome");
-const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
-var ios = Cc['@mozilla.org/network/io-service;1']
- .getService(Ci.nsIIOService);
-
-const CFX_TEST_REGEX = /(([^\/]+\/)(?:lib\/)?)?(tests?\/test-[^\.\/]+)\.js$/;
-const JPM_TEST_REGEX = /^()(tests?\/test-[^\.\/]+)\.js$/;
-
-const { mapcat, map, filter, fromEnumerator } = require("sdk/util/sequence");
-
-const toFile = x => x.QueryInterface(Ci.nsIFile);
-const isTestFile = ({leafName}) => leafName.substr(0, 5) == "test-" && leafName.substr(-3, 3) == ".js";
-const getFileURI = x => ios.newFileURI(x).spec;
-
-const getDirectoryEntries = file => map(toFile, fromEnumerator(_ => file.directoryEntries));
-const getTestFiles = directory => filter(isTestFile, getDirectoryEntries(directory));
-const getTestURIs = directory => map(getFileURI, getTestFiles(directory));
-
-const isDirectory = x => x.isDirectory();
-const getTestEntries = directory => mapcat(entry =>
- /^tests?$/.test(entry.leafName) ? getTestURIs(entry) : getTestEntries(entry),
- filter(isDirectory, getDirectoryEntries(directory)));
-
-const removeDups = (array) => array.reduce((result, value) => {
- if (value != result[result.length - 1]) {
- result.push(value);
- }
- return result;
-}, []);
-
-const getSuites = function getSuites({ id, filter }) {
- const TEST_REGEX = isNative ? JPM_TEST_REGEX : CFX_TEST_REGEX;
-
- return getAddon(id).then(addon => {
- let fileURI = addon.getResourceURI("tests/");
- let isPacked = fileURI.scheme == "jar";
- let xpiURI = addon.getResourceURI();
- let file = xpiURI.QueryInterface(Ci.nsIFileURL).file;
- let suites = [];
- let addEntry = (entry) => {
- if (filter(entry) && TEST_REGEX.test(entry)) {
- let suite = (isNative ? "./" : "") + (RegExp.$2 || "") + RegExp.$3;
- suites.push(suite);
- }
- }
-
- if (isPacked) {
- return getZipReader(file).then(zip => {
- let entries = zip.findEntries(null);
- while (entries.hasMore()) {
- let entry = entries.getNext();
- addEntry(entry);
- }
- zip.close();
-
- // sort and remove dups
- suites = removeDups(suites.sort());
- return suites;
- })
- }
- else {
- let tests = [...getTestEntries(file)];
- let rootURI = addon.getResourceURI("/");
- tests.forEach((entry) => {
- addEntry(entry.replace(rootURI.spec, ""));
- });
- }
-
- // sort and remove dups
- suites = removeDups(suites.sort());
- return suites;
- });
-}
-exports.getSuites = getSuites;
-
-const makeFilters = function makeFilters(options) {
- options = options || {};
-
- // A filter string is {fileNameRegex}[:{testNameRegex}] - ie, a colon
- // optionally separates a regex for the test fileName from a regex for the
- // testName.
- if (options.filter) {
- let colonPos = options.filter.indexOf(':');
- let filterFileRegex, filterNameRegex;
-
- if (colonPos === -1) {
- filterFileRegex = new RegExp(options.filter);
- filterNameRegex = { test: () => true }
- }
- else {
- filterFileRegex = new RegExp(options.filter.substr(0, colonPos));
- filterNameRegex = new RegExp(options.filter.substr(colonPos + 1));
- }
-
- return {
- fileFilter: (name) => filterFileRegex.test(name),
- testFilter: (name) => filterNameRegex.test(name)
- }
- }
-
- return {
- fileFilter: () => true,
- testFilter: () => true
- };
-}
-exports.makeFilters = makeFilters;
-
-var loader = Loader(module);
-const NOT_TESTS = ['setup', 'teardown'];
-
-var TestFinder = exports.TestFinder = function TestFinder(options) {
- this.filter = options.filter;
- this.testInProcess = options.testInProcess === false ? false : true;
- this.testOutOfProcess = options.testOutOfProcess === true ? true : false;
-};
-
-TestFinder.prototype = {
- findTests: function findTests() {
- let { fileFilter, testFilter } = makeFilters({ filter: this.filter });
-
- return getSuites({ id: id, filter: fileFilter }).then(suites => {
- let testsRemaining = [];
-
- let getNextTest = () => {
- if (testsRemaining.length) {
- return testsRemaining.shift();
- }
-
- if (!suites.length) {
- return null;
- }
-
- let suite = suites.shift();
-
- // Load each test file as a main module in its own loader instance
- // `suite` is defined by cuddlefish/manifest.py:ManifestBuilder.build
- let suiteModule;
-
- try {
- suiteModule = cuddlefish.main(loader, suite);
- }
- catch (e) {
- if (/Unsupported Application/i.test(e.message)) {
- // If `Unsupported Application` error thrown during test,
- // skip the test suite
- suiteModule = {
- 'test suite skipped': assert => assert.pass(e.message)
- };
- }
- else {
- console.exception(e);
- throw e;
- }
- }
-
- if (this.testInProcess) {
- for (let name of Object.keys(suiteModule).sort()) {
- if (NOT_TESTS.indexOf(name) === -1 && testFilter(name)) {
- testsRemaining.push({
- setup: suiteModule.setup,
- teardown: suiteModule.teardown,
- testFunction: suiteModule[name],
- name: suite + "." + name
- });
- }
- }
- }
-
- return getNextTest();
- };
-
- return {
- getNext: () => resolve(getNextTest())
- };
- });
- }
-};
diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test.js b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
deleted file mode 100644
index 32bba8f6b..000000000
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js
+++ /dev/null
@@ -1,584 +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 timer = require("../timers");
-const cfxArgs = require("../test/options");
-const { getTabs, closeTab, getURI, getTabId, getSelectedTab } = require("../tabs/utils");
-const { windows, isBrowser, getMostRecentBrowserWindow } = require("../window/utils");
-const { defer, all, Debugging: PromiseDebugging, resolve } = require("../core/promise");
-const { getInnerId } = require("../window/utils");
-const { cleanUI } = require("../test/utils");
-
-const findAndRunTests = function findAndRunTests(options) {
- var TestFinder = require("./unit-test-finder").TestFinder;
- var finder = new TestFinder({
- filter: options.filter,
- testInProcess: options.testInProcess,
- testOutOfProcess: options.testOutOfProcess
- });
- var runner = new TestRunner({fs: options.fs});
- finder.findTests().then(tests => {
- runner.startMany({
- tests: tests,
- 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);
-};
-
-TestRunner.prototype = {
- toString: function toString() {
- return "[object TestRunner]";
- },
-
- DEFAULT_PAUSE_TIMEOUT: (cfxArgs.parseable ? 300000 : 15000), //Five minutes (5*60*1000ms)
- PAUSE_DELAY: 500,
-
- _logTestFailed: function _logTestFailed(why) {
- if (!(why in this.test.errors))
- this.test.errors[why] = 0;
- this.test.errors[why]++;
- },
-
- _uncaughtErrorObserver: function({message, date, fileName, stack, lineNumber}) {
- this.fail("There was an uncaught Promise rejection: " + message + " @ " +
- fileName + ":" + lineNumber + "\n" + stack);
- },
-
- pass: function pass(message) {
- if(!this.expectFailure) {
- if ("testMessage" in this.console)
- this.console.testMessage(true, true, this.test.name, message);
- else
- this.console.info("pass:", message);
- this.passed++;
- this.test.passed++;
- this.test.last = message;
- }
- else {
- this.expectFailure = false;
- this._logTestFailed("failure");
- if ("testMessage" in this.console) {
- this.console.testMessage(true, false, this.test.name, message);
- }
- else {
- this.console.error("fail:", 'Failure Expected: ' + message)
- this.console.trace();
- }
- this.failed++;
- this.test.failed++;
- }
- },
-
- fail: function fail(message) {
- if(!this.expectFailure) {
- this._logTestFailed("failure");
- if ("testMessage" in this.console) {
- this.console.testMessage(false, false, this.test.name, message);
- }
- else {
- this.console.error("fail:", message)
- this.console.trace();
- }
- this.failed++;
- this.test.failed++;
- }
- else {
- this.expectFailure = false;
- if ("testMessage" in this.console)
- this.console.testMessage(false, true, this.test.name, message);
- else
- this.console.info("pass:", message);
- this.passed++;
- this.test.passed++;
- this.test.last = message;
- }
- },
-
- expectFail: function(callback) {
- this.expectFailure = true;
- callback();
- this.expectFailure = false;
- },
-
- exception: function exception(e) {
- this._logTestFailed("exception");
- if (cfxArgs.parseable)
- this.console.print("TEST-UNEXPECTED-FAIL | " + this.test.name + " | " + e + "\n");
- this.console.exception(e);
- this.failed++;
- this.test.failed++;
- },
-
- assertMatches: function assertMatches(string, regexp, message) {
- if (regexp.test(string)) {
- if (!message)
- message = uneval(string) + " matches " + uneval(regexp);
- this.pass(message);
- } else {
- var no = uneval(string) + " doesn't match " + uneval(regexp);
- if (!message)
- message = no;
- else
- message = message + " (" + no + ")";
- this.fail(message);
- }
- },
-
- assertRaises: function assertRaises(func, predicate, message) {
- try {
- func();
- if (message)
- this.fail(message + " (no exception thrown)");
- else
- this.fail("function failed to throw exception");
- } catch (e) {
- var errorMessage;
- if (typeof(e) == "string")
- errorMessage = e;
- else
- errorMessage = e.message;
- if (typeof(predicate) == "string")
- this.assertEqual(errorMessage, predicate, message);
- else
- this.assertMatches(errorMessage, predicate, message);
- }
- },
-
- assert: function assert(a, message) {
- if (!a) {
- if (!message)
- message = "assertion failed, value is " + a;
- this.fail(message);
- } else
- this.pass(message || "assertion successful");
- },
-
- assertNotEqual: function assertNotEqual(a, b, message) {
- if (a != b) {
- if (!message)
- message = "a != b != " + uneval(a);
- this.pass(message);
- } else {
- var equality = uneval(a) + " == " + uneval(b);
- if (!message)
- message = equality;
- else
- message += " (" + equality + ")";
- this.fail(message);
- }
- },
-
- assertEqual: function assertEqual(a, b, message) {
- if (a == b) {
- if (!message)
- message = "a == b == " + uneval(a);
- this.pass(message);
- } else {
- var inequality = uneval(a) + " != " + uneval(b);
- if (!message)
- message = inequality;
- else
- message += " (" + inequality + ")";
- this.fail(message);
- }
- },
-
- assertNotStrictEqual: function assertNotStrictEqual(a, b, message) {
- if (a !== b) {
- if (!message)
- message = "a !== b !== " + uneval(a);
- this.pass(message);
- } else {
- var equality = uneval(a) + " === " + uneval(b);
- if (!message)
- message = equality;
- else
- message += " (" + equality + ")";
- this.fail(message);
- }
- },
-
- assertStrictEqual: function assertStrictEqual(a, b, message) {
- if (a === b) {
- if (!message)
- message = "a === b === " + uneval(a);
- this.pass(message);
- } else {
- var inequality = uneval(a) + " !== " + uneval(b);
- if (!message)
- message = inequality;
- else
- message += " (" + inequality + ")";
- this.fail(message);
- }
- },
-
- assertFunction: function assertFunction(a, message) {
- this.assertStrictEqual('function', typeof a, message);
- },
-
- assertUndefined: function(a, message) {
- this.assertStrictEqual('undefined', typeof a, message);
- },
-
- assertNotUndefined: function(a, message) {
- this.assertNotStrictEqual('undefined', typeof a, message);
- },
-
- assertNull: function(a, message) {
- this.assertStrictEqual(null, a, message);
- },
-
- assertNotNull: function(a, message) {
- this.assertNotStrictEqual(null, a, message);
- },
-
- assertObject: function(a, message) {
- this.assertStrictEqual('[object Object]', Object.prototype.toString.apply(a), message);
- },
-
- assertString: function(a, message) {
- this.assertStrictEqual('[object String]', Object.prototype.toString.apply(a), message);
- },
-
- assertArray: function(a, message) {
- this.assertStrictEqual('[object Array]', Object.prototype.toString.apply(a), message);
- },
-
- assertNumber: function(a, message) {
- this.assertStrictEqual('[object Number]', Object.prototype.toString.apply(a), message);
- },
-
- done: function done() {
- if (this.isDone) {
- return resolve();
- }
-
- this.isDone = true;
- this.pass("This test is done.");
-
- if (this.test.teardown) {
- this.test.teardown(this);
- }
-
- if (this.waitTimeout !== null) {
- timer.clearTimeout(this.waitTimeout);
- this.waitTimeout = null;
- }
-
- // Do not leave any callback set when calling to `waitUntil`
- this.waitUntilCallback = null;
- if (this.test.passed == 0 && this.test.failed == 0) {
- this._logTestFailed("empty test");
-
- if ("testMessage" in this.console) {
- this.console.testMessage(false, false, this.test.name, "Empty test");
- }
- else {
- this.console.error("fail:", "Empty test")
- }
-
- this.failed++;
- this.test.failed++;
- }
-
- let wins = windows(null, { includePrivate: true });
- let winPromises = wins.map(win => {
- return new Promise(resolve => {
- if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
- resolve()
- }
- else {
- win.addEventListener("DOMContentLoaded", function onLoad() {
- win.removeEventListener("DOMContentLoaded", onLoad, false);
- resolve();
- }, false);
- }
- });
- });
-
- 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);
- console.log(win.location + " - " + tabs.map(getURI).join(", "));
- }
- else {
- console.log(win.location);
- }
- }
- }
-
- return failure;
- }).
- then(failure => {
- if (!failure) {
- this.pass("There was a clean UI.");
- return null;
- }
- return cleanUI().then(() => {
- this.pass("There is a clean UI.");
- });
- }).
- then(() => {
- this.testRunSummary.push({
- name: this.test.name,
- passed: this.test.passed,
- failed: this.test.failed,
- errors: Object.keys(this.test.errors).join(", ")
- });
-
- if (this.onDone !== null) {
- let onDone = this.onDone;
- this.onDone = null;
- timer.setTimeout(_ => onDone(this));
- }
- }).
- catch(console.exception);
- },
-
- // Set of assertion functions to wait for an assertion to become true
- // These functions take the same arguments as the TestRunner.assert* methods.
- waitUntil: function waitUntil() {
- return this._waitUntil(this.assert, arguments);
- },
-
- waitUntilNotEqual: function waitUntilNotEqual() {
- return this._waitUntil(this.assertNotEqual, arguments);
- },
-
- waitUntilEqual: function waitUntilEqual() {
- return this._waitUntil(this.assertEqual, arguments);
- },
-
- waitUntilMatches: function waitUntilMatches() {
- return this._waitUntil(this.assertMatches, arguments);
- },
-
- /**
- * Internal function that waits for an assertion to become true.
- * @param {Function} assertionMethod
- * Reference to a TestRunner assertion method like test.assert,
- * test.assertEqual, ...
- * @param {Array} args
- * List of arguments to give to the previous assertion method.
- * All functions in this list are going to be called to retrieve current
- * assertion values.
- */
- _waitUntil: function waitUntil(assertionMethod, args) {
- let { promise, resolve } = defer();
- let count = 0;
- let maxCount = this.DEFAULT_PAUSE_TIMEOUT / this.PAUSE_DELAY;
-
- // We need to ensure that test is asynchronous
- if (!this.waitTimeout)
- this.waitUntilDone(this.DEFAULT_PAUSE_TIMEOUT);
-
- let finished = false;
- let test = this;
-
- // capture a traceback before we go async.
- let traceback = require("../console/traceback");
- let stack = traceback.get();
- stack.splice(-2, 2);
- let currentWaitStack = traceback.format(stack);
- let timeout = null;
-
- function loop(stopIt) {
- timeout = null;
-
- // Build a mockup object to fake TestRunner API and intercept calls to
- // pass and fail methods, in order to retrieve nice error messages
- // and assertion result
- let mock = {
- pass: function (msg) {
- test.pass(msg);
- test.waitUntilCallback = null;
- if (!stopIt)
- resolve();
- },
- fail: function (msg) {
- // If we are called on test timeout, we stop the loop
- // and print which test keeps failing:
- if (stopIt) {
- test.console.error("test assertion never became true:\n",
- msg + "\n",
- currentWaitStack);
- if (timeout)
- timer.clearTimeout(timeout);
- return;
- }
- timeout = timer.setTimeout(loop, test.PAUSE_DELAY);
- }
- };
-
- // Automatically call args closures in order to build arguments for
- // assertion function
- let appliedArgs = [];
- for (let i = 0, l = args.length; i < l; i++) {
- let a = args[i];
- if (typeof a == "function") {
- try {
- a = a();
- }
- catch(e) {
- test.fail("Exception when calling asynchronous assertion: " + e +
- "\n" + e.stack);
- return resolve();
- }
- }
- appliedArgs.push(a);
- }
-
- // Finally call assertion function with current assertion values
- assertionMethod.apply(mock, appliedArgs);
- }
- loop();
- this.waitUntilCallback = loop;
-
- return promise;
- },
-
- waitUntilDone: function waitUntilDone(ms) {
- if (ms === undefined)
- ms = this.DEFAULT_PAUSE_TIMEOUT;
-
- var self = this;
-
- function tiredOfWaiting() {
- self._logTestFailed("timed out");
- if ("testMessage" in self.console) {
- self.console.testMessage(false, false, self.test.name,
- `Test timed out (after: ${self.test.last})`);
- }
- else {
- self.console.error("fail:", `Timed out (after: ${self.test.last})`)
- }
- if (self.waitUntilCallback) {
- self.waitUntilCallback(true);
- self.waitUntilCallback = null;
- }
- self.failed++;
- self.test.failed++;
- self.done();
- }
-
- // We may already have registered a timeout callback
- if (this.waitTimeout)
- timer.clearTimeout(this.waitTimeout);
-
- this.waitTimeout = timer.setTimeout(tiredOfWaiting, ms);
- },
-
- startMany: function startMany(options) {
- function runNextTest(self) {
- let { tests, onDone } = options;
-
- return tests.getNext().then((test) => {
- if (options.stopOnError && self.test && self.test.failed) {
- self.console.error("aborted: test failed and --stop-on-error was specified");
- onDone(self);
- }
- else if (test) {
- self.start({test: test, onDone: runNextTest});
- }
- else {
- onDone(self);
- }
- });
- }
-
- return runNextTest(this).catch(console.exception);
- },
-
- start: function start(options) {
- this.test = options.test;
- this.test.passed = 0;
- this.test.failed = 0;
- this.test.errors = {};
- this.test.last = 'START';
- PromiseDebugging.clearUncaughtErrorObservers();
- this._uncaughtErrorObserver = this._uncaughtErrorObserver.bind(this);
- PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver);
-
- this.isDone = false;
- this.onDone = function(self) {
- if (cfxArgs.parseable)
- self.console.print("TEST-END | " + self.test.name + "\n");
- options.onDone(self);
- }
- this.waitTimeout = null;
-
- try {
- if (cfxArgs.parseable)
- this.console.print("TEST-START | " + this.test.name + "\n");
- else
- this.console.info("executing '" + this.test.name + "'");
-
- if(this.test.setup) {
- this.test.setup(this);
- }
- this.test.testFunction(this);
- } catch (e) {
- this.exception(e);
- }
- if (this.waitTimeout === null)
- this.done();
- }
-};
-exports.TestRunner = TestRunner;
diff --git a/addon-sdk/source/lib/sdk/deprecated/window-utils.js b/addon-sdk/source/lib/sdk/deprecated/window-utils.js
deleted file mode 100644
index 93c0ab7b8..000000000
--- a/addon-sdk/source/lib/sdk/deprecated/window-utils.js
+++ /dev/null
@@ -1,193 +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 { Cc, Ci } = require('chrome');
-const events = require('../system/events');
-const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser,
- getMostRecentBrowserWindow, getToplevelWindow, getMostRecentWindow } = require('../window/utils');
-const { deprecateFunction } = require('../util/deprecate');
-const { ignoreWindow } = require('sdk/private-browsing/utils');
-const { isPrivateBrowsingSupported } = require('../self');
-
-const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
- getService(Ci.nsIWindowWatcher);
-const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
- getService(Ci.nsIAppShellService);
-
-// Bug 834961: ignore private windows when they are not supported
-function getWindows() {
- return windows(null, { includePrivate: isPrivateBrowsingSupported });
-}
-
-/**
- * An iterator for XUL windows currently in the application.
- *
- * @return A generator that yields XUL windows exposing the
- * nsIDOMWindow interface.
- */
-function windowIterator() {
- // Bug 752631: We only pass already loaded window in order to avoid
- // breaking XUL windows DOM. DOM is broken when some JS code try
- // to access DOM during "uninitialized" state of the related document.
- let list = getWindows().filter(isDocumentLoaded);
- for (let i = 0, l = list.length; i < l; i++) {
- yield list[i];
- }
-};
-exports.windowIterator = windowIterator;
-
-/**
- * An iterator for browser windows currently open in the application.
- * @returns {Function}
- * A generator that yields browser windows exposing the `nsIDOMWindow`
- * interface.
- */
-function browserWindowIterator() {
- for (let window of windowIterator()) {
- if (isBrowser(window))
- yield window;
- }
-}
-exports.browserWindowIterator = browserWindowIterator;
-
-function WindowTracker(delegate) {
- if (!(this instanceof WindowTracker)) {
- return new WindowTracker(delegate);
- }
-
- this._delegate = delegate;
-
- for (let window of getWindows())
- this._regWindow(window);
- windowWatcher.registerNotification(this);
- this._onToplevelWindowReady = this._onToplevelWindowReady.bind(this);
- events.on('toplevel-window-ready', this._onToplevelWindowReady);
-
- require('../system/unload').ensure(this);
-
- return this;
-};
-
-WindowTracker.prototype = {
- _regLoadingWindow: function _regLoadingWindow(window) {
- // Bug 834961: ignore private windows when they are not supported
- if (ignoreWindow(window))
- return;
-
- window.addEventListener('load', this, true);
- },
-
- _unregLoadingWindow: function _unregLoadingWindow(window) {
- // This may have no effect if we ignored the window in _regLoadingWindow().
- window.removeEventListener('load', this, true);
- },
-
- _regWindow: function _regWindow(window) {
- // Bug 834961: ignore private windows when they are not supported
- if (ignoreWindow(window))
- return;
-
- if (window.document.readyState == 'complete') {
- this._unregLoadingWindow(window);
- this._delegate.onTrack(window);
- } else
- this._regLoadingWindow(window);
- },
-
- _unregWindow: function _unregWindow(window) {
- if (window.document.readyState == 'complete') {
- if (this._delegate.onUntrack)
- this._delegate.onUntrack(window);
- } else {
- this._unregLoadingWindow(window);
- }
- },
-
- unload: function unload() {
- windowWatcher.unregisterNotification(this);
- events.off('toplevel-window-ready', this._onToplevelWindowReady);
- for (let window of getWindows())
- this._unregWindow(window);
- },
-
- handleEvent: function handleEvent(event) {
- try {
- if (event.type == 'load' && event.target) {
- var window = event.target.defaultView;
- if (window)
- this._regWindow(getToplevelWindow(window));
- }
- }
- catch(e) {
- console.exception(e);
- }
- },
-
- _onToplevelWindowReady: function _onToplevelWindowReady({subject}) {
- let window = getToplevelWindow(subject);
- // ignore private windows if they are not supported
- if (ignoreWindow(window))
- return;
- this._regWindow(window);
- },
-
- observe: function observe(subject, topic, data) {
- try {
- var window = subject.QueryInterface(Ci.nsIDOMWindow);
- // ignore private windows if they are not supported
- if (ignoreWindow(window))
- return;
- if (topic == 'domwindowclosed')
- this._unregWindow(window);
- }
- catch(e) {
- console.exception(e);
- }
- }
-};
-exports.WindowTracker = WindowTracker;
-
-Object.defineProperties(exports, {
- activeWindow: {
- enumerable: true,
- get: function() {
- return getMostRecentWindow(null);
- },
- set: function(window) {
- try {
- window.focus();
- } catch (e) {}
- }
- },
- activeBrowserWindow: {
- enumerable: true,
- get: getMostRecentBrowserWindow
- }
-});
-
-
-/**
- * Returns the ID of the window's current inner window.
- */
-exports.getInnerId = deprecateFunction(getInnerId,
- 'require("window-utils").getInnerId is deprecated, ' +
- 'please use require("sdk/window/utils").getInnerId instead'
-);
-
-exports.getOuterId = deprecateFunction(getOuterId,
- 'require("window-utils").getOuterId is deprecated, ' +
- 'please use require("sdk/window/utils").getOuterId instead'
-);
-
-exports.isBrowser = deprecateFunction(isBrowser,
- 'require("window-utils").isBrowser is deprecated, ' +
- 'please use require("sdk/window/utils").isBrowser instead'
-);
-
-exports.hiddenWindow = appShellService.hiddenDOMWindow;
diff --git a/addon-sdk/source/lib/sdk/dom/events-shimmed.js b/addon-sdk/source/lib/sdk/dom/events-shimmed.js
deleted file mode 100644
index 7a1727681..000000000
--- a/addon-sdk/source/lib/sdk/dom/events-shimmed.js
+++ /dev/null
@@ -1,18 +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 events = require('./events.js');
-
-exports.emit = (element, type, obj) => events.emit(element, type, obj, true);
-exports.on = (element, type, listener, capture) => events.on(element, type, listener, capture, true);
-exports.once = (element, type, listener, capture) => events.once(element, type, listener, capture, true);
-exports.removeListener = (element, type, listener, capture) => events.removeListener(element, type, listener, capture, true);
-exports.removed = events.removed;
-exports.when = (element, eventName, capture) => events.when(element, eventName, capture ? capture : false, true);
diff --git a/addon-sdk/source/lib/sdk/dom/events.js b/addon-sdk/source/lib/sdk/dom/events.js
deleted file mode 100644
index 502d2350f..000000000
--- a/addon-sdk/source/lib/sdk/dom/events.js
+++ /dev/null
@@ -1,192 +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 { Cu } = require("chrome");
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-
-// Utility function that returns copy of the given `text` with last character
-// removed if it is `"s"`.
-function singularify(text) {
- return text[text.length - 1] === "s" ? text.substr(0, text.length - 1) : text;
-}
-
-// Utility function that takes event type, argument is passed to
-// `document.createEvent` and returns name of the initializer method of the
-// given event. Please note that there are some event types whose initializer
-// methods can't be guessed by this function. For more details see following
-// link: https://developer.mozilla.org/En/DOM/Document.createEvent
-function getInitializerName(category) {
- return "init" + singularify(category);
-}
-
-/**
- * Registers an event `listener` on a given `element`, that will be called
- * when events of specified `type` is dispatched on the `element`.
- * @param {Element} element
- * Dom element to register listener on.
- * @param {String} type
- * A string representing the
- * [event type](https://developer.mozilla.org/en/DOM/event.type) to
- * listen for.
- * @param {Function} listener
- * Function that is called whenever an event of the specified `type`
- * occurs.
- * @param {Boolean} capture
- * If true, indicates that the user wishes to initiate capture. After
- * initiating capture, all events of the specified type will be dispatched
- * to the registered listener before being dispatched to any `EventTarget`s
- * beneath it in the DOM tree. Events which are bubbling upward through
- * the tree will not trigger a listener designated to use capture.
- * See [DOM Level 3 Events](http://www.w3.org/TR/DOM-Level-3-Events/#event-flow)
- * for a detailed explanation.
- */
-function on(element, type, listener, capture, shimmed = false) {
- // `capture` defaults to `false`.
- capture = capture || false;
- if (shimmed) {
- element.addEventListener(type, listener, capture);
- } else {
- ShimWaiver.getProperty(element, "addEventListener")(type, listener, capture);
- }
-}
-exports.on = on;
-
-/**
- * Registers an event `listener` on a given `element`, that will be called
- * only once, next time event of specified `type` is dispatched on the
- * `element`.
- * @param {Element} element
- * Dom element to register listener on.
- * @param {String} type
- * A string representing the
- * [event type](https://developer.mozilla.org/en/DOM/event.type) to
- * listen for.
- * @param {Function} listener
- * Function that is called whenever an event of the specified `type`
- * occurs.
- * @param {Boolean} capture
- * If true, indicates that the user wishes to initiate capture. After
- * initiating capture, all events of the specified type will be dispatched
- * to the registered listener before being dispatched to any `EventTarget`s
- * beneath it in the DOM tree. Events which are bubbling upward through
- * the tree will not trigger a listener designated to use capture.
- * See [DOM Level 3 Events](http://www.w3.org/TR/DOM-Level-3-Events/#event-flow)
- * for a detailed explanation.
- */
-function once(element, type, listener, capture, shimmed = false) {
- on(element, type, function selfRemovableListener(event) {
- removeListener(element, type, selfRemovableListener, capture, shimmed);
- listener.apply(this, arguments);
- }, capture, shimmed);
-}
-exports.once = once;
-
-/**
- * Unregisters an event `listener` on a given `element` for the events of the
- * specified `type`.
- *
- * @param {Element} element
- * Dom element to unregister listener from.
- * @param {String} type
- * A string representing the
- * [event type](https://developer.mozilla.org/en/DOM/event.type) to
- * listen for.
- * @param {Function} listener
- * Function that is called whenever an event of the specified `type`
- * occurs.
- * @param {Boolean} capture
- * If true, indicates that the user wishes to initiate capture. After
- * initiating capture, all events of the specified type will be dispatched
- * to the registered listener before being dispatched to any `EventTarget`s
- * beneath it in the DOM tree. Events which are bubbling upward through
- * the tree will not trigger a listener designated to use capture.
- * See [DOM Level 3 Events](http://www.w3.org/TR/DOM-Level-3-Events/#event-flow)
- * for a detailed explanation.
- */
-function removeListener(element, type, listener, capture, shimmed = false) {
- if (shimmed) {
- element.removeEventListener(type, listener, capture);
- } else {
- ShimWaiver.getProperty(element, "removeEventListener")(type, listener, capture);
- }
-}
-exports.removeListener = removeListener;
-
-/**
- * Emits event of the specified `type` and `category` on the given `element`.
- * Specified `settings` are used to initialize event before dispatching it.
- * @param {Element} element
- * Dom element to dispatch event on.
- * @param {String} type
- * A string representing the
- * [event type](https://developer.mozilla.org/en/DOM/event.type).
- * @param {Object} options
- * Options object containing following properties:
- * - `category`: String passed to the `document.createEvent`. Option is
- * optional and defaults to "UIEvents".
- * - `initializer`: If passed it will be used as name of the method used
- * to initialize event. If omitted name will be generated from the
- * `category` field by prefixing it with `"init"` and removing last
- * character if it matches `"s"`.
- * - `settings`: Array of settings that are forwarded to the event
- * initializer after firs `type` argument.
- * @see https://developer.mozilla.org/En/DOM/Document.createEvent
- */
-function emit(element, type, { category, initializer, settings }, shimmed = false) {
- category = category || "UIEvents";
- initializer = initializer || getInitializerName(category);
- let document = element.ownerDocument;
- let event = document.createEvent(category);
- event[initializer].apply(event, [type].concat(settings));
- if (shimmed) {
- element.dispatchEvent(event);
- } else {
- ShimWaiver.getProperty(element, "dispatchEvent")(event);
- }
-};
-exports.emit = emit;
-
-// Takes DOM `element` and returns promise which is resolved
-// when given element is removed from it's parent node.
-const removed = element => {
- return new Promise(resolve => {
- const { MutationObserver } = element.ownerDocument.defaultView;
- const observer = new MutationObserver(mutations => {
- for (let mutation of mutations) {
- for (let node of mutation.removedNodes || []) {
- if (node === element) {
- observer.disconnect();
- resolve(element);
- }
- }
- }
- });
- observer.observe(element.parentNode, {childList: true});
- });
-};
-exports.removed = removed;
-
-const when = (element, eventName, capture=false, shimmed=false) => new Promise(resolve => {
- const listener = event => {
- if (shimmed) {
- element.removeEventListener(eventName, listener, capture);
- } else {
- ShimWaiver.getProperty(element, "removeEventListener")(eventName, listener, capture);
- }
- resolve(event);
- };
-
- if (shimmed) {
- element.addEventListener(eventName, listener, capture);
- } else {
- ShimWaiver.getProperty(element, "addEventListener")(eventName, listener, capture);
- }
-});
-exports.when = when;
diff --git a/addon-sdk/source/lib/sdk/dom/events/keys.js b/addon-sdk/source/lib/sdk/dom/events/keys.js
deleted file mode 100644
index e6f1483a2..000000000
--- a/addon-sdk/source/lib/sdk/dom/events/keys.js
+++ /dev/null
@@ -1,63 +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 { emit } = require("../events");
-const { getCodeForKey, toJSON } = require("../../keyboard/utils");
-const { has } = require("../../util/array");
-const { isString } = require("../../lang/type");
-
-const INITIALIZER = "initKeyEvent";
-const CATEGORY = "KeyboardEvent";
-
-function Options(options) {
- if (!isString(options))
- return options;
-
- var { key, modifiers } = toJSON(options);
- return {
- key: key,
- control: has(modifiers, "control"),
- alt: has(modifiers, "alt"),
- shift: has(modifiers, "shift"),
- meta: has(modifiers, "meta")
- };
-}
-
-var keyEvent = exports.keyEvent = function keyEvent(element, type, options) {
-
- emit(element, type, {
- initializer: INITIALIZER,
- category: CATEGORY,
- settings: [
- !("bubbles" in options) || options.bubbles !== false,
- !("cancelable" in options) || options.cancelable !== false,
- "window" in options && options.window ? options.window : null,
- "control" in options && !!options.control,
- "alt" in options && !!options.alt,
- "shift" in options && !!options.shift,
- "meta" in options && !!options.meta,
- getCodeForKey(options.key) || 0,
- options.key.length === 1 ? options.key.charCodeAt(0) : 0
- ]
- });
-}
-
-exports.keyDown = function keyDown(element, options) {
- keyEvent(element, "keydown", Options(options));
-};
-
-exports.keyUp = function keyUp(element, options) {
- keyEvent(element, "keyup", Options(options));
-};
-
-exports.keyPress = function keyPress(element, options) {
- keyEvent(element, "keypress", Options(options));
-};
-
diff --git a/addon-sdk/source/lib/sdk/event/chrome.js b/addon-sdk/source/lib/sdk/event/chrome.js
deleted file mode 100644
index 9044fef99..000000000
--- a/addon-sdk/source/lib/sdk/event/chrome.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": "unstable"
-};
-
-const { Cc, Ci, Cr, Cu } = require("chrome");
-const { emit, on, off } = require("./core");
-var observerService = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
-
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const addObserver = ShimWaiver.getProperty(observerService, "addObserver");
-const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver");
-
-const { when: unload } = require("../system/unload");
-
-// Simple class that can be used to instantiate event channel that
-// implements `nsIObserver` interface. It's will is used by `observe`
-// function as observer + event target. It basically proxies observer
-// notifications as to it's registered listeners.
-function ObserverChannel() {}
-Object.freeze(Object.defineProperties(ObserverChannel.prototype, {
- QueryInterface: {
- value: function(iid) {
- if (!iid.equals(Ci.nsIObserver) &&
- !iid.equals(Ci.nsISupportsWeakReference) &&
- !iid.equals(Ci.nsISupports))
- throw Cr.NS_ERROR_NO_INTERFACE;
- return this;
- }
- },
- observe: {
- value: function(subject, topic, data) {
- emit(this, "data", {
- type: topic,
- target: subject,
- data: data
- });
- }
- }
-}));
-
-function observe(topic) {
- let observerChannel = new ObserverChannel();
-
- // Note: `nsIObserverService` will not hold a weak reference to a
- // observerChannel (since third argument is `true`). There for if it
- // will be GC-ed with all it's event listeners once no other references
- // will be held.
- addObserver(observerChannel, topic, true);
-
- // We need to remove any observer added once the add-on is unloaded;
- // otherwise we'll get a "dead object" exception.
- // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1001833
- unload(() => removeObserver(observerChannel, topic));
-
- return observerChannel;
-}
-
-exports.observe = observe;
diff --git a/addon-sdk/source/lib/sdk/event/core.js b/addon-sdk/source/lib/sdk/event/core.js
deleted file mode 100644
index c16dd2df5..000000000
--- a/addon-sdk/source/lib/sdk/event/core.js
+++ /dev/null
@@ -1,193 +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 UNCAUGHT_ERROR = 'An error event was emitted for which there was no listener.';
-const BAD_LISTENER = 'The event listener must be a function.';
-
-const { ns } = require('../core/namespace');
-
-const event = ns();
-
-const EVENT_TYPE_PATTERN = /^on([A-Z]\w+$)/;
-exports.EVENT_TYPE_PATTERN = EVENT_TYPE_PATTERN;
-
-// Utility function to access given event `target` object's event listeners for
-// the specific event `type`. If listeners for this type does not exists they
-// will be created.
-const observers = function observers(target, type) {
- if (!target) throw TypeError("Event target must be an object");
- let listeners = event(target);
- return type in listeners ? listeners[type] : listeners[type] = [];
-};
-
-/**
- * Registers an event `listener` that is called every time events of
- * specified `type` is emitted on the given event `target`.
- * @param {Object} target
- * Event target object.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
-function on(target, type, listener) {
- if (typeof(listener) !== 'function')
- throw new Error(BAD_LISTENER);
-
- let listeners = observers(target, type);
- if (!~listeners.indexOf(listener))
- listeners.push(listener);
-}
-exports.on = on;
-
-
-var onceWeakMap = new WeakMap();
-
-
-/**
- * Registers an event `listener` that is called only the next time an event
- * of the specified `type` is emitted on the given event `target`.
- * @param {Object} target
- * Event target object.
- * @param {String} type
- * The type of the event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
-function once(target, type, listener) {
- let replacement = function observer(...args) {
- off(target, type, observer);
- onceWeakMap.delete(listener);
- listener.apply(target, args);
- };
- onceWeakMap.set(listener, replacement);
- on(target, type, replacement);
-}
-exports.once = once;
-
-/**
- * Execute each of the listeners in order with the supplied arguments.
- * All the exceptions that are thrown by listeners during the emit
- * are caught and can be handled by listeners of 'error' event. Thrown
- * exceptions are passed as an argument to an 'error' event listener.
- * If no 'error' listener is registered exception will be logged into an
- * error console.
- * @param {Object} target
- * Event target object.
- * @param {String} type
- * The type of event.
- * @params {Object|Number|String|Boolean} args
- * Arguments that will be passed to listeners.
- */
-function emit (target, type, ...args) {
- emitOnObject(target, type, target, ...args);
-}
-exports.emit = emit;
-
-/**
- * A variant of emit that allows setting the this property for event listeners
- */
-function emitOnObject(target, type, thisArg, ...args) {
- let all = observers(target, '*').length;
- let state = observers(target, type);
- let listeners = state.slice();
- let count = listeners.length;
- let index = 0;
-
- // If error event and there are no handlers (explicit or catch-all)
- // then print error message to the console.
- if (count === 0 && type === 'error' && all === 0)
- console.exception(args[0]);
- while (index < count) {
- try {
- let listener = listeners[index];
- // Dispatch only if listener is still registered.
- if (~state.indexOf(listener))
- listener.apply(thisArg, args);
- }
- catch (error) {
- // If exception is not thrown by a error listener and error listener is
- // registered emit `error` event. Otherwise dump exception to the console.
- if (type !== 'error') emit(target, 'error', error);
- else console.exception(error);
- }
- index++;
- }
- // Also emit on `"*"` so that one could listen for all events.
- if (type !== '*') emit(target, '*', type, ...args);
-}
-exports.emitOnObject = emitOnObject;
-
-/**
- * Removes an event `listener` for the given event `type` on the given event
- * `target`. If no `listener` is passed removes all listeners of the given
- * `type`. If `type` is not passed removes all the listeners of the given
- * event `target`.
- * @param {Object} target
- * The event target object.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
-function off(target, type, listener) {
- let length = arguments.length;
- if (length === 3) {
- if (onceWeakMap.has(listener)) {
- listener = onceWeakMap.get(listener);
- onceWeakMap.delete(listener);
- }
-
- let listeners = observers(target, type);
- let index = listeners.indexOf(listener);
- if (~index)
- listeners.splice(index, 1);
- }
- else if (length === 2) {
- observers(target, type).splice(0);
- }
- else if (length === 1) {
- let listeners = event(target);
- Object.keys(listeners).forEach(type => delete listeners[type]);
- }
-}
-exports.off = off;
-
-/**
- * Returns a number of event listeners registered for the given event `type`
- * on the given event `target`.
- */
-function count(target, type) {
- return observers(target, type).length;
-}
-exports.count = count;
-
-/**
- * Registers listeners on the given event `target` from the given `listeners`
- * dictionary. Iterates over the listeners and if property name matches name
- * pattern `onEventType` and property is a function, then registers it as
- * an `eventType` listener on `target`.
- *
- * @param {Object} target
- * The type of event.
- * @param {Object} listeners
- * Dictionary of listeners.
- */
-function setListeners(target, listeners) {
- Object.keys(listeners || {}).forEach(key => {
- let match = EVENT_TYPE_PATTERN.exec(key);
- let type = match && match[1].toLowerCase();
- if (!type) return;
-
- let listener = listeners[key];
- if (typeof(listener) === 'function')
- on(target, type, listener);
- });
-}
-exports.setListeners = setListeners;
diff --git a/addon-sdk/source/lib/sdk/event/dom.js b/addon-sdk/source/lib/sdk/event/dom.js
deleted file mode 100644
index da99dec7a..000000000
--- a/addon-sdk/source/lib/sdk/event/dom.js
+++ /dev/null
@@ -1,78 +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");
-
-var { emit } = require("./core");
-var { when: unload } = require("../system/unload");
-var listeners = new WeakMap();
-
-const { Cu } = require("chrome");
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const { ThreadSafeChromeUtils } = Cu.import("resource://gre/modules/Services.jsm", {});
-
-var getWindowFrom = x =>
- x instanceof Ci.nsIDOMWindow ? x :
- x instanceof Ci.nsIDOMDocument ? x.defaultView :
- x instanceof Ci.nsIDOMNode ? x.ownerDocument.defaultView :
- null;
-
-function removeFromListeners() {
- ShimWaiver.getProperty(this, "removeEventListener")("DOMWindowClose", removeFromListeners);
- for (let cleaner of listeners.get(this))
- cleaner();
-
- listeners.delete(this);
-}
-
-// Simple utility function takes event target, event type and optional
-// `options.capture` and returns node style event stream that emits "data"
-// events every time event of that type occurs on the given `target`.
-function open(target, type, options) {
- let output = {};
- let capture = options && options.capture ? true : false;
- let listener = (event) => emit(output, "data", event);
-
- // `open` is currently used only on DOM Window objects, however it was made
- // to be used to any kind of `target` that supports `addEventListener`,
- // therefore is safer get the `window` from the `target` instead assuming
- // that `target` is the `window`.
- let window = getWindowFrom(target);
-
- // If we're not able to get a `window` from `target`, there is something
- // wrong. We cannot add listeners that can leak later, or results in
- // "dead object" exception.
- // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1001833
- if (!window)
- throw new Error("Unable to obtain the owner window from the target given.");
-
- let cleaners = listeners.get(window);
- if (!cleaners) {
- cleaners = [];
- listeners.set(window, cleaners);
-
- // We need to remove from our map the `window` once is closed, to prevent
- // memory leak
- ShimWaiver.getProperty(window, "addEventListener")("DOMWindowClose", removeFromListeners);
- }
-
- cleaners.push(() => ShimWaiver.getProperty(target, "removeEventListener")(type, listener, capture));
- ShimWaiver.getProperty(target, "addEventListener")(type, listener, capture);
-
- return output;
-}
-
-unload(() => {
- let keys = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(listeners)
- for (let window of keys)
- removeFromListeners.call(window);
-});
-
-exports.open = open;
diff --git a/addon-sdk/source/lib/sdk/event/target.js b/addon-sdk/source/lib/sdk/event/target.js
deleted file mode 100644
index 3a1f5e5f0..000000000
--- a/addon-sdk/source/lib/sdk/event/target.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';
-
-module.metadata = {
- "stability": "stable"
-};
-
-const { on, once, off, setListeners } = require('./core');
-const { method, chainable } = require('../lang/functional/core');
-const { Class } = require('../core/heritage');
-
-/**
- * `EventTarget` is an exemplar for creating an objects that can be used to
- * add / remove event listeners on them. Events on these objects may be emitted
- * via `emit` function exported by 'event/core' module.
- */
-const EventTarget = Class({
- /**
- * Method initializes `this` event source. It goes through properties of a
- * given `options` and registers listeners for the ones that look like an
- * event listeners.
- */
- /**
- * Method initializes `this` event source. It goes through properties of a
- * given `options` and registers listeners for the ones that look like an
- * event listeners.
- */
- initialize: function initialize(options) {
- setListeners(this, options);
- },
- /**
- * Registers an event `listener` that is called every time events of
- * specified `type` are emitted.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- * @example
- * worker.on('message', function (data) {
- * console.log('data received: ' + data)
- * })
- */
- on: chainable(method(on)),
- /**
- * Registers an event `listener` that is called once the next time an event
- * of the specified `type` is emitted.
- * @param {String} type
- * The type of the event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
- once: chainable(method(once)),
- /**
- * Removes an event `listener` for the given event `type`.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
- removeListener: function removeListener(type, listener) {
- // Note: We can't just wrap `off` in `method` as we do it for other methods
- // cause skipping a second or third argument will behave very differently
- // than intended. This way we make sure all arguments are passed and only
- // one listener is removed at most.
- off(this, type, listener);
- return this;
- },
- // but we can wrap `off` here, as the semantics are the same
- off: chainable(method(off))
-
-});
-exports.EventTarget = EventTarget;
diff --git a/addon-sdk/source/lib/sdk/event/utils.js b/addon-sdk/source/lib/sdk/event/utils.js
deleted file mode 100644
index f193b6785..000000000
--- a/addon-sdk/source/lib/sdk/event/utils.js
+++ /dev/null
@@ -1,328 +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"
-};
-
-var { emit, on, once, off, EVENT_TYPE_PATTERN } = require("./core");
-const { Cu } = require("chrome");
-
-// This module provides set of high order function for working with event
-// streams (streams in a NodeJS style that dispatch data, end and error
-// events).
-
-// Function takes a `target` object and returns set of implicit references
-// (non property references) it keeps. This basically allows defining
-// references between objects without storing the explicitly. See transform for
-// more details.
-var refs = (function() {
- let refSets = new WeakMap();
- return function refs(target) {
- if (!refSets.has(target)) refSets.set(target, new Set());
- return refSets.get(target);
- };
-})();
-
-function transform(input, f) {
- let output = new Output();
-
- // Since event listeners don't prevent `input` to be GC-ed we wanna presrve
- // it until `output` can be GC-ed. There for we add implicit reference which
- // is removed once `input` ends.
- refs(output).add(input);
-
- const next = data => receive(output, data);
- once(output, "start", () => start(input));
- on(input, "error", error => emit(output, "error", error));
- on(input, "end", function() {
- refs(output).delete(input);
- end(output);
- });
- on(input, "data", data => f(data, next));
- return output;
-}
-
-// High order event transformation function that takes `input` event channel
-// and returns transformation containing only events on which `p` predicate
-// returns `true`.
-function filter(input, predicate) {
- return transform(input, function(data, next) {
- if (predicate(data))
- next(data);
- });
-}
-exports.filter = filter;
-
-// High order function that takes `input` and returns input of it's values
-// mapped via given `f` function.
-const map = (input, f) => transform(input, (data, next) => next(f(data)));
-exports.map = map;
-
-// High order function that takes `input` stream of streams and merges them
-// into single event stream. Like flatten but time based rather than order
-// based.
-function merge(inputs) {
- let output = new Output();
- let open = 1;
- let state = [];
- output.state = state;
- refs(output).add(inputs);
-
- function end(input) {
- open = open - 1;
- refs(output).delete(input);
- if (open === 0) emit(output, "end");
- }
- const error = e => emit(output, "error", e);
- function forward(input) {
- state.push(input);
- open = open + 1;
- on(input, "end", () => end(input));
- on(input, "error", error);
- on(input, "data", data => emit(output, "data", data));
- }
-
- // If `inputs` is an array treat it as a stream.
- if (Array.isArray(inputs)) {
- inputs.forEach(forward);
- end(inputs);
- }
- else {
- on(inputs, "end", () => end(inputs));
- on(inputs, "error", error);
- on(inputs, "data", forward);
- }
-
- return output;
-}
-exports.merge = merge;
-
-const expand = (inputs, f) => merge(map(inputs, f));
-exports.expand = expand;
-
-const pipe = (from, to) => on(from, "*", emit.bind(emit, to));
-exports.pipe = pipe;
-
-
-// Shim signal APIs so other modules can be used as is.
-const receive = (input, message) => {
- if (input[receive])
- input[receive](input, message);
- else
- emit(input, "data", message);
-
- // Ideally our input will extend Input and already provide a weak value
- // getter. If not, opportunistically shim the weak value getter on
- // other types passed as the input.
- if (!("value" in input)) {
- Object.defineProperty(input, "value", WeakValueGetterSetter);
- }
- input.value = message;
-};
-receive.toString = () => "@@receive";
-exports.receive = receive;
-exports.send = receive;
-
-const end = input => {
- if (input[end])
- input[end](input);
- else
- emit(input, "end", input);
-};
-end.toString = () => "@@end";
-exports.end = end;
-
-const stop = input => {
- if (input[stop])
- input[stop](input);
- else
- emit(input, "stop", input);
-};
-stop.toString = () => "@@stop";
-exports.stop = stop;
-
-const start = input => {
- if (input[start])
- input[start](input);
- else
- emit(input, "start", input);
-};
-start.toString = () => "@@start";
-exports.start = start;
-
-const lift = (step, ...inputs) => {
- let args = null;
- let opened = inputs.length;
- let started = false;
- const output = new Output();
- const init = () => {
- args = [...inputs.map(input => input.value)];
- output.value = step(...args);
- };
-
- inputs.forEach((input, index) => {
- on(input, "data", data => {
- args[index] = data;
- receive(output, step(...args));
- });
- on(input, "end", () => {
- opened = opened - 1;
- if (opened <= 0)
- end(output);
- });
- });
-
- once(output, "start", () => {
- inputs.forEach(start);
- init();
- });
-
- init();
-
- return output;
-};
-exports.lift = lift;
-
-const merges = inputs => {
- let opened = inputs.length;
- let output = new Output();
- output.value = inputs[0].value;
- inputs.forEach((input, index) => {
- on(input, "data", data => receive(output, data));
- on(input, "end", () => {
- opened = opened - 1;
- if (opened <= 0)
- end(output);
- });
- });
-
- once(output, "start", () => {
- inputs.forEach(start);
- output.value = inputs[0].value;
- });
-
- return output;
-};
-exports.merges = merges;
-
-const foldp = (step, initial, input) => {
- let output = map(input, x => step(output.value, x));
- output.value = initial;
- return output;
-};
-exports.foldp = foldp;
-
-const keepIf = (p, base, input) => {
- let output = filter(input, p);
- output.value = base;
- return output;
-};
-exports.keepIf = keepIf;
-
-function Input() {}
-Input.start = input => emit(input, "start", input);
-Input.prototype.start = Input.start;
-
-Input.end = input => {
- emit(input, "end", input);
- stop(input);
-};
-Input.prototype[end] = Input.end;
-
-// The event channel system caches the last event seen as input.value.
-// Unfortunately, if the last event is a DOM object this is a great way
-// leak windows. Mitigate this by storing input.value using a weak
-// reference. This allows the system to work for normal event processing
-// while also allowing the objects to be reclaimed. It means, however,
-// input.value cannot be accessed long after the event was dispatched.
-const WeakValueGetterSetter = {
- get: function() {
- return this._weakValue ? this._weakValue.get() : this._simpleValue
- },
- set: function(v) {
- if (v && typeof v === "object") {
- try {
- // Try to set a weak reference. This can throw for some values.
- // For example, if the value is a native object that does not
- // implement nsISupportsWeakReference.
- this._weakValue = Cu.getWeakReference(v)
- this._simpleValue = undefined;
- return;
- } catch (e) {
- // Do nothing. Fall through to setting _simpleValue below.
- }
- }
- this._simpleValue = v;
- this._weakValue = undefined;
- },
-}
-Object.defineProperty(Input.prototype, "value", WeakValueGetterSetter);
-
-exports.Input = Input;
-
-// Define an Output type with a weak value getter for the transformation
-// functions that produce new channels.
-function Output() { }
-Object.defineProperty(Output.prototype, "value", WeakValueGetterSetter);
-exports.Output = Output;
-
-const $source = "@@source";
-const $outputs = "@@outputs";
-exports.outputs = $outputs;
-
-// NOTE: Passing DOM objects through a Reactor can cause them to leak
-// when they get cached in this.value. We cannot use a weak reference
-// in this case because the Reactor design expects to always have both the
-// past and present value. If we allow past values to be collected the
-// system breaks.
-
-function Reactor(options={}) {
- const {onStep, onStart, onEnd} = options;
- if (onStep)
- this.onStep = onStep;
- if (onStart)
- this.onStart = onStart;
- if (onEnd)
- this.onEnd = onEnd;
-}
-Reactor.prototype.onStep = _ => void(0);
-Reactor.prototype.onStart = _ => void(0);
-Reactor.prototype.onEnd = _ => void(0);
-Reactor.prototype.onNext = function(present, past) {
- this.value = present;
- this.onStep(present, past);
-};
-Reactor.prototype.run = function(input) {
- on(input, "data", message => this.onNext(message, input.value));
- on(input, "end", () => this.onEnd(input.value));
- start(input);
- this.value = input.value;
- this.onStart(input.value);
-};
-exports.Reactor = Reactor;
-
-/**
- * Takes an object used as options with potential keys like 'onMessage',
- * used to be called `require('sdk/event/core').setListeners` on.
- * This strips all keys that would trigger a listener to be set.
- *
- * @params {Object} object
- * @return {Object}
- */
-
-function stripListeners (object) {
- return Object.keys(object || {}).reduce((agg, key) => {
- if (!EVENT_TYPE_PATTERN.test(key))
- agg[key] = object[key];
- return agg;
- }, {});
-}
-exports.stripListeners = stripListeners;
-
-const when = (target, type) => new Promise(resolve => {
- once(target, type, resolve);
-});
-exports.when = when;
diff --git a/addon-sdk/source/lib/sdk/frame/hidden-frame.js b/addon-sdk/source/lib/sdk/frame/hidden-frame.js
deleted file mode 100644
index 97e0b7974..000000000
--- a/addon-sdk/source/lib/sdk/frame/hidden-frame.js
+++ /dev/null
@@ -1,115 +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 } = require("chrome");
-const { Class } = require("../core/heritage");
-const { List, addListItem, removeListItem } = require("../util/list");
-const { EventTarget } = require("../event/target");
-const { emit } = require("../event/core");
-const { create: makeFrame } = require("./utils");
-const { defer } = require("../core/promise");
-const { when: unload } = require("../system/unload");
-const { validateOptions, getTypeOf } = require("../deprecated/api-utils");
-const { window } = require("../addon/window");
-const { fromIterator } = require("../util/array");
-
-// This cache is used to access friend properties between functions
-// without exposing them on the public API.
-var cache = new Set();
-var elements = new WeakMap();
-
-function contentLoaded(target) {
- var deferred = defer();
- target.addEventListener("DOMContentLoaded", function DOMContentLoaded(event) {
- // "DOMContentLoaded" events from nested frames propagate up to target,
- // ignore events unless it's DOMContentLoaded for the given target.
- if (event.target === target || event.target === target.contentDocument) {
- target.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
- deferred.resolve(target);
- }
- }, false);
- return deferred.promise;
-}
-
-function FrameOptions(options) {
- options = options || {}
- return validateOptions(options, FrameOptions.validator);
-}
-FrameOptions.validator = {
- onReady: {
- is: ["undefined", "function", "array"],
- ok: function(v) {
- if (getTypeOf(v) === "array") {
- // make sure every item is a function
- return v.every(item => typeof(item) === "function")
- }
- return true;
- }
- },
- onUnload: {
- is: ["undefined", "function"]
- }
-};
-
-var HiddenFrame = Class({
- extends: EventTarget,
- initialize: function initialize(options) {
- options = FrameOptions(options);
- EventTarget.prototype.initialize.call(this, options);
- },
- get element() {
- return elements.get(this);
- },
- toString: function toString() {
- return "[object Frame]"
- }
-});
-exports.HiddenFrame = HiddenFrame
-
-function addHidenFrame(frame) {
- if (!(frame instanceof HiddenFrame))
- throw Error("The object to be added must be a HiddenFrame.");
-
- // This instance was already added.
- if (cache.has(frame)) return frame;
- else cache.add(frame);
-
- let element = makeFrame(window.document, {
- nodeName: "iframe",
- type: "content",
- allowJavascript: true,
- allowPlugins: true,
- allowAuth: true,
- });
- elements.set(frame, element);
-
- contentLoaded(element).then(function onFrameReady(element) {
- emit(frame, "ready");
- }, console.exception);
-
- return frame;
-}
-exports.add = addHidenFrame
-
-function removeHiddenFrame(frame) {
- if (!(frame instanceof HiddenFrame))
- throw Error("The object to be removed must be a HiddenFrame.");
-
- if (!cache.has(frame)) return;
-
- // Remove from cache before calling in order to avoid loop
- cache.delete(frame);
- emit(frame, "unload")
- let element = frame.element
- if (element) element.parentNode.removeChild(element)
-}
-exports.remove = removeHiddenFrame;
-
-unload(() => fromIterator(cache).forEach(removeHiddenFrame));
diff --git a/addon-sdk/source/lib/sdk/frame/utils.js b/addon-sdk/source/lib/sdk/frame/utils.js
deleted file mode 100644
index d9fccec4d..000000000
--- a/addon-sdk/source/lib/sdk/frame/utils.js
+++ /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';
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const { Ci } = require("chrome");
-const XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
-
-function eventTarget(frame) {
- return getDocShell(frame).chromeEventHandler;
-}
-exports.eventTarget = eventTarget;
-
-function getDocShell(frame) {
- let { frameLoader } = frame.QueryInterface(Ci.nsIFrameLoaderOwner);
- return frameLoader && frameLoader.docShell;
-}
-exports.getDocShell = getDocShell;
-
-/**
- * Creates a XUL `browser` element in a privileged document.
- * @params {nsIDOMDocument} document
- * @params {String} options.type
- * By default is 'content' for possible values see:
- * https://developer.mozilla.org/en/XUL/iframe#a-browser.type
- * @params {String} options.uri
- * URI of the document to be loaded into created frame.
- * @params {Boolean} options.remote
- * If `true` separate process will be used for this frame, also in such
- * case all the following options are ignored.
- * @params {Boolean} options.allowAuth
- * Whether to allow auth dialogs. Defaults to `false`.
- * @params {Boolean} options.allowJavascript
- * Whether to allow Javascript execution. Defaults to `false`.
- * @params {Boolean} options.allowPlugins
- * Whether to allow plugin execution. Defaults to `false`.
- */
-function create(target, options) {
- target = target instanceof Ci.nsIDOMDocument ? target.documentElement :
- target instanceof Ci.nsIDOMWindow ? target.document.documentElement :
- target;
- options = options || {};
- let remote = options.remote || false;
- let namespaceURI = options.namespaceURI || XUL;
- let isXUL = namespaceURI === XUL;
- let nodeName = isXUL && options.browser ? 'browser' : 'iframe';
- let document = target.ownerDocument;
-
- let frame = document.createElementNS(namespaceURI, nodeName);
- // Type="content" is mandatory to enable stuff here:
- // http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsFrameLoader.cpp#1776
- frame.setAttribute('type', options.type || 'content');
- frame.setAttribute('src', options.uri || 'about:blank');
-
- // Must set the remote attribute before attaching the frame to the document
- if (remote && isXUL) {
- // We remove XBL binding to avoid execution of code that is not going to
- // work because browser has no docShell attribute in remote mode
- // (for example)
- frame.setAttribute('style', '-moz-binding: none;');
- frame.setAttribute('remote', 'true');
- }
-
- target.appendChild(frame);
-
- // Load in separate process if `options.remote` is `true`.
- // http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsFrameLoader.cpp#1347
- if (remote && !isXUL) {
- frame.QueryInterface(Ci.nsIMozBrowserFrame);
- frame.createRemoteFrameLoader(null);
- }
-
- // If browser is remote it won't have a `docShell`.
- if (!remote) {
- let docShell = getDocShell(frame);
- docShell.allowAuth = options.allowAuth || false;
- docShell.allowJavascript = options.allowJavascript || false;
- docShell.allowPlugins = options.allowPlugins || false;
- docShell.allowWindowControl = options.allowWindowControl || false;
- }
-
- return frame;
-}
-exports.create = create;
-
-function swapFrameLoaders(from, to) {
- return from.QueryInterface(Ci.nsIFrameLoaderOwner).swapFrameLoaders(to);
-}
-exports.swapFrameLoaders = swapFrameLoaders;
diff --git a/addon-sdk/source/lib/sdk/fs/path.js b/addon-sdk/source/lib/sdk/fs/path.js
deleted file mode 100644
index 4474b2b4a..000000000
--- a/addon-sdk/source/lib/sdk/fs/path.js
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// Adapted version of:
-// https://github.com/joyent/node/blob/v0.11.3/lib/path.js
-
-// Shim process global from node.
-var process = Object.create(require('../system'));
-process.cwd = process.pathFor.bind(process, 'CurProcD');
-
-// Update original check in node `process.platform === 'win32'` since in SDK it's `winnt`.
-var isWindows = process.platform.indexOf('win') === 0;
-
-
-
-// resolves . and .. elements in a path array with directory names there
-// must be no slashes, empty elements, or device names (c:\) in the array
-// (so also no leading and trailing slashes - it does not distinguish
-// relative and absolute paths)
-function normalizeArray(parts, allowAboveRoot) {
- // if the path tries to go above the root, `up` ends up > 0
- var up = 0;
- for (var i = parts.length - 1; i >= 0; i--) {
- var last = parts[i];
- if (last === '.') {
- parts.splice(i, 1);
- } else if (last === '..') {
- parts.splice(i, 1);
- up++;
- } else if (up) {
- parts.splice(i, 1);
- up--;
- }
- }
-
- // if the path is allowed to go above the root, restore leading ..s
- if (allowAboveRoot) {
- for (; up--; up) {
- parts.unshift('..');
- }
- }
-
- return parts;
-}
-
-
-if (isWindows) {
- // Regex to split a windows path into three parts: [*, device, slash,
- // tail] windows-only
- var splitDeviceRe =
- /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;
-
- // Regex to split the tail part of the above into [*, dir, basename, ext]
- var splitTailRe =
- /^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/;
-
- // Function to split a filename into [root, dir, basename, ext]
- // windows version
- var splitPath = function(filename) {
- // Separate device+slash from tail
- var result = splitDeviceRe.exec(filename),
- device = (result[1] || '') + (result[2] || ''),
- tail = result[3] || '';
- // Split the tail into dir, basename and extension
- var result2 = splitTailRe.exec(tail),
- dir = result2[1],
- basename = result2[2],
- ext = result2[3];
- return [device, dir, basename, ext];
- };
-
- var normalizeUNCRoot = function(device) {
- return '\\\\' + device.replace(/^[\\\/]+/, '').replace(/[\\\/]+/g, '\\');
- };
-
- // path.resolve([from ...], to)
- // windows version
- exports.resolve = function() {
- var resolvedDevice = '',
- resolvedTail = '',
- resolvedAbsolute = false;
-
- for (var i = arguments.length - 1; i >= -1; i--) {
- var path;
- if (i >= 0) {
- path = arguments[i];
- } else if (!resolvedDevice) {
- path = process.cwd();
- } else {
- // Windows has the concept of drive-specific current working
- // directories. If we've resolved a drive letter but not yet an
- // absolute path, get cwd for that drive. We're sure the device is not
- // an unc path at this points, because unc paths are always absolute.
- path = process.env['=' + resolvedDevice];
- // Verify that a drive-local cwd was found and that it actually points
- // to our drive. If not, default to the drive's root.
- if (!path || path.substr(0, 3).toLowerCase() !==
- resolvedDevice.toLowerCase() + '\\') {
- path = resolvedDevice + '\\';
- }
- }
-
- // Skip empty and invalid entries
- if (typeof path !== 'string') {
- throw new TypeError('Arguments to path.resolve must be strings');
- } else if (!path) {
- continue;
- }
-
- var result = splitDeviceRe.exec(path),
- device = result[1] || '',
- isUnc = device && device.charAt(1) !== ':',
- isAbsolute = exports.isAbsolute(path),
- tail = result[3];
-
- if (device &&
- resolvedDevice &&
- device.toLowerCase() !== resolvedDevice.toLowerCase()) {
- // This path points to another device so it is not applicable
- continue;
- }
-
- if (!resolvedDevice) {
- resolvedDevice = device;
- }
- if (!resolvedAbsolute) {
- resolvedTail = tail + '\\' + resolvedTail;
- resolvedAbsolute = isAbsolute;
- }
-
- if (resolvedDevice && resolvedAbsolute) {
- break;
- }
- }
-
- // Convert slashes to backslashes when `resolvedDevice` points to an UNC
- // root. Also squash multiple slashes into a single one where appropriate.
- if (isUnc) {
- resolvedDevice = normalizeUNCRoot(resolvedDevice);
- }
-
- // At this point the path should be resolved to a full absolute path,
- // but handle relative paths to be safe (might happen when process.cwd()
- // fails)
-
- // Normalize the tail path
-
- function f(p) {
- return !!p;
- }
-
- resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/).filter(f),
- !resolvedAbsolute).join('\\');
-
- return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) ||
- '.';
- };
-
- // windows version
- exports.normalize = function(path) {
- var result = splitDeviceRe.exec(path),
- device = result[1] || '',
- isUnc = device && device.charAt(1) !== ':',
- isAbsolute = exports.isAbsolute(path),
- tail = result[3],
- trailingSlash = /[\\\/]$/.test(tail);
-
- // If device is a drive letter, we'll normalize to lower case.
- if (device && device.charAt(1) === ':') {
- device = device[0].toLowerCase() + device.substr(1);
- }
-
- // Normalize the tail path
- tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) {
- return !!p;
- }), !isAbsolute).join('\\');
-
- if (!tail && !isAbsolute) {
- tail = '.';
- }
- if (tail && trailingSlash) {
- tail += '\\';
- }
-
- // Convert slashes to backslashes when `device` points to an UNC root.
- // Also squash multiple slashes into a single one where appropriate.
- if (isUnc) {
- device = normalizeUNCRoot(device);
- }
-
- return device + (isAbsolute ? '\\' : '') + tail;
- };
-
- // windows version
- exports.isAbsolute = function(path) {
- var result = splitDeviceRe.exec(path),
- device = result[1] || '',
- isUnc = device && device.charAt(1) !== ':';
- // UNC paths are always absolute
- return !!result[2] || isUnc;
- };
-
- // windows version
- exports.join = function() {
- function f(p) {
- if (typeof p !== 'string') {
- throw new TypeError('Arguments to path.join must be strings');
- }
- return p;
- }
-
- var paths = Array.prototype.filter.call(arguments, f);
- var joined = paths.join('\\');
-
- // Make sure that the joined path doesn't start with two slashes, because
- // normalize() will mistake it for an UNC path then.
- //
- // This step is skipped when it is very clear that the user actually
- // intended to point at an UNC path. This is assumed when the first
- // non-empty string arguments starts with exactly two slashes followed by
- // at least one more non-slash character.
- //
- // Note that for normalize() to treat a path as an UNC path it needs to
- // have at least 2 components, so we don't filter for that here.
- // This means that the user can use join to construct UNC paths from
- // a server name and a share name; for example:
- // path.join('//server', 'share') -> '\\\\server\\share\')
- if (!/^[\\\/]{2}[^\\\/]/.test(paths[0])) {
- joined = joined.replace(/^[\\\/]{2,}/, '\\');
- }
-
- return exports.normalize(joined);
- };
-
- // path.relative(from, to)
- // it will solve the relative path from 'from' to 'to', for instance:
- // from = 'C:\\orandea\\test\\aaa'
- // to = 'C:\\orandea\\impl\\bbb'
- // The output of the function should be: '..\\..\\impl\\bbb'
- // windows version
- exports.relative = function(from, to) {
- from = exports.resolve(from);
- to = exports.resolve(to);
-
- // windows is not case sensitive
- var lowerFrom = from.toLowerCase();
- var lowerTo = to.toLowerCase();
-
- function trim(arr) {
- var start = 0;
- for (; start < arr.length; start++) {
- if (arr[start] !== '') break;
- }
-
- var end = arr.length - 1;
- for (; end >= 0; end--) {
- if (arr[end] !== '') break;
- }
-
- if (start > end) return [];
- return arr.slice(start, end - start + 1);
- }
-
- var toParts = trim(to.split('\\'));
-
- var lowerFromParts = trim(lowerFrom.split('\\'));
- var lowerToParts = trim(lowerTo.split('\\'));
-
- var length = Math.min(lowerFromParts.length, lowerToParts.length);
- var samePartsLength = length;
- for (var i = 0; i < length; i++) {
- if (lowerFromParts[i] !== lowerToParts[i]) {
- samePartsLength = i;
- break;
- }
- }
-
- if (samePartsLength == 0) {
- return to;
- }
-
- var outputParts = [];
- for (var i = samePartsLength; i < lowerFromParts.length; i++) {
- outputParts.push('..');
- }
-
- outputParts = outputParts.concat(toParts.slice(samePartsLength));
-
- return outputParts.join('\\');
- };
-
- exports.sep = '\\';
- exports.delimiter = ';';
-
-} else /* posix */ {
-
- // Split a filename into [root, dir, basename, ext], unix version
- // 'root' is just a slash, or nothing.
- var splitPathRe =
- /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
- var splitPath = function(filename) {
- return splitPathRe.exec(filename).slice(1);
- };
-
- // path.resolve([from ...], to)
- // posix version
- exports.resolve = function() {
- var resolvedPath = '',
- resolvedAbsolute = false;
-
- for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
- var path = (i >= 0) ? arguments[i] : process.cwd();
-
- // Skip empty and invalid entries
- if (typeof path !== 'string') {
- throw new TypeError('Arguments to path.resolve must be strings');
- } else if (!path) {
- continue;
- }
-
- resolvedPath = path + '/' + resolvedPath;
- resolvedAbsolute = path.charAt(0) === '/';
- }
-
- // At this point the path should be resolved to a full absolute path, but
- // handle relative paths to be safe (might happen when process.cwd() fails)
-
- // Normalize the path
- resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) {
- return !!p;
- }), !resolvedAbsolute).join('/');
-
- return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
- };
-
- // path.normalize(path)
- // posix version
- exports.normalize = function(path) {
- var isAbsolute = exports.isAbsolute(path),
- trailingSlash = path.substr(-1) === '/';
-
- // Normalize the path
- path = normalizeArray(path.split('/').filter(function(p) {
- return !!p;
- }), !isAbsolute).join('/');
-
- if (!path && !isAbsolute) {
- path = '.';
- }
- if (path && trailingSlash) {
- path += '/';
- }
-
- return (isAbsolute ? '/' : '') + path;
- };
-
- // posix version
- exports.isAbsolute = function(path) {
- return path.charAt(0) === '/';
- };
-
- // posix version
- exports.join = function() {
- var paths = Array.prototype.slice.call(arguments, 0);
- return exports.normalize(paths.filter(function(p, index) {
- if (typeof p !== 'string') {
- throw new TypeError('Arguments to path.join must be strings');
- }
- return p;
- }).join('/'));
- };
-
-
- // path.relative(from, to)
- // posix version
- exports.relative = function(from, to) {
- from = exports.resolve(from).substr(1);
- to = exports.resolve(to).substr(1);
-
- function trim(arr) {
- var start = 0;
- for (; start < arr.length; start++) {
- if (arr[start] !== '') break;
- }
-
- var end = arr.length - 1;
- for (; end >= 0; end--) {
- if (arr[end] !== '') break;
- }
-
- if (start > end) return [];
- return arr.slice(start, end - start + 1);
- }
-
- var fromParts = trim(from.split('/'));
- var toParts = trim(to.split('/'));
-
- var length = Math.min(fromParts.length, toParts.length);
- var samePartsLength = length;
- for (var i = 0; i < length; i++) {
- if (fromParts[i] !== toParts[i]) {
- samePartsLength = i;
- break;
- }
- }
-
- var outputParts = [];
- for (var i = samePartsLength; i < fromParts.length; i++) {
- outputParts.push('..');
- }
-
- outputParts = outputParts.concat(toParts.slice(samePartsLength));
-
- return outputParts.join('/');
- };
-
- exports.sep = '/';
- exports.delimiter = ':';
-}
-
-exports.dirname = function(path) {
- var result = splitPath(path),
- root = result[0],
- dir = result[1];
-
- if (!root && !dir) {
- // No dirname whatsoever
- return '.';
- }
-
- if (dir) {
- // It has a dirname, strip trailing slash
- dir = dir.substr(0, dir.length - 1);
- }
-
- return root + dir;
-};
-
-
-exports.basename = function(path, ext) {
- var f = splitPath(path)[2];
- // TODO: make this comparison case-insensitive on windows?
- if (ext && f.substr(-1 * ext.length) === ext) {
- f = f.substr(0, f.length - ext.length);
- }
- return f;
-};
-
-
-exports.extname = function(path) {
- return splitPath(path)[3];
-};
-
-if (isWindows) {
- exports._makeLong = function(path) {
- // Note: this will *probably* throw somewhere.
- if (typeof path !== 'string')
- return path;
-
- if (!path) {
- return '';
- }
-
- var resolvedPath = exports.resolve(path);
-
- if (/^[a-zA-Z]\:\\/.test(resolvedPath)) {
- // path is local filesystem path, which needs to be converted
- // to long UNC path.
- return '\\\\?\\' + resolvedPath;
- } else if (/^\\\\[^?.]/.test(resolvedPath)) {
- // path is network UNC path, which needs to be converted
- // to long UNC path.
- return '\\\\?\\UNC\\' + resolvedPath.substring(2);
- }
-
- return path;
- };
-} else {
- exports._makeLong = function(path) {
- return path;
- };
-} \ No newline at end of file
diff --git a/addon-sdk/source/lib/sdk/hotkeys.js b/addon-sdk/source/lib/sdk/hotkeys.js
deleted file mode 100644
index 00081455e..000000000
--- a/addon-sdk/source/lib/sdk/hotkeys.js
+++ /dev/null
@@ -1,40 +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 INVALID_HOTKEY = "Hotkey must have at least one modifier.";
-
-const { toJSON: jsonify, toString: stringify,
- isFunctionKey } = require("./keyboard/utils");
-const { register, unregister } = require("./keyboard/hotkeys");
-
-const Hotkey = exports.Hotkey = function Hotkey(options) {
- if (!(this instanceof Hotkey))
- return new Hotkey(options);
-
- // Parsing key combination string.
- let hotkey = jsonify(options.combo);
- if (!isFunctionKey(hotkey.key) && !hotkey.modifiers.length) {
- throw new TypeError(INVALID_HOTKEY);
- }
-
- this.onPress = options.onPress && options.onPress.bind(this);
- this.toString = stringify.bind(null, hotkey);
- // Registering listener on keyboard combination enclosed by this hotkey.
- // Please note that `this.toString()` is a normalized version of
- // `options.combination` where order of modifiers is sorted and `accel` is
- // replaced with platform specific key.
- register(this.toString(), this.onPress);
- // We freeze instance before returning it in order to make it's properties
- // read-only.
- return Object.freeze(this);
-};
-Hotkey.prototype.destroy = function destroy() {
- unregister(this.toString(), this.onPress);
-};
diff --git a/addon-sdk/source/lib/sdk/indexed-db.js b/addon-sdk/source/lib/sdk/indexed-db.js
deleted file mode 100644
index d4d166c02..000000000
--- a/addon-sdk/source/lib/sdk/indexed-db.js
+++ /dev/null
@@ -1,79 +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 } = require("chrome");
-const { id } = require("./self");
-
-// placeholder, copied from bootstrap.js
-var sanitizeId = function(id){
- let uuidRe =
- /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/;
-
- let domain = id.
- toLowerCase().
- replace(/@/g, "-at-").
- replace(/\./g, "-dot-").
- replace(uuidRe, "$1");
-
- return domain
-};
-
-const PSEUDOURI = "indexeddb://" + sanitizeId(id) // https://bugzilla.mozilla.org/show_bug.cgi?id=779197
-
-// Use XPCOM because `require("./url").URL` doesn't expose the raw uri object.
-var principaluri = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService).
- newURI(PSEUDOURI, null, null);
-
-var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
- .getService(Ci.nsIScriptSecurityManager);
-var principal = ssm.createCodebasePrincipal(principaluri, {});
-
-function toArray(args) {
- return Array.prototype.slice.call(args);
-}
-
-function openInternal(args, forPrincipal, deleting) {
- if (forPrincipal) {
- args = toArray(args);
- } else {
- args = [principal].concat(toArray(args));
- }
- if (args.length == 2) {
- args.push({ storage: "persistent" });
- } else if (!deleting && args.length >= 3 && typeof args[2] === "number") {
- args[2] = { version: args[2], storage: "persistent" };
- }
-
- if (deleting) {
- return indexedDB.deleteForPrincipal.apply(indexedDB, args);
- }
-
- return indexedDB.openForPrincipal.apply(indexedDB, args);
-}
-
-exports.indexedDB = Object.freeze({
- open: function () {
- return openInternal(arguments, false, false);
- },
- deleteDatabase: function () {
- return openInternal(arguments, false, true);
- },
- openForPrincipal: function () {
- return openInternal(arguments, true, false);
- },
- deleteForPrincipal: function () {
- return openInternal(arguments, true, true);
- },
- cmp: indexedDB.cmp.bind(indexedDB)
-});
-
-exports.IDBKeyRange = IDBKeyRange;
-exports.DOMException = Ci.nsIDOMDOMException;
diff --git a/addon-sdk/source/lib/sdk/input/browser.js b/addon-sdk/source/lib/sdk/input/browser.js
deleted file mode 100644
index daea875bf..000000000
--- a/addon-sdk/source/lib/sdk/input/browser.js
+++ /dev/null
@@ -1,73 +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 { windows, isBrowser, isInteractive, isDocumentLoaded,
- getOuterId } = require("../window/utils");
-const { InputPort } = require("./system");
-const { lift, merges, foldp, keepIf, start, Input } = require("../event/utils");
-const { patch } = require("diffpatcher/index");
-const { Sequence, seq, filter, object, pairs } = require("../util/sequence");
-
-
-// Create lazy iterators from the regular arrays, although
-// once https://github.com/mozilla/addon-sdk/pull/1314 lands
-// `windows` will be transforme to lazy iterators.
-// When iterated over belowe sequences items will represent
-// state of windows at the time of iteration.
-const opened = seq(function*() {
- const items = windows("navigator:browser", {includePrivate: true});
- for (let item of items) {
- yield [getOuterId(item), item];
- }
-});
-const interactive = filter(([_, window]) => isInteractive(window), opened);
-const loaded = filter(([_, window]) => isDocumentLoaded(window), opened);
-
-// Helper function that converts given argument to a delta.
-const Update = window => window && object([getOuterId(window), window]);
-const Delete = window => window && object([getOuterId(window), null]);
-
-
-// Signal represents delta for last top level window close.
-const LastClosed = lift(Delete,
- keepIf(isBrowser, null,
- new InputPort({topic: "domwindowclosed"})));
-exports.LastClosed = LastClosed;
-
-const windowFor = document => document && document.defaultView;
-
-// Signal represent delta for last top level window document becoming interactive.
-const InteractiveDoc = new InputPort({topic: "chrome-document-interactive"});
-const InteractiveWin = lift(windowFor, InteractiveDoc);
-const LastInteractive = lift(Update, keepIf(isBrowser, null, InteractiveWin));
-exports.LastInteractive = LastInteractive;
-
-// Signal represent delta for last top level window loaded.
-const LoadedDoc = new InputPort({topic: "chrome-document-loaded"});
-const LoadedWin = lift(windowFor, LoadedDoc);
-const LastLoaded = lift(Update, keepIf(isBrowser, null, LoadedWin));
-exports.LastLoaded = LastLoaded;
-
-
-const initialize = input => {
- if (!input.initialized) {
- input.value = object(...input.value);
- Input.start(input);
- input.initialized = true;
- }
-};
-
-// Signal represents set of top level interactive windows, updated any
-// time new window becomes interactive or one get's closed.
-const Interactive = foldp(patch, interactive, merges([LastInteractive,
- LastClosed]));
-Interactive[start] = initialize;
-exports.Interactive = Interactive;
-
-// Signal represents set of top level loaded window, updated any time
-// new window becomes interactive or one get's closed.
-const Loaded = foldp(patch, loaded, merges([LastLoaded, LastClosed]));
-Loaded[start] = initialize;
-exports.Loaded = Loaded;
diff --git a/addon-sdk/source/lib/sdk/input/customizable-ui.js b/addon-sdk/source/lib/sdk/input/customizable-ui.js
deleted file mode 100644
index a41d0971a..000000000
--- a/addon-sdk/source/lib/sdk/input/customizable-ui.js
+++ /dev/null
@@ -1,28 +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 { Cu } = require("chrome");
-const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
-const { receive } = require("../event/utils");
-const { InputPort } = require("./system");
-const { object} = require("../util/sequence");
-const { getOuterId } = require("../window/utils");
-
-const Input = function() {};
-Input.prototype = Object.create(InputPort.prototype);
-
-Input.prototype.onCustomizeStart = function (window) {
- receive(this, object([getOuterId(window), true]));
-}
-
-Input.prototype.onCustomizeEnd = function (window) {
- receive(this, object([getOuterId(window), null]));
-}
-
-Input.prototype.addListener = input => CustomizableUI.addListener(input);
-
-Input.prototype.removeListener = input => CustomizableUI.removeListener(input);
-
-exports.CustomizationInput = Input;
diff --git a/addon-sdk/source/lib/sdk/input/frame.js b/addon-sdk/source/lib/sdk/input/frame.js
deleted file mode 100644
index 50efaa745..000000000
--- a/addon-sdk/source/lib/sdk/input/frame.js
+++ /dev/null
@@ -1,85 +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 { InputPort } = require("./system");
-const { getFrameElement, getOuterId,
- getOwnerBrowserWindow } = require("../window/utils");
-const { isnt } = require("../lang/functional");
-const { foldp, lift, merges, keepIf } = require("../event/utils");
-const { object } = require("../util/sequence");
-const { compose } = require("../lang/functional");
-const { LastClosed } = require("./browser");
-const { patch } = require("diffpatcher/index");
-
-const Document = Ci.nsIDOMDocument;
-
-const isntNull = isnt(null);
-
-const frameID = frame => frame.id;
-const browserID = compose(getOuterId, getOwnerBrowserWindow);
-
-const isInnerFrame = frame =>
- frame && frame.hasAttribute("data-is-sdk-inner-frame");
-
-// Utility function that given content window loaded in our frame views returns
-// an actual frame. This basically takes care of fact that actual frame document
-// is loaded in the nested iframe. If content window is not loaded in the nested
-// frame of the frame view it returs null.
-const getFrame = document =>
- document && document.defaultView && getFrameElement(document.defaultView);
-
-const FrameInput = function(options) {
- const input = keepIf(isInnerFrame, null,
- lift(getFrame, new InputPort(options)));
- return lift(frame => {
- if (!frame) return frame;
- const [id, owner] = [frameID(frame), browserID(frame)];
- return object([id, {owners: object([owner, options.update])}]);
- }, input);
-};
-
-const LastLoading = new FrameInput({topic: "document-element-inserted",
- update: {readyState: "loading"}});
-exports.LastLoading = LastLoading;
-
-const LastInteractive = new FrameInput({topic: "content-document-interactive",
- update: {readyState: "interactive"}});
-exports.LastInteractive = LastInteractive;
-
-const LastLoaded = new FrameInput({topic: "content-document-loaded",
- update: {readyState: "complete"}});
-exports.LastLoaded = LastLoaded;
-
-const LastUnloaded = new FrameInput({topic: "content-page-hidden",
- update: null});
-exports.LastUnloaded = LastUnloaded;
-
-// Represents state of SDK frames in form of data structure:
-// {"frame#1": {"id": "frame#1",
-// "inbox": {"data": "ping",
-// "target": {"id": "frame#1", "owner": "outerWindowID#2"},
-// "source": {"id": "frame#1"}}
-// "url": "resource://addon-1/data/index.html",
-// "owners": {"outerWindowID#1": {"readyState": "loading"},
-// "outerWindowID#2": {"readyState": "complete"}}
-//
-//
-// frame#2: {"id": "frame#2",
-// "url": "resource://addon-1/data/main.html",
-// "outbox": {"data": "pong",
-// "source": {"id": "frame#2", "owner": "outerWindowID#1"}
-// "target": {"id": "frame#2"}}
-// "owners": {outerWindowID#1: {readyState: "interacitve"}}}}
-const Frames = foldp(patch, {}, merges([
- LastLoading,
- LastInteractive,
- LastLoaded,
- LastUnloaded,
- new InputPort({ id: "frame-mailbox" }),
- new InputPort({ id: "frame-change" }),
- new InputPort({ id: "frame-changed" })
-]));
-exports.Frames = Frames;
diff --git a/addon-sdk/source/lib/sdk/input/system.js b/addon-sdk/source/lib/sdk/input/system.js
deleted file mode 100644
index 66bc6daec..000000000
--- a/addon-sdk/source/lib/sdk/input/system.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";
-
-const { Cc, Ci, Cr, Cu } = require("chrome");
-const { Input, start, stop, end, receive, outputs } = require("../event/utils");
-const { once, off } = require("../event/core");
-const { id: addonID } = require("../self");
-
-const unloadMessage = require("@loader/unload");
-const observerService = Cc['@mozilla.org/observer-service;1'].
- getService(Ci.nsIObserverService);
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const addObserver = ShimWaiver.getProperty(observerService, "addObserver");
-const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver");
-
-
-const addonUnloadTopic = "sdk:loader:destroy";
-
-const isXrayWrapper = Cu.isXrayWrapper;
-// In the past SDK used to double-wrap notifications dispatched, which
-// made them awkward to use outside of SDK. At present they no longer
-// do that, although we still supported for legacy reasons.
-const isLegacyWrapper = x =>
- x && x.wrappedJSObject &&
- "observersModuleSubjectWrapper" in x.wrappedJSObject;
-
-const unwrapLegacy = x => x.wrappedJSObject.object;
-
-// `InputPort` provides a way to create a signal out of the observer
-// notification subject's for the given `topic`. If `options.initial`
-// is provided it is used as initial value otherwise `null` is used.
-// Constructor can be given `options.id` that will be used to create
-// a `topic` which is namespaced to an add-on (this avoids conflicts
-// when multiple add-on are used, although in a future host probably
-// should just be shared across add-ons). It is also possible to
-// specify a specific `topic` via `options.topic` which is used as
-// without namespacing. Created signal ends whenever add-on is
-// unloaded.
-const InputPort = function InputPort({id, topic, initial}) {
- this.id = id || topic;
- this.topic = topic || "sdk:" + addonID + ":" + id;
- this.value = initial === void(0) ? null : initial;
- this.observing = false;
- this[outputs] = [];
-};
-
-// InputPort type implements `Input` signal interface.
-InputPort.prototype = new Input();
-InputPort.prototype.constructor = InputPort;
-
-// When port is started (which is when it's subgraph get's
-// first subscriber) actual observer is registered.
-InputPort.start = input => {
- input.addListener(input);
- // Also register add-on unload observer to end this signal
- // when that happens.
- addObserver(input, addonUnloadTopic, false);
-};
-InputPort.prototype[start] = InputPort.start;
-
-InputPort.addListener = input => addObserver(input, input.topic, false);
-InputPort.prototype.addListener = InputPort.addListener;
-
-// When port is stopped (which is when it's subgraph has no
-// no subcribers left) an actual observer unregistered.
-// Note that port stopped once it ends as well (which is when
-// add-on is unloaded).
-InputPort.stop = input => {
- input.removeListener(input);
- removeObserver(input, addonUnloadTopic);
-};
-InputPort.prototype[stop] = InputPort.stop;
-
-InputPort.removeListener = input => removeObserver(input, input.topic);
-InputPort.prototype.removeListener = InputPort.removeListener;
-
-// `InputPort` also implements `nsIObserver` interface and
-// `nsISupportsWeakReference` interfaces as it's going to be used as such.
-InputPort.prototype.QueryInterface = function(iid) {
- if (!iid.equals(Ci.nsIObserver) && !iid.equals(Ci.nsISupportsWeakReference))
- throw Cr.NS_ERROR_NO_INTERFACE;
-
- return this;
-};
-
-// `InputPort` instances implement `observe` method, which is invoked when
-// observer notifications are dispatched. The `subject` of that notification
-// are received on this signal.
-InputPort.prototype.observe = function(subject, topic, data) {
- // Unwrap message from the subject. SDK used to have it's own version of
- // wrappedJSObjects which take precedence, if subject has `wrappedJSObject`
- // and it's not an XrayWrapper use it as message. Otherwise use subject as
- // is.
- const message = subject === null ? null :
- isLegacyWrapper(subject) ? unwrapLegacy(subject) :
- isXrayWrapper(subject) ? subject :
- subject.wrappedJSObject ? subject.wrappedJSObject :
- subject;
-
- // If observer topic matches topic of the input port receive a message.
- if (topic === this.topic) {
- receive(this, message);
- }
-
- // If observe topic is add-on unload topic we create an end message.
- if (topic === addonUnloadTopic && message === unloadMessage) {
- end(this);
- }
-};
-
-exports.InputPort = InputPort;
diff --git a/addon-sdk/source/lib/sdk/io/buffer.js b/addon-sdk/source/lib/sdk/io/buffer.js
deleted file mode 100644
index 5ea169402..000000000
--- a/addon-sdk/source/lib/sdk/io/buffer.js
+++ /dev/null
@@ -1,351 +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'
-};
-
-/*
- * Encodings supported by TextEncoder/Decoder:
- * utf-8, utf-16le, utf-16be
- * http://encoding.spec.whatwg.org/#interface-textencoder
- *
- * Node however supports the following encodings:
- * ascii, utf-8, utf-16le, usc2, base64, hex
- */
-
-const { Cu } = require('chrome');
-const { isNumber } = require('sdk/lang/type');
-const { TextEncoder, TextDecoder } = Cu.import('resource://gre/modules/commonjs/toolkit/loader.js', {});
-
-exports.TextEncoder = TextEncoder;
-exports.TextDecoder = TextDecoder;
-
-/**
- * Use WeakMaps to work around Bug 929146, which prevents us from adding
- * getters or values to typed arrays
- * https://bugzilla.mozilla.org/show_bug.cgi?id=929146
- */
-const parents = new WeakMap();
-const views = new WeakMap();
-
-function Buffer(subject, encoding /*, bufferLength */) {
-
- // Allow invocation without `new` constructor
- if (!(this instanceof Buffer))
- return new Buffer(subject, encoding, arguments[2]);
-
- var type = typeof(subject);
-
- switch (type) {
- case 'number':
- // Create typed array of the given size if number.
- try {
- let buffer = new Uint8Array(subject > 0 ? Math.floor(subject) : 0);
- return buffer;
- } catch (e) {
- if (/size and count too large/.test(e.message) ||
- /invalid arguments/.test(e.message))
- throw new RangeError('Could not instantiate buffer: size of buffer may be too large');
- else
- throw new Error('Could not instantiate buffer');
- }
- break;
- case 'string':
- // If string encode it and use buffer for the returned Uint8Array
- // to create a local patched version that acts like node buffer.
- encoding = encoding || 'utf8';
- return new Uint8Array(new TextEncoder(encoding).encode(subject).buffer);
- case 'object':
- // This form of the constructor uses the form of
- // new Uint8Array(buffer, offset, length);
- // So we can instantiate a typed array within the constructor
- // to inherit the appropriate properties, where both the
- // `subject` and newly instantiated buffer share the same underlying
- // data structure.
- if (arguments.length === 3)
- return new Uint8Array(subject, encoding, arguments[2]);
- // If array or alike just make a copy with a local patched prototype.
- else
- return new Uint8Array(subject);
- default:
- throw new TypeError('must start with number, buffer, array or string');
- }
-}
-exports.Buffer = Buffer;
-
-// Tests if `value` is a Buffer.
-Buffer.isBuffer = value => value instanceof Buffer
-
-// Returns true if the encoding is a valid encoding argument & false otherwise
-Buffer.isEncoding = function (encoding) {
- if (!encoding) return false;
- try {
- new TextDecoder(encoding);
- } catch(e) {
- return false;
- }
- return true;
-}
-
-// Gives the actual byte length of a string. encoding defaults to 'utf8'.
-// This is not the same as String.prototype.length since that returns the
-// number of characters in a string.
-Buffer.byteLength = (value, encoding = 'utf8') =>
- new TextEncoder(encoding).encode(value).byteLength
-
-// Direct copy of the nodejs's buffer implementation:
-// https://github.com/joyent/node/blob/b255f4c10a80343f9ce1cee56d0288361429e214/lib/buffer.js#L146-L177
-Buffer.concat = function(list, length) {
- if (!Array.isArray(list))
- throw new TypeError('Usage: Buffer.concat(list[, length])');
-
- if (typeof length === 'undefined') {
- length = 0;
- for (var i = 0; i < list.length; i++)
- length += list[i].length;
- } else {
- length = ~~length;
- }
-
- if (length < 0)
- length = 0;
-
- if (list.length === 0)
- return new Buffer(0);
- else if (list.length === 1)
- return list[0];
-
- if (length < 0)
- throw new RangeError('length is not a positive number');
-
- var buffer = new Buffer(length);
- var pos = 0;
- for (var i = 0; i < list.length; i++) {
- var buf = list[i];
- buf.copy(buffer, pos);
- pos += buf.length;
- }
-
- return buffer;
-};
-
-// Node buffer is very much like Uint8Array although it has bunch of methods
-// that typically can be used in combination with `DataView` while preserving
-// access by index. Since in SDK each module has it's own set of bult-ins it
-// ok to patch ours to make it nodejs Buffer compatible.
-const Uint8ArraySet = Uint8Array.prototype.set
-Buffer.prototype = Uint8Array.prototype;
-Object.defineProperties(Buffer.prototype, {
- parent: {
- get: function() { return parents.get(this, undefined); }
- },
- view: {
- get: function () {
- let view = views.get(this, undefined);
- if (view) return view;
- view = new DataView(this.buffer);
- views.set(this, view);
- return view;
- }
- },
- toString: {
- value: function(encoding, start, end) {
- encoding = !!encoding ? (encoding + '').toLowerCase() : 'utf8';
- start = Math.max(0, ~~start);
- end = Math.min(this.length, end === void(0) ? this.length : ~~end);
- return new TextDecoder(encoding).decode(this.subarray(start, end));
- }
- },
- toJSON: {
- value: function() {
- return { type: 'Buffer', data: Array.slice(this, 0) };
- }
- },
- get: {
- value: function(offset) {
- return this[offset];
- }
- },
- set: {
- value: function(offset, value) { this[offset] = value; }
- },
- copy: {
- value: function(target, offset, start, end) {
- let length = this.length;
- let targetLength = target.length;
- offset = isNumber(offset) ? offset : 0;
- start = isNumber(start) ? start : 0;
-
- if (start < 0)
- throw new RangeError('sourceStart is outside of valid range');
- if (end < 0)
- throw new RangeError('sourceEnd is outside of valid range');
-
- // If sourceStart > sourceEnd, or targetStart > targetLength,
- // zero bytes copied
- if (start > end ||
- offset > targetLength
- )
- return 0;
-
- // If `end` is not defined, or if it is defined
- // but would overflow `target`, redefine `end`
- // so we can copy as much as we can
- if (end - start > targetLength - offset ||
- end == null) {
- let remainingTarget = targetLength - offset;
- let remainingSource = length - start;
- if (remainingSource <= remainingTarget)
- end = length;
- else
- end = start + remainingTarget;
- }
-
- Uint8ArraySet.call(target, this.subarray(start, end), offset);
- return end - start;
- }
- },
- slice: {
- value: function(start, end) {
- let length = this.length;
- start = ~~start;
- end = end != null ? end : length;
-
- if (start < 0) {
- start += length;
- if (start < 0) start = 0;
- } else if (start > length)
- start = length;
-
- if (end < 0) {
- end += length;
- if (end < 0) end = 0;
- } else if (end > length)
- end = length;
-
- if (end < start)
- end = start;
-
- // This instantiation uses the new Uint8Array(buffer, offset, length) version
- // of construction to share the same underling data structure
- let buffer = new Buffer(this.buffer, start, end - start);
-
- // If buffer has a value, assign its parent value to the
- // buffer it shares its underlying structure with. If a slice of
- // a slice, then use the root structure
- if (buffer.length > 0)
- parents.set(buffer, this.parent || this);
-
- return buffer;
- }
- },
- write: {
- value: function(string, offset, length, encoding = 'utf8') {
- // write(string, encoding);
- if (typeof(offset) === 'string' && Number.isNaN(parseInt(offset))) {
- [offset, length, encoding] = [0, null, offset];
- }
- // write(string, offset, encoding);
- else if (typeof(length) === 'string')
- [length, encoding] = [null, length];
-
- if (offset < 0 || offset > this.length)
- throw new RangeError('offset is outside of valid range');
-
- offset = ~~offset;
-
- // Clamp length if it would overflow buffer, or if its
- // undefined
- if (length == null || length + offset > this.length)
- length = this.length - offset;
-
- let buffer = new TextEncoder(encoding).encode(string);
- let result = Math.min(buffer.length, length);
- if (buffer.length !== length)
- buffer = buffer.subarray(0, length);
-
- Uint8ArraySet.call(this, buffer, offset);
- return result;
- }
- },
- fill: {
- value: function fill(value, start, end) {
- let length = this.length;
- value = value || 0;
- start = start || 0;
- end = end || length;
-
- if (typeof(value) === 'string')
- value = value.charCodeAt(0);
- if (typeof(value) !== 'number' || isNaN(value))
- throw TypeError('value is not a number');
- if (end < start)
- throw new RangeError('end < start');
-
- // Fill 0 bytes; we're done
- if (end === start)
- return 0;
- if (length == 0)
- return 0;
-
- if (start < 0 || start >= length)
- throw RangeError('start out of bounds');
-
- if (end < 0 || end > length)
- throw RangeError('end out of bounds');
-
- let index = start;
- while (index < end) this[index++] = value;
- }
- }
-});
-
-// Define nodejs Buffer's getter and setter functions that just proxy
-// to internal DataView's equivalent methods.
-
-// TODO do we need to check architecture to see if it's default big/little endian?
-[['readUInt16LE', 'getUint16', true],
- ['readUInt16BE', 'getUint16', false],
- ['readInt16LE', 'getInt16', true],
- ['readInt16BE', 'getInt16', false],
- ['readUInt32LE', 'getUint32', true],
- ['readUInt32BE', 'getUint32', false],
- ['readInt32LE', 'getInt32', true],
- ['readInt32BE', 'getInt32', false],
- ['readFloatLE', 'getFloat32', true],
- ['readFloatBE', 'getFloat32', false],
- ['readDoubleLE', 'getFloat64', true],
- ['readDoubleBE', 'getFloat64', false],
- ['readUInt8', 'getUint8'],
- ['readInt8', 'getInt8']].forEach(([alias, name, littleEndian]) => {
- Object.defineProperty(Buffer.prototype, alias, {
- value: function(offset) {
- return this.view[name](offset, littleEndian);
- }
- });
-});
-
-[['writeUInt16LE', 'setUint16', true],
- ['writeUInt16BE', 'setUint16', false],
- ['writeInt16LE', 'setInt16', true],
- ['writeInt16BE', 'setInt16', false],
- ['writeUInt32LE', 'setUint32', true],
- ['writeUInt32BE', 'setUint32', false],
- ['writeInt32LE', 'setInt32', true],
- ['writeInt32BE', 'setInt32', false],
- ['writeFloatLE', 'setFloat32', true],
- ['writeFloatBE', 'setFloat32', false],
- ['writeDoubleLE', 'setFloat64', true],
- ['writeDoubleBE', 'setFloat64', false],
- ['writeUInt8', 'setUint8'],
- ['writeInt8', 'setInt8']].forEach(([alias, name, littleEndian]) => {
- Object.defineProperty(Buffer.prototype, alias, {
- value: function(value, offset) {
- return this.view[name](offset, value, littleEndian);
- }
- });
-});
diff --git a/addon-sdk/source/lib/sdk/io/byte-streams.js b/addon-sdk/source/lib/sdk/io/byte-streams.js
deleted file mode 100644
index 6afab4369..000000000
--- a/addon-sdk/source/lib/sdk/io/byte-streams.js
+++ /dev/null
@@ -1,104 +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"
-};
-
-exports.ByteReader = ByteReader;
-exports.ByteWriter = ByteWriter;
-
-const {Cc, Ci} = require("chrome");
-
-// This just controls the maximum number of bytes we read in at one time.
-const BUFFER_BYTE_LEN = 0x8000;
-
-function ByteReader(inputStream) {
- const self = this;
-
- let stream = Cc["@mozilla.org/binaryinputstream;1"].
- createInstance(Ci.nsIBinaryInputStream);
- stream.setInputStream(inputStream);
-
- let manager = new StreamManager(this, stream);
-
- this.read = function ByteReader_read(numBytes) {
- manager.ensureOpened();
- if (typeof(numBytes) !== "number")
- numBytes = Infinity;
-
- let data = "";
- let read = 0;
- try {
- while (true) {
- let avail = stream.available();
- let toRead = Math.min(numBytes - read, avail, BUFFER_BYTE_LEN);
- if (toRead <= 0)
- break;
- data += stream.readBytes(toRead);
- read += toRead;
- }
- }
- catch (err) {
- throw new Error("Error reading from stream: " + err);
- }
-
- return data;
- };
-}
-
-function ByteWriter(outputStream) {
- const self = this;
-
- let stream = Cc["@mozilla.org/binaryoutputstream;1"].
- createInstance(Ci.nsIBinaryOutputStream);
- stream.setOutputStream(outputStream);
-
- let manager = new StreamManager(this, stream);
-
- this.write = function ByteWriter_write(str) {
- manager.ensureOpened();
- try {
- stream.writeBytes(str, str.length);
- }
- catch (err) {
- throw new Error("Error writing to stream: " + err);
- }
- };
-}
-
-
-// This manages the lifetime of stream, a ByteReader or ByteWriter. It defines
-// closed and close() on stream and registers an unload listener that closes
-// rawStream if it's still opened. It also provides ensureOpened(), which
-// throws an exception if the stream is closed.
-function StreamManager(stream, rawStream) {
- const self = this;
- this.rawStream = rawStream;
- this.opened = true;
-
- stream.__defineGetter__("closed", function stream_closed() {
- return !self.opened;
- });
-
- stream.close = function stream_close() {
- self.ensureOpened();
- self.unload();
- };
-
- require("../system/unload").ensure(this);
-}
-
-StreamManager.prototype = {
- ensureOpened: function StreamManager_ensureOpened() {
- if (!this.opened)
- throw new Error("The stream is closed and cannot be used.");
- },
- unload: function StreamManager_unload() {
- this.rawStream.close();
- this.opened = false;
- }
-};
diff --git a/addon-sdk/source/lib/sdk/io/file.js b/addon-sdk/source/lib/sdk/io/file.js
deleted file mode 100644
index 47467df87..000000000
--- a/addon-sdk/source/lib/sdk/io/file.js
+++ /dev/null
@@ -1,196 +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 {Cc,Ci,Cr} = require("chrome");
-const byteStreams = require("./byte-streams");
-const textStreams = require("./text-streams");
-
-// Flags passed when opening a file. See nsprpub/pr/include/prio.h.
-const OPEN_FLAGS = {
- RDONLY: parseInt("0x01"),
- WRONLY: parseInt("0x02"),
- CREATE_FILE: parseInt("0x08"),
- APPEND: parseInt("0x10"),
- TRUNCATE: parseInt("0x20"),
- EXCL: parseInt("0x80")
-};
-
-var dirsvc = Cc["@mozilla.org/file/directory_service;1"]
- .getService(Ci.nsIProperties);
-
-function MozFile(path) {
- var file = Cc['@mozilla.org/file/local;1']
- .createInstance(Ci.nsILocalFile);
- file.initWithPath(path);
- return file;
-}
-
-function ensureReadable(file) {
- if (!file.isReadable())
- throw new Error("path is not readable: " + file.path);
-}
-
-function ensureDir(file) {
- ensureExists(file);
- if (!file.isDirectory())
- throw new Error("path is not a directory: " + file.path);
-}
-
-function ensureFile(file) {
- ensureExists(file);
- if (!file.isFile())
- throw new Error("path is not a file: " + file.path);
-}
-
-function ensureExists(file) {
- if (!file.exists())
- throw friendlyError(Cr.NS_ERROR_FILE_NOT_FOUND, file.path);
-}
-
-function friendlyError(errOrResult, filename) {
- var isResult = typeof(errOrResult) === "number";
- var result = isResult ? errOrResult : errOrResult.result;
- switch (result) {
- case Cr.NS_ERROR_FILE_NOT_FOUND:
- return new Error("path does not exist: " + filename);
- }
- return isResult ? new Error("XPCOM error code: " + errOrResult) : errOrResult;
-}
-
-exports.exists = function exists(filename) {
- return MozFile(filename).exists();
-};
-
-exports.isFile = function isFile(filename) {
- return MozFile(filename).isFile();
-};
-
-exports.read = function read(filename, mode) {
- if (typeof(mode) !== "string")
- mode = "";
-
- // Ensure mode is read-only.
- mode = /b/.test(mode) ? "b" : "";
-
- var stream = exports.open(filename, mode);
- try {
- var str = stream.read();
- }
- finally {
- stream.close();
- }
-
- return str;
-};
-
-exports.join = function join(base) {
- if (arguments.length < 2)
- throw new Error("need at least 2 args");
- base = MozFile(base);
- for (var i = 1; i < arguments.length; i++)
- base.append(arguments[i]);
- return base.path;
-};
-
-exports.dirname = function dirname(path) {
- var parent = MozFile(path).parent;
- return parent ? parent.path : "";
-};
-
-exports.basename = function basename(path) {
- var leafName = MozFile(path).leafName;
-
- // On Windows, leafName when the path is a volume letter and colon ("c:") is
- // the path itself. But such a path has no basename, so we want the empty
- // string.
- return leafName == path ? "" : leafName;
-};
-
-exports.list = function list(path) {
- var file = MozFile(path);
- ensureDir(file);
- ensureReadable(file);
-
- var entries = file.directoryEntries;
- var entryNames = [];
- while(entries.hasMoreElements()) {
- var entry = entries.getNext();
- entry.QueryInterface(Ci.nsIFile);
- entryNames.push(entry.leafName);
- }
- return entryNames;
-};
-
-exports.open = function open(filename, mode) {
- var file = MozFile(filename);
- if (typeof(mode) !== "string")
- mode = "";
-
- // File opened for write only.
- if (/w/.test(mode)) {
- if (file.exists())
- ensureFile(file);
- var stream = Cc['@mozilla.org/network/file-output-stream;1'].
- createInstance(Ci.nsIFileOutputStream);
- var openFlags = OPEN_FLAGS.WRONLY |
- OPEN_FLAGS.CREATE_FILE |
- OPEN_FLAGS.TRUNCATE;
- var permFlags = 0o644; // u+rw go+r
- try {
- stream.init(file, openFlags, permFlags, 0);
- }
- catch (err) {
- throw friendlyError(err, filename);
- }
- return /b/.test(mode) ?
- new byteStreams.ByteWriter(stream) :
- new textStreams.TextWriter(stream);
- }
-
- // File opened for read only, the default.
- ensureFile(file);
- stream = Cc['@mozilla.org/network/file-input-stream;1'].
- createInstance(Ci.nsIFileInputStream);
- try {
- stream.init(file, OPEN_FLAGS.RDONLY, 0, 0);
- }
- catch (err) {
- throw friendlyError(err, filename);
- }
- return /b/.test(mode) ?
- new byteStreams.ByteReader(stream) :
- new textStreams.TextReader(stream);
-};
-
-exports.remove = function remove(path) {
- var file = MozFile(path);
- ensureFile(file);
- file.remove(false);
-};
-
-exports.mkpath = function mkpath(path) {
- var file = MozFile(path);
- if (!file.exists())
- file.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); // u+rwx go+rx
- else if (!file.isDirectory())
- throw new Error("The path already exists and is not a directory: " + path);
-};
-
-exports.rmdir = function rmdir(path) {
- var file = MozFile(path);
- ensureDir(file);
- try {
- file.remove(false);
- }
- catch (err) {
- // Bug 566950 explains why we're not catching a specific exception here.
- throw new Error("The directory is not empty: " + path);
- }
-};
diff --git a/addon-sdk/source/lib/sdk/io/fs.js b/addon-sdk/source/lib/sdk/io/fs.js
deleted file mode 100644
index 860a884a5..000000000
--- a/addon-sdk/source/lib/sdk/io/fs.js
+++ /dev/null
@@ -1,984 +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 } = require("chrome");
-
-const { setTimeout } = require("../timers");
-const { Stream, InputStream, OutputStream } = require("./stream");
-const { emit, on } = require("../event/core");
-const { Buffer } = require("./buffer");
-const { ns } = require("../core/namespace");
-const { Class } = require("../core/heritage");
-
-
-const nsILocalFile = CC("@mozilla.org/file/local;1", "nsILocalFile",
- "initWithPath");
-const FileOutputStream = CC("@mozilla.org/network/file-output-stream;1",
- "nsIFileOutputStream", "init");
-const FileInputStream = CC("@mozilla.org/network/file-input-stream;1",
- "nsIFileInputStream", "init");
-const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
- "nsIBinaryInputStream", "setInputStream");
-const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
- "nsIBinaryOutputStream", "setOutputStream");
-const StreamPump = CC("@mozilla.org/network/input-stream-pump;1",
- "nsIInputStreamPump", "init");
-
-const { createOutputTransport, createInputTransport } =
- Cc["@mozilla.org/network/stream-transport-service;1"].
- getService(Ci.nsIStreamTransportService);
-
-const { OPEN_UNBUFFERED } = Ci.nsITransport;
-
-
-const { REOPEN_ON_REWIND, DEFER_OPEN } = Ci.nsIFileInputStream;
-const { DIRECTORY_TYPE, NORMAL_FILE_TYPE } = Ci.nsIFile;
-const { NS_SEEK_SET, NS_SEEK_CUR, NS_SEEK_END } = Ci.nsISeekableStream;
-
-const FILE_PERMISSION = 0o666;
-const PR_UINT32_MAX = 0xfffffff;
-// Values taken from:
-// http://mxr.mozilla.org/mozilla-central/source/nsprpub/pr/include/prio.h#615
-const PR_RDONLY = 0x01;
-const PR_WRONLY = 0x02;
-const PR_RDWR = 0x04;
-const PR_CREATE_FILE = 0x08;
-const PR_APPEND = 0x10;
-const PR_TRUNCATE = 0x20;
-const PR_SYNC = 0x40;
-const PR_EXCL = 0x80;
-
-const FLAGS = {
- "r": PR_RDONLY,
- "r+": PR_RDWR,
- "w": PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY,
- "w+": PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR,
- "a": PR_APPEND | PR_CREATE_FILE | PR_WRONLY,
- "a+": PR_APPEND | PR_CREATE_FILE | PR_RDWR
-};
-
-function accessor() {
- let map = new WeakMap();
- return function(fd, value) {
- if (value === null) map.delete(fd);
- if (value !== undefined) map.set(fd, value);
- return map.get(fd);
- }
-}
-
-var nsIFile = accessor();
-var nsIFileInputStream = accessor();
-var nsIFileOutputStream = accessor();
-var nsIBinaryInputStream = accessor();
-var nsIBinaryOutputStream = accessor();
-
-// Just a contstant object used to signal that all of the file
-// needs to be read.
-const ALL = new String("Read all of the file");
-
-function isWritable(mode) {
- return !!(mode & PR_WRONLY || mode & PR_RDWR);
-}
-function isReadable(mode) {
- return !!(mode & PR_RDONLY || mode & PR_RDWR);
-}
-
-function isString(value) {
- return typeof(value) === "string";
-}
-function isFunction(value) {
- return typeof(value) === "function";
-}
-
-function toArray(enumerator) {
- let value = [];
- while(enumerator.hasMoreElements())
- value.push(enumerator.getNext())
- return value
-}
-
-function getFileName(file) {
- return file.QueryInterface(Ci.nsIFile).leafName;
-}
-
-
-function remove(path, recursive) {
- let fd = new nsILocalFile(path)
- if (fd.exists()) {
- fd.remove(recursive || false);
- }
- else {
- throw FSError("remove", "ENOENT", 34, path);
- }
-}
-
-/**
- * Utility function to convert either an octal number or string
- * into an octal number
- * 0777 => 0o777
- * "0644" => 0o644
- */
-function Mode(mode, fallback) {
- return isString(mode) ? parseInt(mode, 8) : mode || fallback;
-}
-function Flags(flag) {
- return !isString(flag) ? flag :
- FLAGS[flag] || Error("Unknown file open flag: " + flag);
-}
-
-
-function FSError(op, code, errno, path, file, line) {
- let error = Error(code + ", " + op + " " + path, file, line);
- error.code = code;
- error.path = path;
- error.errno = errno;
- return error;
-}
-
-const ReadStream = Class({
- extends: InputStream,
- initialize: function initialize(path, options) {
- this.position = -1;
- this.length = -1;
- this.flags = "r";
- this.mode = FILE_PERMISSION;
- this.bufferSize = 64 * 1024;
-
- options = options || {};
-
- if ("flags" in options && options.flags)
- this.flags = options.flags;
- if ("bufferSize" in options && options.bufferSize)
- this.bufferSize = options.bufferSize;
- if ("length" in options && options.length)
- this.length = options.length;
- if ("position" in options && options.position !== undefined)
- this.position = options.position;
-
- let { flags, mode, position, length } = this;
- let fd = isString(path) ? openSync(path, flags, mode) : path;
- this.fd = fd;
-
- let input = nsIFileInputStream(fd);
- // Setting a stream position, unless it"s `-1` which means current position.
- if (position >= 0)
- input.QueryInterface(Ci.nsISeekableStream).seek(NS_SEEK_SET, position);
- // We use `nsIStreamTransportService` service to transform blocking
- // file input stream into a fully asynchronous stream that can be written
- // without blocking the main thread.
- let transport = createInputTransport(input, position, length, false);
- // Open an input stream on a transport. We don"t pass flags to guarantee
- // non-blocking stream semantics. Also we use defaults for segment size &
- // count.
- InputStream.prototype.initialize.call(this, {
- asyncInputStream: transport.openInputStream(null, 0, 0)
- });
-
- // Close file descriptor on end and destroy the stream.
- on(this, "end", _ => {
- this.destroy();
- emit(this, "close");
- });
-
- this.read();
- },
- destroy: function() {
- closeSync(this.fd);
- InputStream.prototype.destroy.call(this);
- }
-});
-exports.ReadStream = ReadStream;
-exports.createReadStream = function createReadStream(path, options) {
- return new ReadStream(path, options);
-};
-
-const WriteStream = Class({
- extends: OutputStream,
- initialize: function initialize(path, options) {
- this.drainable = true;
- this.flags = "w";
- this.position = -1;
- this.mode = FILE_PERMISSION;
-
- options = options || {};
-
- if ("flags" in options && options.flags)
- this.flags = options.flags;
- if ("mode" in options && options.mode)
- this.mode = options.mode;
- if ("position" in options && options.position !== undefined)
- this.position = options.position;
-
- let { position, flags, mode } = this;
- // If pass was passed we create a file descriptor out of it. Otherwise
- // we just use given file descriptor.
- let fd = isString(path) ? openSync(path, flags, mode) : path;
- this.fd = fd;
-
- let output = nsIFileOutputStream(fd);
- // Setting a stream position, unless it"s `-1` which means current position.
- if (position >= 0)
- output.QueryInterface(Ci.nsISeekableStream).seek(NS_SEEK_SET, position);
- // We use `nsIStreamTransportService` service to transform blocking
- // file output stream into a fully asynchronous stream that can be written
- // without blocking the main thread.
- let transport = createOutputTransport(output, position, -1, false);
- // Open an output stream on a transport. We don"t pass flags to guarantee
- // non-blocking stream semantics. Also we use defaults for segment size &
- // count.
- OutputStream.prototype.initialize.call(this, {
- asyncOutputStream: transport.openOutputStream(OPEN_UNBUFFERED, 0, 0),
- output: output
- });
-
- // For write streams "finish" basically means close.
- on(this, "finish", _ => {
- this.destroy();
- emit(this, "close");
- });
- },
- destroy: function() {
- OutputStream.prototype.destroy.call(this);
- closeSync(this.fd);
- }
-});
-exports.WriteStream = WriteStream;
-exports.createWriteStream = function createWriteStream(path, options) {
- return new WriteStream(path, options);
-};
-
-const Stats = Class({
- initialize: function initialize(path) {
- let file = new nsILocalFile(path);
- if (!file.exists()) throw FSError("stat", "ENOENT", 34, path);
- nsIFile(this, file);
- },
- isDirectory: function() {
- return nsIFile(this).isDirectory();
- },
- isFile: function() {
- return nsIFile(this).isFile();
- },
- isSymbolicLink: function() {
- return nsIFile(this).isSymlink();
- },
- get mode() {
- return nsIFile(this).permissions;
- },
- get size() {
- return nsIFile(this).fileSize;
- },
- get mtime() {
- return nsIFile(this).lastModifiedTime;
- },
- isBlockDevice: function() {
- return nsIFile(this).isSpecial();
- },
- isCharacterDevice: function() {
- return nsIFile(this).isSpecial();
- },
- isFIFO: function() {
- return nsIFile(this).isSpecial();
- },
- isSocket: function() {
- return nsIFile(this).isSpecial();
- },
- // non standard
- get exists() {
- return nsIFile(this).exists();
- },
- get hidden() {
- return nsIFile(this).isHidden();
- },
- get writable() {
- return nsIFile(this).isWritable();
- },
- get readable() {
- return nsIFile(this).isReadable();
- }
-});
-exports.Stats = Stats;
-
-const LStats = Class({
- extends: Stats,
- get size() {
- return this.isSymbolicLink() ? nsIFile(this).fileSizeOfLink :
- nsIFile(this).fileSize;
- },
- get mtime() {
- return this.isSymbolicLink() ? nsIFile(this).lastModifiedTimeOfLink :
- nsIFile(this).lastModifiedTime;
- },
- // non standard
- get permissions() {
- return this.isSymbolicLink() ? nsIFile(this).permissionsOfLink :
- nsIFile(this).permissions;
- }
-});
-
-const FStat = Class({
- extends: Stats,
- initialize: function initialize(fd) {
- nsIFile(this, nsIFile(fd));
- }
-});
-
-function noop() {}
-function Async(wrapped) {
- return function (path, callback) {
- let args = Array.slice(arguments);
- callback = args.pop();
- // If node is not given a callback argument
- // it just does not calls it.
- if (typeof(callback) !== "function") {
- args.push(callback);
- callback = noop;
- }
- setTimeout(function() {
- try {
- var result = wrapped.apply(this, args);
- if (result === undefined) callback(null);
- else callback(null, result);
- } catch (error) {
- callback(error);
- }
- }, 0);
- }
-}
-
-
-/**
- * Synchronous rename(2)
- */
-function renameSync(oldPath, newPath) {
- let source = new nsILocalFile(oldPath);
- let target = new nsILocalFile(newPath);
- if (!source.exists()) throw FSError("rename", "ENOENT", 34, oldPath);
- return source.moveTo(target.parent, target.leafName);
-};
-exports.renameSync = renameSync;
-
-/**
- * Asynchronous rename(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var rename = Async(renameSync);
-exports.rename = rename;
-
-/**
- * Test whether or not the given path exists by checking with the file system.
- */
-function existsSync(path) {
- return new nsILocalFile(path).exists();
-}
-exports.existsSync = existsSync;
-
-var exists = Async(existsSync);
-exports.exists = exists;
-
-/**
- * Synchronous ftruncate(2).
- */
-function truncateSync(path, length) {
- let fd = openSync(path, "w");
- ftruncateSync(fd, length);
- closeSync(fd);
-}
-exports.truncateSync = truncateSync;
-
-/**
- * Asynchronous ftruncate(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-function truncate(path, length, callback) {
- open(path, "w", function(error, fd) {
- if (error) return callback(error);
- ftruncate(fd, length, function(error) {
- if (error) {
- closeSync(fd);
- callback(error);
- }
- else {
- close(fd, callback);
- }
- });
- });
-}
-exports.truncate = truncate;
-
-function ftruncate(fd, length, callback) {
- write(fd, new Buffer(length), 0, length, 0, function(error) {
- callback(error);
- });
-}
-exports.ftruncate = ftruncate;
-
-function ftruncateSync(fd, length = 0) {
- writeSync(fd, new Buffer(length), 0, length, 0);
-}
-exports.ftruncateSync = ftruncateSync;
-
-function chownSync(path, uid, gid) {
- throw Error("Not implemented yet!!");
-}
-exports.chownSync = chownSync;
-
-var chown = Async(chownSync);
-exports.chown = chown;
-
-function lchownSync(path, uid, gid) {
- throw Error("Not implemented yet!!");
-}
-exports.lchownSync = chownSync;
-
-var lchown = Async(lchown);
-exports.lchown = lchown;
-
-/**
- * Synchronous chmod(2).
- */
-function chmodSync (path, mode) {
- let file;
- try {
- file = new nsILocalFile(path);
- } catch(e) {
- throw FSError("chmod", "ENOENT", 34, path);
- }
-
- file.permissions = Mode(mode);
-}
-exports.chmodSync = chmodSync;
-/**
- * Asynchronous chmod(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var chmod = Async(chmodSync);
-exports.chmod = chmod;
-
-/**
- * Synchronous chmod(2).
- */
-function fchmodSync(fd, mode) {
- throw Error("Not implemented yet!!");
-};
-exports.fchmodSync = fchmodSync;
-/**
- * Asynchronous chmod(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var fchmod = Async(fchmodSync);
-exports.fchmod = fchmod;
-
-
-/**
- * Synchronous stat(2). Returns an instance of `fs.Stats`
- */
-function statSync(path) {
- return new Stats(path);
-};
-exports.statSync = statSync;
-
-/**
- * Asynchronous stat(2). The callback gets two arguments (err, stats) where
- * stats is a `fs.Stats` object. It looks like this:
- */
-var stat = Async(statSync);
-exports.stat = stat;
-
-/**
- * Synchronous lstat(2). Returns an instance of `fs.Stats`.
- */
-function lstatSync(path) {
- return new LStats(path);
-};
-exports.lstatSync = lstatSync;
-
-/**
- * Asynchronous lstat(2). The callback gets two arguments (err, stats) where
- * stats is a fs.Stats object. lstat() is identical to stat(), except that if
- * path is a symbolic link, then the link itself is stat-ed, not the file that
- * it refers to.
- */
-var lstat = Async(lstatSync);
-exports.lstat = lstat;
-
-/**
- * Synchronous fstat(2). Returns an instance of `fs.Stats`.
- */
-function fstatSync(fd) {
- return new FStat(fd);
-};
-exports.fstatSync = fstatSync;
-
-/**
- * Asynchronous fstat(2). The callback gets two arguments (err, stats) where
- * stats is a fs.Stats object.
- */
-var fstat = Async(fstatSync);
-exports.fstat = fstat;
-
-/**
- * Synchronous link(2).
- */
-function linkSync(source, target) {
- throw Error("Not implemented yet!!");
-};
-exports.linkSync = linkSync;
-
-/**
- * Asynchronous link(2). No arguments other than a possible exception are given
- * to the completion callback.
- */
-var link = Async(linkSync);
-exports.link = link;
-
-/**
- * Synchronous symlink(2).
- */
-function symlinkSync(source, target) {
- throw Error("Not implemented yet!!");
-};
-exports.symlinkSync = symlinkSync;
-
-/**
- * Asynchronous symlink(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var symlink = Async(symlinkSync);
-exports.symlink = symlink;
-
-/**
- * Synchronous readlink(2). Returns the resolved path.
- */
-function readlinkSync(path) {
- return new nsILocalFile(path).target;
-};
-exports.readlinkSync = readlinkSync;
-
-/**
- * Asynchronous readlink(2). The callback gets two arguments
- * `(error, resolvedPath)`.
- */
-var readlink = Async(readlinkSync);
-exports.readlink = readlink;
-
-/**
- * Synchronous realpath(2). Returns the resolved path.
- */
-function realpathSync(path) {
- return new nsILocalFile(path).path;
-};
-exports.realpathSync = realpathSync;
-
-/**
- * Asynchronous realpath(2). The callback gets two arguments
- * `(err, resolvedPath)`.
- */
-var realpath = Async(realpathSync);
-exports.realpath = realpath;
-
-/**
- * Synchronous unlink(2).
- */
-var unlinkSync = remove;
-exports.unlinkSync = unlinkSync;
-
-/**
- * Asynchronous unlink(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var unlink = Async(remove);
-exports.unlink = unlink;
-
-/**
- * Synchronous rmdir(2).
- */
-var rmdirSync = remove;
-exports.rmdirSync = rmdirSync;
-
-/**
- * Asynchronous rmdir(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var rmdir = Async(rmdirSync);
-exports.rmdir = rmdir;
-
-/**
- * Synchronous mkdir(2).
- */
-function mkdirSync(path, mode) {
- try {
- return nsILocalFile(path).create(DIRECTORY_TYPE, Mode(mode));
- } catch (error) {
- // Adjust exception thorw to match ones thrown by node.
- if (error.name === "NS_ERROR_FILE_ALREADY_EXISTS") {
- let { fileName, lineNumber } = error;
- error = FSError("mkdir", "EEXIST", 47, path, fileName, lineNumber);
- }
- throw error;
- }
-};
-exports.mkdirSync = mkdirSync;
-
-/**
- * Asynchronous mkdir(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var mkdir = Async(mkdirSync);
-exports.mkdir = mkdir;
-
-/**
- * Synchronous readdir(3). Returns an array of filenames excluding `"."` and
- * `".."`.
- */
-function readdirSync(path) {
- try {
- return toArray(new nsILocalFile(path).directoryEntries).map(getFileName);
- }
- catch (error) {
- // Adjust exception thorw to match ones thrown by node.
- if (error.name === "NS_ERROR_FILE_TARGET_DOES_NOT_EXIST" ||
- error.name === "NS_ERROR_FILE_NOT_FOUND")
- {
- let { fileName, lineNumber } = error;
- error = FSError("readdir", "ENOENT", 34, path, fileName, lineNumber);
- }
- throw error;
- }
-};
-exports.readdirSync = readdirSync;
-
-/**
- * Asynchronous readdir(3). Reads the contents of a directory. The callback
- * gets two arguments `(error, files)` where `files` is an array of the names
- * of the files in the directory excluding `"."` and `".."`.
- */
-var readdir = Async(readdirSync);
-exports.readdir = readdir;
-
-/**
- * Synchronous close(2).
- */
- function closeSync(fd) {
- let input = nsIFileInputStream(fd);
- let output = nsIFileOutputStream(fd);
-
- // Closing input stream and removing reference.
- if (input) input.close();
- // Closing output stream and removing reference.
- if (output) output.close();
-
- nsIFile(fd, null);
- nsIFileInputStream(fd, null);
- nsIFileOutputStream(fd, null);
- nsIBinaryInputStream(fd, null);
- nsIBinaryOutputStream(fd, null);
-};
-exports.closeSync = closeSync;
-/**
- * Asynchronous close(2). No arguments other than a possible exception are
- * given to the completion callback.
- */
-var close = Async(closeSync);
-exports.close = close;
-
-/**
- * Synchronous open(2).
- */
-function openSync(aPath, aFlag, aMode) {
- let [ fd, flags, mode, file ] =
- [ { path: aPath }, Flags(aFlag), Mode(aMode), nsILocalFile(aPath) ];
-
- nsIFile(fd, file);
-
- // If trying to open file for just read that does not exists
- // need to throw exception as node does.
- if (!file.exists() && !isWritable(flags))
- throw FSError("open", "ENOENT", 34, aPath);
-
- // If we want to open file in read mode we initialize input stream.
- if (isReadable(flags)) {
- let input = FileInputStream(file, flags, mode, DEFER_OPEN);
- nsIFileInputStream(fd, input);
- }
-
- // If we want to open file in write mode we initialize output stream for it.
- if (isWritable(flags)) {
- let output = FileOutputStream(file, flags, mode, DEFER_OPEN);
- nsIFileOutputStream(fd, output);
- }
-
- return fd;
-}
-exports.openSync = openSync;
-/**
- * Asynchronous file open. See open(2). Flags can be
- * `"r", "r+", "w", "w+", "a"`, or `"a+"`. mode defaults to `0666`.
- * The callback gets two arguments `(error, fd).
- */
-var open = Async(openSync);
-exports.open = open;
-
-/**
- * Synchronous version of buffer-based fs.write(). Returns the number of bytes
- * written.
- */
-function writeSync(fd, buffer, offset, length, position) {
- if (length + offset > buffer.length) {
- throw Error("Length is extends beyond buffer");
- }
- else if (length + offset !== buffer.length) {
- buffer = buffer.slice(offset, offset + length);
- }
-
- let output = BinaryOutputStream(nsIFileOutputStream(fd));
- nsIBinaryOutputStream(fd, output);
- // We write content as a byte array as this will avoid any transcoding
- // if content was a buffer.
- output.writeByteArray(buffer.valueOf(), buffer.length);
- output.flush();
-};
-exports.writeSync = writeSync;
-
-/**
- * Write buffer to the file specified by fd.
- *
- * `offset` and `length` determine the part of the buffer to be written.
- *
- * `position` refers to the offset from the beginning of the file where this
- * data should be written. If `position` is `null`, the data will be written
- * at the current position. See pwrite(2).
- *
- * The callback will be given three arguments `(error, written, buffer)` where
- * written specifies how many bytes were written into buffer.
- *
- * Note that it is unsafe to use `fs.write` multiple times on the same file
- * without waiting for the callback.
- */
-function write(fd, buffer, offset, length, position, callback) {
- if (!Buffer.isBuffer(buffer)) {
- // (fd, data, position, encoding, callback)
- let encoding = null;
- [ position, encoding, callback ] = Array.slice(arguments, 1);
- buffer = new Buffer(String(buffer), encoding);
- offset = 0;
- } else if (length + offset > buffer.length) {
- throw Error("Length is extends beyond buffer");
- } else if (length + offset !== buffer.length) {
- buffer = buffer.slice(offset, offset + length);
- }
-
- let writeStream = new WriteStream(fd, { position: position,
- length: length });
- writeStream.on("error", callback);
- writeStream.write(buffer, function onEnd() {
- writeStream.destroy();
- if (callback)
- callback(null, buffer.length, buffer);
- });
-};
-exports.write = write;
-
-/**
- * Synchronous version of string-based fs.read. Returns the number of
- * bytes read.
- */
-function readSync(fd, buffer, offset, length, position) {
- let input = nsIFileInputStream(fd);
- // Setting a stream position, unless it"s `-1` which means current position.
- if (position >= 0)
- input.QueryInterface(Ci.nsISeekableStream).seek(NS_SEEK_SET, position);
- // We use `nsIStreamTransportService` service to transform blocking
- // file input stream into a fully asynchronous stream that can be written
- // without blocking the main thread.
- let binaryInputStream = BinaryInputStream(input);
- let count = length === ALL ? binaryInputStream.available() : length;
- if (offset === 0) binaryInputStream.readArrayBuffer(count, buffer.buffer);
- else {
- let chunk = new Buffer(count);
- binaryInputStream.readArrayBuffer(count, chunk.buffer);
- chunk.copy(buffer, offset);
- }
-
- return buffer.slice(offset, offset + count);
-};
-exports.readSync = readSync;
-
-/**
- * Read data from the file specified by `fd`.
- *
- * `buffer` is the buffer that the data will be written to.
- * `offset` is offset within the buffer where writing will start.
- *
- * `length` is an integer specifying the number of bytes to read.
- *
- * `position` is an integer specifying where to begin reading from in the file.
- * If `position` is `null`, data will be read from the current file position.
- *
- * The callback is given the three arguments, `(error, bytesRead, buffer)`.
- */
-function read(fd, buffer, offset, length, position, callback) {
- let bytesRead = 0;
- let readStream = new ReadStream(fd, { position: position, length: length });
- readStream.on("data", function onData(data) {
- data.copy(buffer, offset + bytesRead);
- bytesRead += data.length;
- });
- readStream.on("end", function onEnd() {
- callback(null, bytesRead, buffer);
- readStream.destroy();
- });
-};
-exports.read = read;
-
-/**
- * Asynchronously reads the entire contents of a file.
- * The callback is passed two arguments `(error, data)`, where data is the
- * contents of the file.
- */
-function readFile(path, encoding, callback) {
- if (isFunction(encoding)) {
- callback = encoding
- encoding = null
- }
-
- let buffer = null;
- try {
- let readStream = new ReadStream(path);
- readStream.on("data", function(data) {
- if (!buffer) buffer = data;
- else buffer = Buffer.concat([buffer, data], 2);
- });
- readStream.on("error", function onError(error) {
- callback(error);
- });
- readStream.on("end", function onEnd() {
- // Note: Need to destroy before invoking a callback
- // so that file descriptor is released.
- readStream.destroy();
- callback(null, buffer);
- });
- }
- catch (error) {
- setTimeout(callback, 0, error);
- }
-};
-exports.readFile = readFile;
-
-/**
- * Synchronous version of `fs.readFile`. Returns the contents of the path.
- * If encoding is specified then this function returns a string.
- * Otherwise it returns a buffer.
- */
-function readFileSync(path, encoding) {
- let fd = openSync(path, "r");
- let size = fstatSync(fd).size;
- let buffer = new Buffer(size);
- try {
- readSync(fd, buffer, 0, ALL, 0);
- }
- finally {
- closeSync(fd);
- }
- return buffer;
-};
-exports.readFileSync = readFileSync;
-
-/**
- * Asynchronously writes data to a file, replacing the file if it already
- * exists. data can be a string or a buffer.
- */
-function writeFile(path, content, encoding, callback) {
- if (!isString(path))
- throw new TypeError('path must be a string');
-
- try {
- if (isFunction(encoding)) {
- callback = encoding
- encoding = null
- }
- if (isString(content))
- content = new Buffer(content, encoding);
-
- let writeStream = new WriteStream(path);
- let error = null;
-
- writeStream.end(content, function() {
- writeStream.destroy();
- callback(error);
- });
-
- writeStream.on("error", function onError(reason) {
- error = reason;
- writeStream.destroy();
- });
- } catch (error) {
- callback(error);
- }
-};
-exports.writeFile = writeFile;
-
-/**
- * The synchronous version of `fs.writeFile`.
- */
-function writeFileSync(filename, data, encoding) {
- // TODO: Implement this in bug 1148209 https://bugzilla.mozilla.org/show_bug.cgi?id=1148209
- throw Error("Not implemented");
-};
-exports.writeFileSync = writeFileSync;
-
-
-function utimesSync(path, atime, mtime) {
- throw Error("Not implemented");
-}
-exports.utimesSync = utimesSync;
-
-var utimes = Async(utimesSync);
-exports.utimes = utimes;
-
-function futimesSync(fd, atime, mtime, callback) {
- throw Error("Not implemented");
-}
-exports.futimesSync = futimesSync;
-
-var futimes = Async(futimesSync);
-exports.futimes = futimes;
-
-function fsyncSync(fd, atime, mtime, callback) {
- throw Error("Not implemented");
-}
-exports.fsyncSync = fsyncSync;
-
-var fsync = Async(fsyncSync);
-exports.fsync = fsync;
-
-
-/**
- * Watch for changes on filename. The callback listener will be called each
- * time the file is accessed.
- *
- * The second argument is optional. The options if provided should be an object
- * containing two members a boolean, persistent, and interval, a polling value
- * in milliseconds. The default is { persistent: true, interval: 0 }.
- */
-function watchFile(path, options, listener) {
- throw Error("Not implemented");
-};
-exports.watchFile = watchFile;
-
-
-function unwatchFile(path, listener) {
- throw Error("Not implemented");
-}
-exports.unwatchFile = unwatchFile;
-
-function watch(path, options, listener) {
- throw Error("Not implemented");
-}
-exports.watch = watch;
diff --git a/addon-sdk/source/lib/sdk/io/stream.js b/addon-sdk/source/lib/sdk/io/stream.js
deleted file mode 100644
index 0698b8e32..000000000
--- a/addon-sdk/source/lib/sdk/io/stream.js
+++ /dev/null
@@ -1,440 +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, Cc, Ci, Cu, Cr, components } = require("chrome");
-const { EventTarget } = require("../event/target");
-const { emit } = require("../event/core");
-const { Buffer } = require("./buffer");
-const { Class } = require("../core/heritage");
-const { setTimeout } = require("../timers");
-
-
-const MultiplexInputStream = CC("@mozilla.org/io/multiplex-input-stream;1",
- "nsIMultiplexInputStream");
-const AsyncStreamCopier = CC("@mozilla.org/network/async-stream-copier;1",
- "nsIAsyncStreamCopier", "init");
-const StringInputStream = CC("@mozilla.org/io/string-input-stream;1",
- "nsIStringInputStream");
-const ArrayBufferInputStream = CC("@mozilla.org/io/arraybuffer-input-stream;1",
- "nsIArrayBufferInputStream");
-
-const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
- "nsIBinaryInputStream", "setInputStream");
-const InputStreamPump = CC("@mozilla.org/network/input-stream-pump;1",
- "nsIInputStreamPump", "init");
-
-const threadManager = Cc["@mozilla.org/thread-manager;1"].
- getService(Ci.nsIThreadManager);
-
-const eventTarget = Cc["@mozilla.org/network/stream-transport-service;1"].
- getService(Ci.nsIEventTarget);
-
-var isFunction = value => typeof(value) === "function"
-
-function accessor() {
- let map = new WeakMap();
- return function(target, value) {
- if (value)
- map.set(target, value);
- return map.get(target);
- }
-}
-
-const Stream = Class({
- extends: EventTarget,
- initialize: function() {
- this.readable = false;
- this.writable = false;
- this.encoding = null;
- },
- setEncoding: function setEncoding(encoding) {
- this.encoding = String(encoding).toUpperCase();
- },
- pipe: function pipe(target, options) {
- let source = this;
- function onData(chunk) {
- if (target.writable) {
- if (false === target.write(chunk))
- source.pause();
- }
- }
- function onDrain() {
- if (source.readable)
- source.resume();
- }
- function onEnd() {
- target.end();
- }
- function onPause() {
- source.pause();
- }
- function onResume() {
- if (source.readable)
- source.resume();
- }
-
- function cleanup() {
- source.removeListener("data", onData);
- target.removeListener("drain", onDrain);
- source.removeListener("end", onEnd);
-
- target.removeListener("pause", onPause);
- target.removeListener("resume", onResume);
-
- source.removeListener("end", cleanup);
- source.removeListener("close", cleanup);
-
- target.removeListener("end", cleanup);
- target.removeListener("close", cleanup);
- }
-
- if (!options || options.end !== false)
- target.on("end", onEnd);
-
- source.on("data", onData);
- target.on("drain", onDrain);
- target.on("resume", onResume);
- target.on("pause", onPause);
-
- source.on("end", cleanup);
- source.on("close", cleanup);
-
- target.on("end", cleanup);
- target.on("close", cleanup);
-
- emit(target, "pipe", source);
- },
- pause: function pause() {
- emit(this, "pause");
- },
- resume: function resume() {
- emit(this, "resume");
- },
- destroySoon: function destroySoon() {
- this.destroy();
- }
-});
-exports.Stream = Stream;
-
-
-var nsIStreamListener = accessor();
-var nsIInputStreamPump = accessor();
-var nsIAsyncInputStream = accessor();
-var nsIBinaryInputStream = accessor();
-
-const StreamListener = Class({
- initialize: function(stream) {
- this.stream = stream;
- },
-
- // Next three methods are part of `nsIStreamListener` interface and are
- // invoked by `nsIInputStreamPump.asyncRead`.
- onDataAvailable: function(request, context, input, offset, count) {
- let stream = this.stream;
- let buffer = new ArrayBuffer(count);
- nsIBinaryInputStream(stream).readArrayBuffer(count, buffer);
- emit(stream, "data", new Buffer(buffer));
- },
-
- // Next two methods implement `nsIRequestObserver` interface and are invoked
- // by `nsIInputStreamPump.asyncRead`.
- onStartRequest: function() {},
- // Called to signify the end of an asynchronous request. We only care to
- // discover errors.
- onStopRequest: function(request, context, status) {
- let stream = this.stream;
- stream.readable = false;
- if (!components.isSuccessCode(status))
- emit(stream, "error", status);
- else
- emit(stream, "end");
- }
-});
-
-
-const InputStream = Class({
- extends: Stream,
- readable: false,
- paused: false,
- initialize: function initialize(options) {
- let { asyncInputStream } = options;
-
- this.readable = true;
-
- let binaryInputStream = new BinaryInputStream(asyncInputStream);
- let inputStreamPump = new InputStreamPump(asyncInputStream,
- -1, -1, 0, 0, false);
- let streamListener = new StreamListener(this);
-
- nsIAsyncInputStream(this, asyncInputStream);
- nsIInputStreamPump(this, inputStreamPump);
- nsIBinaryInputStream(this, binaryInputStream);
- nsIStreamListener(this, streamListener);
-
- this.asyncInputStream = asyncInputStream;
- this.inputStreamPump = inputStreamPump;
- this.binaryInputStream = binaryInputStream;
- },
- get status() {
- return nsIInputStreamPump(this).status;
- },
- read: function() {
- nsIInputStreamPump(this).asyncRead(nsIStreamListener(this), null);
- },
- pause: function pause() {
- this.paused = true;
- nsIInputStreamPump(this).suspend();
- emit(this, "paused");
- },
- resume: function resume() {
- this.paused = false;
- if (nsIInputStreamPump(this).isPending()) {
- nsIInputStreamPump(this).resume();
- emit(this, "resume");
- }
- },
- close: function close() {
- this.readable = false;
- nsIInputStreamPump(this).cancel(Cr.NS_OK);
- nsIBinaryInputStream(this).close();
- nsIAsyncInputStream(this).close();
- },
- destroy: function destroy() {
- this.close();
-
- nsIInputStreamPump(this);
- nsIAsyncInputStream(this);
- nsIBinaryInputStream(this);
- nsIStreamListener(this);
- }
-});
-exports.InputStream = InputStream;
-
-
-
-var nsIRequestObserver = accessor();
-var nsIAsyncOutputStream = accessor();
-var nsIAsyncStreamCopier = accessor();
-var nsIMultiplexInputStream = accessor();
-
-const RequestObserver = Class({
- initialize: function(stream) {
- this.stream = stream;
- },
- // Method is part of `nsIRequestObserver` interface that is
- // invoked by `nsIAsyncStreamCopier.asyncCopy`.
- onStartRequest: function() {},
- // Method is part of `nsIRequestObserver` interface that is
- // invoked by `nsIAsyncStreamCopier.asyncCopy`.
- onStopRequest: function(request, context, status) {
- let stream = this.stream;
- stream.drained = true;
-
- // Remove copied chunk.
- let multiplexInputStream = nsIMultiplexInputStream(stream);
- multiplexInputStream.removeStream(0);
-
- // If there was an error report.
- if (!components.isSuccessCode(status))
- emit(stream, "error", status);
-
- // If there more chunks in queue then flush them.
- else if (multiplexInputStream.count)
- stream.flush();
-
- // If stream is still writable notify that queue has drained.
- else if (stream.writable)
- emit(stream, "drain");
-
- // If stream is no longer writable close it.
- else {
- nsIAsyncStreamCopier(stream).cancel(Cr.NS_OK);
- nsIMultiplexInputStream(stream).close();
- nsIAsyncOutputStream(stream).close();
- nsIAsyncOutputStream(stream).flush();
- }
- }
-});
-
-const OutputStreamCallback = Class({
- initialize: function(stream) {
- this.stream = stream;
- },
- // Method is part of `nsIOutputStreamCallback` interface that
- // is invoked by `nsIAsyncOutputStream.asyncWait`. It is registered
- // with `WAIT_CLOSURE_ONLY` flag that overrides the default behavior,
- // causing the `onOutputStreamReady` notification to be suppressed until
- // the stream becomes closed.
- onOutputStreamReady: function(nsIAsyncOutputStream) {
- emit(this.stream, "finish");
- }
-});
-
-const OutputStream = Class({
- extends: Stream,
- writable: false,
- drained: true,
- get bufferSize() {
- let multiplexInputStream = nsIMultiplexInputStream(this);
- return multiplexInputStream && multiplexInputStream.available();
- },
- initialize: function initialize(options) {
- let { asyncOutputStream, output } = options;
- this.writable = true;
-
- // Ensure that `nsIAsyncOutputStream` was provided.
- asyncOutputStream.QueryInterface(Ci.nsIAsyncOutputStream);
-
- // Create a `nsIMultiplexInputStream` and `nsIAsyncStreamCopier`. Former
- // is used to queue written data chunks that `asyncStreamCopier` will
- // asynchronously drain into `asyncOutputStream`.
- let multiplexInputStream = MultiplexInputStream();
- let asyncStreamCopier = AsyncStreamCopier(multiplexInputStream,
- output || asyncOutputStream,
- eventTarget,
- // nsIMultiplexInputStream
- // implemnts .readSegments()
- true,
- // nsIOutputStream may or
- // may not implemnet
- // .writeSegments().
- false,
- // Use default buffer size.
- null,
- // Should not close an input.
- false,
- // Should not close an output.
- false);
-
- // Create `requestObserver` implementing `nsIRequestObserver` interface
- // in the constructor that's gonna be reused across several flushes.
- let requestObserver = RequestObserver(this);
-
-
- // Create observer that implements `nsIOutputStreamCallback` and register
- // using `WAIT_CLOSURE_ONLY` flag. That way it will be notfied once
- // `nsIAsyncOutputStream` is closed.
- asyncOutputStream.asyncWait(OutputStreamCallback(this),
- asyncOutputStream.WAIT_CLOSURE_ONLY,
- 0,
- threadManager.currentThread);
-
- nsIRequestObserver(this, requestObserver);
- nsIAsyncOutputStream(this, asyncOutputStream);
- nsIMultiplexInputStream(this, multiplexInputStream);
- nsIAsyncStreamCopier(this, asyncStreamCopier);
-
- this.asyncOutputStream = asyncOutputStream;
- this.multiplexInputStream = multiplexInputStream;
- this.asyncStreamCopier = asyncStreamCopier;
- },
- write: function write(content, encoding, callback) {
- if (isFunction(encoding)) {
- callback = encoding;
- encoding = callback;
- }
-
- // If stream is not writable we throw an error.
- if (!this.writable) throw Error("stream is not writable");
-
- let chunk = null;
-
- // If content is not a buffer then we create one out of it.
- if (Buffer.isBuffer(content)) {
- chunk = new ArrayBufferInputStream();
- chunk.setData(content.buffer, 0, content.length);
- }
- else {
- chunk = new StringInputStream();
- chunk.setData(content, content.length);
- }
-
- if (callback)
- this.once("drain", callback);
-
- // Queue up chunk to be copied to output sync.
- nsIMultiplexInputStream(this).appendStream(chunk);
- this.flush();
-
- return this.drained;
- },
- flush: function() {
- if (this.drained) {
- this.drained = false;
- nsIAsyncStreamCopier(this).asyncCopy(nsIRequestObserver(this), null);
- }
- },
- end: function end(content, encoding, callback) {
- if (isFunction(content)) {
- callback = content
- content = callback
- }
- if (isFunction(encoding)) {
- callback = encoding
- encoding = callback
- }
-
- // Setting a listener to "finish" event if passed.
- if (isFunction(callback))
- this.once("finish", callback);
-
-
- if (content)
- this.write(content, encoding);
- this.writable = false;
-
- // Close `asyncOutputStream` only if output has drained. If it's
- // not drained than `asyncStreamCopier` is busy writing, so let
- // it finish. Note that since `this.writable` is false copier will
- // close `asyncOutputStream` once output drains.
- if (this.drained)
- nsIAsyncOutputStream(this).close();
- },
- destroy: function destroy() {
- nsIAsyncOutputStream(this).close();
- nsIAsyncOutputStream(this);
- nsIMultiplexInputStream(this);
- nsIAsyncStreamCopier(this);
- nsIRequestObserver(this);
- }
-});
-exports.OutputStream = OutputStream;
-
-const DuplexStream = Class({
- extends: Stream,
- implements: [InputStream, OutputStream],
- allowHalfOpen: true,
- initialize: function initialize(options) {
- options = options || {};
- let { readable, writable, allowHalfOpen } = options;
-
- InputStream.prototype.initialize.call(this, options);
- OutputStream.prototype.initialize.call(this, options);
-
- if (readable === false)
- this.readable = false;
-
- if (writable === false)
- this.writable = false;
-
- if (allowHalfOpen === false)
- this.allowHalfOpen = false;
-
- // If in a half open state and it's disabled enforce end.
- this.once("end", () => {
- if (!this.allowHalfOpen && (!this.readable || !this.writable))
- this.end();
- });
- },
- destroy: function destroy(error) {
- InputStream.prototype.destroy.call(this);
- OutputStream.prototype.destroy.call(this);
- }
-});
-exports.DuplexStream = DuplexStream;
diff --git a/addon-sdk/source/lib/sdk/io/text-streams.js b/addon-sdk/source/lib/sdk/io/text-streams.js
deleted file mode 100644
index ed4ec4972..000000000
--- a/addon-sdk/source/lib/sdk/io/text-streams.js
+++ /dev/null
@@ -1,235 +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, Cu, components } = require("chrome");
-const { ensure } = require("../system/unload");
-const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
-
-// NetUtil.asyncCopy() uses this buffer length, and since we call it, for best
-// performance we use it, too.
-const BUFFER_BYTE_LEN = 0x8000;
-const PR_UINT32_MAX = 0xffffffff;
-const DEFAULT_CHARSET = "UTF-8";
-
-
-/**
- * An input stream that reads text from a backing stream using a given text
- * encoding.
- *
- * @param inputStream
- * The stream is backed by this nsIInputStream. It must already be
- * opened.
- * @param charset
- * Text in inputStream is expected to be in this character encoding. If
- * not given, "UTF-8" is assumed. See nsICharsetConverterManager.idl for
- * documentation on how to determine other valid values for this.
- */
-function TextReader(inputStream, charset) {
- charset = checkCharset(charset);
-
- let stream = Cc["@mozilla.org/intl/converter-input-stream;1"].
- createInstance(Ci.nsIConverterInputStream);
- stream.init(inputStream, charset, BUFFER_BYTE_LEN,
- Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
-
- let manager = new StreamManager(this, stream);
-
- /**
- * Reads a string from the stream. If the stream is closed, an exception is
- * thrown.
- *
- * @param numChars
- * The number of characters to read. If not given, the remainder of
- * the stream is read.
- * @return The string read. If the stream is already at EOS, returns the
- * empty string.
- */
- this.read = function TextReader_read(numChars) {
- manager.ensureOpened();
-
- let readAll = false;
- if (typeof(numChars) === "number")
- numChars = Math.max(numChars, 0);
- else
- readAll = true;
-
- let str = "";
- let totalRead = 0;
- let chunkRead = 1;
-
- // Read in numChars or until EOS, whichever comes first. Note that the
- // units here are characters, not bytes.
- while (true) {
- let chunk = {};
- let toRead = readAll ?
- PR_UINT32_MAX :
- Math.min(numChars - totalRead, PR_UINT32_MAX);
- if (toRead <= 0 || chunkRead <= 0)
- break;
-
- // The converter stream reads in at most BUFFER_BYTE_LEN bytes in a call
- // to readString, enough to fill its byte buffer. chunkRead will be the
- // number of characters encoded by the bytes in that buffer.
- chunkRead = stream.readString(toRead, chunk);
- str += chunk.value;
- totalRead += chunkRead;
- }
-
- return str;
- };
-}
-exports.TextReader = TextReader;
-
-/**
- * A buffered output stream that writes text to a backing stream using a given
- * text encoding.
- *
- * @param outputStream
- * The stream is backed by this nsIOutputStream. It must already be
- * opened.
- * @param charset
- * Text will be written to outputStream using this character encoding.
- * If not given, "UTF-8" is assumed. See nsICharsetConverterManager.idl
- * for documentation on how to determine other valid values for this.
- */
-function TextWriter(outputStream, charset) {
- charset = checkCharset(charset);
-
- let stream = outputStream;
-
- // Buffer outputStream if it's not already.
- let ioUtils = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
- if (!ioUtils.outputStreamIsBuffered(outputStream)) {
- stream = Cc["@mozilla.org/network/buffered-output-stream;1"].
- createInstance(Ci.nsIBufferedOutputStream);
- stream.init(outputStream, BUFFER_BYTE_LEN);
- }
-
- // I'd like to use nsIConverterOutputStream. But NetUtil.asyncCopy(), which
- // we use below in writeAsync(), naturally expects its sink to be an instance
- // of nsIOutputStream, which nsIConverterOutputStream's only implementation is
- // not. So we use uconv and manually convert all strings before writing to
- // outputStream.
- let uconv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
- createInstance(Ci.nsIScriptableUnicodeConverter);
- uconv.charset = charset;
-
- let manager = new StreamManager(this, stream);
-
- /**
- * Flushes the backing stream's buffer.
- */
- this.flush = function TextWriter_flush() {
- manager.ensureOpened();
- stream.flush();
- };
-
- /**
- * Writes a string to the stream. If the stream is closed, an exception is
- * thrown.
- *
- * @param str
- * The string to write.
- */
- this.write = function TextWriter_write(str) {
- manager.ensureOpened();
- let istream = uconv.convertToInputStream(str);
- let len = istream.available();
- while (len > 0) {
- stream.writeFrom(istream, len);
- len = istream.available();
- }
- istream.close();
- };
-
- /**
- * Writes a string on a background thread. After the write completes, the
- * backing stream's buffer is flushed, and both the stream and the backing
- * stream are closed, also on the background thread. If the stream is already
- * closed, an exception is thrown immediately.
- *
- * @param str
- * The string to write.
- * @param callback
- * An optional function. If given, it's called as callback(error) when
- * the write completes. error is an Error object or undefined if there
- * was no error. Inside callback, |this| is the stream object.
- */
- this.writeAsync = function TextWriter_writeAsync(str, callback) {
- manager.ensureOpened();
- let istream = uconv.convertToInputStream(str);
- NetUtil.asyncCopy(istream, stream, (result) => {
- let err = components.isSuccessCode(result) ? undefined :
- new Error("An error occured while writing to the stream: " + result);
- if (err)
- console.error(err);
-
- // asyncCopy() closes its output (and input) stream.
- manager.opened = false;
-
- if (typeof(callback) === "function") {
- try {
- callback.call(this, err);
- }
- catch (exc) {
- console.exception(exc);
- }
- }
- });
- };
-}
-exports.TextWriter = TextWriter;
-
-// This manages the lifetime of stream, a TextReader or TextWriter. It defines
-// closed and close() on stream and registers an unload listener that closes
-// rawStream if it's still opened. It also provides ensureOpened(), which
-// throws an exception if the stream is closed.
-function StreamManager(stream, rawStream) {
- this.rawStream = rawStream;
- this.opened = true;
-
- /**
- * True iff the stream is closed.
- */
- stream.__defineGetter__("closed", () => !this.opened);
-
- /**
- * Closes both the stream and its backing stream. If the stream is already
- * closed, an exception is thrown. For TextWriters, this first flushes the
- * backing stream's buffer.
- */
- stream.close = () => {
- this.ensureOpened();
- this.unload();
- };
-
- ensure(this);
-}
-
-StreamManager.prototype = {
- ensureOpened: function StreamManager_ensureOpened() {
- if (!this.opened)
- throw new Error("The stream is closed and cannot be used.");
- },
- unload: function StreamManager_unload() {
- // TextWriter.writeAsync() causes rawStream to close and therefore sets
- // opened to false, so check that we're still opened.
- if (this.opened) {
- // Calling close() on both an nsIUnicharInputStream and
- // nsIBufferedOutputStream closes their backing streams. It also forces
- // nsIOutputStreams to flush first.
- this.rawStream.close();
- this.opened = false;
- }
- }
-};
-
-function checkCharset(charset) {
- return typeof(charset) === "string" ? charset : DEFAULT_CHARSET;
-}
diff --git a/addon-sdk/source/lib/sdk/keyboard/hotkeys.js b/addon-sdk/source/lib/sdk/keyboard/hotkeys.js
deleted file mode 100644
index a179502b8..000000000
--- a/addon-sdk/source/lib/sdk/keyboard/hotkeys.js
+++ /dev/null
@@ -1,110 +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 { observer: keyboardObserver } = require("./observer");
-const { getKeyForCode, normalize, isFunctionKey,
- MODIFIERS } = require("./utils");
-
-/**
- * Register a global `hotkey` that executes `listener` when the key combination
- * in `hotkey` is pressed. If more then one `listener` is registered on the same
- * key combination only last one will be executed.
- *
- * @param {string} hotkey
- * Key combination in the format of 'modifier key'.
- *
- * Examples:
- *
- * "accel s"
- * "meta shift i"
- * "control alt d"
- *
- * Modifier keynames:
- *
- * - **shift**: The Shift key.
- * - **alt**: The Alt key. On the Macintosh, this is the Option key. On
- * Macintosh this can only be used in conjunction with another modifier,
- * since `Alt+Letter` combinations are reserved for entering special
- * characters in text.
- * - **meta**: The Meta key. On the Macintosh, this is the Command key.
- * - **control**: The Control key.
- * - **accel**: The key used for keyboard shortcuts on the user's platform,
- * which is Control on Windows and Linux, and Command on Mac. Usually, this
- * would be the value you would use.
- *
- * @param {function} listener
- * Function to execute when the `hotkey` is executed.
- */
-exports.register = function register(hotkey, listener) {
- hotkey = normalize(hotkey);
- hotkeys[hotkey] = listener;
-};
-
-/**
- * Unregister a global `hotkey`. If passed `listener` is not the one registered
- * for the given `hotkey`, the call to this function will be ignored.
- *
- * @param {string} hotkey
- * Key combination in the format of 'modifier key'.
- * @param {function} listener
- * Function that will be invoked when the `hotkey` is pressed.
- */
-exports.unregister = function unregister(hotkey, listener) {
- hotkey = normalize(hotkey);
- if (hotkeys[hotkey] === listener)
- delete hotkeys[hotkey];
-};
-
-/**
- * Map of hotkeys and associated functions.
- */
-const hotkeys = exports.hotkeys = {};
-
-keyboardObserver.on("keydown", function onKeypress(event, window) {
- let key, modifiers = [];
- let isChar = "isChar" in event && event.isChar;
- let which = "which" in event ? event.which : null;
- let keyCode = "keyCode" in event ? event.keyCode : null;
-
- if ("shiftKey" in event && event.shiftKey)
- modifiers.push("shift");
- if ("altKey" in event && event.altKey)
- modifiers.push("alt");
- if ("ctrlKey" in event && event.ctrlKey)
- modifiers.push("control");
- if ("metaKey" in event && event.metaKey)
- modifiers.push("meta");
-
- // If it's not a printable character then we fall back to a human readable
- // equivalent of one of the following constants.
- // http://dxr.mozilla.org/mozilla-central/source/dom/interfaces/events/nsIDOMKeyEvent.idl
- key = getKeyForCode(keyCode);
-
- // If only non-function (f1 - f24) key or only modifiers are pressed we don't
- // have a valid combination so we return immediately (Also, sometimes
- // `keyCode` may be one for the modifier which means we do not have a
- // modifier).
- if (!key || (!isFunctionKey(key) && !modifiers.length) || key in MODIFIERS)
- return;
-
- let combination = normalize({ key: key, modifiers: modifiers });
- let hotkey = hotkeys[combination];
-
- if (hotkey) {
- try {
- hotkey();
- } catch (exception) {
- console.exception(exception);
- } finally {
- // Work around bug 582052 by preventing the (nonexistent) default action.
- event.preventDefault();
- }
- }
-});
diff --git a/addon-sdk/source/lib/sdk/keyboard/observer.js b/addon-sdk/source/lib/sdk/keyboard/observer.js
deleted file mode 100644
index b8e32b95c..000000000
--- a/addon-sdk/source/lib/sdk/keyboard/observer.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";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { Class } = require("../core/heritage");
-const { EventTarget } = require("../event/target");
-const { emit } = require("../event/core");
-const { DOMEventAssembler } = require("../deprecated/events/assembler");
-const { browserWindowIterator } = require('../deprecated/window-utils');
-const { isBrowser } = require('../window/utils');
-const { observer: windowObserver } = require("../windows/observer");
-
-// Event emitter objects used to register listeners and emit events on them
-// when they occur.
-const Observer = Class({
- implements: [DOMEventAssembler, EventTarget],
- initialize() {
- // Adding each opened window to a list of observed windows.
- windowObserver.on("open", window => {
- if (isBrowser(window))
- this.observe(window);
- });
-
- // Removing each closed window form the list of observed windows.
- windowObserver.on("close", window => {
- if (isBrowser(window))
- this.ignore(window);
- });
-
- // Making observer aware of already opened windows.
- for (let window of browserWindowIterator()) {
- this.observe(window);
- }
- },
- /**
- * Events that are supported and emitted by the module.
- */
- supportedEventsTypes: [ "keydown", "keyup", "keypress" ],
- /**
- * 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) {
- emit(this, event.type, event, event.target.ownerDocument ? event.target.ownerDocument.defaultView
- : undefined);
- }
-});
-
-exports.observer = new Observer();
diff --git a/addon-sdk/source/lib/sdk/keyboard/utils.js b/addon-sdk/source/lib/sdk/keyboard/utils.js
deleted file mode 100644
index 1b7df4ce3..000000000
--- a/addon-sdk/source/lib/sdk/keyboard/utils.js
+++ /dev/null
@@ -1,189 +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 { Cc, Ci } = require("chrome");
-const runtime = require("../system/runtime");
-const { isString } = require("../lang/type");
-const array = require("../util/array");
-
-
-const SWP = "{{SEPARATOR}}";
-const SEPARATOR = "-"
-const INVALID_COMBINATION = "Hotkey key combination must contain one or more " +
- "modifiers and only one key";
-
-// Map of modifier key mappings.
-const MODIFIERS = exports.MODIFIERS = {
- 'accel': runtime.OS === "Darwin" ? 'meta' : 'control',
- 'meta': 'meta',
- 'control': 'control',
- 'ctrl': 'control',
- 'option': 'alt',
- 'command': 'meta',
- 'alt': 'alt',
- 'shift': 'shift'
-};
-
-// Hash of key:code pairs for all the chars supported by `nsIDOMKeyEvent`.
-// This is just a copy of the `nsIDOMKeyEvent` hash with normalized names.
-// @See: http://dxr.mozilla.org/mozilla-central/source/dom/interfaces/events/nsIDOMKeyEvent.idl
-const CODES = exports.CODES = new function Codes() {
- let nsIDOMKeyEvent = Ci.nsIDOMKeyEvent;
- // Names that will be substituted with a shorter analogs.
- let aliases = {
- 'subtract': '-',
- 'add': '+',
- 'equals': '=',
- 'slash': '/',
- 'backslash': '\\',
- 'openbracket': '[',
- 'closebracket': ']',
- 'quote': '\'',
- 'backquote': '`',
- 'period': '.',
- 'semicolon': ';',
- 'comma': ','
- };
-
- // Normalizing keys and copying values to `this` object.
- Object.keys(nsIDOMKeyEvent).filter(function(key) {
- // Filter out only key codes.
- return key.indexOf('DOM_VK') === 0;
- }).map(function(key) {
- // Map to key:values
- return [ key, nsIDOMKeyEvent[key] ];
- }).map(function([key, value]) {
- return [ key.replace('DOM_VK_', '').replace('_', '').toLowerCase(), value ];
- }).forEach(function ([ key, value ]) {
- this[aliases[key] || key] = value;
- }, this);
-};
-
-// Inverted `CODES` hash of `code:key`.
-const KEYS = exports.KEYS = new function Keys() {
- Object.keys(CODES).forEach(function(key) {
- this[CODES[key]] = key;
- }, this)
-}
-
-exports.getKeyForCode = function getKeyForCode(code) {
- return (code in KEYS) && KEYS[code];
-};
-exports.getCodeForKey = function getCodeForKey(key) {
- return (key in CODES) && CODES[key];
-};
-
-/**
- * Utility function that takes string or JSON that defines a `hotkey` and
- * returns normalized string version of it.
- * @param {JSON|String} hotkey
- * @param {String} [separator=" "]
- * Optional string that represents separator used to concatenate keys in the
- * given `hotkey`.
- * @returns {String}
- * @examples
- *
- * require("keyboard/hotkeys").normalize("b Shift accel");
- * // 'control shift b' -> on windows & linux
- * // 'meta shift b' -> on mac
- * require("keyboard/hotkeys").normalize("alt-d-shift", "-");
- * // 'alt shift d'
- */
-var normalize = exports.normalize = function normalize(hotkey, separator) {
- if (!isString(hotkey))
- hotkey = toString(hotkey, separator);
- return toString(toJSON(hotkey, separator), separator);
-};
-
-/*
- * Utility function that splits a string of characters that defines a `hotkey`
- * into modifier keys and the defining key.
- * @param {String} hotkey
- * @param {String} [separator=" "]
- * Optional string that represents separator used to concatenate keys in the
- * given `hotkey`.
- * @returns {JSON}
- * @examples
- *
- * require("keyboard/hotkeys").toJSON("accel shift b");
- * // { key: 'b', modifiers: [ 'control', 'shift' ] } -> on windows & linux
- * // { key: 'b', modifiers: [ 'meta', 'shift' ] } -> on mac
- *
- * require("keyboard/hotkeys").normalize("alt-d-shift", "-");
- * // { key: 'd', modifiers: [ 'alt', 'shift' ] }
- */
-var toJSON = exports.toJSON = function toJSON(hotkey, separator) {
- separator = separator || SEPARATOR;
- // Since default separator is `-`, combination may take form of `alt--`. To
- // avoid misbehavior we replace `--` with `-{{SEPARATOR}}` where
- // `{{SEPARATOR}}` can be swapped later.
- hotkey = hotkey.toLowerCase().replace(separator + separator, separator + SWP);
-
- let value = {};
- let modifiers = [];
- let keys = hotkey.split(separator);
- keys.forEach(function(name) {
- // If name is `SEPARATOR` than we swap it back.
- if (name === SWP)
- name = separator;
- if (name in MODIFIERS) {
- array.add(modifiers, MODIFIERS[name]);
- } else {
- if (!value.key)
- value.key = name;
- else
- throw new TypeError(INVALID_COMBINATION);
- }
- });
-
- if (!value.key)
- throw new TypeError(INVALID_COMBINATION);
-
- value.modifiers = modifiers.sort();
- return value;
-};
-
-/**
- * Utility function that takes object that defines a `hotkey` and returns
- * string representation of it.
- *
- * _Please note that this function does not validates data neither it normalizes
- * it, if you are unsure that data is well formed use `normalize` function
- * instead.
- *
- * @param {JSON} hotkey
- * @param {String} [separator=" "]
- * Optional string that represents separator used to concatenate keys in the
- * given `hotkey`.
- * @returns {String}
- * @examples
- *
- * require("keyboard/hotkeys").toString({
- * key: 'b',
- * modifiers: [ 'control', 'shift' ]
- * }, '+');
- * // 'control+shift+b
- *
- */
-var toString = exports.toString = function toString(hotkey, separator) {
- let keys = hotkey.modifiers.slice();
- keys.push(hotkey.key);
- return keys.join(separator || SEPARATOR);
-};
-
-/**
- * Utility function takes `key` name and returns `true` if it's function key
- * (F1, ..., F24) and `false` if it's not.
- */
-var isFunctionKey = exports.isFunctionKey = function isFunctionKey(key) {
- var $
- return key[0].toLowerCase() === 'f' &&
- ($ = parseInt(key.substr(1)), 0 < $ && $ < 25);
-};
diff --git a/addon-sdk/source/lib/sdk/l10n.js b/addon-sdk/source/lib/sdk/l10n.js
deleted file mode 100644
index db5a9d7b6..000000000
--- a/addon-sdk/source/lib/sdk/l10n.js
+++ /dev/null
@@ -1,91 +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 json = require("./l10n/json/core");
-const { get: getKey } = require("./l10n/core");
-const properties = require("./l10n/properties/core");
-const { getRulesForLocale } = require("./l10n/plural-rules");
-
-// Retrieve the plural mapping function
-var pluralMappingFunction = getRulesForLocale(json.language()) ||
- getRulesForLocale("en");
-
-exports.get = function get(k) {
- // For now, we only accept a "string" as first argument
- // TODO: handle plural forms in gettext pattern
- if (typeof k !== "string")
- throw new Error("First argument of localization method should be a string");
- let n = arguments[1];
-
- // Get translation from big hashmap or default to hard coded string:
- let localized = getKey(k, n) || k;
-
- // # Simplest usecase:
- // // String hard coded in source code:
- // _("Hello world")
- // // Identifier of a key stored in properties file
- // _("helloString")
- if (arguments.length <= 1)
- return localized;
-
- let args = Array.slice(arguments);
- let placeholders = [null, ...args.slice(typeof(n) === "number" ? 2 : 1)];
-
- if (typeof localized == "object" && "other" in localized) {
- // # Plural form:
- // // Strings hard coded in source code:
- // _(["One download", "%d downloads"], 10);
- // // Identifier of a key stored in properties file
- // _("downloadNumber", 0);
- let n = arguments[1];
-
- // First handle simple universal forms that may not be mandatory
- // for each language, (i.e. not different than 'other' form,
- // but still usefull for better phrasing)
- // For example 0 in english is the same form than 'other'
- // but we accept 'zero' form if specified in localization file
- if (n === 0 && "zero" in localized)
- localized = localized["zero"];
- else if (n === 1 && "one" in localized)
- localized = localized["one"];
- else if (n === 2 && "two" in localized)
- localized = localized["two"];
- else {
- let pluralForm = pluralMappingFunction(n);
- if (pluralForm in localized)
- localized = localized[pluralForm];
- else // Fallback in case of error: missing plural form
- localized = localized["other"];
- }
-
- // Simulate a string with one placeholder:
- args = [null, n];
- }
-
- // # String with placeholders:
- // // Strings hard coded in source code:
- // _("Hello %s", username)
- // // Identifier of a key stored in properties file
- // _("helloString", username)
- // * We supports `%1s`, `%2s`, ... pattern in order to change arguments order
- // in translation.
- // * In case of plural form, we has `%d` instead of `%s`.
- let offset = 1;
- if (placeholders.length > 1) {
- args = placeholders;
- }
-
- localized = localized.replace(/%(\d*)[sd]/g, (v, n) => {
- let rv = args[n != "" ? n : offset];
- offset++;
- return rv;
- });
-
- return localized;
-}
diff --git a/addon-sdk/source/lib/sdk/l10n/core.js b/addon-sdk/source/lib/sdk/l10n/core.js
deleted file mode 100644
index 2f8f84c04..000000000
--- a/addon-sdk/source/lib/sdk/l10n/core.js
+++ /dev/null
@@ -1,9 +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 json = require("./json/core");
-const properties = require("./properties/core");
-
-exports.get = json.usingJSON ? json.get : properties.get;
diff --git a/addon-sdk/source/lib/sdk/l10n/html.js b/addon-sdk/source/lib/sdk/l10n/html.js
deleted file mode 100644
index fa2cf9cf0..000000000
--- a/addon-sdk/source/lib/sdk/l10n/html.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": "unstable"
-};
-
-const { processes, remoteRequire } = require("../remote/parent");
-remoteRequire("sdk/content/l10n-html");
-
-var enabled = false;
-function enable() {
- if (!enabled) {
- processes.port.emit("sdk/l10n/html/enable");
- enabled = true;
- }
-}
-exports.enable = enable;
-
-function disable() {
- if (enabled) {
- processes.port.emit("sdk/l10n/html/disable");
- enabled = false;
- }
-}
-exports.disable = disable;
-
-processes.forEvery(process => {
- process.port.emit(enabled ? "sdk/l10n/html/enable" : "sdk/l10n/html/disable");
-});
diff --git a/addon-sdk/source/lib/sdk/l10n/json/core.js b/addon-sdk/source/lib/sdk/l10n/json/core.js
deleted file mode 100644
index af52f956f..000000000
--- a/addon-sdk/source/lib/sdk/l10n/json/core.js
+++ /dev/null
@@ -1,36 +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"
-};
-
-var usingJSON = false;
-var hash = {}, bestMatchingLocale = null;
-try {
- let data = require("@l10n/data");
- hash = data.hash;
- bestMatchingLocale = data.bestMatchingLocale;
- usingJSON = true;
-}
-catch(e) {}
-
-exports.usingJSON = usingJSON;
-
-// Returns the translation for a given key, if available.
-exports.get = function get(k) {
- return k in hash ? hash[k] : null;
-}
-
-// Returns the full length locale code: ja-JP-mac, en-US or fr
-exports.locale = function locale() {
- return bestMatchingLocale;
-}
-
-// Returns the short locale code: ja, en, fr
-exports.language = function language() {
- return bestMatchingLocale ? bestMatchingLocale.split("-")[0].toLowerCase()
- : "en";
-}
diff --git a/addon-sdk/source/lib/sdk/l10n/loader.js b/addon-sdk/source/lib/sdk/l10n/loader.js
deleted file mode 100644
index 60e219e44..000000000
--- a/addon-sdk/source/lib/sdk/l10n/loader.js
+++ /dev/null
@@ -1,70 +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 { Cc, Ci } = require("chrome");
-const { getPreferedLocales, findClosestLocale } = require("./locale");
-const { readURI } = require("../net/url");
-const { resolve } = require("../core/promise");
-
-function parseJsonURI(uri) {
- return readURI(uri).
- then(JSON.parse).
- then(null, function (error) {
- throw Error("Failed to parse locale file:\n" + uri + "\n" + error);
- });
-}
-
-// Returns the array stored in `locales.json` manifest that list available
-// locales files
-function getAvailableLocales(rootURI) {
- let uri = rootURI + "locales.json";
- return parseJsonURI(uri).then(function (manifest) {
- return "locales" in manifest &&
- Array.isArray(manifest.locales) ?
- manifest.locales : [];
- });
-}
-
-// Returns URI of the best locales file to use from the XPI
-function getBestLocale(rootURI) {
- // Read localization manifest file that contains list of available languages
- return getAvailableLocales(rootURI).then(function (availableLocales) {
- // Retrieve list of prefered locales to use
- let preferedLocales = getPreferedLocales();
-
- // Compute the most preferable locale to use by using these two lists
- return findClosestLocale(availableLocales, preferedLocales);
- });
-}
-
-/**
- * Read localization files and returns a promise of data to put in `@l10n/data`
- * pseudo module, in order to allow l10n/json/core to fetch it.
- */
-exports.load = function load(rootURI) {
- // First, search for a locale file:
- return getBestLocale(rootURI).then(function (bestMatchingLocale) {
- // It may be null if the addon doesn't have any locale file
- if (!bestMatchingLocale)
- return resolve(null);
-
- let localeURI = rootURI + "locale/" + bestMatchingLocale + ".json";
-
- // Locale files only contains one big JSON object that is used as
- // an hashtable of: "key to translate" => "translated key"
- // TODO: We are likely to change this in order to be able to overload
- // a specific key translation. For a specific package, module or line?
- return parseJsonURI(localeURI).then(function (json) {
- return {
- hash: json,
- bestMatchingLocale: bestMatchingLocale
- };
- });
- });
-}
diff --git a/addon-sdk/source/lib/sdk/l10n/locale.js b/addon-sdk/source/lib/sdk/l10n/locale.js
deleted file mode 100644
index 950b33b20..000000000
--- a/addon-sdk/source/lib/sdk/l10n/locale.js
+++ /dev/null
@@ -1,127 +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 prefs = require("../preferences/service");
-const { Cu, Cc, Ci } = require("chrome");
-const { Services } = Cu.import("resource://gre/modules/Services.jsm");
-
-/**
- * Gets the currently selected locale for display.
- * Gets all usable locale that we can use sorted by priority of relevance
- * @return Array of locales, begins with highest priority
- */
-const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
-const PREF_SELECTED_LOCALE = "general.useragent.locale";
-const PREF_ACCEPT_LANGUAGES = "intl.accept_languages";
-
-function getPreferedLocales(caseSensitve) {
- let locales = [];
- function addLocale(locale) {
- locale = locale.trim();
- if (!caseSensitve)
- locale = locale.toLowerCase();
- if (locales.indexOf(locale) === -1)
- locales.push(locale);
- }
-
- // Most important locale is OS one. But we use it, only if
- // "intl.locale.matchOS" pref is set to `true`.
- // Currently only used for multi-locales mobile builds.
- // http://mxr.mozilla.org/mozilla-central/source/mobile/android/installer/Makefile.in#46
- if (prefs.get(PREF_MATCH_OS_LOCALE, false)) {
- let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].
- getService(Ci.nsILocaleService);
- let osLocale = localeService.getLocaleComponentForUserAgent();
- addLocale(osLocale);
- }
-
- // In some cases, mainly on Fennec and on Linux version,
- // `general.useragent.locale` is a special 'localized' value, like:
- // "chrome://global/locale/intl.properties"
- let browserUiLocale = prefs.getLocalized(PREF_SELECTED_LOCALE, "") ||
- prefs.get(PREF_SELECTED_LOCALE, "");
- if (browserUiLocale)
- addLocale(browserUiLocale);
-
- // Third priority is the list of locales used for web content
- let contentLocales = prefs.getLocalized(PREF_ACCEPT_LANGUAGES, "") ||
- prefs.get(PREF_ACCEPT_LANGUAGES, "");
- if (contentLocales) {
- // This list is a string of locales seperated by commas.
- // There is spaces after commas, so strip each item
- for (let locale of contentLocales.split(","))
- addLocale(locale.replace(/(^\s+)|(\s+$)/g, ""));
- }
-
- // Finally, we ensure that en-US is the final fallback if it wasn't added
- addLocale("en-US");
-
- return locales;
-}
-exports.getPreferedLocales = getPreferedLocales;
-
-/**
- * Selects the closest matching locale from a list of locales.
- *
- * @param aLocales
- * An array of available locales
- * @param aMatchLocales
- * An array of prefered locales, ordered by priority. Most wanted first.
- * Locales have to be in lowercase.
- * If null, uses getPreferedLocales() results
- * @return the best match for the currently selected locale
- *
- * Stolen from http://dxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm
- */
-exports.findClosestLocale = function findClosestLocale(aLocales, aMatchLocales) {
- aMatchLocales = aMatchLocales || getPreferedLocales();
-
- // Holds the best matching localized resource
- let bestmatch = null;
- // The number of locale parts it matched with
- let bestmatchcount = 0;
- // The number of locale parts in the match
- let bestpartcount = 0;
-
- for (let locale of aMatchLocales) {
- let lparts = locale.split("-");
- for (let localized of aLocales) {
- let found = localized.toLowerCase();
- // Exact match is returned immediately
- if (locale == found)
- return localized;
-
- let fparts = found.split("-");
- /* If we have found a possible match and this one isn't any longer
- then we dont need to check further. */
- if (bestmatch && fparts.length < bestmatchcount)
- continue;
-
- // Count the number of parts that match
- let maxmatchcount = Math.min(fparts.length, lparts.length);
- let matchcount = 0;
- while (matchcount < maxmatchcount &&
- fparts[matchcount] == lparts[matchcount])
- matchcount++;
-
- /* If we matched more than the last best match or matched the same and
- this locale is less specific than the last best match. */
- if (matchcount > bestmatchcount ||
- (matchcount == bestmatchcount && fparts.length < bestpartcount)) {
- bestmatch = localized;
- bestmatchcount = matchcount;
- bestpartcount = fparts.length;
- }
- }
- // If we found a valid match for this locale return it
- if (bestmatch)
- return bestmatch;
- }
- return null;
-}
diff --git a/addon-sdk/source/lib/sdk/l10n/plural-rules.js b/addon-sdk/source/lib/sdk/l10n/plural-rules.js
deleted file mode 100644
index a3ef48a5e..000000000
--- a/addon-sdk/source/lib/sdk/l10n/plural-rules.js
+++ /dev/null
@@ -1,407 +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/. */
-
-// This file is automatically generated with /python-lib/plural-rules-generator.py
-// Fetching data from: http://unicode.org/repos/cldr/trunk/common/supplemental/plurals.xml
-
-// Mapping of short locale name == to == > rule index in following list
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const LOCALES_TO_RULES = {
- "af": 3,
- "ak": 4,
- "am": 4,
- "ar": 1,
- "asa": 3,
- "az": 0,
- "be": 11,
- "bem": 3,
- "bez": 3,
- "bg": 3,
- "bh": 4,
- "bm": 0,
- "bn": 3,
- "bo": 0,
- "br": 20,
- "brx": 3,
- "bs": 11,
- "ca": 3,
- "cgg": 3,
- "chr": 3,
- "cs": 12,
- "cy": 17,
- "da": 3,
- "de": 3,
- "dv": 3,
- "dz": 0,
- "ee": 3,
- "el": 3,
- "en": 3,
- "eo": 3,
- "es": 3,
- "et": 3,
- "eu": 3,
- "fa": 0,
- "ff": 5,
- "fi": 3,
- "fil": 4,
- "fo": 3,
- "fr": 5,
- "fur": 3,
- "fy": 3,
- "ga": 8,
- "gd": 24,
- "gl": 3,
- "gsw": 3,
- "gu": 3,
- "guw": 4,
- "gv": 23,
- "ha": 3,
- "haw": 3,
- "he": 2,
- "hi": 4,
- "hr": 11,
- "hu": 0,
- "id": 0,
- "ig": 0,
- "ii": 0,
- "is": 3,
- "it": 3,
- "iu": 7,
- "ja": 0,
- "jmc": 3,
- "jv": 0,
- "ka": 0,
- "kab": 5,
- "kaj": 3,
- "kcg": 3,
- "kde": 0,
- "kea": 0,
- "kk": 3,
- "kl": 3,
- "km": 0,
- "kn": 0,
- "ko": 0,
- "ksb": 3,
- "ksh": 21,
- "ku": 3,
- "kw": 7,
- "lag": 18,
- "lb": 3,
- "lg": 3,
- "ln": 4,
- "lo": 0,
- "lt": 10,
- "lv": 6,
- "mas": 3,
- "mg": 4,
- "mk": 16,
- "ml": 3,
- "mn": 3,
- "mo": 9,
- "mr": 3,
- "ms": 0,
- "mt": 15,
- "my": 0,
- "nah": 3,
- "naq": 7,
- "nb": 3,
- "nd": 3,
- "ne": 3,
- "nl": 3,
- "nn": 3,
- "no": 3,
- "nr": 3,
- "nso": 4,
- "ny": 3,
- "nyn": 3,
- "om": 3,
- "or": 3,
- "pa": 3,
- "pap": 3,
- "pl": 13,
- "ps": 3,
- "pt": 3,
- "rm": 3,
- "ro": 9,
- "rof": 3,
- "ru": 11,
- "rwk": 3,
- "sah": 0,
- "saq": 3,
- "se": 7,
- "seh": 3,
- "ses": 0,
- "sg": 0,
- "sh": 11,
- "shi": 19,
- "sk": 12,
- "sl": 14,
- "sma": 7,
- "smi": 7,
- "smj": 7,
- "smn": 7,
- "sms": 7,
- "sn": 3,
- "so": 3,
- "sq": 3,
- "sr": 11,
- "ss": 3,
- "ssy": 3,
- "st": 3,
- "sv": 3,
- "sw": 3,
- "syr": 3,
- "ta": 3,
- "te": 3,
- "teo": 3,
- "th": 0,
- "ti": 4,
- "tig": 3,
- "tk": 3,
- "tl": 4,
- "tn": 3,
- "to": 0,
- "tr": 0,
- "ts": 3,
- "tzm": 22,
- "uk": 11,
- "ur": 3,
- "ve": 3,
- "vi": 0,
- "vun": 3,
- "wa": 4,
- "wae": 3,
- "wo": 0,
- "xh": 3,
- "xog": 3,
- "yo": 0,
- "zh": 0,
- "zu": 3
-};
-
-// Utility functions for plural rules methods
-function isIn(n, list) {
- return list.indexOf(n) !== -1;
-}
-function isBetween(n, start, end) {
- return start <= n && n <= end;
-}
-
-// List of all plural rules methods, that maps an integer to the plural form name to use
-const RULES = {
- "0": function (n) {
-
- return "other"
- },
- "1": function (n) {
- if ((isBetween((n % 100), 3, 10)))
- return "few";
- if (n == 0)
- return "zero";
- if ((isBetween((n % 100), 11, 99)))
- return "many";
- if (n == 2)
- return "two";
- if (n == 1)
- return "one";
- return "other"
- },
- "2": function (n) {
- if (n != 0 && (n % 10) == 0)
- return "many";
- if (n == 2)
- return "two";
- if (n == 1)
- return "one";
- return "other"
- },
- "3": function (n) {
- if (n == 1)
- return "one";
- return "other"
- },
- "4": function (n) {
- if ((isBetween(n, 0, 1)))
- return "one";
- return "other"
- },
- "5": function (n) {
- if ((isBetween(n, 0, 2)) && n != 2)
- return "one";
- return "other"
- },
- "6": function (n) {
- if (n == 0)
- return "zero";
- if ((n % 10) == 1 && (n % 100) != 11)
- return "one";
- return "other"
- },
- "7": function (n) {
- if (n == 2)
- return "two";
- if (n == 1)
- return "one";
- return "other"
- },
- "8": function (n) {
- if ((isBetween(n, 3, 6)))
- return "few";
- if ((isBetween(n, 7, 10)))
- return "many";
- if (n == 2)
- return "two";
- if (n == 1)
- return "one";
- return "other"
- },
- "9": function (n) {
- if (n == 0 || n != 1 && (isBetween((n % 100), 1, 19)))
- return "few";
- if (n == 1)
- return "one";
- return "other"
- },
- "10": function (n) {
- if ((isBetween((n % 10), 2, 9)) && !(isBetween((n % 100), 11, 19)))
- return "few";
- if ((n % 10) == 1 && !(isBetween((n % 100), 11, 19)))
- return "one";
- return "other"
- },
- "11": function (n) {
- if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
- return "few";
- if ((n % 10) == 0 || (isBetween((n % 10), 5, 9)) || (isBetween((n % 100), 11, 14)))
- return "many";
- if ((n % 10) == 1 && (n % 100) != 11)
- return "one";
- return "other"
- },
- "12": function (n) {
- if ((isBetween(n, 2, 4)))
- return "few";
- if (n == 1)
- return "one";
- return "other"
- },
- "13": function (n) {
- if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
- return "few";
- if (n != 1 && (isBetween((n % 10), 0, 1)) || (isBetween((n % 10), 5, 9)) || (isBetween((n % 100), 12, 14)))
- return "many";
- if (n == 1)
- return "one";
- return "other"
- },
- "14": function (n) {
- if ((isBetween((n % 100), 3, 4)))
- return "few";
- if ((n % 100) == 2)
- return "two";
- if ((n % 100) == 1)
- return "one";
- return "other"
- },
- "15": function (n) {
- if (n == 0 || (isBetween((n % 100), 2, 10)))
- return "few";
- if ((isBetween((n % 100), 11, 19)))
- return "many";
- if (n == 1)
- return "one";
- return "other"
- },
- "16": function (n) {
- if ((n % 10) == 1 && n != 11)
- return "one";
- return "other"
- },
- "17": function (n) {
- if (n == 3)
- return "few";
- if (n == 0)
- return "zero";
- if (n == 6)
- return "many";
- if (n == 2)
- return "two";
- if (n == 1)
- return "one";
- return "other"
- },
- "18": function (n) {
- if (n == 0)
- return "zero";
- if ((isBetween(n, 0, 2)) && n != 0 && n != 2)
- return "one";
- return "other"
- },
- "19": function (n) {
- if ((isBetween(n, 2, 10)))
- return "few";
- if ((isBetween(n, 0, 1)))
- return "one";
- return "other"
- },
- "20": function (n) {
- if ((isBetween((n % 10), 3, 4) || ((n % 10) == 9)) && !(isBetween((n % 100), 10, 19) || isBetween((n % 100), 70, 79) || isBetween((n % 100), 90, 99)))
- return "few";
- if ((n % 1000000) == 0 && n != 0)
- return "many";
- if ((n % 10) == 2 && !isIn((n % 100), [12, 72, 92]))
- return "two";
- if ((n % 10) == 1 && !isIn((n % 100), [11, 71, 91]))
- return "one";
- return "other"
- },
- "21": function (n) {
- if (n == 0)
- return "zero";
- if (n == 1)
- return "one";
- return "other"
- },
- "22": function (n) {
- if ((isBetween(n, 0, 1)) || (isBetween(n, 11, 99)))
- return "one";
- return "other"
- },
- "23": function (n) {
- if ((isBetween((n % 10), 1, 2)) || (n % 20) == 0)
- return "one";
- return "other"
- },
- "24": function (n) {
- if ((isBetween(n, 3, 10) || isBetween(n, 13, 19)))
- return "few";
- if (isIn(n, [2, 12]))
- return "two";
- if (isIn(n, [1, 11]))
- return "one";
- return "other"
- },
-};
-
-/**
- * Return a function that gives the plural form name for a given integer
- * for the specified `locale`
- * let fun = getRulesForLocale('en');
- * fun(1) -> 'one'
- * fun(0) -> 'other'
- * fun(1000) -> 'other'
- */
-exports.getRulesForLocale = function getRulesForLocale(locale) {
- let index = LOCALES_TO_RULES[locale];
- if (!(index in RULES)) {
- console.warn('Plural form unknown for locale "' + locale + '"');
- return function () { return "other"; };
- }
- return RULES[index];
-}
-
diff --git a/addon-sdk/source/lib/sdk/l10n/prefs.js b/addon-sdk/source/lib/sdk/l10n/prefs.js
deleted file mode 100644
index 8ee26fc5b..000000000
--- a/addon-sdk/source/lib/sdk/l10n/prefs.js
+++ /dev/null
@@ -1,51 +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 { on } = require("../system/events");
-const core = require("./core");
-const { id: jetpackId } = require('../self');
-
-const OPTIONS_DISPLAYED = "addon-options-displayed";
-
-function enable() {
- on(OPTIONS_DISPLAYED, onOptionsDisplayed);
-}
-exports.enable = enable;
-
-function onOptionsDisplayed({ subject: document, data: addonId }) {
- if (addonId !== jetpackId)
- return;
- localizeInlineOptions(document);
-}
-
-function localizeInlineOptions(document) {
- let query = 'setting[data-jetpack-id="' + jetpackId + '"][pref-name], ' +
- 'button[data-jetpack-id="' + jetpackId + '"][pref-name]';
- let nodes = document.querySelectorAll(query);
- for (let node of nodes) {
- let name = node.getAttribute("pref-name");
- if (node.tagName == "setting") {
- let desc = core.get(name + "_description");
- if (desc)
- node.setAttribute("desc", desc);
- let title = core.get(name + "_title");
- if (title)
- node.setAttribute("title", title);
-
- for (let item of node.querySelectorAll("menuitem, radio")) {
- let key = name + "_options." + item.getAttribute("label");
- let label = core.get(key);
- if (label)
- item.setAttribute("label", label);
- }
- }
- else if (node.tagName == "button") {
- let label = core.get(name + "_label");
- if (label)
- node.setAttribute("label", label);
- }
- }
-}
-exports.localizeInlineOptions = localizeInlineOptions;
diff --git a/addon-sdk/source/lib/sdk/l10n/properties/core.js b/addon-sdk/source/lib/sdk/l10n/properties/core.js
deleted file mode 100644
index 7a9081d0b..000000000
--- a/addon-sdk/source/lib/sdk/l10n/properties/core.js
+++ /dev/null
@@ -1,87 +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 { Cu } = require("chrome");
-const { newURI } = require('../../url/utils')
-const { getRulesForLocale } = require("../plural-rules");
-const { getPreferedLocales } = require('../locale');
-const { rootURI } = require("@loader/options");
-const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-
-const baseURI = rootURI + "locale/";
-const preferedLocales = getPreferedLocales(true);
-
-// Make sure we don't get stale data after an update
-// (See Bug 1300735 for rationale).
-Services.strings.flushBundles();
-
-function getLocaleURL(locale) {
- // if the locale is a valid chrome URI, return it
- try {
- let uri = newURI(locale);
- if (uri.scheme == 'chrome')
- return uri.spec;
- }
- catch(_) {}
- // otherwise try to construct the url
- return baseURI + locale + ".properties";
-}
-
-function getKey(locale, key) {
- let bundle = Services.strings.createBundle(getLocaleURL(locale));
- try {
- return bundle.GetStringFromName(key) + "";
- }
- catch (_) {}
- return undefined;
-}
-
-function get(key, n, locales) {
- // try this locale
- let locale = locales.shift();
- let localized;
-
- if (typeof n == 'number') {
- if (n == 0) {
- localized = getKey(locale, key + '[zero]');
- }
- else if (n == 1) {
- localized = getKey(locale, key + '[one]');
- }
- else if (n == 2) {
- localized = getKey(locale, key + '[two]');
- }
-
- if (!localized) {
- // Retrieve the plural mapping function
- let pluralForm = (getRulesForLocale(locale.split("-")[0].toLowerCase()) ||
- getRulesForLocale("en"))(n);
- localized = getKey(locale, key + '[' + pluralForm + ']');
- }
-
- if (!localized) {
- localized = getKey(locale, key + '[other]');
- }
- }
-
- if (!localized) {
- localized = getKey(locale, key);
- }
-
- if (!localized) {
- localized = getKey(locale, key + '[other]');
- }
-
- if (localized) {
- return localized;
- }
-
- // try next locale
- if (locales.length)
- return get(key, n, locales);
-
- return undefined;
-}
-exports.get = (k, n) => get(k, n, Array.slice(preferedLocales));
diff --git a/addon-sdk/source/lib/sdk/lang/functional.js b/addon-sdk/source/lib/sdk/lang/functional.js
deleted file mode 100644
index 66e30edfa..000000000
--- a/addon-sdk/source/lib/sdk/lang/functional.js
+++ /dev/null
@@ -1,47 +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/. */
-
-// Disclaimer: Some of the functions in this module implement APIs from
-// Jeremy Ashkenas's http://underscorejs.org/ library and all credits for
-// those goes to him.
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { defer, remit, delay, debounce,
- throttle } = require("./functional/concurrent");
-const { method, invoke, partial, curry, compose, wrap, identity, memoize, once,
- cache, complement, constant, when, apply, flip, field, query,
- isInstance, chainable, is, isnt } = require("./functional/core");
-
-exports.defer = defer;
-exports.remit = remit;
-exports.delay = delay;
-exports.debounce = debounce;
-exports.throttle = throttle;
-
-exports.method = method;
-exports.invoke = invoke;
-exports.partial = partial;
-exports.curry = curry;
-exports.compose = compose;
-exports.wrap = wrap;
-exports.identity = identity;
-exports.memoize = memoize;
-exports.once = once;
-exports.cache = cache;
-exports.complement = complement;
-exports.constant = constant;
-exports.when = when;
-exports.apply = apply;
-exports.flip = flip;
-exports.field = field;
-exports.query = query;
-exports.isInstance = isInstance;
-exports.chainable = chainable;
-exports.is = is;
-exports.isnt = isnt;
diff --git a/addon-sdk/source/lib/sdk/lang/functional/concurrent.js b/addon-sdk/source/lib/sdk/lang/functional/concurrent.js
deleted file mode 100644
index 85e8cff46..000000000
--- a/addon-sdk/source/lib/sdk/lang/functional/concurrent.js
+++ /dev/null
@@ -1,110 +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/. */
-
-// Disclaimer: Some of the functions in this module implement APIs from
-// Jeremy Ashkenas's http://underscorejs.org/ library and all credits for
-// those goes to him.
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { arity, name, derive, invoke } = require("./helpers");
-const { setTimeout, clearTimeout, setImmediate } = require("../../timers");
-
-/**
- * Takes a function and returns a wrapped one instead, calling which will call
- * original function in the next turn of event loop. This is basically utility
- * to do `setImmediate(function() { ... })`, with a difference that returned
- * function is reused, instead of creating a new one each time. This also allows
- * to use this functions as event listeners.
- */
-const defer = f => derive(function(...args) {
- setImmediate(invoke, f, args, this);
-}, f);
-exports.defer = defer;
-// Exporting `remit` alias as `defer` may conflict with promises.
-exports.remit = defer;
-
-/**
- * Much like setTimeout, invokes function after wait milliseconds. If you pass
- * the optional arguments, they will be forwarded on to the function when it is
- * invoked.
- */
-const delay = function delay(f, ms, ...args) {
- setTimeout(() => f.apply(this, args), ms);
-};
-exports.delay = delay;
-
-/**
- * From underscore's `_.debounce`
- * http://underscorejs.org
- * (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Underscore may be freely distributed under the MIT license.
- */
-const debounce = function debounce (fn, wait) {
- let timeout, args, context, timestamp, result;
-
- let later = function () {
- let last = Date.now() - timestamp;
- if (last < wait) {
- timeout = setTimeout(later, wait - last);
- } else {
- timeout = null;
- result = fn.apply(context, args);
- context = args = null;
- }
- };
-
- return function (...aArgs) {
- context = this;
- args = aArgs;
- timestamp = Date.now();
- if (!timeout) {
- timeout = setTimeout(later, wait);
- }
-
- return result;
- };
-};
-exports.debounce = debounce;
-
-/**
- * From underscore's `_.throttle`
- * http://underscorejs.org
- * (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Underscore may be freely distributed under the MIT license.
- */
-const throttle = function throttle (func, wait, options) {
- let context, args, result;
- let timeout = null;
- let previous = 0;
- options || (options = {});
- let later = function() {
- previous = options.leading === false ? 0 : Date.now();
- timeout = null;
- result = func.apply(context, args);
- context = args = null;
- };
- return function() {
- let now = Date.now();
- if (!previous && options.leading === false) previous = now;
- let remaining = wait - (now - previous);
- context = this;
- args = arguments;
- if (remaining <= 0) {
- clearTimeout(timeout);
- timeout = null;
- previous = now;
- result = func.apply(context, args);
- context = args = null;
- } else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining);
- }
- return result;
- };
-};
-exports.throttle = throttle;
diff --git a/addon-sdk/source/lib/sdk/lang/functional/core.js b/addon-sdk/source/lib/sdk/lang/functional/core.js
deleted file mode 100644
index 0d9143364..000000000
--- a/addon-sdk/source/lib/sdk/lang/functional/core.js
+++ /dev/null
@@ -1,290 +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/. */
-
-// Disclaimer: Some of the functions in this module implement APIs from
-// Jeremy Ashkenas's http://underscorejs.org/ library and all credits for
-// those goes to him.
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable"
-}
-const { arity, name, derive, invoke } = require("./helpers");
-
-/**
- * Takes variadic numeber of functions and returns composed one.
- * Returned function pushes `this` pseudo-variable to the head
- * of the passed arguments and invokes all the functions from
- * left to right passing same arguments to them. Composite function
- * returns return value of the right most funciton.
- */
-const method = (...lambdas) => {
- return function method(...args) {
- args.unshift(this);
- return lambdas.reduce((_, lambda) => lambda.apply(this, args),
- void(0));
- };
-};
-exports.method = method;
-
-/**
- * Invokes `callee` by passing `params` as an arguments and `self` as `this`
- * pseudo-variable. Returns value that is returned by a callee.
- * @param {Function} callee
- * Function to invoke.
- * @param {Array} params
- * Arguments to invoke function with.
- * @param {Object} self
- * Object to be passed as a `this` pseudo variable.
- */
-exports.invoke = invoke;
-
-/**
- * Takes a function and bind values to one or more arguments, returning a new
- * function of smaller arity.
- *
- * @param {Function} fn
- * The function to partial
- *
- * @returns The new function with binded values
- */
-const partial = (f, ...curried) => {
- if (typeof(f) !== "function")
- throw new TypeError(String(f) + " is not a function");
-
- let fn = derive(function(...args) {
- return f.apply(this, curried.concat(args));
- }, f);
- fn.arity = arity(f) - curried.length;
- return fn;
-};
-exports.partial = partial;
-
-/**
- * Returns function with implicit currying, which will continue currying until
- * expected number of argument is collected. Expected number of arguments is
- * determined by `fn.length`. Using this with variadic functions is stupid,
- * so don't do it.
- *
- * @examples
- *
- * var sum = curry(function(a, b) {
- * return a + b
- * })
- * console.log(sum(2, 2)) // 4
- * console.log(sum(2)(4)) // 6
- */
-const curry = new function() {
- const currier = (fn, arity, params) => {
- // Function either continues to curry arguments or executes function
- // if desired arguments have being collected.
- const curried = function(...input) {
- // Prepend all curried arguments to the given arguments.
- if (params) input.unshift.apply(input, params);
- // If expected number of arguments has being collected invoke fn,
- // othrewise return curried version Otherwise continue curried.
- return (input.length >= arity) ? fn.apply(this, input) :
- currier(fn, arity, input);
- };
- curried.arity = arity - (params ? params.length : 0);
-
- return curried;
- };
-
- return fn => currier(fn, arity(fn));
-};
-exports.curry = curry;
-
-/**
- * Returns the composition of a list of functions, where each function consumes
- * the return value of the function that follows. In math terms, composing the
- * functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
- * @example
- *
- * var greet = function(name) { return "hi: " + name; };
- * var exclaim = function(statement) { return statement + "!"; };
- * var welcome = compose(exclaim, greet);
- *
- * welcome('moe'); // => 'hi: moe!'
- */
-function compose(...lambdas) {
- return function composed(...args) {
- let index = lambdas.length;
- while (0 <= --index)
- args = [lambdas[index].apply(this, args)];
-
- return args[0];
- };
-}
-exports.compose = compose;
-
-/*
- * Returns the first function passed as an argument to the second,
- * allowing you to adjust arguments, run code before and after, and
- * conditionally execute the original function.
- * @example
- *
- * var hello = function(name) { return "hello: " + name; };
- * hello = wrap(hello, function(f) {
- * return "before, " + f("moe") + ", after";
- * });
- *
- * hello(); // => 'before, hello: moe, after'
- */
-const wrap = (f, wrapper) => derive(function wrapped(...args) {
- return wrapper.apply(this, [f].concat(args));
-}, f);
-exports.wrap = wrap;
-
-/**
- * Returns the same value that is used as the argument. In math: f(x) = x
- */
-const identity = value => value;
-exports.identity = identity;
-
-/**
- * Memoizes a given function by caching the computed result. Useful for
- * speeding up slow-running computations. If passed an optional hashFunction,
- * it will be used to compute the hash key for storing the result, based on
- * the arguments to the original function. The default hashFunction just uses
- * the first argument to the memoized function as the key.
- */
-const memoize = (f, hasher) => {
- let memo = Object.create(null);
- let cache = new WeakMap();
- hasher = hasher || identity;
- return derive(function memoizer(...args) {
- const key = hasher.apply(this, args);
- const type = typeof(key);
- if (key && (type === "object" || type === "function")) {
- if (!cache.has(key))
- cache.set(key, f.apply(this, args));
- return cache.get(key);
- }
- else {
- if (!(key in memo))
- memo[key] = f.apply(this, args);
- return memo[key];
- }
- }, f);
-};
-exports.memoize = memoize;
-
-/*
- * Creates a version of the function that can only be called one time. Repeated
- * calls to the modified function will have no effect, returning the value from
- * the original call. Useful for initialization functions, instead of having to
- * set a boolean flag and then check it later.
- */
-const once = f => {
- let ran = false, cache;
- return derive(function(...args) {
- return ran ? cache : (ran = true, cache = f.apply(this, args));
- }, f);
-};
-exports.once = once;
-// export cache as once will may be conflicting with event once a lot.
-exports.cache = once;
-
-// Takes a `f` function and returns a function that takes the same
-// arguments as `f`, has the same effects, if any, and returns the
-// opposite truth value.
-const complement = f => derive(function(...args) {
- return args.length < arity(f) ? complement(partial(f, ...args)) :
- !f.apply(this, args);
-}, f);
-exports.complement = complement;
-
-// Constructs function that returns `x` no matter what is it
-// invoked with.
-const constant = x => _ => x;
-exports.constant = constant;
-
-// Takes `p` predicate, `consequent` function and an optional
-// `alternate` function and composes function that returns
-// application of arguments over `consequent` if application over
-// `p` is `true` otherwise returns application over `alternate`.
-// If `alternate` is not a function returns `undefined`.
-const when = (p, consequent, alternate) => {
- if (typeof(alternate) !== "function" && alternate !== void(0))
- throw TypeError("alternate must be a function");
- if (typeof(consequent) !== "function")
- throw TypeError("consequent must be a function");
-
- return function(...args) {
- return p.apply(this, args) ?
- consequent.apply(this, args) :
- alternate && alternate.apply(this, args);
- };
-};
-exports.when = when;
-
-// Apply function that behaves as `apply` does in lisp:
-// apply(f, x, [y, z]) => f.apply(f, [x, y, z])
-// apply(f, x) => f.apply(f, [x])
-const apply = (f, ...rest) => f.apply(f, rest.concat(rest.pop()));
-exports.apply = apply;
-
-// Returns function identical to given `f` but with flipped order
-// of arguments.
-const flip = f => derive(function(...args) {
- return f.apply(this, args.reverse());
-}, f);
-exports.flip = flip;
-
-// Takes field `name` and `target` and returns value of that field.
-// If `target` is `null` or `undefined` it would be returned back
-// instead of attempt to access it's field. Function is implicitly
-// curried, this allows accessor function generation by calling it
-// with only `name` argument.
-const field = curry((name, target) =>
- // Note: Permisive `==` is intentional.
- target == null ? target : target[name]);
-exports.field = field;
-
-// Takes `.` delimited string representing `path` to a nested field
-// and a `target` to get it from. For convinience function is
-// implicitly curried, there for accessors can be created by invoking
-// it with just a `path` argument.
-const query = curry((path, target) => {
- const names = path.split(".");
- const count = names.length;
- let index = 0;
- let result = target;
- // Note: Permisive `!=` is intentional.
- while (result != null && index < count) {
- result = result[names[index]];
- index = index + 1;
- }
- return result;
-});
-exports.query = query;
-
-// Takes `Type` (constructor function) and a `value` and returns
-// `true` if `value` is instance of the given `Type`. Function is
-// implicitly curried this allows predicate generation by calling
-// function with just first argument.
-const isInstance = curry((Type, value) => value instanceof Type);
-exports.isInstance = isInstance;
-
-/*
- * Takes a funtion and returns a wrapped function that returns `this`
- */
-const chainable = f => derive(function(...args) {
- f.apply(this, args);
- return this;
-}, f);
-exports.chainable = chainable;
-
-// Functions takes `expected` and `actual` values and returns `true` if
-// `expected === actual`. Returns curried function if called with less then
-// two arguments.
-//
-// [ 1, 0, 1, 0, 1 ].map(is(1)) // => [ true, false, true, false, true ]
-const is = curry((expected, actual) => actual === expected);
-exports.is = is;
-
-const isnt = complement(is);
-exports.isnt = isnt;
diff --git a/addon-sdk/source/lib/sdk/lang/functional/helpers.js b/addon-sdk/source/lib/sdk/lang/functional/helpers.js
deleted file mode 100644
index 60f4e3300..000000000
--- a/addon-sdk/source/lib/sdk/lang/functional/helpers.js
+++ /dev/null
@@ -1,29 +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/. */
-
-// Disclaimer: Some of the functions in this module implement APIs from
-// Jeremy Ashkenas's http://underscorejs.org/ library and all credits for
-// those goes to him.
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable"
-}
-
-const arity = f => f.arity || f.length;
-exports.arity = arity;
-
-const name = f => f.displayName || f.name;
-exports.name = name;
-
-const derive = (f, source) => {
- f.displayName = name(source);
- f.arity = arity(source);
- return f;
-};
-exports.derive = derive;
-
-const invoke = (callee, params, self) => callee.apply(self, params);
-exports.invoke = invoke;
diff --git a/addon-sdk/source/lib/sdk/lang/type.js b/addon-sdk/source/lib/sdk/lang/type.js
deleted file mode 100644
index b50e6be4c..000000000
--- a/addon-sdk/source/lib/sdk/lang/type.js
+++ /dev/null
@@ -1,388 +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"
-};
-
-/**
- * Returns `true` if `value` is `undefined`.
- * @examples
- * var foo; isUndefined(foo); // true
- * isUndefined(0); // false
- */
-function isUndefined(value) {
- return value === undefined;
-}
-exports.isUndefined = isUndefined;
-
-/**
- * Returns `true` if value is `null`.
- * @examples
- * isNull(null); // true
- * isNull(undefined); // false
- */
-function isNull(value) {
- return value === null;
-}
-exports.isNull = isNull;
-
-/**
- * Returns `true` if value is `null` or `undefined`.
- * It's equivalent to `== null`, but resolve the ambiguity of the writer
- * intention, makes clear that he's clearly checking both `null` and `undefined`
- * values, and it's not a typo for `=== null`.
- */
-function isNil(value) {
- return value === null || value === undefined;
-}
-exports.isNil = isNil;
-
-function isBoolean(value) {
- return typeof value === "boolean";
-}
-exports.isBoolean = isBoolean;
-/**
- * Returns `true` if value is a string.
- * @examples
- * isString("moe"); // true
- */
-function isString(value) {
- return typeof value === "string";
-}
-exports.isString = isString;
-
-/**
- * Returns `true` if `value` is a number.
- * @examples
- * isNumber(8.4 * 5); // true
- */
-function isNumber(value) {
- return typeof value === "number";
-}
-exports.isNumber = isNumber;
-
-/**
- * Returns `true` if `value` is a `RegExp`.
- * @examples
- * isRegExp(/moe/); // true
- */
-function isRegExp(value) {
- return isObject(value) && instanceOf(value, RegExp);
-}
-exports.isRegExp = isRegExp;
-
-/**
- * Returns true if `value` is a `Date`.
- * @examples
- * isDate(new Date()); // true
- */
-function isDate(value) {
- return isObject(value) && instanceOf(value, Date);
-}
-exports.isDate = isDate;
-
-/**
- * Returns true if object is a Function.
- * @examples
- * isFunction(function foo(){}) // true
- */
-function isFunction(value) {
- return typeof value === "function";
-}
-exports.isFunction = isFunction;
-
-/**
- * Returns `true` if `value` is an object (please note that `null` is considered
- * to be an atom and not an object).
- * @examples
- * isObject({}) // true
- * isObject(null) // false
- */
-function isObject(value) {
- return typeof value === "object" && value !== null;
-}
-exports.isObject = isObject;
-
-/**
- * Detect whether a value is a generator.
- *
- * @param aValue
- * The value to identify.
- * @return A boolean indicating whether the value is a generator.
- */
-function isGenerator(aValue) {
- return !!(aValue && aValue.isGenerator && aValue.isGenerator());
-}
-exports.isGenerator = isGenerator;
-
-/**
- * Returns true if `value` is an Array.
- * @examples
- * isArray([1, 2, 3]) // true
- * isArray({ 0: 'foo', length: 1 }) // false
- */
-var isArray = Array.isArray;
-exports.isArray = isArray;
-
-/**
- * Returns `true` if `value` is an Arguments object.
- * @examples
- * (function(){ return isArguments(arguments); })(1, 2, 3); // true
- * isArguments([1,2,3]); // false
- */
-function isArguments(value) {
- return Object.prototype.toString.call(value) === "[object Arguments]";
-}
-exports.isArguments = isArguments;
-
-var isMap = value => Object.prototype.toString.call(value) === "[object Map]"
-exports.isMap = isMap;
-
-var isSet = value => Object.prototype.toString.call(value) === "[object Set]"
-exports.isSet = isSet;
-
-/**
- * Returns true if it is a primitive `value`. (null, undefined, number,
- * boolean, string)
- * @examples
- * isPrimitive(3) // true
- * isPrimitive('foo') // true
- * isPrimitive({ bar: 3 }) // false
- */
-function isPrimitive(value) {
- return !isFunction(value) && !isObject(value);
-}
-exports.isPrimitive = isPrimitive;
-
-/**
- * Returns `true` if given `object` is flat (it is direct decedent of
- * `Object.prototype` or `null`).
- * @examples
- * isFlat({}) // true
- * isFlat(new Type()) // false
- */
-function isFlat(object) {
- return isObject(object) && (isNull(Object.getPrototypeOf(object)) ||
- isNull(Object.getPrototypeOf(
- Object.getPrototypeOf(object))));
-}
-exports.isFlat = isFlat;
-
-/**
- * Returns `true` if object contains no values.
- */
-function isEmpty(object) {
- if (isObject(object)) {
- for (var key in object)
- return false;
- return true;
- }
- return false;
-}
-exports.isEmpty = isEmpty;
-
-/**
- * Returns `true` if `value` is an array / flat object containing only atomic
- * values and other flat objects.
- */
-function isJSON(value, visited) {
- // Adding value to array of visited values.
- (visited || (visited = [])).push(value);
- // If `value` is an atom return `true` cause it's valid JSON.
- return isPrimitive(value) ||
- // If `value` is an array of JSON values that has not been visited
- // yet.
- (isArray(value) && value.every(function(element) {
- return isJSON(element, visited);
- })) ||
- // If `value` is a plain object containing properties with a JSON
- // values it's a valid JSON.
- (isFlat(value) && Object.keys(value).every(function(key) {
- var $ = Object.getOwnPropertyDescriptor(value, key);
- // Check every proprety of a plain object to verify that
- // it's neither getter nor setter, but a JSON value, that
- // has not been visited yet.
- return ((!isObject($.value) || !~visited.indexOf($.value)) &&
- !('get' in $) && !('set' in $) &&
- isJSON($.value, visited));
- }));
-}
-exports.isJSON = function (value) {
- return isJSON(value);
-};
-
-/**
- * Returns `true` if `value` is JSONable
- */
-const isJSONable = (value) => {
- try {
- JSON.parse(JSON.stringify(value));
- }
- catch (e) {
- return false;
- }
- return true;
-};
-exports.isJSONable = isJSONable;
-
-/**
- * Returns if `value` is an instance of a given `Type`. This is exactly same as
- * `value instanceof Type` with a difference that `Type` can be from a scope
- * that has a different top level object. (Like in case where `Type` is a
- * function from different iframe / jetpack module / sandbox).
- */
-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;
-}
-exports.instanceOf = instanceOf;
-
-/**
- * Function returns textual representation of a value passed to it. Function
- * takes additional `indent` argument that is used for indentation. Also
- * optional `limit` argument may be passed to limit amount of detail returned.
- * @param {Object} value
- * @param {String} [indent=" "]
- * @param {Number} [limit]
- */
-function source(value, indent, limit, offset, visited) {
- var result;
- var names;
- var nestingIndex;
- var isCompact = !isUndefined(limit);
-
- indent = indent || " ";
- offset = (offset || "");
- result = "";
- visited = visited || [];
-
- if (isUndefined(value)) {
- result += "undefined";
- }
- else if (isNull(value)) {
- result += "null";
- }
- else if (isString(value)) {
- result += '"' + value + '"';
- }
- else if (isFunction(value)) {
- value = String(value).split("\n");
- if (isCompact && value.length > 2) {
- value = value.splice(0, 2);
- value.push("...}");
- }
- result += value.join("\n" + offset);
- }
- else if (isArray(value)) {
- if ((nestingIndex = (visited.indexOf(value) + 1))) {
- result = "#" + nestingIndex + "#";
- }
- else {
- visited.push(value);
-
- if (isCompact)
- value = value.slice(0, limit);
-
- result += "[\n";
- result += value.map(function(value) {
- return offset + indent + source(value, indent, limit, offset + indent,
- visited);
- }).join(",\n");
- result += isCompact && value.length > limit ?
- ",\n" + offset + "...]" : "\n" + offset + "]";
- }
- }
- else if (isObject(value)) {
- if ((nestingIndex = (visited.indexOf(value) + 1))) {
- result = "#" + nestingIndex + "#"
- }
- else {
- visited.push(value)
-
- names = Object.keys(value);
-
- result += "{ // " + value + "\n";
- result += (isCompact ? names.slice(0, limit) : names).map(function(name) {
- var _limit = isCompact ? limit - 1 : limit;
- var descriptor = Object.getOwnPropertyDescriptor(value, name);
- var result = offset + indent + "// ";
- var accessor;
- if (0 <= name.indexOf(" "))
- name = '"' + name + '"';
-
- if (descriptor.writable)
- result += "writable ";
- if (descriptor.configurable)
- result += "configurable ";
- if (descriptor.enumerable)
- result += "enumerable ";
-
- result += "\n";
- if ("value" in descriptor) {
- result += offset + indent + name + ": ";
- result += source(descriptor.value, indent, _limit, indent + offset,
- visited);
- }
- else {
-
- if (descriptor.get) {
- result += offset + indent + "get " + name + " ";
- accessor = source(descriptor.get, indent, _limit, indent + offset,
- visited);
- result += accessor.substr(accessor.indexOf("{"));
- }
-
- if (descriptor.set) {
- result += offset + indent + "set " + name + " ";
- accessor = source(descriptor.set, indent, _limit, indent + offset,
- visited);
- result += accessor.substr(accessor.indexOf("{"));
- }
- }
- return result;
- }).join(",\n");
-
- if (isCompact) {
- if (names.length > limit && limit > 0) {
- result += ",\n" + offset + indent + "//...";
- }
- }
- else {
- if (names.length)
- result += ",";
-
- result += "\n" + offset + indent + '"__proto__": ';
- result += source(Object.getPrototypeOf(value), indent, 0,
- offset + indent);
- }
-
- result += "\n" + offset + "}";
- }
- }
- else {
- result += String(value);
- }
- return result;
-}
-exports.source = function (value, indentation, limit) {
- return source(value, indentation, limit);
-};
diff --git a/addon-sdk/source/lib/sdk/lang/weak-set.js b/addon-sdk/source/lib/sdk/lang/weak-set.js
deleted file mode 100644
index 8972602a5..000000000
--- a/addon-sdk/source/lib/sdk/lang/weak-set.js
+++ /dev/null
@@ -1,75 +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/. */
-
-module.metadata = {
- "stability": "experimental"
-};
-
-"use strict";
-
-const { Cu } = require("chrome");
-
-function makeGetterFor(Type) {
- let cache = new WeakMap();
-
- return {
- getFor(target) {
- if (!cache.has(target))
- cache.set(target, new Type());
-
- return cache.get(target);
- },
- clearFor(target) {
- return cache.delete(target)
- }
- }
-}
-
-var {getFor: getLookupFor, clearFor: clearLookupFor} = makeGetterFor(WeakMap);
-var {getFor: getRefsFor, clearFor: clearRefsFor} = makeGetterFor(Set);
-
-function add(target, value) {
- if (has(target, value))
- return;
-
- getLookupFor(target).set(value, true);
- getRefsFor(target).add(Cu.getWeakReference(value));
-}
-exports.add = add;
-
-function remove(target, value) {
- getLookupFor(target).delete(value);
-}
-exports.remove = remove;
-
-function has(target, value) {
- return getLookupFor(target).has(value);
-}
-exports.has = has;
-
-function clear(target) {
- clearLookupFor(target);
- clearRefsFor(target);
-}
-exports.clear = clear;
-
-function iterator(target) {
- let refs = getRefsFor(target);
-
- for (let ref of refs) {
- let value = ref.get();
-
- // If `value` is already gc'ed, it would be `null`.
- // The `has` function is using a WeakMap as lookup table, so passing `null`
- // would raise an exception because WeakMap accepts as value only non-null
- // object.
- // Plus, if `value` is already gc'ed, we do not have to take it in account
- // during the iteration, and remove it from the references.
- if (value !== null && has(target, value))
- yield value;
- else
- refs.delete(ref);
- }
-}
-exports.iterator = iterator;
diff --git a/addon-sdk/source/lib/sdk/loader/cuddlefish.js b/addon-sdk/source/lib/sdk/loader/cuddlefish.js
deleted file mode 100644
index 6ba19157b..000000000
--- a/addon-sdk/source/lib/sdk/loader/cuddlefish.js
+++ /dev/null
@@ -1,102 +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"
-};
-
-// This module is manually loaded by bootstrap.js in a sandbox and immediatly
-// put in module cache so that it is never loaded in any other way.
-
-/* Workarounds to include dependencies in the manifest
-require('chrome') // Otherwise CFX will complain about Components
-require('toolkit/loader') // Otherwise CFX will stip out loader.js
-require('sdk/addon/runner') // Otherwise CFX will stip out addon/runner.js
-*/
-
-const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
-
-// `loadSandbox` is exposed by bootstrap.js
-const loaderURI = module.uri.replace("sdk/loader/cuddlefish.js",
- "toolkit/loader.js");
-const xulappURI = module.uri.replace("loader/cuddlefish.js",
- "system/xul-app.jsm");
-// We need to keep a reference to the sandbox in order to unload it in
-// bootstrap.js
-
-var loaderSandbox = loadSandbox(loaderURI);
-const loaderModule = loaderSandbox.exports;
-
-const { incompatibility } = Cu.import(xulappURI, {}).XulApp;
-
-const { override, load } = loaderModule;
-
-function CuddlefishLoader(options) {
- let { manifest } = options;
-
- options = override(options, {
- // Put `api-utils/loader` and `api-utils/cuddlefish` loaded as JSM to module
- // cache to avoid subsequent loads via `require`.
- modules: override({
- 'toolkit/loader': loaderModule,
- 'sdk/loader/cuddlefish': exports
- }, options.modules),
- resolve: function resolve(id, requirer) {
- let entry = requirer && requirer in manifest && manifest[requirer];
- let uri = null;
-
- // If manifest entry for this requirement is present we follow manifest.
- // Note: Standard library modules like 'panel' will be present in
- // manifest unless they were moved to platform.
- if (entry) {
- let requirement = entry.requirements[id];
- // If requirer entry is in manifest and it's requirement is not, than
- // it has no authority to load since linker was not able to find it.
- if (!requirement)
- throw Error('Module: ' + requirer + ' has no authority to load: '
- + id, requirer);
-
- uri = requirement;
- } else {
- // If requirer is off manifest than it's a system module and we allow it
- // to go off manifest by resolving a relative path.
- uri = loaderModule.resolve(id, requirer);
- }
- return uri;
- },
- load: function(loader, module) {
- let result;
- let error;
-
- // In order to get the module's metadata, we need to load the module.
- // if an exception is raised here, it could be that is due to application
- // incompatibility. Therefore the exception is stored, and thrown again
- // only if the module seems be compatible with the application currently
- // running. Otherwise the incompatibility message takes the precedence.
- try {
- result = load(loader, module);
- }
- catch (e) {
- error = e;
- }
-
- error = incompatibility(module) || error;
-
- if (error)
- throw error;
-
- return result;
- }
- });
-
- let loader = loaderModule.Loader(options);
- // Hack to allow loading from `toolkit/loader`.
- loader.modules[loaderURI] = loaderSandbox;
- return loader;
-}
-
-exports = override(loaderModule, {
- Loader: CuddlefishLoader
-});
diff --git a/addon-sdk/source/lib/sdk/loader/sandbox.js b/addon-sdk/source/lib/sdk/loader/sandbox.js
deleted file mode 100644
index 791dbc086..000000000
--- a/addon-sdk/source/lib/sdk/loader/sandbox.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";
-
-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');
-
-const { devtools } = Cu.import("resource://devtools/shared/Loader.jsm", {});
-const { require: devtoolsRequire } = devtools;
-const { addContentGlobal, removeContentGlobal } = devtoolsRequire("devtools/server/content-globals");
-
-/**
- * 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);
- let innerWindowID = options.metadata['inner-window-id']
- if (innerWindowID) {
- addContentGlobal({
- global: sandbox,
- 'inner-window-id': innerWindowID
- });
- }
- 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.loadSubScript(uri, sandbox, 'UTF-8');
- }
-}
-exports.load = load;
-
-/**
- * Forces the given `sandbox` to be freed immediately.
- */
-exports.nuke = Cu.nukeSandbox
diff --git a/addon-sdk/source/lib/sdk/messaging.js b/addon-sdk/source/lib/sdk/messaging.js
deleted file mode 100644
index 07580eb33..000000000
--- a/addon-sdk/source/lib/sdk/messaging.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": "unstable"
-};
-
-const { window } = require("sdk/addon/window");
-exports.MessageChannel = window.MessageChannel;
-exports.MessagePort = window.MessagePort;
diff --git a/addon-sdk/source/lib/sdk/model/core.js b/addon-sdk/source/lib/sdk/model/core.js
deleted file mode 100644
index 315f8b1cd..000000000
--- a/addon-sdk/source/lib/sdk/model/core.js
+++ /dev/null
@@ -1,23 +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 { dispatcher } = require("../util/dispatcher");
-
-
-// Define `modelFor` accessor function that can be implemented
-// for different types of views. Since view's we'll be dealing
-// with types that don't really play well with `instanceof`
-// operator we're gonig to use `dispatcher` that is slight
-// extension over polymorphic dispatch provided by method.
-// This allows models to extend implementations of this by
-// providing predicates:
-//
-// modelFor.when($ => $ && $.nodeName === "tab", findTabById($.id))
-const modelFor = dispatcher("modelFor");
-exports.modelFor = modelFor;
diff --git a/addon-sdk/source/lib/sdk/net/url.js b/addon-sdk/source/lib/sdk/net/url.js
deleted file mode 100644
index 5502171ee..000000000
--- a/addon-sdk/source/lib/sdk/net/url.js
+++ /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";
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const { Ci, Cu, components } = require("chrome");
-
-const { defer } = require("../core/promise");
-const { merge } = require("../util/object");
-
-const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
-const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-
-/**
- * Reads a URI and returns a promise.
- *
- * @param uri {string} The URI to read
- * @param [options] {object} This parameter can have any or all of the following
- * fields: `charset`. By default the `charset` is set to 'UTF-8'.
- *
- * @returns {promise} The promise that will be resolved with the content of the
- * URL given.
- *
- * @example
- * let promise = readURI('resource://gre/modules/NetUtil.jsm', {
- * charset: 'US-ASCII'
- * });
- */
-function readURI(uri, options) {
- options = options || {};
- let charset = options.charset || 'UTF-8';
-
- let channel = NetUtil.newChannel({
- uri: NetUtil.newURI(uri, charset),
- loadUsingSystemPrincipal: true});
-
- let { promise, resolve, reject } = defer();
-
- try {
- NetUtil.asyncFetch(channel, function (stream, result) {
- if (components.isSuccessCode(result)) {
- let count = stream.available();
- let data = NetUtil.readInputStreamToString(stream, count, { charset : charset });
-
- resolve(data);
- } else {
- reject("Failed to read: '" + uri + "' (Error Code: " + result + ")");
- }
- });
- }
- catch (e) {
- reject("Failed to read: '" + uri + "' (Error: " + e.message + ")");
- }
-
- return promise;
-}
-
-exports.readURI = readURI;
-
-/**
- * Reads a URI synchronously.
- * This function is intentionally undocumented to favorites the `readURI` usage.
- *
- * @param uri {string} The URI to read
- * @param [charset] {string} The character set to use when read the content of
- * the `uri` given. By default is set to 'UTF-8'.
- *
- * @returns {string} The content of the URI given.
- *
- * @example
- * let data = readURISync('resource://gre/modules/NetUtil.jsm');
- */
-function readURISync(uri, charset) {
- charset = typeof charset === "string" ? charset : "UTF-8";
-
- let channel = NetUtil.newChannel({
- uri: NetUtil.newURI(uri, charset),
- loadUsingSystemPrincipal: true});
- let stream = channel.open2();
-
- let count = stream.available();
- let data = NetUtil.readInputStreamToString(stream, count, { charset : charset });
-
- stream.close();
-
- return data;
-}
-
-exports.readURISync = readURISync;
diff --git a/addon-sdk/source/lib/sdk/net/xhr.js b/addon-sdk/source/lib/sdk/net/xhr.js
deleted file mode 100644
index 415b9cbf4..000000000
--- a/addon-sdk/source/lib/sdk/net/xhr.js
+++ /dev/null
@@ -1,36 +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 { deprecateFunction } = require("../util/deprecate");
-const { Cc, Ci } = require("chrome");
-const XMLHttpRequest = require("../addon/window").window.XMLHttpRequest;
-
-Object.defineProperties(XMLHttpRequest.prototype, {
- mozBackgroundRequest: {
- value: true,
- },
- forceAllowThirdPartyCookie: {
- configurable: true,
- value: deprecateFunction(function() {
- forceAllowThirdPartyCookie(this);
-
- }, "`xhr.forceAllowThirdPartyCookie()` is deprecated, please use" +
- "`require('sdk/net/xhr').forceAllowThirdPartyCookie(request)` instead")
- }
-});
-exports.XMLHttpRequest = XMLHttpRequest;
-
-function forceAllowThirdPartyCookie(xhr) {
- if (xhr.channel instanceof Ci.nsIHttpChannelInternal)
- xhr.channel.forceAllowThirdPartyCookie = true;
-}
-exports.forceAllowThirdPartyCookie = forceAllowThirdPartyCookie;
-
-// No need to handle add-on unloads as addon/window is closed at unload
-// and it will take down all the associated requests.
diff --git a/addon-sdk/source/lib/sdk/notifications.js b/addon-sdk/source/lib/sdk/notifications.js
deleted file mode 100644
index 752e08fb1..000000000
--- a/addon-sdk/source/lib/sdk/notifications.js
+++ /dev/null
@@ -1,112 +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 { Cc, Ci, Cr } = require("chrome");
-const apiUtils = require("./deprecated/api-utils");
-const { isString, isUndefined, instanceOf } = require('./lang/type');
-const { URL, isLocalURL } = require('./url');
-const { data } = require('./self');
-
-const NOTIFICATION_DIRECTIONS = ["auto", "ltr", "rtl"];
-
-try {
- let alertServ = Cc["@mozilla.org/alerts-service;1"].
- getService(Ci.nsIAlertsService);
-
- // The unit test sets this to a mock notification function.
- var notify = alertServ.showAlertNotification.bind(alertServ);
-}
-catch (err) {
- // An exception will be thrown if the platform doesn't provide an alert
- // service, e.g., if Growl is not installed on OS X. In that case, use a
- // mock notification function that just logs to the console.
- notify = notifyUsingConsole;
-}
-
-exports.notify = function notifications_notify(options) {
- let valOpts = validateOptions(options);
- let clickObserver = !valOpts.onClick ? null : {
- observe: (subject, topic, data) => {
- if (topic === "alertclickcallback") {
- try {
- valOpts.onClick.call(exports, valOpts.data);
- }
- catch(e) {
- console.exception(e);
- }
- }
- }
- };
- function notifyWithOpts(notifyFn) {
- let { iconURL } = valOpts;
- iconURL = iconURL && isLocalURL(iconURL) ? data.url(iconURL) : iconURL;
-
- notifyFn(iconURL, valOpts.title, valOpts.text, !!clickObserver,
- valOpts.data, clickObserver, valOpts.tag, valOpts.dir, valOpts.lang);
- }
- try {
- notifyWithOpts(notify);
- }
- catch (err) {
- if (err instanceof Ci.nsIException && err.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
- console.warn("The notification icon named by " + iconURL +
- " does not exist. A default icon will be used instead.");
- delete valOpts.iconURL;
- notifyWithOpts(notify);
- }
- else {
- notifyWithOpts(notifyUsingConsole);
- }
- }
-};
-
-function notifyUsingConsole(iconURL, title, text) {
- title = title ? "[" + title + "]" : "";
- text = text || "";
- let str = [title, text].filter(s => s).join(" ");
- console.log(str);
-}
-
-function validateOptions(options) {
- return apiUtils.validateOptions(options, {
- data: {
- is: ["string", "undefined"]
- },
- iconURL: {
- is: ["string", "undefined", "object"],
- ok: function(value) {
- return isUndefined(value) || isString(value) || (value instanceof URL);
- },
- msg: "`iconURL` must be a string or an URL instance."
- },
- onClick: {
- is: ["function", "undefined"]
- },
- text: {
- is: ["string", "undefined", "number"]
- },
- title: {
- is: ["string", "undefined", "number"]
- },
- tag: {
- is: ["string", "undefined", "number"]
- },
- dir: {
- is: ["string", "undefined"],
- ok: function(value) {
- return isUndefined(value) || ~NOTIFICATION_DIRECTIONS.indexOf(value);
- },
- msg: '`dir` option must be one of: "auto", "ltr" or "rtl".'
- },
- lang: {
- is: ["string", "undefined"]
- }
- });
-}
diff --git a/addon-sdk/source/lib/sdk/output/system.js b/addon-sdk/source/lib/sdk/output/system.js
deleted file mode 100644
index 4fb16dcd5..000000000
--- a/addon-sdk/source/lib/sdk/output/system.js
+++ /dev/null
@@ -1,71 +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, Cr } = require("chrome");
-const { Input, start, stop, receive, outputs } = require("../event/utils");
-const { id: addonID } = require("../self");
-const { setImmediate } = require("../timers");
-const { notifyObservers } = Cc['@mozilla.org/observer-service;1'].
- getService(Ci.nsIObserverService);
-
-const NOT_AN_INPUT = "OutputPort can be used only for sending messages";
-
-// `OutputPort` creates a port to which messages can be send. Those
-// messages are actually disptached as `subject`'s of the observer
-// notifications. This is handy for communicating between different
-// components of the SDK. By default messages are dispatched
-// asynchronously, although `options.sync` can be used to make them
-// synchronous. If `options.id` is given `topic` for observer
-// notifications is generated by namespacing it, to avoid spamming
-// other SDK add-ons. It's also possible to provide `options.topic`
-// to use excat `topic` without namespacing it.
-//
-// Note: Symmetric `new InputPort({ id: "x" })` instances can be used to
-// receive messages send to the instances of `new OutputPort({ id: "x" })`.
-const OutputPort = function({id, topic, sync}) {
- this.id = id || topic;
- this.sync = !!sync;
- this.topic = topic || "sdk:" + addonID + ":" + id;
-};
-// OutputPort extends base signal type to implement same message
-// receiving interface.
-OutputPort.prototype = new Input();
-OutputPort.constructor = OutputPort;
-
-// OutputPort can not be consumed there for starting or stopping it
-// is not supported.
-OutputPort.prototype[start] = _ => { throw TypeError(NOT_AN_INPUT); };
-OutputPort.prototype[stop] = _ => { throw TypeError(NOT_AN_INPUT); };
-
-// Port reecives message send to it, which will be dispatched via
-// observer notification service.
-OutputPort.receive = ({topic, sync}, message) => {
- const type = typeof(message);
- const supported = message === null ||
- type === "object" ||
- type === "function";
-
- // There is no sensible way to wrap JS primitives that would make sense
- // for general observer notification users. It's also probably not very
- // useful to dispatch JS primitives as subject of observer service, there
- // for we do not support those use cases.
- if (!supported)
- throw new TypeError("Unsupproted message type: `" + type + "`");
-
- // Normalize `message` to create a valid observer notification `subject`.
- // If `message` is `null`, implements `nsISupports` interface or already
- // represents wrapped JS object use it as is. Otherwise create a wrapped
- // object so that observers could receive it.
- const subject = message === null ? null :
- message instanceof Ci.nsISupports ? message :
- message.wrappedJSObject ? message :
- {wrappedJSObject: message};
- if (sync)
- notifyObservers(subject, topic, null);
- else
- setImmediate(notifyObservers, subject, topic, null);
-};
-OutputPort.prototype[receive] = OutputPort.receive;
-exports.OutputPort = OutputPort;
diff --git a/addon-sdk/source/lib/sdk/page-mod.js b/addon-sdk/source/lib/sdk/page-mod.js
deleted file mode 100644
index 538be2732..000000000
--- a/addon-sdk/source/lib/sdk/page-mod.js
+++ /dev/null
@@ -1,190 +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 { contract: loaderContract } = require('./content/loader');
-const { contract } = require('./util/contract');
-const { WorkerHost, connect } = require('./content/utils');
-const { Class } = require('./core/heritage');
-const { Disposable } = require('./core/disposable');
-const { Worker } = require('./content/worker');
-const { EventTarget } = require('./event/target');
-const { on, emit, once, setListeners } = require('./event/core');
-const { isRegExp, isUndefined } = require('./lang/type');
-const { merge, omit } = require('./util/object');
-const { remove, has, hasAny } = require("./util/array");
-const { Rules } = require("./util/rules");
-const { processes, frames, remoteRequire } = require('./remote/parent');
-remoteRequire('sdk/content/page-mod');
-
-const pagemods = new Map();
-const workers = new Map();
-const models = new WeakMap();
-var modelFor = (mod) => models.get(mod);
-var workerFor = (mod) => workers.get(mod)[0];
-
-// Helper functions
-var isRegExpOrString = (v) => isRegExp(v) || typeof v === 'string';
-
-var PAGEMOD_ID = 0;
-
-// Validation Contracts
-const modOptions = {
- // contentStyle* / contentScript* are sharing the same validation constraints,
- // so they can be mostly reused, except for the messages.
- contentStyle: merge(Object.create(loaderContract.rules.contentScript), {
- msg: 'The `contentStyle` option must be a string or an array of strings.'
- }),
- contentStyleFile: merge(Object.create(loaderContract.rules.contentScriptFile), {
- msg: 'The `contentStyleFile` option must be a local URL or an array of URLs'
- }),
- include: {
- is: ['string', 'array', 'regexp'],
- ok: (rule) => {
- if (isRegExpOrString(rule))
- return true;
- if (Array.isArray(rule) && rule.length > 0)
- return rule.every(isRegExpOrString);
- return false;
- },
- msg: 'The `include` option must always contain atleast one rule as a string, regular expression, or an array of strings and regular expressions.'
- },
- exclude: {
- is: ['string', 'array', 'regexp', 'undefined'],
- ok: (rule) => {
- if (isRegExpOrString(rule) || isUndefined(rule))
- return true;
- if (Array.isArray(rule) && rule.length > 0)
- return rule.every(isRegExpOrString);
- return false;
- },
- msg: 'If set, the `exclude` option must always contain at least one ' +
- 'rule as a string, regular expression, or an array of strings and ' +
- 'regular expressions.'
- },
- attachTo: {
- is: ['string', 'array', 'undefined'],
- map: function (attachTo) {
- if (!attachTo) return ['top', 'frame'];
- if (typeof attachTo === 'string') return [attachTo];
- return attachTo;
- },
- ok: function (attachTo) {
- return hasAny(attachTo, ['top', 'frame']) &&
- attachTo.every(has.bind(null, ['top', 'frame', 'existing']));
- },
- msg: 'The `attachTo` option must be a string or an array of strings. ' +
- 'The only valid options are "existing", "top" and "frame", and must ' +
- 'contain at least "top" or "frame" values.'
- },
-};
-
-const modContract = contract(merge({}, loaderContract.rules, modOptions));
-
-/**
- * PageMod constructor (exported below).
- * @constructor
- */
-const PageMod = Class({
- implements: [
- modContract.properties(modelFor),
- EventTarget,
- Disposable,
- ],
- extends: WorkerHost(workerFor),
- setup: function PageMod(options) {
- let mod = this;
- let model = modContract(options);
- models.set(this, model);
- model.id = PAGEMOD_ID++;
-
- let include = model.include;
- model.include = Rules();
- model.include.add.apply(model.include, [].concat(include));
-
- let exclude = isUndefined(model.exclude) ? [] : model.exclude;
- model.exclude = Rules();
- model.exclude.add.apply(model.exclude, [].concat(exclude));
-
- // Set listeners on {PageMod} itself, not the underlying worker,
- // like `onMessage`, as it'll get piped.
- setListeners(this, options);
-
- pagemods.set(model.id, this);
- workers.set(this, []);
-
- function serializeRules(rules) {
- for (let rule of rules) {
- yield isRegExp(rule) ? { type: "regexp", pattern: rule.source, flags: rule.flags }
- : { type: "string", value: rule };
- }
- }
-
- model.childOptions = omit(model, ["include", "exclude", "contentScriptOptions"]);
- model.childOptions.include = [...serializeRules(model.include)];
- model.childOptions.exclude = [...serializeRules(model.exclude)];
- model.childOptions.contentScriptOptions = model.contentScriptOptions ?
- JSON.stringify(model.contentScriptOptions) :
- null;
-
- processes.port.emit('sdk/page-mod/create', model.childOptions);
- },
-
- dispose: function(reason) {
- processes.port.emit('sdk/page-mod/destroy', modelFor(this).id);
- pagemods.delete(modelFor(this).id);
- workers.delete(this);
- },
-
- destroy: function(reason) {
- // Explicit destroy call, i.e. not via unload so destroy the workers
- let list = workers.get(this);
- if (!list)
- return;
-
- // Triggers dispose which will cause the child page-mod to be destroyed
- Disposable.prototype.destroy.call(this, reason);
-
- // Destroy any active workers
- for (let worker of list)
- worker.destroy(reason);
- }
-});
-exports.PageMod = PageMod;
-
-// Whenever a new process starts send over the list of page-mods
-processes.forEvery(process => {
- for (let mod of pagemods.values())
- process.port.emit('sdk/page-mod/create', modelFor(mod).childOptions);
-});
-
-frames.port.on('sdk/page-mod/worker-create', (frame, modId, workerOptions) => {
- let mod = pagemods.get(modId);
- if (!mod)
- return;
-
- // Attach the parent side of the worker to the child
- let worker = Worker();
-
- workers.get(mod).unshift(worker);
- worker.on('*', (event, ...args) => {
- // page-mod's "attach" event needs to be passed a worker
- if (event === 'attach')
- emit(mod, event, worker)
- else
- emit(mod, event, ...args);
- });
-
- worker.on('detach', () => {
- let array = workers.get(mod);
- if (array)
- remove(array, worker);
- });
-
- connect(worker, frame, workerOptions);
-});
diff --git a/addon-sdk/source/lib/sdk/page-mod/match-pattern.js b/addon-sdk/source/lib/sdk/page-mod/match-pattern.js
deleted file mode 100644
index afbbd401e..000000000
--- a/addon-sdk/source/lib/sdk/page-mod/match-pattern.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 { deprecateUsage } = require("../util/deprecate");
-
-deprecateUsage("Module 'sdk/page-mod/match-pattern' is deprecated use 'sdk/util/match-pattern' instead");
-
-module.exports = require("../util/match-pattern");
diff --git a/addon-sdk/source/lib/sdk/page-worker.js b/addon-sdk/source/lib/sdk/page-worker.js
deleted file mode 100644
index 837cf774b..000000000
--- a/addon-sdk/source/lib/sdk/page-worker.js
+++ /dev/null
@@ -1,194 +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 { Class } = require('./core/heritage');
-const { ns } = require('./core/namespace');
-const { pipe, stripListeners } = require('./event/utils');
-const { connect, destroy, WorkerHost } = require('./content/utils');
-const { Worker } = require('./content/worker');
-const { Disposable } = require('./core/disposable');
-const { EventTarget } = require('./event/target');
-const { setListeners } = require('./event/core');
-const { window } = require('./addon/window');
-const { create: makeFrame, getDocShell } = require('./frame/utils');
-const { contract } = require('./util/contract');
-const { contract: loaderContract } = require('./content/loader');
-const { Rules } = require('./util/rules');
-const { merge } = require('./util/object');
-const { uuid } = require('./util/uuid');
-const { useRemoteProcesses, remoteRequire, frames } = require("./remote/parent");
-remoteRequire("sdk/content/page-worker");
-
-const workers = new WeakMap();
-const pages = new Map();
-
-const internal = ns();
-
-let workerFor = (page) => workers.get(page);
-let isDisposed = (page) => !pages.has(internal(page).id);
-
-// The frame is used to ensure we have a remote process to load workers in
-let remoteFrame = null;
-let framePromise = null;
-function getFrame() {
- if (framePromise)
- return framePromise;
-
- framePromise = new Promise(resolve => {
- let view = makeFrame(window.document, {
- namespaceURI: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
- nodeName: "iframe",
- type: "content",
- remote: useRemoteProcesses,
- uri: "about:blank"
- });
-
- // Wait for the remote side to connect
- let listener = (frame) => {
- if (frame.frameElement != view)
- return;
- frames.off("attach", listener);
- remoteFrame = frame;
- resolve(frame);
- }
- frames.on("attach", listener);
- });
- return framePromise;
-}
-
-var pageContract = contract(merge({
- allow: {
- is: ['object', 'undefined', 'null'],
- map: function (allow) { return { script: !allow || allow.script !== false }}
- },
- onMessage: {
- is: ['function', 'undefined']
- },
- include: {
- is: ['string', 'array', 'regexp', 'undefined']
- },
- contentScriptWhen: {
- is: ['string', 'undefined'],
- map: (when) => when || "end"
- }
-}, loaderContract.rules));
-
-function enableScript (page) {
- getDocShell(viewFor(page)).allowJavascript = true;
-}
-
-function disableScript (page) {
- getDocShell(viewFor(page)).allowJavascript = false;
-}
-
-function Allow (page) {
- return {
- get script() {
- return internal(page).options.allow.script;
- },
- set script(value) {
- internal(page).options.allow.script = value;
-
- if (isDisposed(page))
- return;
-
- remoteFrame.port.emit("sdk/frame/set", internal(page).id, { allowScript: value });
- }
- };
-}
-
-function isValidURL(page, url) {
- return !page.rules || page.rules.matchesAny(url);
-}
-
-const Page = Class({
- implements: [
- EventTarget,
- Disposable
- ],
- extends: WorkerHost(workerFor),
- setup: function Page(options) {
- options = pageContract(options);
- // Sanitize the options
- if ("contentScriptOptions" in options)
- options.contentScriptOptions = JSON.stringify(options.contentScriptOptions);
-
- internal(this).id = uuid().toString();
- internal(this).options = options;
-
- for (let prop of ['contentScriptFile', 'contentScript', 'contentScriptWhen']) {
- this[prop] = options[prop];
- }
-
- pages.set(internal(this).id, this);
-
- // Set listeners on the {Page} object itself, not the underlying worker,
- // like `onMessage`, as it gets piped
- setListeners(this, options);
- let worker = new Worker(stripListeners(options));
- workers.set(this, worker);
- pipe(worker, this);
-
- if (options.include) {
- this.rules = Rules();
- this.rules.add.apply(this.rules, [].concat(options.include));
- }
-
- getFrame().then(frame => {
- if (isDisposed(this))
- return;
-
- frame.port.emit("sdk/frame/create", internal(this).id, stripListeners(options));
- });
- },
- get allow() { return Allow(this); },
- set allow(value) {
- if (isDisposed(this))
- return;
- this.allow.script = pageContract({ allow: value }).allow.script;
- },
- get contentURL() {
- return internal(this).options.contentURL;
- },
- set contentURL(value) {
- if (!isValidURL(this, value))
- return;
- internal(this).options.contentURL = value;
- if (isDisposed(this))
- return;
-
- remoteFrame.port.emit("sdk/frame/set", internal(this).id, { contentURL: value });
- },
- dispose: function () {
- if (isDisposed(this))
- return;
- pages.delete(internal(this).id);
- let worker = workerFor(this);
- if (worker)
- destroy(worker);
- remoteFrame.port.emit("sdk/frame/destroy", internal(this).id);
-
- // Destroy the remote frame if all the pages have been destroyed
- if (pages.size == 0) {
- framePromise = null;
- remoteFrame.frameElement.remove();
- remoteFrame = null;
- }
- },
- toString: function () { return '[object Page]' }
-});
-
-exports.Page = Page;
-
-frames.port.on("sdk/frame/connect", (frame, id, params) => {
- let page = pages.get(id);
- if (!page)
- return;
- connect(workerFor(page), frame, params);
-});
diff --git a/addon-sdk/source/lib/sdk/panel.js b/addon-sdk/source/lib/sdk/panel.js
deleted file mode 100644
index 4b625799d..000000000
--- a/addon-sdk/source/lib/sdk/panel.js
+++ /dev/null
@@ -1,427 +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";
-
-// The panel module currently supports only Firefox and SeaMonkey.
-// See: https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps
-module.metadata = {
- "stability": "stable",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cu, Ci } = require("chrome");
-const { setTimeout } = require('./timers');
-const { Class } = require("./core/heritage");
-const { merge } = require("./util/object");
-const { WorkerHost } = require("./content/utils");
-const { Worker } = require("./deprecated/sync-worker");
-const { Disposable } = require("./core/disposable");
-const { WeakReference } = require('./core/reference');
-const { contract: loaderContract } = require("./content/loader");
-const { contract } = require("./util/contract");
-const { on, off, emit, setListeners } = require("./event/core");
-const { EventTarget } = require("./event/target");
-const domPanel = require("./panel/utils");
-const { getDocShell } = require('./frame/utils');
-const { events } = require("./panel/events");
-const systemEvents = require("./system/events");
-const { filter, pipe, stripListeners } = require("./event/utils");
-const { getNodeView, getActiveView } = require("./view/core");
-const { isNil, isObject, isNumber } = require("./lang/type");
-const { getAttachEventType } = require("./content/utils");
-const { number, boolean, object } = require('./deprecated/api-utils');
-const { Style } = require("./stylesheet/style");
-const { attach, detach } = require("./content/mod");
-
-var isRect = ({top, right, bottom, left}) => [top, right, bottom, left].
- some(value => isNumber(value) && !isNaN(value));
-
-var isSDKObj = obj => obj instanceof Class;
-
-var rectContract = contract({
- top: number,
- right: number,
- bottom: number,
- left: number
-});
-
-var position = {
- is: object,
- map: v => (isNil(v) || isSDKObj(v) || !isObject(v)) ? v : rectContract(v),
- ok: v => isNil(v) || isSDKObj(v) || (isObject(v) && isRect(v)),
- msg: 'The option "position" must be a SDK object registered as anchor; ' +
- 'or an object with one or more of the following keys set to numeric ' +
- 'values: top, right, bottom, left.'
-}
-
-var displayContract = contract({
- width: number,
- height: number,
- focus: boolean,
- position: position
-});
-
-var panelContract = contract(merge({
- // contentStyle* / contentScript* are sharing the same validation constraints,
- // so they can be mostly reused, except for the messages.
- contentStyle: merge(Object.create(loaderContract.rules.contentScript), {
- msg: 'The `contentStyle` option must be a string or an array of strings.'
- }),
- contentStyleFile: merge(Object.create(loaderContract.rules.contentScriptFile), {
- msg: 'The `contentStyleFile` option must be a local URL or an array of URLs'
- }),
- contextMenu: boolean,
- allow: {
- is: ['object', 'undefined', 'null'],
- map: function (allow) { return { script: !allow || allow.script !== false }}
- },
-}, displayContract.rules, loaderContract.rules));
-
-function Allow(panel) {
- return {
- get script() { return getDocShell(viewFor(panel).backgroundFrame).allowJavascript; },
- set script(value) { return setScriptState(panel, value); },
- };
-}
-
-function setScriptState(panel, value) {
- let view = viewFor(panel);
- getDocShell(view.backgroundFrame).allowJavascript = value;
- getDocShell(view.viewFrame).allowJavascript = value;
- view.setAttribute("sdkscriptenabled", "" + value);
-}
-
-function isDisposed(panel) {
- return !views.has(panel);
-}
-
-var panels = new WeakMap();
-var models = new WeakMap();
-var views = new WeakMap();
-var workers = new WeakMap();
-var styles = new WeakMap();
-
-const viewFor = (panel) => views.get(panel);
-const modelFor = (panel) => models.get(panel);
-const panelFor = (view) => panels.get(view);
-const workerFor = (panel) => workers.get(panel);
-const styleFor = (panel) => styles.get(panel);
-
-function getPanelFromWeakRef(weakRef) {
- if (!weakRef) {
- return null;
- }
- let panel = weakRef.get();
- if (!panel) {
- return null;
- }
- if (isDisposed(panel)) {
- return null;
- }
- return panel;
-}
-
-var SinglePanelManager = {
- visiblePanel: null,
- enqueuedPanel: null,
- enqueuedPanelCallback: null,
- // Calls |callback| with no arguments when the panel may be shown.
- requestOpen: function(panelToOpen, callback) {
- let currentPanel = getPanelFromWeakRef(SinglePanelManager.visiblePanel);
- if (currentPanel || SinglePanelManager.enqueuedPanel) {
- SinglePanelManager.enqueuedPanel = Cu.getWeakReference(panelToOpen);
- SinglePanelManager.enqueuedPanelCallback = callback;
- if (currentPanel && currentPanel.isShowing) {
- currentPanel.hide();
- }
- } else {
- SinglePanelManager.notifyPanelCanOpen(panelToOpen, callback);
- }
- },
- notifyPanelCanOpen: function(panel, callback) {
- let view = viewFor(panel);
- // Can't pass an arrow function as the event handler because we need to be
- // able to call |removeEventListener| later.
- view.addEventListener("popuphidden", SinglePanelManager.onVisiblePanelHidden, true);
- view.addEventListener("popupshown", SinglePanelManager.onVisiblePanelShown, false);
- SinglePanelManager.enqueuedPanel = null;
- SinglePanelManager.enqueuedPanelCallback = null;
- SinglePanelManager.visiblePanel = Cu.getWeakReference(panel);
- callback();
- },
- onVisiblePanelShown: function(event) {
- let panel = panelFor(event.target);
- if (SinglePanelManager.enqueuedPanel) {
- // Another panel started waiting for |panel| to close before |panel| was
- // even done opening.
- panel.hide();
- }
- },
- onVisiblePanelHidden: function(event) {
- let view = event.target;
- let panel = panelFor(view);
- let currentPanel = getPanelFromWeakRef(SinglePanelManager.visiblePanel);
- if (currentPanel && currentPanel != panel) {
- return;
- }
- SinglePanelManager.visiblePanel = null;
- view.removeEventListener("popuphidden", SinglePanelManager.onVisiblePanelHidden, true);
- view.removeEventListener("popupshown", SinglePanelManager.onVisiblePanelShown, false);
- let nextPanel = getPanelFromWeakRef(SinglePanelManager.enqueuedPanel);
- let nextPanelCallback = SinglePanelManager.enqueuedPanelCallback;
- if (nextPanel) {
- SinglePanelManager.notifyPanelCanOpen(nextPanel, nextPanelCallback);
- }
- }
-};
-
-const Panel = Class({
- implements: [
- // Generate accessors for the validated properties that update model on
- // set and return values from model on get.
- panelContract.properties(modelFor),
- EventTarget,
- Disposable,
- WeakReference
- ],
- extends: WorkerHost(workerFor),
- setup: function setup(options) {
- let model = merge({
- defaultWidth: 320,
- defaultHeight: 240,
- focus: true,
- position: Object.freeze({}),
- contextMenu: false
- }, panelContract(options));
- model.ready = false;
- models.set(this, model);
-
- if (model.contentStyle || model.contentStyleFile) {
- styles.set(this, Style({
- uri: model.contentStyleFile,
- source: model.contentStyle
- }));
- }
-
- // Setup view
- let viewOptions = {allowJavascript: !model.allow || (model.allow.script !== false)};
- let view = domPanel.make(null, viewOptions);
- panels.set(view, this);
- views.set(this, view);
-
- // Load panel content.
- domPanel.setURL(view, model.contentURL);
-
- // Allow context menu
- domPanel.allowContextMenu(view, model.contextMenu);
-
- // Setup listeners.
- setListeners(this, options);
- let worker = new Worker(stripListeners(options));
- workers.set(this, worker);
-
- // pipe events from worker to a panel.
- pipe(worker, this);
- },
- dispose: function dispose() {
- this.hide();
- off(this);
-
- workerFor(this).destroy();
- detach(styleFor(this));
-
- domPanel.dispose(viewFor(this));
-
- // Release circular reference between view and panel instance. This
- // way view will be GC-ed. And panel as well once all the other refs
- // will be removed from it.
- views.delete(this);
- },
- /* Public API: Panel.width */
- get width() {
- return modelFor(this).width;
- },
- set width(value) {
- this.resize(value, this.height);
- },
- /* Public API: Panel.height */
- get height() {
- return modelFor(this).height;
- },
- set height(value) {
- this.resize(this.width, value);
- },
-
- /* Public API: Panel.focus */
- get focus() {
- return modelFor(this).focus;
- },
-
- /* Public API: Panel.position */
- get position() {
- return modelFor(this).position;
- },
-
- /* Public API: Panel.contextMenu */
- get contextMenu() {
- return modelFor(this).contextMenu;
- },
- set contextMenu(allow) {
- let model = modelFor(this);
- model.contextMenu = panelContract({ contextMenu: allow }).contextMenu;
- domPanel.allowContextMenu(viewFor(this), model.contextMenu);
- },
-
- get contentURL() {
- return modelFor(this).contentURL;
- },
- set contentURL(value) {
- let model = modelFor(this);
- model.contentURL = panelContract({ contentURL: value }).contentURL;
- domPanel.setURL(viewFor(this), model.contentURL);
- // Detach worker so that messages send will be queued until it's
- // reatached once panel content is ready.
- workerFor(this).detach();
- },
-
- get allow() { return Allow(this); },
- set allow(value) {
- let allowJavascript = panelContract({ allow: value }).allow.script;
- return setScriptState(this, value);
- },
-
- /* Public API: Panel.isShowing */
- get isShowing() {
- return !isDisposed(this) && domPanel.isOpen(viewFor(this));
- },
-
- /* Public API: Panel.show */
- show: function show(options={}, anchor) {
- SinglePanelManager.requestOpen(this, () => {
- if (options instanceof Ci.nsIDOMElement) {
- [anchor, options] = [options, null];
- }
-
- if (anchor instanceof Ci.nsIDOMElement) {
- console.warn(
- "Passing a DOM node to Panel.show() method is an unsupported " +
- "feature that will be soon replaced. " +
- "See: https://bugzilla.mozilla.org/show_bug.cgi?id=878877"
- );
- }
-
- let model = modelFor(this);
- let view = viewFor(this);
- let anchorView = getNodeView(anchor || options.position || model.position);
-
- options = merge({
- position: model.position,
- width: model.width,
- height: model.height,
- defaultWidth: model.defaultWidth,
- defaultHeight: model.defaultHeight,
- focus: model.focus,
- contextMenu: model.contextMenu
- }, displayContract(options));
-
- if (!isDisposed(this)) {
- domPanel.show(view, options, anchorView);
- }
- });
- return this;
- },
-
- /* Public API: Panel.hide */
- hide: function hide() {
- // Quit immediately if panel is disposed or there is no state change.
- domPanel.close(viewFor(this));
-
- return this;
- },
-
- /* Public API: Panel.resize */
- resize: function resize(width, height) {
- let model = modelFor(this);
- let view = viewFor(this);
- let change = panelContract({
- width: width || model.width || model.defaultWidth,
- height: height || model.height || model.defaultHeight
- });
-
- model.width = change.width
- model.height = change.height
-
- domPanel.resize(view, model.width, model.height);
-
- return this;
- }
-});
-exports.Panel = Panel;
-
-// Note must be defined only after value to `Panel` is assigned.
-getActiveView.define(Panel, viewFor);
-
-// Filter panel events to only panels that are create by this module.
-var panelEvents = filter(events, ({target}) => panelFor(target));
-
-// Panel events emitted after panel has being shown.
-var shows = filter(panelEvents, ({type}) => type === "popupshown");
-
-// Panel events emitted after panel became hidden.
-var hides = filter(panelEvents, ({type}) => type === "popuphidden");
-
-// Panel events emitted after content inside panel is ready. For different
-// panels ready may mean different state based on `contentScriptWhen` attribute.
-// Weather given event represents readyness is detected by `getAttachEventType`
-// helper function.
-var ready = filter(panelEvents, ({type, target}) =>
- getAttachEventType(modelFor(panelFor(target))) === type);
-
-// Panel event emitted when the contents of the panel has been loaded.
-var readyToShow = filter(panelEvents, ({type}) => type === "DOMContentLoaded");
-
-// Styles should be always added as soon as possible, and doesn't makes them
-// depends on `contentScriptWhen`
-var start = filter(panelEvents, ({type}) => type === "document-element-inserted");
-
-// Forward panel show / hide events to panel's own event listeners.
-on(shows, "data", ({target}) => {
- let panel = panelFor(target);
- if (modelFor(panel).ready)
- emit(panel, "show");
-});
-
-on(hides, "data", ({target}) => {
- let panel = panelFor(target);
- if (modelFor(panel).ready)
- emit(panel, "hide");
-});
-
-on(ready, "data", ({target}) => {
- let panel = panelFor(target);
- let window = domPanel.getContentDocument(target).defaultView;
-
- workerFor(panel).attach(window);
-});
-
-on(readyToShow, "data", ({target}) => {
- let panel = panelFor(target);
-
- if (!modelFor(panel).ready) {
- modelFor(panel).ready = true;
-
- if (viewFor(panel).state == "open")
- emit(panel, "show");
- }
-});
-
-on(start, "data", ({target}) => {
- let panel = panelFor(target);
- let window = domPanel.getContentDocument(target).defaultView;
-
- attach(styleFor(panel), window);
-});
diff --git a/addon-sdk/source/lib/sdk/panel/events.js b/addon-sdk/source/lib/sdk/panel/events.js
deleted file mode 100644
index f3040a11d..000000000
--- a/addon-sdk/source/lib/sdk/panel/events.js
+++ /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";
-
-// This module basically translates system/events to a SDK standard events
-// so that `map`, `filter` and other utilities could be used with them.
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const events = require("../system/events");
-const { emit } = require("../event/core");
-
-var channel = {};
-
-function forward({ subject, type, data }) {
- return emit(channel, "data", { target: subject, type: type, data: data });
-}
-
-["popupshowing", "popuphiding", "popupshown", "popuphidden",
-"document-element-inserted", "DOMContentLoaded", "load"
-].forEach(type => events.on(type, forward));
-
-exports.events = channel;
diff --git a/addon-sdk/source/lib/sdk/panel/utils.js b/addon-sdk/source/lib/sdk/panel/utils.js
deleted file mode 100644
index c85b274bc..000000000
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ /dev/null
@@ -1,451 +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 { Cc, Ci } = require("chrome");
-const { Services } = require("resource://gre/modules/Services.jsm");
-const { setTimeout } = require("../timers");
-const { platform } = require("../system");
-const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
- getHiddenWindow, getScreenPixelsPerCSSPixel } = require("../window/utils");
-
-const { create: createFrame, swapFrameLoaders, getDocShell } = require("../frame/utils");
-const { window: addonWindow } = require("../addon/window");
-const { isNil } = require("../lang/type");
-const { data } = require('../self');
-
-const events = require("../system/events");
-
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-function calculateRegion({ position, width, height, defaultWidth, defaultHeight }, rect) {
- position = position || {};
-
- let x, y;
-
- let hasTop = !isNil(position.top);
- let hasRight = !isNil(position.right);
- let hasBottom = !isNil(position.bottom);
- let hasLeft = !isNil(position.left);
- let hasWidth = !isNil(width);
- let hasHeight = !isNil(height);
-
- // if width is not specified by constructor or show's options, then get
- // the default width
- if (!hasWidth)
- width = defaultWidth;
-
- // if height is not specified by constructor or show's options, then get
- // the default height
- if (!hasHeight)
- height = defaultHeight;
-
- // default position is centered
- x = (rect.right - width) / 2;
- y = (rect.top + rect.bottom - height) / 2;
-
- if (hasTop) {
- y = rect.top + position.top;
-
- if (hasBottom && !hasHeight)
- height = rect.bottom - position.bottom - y;
- }
- else if (hasBottom) {
- y = rect.bottom - position.bottom - height;
- }
-
- if (hasLeft) {
- x = position.left;
-
- if (hasRight && !hasWidth)
- width = rect.right - position.right - x;
- }
- else if (hasRight) {
- x = rect.right - width - position.right;
- }
-
- return {x: x, y: y, width: width, height: height};
-}
-
-function open(panel, options, anchor) {
- // Wait for the XBL binding to be constructed
- if (!panel.openPopup) setTimeout(open, 50, panel, options, anchor);
- else display(panel, options, anchor);
-}
-exports.open = open;
-
-function isOpen(panel) {
- return panel.state === "open"
-}
-exports.isOpen = isOpen;
-
-function isOpening(panel) {
- return panel.state === "showing"
-}
-exports.isOpening = isOpening
-
-function close(panel) {
- // Sometimes "TypeError: panel.hidePopup is not a function" is thrown
- // when quitting the host application while a panel is visible. To suppress
- // these errors, check for "hidePopup" in panel before calling it.
- // It's not clear if there's an issue or it's expected behavior.
- // See Bug 1151796.
-
- return panel.hidePopup && panel.hidePopup();
-}
-exports.close = close
-
-
-function resize(panel, width, height) {
- // Resize the iframe instead of using panel.sizeTo
- // because sizeTo doesn't work with arrow panels
- if (panel.firstChild) {
- panel.firstChild.style.width = width + "px";
- panel.firstChild.style.height = height + "px";
- }
-}
-exports.resize = resize
-
-function display(panel, options, anchor) {
- let document = panel.ownerDocument;
-
- let x, y;
- let { width, height, defaultWidth, defaultHeight } = options;
-
- let popupPosition = null;
-
- // Panel XBL has some SDK incompatible styling decisions. We shim panel
- // instances until proper fix for Bug 859504 is shipped.
- shimDefaultStyle(panel);
-
- if (!anchor) {
- // The XUL Panel doesn't have an arrow, so the margin needs to be reset
- // in order to, be positioned properly
- panel.style.margin = "0";
-
- let viewportRect = document.defaultView.gBrowser.getBoundingClientRect();
-
- ({x, y, width, height} = calculateRegion(options, viewportRect));
- }
- else {
- // The XUL Panel has an arrow, so the margin needs to be reset
- // to the default value.
- panel.style.margin = "";
- let { CustomizableUI, window } = anchor.ownerDocument.defaultView;
-
- // In Australis, widgets may be positioned in an overflow panel or the
- // menu panel.
- // In such cases clicking this widget will hide the overflow/menu panel,
- // and the widget's panel will show instead.
- // If `CustomizableUI` is not available, it means the anchor is not in a
- // chrome browser window, and therefore there is no need for this check.
- if (CustomizableUI) {
- let node = anchor;
- ({anchor} = CustomizableUI.getWidget(anchor.id).forWindow(window));
-
- // if `node` is not the `anchor` itself, it means the widget is
- // positioned in a panel, therefore we have to hide it before show
- // the widget's panel in the same anchor
- if (node !== anchor)
- CustomizableUI.hidePanelForNode(anchor);
- }
-
- width = width || defaultWidth;
- height = height || defaultHeight;
-
- // Open the popup by the anchor.
- let rect = anchor.getBoundingClientRect();
-
- let zoom = getScreenPixelsPerCSSPixel(window);
- let screenX = rect.left + window.mozInnerScreenX * zoom;
- let screenY = rect.top + window.mozInnerScreenY * zoom;
-
- // Set up the vertical position of the popup relative to the anchor
- // (always display the arrow on anchor center)
- let horizontal, vertical;
- if (screenY > window.screen.availHeight / 2 + height)
- vertical = "top";
- else
- vertical = "bottom";
-
- if (screenY > window.screen.availWidth / 2 + width)
- horizontal = "left";
- else
- horizontal = "right";
-
- let verticalInverse = vertical == "top" ? "bottom" : "top";
- popupPosition = vertical + "center " + verticalInverse + horizontal;
-
- // Allow panel to flip itself if the panel can't be displayed at the
- // specified position (useful if we compute a bad position or if the
- // user moves the window and panel remains visible)
- panel.setAttribute("flip", "both");
- }
-
- if (!panel.viewFrame) {
- panel.viewFrame = document.importNode(panel.backgroundFrame, false);
- panel.appendChild(panel.viewFrame);
-
- let {privateBrowsingId} = getDocShell(panel.viewFrame).getOriginAttributes();
- let principal = Services.scriptSecurityManager.createNullPrincipal({privateBrowsingId});
- getDocShell(panel.viewFrame).createAboutBlankContentViewer(principal);
- }
-
- // Resize the iframe instead of using panel.sizeTo
- // because sizeTo doesn't work with arrow panels
- panel.firstChild.style.width = width + "px";
- panel.firstChild.style.height = height + "px";
-
- panel.openPopup(anchor, popupPosition, x, y);
-}
-exports.display = display;
-
-// This utility function is just a workaround until Bug 859504 has shipped.
-function shimDefaultStyle(panel) {
- let document = panel.ownerDocument;
- // Please note that `panel` needs to be part of document in order to reach
- // it's anonymous nodes. One of the anonymous node has a big padding which
- // doesn't work well since panel frame needs to fill all of the panel.
- // XBL binding is a not the best option as it's applied asynchronously, and
- // makes injected frames behave in strange way. Also this feels a lot
- // cheaper to do.
- ["panel-inner-arrowcontent", "panel-arrowcontent"].forEach(function(value) {
- let node = document.getAnonymousElementByAttribute(panel, "class", value);
- if (node) node.style.padding = 0;
- });
-}
-
-function show(panel, options, anchor) {
- // Prevent the panel from getting focus when showing up
- // if focus is set to false
- panel.setAttribute("noautofocus", !options.focus);
-
- let window = anchor && getOwnerBrowserWindow(anchor);
- let { document } = window ? window : getMostRecentBrowserWindow();
- attach(panel, document);
-
- open(panel, options, anchor);
-}
-exports.show = show
-
-function onPanelClick(event) {
- let { target, metaKey, ctrlKey, shiftKey, button } = event;
- let accel = platform === "darwin" ? metaKey : ctrlKey;
- let isLeftClick = button === 0;
- let isMiddleClick = button === 1;
-
- if ((isLeftClick && (accel || shiftKey)) || isMiddleClick) {
- let link = target.closest('a');
-
- if (link && link.href)
- getMostRecentBrowserWindow().openUILink(link.href, event)
- }
-}
-
-function setupPanelFrame(frame) {
- frame.setAttribute("flex", 1);
- frame.setAttribute("transparent", "transparent");
- frame.setAttribute("autocompleteenabled", true);
- frame.setAttribute("tooltip", "aHTMLTooltip");
- if (platform === "darwin") {
- frame.style.borderRadius = "var(--arrowpanel-border-radius, 3.5px)";
- frame.style.padding = "1px";
- }
-}
-
-function make(document, options) {
- document = document || getMostRecentBrowserWindow().document;
- let panel = document.createElementNS(XUL_NS, "panel");
- panel.setAttribute("type", "arrow");
- panel.setAttribute("sdkscriptenabled", options.allowJavascript);
-
- // The panel needs to be attached to a browser window in order for us
- // to copy browser styles to the content document when it loads.
- attach(panel, document);
-
- let frameOptions = {
- allowJavascript: options.allowJavascript,
- allowPlugins: true,
- allowAuth: true,
- allowWindowControl: false,
- // Need to override `nodeName` to use `iframe` as `browsers` save session
- // history and in consequence do not dispatch "inner-window-destroyed"
- // notifications.
- browser: false,
- };
-
- let backgroundFrame = createFrame(addonWindow, frameOptions);
- setupPanelFrame(backgroundFrame);
-
- getDocShell(backgroundFrame).inheritPrivateBrowsingId = false;
-
- function onPopupShowing({type, target}) {
- if (target === this) {
- let attrs = getDocShell(backgroundFrame).getOriginAttributes();
- getDocShell(panel.viewFrame).setOriginAttributes(attrs);
-
- swapFrameLoaders(backgroundFrame, panel.viewFrame);
- }
- }
-
- function onPopupHiding({type, target}) {
- if (target === this) {
- swapFrameLoaders(backgroundFrame, panel.viewFrame);
-
- panel.viewFrame.remove();
- panel.viewFrame = null;
- }
- }
-
- function onContentReady({target, type}) {
- if (target === getContentDocument(panel)) {
- style(panel);
- events.emit(type, { subject: panel });
- }
- }
-
- function onContentLoad({target, type}) {
- if (target === getContentDocument(panel))
- events.emit(type, { subject: panel });
- }
-
- function onContentChange({subject: document, type}) {
- if (document === getContentDocument(panel) && document.defaultView)
- events.emit(type, { subject: panel });
- }
-
- function onPanelStateChange({target, type}) {
- if (target === this)
- events.emit(type, { subject: panel })
- }
-
- panel.addEventListener("popupshowing", onPopupShowing);
- panel.addEventListener("popuphiding", onPopupHiding);
- for (let event of ["popupshowing", "popuphiding", "popupshown", "popuphidden"])
- panel.addEventListener(event, onPanelStateChange);
-
- panel.addEventListener("click", onPanelClick, false);
-
- // Panel content document can be either in panel `viewFrame` or in
- // a `backgroundFrame` depending on panel state. Listeners are set
- // on both to avoid setting and removing listeners on panel state changes.
-
- panel.addEventListener("DOMContentLoaded", onContentReady, true);
- backgroundFrame.addEventListener("DOMContentLoaded", onContentReady, true);
-
- panel.addEventListener("load", onContentLoad, true);
- backgroundFrame.addEventListener("load", onContentLoad, true);
-
- events.on("document-element-inserted", onContentChange);
-
- panel.backgroundFrame = backgroundFrame;
- panel.viewFrame = null;
-
- // Store event listener on the panel instance so that it won't be GC-ed
- // while panel is alive.
- panel.onContentChange = onContentChange;
-
- return panel;
-}
-exports.make = make;
-
-function attach(panel, document) {
- document = document || getMostRecentBrowserWindow().document;
- let container = document.getElementById("mainPopupSet");
- if (container !== panel.parentNode) {
- detach(panel);
- document.getElementById("mainPopupSet").appendChild(panel);
- }
-}
-exports.attach = attach;
-
-function detach(panel) {
- if (panel.parentNode) panel.parentNode.removeChild(panel);
-}
-exports.detach = detach;
-
-function dispose(panel) {
- panel.backgroundFrame.remove();
- panel.backgroundFrame = null;
- events.off("document-element-inserted", panel.onContentChange);
- panel.onContentChange = null;
- detach(panel);
-}
-exports.dispose = dispose;
-
-function style(panel) {
- /**
- Injects default OS specific panel styles into content document that is loaded
- into given panel. Optionally `document` of the browser window can be
- given to inherit styles from it, by default it will use either panel owner
- document or an active browser's document. It should not matter though unless
- Firefox decides to style windows differently base on profile or mode like
- chrome for example.
- **/
-
- try {
- let document = panel.ownerDocument;
- let contentDocument = getContentDocument(panel);
- let window = document.defaultView;
- let node = document.getAnonymousElementByAttribute(panel, "class",
- "panel-arrowcontent");
-
- let { color, fontFamily, fontSize, fontWeight } = window.getComputedStyle(node);
-
- let style = contentDocument.createElement("style");
- style.id = "sdk-panel-style";
- style.textContent = "body { " +
- "color: " + color + ";" +
- "font-family: " + fontFamily + ";" +
- "font-weight: " + fontWeight + ";" +
- "font-size: " + fontSize + ";" +
- "}";
-
- let container = contentDocument.head ? contentDocument.head :
- contentDocument.documentElement;
-
- if (container.firstChild)
- container.insertBefore(style, container.firstChild);
- else
- container.appendChild(style);
- }
- catch (error) {
- console.error("Unable to apply panel style");
- console.exception(error);
- }
-}
-exports.style = style;
-
-var getContentFrame = panel => panel.viewFrame || panel.backgroundFrame;
-exports.getContentFrame = getContentFrame;
-
-function getContentDocument(panel) {
- return getContentFrame(panel).contentDocument;
-}
-exports.getContentDocument = getContentDocument;
-
-function setURL(panel, url) {
- let frame = getContentFrame(panel);
- let webNav = getDocShell(frame).QueryInterface(Ci.nsIWebNavigation);
-
- webNav.loadURI(url ? data.url(url) : "about:blank", 0, null, null, null);
-}
-
-exports.setURL = setURL;
-
-function allowContextMenu(panel, allow) {
- if (allow) {
- panel.setAttribute("context", "contentAreaContextMenu");
- }
- else {
- panel.removeAttribute("context");
- }
-}
-exports.allowContextMenu = allowContextMenu;
diff --git a/addon-sdk/source/lib/sdk/passwords.js b/addon-sdk/source/lib/sdk/passwords.js
deleted file mode 100644
index 70f0aa4da..000000000
--- a/addon-sdk/source/lib/sdk/passwords.js
+++ /dev/null
@@ -1,61 +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 { search, remove, store } = require("./passwords/utils");
-const { defer, delay } = require("./lang/functional");
-
-/**
- * Utility function that returns `onComplete` and `onError` callbacks form the
- * given `options` objects. Also properties are removed from the passed
- * `options` objects.
- * @param {Object} options
- * Object that is passed to the exported functions of this module.
- * @returns {Function[]}
- * Array with two elements `onComplete` and `onError` functions.
- */
-function getCallbacks(options) {
- let value = [
- 'onComplete' in options ? options.onComplete : null,
- 'onError' in options ? defer(options.onError) : console.exception
- ];
-
- delete options.onComplete;
- delete options.onError;
-
- return value;
-};
-
-/**
- * Creates a wrapper function that tries to call `onComplete` with a return
- * value of the wrapped function or falls back to `onError` if wrapped function
- * throws an exception.
- */
-function createWrapperMethod(wrapped) {
- return function (options) {
- let [ onComplete, onError ] = getCallbacks(options);
- try {
- let value = wrapped(options);
- if (onComplete) {
- delay(function() {
- try {
- onComplete(value);
- } catch (exception) {
- onError(exception);
- }
- });
- }
- } catch (exception) {
- onError(exception);
- }
- };
-}
-
-exports.search = createWrapperMethod(search);
-exports.store = createWrapperMethod(store);
-exports.remove = createWrapperMethod(remove);
diff --git a/addon-sdk/source/lib/sdk/passwords/utils.js b/addon-sdk/source/lib/sdk/passwords/utils.js
deleted file mode 100644
index 334efa490..000000000
--- a/addon-sdk/source/lib/sdk/passwords/utils.js
+++ /dev/null
@@ -1,107 +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 { Cc, Ci, CC } = require("chrome");
-const { uri: ADDON_URI } = require("../self");
-const loginManager = Cc["@mozilla.org/login-manager;1"].
- getService(Ci.nsILoginManager);
-const { URL: parseURL } = require("../url");
-const LoginInfo = CC("@mozilla.org/login-manager/loginInfo;1",
- "nsILoginInfo", "init");
-
-function filterMatchingLogins(loginInfo) {
- return Object.keys(this).every(key => loginInfo[key] === this[key], this);
-}
-
-/**
- * Removes `user`, `password` and `path` fields from the given `url` if it's
- * 'http', 'https' or 'ftp'. All other URLs are returned unchanged.
- * @example
- * http://user:pass@www.site.com/foo/?bar=baz#bang -> http://www.site.com
- */
-function normalizeURL(url) {
- let { scheme, host, port } = parseURL(url);
- // We normalize URL only if it's `http`, `https` or `ftp`. All other types of
- // URLs (`resource`, `chrome`, etc..) should not be normalized as they are
- // used with add-on associated credentials path.
- return scheme === "http" || scheme === "https" || scheme === "ftp" ?
- scheme + "://" + (host || "") + (port ? ":" + port : "") :
- url
-}
-
-function Login(options) {
- let login = Object.create(Login.prototype);
- Object.keys(options || {}).forEach(function(key) {
- if (key === 'url')
- login.hostname = normalizeURL(options.url);
- else if (key === 'formSubmitURL')
- login.formSubmitURL = options.formSubmitURL ?
- normalizeURL(options.formSubmitURL) : null;
- else if (key === 'realm')
- login.httpRealm = options.realm;
- else
- login[key] = options[key];
- });
-
- return login;
-}
-Login.prototype.toJSON = function toJSON() {
- return {
- url: this.hostname || ADDON_URI,
- realm: this.httpRealm || null,
- formSubmitURL: this.formSubmitURL || null,
- username: this.username || null,
- password: this.password || null,
- usernameField: this.usernameField || '',
- passwordField: this.passwordField || '',
- }
-};
-Login.prototype.toLoginInfo = function toLoginInfo() {
- let { url, realm, formSubmitURL, username, password, usernameField,
- passwordField } = this.toJSON();
-
- return new LoginInfo(url, formSubmitURL, realm, username, password,
- usernameField, passwordField);
-};
-
-function loginToJSON(value) {
- return Login(value).toJSON();
-}
-
-/**
- * Returns array of `nsILoginInfo` objects that are stored in the login manager
- * and have all the properties with matching values as a given `options` object.
- * @param {Object} options
- * @returns {nsILoginInfo[]}
- */
-exports.search = function search(options) {
- return loginManager.getAllLogins()
- .filter(filterMatchingLogins, Login(options))
- .map(loginToJSON);
-};
-
-/**
- * Stores login info created from the given `options` to the applications
- * built-in login management system.
- * @param {Object} options.
- */
-exports.store = function store(options) {
- loginManager.addLogin(Login(options).toLoginInfo());
-};
-
-/**
- * Removes login info from the applications built-in login management system.
- * _Please note: When removing a login info the specified properties must
- * exactly match to the one that is already stored or exception will be thrown._
- * @param {Object} options.
- */
-exports.remove = function remove(options) {
- loginManager.removeLogin(Login(options).toLoginInfo());
-};
diff --git a/addon-sdk/source/lib/sdk/places/bookmarks.js b/addon-sdk/source/lib/sdk/places/bookmarks.js
deleted file mode 100644
index c4f9528f1..000000000
--- a/addon-sdk/source/lib/sdk/places/bookmarks.js
+++ /dev/null
@@ -1,395 +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",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-/*
- * Requiring hosts so they can subscribe to client messages
- */
-require('./host/host-bookmarks');
-require('./host/host-tags');
-require('./host/host-query');
-
-const { Cc, Ci } = require('chrome');
-const { Class } = require('../core/heritage');
-const { send } = require('../addon/events');
-const { defer, reject, all, resolve, promised } = require('../core/promise');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const { identity, defer:async } = require('../lang/functional');
-const { extend, merge } = require('../util/object');
-const { fromIterator } = require('../util/array');
-const {
- constructTree, fetchItem, createQuery,
- isRootGroup, createQueryOptions
-} = require('./utils');
-const {
- bookmarkContract, groupContract, separatorContract
-} = require('./contract');
-const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
- getService(Ci.nsINavBookmarksService);
-
-/*
- * Mapping of uncreated bookmarks with their created
- * counterparts
- */
-const itemMap = new WeakMap();
-
-/*
- * Constant used by nsIHistoryQuery; 1 is a bookmark query
- * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
- */
-const BOOKMARK_QUERY = 1;
-
-/*
- * Bookmark Item classes
- */
-
-const Bookmark = Class({
- extends: [
- bookmarkContract.properties(identity)
- ],
- initialize: function initialize (options) {
- merge(this, bookmarkContract(extend(defaults, options)));
- },
- type: 'bookmark',
- toString: () => '[object Bookmark]'
-});
-exports.Bookmark = Bookmark;
-
-const Group = Class({
- extends: [
- groupContract.properties(identity)
- ],
- initialize: function initialize (options) {
- // Don't validate if root group
- if (isRootGroup(options))
- merge(this, options);
- else
- merge(this, groupContract(extend(defaults, options)));
- },
- type: 'group',
- toString: () => '[object Group]'
-});
-exports.Group = Group;
-
-const Separator = Class({
- extends: [
- separatorContract.properties(identity)
- ],
- initialize: function initialize (options) {
- merge(this, separatorContract(extend(defaults, options)));
- },
- type: 'separator',
- toString: () => '[object Separator]'
-});
-exports.Separator = Separator;
-
-/*
- * Functions
- */
-
-function save (items, options) {
- items = [].concat(items);
- options = options || {};
- let emitter = EventTarget();
- let results = [];
- let errors = [];
- let root = constructTree(items);
- let cache = new Map();
-
- let isExplicitSave = item => !!~items.indexOf(item);
- // `walk` returns an aggregate promise indicating the completion
- // of the `commitItem` on each node, not whether or not that
- // commit was successful
-
- // Force this to be async, as if a ducktype fails validation,
- // the promise implementation will fire an error event, which will
- // not trigger the handler as it's not yet bound
- //
- // Can remove after `Promise.jsm` is implemented in Bug 881047,
- // which will guarantee next tick execution
- async(() => root.walk(preCommitItem).then(commitComplete))();
-
- function preCommitItem ({value:item}) {
- // Do nothing if tree root, default group (unsavable),
- // or if it's a dependency and not explicitly saved (in the list
- // of items to be saved), and not needed to be saved
- if (item === null || // node is the tree root
- isRootGroup(item) ||
- (getId(item) && !isExplicitSave(item)))
- return;
-
- return promised(validate)(item)
- .then(() => commitItem(item, options))
- .then(data => construct(data, cache))
- .then(savedItem => {
- // If item was just created, make a map between
- // the creation object and created object,
- // so we can reference the item that doesn't have an id
- if (!getId(item))
- saveId(item, savedItem.id);
-
- // Emit both the processed item, and original item
- // so a mapping can be understood in handler
- emit(emitter, 'data', savedItem, item);
-
- // Push to results iff item was explicitly saved
- if (isExplicitSave(item))
- results[items.indexOf(item)] = savedItem;
- }, reason => {
- // Force reason to be a string for consistency
- reason = reason + '';
- // Emit both the reason, and original item
- // so a mapping can be understood in handler
- emit(emitter, 'error', reason + '', item);
- // Store unsaved item in results list
- results[items.indexOf(item)] = item;
- errors.push(reason);
- });
- }
-
- // Called when traversal of the node tree is completed and all
- // items have been committed
- function commitComplete () {
- emit(emitter, 'end', results);
- }
-
- return emitter;
-}
-exports.save = save;
-
-function search (queries, options) {
- queries = [].concat(queries);
- let emitter = EventTarget();
- let cache = new Map();
- let queryObjs = queries.map(createQuery.bind(null, BOOKMARK_QUERY));
- let optionsObj = createQueryOptions(BOOKMARK_QUERY, options);
-
- // Can remove after `Promise.jsm` is implemented in Bug 881047,
- // which will guarantee next tick execution
- async(() => {
- send('sdk-places-query', { queries: queryObjs, options: optionsObj })
- .then(handleQueryResponse);
- })();
-
- function handleQueryResponse (data) {
- let deferreds = data.map(item => {
- return construct(item, cache).then(bookmark => {
- emit(emitter, 'data', bookmark);
- return bookmark;
- }, reason => {
- emit(emitter, 'error', reason);
- errors.push(reason);
- });
- });
-
- all(deferreds).then(data => {
- emit(emitter, 'end', data);
- }, () => emit(emitter, 'end', []));
- }
-
- return emitter;
-}
-exports.search = search;
-
-function remove (items) {
- return [].concat(items).map(item => {
- item.remove = true;
- return item;
- });
-}
-
-exports.remove = remove;
-
-/*
- * Internal Utilities
- */
-
-function commitItem (item, options) {
- // Get the item's ID, or getId it's saved version if it exists
- let id = getId(item);
- let data = normalize(item);
- let promise;
-
- data.id = id;
-
- if (!id) {
- promise = send('sdk-places-bookmarks-create', data);
- } else if (item.remove) {
- promise = send('sdk-places-bookmarks-remove', { id: id });
- } else {
- promise = send('sdk-places-bookmarks-last-updated', {
- id: id
- }).then(function (updated) {
- // If attempting to save an item that is not the
- // latest snapshot of a bookmark item, execute
- // the resolution function
- if (updated !== item.updated && options.resolve)
- return fetchItem(id)
- .then(options.resolve.bind(null, data));
- else
- return data;
- }).then(send.bind(null, 'sdk-places-bookmarks-save'));
- }
-
- return promise;
-}
-
-/*
- * Turns a bookmark item into a plain object,
- * converts `tags` from Set to Array, group instance to an id
- */
-function normalize (item) {
- let data = merge({}, item);
- // Circumvent prototype property of `type`
- delete data.type;
- data.type = item.type;
- data.tags = [];
- if (item.tags) {
- data.tags = fromIterator(item.tags);
- }
- data.group = getId(data.group) || exports.UNSORTED.id;
-
- return data;
-}
-
-/*
- * Takes a data object and constructs a BookmarkItem instance
- * of it, recursively generating parent instances as well.
- *
- * Pass in a `cache` Map to reuse instances of
- * bookmark items to reduce overhead;
- * The cache object is a map of id to a deferred with a
- * promise that resolves to the bookmark item.
- */
-function construct (object, cache, forced) {
- let item = instantiate(object);
- let deferred = defer();
-
- // Item could not be instantiated
- if (!item)
- return resolve(null);
-
- // Return promise for item if found in the cache,
- // and not `forced`. `forced` indicates that this is the construct
- // call that should not read from cache, but should actually perform
- // the construction, as it was set before several async calls
- if (cache.has(item.id) && !forced)
- return cache.get(item.id).promise;
- else if (cache.has(item.id))
- deferred = cache.get(item.id);
- else
- cache.set(item.id, deferred);
-
- // When parent group is found in cache, use
- // the same deferred value
- if (item.group && cache.has(item.group)) {
- cache.get(item.group).promise.then(group => {
- item.group = group;
- deferred.resolve(item);
- });
-
- // If not in the cache, and a root group, return
- // the premade instance
- } else if (rootGroups.get(item.group)) {
- item.group = rootGroups.get(item.group);
- deferred.resolve(item);
-
- // If not in the cache or a root group, fetch the parent
- } else {
- cache.set(item.group, defer());
- fetchItem(item.group).then(group => {
- return construct(group, cache, true);
- }).then(group => {
- item.group = group;
- deferred.resolve(item);
- }, deferred.reject);
- }
-
- return deferred.promise;
-}
-
-function instantiate (object) {
- if (object.type === 'bookmark')
- return Bookmark(object);
- if (object.type === 'group')
- return Group(object);
- if (object.type === 'separator')
- return Separator(object);
- return null;
-}
-
-/**
- * Validates a bookmark item; will throw an error if ininvalid,
- * to be used with `promised`. As bookmark items check on their class,
- * this only checks ducktypes
- */
-function validate (object) {
- if (!isDuckType(object)) return true;
- let contract = object.type === 'bookmark' ? bookmarkContract :
- object.type === 'group' ? groupContract :
- object.type === 'separator' ? separatorContract :
- null;
- if (!contract) {
- throw Error('No type specified');
- }
-
- // If object has a property set, and undefined,
- // manually override with default as it'll fail otherwise
- let withDefaults = Object.keys(defaults).reduce((obj, prop) => {
- if (obj[prop] == null) obj[prop] = defaults[prop];
- return obj;
- }, extend(object));
-
- contract(withDefaults);
-}
-
-function isDuckType (item) {
- return !(item instanceof Bookmark) &&
- !(item instanceof Group) &&
- !(item instanceof Separator);
-}
-
-function saveId (unsaved, id) {
- itemMap.set(unsaved, id);
-}
-
-// Fetches an item's ID from itself, or from the mapped items
-function getId (item) {
- return typeof item === 'number' ? item :
- item ? item.id || itemMap.get(item) :
- null;
-}
-
-/*
- * Set up the default, root groups
- */
-
-var defaultGroupMap = {
- MENU: bmsrv.bookmarksMenuFolder,
- TOOLBAR: bmsrv.toolbarFolder,
- UNSORTED: bmsrv.unfiledBookmarksFolder
-};
-
-var rootGroups = new Map();
-
-for (let i in defaultGroupMap) {
- let group = Object.freeze(Group({ title: i, id: defaultGroupMap[i] }));
- rootGroups.set(defaultGroupMap[i], group);
- exports[i] = group;
-}
-
-var defaults = {
- group: exports.UNSORTED,
- index: -1
-};
diff --git a/addon-sdk/source/lib/sdk/places/contract.js b/addon-sdk/source/lib/sdk/places/contract.js
deleted file mode 100644
index a3541c34d..000000000
--- a/addon-sdk/source/lib/sdk/places/contract.js
+++ /dev/null
@@ -1,73 +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 { Cc, Ci } = require('chrome');
-const { isValidURI, URL } = require('../url');
-const { contract } = require('../util/contract');
-const { extend } = require('../util/object');
-
-// map of property validations
-const validItem = {
- id: {
- is: ['number', 'undefined', 'null'],
- },
- group: {
- is: ['object', 'number', 'undefined', 'null'],
- ok: function (value) {
- return value &&
- (value.toString && value.toString() === '[object Group]') ||
- typeof value === 'number' ||
- value.type === 'group';
- },
- msg: 'The `group` property must be a valid Group object'
- },
- index: {
- is: ['undefined', 'null', 'number'],
- map: value => value == null ? -1 : value,
- msg: 'The `index` property must be a number.'
- },
- updated: {
- is: ['number', 'undefined']
- }
-};
-
-const validTitle = {
- title: {
- is: ['string'],
- msg: 'The `title` property must be defined.'
- }
-};
-
-const validURL = {
- url: {
- is: ['string'],
- ok: isValidURI,
- msg: 'The `url` property must be a valid URL.'
- }
-};
-
-const validTags = {
- tags: {
- is: ['object'],
- ok: tags => tags instanceof Set,
- map: function (tags) {
- if (Array.isArray(tags))
- return new Set(tags);
- if (tags == null)
- return new Set();
- return tags;
- },
- msg: 'The `tags` property must be a Set, or an array'
- }
-};
-
-exports.bookmarkContract = contract(
- extend(validItem, validTitle, validURL, validTags));
-exports.separatorContract = contract(validItem);
-exports.groupContract = contract(extend(validItem, validTitle));
diff --git a/addon-sdk/source/lib/sdk/places/events.js b/addon-sdk/source/lib/sdk/places/events.js
deleted file mode 100644
index a3f95ee03..000000000
--- a/addon-sdk/source/lib/sdk/places/events.js
+++ /dev/null
@@ -1,128 +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',
- 'engines': {
- 'Firefox': '*',
- "SeaMonkey": '*'
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const { Unknown } = require('../platform/xpcom');
-const { Class } = require('../core/heritage');
-const { merge } = require('../util/object');
-const bookmarkService = Cc['@mozilla.org/browser/nav-bookmarks-service;1']
- .getService(Ci.nsINavBookmarksService);
-const historyService = Cc['@mozilla.org/browser/nav-history-service;1']
- .getService(Ci.nsINavHistoryService);
-const { mapBookmarkItemType } = require('./utils');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const { when } = require('../system/unload');
-
-const emitter = EventTarget();
-
-var HISTORY_ARGS = {
- onBeginUpdateBatch: [],
- onEndUpdateBatch: [],
- onClearHistory: [],
- onDeleteURI: ['url'],
- onDeleteVisits: ['url', 'visitTime'],
- onPageChanged: ['url', 'property', 'value'],
- onTitleChanged: ['url', 'title'],
- onVisit: [
- 'url', 'visitId', 'time', 'sessionId', 'referringId', 'transitionType'
- ]
-};
-
-var HISTORY_EVENTS = {
- onBeginUpdateBatch: 'history-start-batch',
- onEndUpdateBatch: 'history-end-batch',
- onClearHistory: 'history-start-clear',
- onDeleteURI: 'history-delete-url',
- onDeleteVisits: 'history-delete-visits',
- onPageChanged: 'history-page-changed',
- onTitleChanged: 'history-title-changed',
- onVisit: 'history-visit'
-};
-
-var BOOKMARK_ARGS = {
- onItemAdded: [
- 'id', 'parentId', 'index', 'type', 'url', 'title', 'dateAdded'
- ],
- onItemChanged: [
- 'id', 'property', null, 'value', 'lastModified', 'type', 'parentId'
- ],
- onItemMoved: [
- 'id', 'previousParentId', 'previousIndex', 'currentParentId',
- 'currentIndex', 'type'
- ],
- onItemRemoved: ['id', 'parentId', 'index', 'type', 'url'],
- onItemVisited: ['id', 'visitId', 'time', 'transitionType', 'url', 'parentId']
-};
-
-var BOOKMARK_EVENTS = {
- onItemAdded: 'bookmark-item-added',
- onItemChanged: 'bookmark-item-changed',
- onItemMoved: 'bookmark-item-moved',
- onItemRemoved: 'bookmark-item-removed',
- onItemVisited: 'bookmark-item-visited',
-};
-
-function createHandler (type, propNames) {
- propNames = propNames || [];
- return function (...args) {
- let data = propNames.reduce((acc, prop, i) => {
- if (prop)
- acc[prop] = formatValue(prop, args[i]);
- return acc;
- }, {});
-
- emit(emitter, 'data', {
- type: type,
- data: data
- });
- };
-}
-
-/*
- * Creates an observer, creating handlers based off of
- * the `events` names, and ordering arguments from `propNames` hash
- */
-function createObserverInstance (events, propNames) {
- let definition = Object.keys(events).reduce((prototype, eventName) => {
- prototype[eventName] = createHandler(events[eventName], propNames[eventName]);
- return prototype;
- }, {});
-
- return Class(merge(definition, { extends: Unknown }))();
-}
-
-/*
- * Formats `data` based off of the value of `type`
- */
-function formatValue (type, data) {
- if (type === 'type')
- return mapBookmarkItemType(data);
- if (type === 'url' && data)
- return data.spec;
- return data;
-}
-
-var historyObserver = createObserverInstance(HISTORY_EVENTS, HISTORY_ARGS);
-historyService.addObserver(historyObserver, false);
-
-var bookmarkObserver = createObserverInstance(BOOKMARK_EVENTS, BOOKMARK_ARGS);
-bookmarkService.addObserver(bookmarkObserver, false);
-
-when(() => {
- historyService.removeObserver(historyObserver);
- bookmarkService.removeObserver(bookmarkObserver);
-});
-
-exports.events = emitter;
diff --git a/addon-sdk/source/lib/sdk/places/favicon.js b/addon-sdk/source/lib/sdk/places/favicon.js
deleted file mode 100644
index 05b057db1..000000000
--- a/addon-sdk/source/lib/sdk/places/favicon.js
+++ /dev/null
@@ -1,49 +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",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci, Cu } = require("chrome");
-const { defer, reject } = require("../core/promise");
-const FaviconService = Cc["@mozilla.org/browser/favicon-service;1"].
- getService(Ci.nsIFaviconService);
-const AsyncFavicons = FaviconService.QueryInterface(Ci.mozIAsyncFavicons);
-const { isValidURI } = require("../url");
-const { newURI, getURL } = require("../url/utils");
-
-/**
- * Takes an object of several possible types and
- * returns a promise that resolves to the page's favicon URI.
- * @param {String|Tab} object
- * @param {Function} (callback)
- * @returns {Promise}
- */
-
-function getFavicon (object, callback) {
- let url = getURL(object);
- let deferred = defer();
-
- if (url && isValidURI(url)) {
- AsyncFavicons.getFaviconURLForPage(newURI(url), function (aURI) {
- if (aURI && aURI.spec)
- deferred.resolve(aURI.spec.toString());
- else
- deferred.reject(null);
- });
- } else {
- deferred.reject(null);
- }
-
- if (callback) deferred.promise.then(callback, callback);
- return deferred.promise;
-}
-exports.getFavicon = getFavicon;
diff --git a/addon-sdk/source/lib/sdk/places/history.js b/addon-sdk/source/lib/sdk/places/history.js
deleted file mode 100644
index b243b024c..000000000
--- a/addon-sdk/source/lib/sdk/places/history.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": "unstable",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-/*
- * Requiring hosts so they can subscribe to client messages
- */
-require('./host/host-bookmarks');
-require('./host/host-tags');
-require('./host/host-query');
-
-const { Cc, Ci } = require('chrome');
-const { Class } = require('../core/heritage');
-const { events, send } = require('../addon/events');
-const { defer, reject, all } = require('../core/promise');
-const { uuid } = require('../util/uuid');
-const { flatten } = require('../util/array');
-const { has, extend, merge, pick } = require('../util/object');
-const { emit } = require('../event/core');
-const { defer: async } = require('../lang/functional');
-const { EventTarget } = require('../event/target');
-const {
- urlQueryParser, createQuery, createQueryOptions
-} = require('./utils');
-
-/*
- * Constant used by nsIHistoryQuery; 0 is a history query
- * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
- */
-const HISTORY_QUERY = 0;
-
-var search = function query (queries, options) {
- queries = [].concat(queries);
- let emitter = EventTarget();
- let queryObjs = queries.map(createQuery.bind(null, HISTORY_QUERY));
- let optionsObj = createQueryOptions(HISTORY_QUERY, options);
-
- // Can remove after `Promise.jsm` is implemented in Bug 881047,
- // which will guarantee next tick execution
- async(() => {
- send('sdk-places-query', {
- query: queryObjs,
- options: optionsObj
- }).then(results => {
- results.map(item => emit(emitter, 'data', item));
- emit(emitter, 'end', results);
- }, reason => {
- emit(emitter, 'error', reason);
- emit(emitter, 'end', []);
- });
- })();
-
- return emitter;
-};
-exports.search = search;
diff --git a/addon-sdk/source/lib/sdk/places/host/host-bookmarks.js b/addon-sdk/source/lib/sdk/places/host/host-bookmarks.js
deleted file mode 100644
index 3245c4070..000000000
--- a/addon-sdk/source/lib/sdk/places/host/host-bookmarks.js
+++ /dev/null
@@ -1,238 +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",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const browserHistory = Cc["@mozilla.org/browser/nav-history-service;1"].
- getService(Ci.nsIBrowserHistory);
-const asyncHistory = Cc["@mozilla.org/browser/history;1"].
- getService(Ci.mozIAsyncHistory);
-const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
- getService(Ci.nsINavBookmarksService);
-const taggingService = Cc["@mozilla.org/browser/tagging-service;1"].
- getService(Ci.nsITaggingService);
-const ios = Cc['@mozilla.org/network/io-service;1'].
- getService(Ci.nsIIOService);
-const { query } = require('./host-query');
-const {
- defer, all, resolve, promised, reject
-} = require('../../core/promise');
-const { request, response } = require('../../addon/host');
-const { send } = require('../../addon/events');
-const { on, emit } = require('../../event/core');
-const { filter } = require('../../event/utils');
-const { URL, isValidURI } = require('../../url');
-const { newURI } = require('../../url/utils');
-
-const DEFAULT_INDEX = bmsrv.DEFAULT_INDEX;
-const UNSORTED_ID = bmsrv.unfiledBookmarksFolder;
-const ROOT_FOLDERS = [
- bmsrv.unfiledBookmarksFolder, bmsrv.toolbarFolder,
- bmsrv.tagsFolder, bmsrv.bookmarksMenuFolder
-];
-
-const EVENT_MAP = {
- 'sdk-places-bookmarks-create': createBookmarkItem,
- 'sdk-places-bookmarks-save': saveBookmarkItem,
- 'sdk-places-bookmarks-last-updated': getBookmarkLastUpdated,
- 'sdk-places-bookmarks-get': getBookmarkItem,
- 'sdk-places-bookmarks-remove': removeBookmarkItem,
- 'sdk-places-bookmarks-get-all': getAllBookmarks,
- 'sdk-places-bookmarks-get-children': getChildren
-};
-
-function typeMap (type) {
- if (typeof type === 'number') {
- if (bmsrv.TYPE_BOOKMARK === type) return 'bookmark';
- if (bmsrv.TYPE_FOLDER === type) return 'group';
- if (bmsrv.TYPE_SEPARATOR === type) return 'separator';
- } else {
- if ('bookmark' === type) return bmsrv.TYPE_BOOKMARK;
- if ('group' === type) return bmsrv.TYPE_FOLDER;
- if ('separator' === type) return bmsrv.TYPE_SEPARATOR;
- }
-}
-
-function getBookmarkLastUpdated ({id}) {
- return resolve(bmsrv.getItemLastModified(id));
-}
-exports.getBookmarkLastUpdated;
-
-function createBookmarkItem (data) {
- let error;
-
- if (data.group == null) data.group = UNSORTED_ID;
- if (data.index == null) data.index = DEFAULT_INDEX;
-
- if (data.type === 'group')
- data.id = bmsrv.createFolder(
- data.group, data.title, data.index
- );
- else if (data.type === 'separator')
- data.id = bmsrv.insertSeparator(
- data.group, data.index
- );
- else
- data.id = bmsrv.insertBookmark(
- data.group, newURI(data.url), data.index, data.title
- );
-
- // In the event where default or no index is provided (-1),
- // query the actual index for the response
- if (data.index === -1)
- data.index = bmsrv.getItemIndex(data.id);
-
- try {
- data.updated = bmsrv.getItemLastModified(data.id);
- }
- catch (e) {
- console.exception(e);
- }
-
- return tag(data, true).then(() => data);
-}
-exports.createBookmarkItem = createBookmarkItem;
-
-function saveBookmarkItem (data) {
- let id = data.id;
- if (!id)
- reject('Item is missing id');
-
- let group = bmsrv.getFolderIdForItem(id);
- let index = bmsrv.getItemIndex(id);
- let type = bmsrv.getItemType(id);
- let title = typeMap(type) !== 'separator' ?
- bmsrv.getItemTitle(id) :
- undefined;
- let url = typeMap(type) === 'bookmark' ?
- bmsrv.getBookmarkURI(id).spec :
- undefined;
-
- if (url != data.url)
- bmsrv.changeBookmarkURI(id, newURI(data.url));
- else if (typeMap(type) === 'bookmark')
- data.url = url;
-
- if (title != data.title)
- bmsrv.setItemTitle(id, data.title);
- else if (typeMap(type) !== 'separator')
- data.title = title;
-
- if (data.group && data.group !== group)
- bmsrv.moveItem(id, data.group, data.index || -1);
- else if (data.index != null && data.index !== index) {
- // We use moveItem here instead of setItemIndex
- // so we don't have to manage the indicies of the siblings
- bmsrv.moveItem(id, group, data.index);
- } else if (data.index == null)
- data.index = index;
-
- data.updated = bmsrv.getItemLastModified(data.id);
-
- return tag(data).then(() => data);
-}
-exports.saveBookmarkItem = saveBookmarkItem;
-
-function removeBookmarkItem (data) {
- let id = data.id;
-
- if (!id)
- reject('Item is missing id');
-
- bmsrv.removeItem(id);
- return resolve(null);
-}
-exports.removeBookmarkItem = removeBookmarkItem;
-
-function getBookmarkItem (data) {
- let id = data.id;
-
- if (!id)
- reject('Item is missing id');
-
- let type = bmsrv.getItemType(id);
-
- data.type = typeMap(type);
-
- if (type === bmsrv.TYPE_BOOKMARK || type === bmsrv.TYPE_FOLDER)
- data.title = bmsrv.getItemTitle(id);
-
- if (type === bmsrv.TYPE_BOOKMARK) {
- data.url = bmsrv.getBookmarkURI(id).spec;
- // Should be moved into host-tags as a method
- data.tags = taggingService.getTagsForURI(newURI(data.url), {});
- }
-
- data.group = bmsrv.getFolderIdForItem(id);
- data.index = bmsrv.getItemIndex(id);
- data.updated = bmsrv.getItemLastModified(data.id);
-
- return resolve(data);
-}
-exports.getBookmarkItem = getBookmarkItem;
-
-function getAllBookmarks () {
- return query({}, { queryType: 1 }).then(bookmarks =>
- all(bookmarks.map(getBookmarkItem)));
-}
-exports.getAllBookmarks = getAllBookmarks;
-
-function getChildren ({ id }) {
- if (typeMap(bmsrv.getItemType(id)) !== 'group') return [];
- let ids = [];
- for (let i = 0; ids[ids.length - 1] !== -1; i++)
- ids.push(bmsrv.getIdForItemAt(id, i));
- ids.pop();
- return all(ids.map(id => getBookmarkItem({ id: id })));
-}
-exports.getChildren = getChildren;
-
-/*
- * Hook into host
- */
-
-var reqStream = filter(request, (data) => /sdk-places-bookmarks/.test(data.event));
-on(reqStream, 'data', ({ event, id, data }) => {
- if (!EVENT_MAP[event]) return;
-
- let resData = { id: id, event: event };
-
- promised(EVENT_MAP[event])(data).
- then(res => resData.data = res, e => resData.error = e).
- then(() => emit(response, 'data', resData));
-});
-
-function tag (data, isNew) {
- // If a new item, we can skip checking what other tags
- // are on the item
- if (data.type !== 'bookmark') {
- return resolve();
- }
- else if (!isNew) {
- return send('sdk-places-tags-get-tags-by-url', { url: data.url })
- .then(tags => {
- return send('sdk-places-tags-untag', {
- tags: tags.filter(tag => !~data.tags.indexOf(tag)),
- url: data.url
- });
- }).then(() => send('sdk-places-tags-tag', {
- url: data.url, tags: data.tags
- }));
- }
- else if (data.tags && data.tags.length) {
- return send('sdk-places-tags-tag', { url: data.url, tags: data.tags });
- }
- else
- return resolve();
-}
-
diff --git a/addon-sdk/source/lib/sdk/places/host/host-query.js b/addon-sdk/source/lib/sdk/places/host/host-query.js
deleted file mode 100644
index f2dbd6550..000000000
--- a/addon-sdk/source/lib/sdk/places/host/host-query.js
+++ /dev/null
@@ -1,179 +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",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const { all } = require('../../core/promise');
-const { safeMerge, omit } = require('../../util/object');
-const historyService = Cc['@mozilla.org/browser/nav-history-service;1']
- .getService(Ci.nsINavHistoryService);
-const bookmarksService = Cc['@mozilla.org/browser/nav-bookmarks-service;1']
- .getService(Ci.nsINavBookmarksService);
-const { request, response } = require('../../addon/host');
-const { newURI } = require('../../url/utils');
-const { send } = require('../../addon/events');
-const { on, emit } = require('../../event/core');
-const { filter } = require('../../event/utils');
-
-const ROOT_FOLDERS = [
- bookmarksService.unfiledBookmarksFolder, bookmarksService.toolbarFolder,
- bookmarksService.bookmarksMenuFolder
-];
-
-const EVENT_MAP = {
- 'sdk-places-query': queryReceiver
-};
-
-// Properties that need to be manually
-// copied into a nsINavHistoryQuery object
-const MANUAL_QUERY_PROPERTIES = [
- 'uri', 'folder', 'tags', 'url', 'folder'
-];
-
-const PLACES_PROPERTIES = [
- 'uri', 'title', 'accessCount', 'time'
-];
-
-function execute (queries, options) {
- return new Promise(resolve => {
- let root = historyService
- .executeQueries(queries, queries.length, options).root;
- // Let's extract an eventual uri wildcard, if both domain and uri are set.
- // See utils.js::urlQueryParser() for more details.
- // In case of multiple queries, we only retain the first found wildcard.
- let uriWildcard = queries.reduce((prev, query) => {
- if (query.uri && query.domain) {
- if (!prev)
- prev = query.uri.spec;
- query.uri = null;
- }
- return prev;
- }, "");
- resolve(collect([], root, uriWildcard));
- });
-}
-
-function collect (acc, node, uriWildcard) {
- node.containerOpen = true;
- for (let i = 0; i < node.childCount; i++) {
- let child = node.getChild(i);
-
- if (!uriWildcard || child.uri.startsWith(uriWildcard)) {
- acc.push(child);
- }
- if (child.type === child.RESULT_TYPE_FOLDER) {
- let container = child.QueryInterface(Ci.nsINavHistoryContainerResultNode);
- collect(acc, container, uriWildcard);
- }
- }
- node.containerOpen = false;
- return acc;
-}
-
-function query (queries, options) {
- return new Promise((resolve, reject) => {
- queries = queries || [];
- options = options || {};
- let optionsObj, queryObjs;
-
- optionsObj = historyService.getNewQueryOptions();
- queryObjs = [].concat(queries).map(createQuery);
- if (!queryObjs.length) {
- queryObjs = [historyService.getNewQuery()];
- }
- safeMerge(optionsObj, options);
-
- /*
- * Currently `places:` queries are not supported
- */
- optionsObj.excludeQueries = true;
-
- execute(queryObjs, optionsObj).then((results) => {
- if (optionsObj.queryType === 0) {
- return results.map(normalize);
- }
- else if (optionsObj.queryType === 1) {
- // Formats query results into more standard
- // data structures for returning
- return all(results.map(({itemId}) =>
- send('sdk-places-bookmarks-get', { id: itemId })));
- }
- }).then(resolve, reject);
- });
-}
-exports.query = query;
-
-function createQuery (query) {
- query = query || {};
- let queryObj = historyService.getNewQuery();
-
- safeMerge(queryObj, omit(query, MANUAL_QUERY_PROPERTIES));
-
- if (query.tags && Array.isArray(query.tags))
- queryObj.tags = query.tags;
- if (query.uri || query.url)
- queryObj.uri = newURI(query.uri || query.url);
- if (query.folder)
- queryObj.setFolders([query.folder], 1);
- return queryObj;
-}
-
-function queryReceiver (message) {
- let queries = message.data.queries || message.data.query;
- let options = message.data.options;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- query(queries, options).then(results => {
- resData.data = results;
- respond(resData);
- }, reason => {
- resData.error = reason;
- respond(resData);
- });
-}
-
-/*
- * Converts a nsINavHistoryResultNode into a plain object
- *
- * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryResultNode
- */
-function normalize (historyObj) {
- return PLACES_PROPERTIES.reduce((obj, prop) => {
- if (prop === 'uri')
- obj.url = historyObj.uri;
- else if (prop === 'time') {
- // Cast from microseconds to milliseconds
- obj.time = Math.floor(historyObj.time / 1000)
- }
- else if (prop === 'accessCount')
- obj.visitCount = historyObj[prop];
- else
- obj[prop] = historyObj[prop];
- return obj;
- }, {});
-}
-
-/*
- * Hook into host
- */
-
-var reqStream = filter(request, data => /sdk-places-query/.test(data.event));
-on(reqStream, 'data', function (e) {
- if (EVENT_MAP[e.event]) EVENT_MAP[e.event](e);
-});
-
-function respond (data) {
- emit(response, 'data', data);
-}
diff --git a/addon-sdk/source/lib/sdk/places/host/host-tags.js b/addon-sdk/source/lib/sdk/places/host/host-tags.js
deleted file mode 100644
index 929a5d5af..000000000
--- a/addon-sdk/source/lib/sdk/places/host/host-tags.js
+++ /dev/null
@@ -1,92 +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",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const taggingService = Cc["@mozilla.org/browser/tagging-service;1"].
- getService(Ci.nsITaggingService);
-const ios = Cc['@mozilla.org/network/io-service;1'].
- getService(Ci.nsIIOService);
-const { URL } = require('../../url');
-const { newURI } = require('../../url/utils');
-const { request, response } = require('../../addon/host');
-const { on, emit } = require('../../event/core');
-const { filter } = require('../../event/utils');
-
-const EVENT_MAP = {
- 'sdk-places-tags-tag': tag,
- 'sdk-places-tags-untag': untag,
- 'sdk-places-tags-get-tags-by-url': getTagsByURL,
- 'sdk-places-tags-get-urls-by-tag': getURLsByTag
-};
-
-function tag (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService.tagURI(newURI(data.url), data.tags);
- respond(resData);
-}
-
-function untag (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService.untagURI(newURI(data.url), data.tags);
- respond(resData);
-}
-
-function getURLsByTag (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService
- .getURIsForTag(data.tag).map(uri => uri.spec);
- respond(resData);
-}
-
-function getTagsByURL (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService.getTagsForURI(newURI(data.url), {});
- respond(resData);
-}
-
-/*
- * Hook into host
- */
-
-var reqStream = filter(request, function (data) {
- return /sdk-places-tags/.test(data.event);
-});
-
-on(reqStream, 'data', function (e) {
- if (EVENT_MAP[e.event]) EVENT_MAP[e.event](e);
-});
-
-function respond (data) {
- emit(response, 'data', data);
-}
diff --git a/addon-sdk/source/lib/sdk/places/utils.js b/addon-sdk/source/lib/sdk/places/utils.js
deleted file mode 100644
index 44366d2aa..000000000
--- a/addon-sdk/source/lib/sdk/places/utils.js
+++ /dev/null
@@ -1,268 +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",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci, Cu } = require('chrome');
-const { Class } = require('../core/heritage');
-const { method } = require('../lang/functional');
-const { defer, promised, all } = require('../core/promise');
-const { send } = require('../addon/events');
-const { EventTarget } = require('../event/target');
-const { merge } = require('../util/object');
-const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
- getService(Ci.nsINavBookmarksService);
-
-Cu.importGlobalProperties(["URL"]);
-
-/*
- * TreeNodes are used to construct dependency trees
- * for BookmarkItems
- */
-var TreeNode = Class({
- initialize: function (value) {
- this.value = value;
- this.children = [];
- },
- add: function (values) {
- [].concat(values).forEach(value => {
- this.children.push(value instanceof TreeNode ? value : TreeNode(value));
- });
- },
- get length () {
- let count = 0;
- this.walk(() => count++);
- // Do not count the current node
- return --count;
- },
- get: method(get),
- walk: method(walk),
- toString: () => '[object TreeNode]'
-});
-exports.TreeNode = TreeNode;
-
-/*
- * Descends down from `node` applying `fn` to each in order.
- * `fn` can return values or promises -- if promise returned,
- * children are not processed until resolved. `fn` is passed
- * one argument, the current node, `curr`.
- */
-function walk (curr, fn) {
- return promised(fn)(curr).then(val => {
- return all(curr.children.map(child => walk(child, fn)));
- });
-}
-
-/*
- * Descends from the TreeNode `node`, returning
- * the node with value `value` if found or `null`
- * otherwise
- */
-function get (node, value) {
- if (node.value === value) return node;
- for (let child of node.children) {
- let found = get(child, value);
- if (found) return found;
- }
- return null;
-}
-
-/*
- * Constructs a tree of bookmark nodes
- * returning the root (value: null);
- */
-
-function constructTree (items) {
- let root = TreeNode(null);
- items.forEach(treeify.bind(null, root));
-
- function treeify (root, item) {
- // If node already exists, skip
- let node = root.get(item);
- if (node) return node;
- node = TreeNode(item);
-
- let parentNode = item.group ? treeify(root, item.group) : root;
- parentNode.add(node);
-
- return node;
- }
-
- return root;
-}
-exports.constructTree = constructTree;
-
-/*
- * Shortcut for converting an id, or an object with an id, into
- * an object with corresponding bookmark data
- */
-function fetchItem (item) {
- return send('sdk-places-bookmarks-get', { id: item.id || item });
-}
-exports.fetchItem = fetchItem;
-
-/*
- * Takes an ID or an object with ID and checks it against
- * the root bookmark folders
- */
-function isRootGroup (id) {
- id = id && id.id;
- return ~[bmsrv.bookmarksMenuFolder, bmsrv.toolbarFolder,
- bmsrv.unfiledBookmarksFolder
- ].indexOf(id);
-}
-exports.isRootGroup = isRootGroup;
-
-/*
- * Merges appropriate options into query based off of url
- * 4 scenarios:
- *
- * 'moz.com' // domain: moz.com, domainIsHost: true
- * --> 'http://moz.com', 'http://moz.com/thunderbird'
- * '*.moz.com' // domain: moz.com, domainIsHost: false
- * --> 'http://moz.com', 'http://moz.com/index', 'http://ff.moz.com/test'
- * 'http://moz.com' // uri: http://moz.com/
- * --> 'http://moz.com/'
- * 'http://moz.com/*' // uri: http://moz.com/, domain: moz.com, domainIsHost: true
- * --> 'http://moz.com/', 'http://moz.com/thunderbird'
- */
-
-function urlQueryParser (query, url) {
- if (!url) return;
- if (/^https?:\/\//.test(url)) {
- query.uri = url.charAt(url.length - 1) === '/' ? url : url + '/';
- if (/\*$/.test(url)) {
- // Wildcard searches on URIs are not supported, so try to extract a
- // domain and filter the data later.
- url = url.replace(/\*$/, '');
- try {
- query.domain = new URL(url).hostname;
- query.domainIsHost = true;
- // Unfortunately here we cannot use an expando to store the wildcard,
- // cause the query is a wrapped native XPCOM object, so we reuse uri.
- // We clearly don't want to query for both uri and domain, thus we'll
- // have to handle this in host-query.js::execute()
- query.uri = url;
- } catch (ex) {
- // Cannot extract an host cause it's not a valid uri, the query will
- // just return nothing.
- }
- }
- } else {
- if (/^\*/.test(url)) {
- query.domain = url.replace(/^\*\./, '');
- query.domainIsHost = false;
- } else {
- query.domain = url;
- query.domainIsHost = true;
- }
- }
-}
-exports.urlQueryParser = urlQueryParser;
-
-/*
- * Takes an EventEmitter and returns a promise that
- * aggregates results and handles a bulk resolve and reject
- */
-
-function promisedEmitter (emitter) {
- let { promise, resolve, reject } = defer();
- let errors = [];
- emitter.on('error', error => errors.push(error));
- emitter.on('end', (items) => {
- if (errors.length) reject(errors[0]);
- else resolve(items);
- });
- return promise;
-}
-exports.promisedEmitter = promisedEmitter;
-
-
-// https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
-function createQuery (type, query) {
- query = query || {};
- let qObj = {
- searchTerms: query.query
- };
-
- urlQueryParser(qObj, query.url);
-
- // 0 === history
- if (type === 0) {
- // PRTime used by query is in microseconds, not milliseconds
- qObj.beginTime = (query.from || 0) * 1000;
- qObj.endTime = (query.to || new Date()) * 1000;
-
- // Set reference time to Epoch
- qObj.beginTimeReference = 0;
- qObj.endTimeReference = 0;
- }
- // 1 === bookmarks
- else if (type === 1) {
- qObj.tags = query.tags;
- qObj.folder = query.group && query.group.id;
- }
- // 2 === unified (not implemented on platform)
- else if (type === 2) {
-
- }
-
- return qObj;
-}
-exports.createQuery = createQuery;
-
-// https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
-
-const SORT_MAP = {
- title: 1,
- date: 3, // sort by visit date
- url: 5,
- visitCount: 7,
- // keywords currently unsupported
- // keyword: 9,
- dateAdded: 11, // bookmarks only
- lastModified: 13 // bookmarks only
-};
-
-function createQueryOptions (type, options) {
- options = options || {};
- let oObj = {};
- oObj.sortingMode = SORT_MAP[options.sort] || 0;
- if (options.descending && options.sort)
- oObj.sortingMode++;
-
- // Resolve to default sort if ineligible based on query type
- if (type === 0 && // history
- (options.sort === 'dateAdded' || options.sort === 'lastModified'))
- oObj.sortingMode = 0;
-
- oObj.maxResults = typeof options.count === 'number' ? options.count : 0;
-
- oObj.queryType = type;
-
- return oObj;
-}
-exports.createQueryOptions = createQueryOptions;
-
-
-function mapBookmarkItemType (type) {
- if (typeof type === 'number') {
- if (bmsrv.TYPE_BOOKMARK === type) return 'bookmark';
- if (bmsrv.TYPE_FOLDER === type) return 'group';
- if (bmsrv.TYPE_SEPARATOR === type) return 'separator';
- } else {
- if ('bookmark' === type) return bmsrv.TYPE_BOOKMARK;
- if ('group' === type) return bmsrv.TYPE_FOLDER;
- if ('separator' === type) return bmsrv.TYPE_SEPARATOR;
- }
-}
-exports.mapBookmarkItemType = mapBookmarkItemType;
diff --git a/addon-sdk/source/lib/sdk/platform/xpcom.js b/addon-sdk/source/lib/sdk/platform/xpcom.js
deleted file mode 100644
index 383baf67a..000000000
--- a/addon-sdk/source/lib/sdk/platform/xpcom.js
+++ /dev/null
@@ -1,241 +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 { Cc, Ci, Cr, Cm, components: { classesByID } } = require('chrome');
-const { registerFactory, unregisterFactory, isCIDRegistered } =
- Cm.QueryInterface(Ci.nsIComponentRegistrar);
-
-const { merge } = require('../util/object');
-const { Class, extend, mix } = require('../core/heritage');
-const { uuid } = require('../util/uuid');
-
-// This is a base prototype, that provides bare bones of XPCOM. JS based
-// components can be easily implement by extending it.
-const Unknown = new function() {
- function hasInterface(component, iid) {
- return component && component.interfaces &&
- ( component.interfaces.some(id => iid.equals(Ci[id])) ||
- component.implements.some($ => hasInterface($, iid)) ||
- hasInterface(Object.getPrototypeOf(component), iid));
- }
-
- return Class({
- /**
- * The `QueryInterface` method provides runtime type discovery used by XPCOM.
- * This method return queried instance of `this` if given `iid` is listed in
- * the `interfaces` property or in equivalent properties of objects in it's
- * prototype chain. In addition it will look up in the prototypes under
- * `implements` array property, this ways compositions made via `Class`
- * utility will carry interfaces implemented by composition components.
- */
- QueryInterface: function QueryInterface(iid) {
- // For some reason there are cases when `iid` is `null`. In such cases we
- // just return `this`. Otherwise we verify that component implements given
- // `iid` interface. This will be no longer necessary once Bug 748003 is
- // fixed.
- if (iid && !hasInterface(this, iid))
- throw Cr.NS_ERROR_NO_INTERFACE;
-
- return this;
- },
- /**
- * Array of `XPCOM` interfaces (as strings) implemented by this component.
- * All components implement `nsISupports` by default which is default value
- * here. Provide array of interfaces implemented by an object when
- * extending, to append them to this list (Please note that there is no
- * need to repeat interfaces implemented by super as they will be added
- * automatically).
- */
- interfaces: Object.freeze([ 'nsISupports' ])
- });
-}
-exports.Unknown = Unknown;
-
-// Base exemplar for creating instances implementing `nsIFactory` interface,
-// that maybe registered into runtime via `register` function. Instances of
-// this factory create instances of enclosed component on `createInstance`.
-const Factory = Class({
- extends: Unknown,
- interfaces: [ 'nsIFactory' ],
- /**
- * All the descendants will get auto generated `id` (also known as `classID`
- * in XPCOM world) unless one is manually provided.
- */
- get id() { throw Error('Factory must implement `id` property') },
- /**
- * XPCOM `contractID` may optionally be provided to associate this factory
- * with it. `contract` is a unique string that has a following format:
- * '@vendor.com/unique/id;1'.
- */
- contract: null,
- /**
- * Class description that is being registered. This value is intended as a
- * human-readable description for the given class and does not needs to be
- * globally unique.
- */
- description: 'Jetpack generated factory',
- /**
- * This method is required by `nsIFactory` interfaces, but as in most
- * implementations it does nothing interesting.
- */
- lockFactory: function lockFactory(lock) {
- return undefined;
- },
- /**
- * If property is `true` XPCOM service / factory will be registered
- * automatically on creation.
- */
- register: true,
- /**
- * If property is `true` XPCOM factory will be unregistered prior to add-on
- * unload.
- */
- unregister: true,
- /**
- * Method is called on `Service.new(options)` passing given `options` to
- * it. Options is expected to have `component` property holding XPCOM
- * component implementation typically decedent of `Unknown` or any custom
- * implementation with a `new` method and optional `register`, `unregister`
- * flags. Unless `register` is `false` Service / Factory will be
- * automatically registered. Unless `unregister` is `false` component will
- * be automatically unregistered on add-on unload.
- */
- initialize: function initialize(options) {
- merge(this, {
- id: 'id' in options ? options.id : uuid(),
- register: 'register' in options ? options.register : this.register,
- unregister: 'unregister' in options ? options.unregister : this.unregister,
- contract: 'contract' in options ? options.contract : null,
- Component: options.Component
- });
-
- // If service / factory has auto registration enabled then register.
- if (this.register)
- register(this);
- },
- /**
- * Creates an instance of the class associated with this factory.
- */
- createInstance: function createInstance(outer, iid) {
- try {
- if (outer)
- throw Cr.NS_ERROR_NO_AGGREGATION;
- return this.create().QueryInterface(iid);
- }
- catch (error) {
- throw error instanceof Ci.nsIException ? error : Cr.NS_ERROR_FAILURE;
- }
- },
- create: function create() {
- return this.Component();
- }
-});
-exports.Factory = Factory;
-
-// Exemplar for creating services that implement `nsIFactory` interface, that
-// can be registered into runtime via call to `register`. This services return
-// enclosed `component` on `getService`.
-const Service = Class({
- extends: Factory,
- initialize: function initialize(options) {
- this.component = options.Component();
- Factory.prototype.initialize.call(this, options);
- },
- description: 'Jetpack generated service',
- /**
- * Creates an instance of the class associated with this factory.
- */
- create: function create() {
- return this.component;
- }
-});
-exports.Service = Service;
-
-function isRegistered({ id }) {
- return isCIDRegistered(id);
-}
-exports.isRegistered = isRegistered;
-
-/**
- * Registers given `component` object to be used to instantiate a particular
- * class identified by `component.id`, and creates an association of class
- * name and `component.contract` with the class.
- */
-function register(factory) {
- if (!(factory instanceof Factory)) {
- throw new Error("xpcom.register() expect a Factory instance.\n" +
- "Please refactor your code to new xpcom module if you" +
- " are repacking an addon from SDK <= 1.5:\n" +
- "https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/platform_xpcom");
- }
-
- registerFactory(factory.id, factory.description, factory.contract, factory);
-
- if (factory.unregister)
- require('../system/unload').when(unregister.bind(null, factory));
-}
-exports.register = register;
-
-/**
- * Unregister a factory associated with a particular class identified by
- * `factory.classID`.
- */
-function unregister(factory) {
- if (isRegistered(factory))
- unregisterFactory(factory.id, factory);
-}
-exports.unregister = unregister;
-
-function autoRegister(path) {
- // TODO: This assumes that the url points to a directory
- // that contains subdirectories corresponding to OS/ABI and then
- // further subdirectories corresponding to Gecko platform version.
- // we should probably either behave intelligently here or allow
- // the caller to pass-in more options if e.g. there aren't
- // Gecko-specific binaries for a component (which will be the case
- // if only frozen interfaces are used).
-
- var runtime = require("../system/runtime");
- var osDirName = runtime.OS + "_" + runtime.XPCOMABI;
- var platformVersion = require("../system/xul-app").platformVersion.substring(0, 5);
-
- var file = Cc['@mozilla.org/file/local;1']
- .createInstance(Ci.nsILocalFile);
- file.initWithPath(path);
- file.append(osDirName);
- file.append(platformVersion);
-
- if (!(file.exists() && file.isDirectory()))
- throw new Error("component not available for OS/ABI " +
- osDirName + " and platform " + platformVersion);
-
- Cm.QueryInterface(Ci.nsIComponentRegistrar);
- Cm.autoRegister(file);
-}
-exports.autoRegister = autoRegister;
-
-/**
- * Returns registered factory that has a given `id` or `null` if not found.
- */
-function factoryByID(id) {
- return classesByID[id] || null;
-}
-exports.factoryByID = factoryByID;
-
-/**
- * Returns factory registered with a given `contract` or `null` if not found.
- * In contrast to `Cc[contract]` that does ignores new factory registration
- * with a given `contract` this will return a factory currently associated
- * with a `contract`.
- */
-function factoryByContract(contract) {
- return factoryByID(Cm.contractIDToCID(contract));
-}
-exports.factoryByContract = factoryByContract;
diff --git a/addon-sdk/source/lib/sdk/preferences/event-target.js b/addon-sdk/source/lib/sdk/preferences/event-target.js
deleted file mode 100644
index b64ba303c..000000000
--- a/addon-sdk/source/lib/sdk/preferences/event-target.js
+++ /dev/null
@@ -1,61 +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 { Cc, Ci } = require('chrome');
-const { Class } = require('../core/heritage');
-const { EventTarget } = require('../event/target');
-const { Branch } = require('./service');
-const { emit, off } = require('../event/core');
-const { when: unload } = require('../system/unload');
-
-const prefTargetNS = require('../core/namespace').ns();
-
-const PrefsTarget = Class({
- extends: EventTarget,
- initialize: function(options) {
- options = options || {};
- EventTarget.prototype.initialize.call(this, options);
-
- let branchName = options.branchName || '';
- let branch = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefService).
- getBranch(branchName).
- QueryInterface(Ci.nsIPrefBranch2);
- prefTargetNS(this).branch = branch;
-
- // provides easy access to preference values
- this.prefs = Branch(branchName);
-
- // start listening to preference changes
- let observer = prefTargetNS(this).observer = onChange.bind(this);
- branch.addObserver('', observer, false);
-
- // Make sure to destroy this on unload
- unload(destroy.bind(this));
- }
-});
-exports.PrefsTarget = PrefsTarget;
-
-/* HELPERS */
-
-function onChange(subject, topic, name) {
- if (topic === 'nsPref:changed') {
- emit(this, name, name);
- emit(this, '', name);
- }
-}
-
-function destroy() {
- off(this);
-
- // stop listening to preference changes
- let branch = prefTargetNS(this).branch;
- branch.removeObserver('', prefTargetNS(this).observer, false);
- prefTargetNS(this).observer = null;
-}
diff --git a/addon-sdk/source/lib/sdk/preferences/native-options.js b/addon-sdk/source/lib/sdk/preferences/native-options.js
deleted file mode 100644
index 840997df9..000000000
--- a/addon-sdk/source/lib/sdk/preferences/native-options.js
+++ /dev/null
@@ -1,193 +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 { Cc, Ci, Cu } = require('chrome');
-const { on } = require('../system/events');
-const { id, preferencesBranch } = require('../self');
-const { localizeInlineOptions } = require('../l10n/prefs');
-const { Services } = require("resource://gre/modules/Services.jsm");
-const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
-const { defer } = require("sdk/core/promise");
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";;
-const DEFAULT_OPTIONS_URL = 'data:text/xml,<placeholder/>';
-
-const VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color',
- 'file', 'directory', 'control', 'menulist', 'radio'];
-
-const isFennec = require("sdk/system/xul-app").is("Fennec");
-
-function enable({ preferences, id }) {
- let enabled = defer();
-
- validate(preferences);
-
- setDefaults(preferences, preferencesBranch);
-
- // allow the use of custom options.xul
- AddonManager.getAddonByID(id, (addon) => {
- on('addon-options-displayed', onAddonOptionsDisplayed, true);
- enabled.resolve({ id: id });
- });
-
- function onAddonOptionsDisplayed({ subject: doc, data }) {
- if (data === id) {
- let parent;
-
- if (isFennec) {
- parent = doc.querySelector('.options-box');
-
- // NOTE: This disable the CSS rule that makes the options invisible
- let item = doc.querySelector('#addons-details .addon-item');
- item.removeAttribute("optionsURL");
- } else {
- parent = doc.getElementById('detail-downloads').parentNode;
- }
-
- if (parent) {
- injectOptions({
- preferences: preferences,
- preferencesBranch: preferencesBranch,
- document: doc,
- parent: parent,
- id: id
- });
- localizeInlineOptions(doc);
- } else {
- throw Error("Preferences parent node not found in Addon Details. The configured custom preferences will not be visible.");
- }
- }
- }
-
- return enabled.promise;
-}
-exports.enable = enable;
-
-// centralized sanity checks
-function validate(preferences) {
- for (let { name, title, type, label, options } of preferences) {
- // make sure the title is set and non-empty
- if (!title)
- throw Error("The '" + name + "' pref requires a title");
-
- // make sure that pref type is a valid inline option type
- if (!~VALID_PREF_TYPES.indexOf(type))
- throw Error("The '" + name + "' pref must be of valid type");
-
- // if it's a control, make sure it has a label
- if (type === 'control' && !label)
- throw Error("The '" + name + "' control requires a label");
-
- // if it's a menulist or radio, make sure it has options
- if (type === 'menulist' || type === 'radio') {
- if (!options)
- throw Error("The '" + name + "' pref requires options");
-
- // make sure each option has a value and a label
- for (let item of options) {
- if (!('value' in item) || !('label' in item))
- throw Error("Each option requires both a value and a label");
- }
- }
-
- // TODO: check that pref type matches default value type
- }
-}
-exports.validate = validate;
-
-// initializes default preferences, emulates defaults/prefs.js
-function setDefaults(preferences, preferencesBranch) {
- const branch = Cc['@mozilla.org/preferences-service;1'].
- getService(Ci.nsIPrefService).
- getDefaultBranch('extensions.' + preferencesBranch + '.');
- for (let { name, value } of preferences) {
- switch (typeof value) {
- case 'boolean':
- branch.setBoolPref(name, value);
- break;
- case 'number':
- // must be integer, ignore otherwise
- if (value % 1 === 0) {
- branch.setIntPref(name, value);
- }
- break;
- case 'string':
- let str = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- str.data = value;
- branch.setComplexValue(name, Ci.nsISupportsString, str);
- break;
- }
- }
-}
-exports.setDefaults = setDefaults;
-
-// dynamically injects inline options into about:addons page at runtime
-// NOTE: on Firefox Desktop the about:addons page is a xul page document,
-// on Firefox for Android the about:addons page is an xhtml page, to support both
-// the XUL xml namespace have to be enforced.
-function injectOptions({ preferences, preferencesBranch, document, parent, id }) {
- preferences.forEach(({name, type, hidden, title, description, label, options, on, off}) => {
- if (hidden) {
- return;
- }
-
- let setting = document.createElementNS(XUL_NS, 'setting');
- setting.setAttribute('pref-name', name);
- setting.setAttribute('data-jetpack-id', id);
- setting.setAttribute('pref', 'extensions.' + preferencesBranch + '.' + name);
- setting.setAttribute('type', type);
- setting.setAttribute('title', title);
- if (description)
- setting.setAttribute('desc', description);
-
- if (type === 'file' || type === 'directory') {
- setting.setAttribute('fullpath', 'true');
- }
- else if (type === 'control') {
- let button = document.createElementNS(XUL_NS, 'button');
- button.setAttribute('pref-name', name);
- button.setAttribute('data-jetpack-id', id);
- button.setAttribute('label', label);
- button.addEventListener('command', function() {
- Services.obs.notifyObservers(null, `${id}-cmdPressed`, name);
- }, true);
- setting.appendChild(button);
- }
- else if (type === 'boolint') {
- setting.setAttribute('on', on);
- setting.setAttribute('off', off);
- }
- else if (type === 'menulist') {
- let menulist = document.createElementNS(XUL_NS, 'menulist');
- let menupopup = document.createElementNS(XUL_NS, 'menupopup');
- for (let { value, label } of options) {
- let menuitem = document.createElementNS(XUL_NS, 'menuitem');
- menuitem.setAttribute('value', value);
- menuitem.setAttribute('label', label);
- menupopup.appendChild(menuitem);
- }
- menulist.appendChild(menupopup);
- setting.appendChild(menulist);
- }
- else if (type === 'radio') {
- let radiogroup = document.createElementNS(XUL_NS, 'radiogroup');
- for (let { value, label } of options) {
- let radio = document.createElementNS(XUL_NS, 'radio');
- radio.setAttribute('value', value);
- radio.setAttribute('label', label);
- radiogroup.appendChild(radio);
- }
- setting.appendChild(radiogroup);
- }
-
- parent.appendChild(setting);
- });
-}
-exports.injectOptions = injectOptions;
diff --git a/addon-sdk/source/lib/sdk/preferences/service.js b/addon-sdk/source/lib/sdk/preferences/service.js
deleted file mode 100644
index 231cd8e14..000000000
--- a/addon-sdk/source/lib/sdk/preferences/service.js
+++ /dev/null
@@ -1,137 +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"
-};
-
-// The minimum and maximum integers that can be set as preferences.
-// The range of valid values is narrower than the range of valid JS values
-// because the native preferences code treats integers as NSPR PRInt32s,
-// which are 32-bit signed integers on all platforms.
-const MAX_INT = 0x7FFFFFFF;
-const MIN_INT = -0x80000000;
-
-const {Cc,Ci,Cr} = require("chrome");
-
-const prefService = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefService);
-const prefSvc = prefService.getBranch(null);
-const defaultBranch = prefService.getDefaultBranch(null);
-
-const { Preferences } = require("resource://gre/modules/Preferences.jsm");
-const prefs = new Preferences({});
-
-const branchKeys = branchName =>
- keys(branchName).map($ => $.replace(branchName, ""));
-
-const Branch = function(branchName) {
- return new Proxy(Branch.prototype, {
- getOwnPropertyDescriptor(target, name, receiver) {
- return {
- configurable: true,
- enumerable: true,
- writable: false,
- value: this.get(target, name, receiver)
- };
- },
- ownKeys(target) {
- return branchKeys(branchName);
- },
- get(target, name, receiver) {
- return get(`${branchName}${name}`);
- },
- set(target, name, value, receiver) {
- set(`${branchName}${name}`, value);
- return true;
- },
- has(target, name) {
- return this.hasOwn(target, name);
- },
- hasOwn(target, name) {
- return has(`${branchName}${name}`);
- },
- deleteProperty(target, name) {
- reset(`${branchName}${name}`);
- return true;
- }
- });
-}
-
-
-function get(name, defaultValue) {
- return prefs.get(name, defaultValue);
-}
-exports.get = get;
-
-
-function set(name, value) {
- var prefType;
- if (typeof value != "undefined" && value != null)
- prefType = value.constructor.name;
-
- switch (prefType) {
- case "Number":
- if (value % 1 != 0)
- throw new Error("cannot store non-integer number: " + value);
- }
-
- prefs.set(name, value);
-}
-exports.set = set;
-
-const has = prefs.has.bind(prefs)
-exports.has = has;
-
-function keys(root) {
- return prefSvc.getChildList(root);
-}
-exports.keys = keys;
-
-const isSet = prefs.isSet.bind(prefs);
-exports.isSet = isSet;
-
-function reset(name) {
- try {
- prefSvc.clearUserPref(name);
- }
- catch (e) {
- // The pref service throws NS_ERROR_UNEXPECTED when the caller tries
- // to reset a pref that doesn't exist or is already set to its default
- // value. This interface fails silently in those cases, so callers
- // can unconditionally reset a pref without having to check if it needs
- // resetting first or trap exceptions after the fact. It passes through
- // other exceptions, however, so callers know about them, since we don't
- // know what other exceptions might be thrown and what they might mean.
- if (e.result != Cr.NS_ERROR_UNEXPECTED) {
- throw e;
- }
- }
-}
-exports.reset = reset;
-
-function getLocalized(name, defaultValue) {
- let value = null;
- try {
- value = prefSvc.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
- }
- finally {
- return value || defaultValue;
- }
-}
-exports.getLocalized = getLocalized;
-
-function setLocalized(name, value) {
- // We can't use `prefs.set` here as we have to use `getDefaultBranch`
- // (instead of `getBranch`) in order to have `mIsDefault` set to true, here:
- // http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/nsPrefBranch.cpp#233
- // Otherwise, we do not enter into this expected condition:
- // http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/nsPrefBranch.cpp#244
- defaultBranch.setCharPref(name, value);
-}
-exports.setLocalized = setLocalized;
-
-exports.Branch = Branch;
-
diff --git a/addon-sdk/source/lib/sdk/preferences/utils.js b/addon-sdk/source/lib/sdk/preferences/utils.js
deleted file mode 100644
index 1d5769c37..000000000
--- a/addon-sdk/source/lib/sdk/preferences/utils.js
+++ /dev/null
@@ -1,42 +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 { openTab, getBrowserForTab, getTabId } = require("sdk/tabs/utils");
-const { on, off } = require("sdk/system/events");
-const { getMostRecentBrowserWindow } = require('../window/utils');
-
-// Opens about:addons in a new tab, then displays the inline
-// preferences of the provided add-on
-const open = ({ id }) => new Promise((resolve, reject) => {
- // opening the about:addons page in a new tab
- let tab = openTab(getMostRecentBrowserWindow(), "about:addons");
- let browser = getBrowserForTab(tab);
-
- // waiting for the about:addons page to load
- browser.addEventListener("load", function onPageLoad() {
- browser.removeEventListener("load", onPageLoad, true);
- let window = browser.contentWindow;
-
- // wait for the add-on's "addon-options-displayed"
- on("addon-options-displayed", function onPrefDisplayed({ subject: doc, data }) {
- if (data === id) {
- off("addon-options-displayed", onPrefDisplayed);
- resolve({
- id: id,
- tabId: getTabId(tab),
- "document": doc
- });
- }
- }, true);
-
- // display the add-on inline preferences page
- window.gViewController.commands.cmd_showItemDetails.doCommand({ id: id }, true);
- }, true);
-});
-exports.open = open;
diff --git a/addon-sdk/source/lib/sdk/private-browsing.js b/addon-sdk/source/lib/sdk/private-browsing.js
deleted file mode 100644
index 29ca16185..000000000
--- a/addon-sdk/source/lib/sdk/private-browsing.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": "stable"
-};
-
-const { isPrivate } = require('./private-browsing/utils');
-
-exports.isPrivate = isPrivate;
diff --git a/addon-sdk/source/lib/sdk/private-browsing/utils.js b/addon-sdk/source/lib/sdk/private-browsing/utils.js
deleted file mode 100644
index 8b012f0ce..000000000
--- a/addon-sdk/source/lib/sdk/private-browsing/utils.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';
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { Cc, Ci, Cu } = require('chrome');
-const { is } = require('../system/xul-app');
-const { isWindowPrivate } = require('../window/utils');
-const { isPrivateBrowsingSupported } = require('../self');
-const { dispatcher } = require("../util/dispatcher");
-
-var PrivateBrowsingUtils;
-
-// Private browsing is only supported in Fx
-try {
- PrivateBrowsingUtils = Cu.import('resource://gre/modules/PrivateBrowsingUtils.jsm', {}).PrivateBrowsingUtils;
-}
-catch (e) {}
-
-exports.isGlobalPBSupported = false;
-
-// checks that per-window private browsing is implemented
-var isWindowPBSupported = exports.isWindowPBSupported =
- !!PrivateBrowsingUtils && is('Firefox');
-
-// checks that per-tab private browsing is implemented
-var isTabPBSupported = exports.isTabPBSupported =
- !!PrivateBrowsingUtils && is('Fennec');
-
-function isPermanentPrivateBrowsing() {
- return !!(PrivateBrowsingUtils && PrivateBrowsingUtils.permanentPrivateBrowsing);
-}
-exports.isPermanentPrivateBrowsing = isPermanentPrivateBrowsing;
-
-function ignoreWindow(window) {
- return !isPrivateBrowsingSupported && isWindowPrivate(window);
-}
-exports.ignoreWindow = ignoreWindow;
-
-var getMode = function getMode(chromeWin) {
- return (chromeWin !== undefined && isWindowPrivate(chromeWin));
-};
-exports.getMode = getMode;
-
-const isPrivate = dispatcher("isPrivate");
-isPrivate.when(isPermanentPrivateBrowsing, _ => true);
-isPrivate.when(x => x instanceof Ci.nsIDOMWindow, isWindowPrivate);
-isPrivate.when(x => Ci.nsIPrivateBrowsingChannel && x instanceof Ci.nsIPrivateBrowsingChannel, x => x.isChannelPrivate);
-isPrivate.define(() => false);
-exports.isPrivate = isPrivate;
diff --git a/addon-sdk/source/lib/sdk/querystring.js b/addon-sdk/source/lib/sdk/querystring.js
deleted file mode 100644
index 9982a00ab..000000000
--- a/addon-sdk/source/lib/sdk/querystring.js
+++ /dev/null
@@ -1,121 +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"
-};
-
-var unescape = decodeURIComponent;
-exports.unescape = unescape;
-
-// encodes a string safely for application/x-www-form-urlencoded
-// adheres to RFC 3986
-// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURIComponent
-function escape(query) {
- return encodeURIComponent(query).
- replace(/%20/g, '+').
- replace(/!/g, '%21').
- replace(/'/g, '%27').
- replace(/\(/g, '%28').
- replace(/\)/g, '%29').
- replace(/\*/g, '%2A');
-}
-exports.escape = escape;
-
-// Converts an object of unordered key-vals to a string that can be passed
-// as part of a request
-function stringify(options, separator, assigner) {
- separator = separator || '&';
- assigner = assigner || '=';
- // Explicitly return null if we have null, and empty string, or empty object.
- if (!options)
- return '';
-
- // If content is already a string, just return it as is.
- if (typeof(options) == 'string')
- return options;
-
- // At this point we have a k:v object. Iterate over it and encode each value.
- // Arrays and nested objects will get encoded as needed. For example...
- //
- // { foo: [1, 2, { omg: 'bbq', 'all your base!': 'are belong to us' }], bar: 'baz' }
- //
- // will be encoded as
- //
- // foo[0]=1&foo[1]=2&foo[2][omg]=bbq&foo[2][all+your+base!]=are+belong+to+us&bar=baz
- //
- // Keys (including '[' and ']') and values will be encoded with
- // `escape` before returning.
- //
- // Execution was inspired by jQuery, but some details have changed and numeric
- // array keys are included (whereas they are not in jQuery).
-
- let encodedContent = [];
- function add(key, val) {
- encodedContent.push(escape(key) + assigner + escape(val));
- }
-
- function make(key, value) {
- if (value && typeof(value) === 'object')
- Object.keys(value).forEach(function(name) {
- make(key + '[' + name + ']', value[name]);
- });
- else
- add(key, value);
- }
-
- Object.keys(options).forEach(function(name) { make(name, options[name]); });
- return encodedContent.join(separator);
-
- //XXXzpao In theory, we can just use a FormData object on 1.9.3, but I had
- // trouble getting that working. It would also be nice to stay
- // backwards-compat as long as possible. Keeping this in for now...
- // let formData = Cc['@mozilla.org/files/formdata;1'].
- // createInstance(Ci.nsIDOMFormData);
- // for ([k, v] in Iterator(content)) {
- // formData.append(k, v);
- // }
- // return formData;
-}
-exports.stringify = stringify;
-
-// Exporting aliases that nodejs implements just for the sake of
-// interoperability.
-exports.encode = stringify;
-exports.serialize = stringify;
-
-// Note: That `stringify` and `parse` aren't bijective as we use `stringify`
-// as it was implement in request module, but implement `parse` to match nodejs
-// behavior.
-// TODO: Make `stringify` implement API as in nodejs and figure out backwards
-// compatibility.
-function parse(query, separator, assigner) {
- separator = separator || '&';
- assigner = assigner || '=';
- let result = {};
-
- if (typeof query !== 'string' || query.length === 0)
- return result;
-
- query.split(separator).forEach(function(chunk) {
- let pair = chunk.split(assigner);
- let key = unescape(pair[0]);
- let value = unescape(pair.slice(1).join(assigner));
-
- if (!(key in result))
- result[key] = value;
- else if (Array.isArray(result[key]))
- result[key].push(value);
- else
- result[key] = [result[key], value];
- });
-
- return result;
-};
-exports.parse = parse;
-// Exporting aliases that nodejs implements just for the sake of
-// interoperability.
-exports.decode = parse;
diff --git a/addon-sdk/source/lib/sdk/remote/child.js b/addon-sdk/source/lib/sdk/remote/child.js
deleted file mode 100644
index 4ccfa661a..000000000
--- 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;
diff --git a/addon-sdk/source/lib/sdk/remote/core.js b/addon-sdk/source/lib/sdk/remote/core.js
deleted file mode 100644
index 78bb673fd..000000000
--- 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;
diff --git a/addon-sdk/source/lib/sdk/remote/parent.js b/addon-sdk/source/lib/sdk/remote/parent.js
deleted file mode 100644
index f110fe3f6..000000000
--- a/addon-sdk/source/lib/sdk/remote/parent.js
+++ /dev/null
@@ -1,338 +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');
-const { getTabForBrowser } = require('../tabs/utils');
-
-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;
-}
-// Build the sorted path mapping structure that resolveURI requires
-var pathMapping = Object.keys(options.paths)
- .sort((a, b) => b.length - a.length)
- .map(p => [p, options.paths[p]]);
-
-// 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);
- let uri = loaderModule.resolveURI(id, pathMapping);
-
- // Don't reload the same module
- if (remoteModules.has(uri))
- return;
-
- remoteModules.add(uri);
- processes.port.emit('sdk/remote/require', uri);
-}
-exports.remoteRequire = remoteRequire;
diff --git a/addon-sdk/source/lib/sdk/remote/utils.js b/addon-sdk/source/lib/sdk/remote/utils.js
deleted file mode 100644
index 5a5e39198..000000000
--- 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');
-const { emit } = require('../event/core');
-const { pipe } = require('../event/utils');
-
-// 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;
diff --git a/addon-sdk/source/lib/sdk/request.js b/addon-sdk/source/lib/sdk/request.js
deleted file mode 100644
index 96bb1e6d7..000000000
--- a/addon-sdk/source/lib/sdk/request.js
+++ /dev/null
@@ -1,248 +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 { ns } = require("./core/namespace");
-const { emit } = require("./event/core");
-const { merge } = require("./util/object");
-const { stringify } = require("./querystring");
-const { EventTarget } = require("./event/target");
-const { Class } = require("./core/heritage");
-const { XMLHttpRequest, forceAllowThirdPartyCookie } = require("./net/xhr");
-const apiUtils = require("./deprecated/api-utils");
-const { isValidURI } = require("./url.js");
-
-const response = ns();
-const request = ns();
-
-// Instead of creating a new validator for each request, just make one and
-// reuse it.
-const { validateOptions, validateSingleOption } = new OptionsValidator({
- url: {
- // Also converts a URL instance to string, bug 857902
- map: url => url.toString(),
- ok: isValidURI
- },
- headers: {
- map: v => v || {},
- is: ["object"],
- },
- content: {
- map: v => v || null,
- is: ["string", "object", "null"],
- },
- contentType: {
- map: v => v || "application/x-www-form-urlencoded",
- is: ["string"],
- },
- overrideMimeType: {
- map: v => v || null,
- is: ["string", "null"],
- },
- anonymous: {
- map: v => v || false,
- is: ["boolean", "null"],
- }
-});
-
-const REUSE_ERROR = "This request object has been used already. You must " +
- "create a new one to make a new request."
-
-// Utility function to prep the request since it's the same between
-// request types
-function runRequest(mode, target) {
- let source = request(target)
- let { xhr, url, content, contentType, headers, overrideMimeType, anonymous } = source;
-
- let isGetOrHead = (mode == "GET" || mode == "HEAD");
-
- // If this request has already been used, then we can't reuse it.
- // Throw an error.
- if (xhr)
- throw new Error(REUSE_ERROR);
-
- xhr = source.xhr = new XMLHttpRequest({
- mozAnon: anonymous
- });
-
- // Build the data to be set. For GET or HEAD requests, we want to append that
- // to the URL before opening the request.
- let data = stringify(content);
- // If the URL already has ? in it, then we want to just use &
- if (isGetOrHead && data)
- url = url + (/\?/.test(url) ? "&" : "?") + data;
-
- // open the request
- xhr.open(mode, url);
-
-
- forceAllowThirdPartyCookie(xhr);
-
- // request header must be set after open, but before send
- xhr.setRequestHeader("Content-Type", contentType);
-
- // set other headers
- Object.keys(headers).forEach(function(name) {
- xhr.setRequestHeader(name, headers[name]);
- });
-
- // set overrideMimeType
- if (overrideMimeType)
- xhr.overrideMimeType(overrideMimeType);
-
- // handle the readystate, create the response, and call the callback
- xhr.onreadystatechange = function onreadystatechange() {
- if (xhr.readyState === 4) {
- let response = Response(xhr);
- source.response = response;
- emit(target, 'complete', response);
- }
- };
-
- // actually send the request.
- // We don't want to send data on GET or HEAD requests.
- xhr.send(!isGetOrHead ? data : null);
-}
-
-const Request = Class({
- extends: EventTarget,
- initialize: function initialize(options) {
- // `EventTarget.initialize` will set event listeners that are named
- // like `onEvent` in this case `onComplete` listener will be set to
- // `complete` event.
- EventTarget.prototype.initialize.call(this, options);
-
- // Copy normalized options.
- merge(request(this), validateOptions(options));
- },
- get url() { return request(this).url; },
- set url(value) { request(this).url = validateSingleOption('url', value); },
- get headers() { return request(this).headers; },
- set headers(value) {
- return request(this).headers = validateSingleOption('headers', value);
- },
- get content() { return request(this).content; },
- set content(value) {
- request(this).content = validateSingleOption('content', value);
- },
- get contentType() { return request(this).contentType; },
- set contentType(value) {
- request(this).contentType = validateSingleOption('contentType', value);
- },
- get anonymous() { return request(this).anonymous; },
- get response() { return request(this).response; },
- delete: function() {
- runRequest('DELETE', this);
- return this;
- },
- get: function() {
- runRequest('GET', this);
- return this;
- },
- post: function() {
- runRequest('POST', this);
- return this;
- },
- put: function() {
- runRequest('PUT', this);
- return this;
- },
- head: function() {
- runRequest('HEAD', this);
- return this;
- }
-});
-exports.Request = Request;
-
-const Response = Class({
- initialize: function initialize(request) {
- response(this).request = request;
- },
- // more about responseURL: https://bugzilla.mozilla.org/show_bug.cgi?id=998076
- get url() {
- return response(this).request.responseURL;
- },
- get text() {
- return response(this).request.responseText;
- },
- get xml() {
- throw new Error("Sorry, the 'xml' property is no longer available. " +
- "see bug 611042 for more information.");
- },
- get status() {
- return response(this).request.status;
- },
- get statusText() {
- return response(this).request.statusText;
- },
- get json() {
- try {
- return JSON.parse(this.text);
- } catch(error) {
- return null;
- }
- },
- get headers() {
- let headers = {}, lastKey;
- // Since getAllResponseHeaders() will return null if there are no headers,
- // defend against it by defaulting to ""
- let rawHeaders = response(this).request.getAllResponseHeaders() || "";
- rawHeaders.split("\n").forEach(function (h) {
- // According to the HTTP spec, the header string is terminated by an empty
- // line, so we can just skip it.
- if (!h.length) {
- return;
- }
-
- let index = h.indexOf(":");
- // The spec allows for leading spaces, so instead of assuming a single
- // leading space, just trim the values.
- let key = h.substring(0, index).trim(),
- val = h.substring(index + 1).trim();
-
- // For empty keys, that means that the header value spanned multiple lines.
- // In that case we should append the value to the value of lastKey with a
- // new line. We'll assume lastKey will be set because there should never
- // be an empty key on the first pass.
- if (key) {
- headers[key] = val;
- lastKey = key;
- }
- else {
- headers[lastKey] += "\n" + val;
- }
- });
- return headers;
- },
- get anonymous() {
- return response(this).request.mozAnon;
- }
-});
-
-// apiUtils.validateOptions doesn't give the ability to easily validate single
-// options, so this is a wrapper that provides that ability.
-function OptionsValidator(rules) {
- return {
- validateOptions: function (options) {
- return apiUtils.validateOptions(options, rules);
- },
- validateSingleOption: function (field, value) {
- // We need to create a single rule object from our listed rules. To avoid
- // JavaScript String warnings, check for the field & default to an empty object.
- let singleRule = {};
- if (field in rules) {
- singleRule[field] = rules[field];
- }
- let singleOption = {};
- singleOption[field] = value;
- // This should throw if it's invalid, which will bubble up & out.
- return apiUtils.validateOptions(singleOption, singleRule)[field];
- }
- };
-}
diff --git a/addon-sdk/source/lib/sdk/selection.js b/addon-sdk/source/lib/sdk/selection.js
deleted file mode 100644
index 8682e8c6d..000000000
--- a/addon-sdk/source/lib/sdk/selection.js
+++ /dev/null
@@ -1,470 +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"),
- { setTimeout } = require("./timers"),
- { emit, off } = require("./event/core"),
- { Class, obscure } = require("./core/heritage"),
- { EventTarget } = require("./event/target"),
- { ns } = require("./core/namespace"),
- { when: unload } = require("./system/unload"),
- { ignoreWindow } = require('./private-browsing/utils'),
- { getTabs, getTabForContentWindow,
- getAllTabContentWindows } = require('./tabs/utils'),
- winUtils = require("./window/utils"),
- 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.ownerDocument.defaultView))
- 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;
diff --git a/addon-sdk/source/lib/sdk/self.js b/addon-sdk/source/lib/sdk/self.js
deleted file mode 100644
index c2114a926..000000000
--- a/addon-sdk/source/lib/sdk/self.js
+++ /dev/null
@@ -1,61 +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 { CC } = require('chrome');
-const options = require('@loader/options');
-
-const { get } = require("./preferences/service");
-const { readURISync } = require('./net/url');
-
-const id = options.id;
-
-const readPref = key => get("extensions." + id + ".sdk." + key);
-
-const name = readPref("name") || options.name;
-const version = readPref("version") || options.version;
-const loadReason = readPref("load.reason") || options.loadReason;
-const rootURI = readPref("rootURI") || options.rootURI || "";
-const baseURI = readPref("baseURI") || options.prefixURI + name + "/"
-const addonDataURI = baseURI + "data/";
-const metadata = options.metadata || {};
-const permissions = metadata.permissions || {};
-const isPacked = rootURI && rootURI.indexOf("jar:") === 0;
-
-const isPrivateBrowsingSupported = 'private-browsing' in permissions &&
- permissions['private-browsing'] === true;
-
-const uri = (path="") =>
- path.includes(":") ? path : addonDataURI + path.replace(/^\.\//, "");
-
-var preferencesBranch = ("preferences-branch" in metadata)
- ? metadata["preferences-branch"]
- : options.preferencesBranch
-
-if (/[^\w{@}.-]/.test(preferencesBranch)) {
- preferencesBranch = id;
- console.warn("Ignoring preferences-branch (not a valid branch name)");
-}
-
-// Some XPCOM APIs require valid URIs as an argument for certain operations
-// (see `nsILoginManager` for example). This property represents add-on
-// associated unique URI string that can be used for that.
-exports.uri = 'addon:' + id;
-exports.id = id;
-exports.preferencesBranch = preferencesBranch || id;
-exports.name = name;
-exports.loadReason = loadReason;
-exports.version = version;
-exports.packed = isPacked;
-exports.data = Object.freeze({
- url: uri,
- load: function read(path) {
- return readURISync(uri(path));
- }
-});
-exports.isPrivateBrowsingSupported = isPrivateBrowsingSupported;
diff --git a/addon-sdk/source/lib/sdk/simple-prefs.js b/addon-sdk/source/lib/sdk/simple-prefs.js
deleted file mode 100644
index 3472f4418..000000000
--- a/addon-sdk/source/lib/sdk/simple-prefs.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": "experimental"
-};
-
-const { emit, off } = require("./event/core");
-const { PrefsTarget } = require("./preferences/event-target");
-const { preferencesBranch, id } = require("./self");
-const { on } = require("./system/events");
-
-const ADDON_BRANCH = "extensions." + preferencesBranch + ".";
-const BUTTON_PRESSED = id + "-cmdPressed";
-
-const target = PrefsTarget({ branchName: ADDON_BRANCH });
-
-// Listen to clicks on buttons
-function buttonClick({ data }) {
- emit(target, data);
-}
-on(BUTTON_PRESSED, buttonClick);
-
-module.exports = target;
diff --git a/addon-sdk/source/lib/sdk/simple-storage.js b/addon-sdk/source/lib/sdk/simple-storage.js
deleted file mode 100644
index bcf9b1cb9..000000000
--- a/addon-sdk/source/lib/sdk/simple-storage.js
+++ /dev/null
@@ -1,235 +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 { Cc, Ci } = require("chrome");
-const file = require("./io/file");
-const prefs = require("./preferences/service");
-const jpSelf = require("./self");
-const timer = require("./timers");
-const unload = require("./system/unload");
-const { emit, on, off } = require("./event/core");
-
-const WRITE_PERIOD_PREF = "extensions.addon-sdk.simple-storage.writePeriod";
-const WRITE_PERIOD_DEFAULT = 300000; // 5 minutes
-
-const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota";
-const QUOTA_DEFAULT = 5242880; // 5 MiB
-
-const JETPACK_DIR_BASENAME = "jetpack";
-
-Object.defineProperties(exports, {
- storage: {
- enumerable: true,
- get: function() { return manager.root; },
- set: function(value) { manager.root = value; }
- },
- quotaUsage: {
- get: function() { return manager.quotaUsage; }
- }
-});
-
-// A generic JSON store backed by a file on disk. This should be isolated
-// enough to move to its own module if need be...
-function JsonStore(options) {
- this.filename = options.filename;
- this.quota = options.quota;
- this.writePeriod = options.writePeriod;
- this.onOverQuota = options.onOverQuota;
- this.onWrite = options.onWrite;
-
- unload.ensure(this);
-
- this.writeTimer = timer.setInterval(this.write.bind(this),
- this.writePeriod);
-}
-
-JsonStore.prototype = {
- // The store's root.
- get root() {
- return this.isRootInited ? this._root : {};
- },
-
- // Performs some type checking.
- set root(val) {
- let types = ["array", "boolean", "null", "number", "object", "string"];
- if (types.indexOf(typeof(val)) < 0) {
- throw new Error("storage must be one of the following types: " +
- types.join(", "));
- }
- this._root = val;
- return val;
- },
-
- // True if the root has ever been set (either via the root setter or by the
- // backing file's having been read).
- get isRootInited() {
- return this._root !== undefined;
- },
-
- // Percentage of quota used, as a number [0, Inf). > 1 implies over quota.
- // Undefined if there is no quota.
- get quotaUsage() {
- return this.quota > 0 ?
- JSON.stringify(this.root).length / this.quota :
- undefined;
- },
-
- // Removes the backing file and all empty subdirectories.
- purge: function JsonStore_purge() {
- try {
- // This'll throw if the file doesn't exist.
- file.remove(this.filename);
- let parentPath = this.filename;
- do {
- parentPath = file.dirname(parentPath);
- // This'll throw if the dir isn't empty.
- file.rmdir(parentPath);
- } while (file.basename(parentPath) !== JETPACK_DIR_BASENAME);
- }
- catch (err) {}
- },
-
- // Initializes the root by reading the backing file.
- read: function JsonStore_read() {
- try {
- let str = file.read(this.filename);
-
- // Ideally we'd log the parse error with console.error(), but logged
- // errors cause tests to fail. Supporting "known" errors in the test
- // harness appears to be non-trivial. Maybe later.
- this.root = JSON.parse(str);
- }
- catch (err) {
- this.root = {};
- }
- },
-
- // If the store is under quota, writes the root to the backing file.
- // Otherwise quota observers are notified and nothing is written.
- write: function JsonStore_write() {
- if (this.quotaUsage > 1)
- this.onOverQuota(this);
- else
- this._write();
- },
-
- // Cleans up on unload. If unloading because of uninstall, the store is
- // purged; otherwise it's written.
- unload: function JsonStore_unload(reason) {
- timer.clearInterval(this.writeTimer);
- this.writeTimer = null;
-
- if (reason === "uninstall")
- this.purge();
- else
- this._write();
- },
-
- // True if the root is an empty object.
- get _isEmpty() {
- if (this.root && typeof(this.root) === "object") {
- let empty = true;
- for (let key in this.root) {
- empty = false;
- break;
- }
- return empty;
- }
- return false;
- },
-
- // Writes the root to the backing file, notifying write observers when
- // complete. If the store is over quota or if it's empty and the store has
- // never been written, nothing is written and write observers aren't notified.
- _write: function JsonStore__write() {
- // Don't write if the root is uninitialized or if the store is empty and the
- // backing file doesn't yet exist.
- if (!this.isRootInited || (this._isEmpty && !file.exists(this.filename)))
- return;
-
- // If the store is over quota, don't write. The current under-quota state
- // should persist.
- if (this.quotaUsage > 1)
- return;
-
- // Finally, write.
- let stream = file.open(this.filename, "w");
- try {
- stream.writeAsync(JSON.stringify(this.root), function writeAsync(err) {
- if (err)
- console.error("Error writing simple storage file: " + this.filename);
- else if (this.onWrite)
- this.onWrite(this);
- }.bind(this));
- }
- catch (err) {
- // writeAsync closes the stream after it's done, so only close on error.
- stream.close();
- }
- }
-};
-
-
-// This manages a JsonStore singleton and tailors its use to simple storage.
-// The root of the JsonStore is lazy-loaded: The backing file is only read the
-// first time the root's gotten.
-var manager = ({
- jsonStore: null,
-
- // The filename of the store, based on the profile dir and extension ID.
- get filename() {
- let storeFile = Cc["@mozilla.org/file/directory_service;1"].
- getService(Ci.nsIProperties).
- get("ProfD", Ci.nsIFile);
- storeFile.append(JETPACK_DIR_BASENAME);
- storeFile.append(jpSelf.id);
- storeFile.append("simple-storage");
- file.mkpath(storeFile.path);
- storeFile.append("store.json");
- return storeFile.path;
- },
-
- get quotaUsage() {
- return this.jsonStore.quotaUsage;
- },
-
- get root() {
- if (!this.jsonStore.isRootInited)
- this.jsonStore.read();
- return this.jsonStore.root;
- },
-
- set root(val) {
- return this.jsonStore.root = val;
- },
-
- unload: function manager_unload() {
- off(this);
- },
-
- new: function manager_constructor() {
- let manager = Object.create(this);
- unload.ensure(manager);
-
- manager.jsonStore = new JsonStore({
- filename: manager.filename,
- writePeriod: prefs.get(WRITE_PERIOD_PREF, WRITE_PERIOD_DEFAULT),
- quota: prefs.get(QUOTA_PREF, QUOTA_DEFAULT),
- onOverQuota: emit.bind(null, exports, "OverQuota")
- });
-
- return manager;
- }
-}).new();
-
-exports.on = on.bind(null, exports);
-exports.removeListener = function(type, listener) {
- off(exports, type, listener);
-};
diff --git a/addon-sdk/source/lib/sdk/stylesheet/style.js b/addon-sdk/source/lib/sdk/stylesheet/style.js
deleted file mode 100644
index 7ec0787e1..000000000
--- a/addon-sdk/source/lib/sdk/stylesheet/style.js
+++ /dev/null
@@ -1,71 +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 } = require("chrome");
-const { Class } = require("../core/heritage");
-const { URL, isLocalURL } = require('../url');
-const events = require("../system/events");
-const { loadSheet, removeSheet, isTypeValid } = require("./utils");
-const { isString } = require("../lang/type");
-const { attachTo, detachFrom } = require("../content/mod");
-const { data } = require('../self');
-
-const { freeze, create } = Object;
-
-function Style({ source, uri, type }) {
- source = source == null ? null : freeze([].concat(source));
- uri = uri == null ? null : freeze([].concat(uri));
- type = type == null ? "author" : type;
-
- if (source && !source.every(isString))
- throw new Error('Style.source must be a string or an array of strings.');
-
- if (uri && !uri.every(isLocalURL))
- throw new Error('Style.uri must be a local URL or an array of local URLs');
-
- if (type && !isTypeValid(type))
- throw new Error('Style.type must be "agent", "user" or "author"');
-
- return freeze(create(Style.prototype, {
- "source": { value: source, enumerable: true },
- "uri": { value: uri, enumerable: true },
- "type": { value: type, enumerable: true }
- }));
-};
-
-exports.Style = Style;
-
-attachTo.define(Style, function (style, window) {
- if (style.uri) {
- for (let uri of style.uri)
- loadSheet(window, data.url(uri), style.type);
- }
-
- if (style.source) {
- let uri = "data:text/css;charset=utf-8,";
-
- uri += encodeURIComponent(style.source.join(""));
-
- loadSheet(window, uri, style.type);
- }
-});
-
-detachFrom.define(Style, function (style, window) {
- if (style.uri)
- for (let uri of style.uri)
- removeSheet(window, data.url(uri));
-
- if (style.source) {
- let uri = "data:text/css;charset=utf-8,";
-
- uri += encodeURIComponent(style.source.join(""));
-
- removeSheet(window, uri, style.type);
- }
-});
diff --git a/addon-sdk/source/lib/sdk/stylesheet/utils.js b/addon-sdk/source/lib/sdk/stylesheet/utils.js
deleted file mode 100644
index 844996bf3..000000000
--- a/addon-sdk/source/lib/sdk/stylesheet/utils.js
+++ /dev/null
@@ -1,75 +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 { Ci } = require("chrome");
-
-const SHEET_TYPE = {
- "agent": "AGENT_SHEET",
- "user": "USER_SHEET",
- "author": "AUTHOR_SHEET"
-};
-
-function getDOMWindowUtils(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils);
-};
-
-/**
- * Synchronously loads a style sheet from `uri` and adds it to the list of
- * additional style sheets of the document.
- * The sheets added takes effect immediately, and only on the document of the
- * `window` given.
- */
-function loadSheet(window, url, type) {
- if (!(type && type in SHEET_TYPE))
- type = "author";
-
- type = SHEET_TYPE[type];
-
- if (url instanceof Ci.nsIURI)
- url = url.spec;
-
- let winUtils = getDOMWindowUtils(window);
- try {
- winUtils.loadSheetUsingURIString(url, winUtils[type]);
- }
- catch (e) {};
-};
-exports.loadSheet = loadSheet;
-
-/**
- * Remove the document style sheet at `sheetURI` from the list of additional
- * style sheets of the document. The removal takes effect immediately.
- */
-function removeSheet(window, url, type) {
- if (!(type && type in SHEET_TYPE))
- type = "author";
-
- type = SHEET_TYPE[type];
-
- if (url instanceof Ci.nsIURI)
- url = url.spec;
-
- let winUtils = getDOMWindowUtils(window);
-
- try {
- winUtils.removeSheetUsingURIString(url, winUtils[type]);
- }
- catch (e) {};
-};
-exports.removeSheet = removeSheet;
-
-/**
- * Returns `true` if the `type` given is valid, otherwise `false`.
- * The values currently accepted are: "agent", "user" and "author".
- */
-function isTypeValid(type) {
- return type in SHEET_TYPE;
-}
-exports.isTypeValid = isTypeValid;
diff --git a/addon-sdk/source/lib/sdk/system.js b/addon-sdk/source/lib/sdk/system.js
deleted file mode 100644
index 1acfe8c8c..000000000
--- a/addon-sdk/source/lib/sdk/system.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';
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { Cc, Ci, CC } = require('chrome');
-const options = require('@loader/options');
-const runtime = require("./system/runtime");
-const { when: unload } = require("./system/unload");
-
-const appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
- getService(Ci.nsIAppStartup);
-const appInfo = Cc["@mozilla.org/xre/app-info;1"].
- getService(Ci.nsIXULAppInfo);
-const directoryService = Cc['@mozilla.org/file/directory_service;1'].
- getService(Ci.nsIProperties);
-
-const PR_WRONLY = parseInt("0x02");
-const PR_CREATE_FILE = parseInt("0x08");
-const PR_APPEND = parseInt("0x10");
-const PR_TRUNCATE = parseInt("0x20");
-
-function openFile(path, mode) {
- let file = Cc["@mozilla.org/file/local;1"].
- createInstance(Ci.nsILocalFile);
- file.initWithPath(path);
- let stream = Cc["@mozilla.org/network/file-output-stream;1"].
- createInstance(Ci.nsIFileOutputStream);
- stream.init(file, mode, -1, 0);
- return stream
-}
-
-const { eAttemptQuit: E_ATTEMPT, eForceQuit: E_FORCE } = appStartup;
-
-/**
- * Parsed JSON object that was passed via `cfx --static-args "{ foo: 'bar' }"`
- */
-exports.staticArgs = options.staticArgs;
-
-/**
- * Environment variables. Environment variables are non-enumerable properties
- * of this object (key is name and value is value).
- */
-exports.env = require('./system/environment').env;
-
-/**
- * Ends the process with the specified `code`. If omitted, exit uses the
- * 'success' code 0. To exit with failure use `1`.
- * TODO: Improve platform to actually quit with an exit code.
- */
-var forcedExit = false;
-exports.exit = function exit(code) {
- if (forcedExit) {
- // a forced exit was already tried
- // NOTE: exit(0) is called twice sometimes (ex when using cfx testaddons)
- return;
- }
-
- let resultsFile = 'resultFile' in options && options.resultFile;
- function unloader() {
- if (!options.resultFile) {
- return;
- }
-
- // This is used by 'cfx' to find out exit code.
- let mode = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
- let stream = openFile(options.resultFile, mode);
- let status = code ? 'FAIL' : 'OK';
- stream.write(status, status.length);
- stream.flush();
- stream.close();
- return;
- }
-
- if (code == 0) {
- forcedExit = true;
- }
-
- // Bug 856999: Prevent automatic kill of Firefox when running tests
- if (options.noQuit) {
- return unload(unloader);
- }
-
- unloader();
- appStartup.quit(code ? E_ATTEMPT : E_FORCE);
-};
-
-// Adapter for nodejs's stdout & stderr:
-// http://nodejs.org/api/process.html#process_process_stdout
-var stdout = Object.freeze({ write: dump, end: dump });
-exports.stdout = stdout;
-exports.stderr = stdout;
-
-/**
- * Returns a path of the system's or application's special directory / file
- * associated with a given `id`. For list of possible `id`s please see:
- * https://developer.mozilla.org/en-US/docs/Code_snippets/File_I_O#Getting_files_in_special_directories
- * http://dxr.mozilla.org/mozilla-central/source/xpcom/io/nsAppDirectoryServiceDefs.h
- * @example
- *
- * // get firefox profile path
- * let profilePath = require('system').pathFor('ProfD');
- * // get OS temp files directory (/tmp)
- * let temps = require('system').pathFor('TmpD');
- * // get OS desktop path for an active user (~/Desktop on linux
- * // or C:\Documents and Settings\username\Desktop on windows).
- * let desktopPath = require('system').pathFor('Desk');
- */
-exports.pathFor = function pathFor(id) {
- return directoryService.get(id, Ci.nsIFile).path;
-};
-
-/**
- * What platform you're running on (all lower case string).
- * For possible values see:
- * https://developer.mozilla.org/en/OS_TARGET
- */
-exports.platform = runtime.OS.toLowerCase();
-
-const [, architecture, compiler] = runtime.XPCOMABI ?
- runtime.XPCOMABI.match(/^([^-]*)-(.*)$/) :
- [, null, null];
-
-/**
- * What processor architecture you're running on:
- * `'arm', 'ia32', or 'x64'`.
- */
-exports.architecture = architecture;
-
-/**
- * What compiler used for build:
- * `'msvc', 'n32', 'gcc2', 'gcc3', 'sunc', 'ibmc'...`
- */
-exports.compiler = compiler;
-
-/**
- * The application's build ID/date, for example "2004051604".
- */
-exports.build = appInfo.appBuildID;
-
-/**
- * The XUL application's UUID.
- * This has traditionally been in the form
- * `{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}` but for some applications it may
- * be: "appname@vendor.tld".
- */
-exports.id = appInfo.ID;
-
-/**
- * The name of the application.
- */
-exports.name = appInfo.name;
-
-/**
- * The XUL application's version, for example "0.8.0+" or "3.7a1pre".
- */
-exports.version = appInfo.version;
-
-/**
- * XULRunner version.
- */
-exports.platformVersion = appInfo.platformVersion;
-
-
-/**
- * The name of the application vendor, for example "Mozilla".
- */
-exports.vendor = appInfo.vendor;
diff --git a/addon-sdk/source/lib/sdk/system/child_process.js b/addon-sdk/source/lib/sdk/system/child_process.js
deleted file mode 100644
index 8ea1f4f80..000000000
--- a/addon-sdk/source/lib/sdk/system/child_process.js
+++ /dev/null
@@ -1,332 +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'
-};
-
-var { Ci } = require('chrome');
-var subprocess = require('./child_process/subprocess');
-var { EventTarget } = require('../event/target');
-var { Stream } = require('../io/stream');
-var { on, emit, off } = require('../event/core');
-var { Class } = require('../core/heritage');
-var { platform } = require('../system');
-var { isFunction, isArray } = require('../lang/type');
-var { delay } = require('../lang/functional');
-var { merge } = require('../util/object');
-var { setTimeout, clearTimeout } = require('../timers');
-var isWindows = platform.indexOf('win') === 0;
-
-var processes = new WeakMap();
-
-
-/**
- * The `Child` class wraps a subprocess command, exposes
- * the stdio streams, and methods to manipulate the subprocess
- */
-var Child = Class({
- implements: [EventTarget],
- initialize: function initialize (options) {
- let child = this;
- let proc;
-
- this.killed = false;
- this.exitCode = undefined;
- this.signalCode = undefined;
-
- this.stdin = Stream();
- this.stdout = Stream();
- this.stderr = Stream();
-
- try {
- proc = subprocess.call({
- command: options.file,
- arguments: options.cmdArgs,
- environment: serializeEnv(options.env),
- workdir: options.cwd,
- charset: options.encoding,
- stdout: data => emit(child.stdout, 'data', data),
- stderr: data => emit(child.stderr, 'data', data),
- stdin: stream => {
- child.stdin.on('data', pumpStdin);
- child.stdin.on('end', function closeStdin () {
- child.stdin.off('data', pumpStdin);
- child.stdin.off('end', closeStdin);
- stream.close();
- });
- function pumpStdin (data) {
- stream.write(data);
- }
- },
- done: function (result, error) {
- if (error)
- return handleError(error);
-
- // Only emit if child is not killed; otherwise,
- // the `kill` method will handle this
- if (!child.killed) {
- child.exitCode = result.exitCode;
- child.signalCode = null;
-
- // If process exits with < 0, there was an error
- if (child.exitCode < 0) {
- handleError(new Error('Process exited with exit code ' + child.exitCode));
- }
- else {
- // Also do 'exit' event as there's not much of
- // a difference in our implementation as we're not using
- // node streams
- emit(child, 'exit', child.exitCode, child.signalCode);
- }
-
- // Emit 'close' event with exit code and signal,
- // which is `null`, as it was not a killed process
- emit(child, 'close', child.exitCode, child.signalCode);
- }
- }
- });
- processes.set(child, proc);
- } catch (e) {
- // Delay the error handling so an error handler can be set
- // during the same tick that the Child was created
- delay(() => handleError(e));
- }
-
- // `handleError` is called when process could not even
- // be spawned
- function handleError (e) {
- // If error is an nsIObject, make a fresh error object
- // so we're not exposing nsIObjects, and we can modify it
- // with additional process information, like node
- let error = e;
- if (e instanceof Ci.nsISupports) {
- error = new Error(e.message, e.filename, e.lineNumber);
- }
- emit(child, 'error', error);
- child.exitCode = -1;
- child.signalCode = null;
- emit(child, 'close', child.exitCode, child.signalCode);
- }
- },
- kill: function kill (signal) {
- let proc = processes.get(this);
- proc.kill(signal);
- this.killed = true;
- this.exitCode = null;
- this.signalCode = signal;
- emit(this, 'exit', this.exitCode, this.signalCode);
- emit(this, 'close', this.exitCode, this.signalCode);
- },
- get pid() { return processes.get(this, {}).pid || -1; }
-});
-
-function spawn (file, ...args) {
- let cmdArgs = [];
- // Default options
- let options = {
- cwd: null,
- env: null,
- encoding: 'UTF-8'
- };
-
- if (args[1]) {
- merge(options, args[1]);
- cmdArgs = args[0];
- }
- else {
- if (isArray(args[0]))
- cmdArgs = args[0];
- else
- merge(options, args[0]);
- }
-
- if ('gid' in options)
- console.warn('`gid` option is not yet supported for `child_process`');
- if ('uid' in options)
- console.warn('`uid` option is not yet supported for `child_process`');
- if ('detached' in options)
- console.warn('`detached` option is not yet supported for `child_process`');
-
- options.file = file;
- options.cmdArgs = cmdArgs;
-
- return Child(options);
-}
-
-exports.spawn = spawn;
-
-/**
- * exec(command, options, callback)
- */
-function exec (cmd, ...args) {
- let file, cmdArgs, callback, options = {};
-
- if (isFunction(args[0]))
- callback = args[0];
- else {
- merge(options, args[0]);
- callback = args[1];
- }
-
- if (isWindows) {
- file = 'C:\\Windows\\System32\\cmd.exe';
- cmdArgs = ['/S/C', cmd || ''];
- }
- else {
- file = '/bin/sh';
- cmdArgs = ['-c', cmd];
- }
-
- // Undocumented option from node being able to specify shell
- if (options && options.shell)
- file = options.shell;
-
- return execFile(file, cmdArgs, options, callback);
-}
-exports.exec = exec;
-/**
- * execFile (file, args, options, callback)
- */
-function execFile (file, ...args) {
- let cmdArgs = [], callback;
- // Default options
- let options = {
- cwd: null,
- env: null,
- encoding: 'utf8',
- timeout: 0,
- maxBuffer: 204800, //200 KB (200*1024 bytes)
- killSignal: 'SIGTERM'
- };
-
- if (isFunction(args[args.length - 1]))
- callback = args[args.length - 1];
-
- if (isArray(args[0])) {
- cmdArgs = args[0];
- merge(options, args[1]);
- } else if (!isFunction(args[0]))
- merge(options, args[0]);
-
- let child = spawn(file, cmdArgs, options);
- let exited = false;
- let stdout = '';
- let stderr = '';
- let error = null;
- let timeoutId = null;
-
- child.stdout.setEncoding(options.encoding);
- child.stderr.setEncoding(options.encoding);
-
- on(child.stdout, 'data', pumpStdout);
- on(child.stderr, 'data', pumpStderr);
- on(child, 'close', exitHandler);
- on(child, 'error', errorHandler);
-
- if (options.timeout > 0) {
- setTimeout(() => {
- kill();
- timeoutId = null;
- }, options.timeout);
- }
-
- function exitHandler (code, signal) {
-
- // Return if exitHandler called previously, occurs
- // when multiple maxBuffer errors thrown and attempt to kill multiple
- // times
- if (exited) return;
- exited = true;
-
- if (!isFunction(callback)) return;
-
- if (timeoutId) {
- clearTimeout(timeoutId);
- timeoutId = null;
- }
-
- if (!error && (code !== 0 || signal !== null))
- error = createProcessError(new Error('Command failed: ' + stderr), {
- code: code,
- signal: signal,
- killed: !!child.killed
- });
-
- callback(error, stdout, stderr);
-
- off(child.stdout, 'data', pumpStdout);
- off(child.stderr, 'data', pumpStderr);
- off(child, 'close', exitHandler);
- off(child, 'error', errorHandler);
- }
-
- function errorHandler (e) {
- error = e;
- exitHandler();
- }
-
- function kill () {
- try {
- child.kill(options.killSignal);
- } catch (e) {
- // In the scenario where the kill signal happens when
- // the process is already closing, just abort the kill fail
- if (/library is not open/.test(e))
- return;
- error = e;
- exitHandler(-1, options.killSignal);
- }
- }
-
- function pumpStdout (data) {
- stdout += data;
- if (stdout.length > options.maxBuffer) {
- error = new Error('stdout maxBuffer exceeded');
- kill();
- }
- }
-
- function pumpStderr (data) {
- stderr += data;
- if (stderr.length > options.maxBuffer) {
- error = new Error('stderr maxBuffer exceeded');
- kill();
- }
- }
-
- return child;
-}
-exports.execFile = execFile;
-
-exports.fork = function fork () {
- throw new Error("child_process#fork is not currently supported");
-};
-
-function serializeEnv (obj) {
- return Object.keys(obj || {}).map(prop => prop + '=' + obj[prop]);
-}
-
-function createProcessError (err, options = {}) {
- // If code and signal look OK, this was probably a failure
- // attempting to spawn the process (like ENOENT in node) -- use
- // the code from the error message
- if (!options.code && !options.signal) {
- let match = err.message.match(/(NS_ERROR_\w*)/);
- if (match && match.length > 1)
- err.code = match[1];
- else {
- // If no good error message found, use the passed in exit code;
- // this occurs when killing a process that's already closing,
- // where we want both a valid exit code (0) and the error
- err.code = options.code != null ? options.code : null;
- }
- }
- else
- err.code = options.code != null ? options.code : null;
- err.signal = options.signal || null;
- err.killed = options.killed || false;
- return err;
-}
diff --git a/addon-sdk/source/lib/sdk/system/child_process/subprocess.js b/addon-sdk/source/lib/sdk/system/child_process/subprocess.js
deleted file mode 100644
index e3454e95b..000000000
--- a/addon-sdk/source/lib/sdk/system/child_process/subprocess.js
+++ /dev/null
@@ -1,186 +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, Cu } = require("chrome");
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Subprocess.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-
-const Runtime = require("sdk/system/runtime");
-const Environment = require("sdk/system/environment").env;
-const DEFAULT_ENVIRONMENT = [];
-if (Runtime.OS == "Linux" && "DISPLAY" in Environment) {
- DEFAULT_ENVIRONMENT.push("DISPLAY=" + Environment.DISPLAY);
-}
-
-function awaitPromise(promise) {
- let value;
- let resolved = null;
- promise.then(val => {
- resolved = true;
- value = val;
- }, val => {
- resolved = false;
- value = val;
- });
-
- while (resolved === null)
- Services.tm.mainThread.processNextEvent(true);
-
- if (resolved === true)
- return value;
- throw value;
-}
-
-let readAllData = Task.async(function* (pipe, read, callback) {
- let string;
- while (string = yield read(pipe))
- callback(string);
-});
-
-let write = (pipe, data) => {
- let buffer = new Uint8Array(Array.from(data, c => c.charCodeAt(0)));
- return pipe.write(data);
-};
-
-var subprocess = {
- call: function(options) {
- var result;
-
- let procPromise = Task.spawn(function*() {
- let opts = {};
-
- if (options.mergeStderr) {
- opts.stderr = "stdout"
- } else if (options.stderr) {
- opts.stderr = "pipe";
- }
-
- if (options.command instanceof Ci.nsIFile) {
- opts.command = options.command.path;
- } else {
- opts.command = yield Subprocess.pathSearch(options.command);
- }
-
- if (options.workdir) {
- opts.workdir = options.workdir;
- }
-
- opts.arguments = options.arguments || [];
-
-
- // Set up environment
-
- let envVars = options.environment || DEFAULT_ENVIRONMENT;
- if (envVars.length) {
- let environment = {};
- for (let val of envVars) {
- let idx = val.indexOf("=");
- if (idx >= 0)
- environment[val.slice(0, idx)] = val.slice(idx + 1);
- }
-
- opts.environment = environment;
- }
-
-
- let proc = yield Subprocess.call(opts);
-
- Object.defineProperty(result, "pid", {
- value: proc.pid,
- enumerable: true,
- configurable: true,
- });
-
-
- let promises = [];
-
- // Set up IO handlers.
-
- let read = pipe => pipe.readString();
- if (options.charset === null) {
- read = pipe => {
- return pipe.read().then(buffer => {
- return String.fromCharCode(...buffer);
- });
- };
- }
-
- if (options.stdout)
- promises.push(readAllData(proc.stdout, read, options.stdout));
-
- if (options.stderr && proc.stderr)
- promises.push(readAllData(proc.stderr, read, options.stderr));
-
- // Process stdin
-
- if (typeof options.stdin === "string") {
- write(proc.stdin, options.stdin);
- proc.stdin.close();
- }
-
-
- // Handle process completion
-
- if (options.done)
- Promise.all(promises)
- .then(() => proc.wait())
- .then(options.done);
-
- return proc;
- });
-
- procPromise.catch(e => {
- if (options.done)
- options.done({exitCode: -1}, e);
- else
- Cu.reportError(e instanceof Error ? e : e.message || e);
- });
-
- if (typeof options.stdin === "function") {
- // Unfortunately, some callers (child_process.js) depend on this
- // being called synchronously.
- options.stdin({
- write(val) {
- procPromise.then(proc => {
- write(proc.stdin, val);
- });
- },
-
- close() {
- procPromise.then(proc => {
- proc.stdin.close();
- });
- },
- });
- }
-
- result = {
- get pid() {
- return awaitPromise(procPromise.then(proc => {
- return proc.pid;
- }));
- },
-
- wait() {
- return awaitPromise(procPromise.then(proc => {
- return proc.wait().then(({exitCode}) => exitCode);
- }));
- },
-
- kill(hard = false) {
- procPromise.then(proc => {
- proc.kill(hard ? 0 : undefined);
- });
- },
- };
-
- return result;
- },
-};
-
-module.exports = subprocess;
diff --git a/addon-sdk/source/lib/sdk/system/environment.js b/addon-sdk/source/lib/sdk/system/environment.js
deleted file mode 100644
index 13621a696..000000000
--- a/addon-sdk/source/lib/sdk/system/environment.js
+++ /dev/null
@@ -1,33 +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 { Cc, Ci } = require('chrome');
-const { get, set, exists } = Cc['@mozilla.org/process/environment;1'].
- getService(Ci.nsIEnvironment);
-
-exports.env = new Proxy({}, {
- deleteProperty(target, property) {
- set(property, null);
- return true;
- },
-
- get(target, property, receiver) {
- return get(property) || undefined;
- },
-
- has(target, property) {
- return exists(property);
- },
-
- set(target, property, value, receiver) {
- set(property, value);
- return true;
- }
-});
diff --git a/addon-sdk/source/lib/sdk/system/events-shimmed.js b/addon-sdk/source/lib/sdk/system/events-shimmed.js
deleted file mode 100644
index 14496f1f0..000000000
--- a/addon-sdk/source/lib/sdk/system/events-shimmed.js
+++ /dev/null
@@ -1,16 +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 events = require('./events.js');
-
-exports.emit = (type, event) => events.emit(type, event, true);
-exports.on = (type, listener, strong) => events.on(type, listener, strong, true);
-exports.once = (type, listener) => events.once(type, listener, true);
-exports.off = (type, listener) => events.off(type, listener, true);
diff --git a/addon-sdk/source/lib/sdk/system/events.js b/addon-sdk/source/lib/sdk/system/events.js
deleted file mode 100644
index 0cf525aa1..000000000
--- a/addon-sdk/source/lib/sdk/system/events.js
+++ /dev/null
@@ -1,181 +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 { Cc, Ci, Cu } = require('chrome');
-const { Unknown } = require('../platform/xpcom');
-const { Class } = require('../core/heritage');
-const { ns } = require('../core/namespace');
-const observerService =
- Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
-const { addObserver, removeObserver, notifyObservers } = observerService;
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const addObserverNoShim = ShimWaiver.getProperty(observerService, "addObserver");
-const removeObserverNoShim = ShimWaiver.getProperty(observerService, "removeObserver");
-const notifyObserversNoShim = ShimWaiver.getProperty(observerService, "notifyObservers");
-const unloadSubject = require('@loader/unload');
-
-const Subject = Class({
- extends: Unknown,
- initialize: function initialize(object) {
- // Double-wrap the object and set a property identifying the
- // wrappedJSObject as one of our wrappers to distinguish between
- // subjects that are one of our wrappers (which we should unwrap
- // when notifying our observers) and those that are real JS XPCOM
- // components (which we should pass through unaltered).
- this.wrappedJSObject = {
- observersModuleSubjectWrapper: true,
- object: object
- };
- },
- getScriptableHelper: function() {},
- getInterfaces: function() {}
-});
-
-function emit(type, event, shimmed = false) {
- // From bug 910599
- // We must test to see if 'subject' or 'data' is a defined property
- // of the event object, but also allow primitives to be passed in,
- // which the `in` operator breaks, yet `null` is an object, hence
- // the long conditional
- let subject = event && typeof event === 'object' && 'subject' in event ?
- Subject(event.subject) :
- null;
- let data = event && typeof event === 'object' ?
- // An object either returns its `data` property or null
- ('data' in event ? event.data : null) :
- // All other types return themselves (and cast to strings/null
- // via observer service)
- event;
- if (shimmed) {
- notifyObservers(subject, type, data);
- } else {
- notifyObserversNoShim(subject, type, data);
- }
-}
-exports.emit = emit;
-
-const Observer = Class({
- extends: Unknown,
- initialize: function initialize(listener) {
- this.listener = listener;
- },
- interfaces: [ 'nsIObserver', 'nsISupportsWeakReference' ],
- observe: function(subject, topic, data) {
- // Extract the wrapped object for subjects that are one of our
- // wrappers around a JS object. This way we support both wrapped
- // subjects created using this module and those that are real
- // XPCOM components.
- if (subject && typeof(subject) == 'object' &&
- ('wrappedJSObject' in subject) &&
- ('observersModuleSubjectWrapper' in subject.wrappedJSObject))
- subject = subject.wrappedJSObject.object;
-
- try {
- this.listener({
- type: topic,
- subject: subject,
- data: data
- });
- }
- catch (error) {
- console.exception(error);
- }
- }
-});
-
-const subscribers = ns();
-
-function on(type, listener, strong, shimmed = false) {
- // Unless last optional argument is `true` we use a weak reference to a
- // listener.
- let weak = !strong;
- // Take list of observers associated with given `listener` function.
- let observers = subscribers(listener);
- // If `observer` for the given `type` is not registered yet, then
- // associate an `observer` and register it.
- if (!(type in observers)) {
- let observer = Observer(listener);
- observers[type] = observer;
- if (shimmed) {
- addObserver(observer, type, weak);
- } else {
- addObserverNoShim(observer, type, weak);
- }
- // WeakRef gymnastics to remove all alive observers on unload
- let ref = Cu.getWeakReference(observer);
- weakRefs.set(observer, ref);
- stillAlive.set(ref, type);
- wasShimmed.set(ref, shimmed);
- }
-}
-exports.on = on;
-
-function once(type, listener, shimmed = false) {
- // Note: this code assumes order in which listeners are called, which is fine
- // as long as dispatch happens in same order as listener registration which
- // is the case now. That being said we should be aware that this may break
- // in a future if order will change.
- on(type, listener, shimmed);
- on(type, function cleanup() {
- off(type, listener, shimmed);
- off(type, cleanup, shimmed);
- }, true, shimmed);
-}
-exports.once = once;
-
-function off(type, listener, shimmed = false) {
- // Take list of observers as with the given `listener`.
- let observers = subscribers(listener);
- // If `observer` for the given `type` is registered, then
- // remove it & unregister.
- if (type in observers) {
- let observer = observers[type];
- delete observers[type];
- if (shimmed) {
- removeObserver(observer, type);
- } else {
- removeObserverNoShim(observer, type);
- }
- stillAlive.delete(weakRefs.get(observer));
- wasShimmed.delete(weakRefs.get(observer));
- }
-}
-exports.off = off;
-
-// must use WeakMap to keep reference to all the WeakRefs (!), see bug 986115
-var weakRefs = new WeakMap();
-
-// and we're out of beta, we're releasing on time!
-var stillAlive = new Map();
-
-var wasShimmed = new Map();
-
-on('sdk:loader:destroy', function onunload({ subject, data: reason }) {
- // using logic from ./unload, to avoid a circular module reference
- if (subject.wrappedJSObject === unloadSubject) {
- off('sdk:loader:destroy', onunload, false);
-
- // don't bother
- if (reason === 'shutdown')
- return;
-
- stillAlive.forEach( (type, ref) => {
- let observer = ref.get();
- if (observer) {
- if (wasShimmed.get(ref)) {
- removeObserver(observer, type);
- } else {
- removeObserverNoShim(observer, type);
- }
- }
- })
- }
- // a strong reference
-}, true, false);
diff --git a/addon-sdk/source/lib/sdk/system/globals.js b/addon-sdk/source/lib/sdk/system/globals.js
deleted file mode 100644
index a1a6cf9a2..000000000
--- a/addon-sdk/source/lib/sdk/system/globals.js
+++ /dev/null
@@ -1,46 +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"
-};
-
-var { Cc, Ci, CC } = require('chrome');
-var { PlainTextConsole } = require('../console/plain-text');
-var { stdout } = require('../system');
-var ScriptError = CC('@mozilla.org/scripterror;1', 'nsIScriptError');
-var consoleService = Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService);
-
-// On windows dump does not writes into stdout so cfx can't read thous dumps.
-// To workaround this issue we write to a special file from which cfx will
-// read and print to the console.
-// For more details see: bug-673383
-exports.dump = stdout.write;
-
-exports.console = new PlainTextConsole();
-
-// Provide CommonJS `define` to allow authoring modules in a format that can be
-// loaded both into jetpack and into browser via AMD loaders.
-Object.defineProperty(exports, 'define', {
- // `define` is provided as a lazy getter that binds below defined `define`
- // function to the module scope, so that require, exports and module
- // variables remain accessible.
- configurable: true,
- get: function() {
- let sandbox = this;
- return function define(factory) {
- factory = Array.slice(arguments).pop();
- factory.call(sandbox, sandbox.require, sandbox.exports, sandbox.module);
- }
- },
- set: function(value) {
- Object.defineProperty(this, 'define', {
- configurable: true,
- enumerable: true,
- value,
- });
- },
-});
diff --git a/addon-sdk/source/lib/sdk/system/process.js b/addon-sdk/source/lib/sdk/system/process.js
deleted file mode 100644
index f44a36658..000000000
--- a/addon-sdk/source/lib/sdk/system/process.js
+++ /dev/null
@@ -1,62 +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 {
- exit, version, stdout, stderr, platform, architecture
-} = require("../system");
-
-/**
- * Supported
- */
-
-exports.stdout = stdout;
-exports.stderr = stderr;
-exports.version = version;
-exports.versions = {};
-exports.config = {};
-exports.arch = architecture;
-exports.platform = platform;
-exports.exit = exit;
-
-/**
- * Partial support
- */
-
-// An alias to `setTimeout(fn, 0)`, which isn't the same as node's `nextTick`,
-// but atleast ensures it'll occur asynchronously
-exports.nextTick = (callback) => setTimeout(callback, 0);
-
-/**
- * Unsupported
- */
-
-exports.maxTickDepth = 1000;
-exports.pid = 0;
-exports.title = "";
-exports.stdin = {};
-exports.argv = [];
-exports.execPath = "";
-exports.execArgv = [];
-exports.abort = function () {};
-exports.chdir = function () {};
-exports.cwd = function () {};
-exports.env = {};
-exports.getgid = function () {};
-exports.setgid = function () {};
-exports.getuid = function () {};
-exports.setuid = function () {};
-exports.getgroups = function () {};
-exports.setgroups = function () {};
-exports.initgroups = function () {};
-exports.kill = function () {};
-exports.memoryUsage = function () {};
-exports.umask = function () {};
-exports.uptime = function () {};
-exports.hrtime = function () {};
diff --git a/addon-sdk/source/lib/sdk/system/runtime.js b/addon-sdk/source/lib/sdk/system/runtime.js
deleted file mode 100644
index 9a70f142d..000000000
--- a/addon-sdk/source/lib/sdk/system/runtime.js
+++ /dev/null
@@ -1,28 +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 { Cc, Ci } = require("chrome");
-const runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
-
-exports.inSafeMode = runtime.inSafeMode;
-exports.OS = runtime.OS;
-exports.processType = runtime.processType;
-exports.widgetToolkit = runtime.widgetToolkit;
-exports.processID = runtime.processID;
-
-// Attempt to access `XPCOMABI` may throw exception, in which case exported
-// `XPCOMABI` will be set to `null`.
-// https://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#732
-try {
- exports.XPCOMABI = runtime.XPCOMABI;
-}
-catch (error) {
- exports.XPCOMABI = null;
-}
diff --git a/addon-sdk/source/lib/sdk/system/unload.js b/addon-sdk/source/lib/sdk/system/unload.js
deleted file mode 100644
index 98ab5f8f3..000000000
--- a/addon-sdk/source/lib/sdk/system/unload.js
+++ /dev/null
@@ -1,104 +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/. */
-
-// Parts of this module were taken from narwhal:
-//
-// http://narwhaljs.org
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const { Cu } = require('chrome');
-const { on, off } = require('./events');
-const unloadSubject = require('@loader/unload');
-
-const observers = [];
-const unloaders = [];
-
-function WeakObserver(inner) {
- this._inner = Cu.getWeakReference(inner);
-}
-
-Object.defineProperty(WeakObserver.prototype, 'value', {
- get: function() { this._inner.get() }
-});
-
-var when = exports.when = function when(observer, opts) {
- opts = opts || {};
- for (var i = 0; i < observers.length; ++i) {
- if (observers[i] === observer || observers[i].value === observer) {
- return;
- }
- }
- if (opts.weak) {
- observers.unshift(new WeakObserver(observer));
- } else {
- observers.unshift(observer);
- }
-};
-
-var ensure = exports.ensure = function ensure(obj, destructorName) {
- if (!destructorName)
- destructorName = "unload";
- if (!(destructorName in obj))
- throw new Error("object has no '" + destructorName + "' property");
-
- let called = false;
- let originalDestructor = obj[destructorName];
-
- function unloadWrapper(reason) {
- if (!called) {
- called = true;
- let index = unloaders.indexOf(unloadWrapper);
- if (index == -1)
- throw new Error("internal error: unloader not found");
- unloaders.splice(index, 1);
- originalDestructor.call(obj, reason);
- originalDestructor = null;
- destructorName = null;
- obj = null;
- }
- };
-
- // TODO: Find out why the order is inverted here. It seems that
- // it may be causing issues!
- unloaders.push(unloadWrapper);
-
- obj[destructorName] = unloadWrapper;
-};
-
-function unload(reason) {
- observers.forEach(function(observer) {
- try {
- if (observer instanceof WeakObserver) {
- observer = observer.value;
- }
- if (typeof observer === 'function') {
- observer(reason);
- }
- }
- catch (error) {
- console.exception(error);
- }
- });
-}
-
-when(function(reason) {
- unloaders.slice().forEach(function(unloadWrapper) {
- unloadWrapper(reason);
- });
-});
-
-on('sdk:loader:destroy', function onunload({ subject, data: reason }) {
- // If this loader is unload then `subject.wrappedJSObject` will be
- // `destructor`.
- if (subject.wrappedJSObject === unloadSubject) {
- off('sdk:loader:destroy', onunload);
- unload(reason);
- }
-// Note that we use strong reference to listener here to make sure it's not
-// GC-ed, which may happen otherwise since nothing keeps reference to `onunolad`
-// function.
-}, true);
diff --git a/addon-sdk/source/lib/sdk/system/xul-app.js b/addon-sdk/source/lib/sdk/system/xul-app.js
deleted file mode 100644
index 612386f77..000000000
--- a/addon-sdk/source/lib/sdk/system/xul-app.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 { XulApp } = require("./xul-app.jsm");
-
-Object.keys(XulApp).forEach(k => exports[k] = XulApp[k]);
diff --git a/addon-sdk/source/lib/sdk/system/xul-app.jsm b/addon-sdk/source/lib/sdk/system/xul-app.jsm
deleted file mode 100644
index 90681bb1b..000000000
--- a/addon-sdk/source/lib/sdk/system/xul-app.jsm
+++ /dev/null
@@ -1,242 +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.EXPORTED_SYMBOLS = [ "XulApp" ];
-
-var { classes: Cc, interfaces: Ci } = Components;
-
-var exports = {};
-this.XulApp = exports;
-
-var appInfo;
-
-// NOTE: below is required to avoid failing xpcshell tests,
-// which do not implement nsIXULAppInfo
-// See Bug 1114752 https://bugzilla.mozilla.org/show_bug.cgi?id=1114752
-try {
- appInfo = Cc["@mozilla.org/xre/app-info;1"]
- .getService(Ci.nsIXULAppInfo);
-}
-catch (e) {
- // xpcshell test case
- appInfo = {};
-}
-var vc = Cc["@mozilla.org/xpcom/version-comparator;1"]
- .getService(Ci.nsIVersionComparator);
-
-var ID = exports.ID = appInfo.ID;
-var name = exports.name = appInfo.name;
-var version = exports.version = appInfo.version;
-var platformVersion = exports.platformVersion = appInfo.platformVersion;
-
-// The following mapping of application names to GUIDs was taken from:
-//
-// https://addons.mozilla.org/en-US/firefox/pages/appversions
-//
-// Using the GUID instead of the app's name is preferable because sometimes
-// re-branded versions of a product have different names: for instance,
-// Firefox, Minefield, Iceweasel, and Shiretoko all have the same
-// GUID.
-
-var ids = exports.ids = {
- Firefox: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
- Mozilla: "{86c18b42-e466-45a9-ae7a-9b95ba6f5640}",
- SeaMonkey: "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}",
- Fennec: "{aa3c5121-dab2-40e2-81ca-7ea25febc110}",
- Thunderbird: "{3550f703-e582-4d05-9a08-453d09bdfdc6}",
- Instantbird: "{33cb9019-c295-46dd-be21-8c4936574bee}"
-};
-
-function is(name) {
- if (!(name in ids))
- throw new Error("Unkown Mozilla Application: " + name);
- return ID == ids[name];
-};
-exports.is = is;
-
-function isOneOf(names) {
- for (var i = 0; i < names.length; i++)
- if (is(names[i]))
- return true;
- return false;
-};
-exports.isOneOf = isOneOf;
-
-/**
- * Use this to check whether the given version (e.g. xulApp.platformVersion)
- * is in the given range. Versions must be in version comparator-compatible
- * format. See MDC for details:
- * https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIVersionComparator
- */
-var versionInRange = exports.versionInRange =
-function versionInRange(version, lowInclusive, highExclusive) {
- return (vc.compare(version, lowInclusive) >= 0) &&
- (vc.compare(version, highExclusive) < 0);
-}
-
-const reVersionRange = /^((?:<|>)?=?)?\s*((?:\d+[\S]*)|\*)(?:\s+((?:<|>)=?)?(\d+[\S]+))?$/;
-const reOnlyInifinity = /^[<>]?=?\s*[*x]$/;
-const reSubInfinity = /\.[*x]/g;
-const reHyphenRange = /^(\d+.*?)\s*-\s*(\d+.*?)$/;
-const reRangeSeparator = /\s*\|\|\s*/;
-
-const compares = {
- "=": function (c) { return c === 0 },
- ">=": function (c) { return c >= 0 },
- "<=": function (c) { return c <= 0},
- "<": function (c) { return c < 0 },
- ">": function (c) { return c > 0 }
-}
-
-function normalizeRange(range) {
- return range
- .replace(reOnlyInifinity, "")
- .replace(reSubInfinity, ".*")
- .replace(reHyphenRange, ">=$1 <=$2")
-}
-
-/**
- * Compare the versions given, using the comparison operator provided.
- * Internal use only.
- *
- * @example
- * compareVersion("1.2", "<=", "1.*") // true
- *
- * @param {String} version
- * A version to compare
- *
- * @param {String} comparison
- * The comparison operator
- *
- * @param {String} compareVersion
- * A version to compare
- */
-function compareVersion(version, comparison, compareVersion) {
- let hasWildcard = compareVersion.indexOf("*") !== -1;
-
- comparison = comparison || "=";
-
- if (hasWildcard) {
- switch (comparison) {
- case "=":
- let zeroVersion = compareVersion.replace(reSubInfinity, ".0");
- return versionInRange(version, zeroVersion, compareVersion);
- case ">=":
- compareVersion = compareVersion.replace(reSubInfinity, ".0");
- break;
- }
- }
-
- let compare = compares[comparison];
-
- return typeof compare === "function" && compare(vc.compare(version, compareVersion));
-}
-
-/**
- * Returns `true` if `version` satisfies the `versionRange` given.
- * If only an argument is passed, is used as `versionRange` and compared against
- * `xulApp.platformVersion`.
- *
- * `versionRange` is either a string which has one or more space-separated
- * descriptors, or a range like "fromVersion - toVersion".
- * Version range descriptors may be any of the following styles:
- *
- * - "version" Must match `version` exactly
- * - "=version" Same as just `version`
- * - ">version" Must be greater than `version`
- * - ">=version" Must be greater or equal than `version`
- * - "<version" Must be less than `version`
- * - "<=version" Must be less or equal than `version`
- * - "1.2.x" or "1.2.*" See 'X version ranges' below
- * - "*" or "" (just an empty string) Matches any version
- * - "version1 - version2" Same as ">=version1 <=version2"
- * - "range1 || range2" Passes if either `range1` or `range2` are satisfied
- *
- * For example, these are all valid:
- * - "1.0.0 - 2.9999.9999"
- * - ">=1.0.2 <2.1.2"
- * - ">1.0.2 <=2.3.4"
- * - "2.0.1"
- * - "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
- * - "2.x" (equivalent to "2.*")
- * - "1.2.x" (equivalent to "1.2.*" and ">=1.2.0 <1.3.0")
- */
-function satisfiesVersion(version, versionRange) {
- if (arguments.length === 1) {
- versionRange = version;
- version = appInfo.version;
- }
-
- let ranges = versionRange.trim().split(reRangeSeparator);
-
- return ranges.some(function(range) {
- range = normalizeRange(range);
-
- // No versions' range specified means that any version satisfies the
- // requirements.
- if (range === "")
- return true;
-
- let matches = range.match(reVersionRange);
-
- if (!matches)
- return false;
-
- let [, lowMod, lowVer, highMod, highVer] = matches;
-
- return compareVersion(version, lowMod, lowVer) && (highVer !== undefined
- ? compareVersion(version, highMod, highVer)
- : true);
- });
-}
-exports.satisfiesVersion = satisfiesVersion;
-
-/**
- * Ensure the current application satisfied the requirements specified in the
- * module given. If not, an exception related to the incompatibility is
- * returned; `null` otherwise.
- *
- * @param {Object} module
- * The module to check
- * @returns {Error}
- */
-function incompatibility(module) {
- let { metadata, id } = module;
-
- // if metadata or engines are not specified we assume compatibility is not
- // an issue.
- if (!metadata || !("engines" in metadata))
- return null;
-
- let { engines } = metadata;
-
- if (engines === null || typeof(engines) !== "object")
- return new Error("Malformed engines' property in metadata");
-
- let applications = Object.keys(engines);
-
- let versionRange;
- applications.forEach(function(name) {
- if (is(name)) {
- versionRange = engines[name];
- // Continue iteration. We want to ensure the module doesn't
- // contain a typo in the applications' name or some unknown
- // application - `is` function throws an exception in that case.
- }
- });
-
- if (typeof(versionRange) === "string") {
- if (satisfiesVersion(versionRange))
- return null;
-
- return new Error("Unsupported Application version: The module " + id +
- " currently supports only version " + versionRange + " of " +
- name + ".");
- }
-
- return new Error("Unsupported Application: The module " + id +
- " currently supports only " + applications.join(", ") + ".")
-}
-exports.incompatibility = incompatibility;
diff --git a/addon-sdk/source/lib/sdk/tab/events.js b/addon-sdk/source/lib/sdk/tab/events.js
deleted file mode 100644
index e431cc9d2..000000000
--- 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.ownerDocument.defaultView.BrowserApp
- .getTabForBrowser(event.target)
- };
-});
diff --git a/addon-sdk/source/lib/sdk/tabs.js b/addon-sdk/source/lib/sdk/tabs.js
deleted file mode 100644
index f61cad478..000000000
--- 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;
diff --git a/addon-sdk/source/lib/sdk/tabs/common.js b/addon-sdk/source/lib/sdk/tabs/common.js
deleted file mode 100644
index 9ee512a7b..000000000
--- 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;
diff --git a/addon-sdk/source/lib/sdk/tabs/events.js b/addon-sdk/source/lib/sdk/tabs/events.js
deleted file mode 100644
index 65650f9dc..000000000
--- 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);
-}
diff --git a/addon-sdk/source/lib/sdk/tabs/helpers.js b/addon-sdk/source/lib/sdk/tabs/helpers.js
deleted file mode 100644
index b2c8aa013..000000000
--- 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
-
-
-const { getTabForBrowser: getRawTabForBrowser } = require('./utils');
-const { modelFor } = require('../model/core');
-
-exports.getTabForRawTab = modelFor;
-
-function getTabForBrowser(browser) {
- return modelFor(getRawTabForBrowser(browser)) || null;
-}
-exports.getTabForBrowser = getTabForBrowser;
diff --git a/addon-sdk/source/lib/sdk/tabs/namespace.js b/addon-sdk/source/lib/sdk/tabs/namespace.js
deleted file mode 100644
index 3553b1a99..000000000
--- 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();
diff --git a/addon-sdk/source/lib/sdk/tabs/observer.js b/addon-sdk/source/lib/sdk/tabs/observer.js
deleted file mode 100644
index 4e935cd62..000000000
--- 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();
diff --git a/addon-sdk/source/lib/sdk/tabs/tab-fennec.js b/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
deleted file mode 100644
index 3927337f6..000000000
--- 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, false);
-
- // TabPageShow
- let onPageShow = tabInternals.onPageShow = onTabPageShow.bind(this);
- tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow, false);
-
- // 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, false);
-
- 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, false);
- tabInternals.tab.browser.removeEventListener(EVENTS.pageshow.dom, tabInternals.onPageShow, false);
- 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, false);
- 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;
-});
diff --git a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js b/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
deleted file mode 100644
index f1da92379..000000000
--- 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).ownerDocument.defaultView);
- });
- },
-
- 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.ownerDocument.defaultView;
- 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.ownerDocument.defaultView);
- 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.ownerDocument.defaultView;
-
- 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);
-});
diff --git a/addon-sdk/source/lib/sdk/tabs/tab.js b/addon-sdk/source/lib/sdk/tabs/tab.js
deleted file mode 100644
index fa2272494..000000000
--- 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");
-const { getTabContentWindow, isTab } = require("./utils");
-const { viewFor } = require("../view/core");
-
-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)));
diff --git a/addon-sdk/source/lib/sdk/tabs/tabs-firefox.js b/addon-sdk/source/lib/sdk/tabs/tabs-firefox.js
deleted file mode 100644
index 1eefecb4c..000000000
--- a/addon-sdk/source/lib/sdk/tabs/tabs-firefox.js
+++ /dev/null
@@ -1,135 +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');
-const { emit, setListeners } = require('../event/core');
-const { pipe } = require('../event/utils');
-const { observer: windowObserver } = require('../windows/observer');
-const { List, addListItem, removeListItem } = require('../util/list');
-const { modelFor } = require('../model/core');
-const { viewFor } = require('../view/core');
-const { getTabs, getSelectedTab } = require('./utils');
-const { getMostRecentBrowserWindow, isBrowser } = require('../window/utils');
-const { Options } = require('./common');
-const { isPrivate } = require('../private-browsing');
-const { ignoreWindow, isWindowPBSupported } = require('../private-browsing/utils')
-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();
-// Export a new object with allTabs as the prototype, otherwise allTabs becomes
-// frozen and addListItem and removeListItem don't work correctly.
-module.exports = Object.create(allTabs);
-pipe(tabEvents, module.exports);
-
-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);
- }
-});
diff --git a/addon-sdk/source/lib/sdk/tabs/utils.js b/addon-sdk/source/lib/sdk/tabs/utils.js
deleted file mode 100644
index eae3d41fe..000000000
--- 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');
-const { defer } = require("../lang/functional");
-const { windows, isBrowser } = require('../window/utils');
-const { isPrivateBrowsingSupported } = require('../self');
-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.ownerDocument.defaultView;
-
- // 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.split(tab.linkedPanel, '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;
diff --git a/addon-sdk/source/lib/sdk/tabs/worker.js b/addon-sdk/source/lib/sdk/tabs/worker.js
deleted file mode 100644
index d2ba33696..000000000
--- 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
diff --git a/addon-sdk/source/lib/sdk/test.js b/addon-sdk/source/lib/sdk/test.js
deleted file mode 100644
index e7e3df840..000000000
--- a/addon-sdk/source/lib/sdk/test.js
+++ /dev/null
@@ -1,114 +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 { Cu } = require("chrome");
-const { Task } = require("resource://gre/modules/Task.jsm", {});
-const { defer } = require("sdk/core/promise");
-const BaseAssert = require("sdk/test/assert").Assert;
-const { isFunction, isObject, isGenerator } = require("sdk/lang/type");
-const { extend } = require("sdk/util/object");
-
-exports.Assert = BaseAssert;
-
-/**
- * Function takes test `suite` object in CommonJS format and defines all of the
- * tests from that suite and nested suites in a jetpack format on a given
- * `target` object. Optionally third argument `prefix` can be passed to prefix
- * all the test names.
- */
-function defineTestSuite(target, suite, prefix) {
- prefix = prefix || "";
- // If suite defines `Assert` that's what `assert` object have to be created
- // from and passed to a test function (This allows custom assertion functions)
- // See for details: http://wiki.commonjs.org/wiki/Unit_Testing/1.1
- let Assert = suite.Assert || BaseAssert;
- // Going through each item in the test suite and wrapping it into a
- // Jetpack test format.
- Object.keys(suite).forEach(function(key) {
- // If name starts with test then it's a test function or suite.
- if (key.indexOf("test") === 0) {
- let test = suite[key];
-
- // For each test function so we create a wrapper test function in a
- // jetpack format and copy that to a `target` exports.
- if (isFunction(test)) {
-
- // Since names of the test may match across suites we use full object
- // path as a name to avoid overriding same function.
- target[prefix + key] = function(options) {
-
- // Creating `assert` functions for this test.
- let assert = Assert(options);
- assert.end = () => options.done();
-
- // If test function is a generator use a task JS to allow yield-ing
- // style test runs.
- if (isGenerator(test)) {
- options.waitUntilDone();
- Task.spawn(test.bind(null, assert)).
- catch(assert.fail).
- then(assert.end);
- }
-
- // If CommonJS test function expects more than one argument
- // it means that test is async and second argument is a callback
- // to notify that test is finished.
- else if (1 < test.length) {
- // Letting test runner know that test is executed async and
- // creating a callback function that CommonJS tests will call
- // once it's done.
- options.waitUntilDone();
- test(assert, function() {
- options.done();
- });
- }
-
- // Otherwise CommonJS test is synchronous so we call it only with
- // one argument.
- else {
- test(assert);
- }
- }
- }
-
- // If it's an object then it's a test suite containing test function
- // and / or nested test suites. In that case we just extend prefix used
- // and call this function to copy and wrap tests from nested suite.
- else if (isObject(test)) {
- // We need to clone `tests` instead of modifying it, since it's very
- // likely that it is frozen (usually test suites imported modules).
- test = extend(Object.prototype, test, {
- Assert: test.Assert || Assert
- });
- defineTestSuite(target, test, prefix + key + ".");
- }
- }
- });
-}
-
-/**
- * This function is a CommonJS test runner function, but since Jetpack test
- * runner and test format is different from CommonJS this function shims given
- * `exports` with all its tests into a Jetpack test format so that the built-in
- * test runner will be able to run CommonJS test without manual changes.
- */
-exports.run = function run(exports) {
- // We can't leave old properties on exports since those are test in a CommonJS
- // format that why we move everything to a new `suite` object.
- let suite = {};
- Object.keys(exports).forEach(function(key) {
- suite[key] = exports[key];
- delete exports[key];
- });
-
- // Now we wrap all the CommonJS tests to a Jetpack format and define
- // those to a given `exports` object since that where jetpack test runner
- // will look for them.
- defineTestSuite(exports, suite);
-};
diff --git a/addon-sdk/source/lib/sdk/test/assert.js b/addon-sdk/source/lib/sdk/test/assert.js
deleted file mode 100644
index 8478c8414..000000000
--- a/addon-sdk/source/lib/sdk/test/assert.js
+++ /dev/null
@@ -1,366 +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 { isFunction, isNull, isObject, isString,
- isRegExp, isArray, isDate, isPrimitive,
- isUndefined, instanceOf, source } = require("../lang/type");
-
-/**
- * The `AssertionError` is defined in assert.
- * @extends Error
- * @example
- * new assert.AssertionError({
- * message: message,
- * actual: actual,
- * expected: expected
- * })
- */
-function AssertionError(options) {
- let assertionError = Object.create(AssertionError.prototype);
-
- if (isString(options))
- options = { message: options };
- if ("actual" in options)
- assertionError.actual = options.actual;
- if ("expected" in options)
- assertionError.expected = options.expected;
- if ("operator" in options)
- assertionError.operator = options.operator;
-
- assertionError.message = options.message;
- assertionError.stack = new Error().stack;
- return assertionError;
-}
-AssertionError.prototype = Object.create(Error.prototype, {
- constructor: { value: AssertionError },
- name: { value: "AssertionError", enumerable: true },
- toString: { value: function toString() {
- let value;
- if (this.message) {
- value = this.name + " : " + this.message;
- }
- else {
- value = [
- this.name + " : ",
- source(this.expected),
- this.operator,
- source(this.actual)
- ].join(" ");
- }
- return value;
- }}
-});
-exports.AssertionError = AssertionError;
-
-function Assert(logger) {
- let assert = Object.create(Assert.prototype, { _log: { value: logger }});
-
- assert.fail = assert.fail.bind(assert);
- assert.pass = assert.pass.bind(assert);
-
- return assert;
-}
-
-Assert.prototype = {
- fail: function fail(e) {
- if (!e || typeof(e) !== 'object') {
- this._log.fail(e);
- return;
- }
- let message = e.message;
- try {
- if ('operator' in e) {
- message += [
- " -",
- source(e.actual),
- e.operator,
- source(e.expected)
- ].join(" ");
- }
- }
- catch(e) {}
- this._log.fail(message);
- },
- pass: function pass(message) {
- this._log.pass(message);
- return true;
- },
- error: function error(e) {
- this._log.exception(e);
- },
- ok: function ok(value, message) {
- if (!!!value) {
- this.fail({
- actual: value,
- expected: true,
- message: message,
- operator: "=="
- });
- return false;
- }
-
- this.pass(message);
- return true;
- },
-
- /**
- * The equality assertion tests shallow, coercive equality with `==`.
- * @example
- * assert.equal(1, 1, "one is one");
- */
- equal: function equal(actual, expected, message) {
- if (actual == expected) {
- this.pass(message);
- return true;
- }
-
- this.fail({
- actual: actual,
- expected: expected,
- message: message,
- operator: "=="
- });
- return false;
- },
-
- /**
- * The non-equality assertion tests for whether two objects are not equal
- * with `!=`.
- * @example
- * assert.notEqual(1, 2, "one is not two");
- */
- notEqual: function notEqual(actual, expected, message) {
- if (actual != expected) {
- this.pass(message);
- return true;
- }
-
- this.fail({
- actual: actual,
- expected: expected,
- message: message,
- operator: "!=",
- });
- return false;
- },
-
- /**
- * The equivalence assertion tests a deep (with `===`) equality relation.
- * @example
- * assert.deepEqual({ a: "foo" }, { a: "foo" }, "equivalent objects")
- */
- deepEqual: function deepEqual(actual, expected, message) {
- if (isDeepEqual(actual, expected)) {
- this.pass(message);
- return true;
- }
-
- this.fail({
- actual: actual,
- expected: expected,
- message: message,
- operator: "deepEqual"
- });
- return false;
- },
-
- /**
- * The non-equivalence assertion tests for any deep (with `===`) inequality.
- * @example
- * assert.notDeepEqual({ a: "foo" }, Object.create({ a: "foo" }),
- * "object's inherit from different prototypes");
- */
- notDeepEqual: function notDeepEqual(actual, expected, message) {
- if (!isDeepEqual(actual, expected)) {
- this.pass(message);
- return true;
- }
-
- this.fail({
- actual: actual,
- expected: expected,
- message: message,
- operator: "notDeepEqual"
- });
- return false;
- },
-
- /**
- * The strict equality assertion tests strict equality, as determined by
- * `===`.
- * @example
- * assert.strictEqual(null, null, "`null` is `null`")
- */
- strictEqual: function strictEqual(actual, expected, message) {
- if (actual === expected) {
- this.pass(message);
- return true;
- }
-
- this.fail({
- actual: actual,
- expected: expected,
- message: message,
- operator: "==="
- });
- return false;
- },
-
- /**
- * The strict non-equality assertion tests for strict inequality, as
- * determined by `!==`.
- * @example
- * assert.notStrictEqual(null, undefined, "`null` is not `undefined`");
- */
- notStrictEqual: function notStrictEqual(actual, expected, message) {
- if (actual !== expected) {
- this.pass(message);
- return true;
- }
-
- this.fail({
- actual: actual,
- expected: expected,
- message: message,
- operator: "!=="
- });
- return false;
- },
-
- /**
- * The assertion whether or not given `block` throws an exception. If optional
- * `Error` argument is provided and it's type of function thrown error is
- * asserted to be an instance of it, if type of `Error` is string then message
- * of throw exception is asserted to contain it.
- * @param {Function} block
- * Function that is expected to throw.
- * @param {Error|RegExp} [Error]
- * Error constructor that is expected to be thrown or a string that
- * must be contained by a message of the thrown exception, or a RegExp
- * matching a message of the thrown exception.
- * @param {String} message
- * Description message
- *
- * @examples
- *
- * assert.throws(function block() {
- * doSomething(4)
- * }, "Object is expected", "Incorrect argument is passed");
- *
- * assert.throws(function block() {
- * Object.create(5)
- * }, TypeError, "TypeError is thrown");
- */
- throws: function throws(block, Error, message) {
- let threw = false;
- let exception = null;
-
- // If third argument is not provided and second argument is a string it
- // means that optional `Error` argument was not passed, so we shift
- // arguments.
- if (isString(Error) && isUndefined(message)) {
- message = Error;
- Error = undefined;
- }
-
- // Executing given `block`.
- try {
- block();
- }
- catch (e) {
- threw = true;
- exception = e;
- }
-
- // If exception was thrown and `Error` argument was not passed assert is
- // passed.
- if (threw && (isUndefined(Error) ||
- // If passed `Error` is RegExp using it's test method to
- // assert thrown exception message.
- (isRegExp(Error) && (Error.test(exception.message) || Error.test(exception.toString()))) ||
- // If passed `Error` is a constructor function testing if
- // thrown exception is an instance of it.
- (isFunction(Error) && instanceOf(exception, Error))))
- {
- this.pass(message);
- return true;
- }
-
- // Otherwise we report assertion failure.
- let failure = {
- message: message,
- operator: "matches"
- };
-
- if (exception) {
- failure.actual = exception.message || exception.toString();
- }
-
- if (Error) {
- failure.expected = Error.toString();
- }
-
- this.fail(failure);
- return false;
- }
-};
-exports.Assert = Assert;
-
-function isDeepEqual(actual, expected) {
- // 7.1. All identical values are equivalent, as determined by ===.
- if (actual === expected) {
- return true;
- }
-
- // 7.2. If the expected value is a Date object, the actual value is
- // equivalent if it is also a Date object that refers to the same time.
- else if (isDate(actual) && isDate(expected)) {
- return actual.getTime() === expected.getTime();
- }
-
- // XXX specification bug: this should be specified
- else if (isPrimitive(actual) || isPrimitive(expected)) {
- return expected === actual;
- }
-
- // 7.3. Other pairs that do not both pass typeof value == "object",
- // equivalence is determined by ==.
- else if (!isObject(actual) && !isObject(expected)) {
- return actual == expected;
- }
-
- // 7.4. For all other Object pairs, including Array objects, equivalence is
- // determined by having the same number of owned properties (as verified
- // with Object.prototype.hasOwnProperty.call), the same set of keys
- // (although not necessarily the same order), equivalent values for every
- // corresponding key, and an identical "prototype" property. Note: this
- // accounts for both named and indexed properties on Arrays.
- else {
- return actual.prototype === expected.prototype &&
- isEquivalent(actual, expected);
- }
-}
-
-function isEquivalent(a, b, stack) {
- let aKeys = Object.keys(a);
- let bKeys = Object.keys(b);
-
- return aKeys.length === bKeys.length &&
- isArrayEquivalent(aKeys.sort(), bKeys.sort()) &&
- aKeys.every(function(key) {
- return isDeepEqual(a[key], b[key], stack)
- });
-}
-
-function isArrayEquivalent(a, b, stack) {
- return isArray(a) && isArray(b) &&
- a.every(function(value, index) {
- return isDeepEqual(value, b[index]);
- });
-}
diff --git a/addon-sdk/source/lib/sdk/test/harness.js b/addon-sdk/source/lib/sdk/test/harness.js
deleted file mode 100644
index 1b31a1c79..000000000
--- a/addon-sdk/source/lib/sdk/test/harness.js
+++ /dev/null
@@ -1,645 +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, Cu } = require("chrome");
-const { Loader } = require('./loader');
-const { serializeStack, parseStack } = require("toolkit/loader");
-const { setTimeout } = require('../timers');
-const { PlainTextConsole } = require("../console/plain-text");
-const { when: unload } = require("../system/unload");
-const { format, fromException } = require("../console/traceback");
-const system = require("../system");
-const { gc: gcPromise } = require('./memory');
-const { defer } = require('../core/promise');
-const { extend } = require('../core/heritage');
-
-// Trick manifest builder to make it think we need these modules ?
-const unit = require("../deprecated/unit-test");
-const test = require("../../test");
-const url = require("../url");
-
-function emptyPromise() {
- let { promise, resolve } = defer();
- resolve();
- return promise;
-}
-
-var cService = Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService);
-
-// The console used to log messages
-var testConsole;
-
-// Cuddlefish loader in which we load and execute tests.
-var loader;
-
-// Function to call when we're done running tests.
-var onDone;
-
-// Function to print text to a console, w/o CR at the end.
-var print;
-
-// How many more times to run all tests.
-var iterationsLeft;
-
-// Whether to report memory profiling information.
-var profileMemory;
-
-// Whether we should stop as soon as a test reports a failure.
-var stopOnError;
-
-// Function to call to retrieve a list of tests to execute
-var findAndRunTests;
-
-// Combined information from all test runs.
-var results;
-
-// A list of the compartments and windows loaded after startup
-var startLeaks;
-
-// JSON serialization of last memory usage stats; we keep it stringified
-// so we don't actually change the memory usage stats (in terms of objects)
-// of the JSRuntime we're profiling.
-var lastMemoryUsage;
-
-function analyzeRawProfilingData(data) {
- var graph = data.graph;
- var shapes = {};
-
- // Convert keys in the graph from strings to ints.
- // TODO: Can we get rid of this ridiculousness?
- var newGraph = {};
- for (id in graph) {
- newGraph[parseInt(id)] = graph[id];
- }
- graph = newGraph;
-
- var modules = 0;
- var moduleIds = [];
- var moduleObjs = {UNKNOWN: 0};
- for (let name in data.namedObjects) {
- moduleObjs[name] = 0;
- moduleIds[data.namedObjects[name]] = name;
- modules++;
- }
-
- var count = 0;
- for (id in graph) {
- var parent = graph[id].parent;
- while (parent) {
- if (parent in moduleIds) {
- var name = moduleIds[parent];
- moduleObjs[name]++;
- break;
- }
- if (!(parent in graph)) {
- moduleObjs.UNKNOWN++;
- break;
- }
- parent = graph[parent].parent;
- }
- count++;
- }
-
- print("\nobject count is " + count + " in " + modules + " modules" +
- " (" + data.totalObjectCount + " across entire JS runtime)\n");
- if (lastMemoryUsage) {
- var last = JSON.parse(lastMemoryUsage);
- var diff = {
- moduleObjs: dictDiff(last.moduleObjs, moduleObjs),
- totalObjectClasses: dictDiff(last.totalObjectClasses,
- data.totalObjectClasses)
- };
-
- for (let name in diff.moduleObjs)
- print(" " + diff.moduleObjs[name] + " in " + name + "\n");
- for (let name in diff.totalObjectClasses)
- print(" " + diff.totalObjectClasses[name] + " instances of " +
- name + "\n");
- }
- lastMemoryUsage = JSON.stringify(
- {moduleObjs: moduleObjs,
- totalObjectClasses: data.totalObjectClasses}
- );
-}
-
-function dictDiff(last, curr) {
- var diff = {};
-
- for (let name in last) {
- var result = (curr[name] || 0) - last[name];
- if (result)
- diff[name] = (result > 0 ? "+" : "") + result;
- }
- for (let name in curr) {
- var result = curr[name] - (last[name] || 0);
- if (result)
- diff[name] = (result > 0 ? "+" : "") + result;
- }
- return diff;
-}
-
-function reportMemoryUsage() {
- if (!profileMemory) {
- return emptyPromise();
- }
-
- return gcPromise().then((() => {
- var mgr = Cc["@mozilla.org/memory-reporter-manager;1"]
- .getService(Ci.nsIMemoryReporterManager);
- let count = 0;
- function logReporter(process, path, kind, units, amount, description) {
- print(((++count == 1) ? "\n" : "") + description + ": " + amount + "\n");
- }
- mgr.getReportsForThisProcess(logReporter, null, /* anonymize = */ false);
- }));
-}
-
-var gWeakrefInfo;
-
-function checkMemory() {
- return gcPromise().then(_ => {
- let leaks = getPotentialLeaks();
-
- let compartmentURLs = Object.keys(leaks.compartments).filter(function(url) {
- return !(url in startLeaks.compartments);
- });
-
- let windowURLs = Object.keys(leaks.windows).filter(function(url) {
- return !(url in startLeaks.windows);
- });
-
- for (let url of compartmentURLs)
- console.warn("LEAKED", leaks.compartments[url]);
-
- for (let url of windowURLs)
- console.warn("LEAKED", leaks.windows[url]);
- }).then(showResults);
-}
-
-function showResults() {
- let { promise, resolve } = defer();
-
- if (gWeakrefInfo) {
- gWeakrefInfo.forEach(
- function(info) {
- var ref = info.weakref.get();
- if (ref !== null) {
- var data = ref.__url__ ? ref.__url__ : ref;
- var warning = data == "[object Object]"
- ? "[object " + data.constructor.name + "(" +
- Object.keys(data).join(", ") + ")]"
- : data;
- console.warn("LEAK", warning, info.bin);
- }
- }
- );
- }
-
- onDone(results);
-
- resolve();
- return promise;
-}
-
-function cleanup() {
- let coverObject = {};
- try {
- loader.unload();
-
- if (loader.globals.console.errorsLogged && !results.failed) {
- results.failed++;
- console.error("warnings and/or errors were logged.");
- }
-
- if (consoleListener.errorsLogged && !results.failed) {
- console.warn(consoleListener.errorsLogged + " " +
- "warnings or errors were logged to the " +
- "platform's nsIConsoleService, which could " +
- "be of no consequence; however, they could also " +
- "be indicative of aberrant behavior.");
- }
-
- // read the code coverage object, if it exists, from CoverJS-moz
- if (typeof loader.globals.global == "object") {
- coverObject = loader.globals.global['__$coverObject'] || {};
- }
-
- consoleListener.errorsLogged = 0;
- loader = null;
-
- consoleListener.unregister();
-
- Cu.forceGC();
- }
- catch (e) {
- results.failed++;
- console.error("unload.send() threw an exception.");
- console.exception(e);
- };
-
- setTimeout(require("./options").checkMemory ? checkMemory : showResults, 1);
-
- // dump the coverobject
- if (Object.keys(coverObject).length){
- const self = require('sdk/self');
- const {pathFor} = require("sdk/system");
- let file = require('sdk/io/file');
- const {env} = require('sdk/system/environment');
- console.log("CWD:", env.PWD);
- let out = file.join(env.PWD,'coverstats-'+self.id+'.json');
- console.log('coverstats:', out);
- let outfh = file.open(out,'w');
- outfh.write(JSON.stringify(coverObject,null,2));
- outfh.flush();
- outfh.close();
- }
-}
-
-function getPotentialLeaks() {
- Cu.forceGC();
-
- // Things we can assume are part of the platform and so aren't leaks
- let GOOD_BASE_URLS = [
- "chrome://",
- "resource:///",
- "resource://app/",
- "resource://gre/",
- "resource://gre-resources/",
- "resource://pdf.js/",
- "resource://pdf.js.components/",
- "resource://services-common/",
- "resource://services-crypto/",
- "resource://services-sync/"
- ];
-
- let ioService = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
- let uri = ioService.newURI("chrome://global/content/", "UTF-8", null);
- let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
- getService(Ci.nsIChromeRegistry);
- uri = chromeReg.convertChromeURL(uri);
- let spec = uri.spec;
- let pos = spec.indexOf("!/");
- GOOD_BASE_URLS.push(spec.substring(0, pos + 2));
-
- let zoneRegExp = new RegExp("^explicit/js-non-window/zones/zone[^/]+/compartment\\((.+)\\)");
- let compartmentRegexp = new RegExp("^explicit/js-non-window/compartments/non-window-global/compartment\\((.+)\\)/");
- let compartmentDetails = new RegExp("^([^,]+)(?:, (.+?))?(?: \\(from: (.*)\\))?$");
- let windowRegexp = new RegExp("^explicit/window-objects/top\\((.*)\\)/active");
- let windowDetails = new RegExp("^(.*), id=.*$");
-
- function isPossibleLeak(item) {
- if (!item.location)
- return false;
-
- for (let url of GOOD_BASE_URLS) {
- if (item.location.substring(0, url.length) == url) {
- return false;
- }
- }
-
- return true;
- }
-
- let compartments = {};
- let windows = {};
- function logReporter(process, path, kind, units, amount, description) {
- let matches;
-
- if ((matches = compartmentRegexp.exec(path)) || (matches = zoneRegExp.exec(path))) {
- if (matches[1] in compartments)
- return;
-
- let details = compartmentDetails.exec(matches[1]);
- if (!details) {
- console.error("Unable to parse compartment detail " + matches[1]);
- return;
- }
-
- let item = {
- path: matches[1],
- principal: details[1],
- location: details[2] ? details[2].replace(/\\/g, "/") : undefined,
- source: details[3] ? details[3].split(" -> ").reverse() : undefined,
- toString: function() {
- return this.location;
- }
- };
-
- if (!isPossibleLeak(item))
- return;
-
- compartments[matches[1]] = item;
- return;
- }
-
- if ((matches = windowRegexp.exec(path))) {
- if (matches[1] in windows)
- return;
-
- let details = windowDetails.exec(matches[1]);
- if (!details) {
- console.error("Unable to parse window detail " + matches[1]);
- return;
- }
-
- let item = {
- path: matches[1],
- location: details[1].replace(/\\/g, "/"),
- source: [details[1].replace(/\\/g, "/")],
- toString: function() {
- return this.location;
- }
- };
-
- if (!isPossibleLeak(item))
- return;
-
- windows[matches[1]] = item;
- }
- }
-
- Cc["@mozilla.org/memory-reporter-manager;1"]
- .getService(Ci.nsIMemoryReporterManager)
- .getReportsForThisProcess(logReporter, null, /* anonymize = */ false);
-
- return { compartments: compartments, windows: windows };
-}
-
-function nextIteration(tests) {
- if (tests) {
- results.passed += tests.passed;
- results.failed += tests.failed;
-
- reportMemoryUsage().then(_ => {
- let testRun = [];
- for (let test of tests.testRunSummary) {
- let testCopy = {};
- for (let info in test) {
- testCopy[info] = test[info];
- }
- testRun.push(testCopy);
- }
-
- results.testRuns.push(testRun);
- iterationsLeft--;
-
- checkForEnd();
- })
- }
- else {
- checkForEnd();
- }
-}
-
-function checkForEnd() {
- if (iterationsLeft && (!stopOnError || results.failed == 0)) {
- // Pass the loader which has a hooked console that doesn't dispatch
- // errors to the JS console and avoid firing false alarm in our
- // console listener
- findAndRunTests(loader, nextIteration);
- }
- else {
- setTimeout(cleanup, 0);
- }
-}
-
-var POINTLESS_ERRORS = [
- 'Invalid chrome URI:',
- 'OpenGL LayerManager Initialized Succesfully.',
- '[JavaScript Error: "TelemetryStopwatch:',
- 'reference to undefined property',
- '[JavaScript Error: "The character encoding of the HTML document was ' +
- 'not declared.',
- '[Javascript Warning: "Error: Failed to preserve wrapper of wrapped ' +
- 'native weak map key',
- '[JavaScript Warning: "Duplicate resource declaration for',
- 'file: "chrome://browser/content/',
- 'file: "chrome://global/content/',
- '[JavaScript Warning: "The character encoding of a framed document was ' +
- 'not declared.',
- 'file: "chrome://browser/skin/'
-];
-
-// These are messages that will cause a test to fail if logged through the
-// console service
-var IMPORTANT_ERRORS = [
- 'Sending message that cannot be cloned. Are you trying to send an XPCOM object?',
-];
-
-var consoleListener = {
- registered: false,
-
- register: function() {
- if (this.registered)
- return;
- cService.registerListener(this);
- this.registered = true;
- },
-
- unregister: function() {
- if (!this.registered)
- return;
- cService.unregisterListener(this);
- this.registered = false;
- },
-
- errorsLogged: 0,
-
- observe: function(object) {
- if (!(object instanceof Ci.nsIScriptError))
- return;
- this.errorsLogged++;
- var message = object.QueryInterface(Ci.nsIConsoleMessage).message;
- if (IMPORTANT_ERRORS.find(msg => message.indexOf(msg) >= 0)) {
- testConsole.error(message);
- return;
- }
- var pointless = POINTLESS_ERRORS.filter(err => message.indexOf(err) >= 0);
- if (pointless.length == 0 && message)
- testConsole.log(message);
- }
-};
-
-function TestRunnerConsole(base, options) {
- let proto = extend(base, {
- errorsLogged: 0,
- warn: function warn() {
- this.errorsLogged++;
- base.warn.apply(base, arguments);
- },
- error: function error() {
- this.errorsLogged++;
- base.error.apply(base, arguments);
- },
- info: function info(first) {
- if (options.verbose)
- base.info.apply(base, arguments);
- else
- if (first == "pass:")
- print(".");
- },
- });
- return Object.create(proto);
-}
-
-function stringify(arg) {
- try {
- return String(arg);
- }
- catch(ex) {
- return "<toString() error>";
- }
-}
-
-function stringifyArgs(args) {
- return Array.map(args, stringify).join(" ");
-}
-
-function TestRunnerTinderboxConsole(base, options) {
- this.base = base;
- this.print = options.print;
- this.verbose = options.verbose;
- this.errorsLogged = 0;
-
- // Binding all the public methods to an instance so that they can be used
- // as callback / listener functions straightaway.
- this.log = this.log.bind(this);
- this.info = this.info.bind(this);
- this.warn = this.warn.bind(this);
- this.error = this.error.bind(this);
- this.debug = this.debug.bind(this);
- this.exception = this.exception.bind(this);
- this.trace = this.trace.bind(this);
-};
-
-TestRunnerTinderboxConsole.prototype = {
- testMessage: function testMessage(pass, expected, test, message) {
- let type = "TEST-";
- if (expected) {
- if (pass)
- type += "PASS";
- else
- type += "KNOWN-FAIL";
- }
- else {
- this.errorsLogged++;
- if (pass)
- type += "UNEXPECTED-PASS";
- else
- type += "UNEXPECTED-FAIL";
- }
-
- this.print(type + " | " + test + " | " + message + "\n");
- if (!expected)
- this.trace();
- },
-
- log: function log() {
- this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n");
- },
-
- info: function info(first) {
- this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n");
- },
-
- warn: function warn() {
- this.errorsLogged++;
- this.print("TEST-UNEXPECTED-FAIL | " + stringifyArgs(arguments) + "\n");
- },
-
- error: function error() {
- this.errorsLogged++;
- this.print("TEST-UNEXPECTED-FAIL | " + stringifyArgs(arguments) + "\n");
- this.base.error.apply(this.base, arguments);
- },
-
- debug: function debug() {
- this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n");
- },
-
- exception: function exception(e) {
- this.print("An exception occurred.\n" +
- require("../console/traceback").format(e) + "\n" + e + "\n");
- },
-
- trace: function trace() {
- var traceback = require("../console/traceback");
- var stack = traceback.get();
- stack.splice(-1, 1);
- this.print("TEST-INFO | " + stringify(traceback.format(stack)) + "\n");
- }
-};
-
-var runTests = exports.runTests = function runTests(options) {
- iterationsLeft = options.iterations;
- profileMemory = options.profileMemory;
- stopOnError = options.stopOnError;
- onDone = options.onDone;
- print = options.print;
- findAndRunTests = options.findAndRunTests;
-
- results = {
- passed: 0,
- failed: 0,
- testRuns: []
- };
-
- try {
- consoleListener.register();
- print("Running tests on " + system.name + " " + system.version +
- "/Gecko " + system.platformVersion + " (Build " +
- system.build + ") (" + system.id + ") under " +
- system.platform + "/" + system.architecture + ".\n");
-
- if (options.parseable)
- testConsole = new TestRunnerTinderboxConsole(new PlainTextConsole(), options);
- else
- testConsole = new TestRunnerConsole(new PlainTextConsole(), options);
-
- loader = Loader(module, {
- console: testConsole,
- global: {} // useful for storing things like coverage testing.
- });
-
- // Load these before getting initial leak stats as they will still be in
- // memory when we check later
- require("../deprecated/unit-test");
- require("../deprecated/unit-test-finder");
- if (profileMemory)
- startLeaks = getPotentialLeaks();
-
- nextIteration();
- } catch (e) {
- let frames = fromException(e).reverse().reduce(function(frames, frame) {
- if (frame.fileName.split("/").pop() === "unit-test-finder.js")
- frames.done = true
- if (!frames.done) frames.push(frame)
-
- return frames
- }, [])
-
- let prototype = typeof(e) === "object" ? e.constructor.prototype :
- Error.prototype;
- let stack = serializeStack(frames.reverse());
-
- let error = Object.create(prototype, {
- message: { value: e.message, writable: true, configurable: true },
- fileName: { value: e.fileName, writable: true, configurable: true },
- lineNumber: { value: e.lineNumber, writable: true, configurable: true },
- stack: { value: stack, writable: true, configurable: true },
- toString: { value: () => String(e), writable: true, configurable: true },
- });
-
- print("Error: " + error + " \n " + format(error));
- onDone({passed: 0, failed: 1});
- }
-};
-
-unload(_ => consoleListener.unregister());
diff --git a/addon-sdk/source/lib/sdk/test/httpd.js b/addon-sdk/source/lib/sdk/test/httpd.js
deleted file mode 100644
index 218493924..000000000
--- a/addon-sdk/source/lib/sdk/test/httpd.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/. */
-
-throw new Error(`This file was removed. A copy can be obtained from:
- https://github.com/mozilla/addon-sdk/blob/master/test/lib/httpd.js`);
diff --git a/addon-sdk/source/lib/sdk/test/loader.js b/addon-sdk/source/lib/sdk/test/loader.js
deleted file mode 100644
index 33ba2ca5a..000000000
--- a/addon-sdk/source/lib/sdk/test/loader.js
+++ /dev/null
@@ -1,123 +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 { resolveURI, Require,
- unload, override, descriptor } = require('../../toolkit/loader');
-const { ensure } = require('../system/unload');
-const addonWindow = require('../addon/window');
-const { PlainTextConsole } = require('sdk/console/plain-text');
-
-var defaultGlobals = override(require('../system/globals'), {
- console: console
-});
-
-function CustomLoader(module, globals, packaging, overrides={}) {
- let options = packaging || require("@loader/options");
- options = override(options, {
- id: overrides.id || options.id,
- globals: override(defaultGlobals, globals || {}),
- modules: override(override(options.modules || {}, overrides.modules || {}), {
- 'sdk/addon/window': addonWindow
- })
- });
-
- let loaderModule = options.isNative ? '../../toolkit/loader' : '../loader/cuddlefish';
- let { Loader } = require(loaderModule);
- let loader = Loader(options);
- let wrapper = Object.create(loader, descriptor({
- require: Require(loader, module),
- sandbox: function(id) {
- let requirement = loader.resolve(id, module.id);
- if (!requirement)
- requirement = id;
- let uri = resolveURI(requirement, loader.mapping);
- return loader.sandboxes[uri];
- },
- unload: function(reason) {
- unload(loader, reason);
- }
- }));
- ensure(wrapper);
- return wrapper;
-};
-exports.Loader = CustomLoader;
-
-function HookedPlainTextConsole(hook, print, innerID) {
- this.log = hook.bind(null, "log", innerID);
- this.info = hook.bind(null, "info", innerID);
- this.warn = hook.bind(null, "warn", innerID);
- this.error = hook.bind(null, "error", innerID);
- this.debug = hook.bind(null, "debug", innerID);
- this.exception = hook.bind(null, "exception", innerID);
- this.time = hook.bind(null, "time", innerID);
- this.timeEnd = hook.bind(null, "timeEnd", innerID);
-
- this.__exposedProps__ = {
- log: "rw", info: "rw", warn: "rw", error: "rw", debug: "rw",
- exception: "rw", time: "rw", timeEnd: "rw"
- };
-}
-
-// Creates a custom loader instance whose console module is hooked in order
-// to avoid printing messages to the console, and instead, expose them in the
-// returned `messages` array attribute
-exports.LoaderWithHookedConsole = function (module, callback) {
- let messages = [];
- function hook(type, innerID, msg) {
- messages.push({ type: type, msg: msg, innerID: innerID });
- if (callback)
- callback(type, msg, innerID);
- }
-
- return {
- loader: CustomLoader(module, {
- console: new HookedPlainTextConsole(hook, null, null)
- }, null, {
- modules: {
- 'sdk/console/plain-text': {
- PlainTextConsole: HookedPlainTextConsole.bind(null, hook)
- }
- }
- }),
- messages: messages
- };
-}
-
-// Same than LoaderWithHookedConsole with lower level, instead we get what is
-// actually printed to the command line console
-exports.LoaderWithHookedConsole2 = function (module, callback) {
- let messages = [];
- return {
- loader: CustomLoader(module, {
- console: new PlainTextConsole(function (msg) {
- messages.push(msg);
- if (callback)
- callback(msg);
- })
- }),
- messages: messages
- };
-}
-
-// Creates a custom loader with a filtered console. The callback is passed every
-// console message type and message and if it returns false the message will
-// not be logged normally
-exports.LoaderWithFilteredConsole = function (module, callback) {
- function hook(type, innerID, msg) {
- if (callback && callback(type, msg, innerID) == false)
- return;
- console[type](msg);
- }
-
- return CustomLoader(module, {
- console: new HookedPlainTextConsole(hook, null, null)
- }, null, {
- modules: {
- 'sdk/console/plain-text': {
- PlainTextConsole: HookedPlainTextConsole.bind(null, hook)
- }
- }
- });
-}
diff --git a/addon-sdk/source/lib/sdk/test/memory.js b/addon-sdk/source/lib/sdk/test/memory.js
deleted file mode 100644
index bd1198bfe..000000000
--- a/addon-sdk/source/lib/sdk/test/memory.js
+++ /dev/null
@@ -1,11 +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 { Cu } = require("chrome");
-
-function gc() {
- return new Promise(resolve => Cu.schedulePreciseGC(resolve));
-}
-exports.gc = gc;
diff --git a/addon-sdk/source/lib/sdk/test/options.js b/addon-sdk/source/lib/sdk/test/options.js
deleted file mode 100644
index 9bc611ca5..000000000
--- a/addon-sdk/source/lib/sdk/test/options.js
+++ /dev/null
@@ -1,23 +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 options = require("@test/options");
-const { id } = require("../self");
-const { get } = require("../preferences/service");
-
-const readPref = (key) => get("extensions." + id + ".sdk." + key);
-
-exports.iterations = readPref("test.iterations") || options.iterations;
-exports.filter = readPref("test.filter") || options.filter;
-exports.profileMemory = readPref("profile.memory") || options.profileMemory;
-exports.stopOnError = readPref("test.stop") || options.stopOnError;
-exports.keepOpen = readPref("test.keepOpen") || false;
-exports.verbose = (readPref("output.logLevel") == "verbose") || options.verbose;
-exports.parseable = (readPref("output.format") == "tbpl") || options.parseable;
-exports.checkMemory = readPref("profile.leaks") || options.check_memory;
diff --git a/addon-sdk/source/lib/sdk/test/runner.js b/addon-sdk/source/lib/sdk/test/runner.js
deleted file mode 100644
index ea37ac84f..000000000
--- a/addon-sdk/source/lib/sdk/test/runner.js
+++ /dev/null
@@ -1,131 +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"
-};
-
-var { exit, stdout } = require("../system");
-var cfxArgs = require("../test/options");
-var events = require("../system/events");
-const { resolve } = require("../core/promise");
-
-function runTests(findAndRunTests) {
- var harness = require("./harness");
-
- function onDone(tests) {
- stdout.write("\n");
- var total = tests.passed + tests.failed;
- stdout.write(tests.passed + " of " + total + " tests passed.\n");
-
- events.emit("sdk:test:results", { data: JSON.stringify(tests) });
-
- if (tests.failed == 0) {
- if (tests.passed === 0)
- stdout.write("No tests were run\n");
- if (!cfxArgs.keepOpen)
- exit(0);
- } else {
- if (cfxArgs.verbose || cfxArgs.parseable)
- printFailedTests(tests, stdout.write);
- if (!cfxArgs.keepOpen)
- exit(1);
- }
- };
-
- // We may have to run test on next cycle, otherwise XPCOM components
- // are not correctly updated.
- // For ex: nsIFocusManager.getFocusedElementForWindow may throw
- // NS_ERROR_ILLEGAL_VALUE exception.
- require("../timers").setTimeout(_ => harness.runTests({
- findAndRunTests: findAndRunTests,
- iterations: cfxArgs.iterations || 1,
- filter: cfxArgs.filter,
- profileMemory: cfxArgs.profileMemory,
- stopOnError: cfxArgs.stopOnError,
- verbose: cfxArgs.verbose,
- parseable: cfxArgs.parseable,
- print: stdout.write,
- onDone: onDone
- }));
-}
-
-function printFailedTests(tests, print) {
- let iterationNumber = 0;
- let singleIteration = (tests.testRuns || []).length == 1;
- let padding = singleIteration ? "" : " ";
-
- print("\nThe following tests failed:\n");
-
- for (let testRun of tests.testRuns) {
- iterationNumber++;
-
- if (!singleIteration)
- print(" Iteration " + iterationNumber + ":\n");
-
- for (let test of testRun) {
- if (test.failed > 0) {
- print(padding + " " + test.name + ": " + test.errors +"\n");
- }
- }
- print("\n");
- }
-}
-
-function main() {
- var testsStarted = false;
-
- if (!testsStarted) {
- testsStarted = true;
- runTests(function findAndRunTests(loader, nextIteration) {
- loader.require("../deprecated/unit-test").findAndRunTests({
- testOutOfProcess: false,
- testInProcess: true,
- stopOnError: cfxArgs.stopOnError,
- filter: cfxArgs.filter,
- onDone: nextIteration
- });
- });
- }
-};
-
-if (require.main === module)
- main();
-
-exports.runTestsFromModule = function runTestsFromModule(module) {
- let id = module.id;
- // Make a copy of exports as it may already be frozen by module loader
- let exports = {};
- Object.keys(module.exports).forEach(key => {
- exports[key] = module.exports[key];
- });
-
- runTests(function findAndRunTests(loader, nextIteration) {
- // Consider that all these tests are CommonJS ones
- loader.require('../../test').run(exports);
-
- // Reproduce what is done in sdk/deprecated/unit-test-finder.findTests()
- let tests = [];
- for (let name of Object.keys(exports).sort()) {
- tests.push({
- setup: exports.setup,
- teardown: exports.teardown,
- testFunction: exports[name],
- name: id + "." + name
- });
- }
-
- // Reproduce what is done by unit-test.findAndRunTests()
- var { TestRunner } = loader.require("../deprecated/unit-test");
- var runner = new TestRunner();
- runner.startMany({
- tests: {
- getNext: () => resolve(tests.shift())
- },
- stopOnError: cfxArgs.stopOnError,
- onDone: nextIteration
- });
- });
-}
diff --git a/addon-sdk/source/lib/sdk/test/utils.js b/addon-sdk/source/lib/sdk/test/utils.js
deleted file mode 100644
index b01df67d4..000000000
--- a/addon-sdk/source/lib/sdk/test/utils.js
+++ /dev/null
@@ -1,199 +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 { defer } = require('../core/promise');
-const { setInterval, clearInterval } = require('../timers');
-const { getTabs, closeTab } = require("../tabs/utils");
-const { windows: getWindows } = require("../window/utils");
-const { close: closeWindow } = require("../window/helpers");
-const { isGenerator } = require("../lang/type");
-const { env } = require("../system/environment");
-const { Task } = require("resource://gre/modules/Task.jsm");
-
-const getTestNames = (exports) =>
- Object.keys(exports).filter(name => /^test/.test(name));
-
-const isTestAsync = ({length}) => length > 1;
-const isHelperAsync = ({length}) => length > 2;
-
-/*
- * Takes an `exports` object of a test file and a function `beforeFn`
- * to be run before each test. `beforeFn` is called with a `name` string
- * as the first argument of the test name, and may specify a second
- * argument function `done` to indicate that this function should
- * resolve asynchronously
- */
-function before (exports, beforeFn) {
- getTestNames(exports).map(name => {
- let testFn = exports[name];
-
- // GENERATOR TESTS
- if (isGenerator(testFn) && isGenerator(beforeFn)) {
- exports[name] = function*(assert) {
- yield Task.spawn(beforeFn.bind(null, name, assert));
- yield Task.spawn(testFn.bind(null, assert));
- }
- }
- else if (isGenerator(testFn) && !isHelperAsync(beforeFn)) {
- exports[name] = function*(assert) {
- beforeFn(name, assert);
- yield Task.spawn(testFn.bind(null, assert));
- }
- }
- else if (isGenerator(testFn) && isHelperAsync(beforeFn)) {
- exports[name] = function*(assert) {
- yield new Promise(resolve => beforeFn(name, assert, resolve));
- yield Task.spawn(testFn.bind(null, assert));
- }
- }
- // SYNC TESTS
- else if (!isTestAsync(testFn) && isGenerator(beforeFn)) {
- exports[name] = function*(assert) {
- yield Task.spawn(beforeFn.bind(null, name, assert));
- testFn(assert);
- };
- }
- else if (!isTestAsync(testFn) && !isHelperAsync(beforeFn)) {
- exports[name] = function (assert) {
- beforeFn(name, assert);
- testFn(assert);
- };
- }
- else if (!isTestAsync(testFn) && isHelperAsync(beforeFn)) {
- exports[name] = function (assert, done) {
- beforeFn(name, assert, () => {
- testFn(assert);
- done();
- });
- };
- }
- // ASYNC TESTS
- else if (isTestAsync(testFn) && isGenerator(beforeFn)) {
- exports[name] = function*(assert) {
- yield Task.spawn(beforeFn.bind(null, name, assert));
- yield new Promise(resolve => testFn(assert, resolve));
- };
- }
- else if (isTestAsync(testFn) && !isHelperAsync(beforeFn)) {
- exports[name] = function (assert, done) {
- beforeFn(name, assert);
- testFn(assert, done);
- };
- }
- else if (isTestAsync(testFn) && isHelperAsync(beforeFn)) {
- exports[name] = function (assert, done) {
- beforeFn(name, assert, () => {
- testFn(assert, done);
- });
- };
- }
- });
-}
-exports.before = before;
-
-/*
- * Takes an `exports` object of a test file and a function `afterFn`
- * to be run after each test. `afterFn` is called with a `name` string
- * as the first argument of the test name, and may specify a second
- * argument function `done` to indicate that this function should
- * resolve asynchronously
- */
-function after (exports, afterFn) {
- getTestNames(exports).map(name => {
- let testFn = exports[name];
-
- // GENERATOR TESTS
- if (isGenerator(testFn) && isGenerator(afterFn)) {
- exports[name] = function*(assert) {
- yield Task.spawn(testFn.bind(null, assert));
- yield Task.spawn(afterFn.bind(null, name, assert));
- }
- }
- else if (isGenerator(testFn) && !isHelperAsync(afterFn)) {
- exports[name] = function*(assert) {
- yield Task.spawn(testFn.bind(null, assert));
- afterFn(name, assert);
- }
- }
- else if (isGenerator(testFn) && isHelperAsync(afterFn)) {
- exports[name] = function*(assert) {
- yield Task.spawn(testFn.bind(null, assert));
- yield new Promise(resolve => afterFn(name, assert, resolve));
- }
- }
- // SYNC TESTS
- else if (!isTestAsync(testFn) && isGenerator(afterFn)) {
- exports[name] = function*(assert) {
- testFn(assert);
- yield Task.spawn(afterFn.bind(null, name, assert));
- };
- }
- else if (!isTestAsync(testFn) && !isHelperAsync(afterFn)) {
- exports[name] = function (assert) {
- testFn(assert);
- afterFn(name, assert);
- };
- }
- else if (!isTestAsync(testFn) && isHelperAsync(afterFn)) {
- exports[name] = function (assert, done) {
- testFn(assert);
- afterFn(name, assert, done);
- };
- }
- // ASYNC TESTS
- else if (isTestAsync(testFn) && isGenerator(afterFn)) {
- exports[name] = function*(assert) {
- yield new Promise(resolve => testFn(assert, resolve));
- yield Task.spawn(afterFn.bind(null, name, assert));
- };
- }
- else if (isTestAsync(testFn) && !isHelperAsync(afterFn)) {
- exports[name] = function*(assert) {
- yield new Promise(resolve => testFn(assert, resolve));
- afterFn(name, assert);
- };
- }
- else if (isTestAsync(testFn) && isHelperAsync(afterFn)) {
- exports[name] = function*(assert) {
- yield new Promise(resolve => testFn(assert, resolve));
- yield new Promise(resolve => afterFn(name, assert, resolve));
- };
- }
- });
-}
-exports.after = after;
-
-function waitUntil (predicate, delay) {
- let { promise, resolve } = defer();
- let interval = setInterval(() => {
- if (!predicate()) return;
- clearInterval(interval);
- resolve();
- }, 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);
diff --git a/addon-sdk/source/lib/sdk/timers.js b/addon-sdk/source/lib/sdk/timers.js
deleted file mode 100644
index e97db01f2..000000000
--- a/addon-sdk/source/lib/sdk/timers.js
+++ /dev/null
@@ -1,105 +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 { CC, Cc, Ci } = require("chrome");
-const { when: unload } = require("./system/unload");
-
-const { TYPE_ONE_SHOT, TYPE_REPEATING_SLACK } = Ci.nsITimer;
-const Timer = CC("@mozilla.org/timer;1", "nsITimer");
-const timers = Object.create(null);
-const threadManager = Cc["@mozilla.org/thread-manager;1"].
- getService(Ci.nsIThreadManager);
-const prefBranch = Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefService).
- QueryInterface(Ci.nsIPrefBranch);
-
-var MIN_DELAY = 4;
-// Try to get min timeout delay used by browser.
-try { MIN_DELAY = prefBranch.getIntPref("dom.min_timeout_value"); } finally {}
-
-
-// Last timer id.
-var lastID = 0;
-
-// Sets typer either by timeout or by interval
-// depending on a given type.
-function setTimer(type, callback, delay, ...args) {
- let id = ++ lastID;
- let timer = timers[id] = Timer();
- timer.initWithCallback({
- notify: function notify() {
- try {
- if (type === TYPE_ONE_SHOT)
- delete timers[id];
- callback.apply(null, args);
- }
- catch(error) {
- console.exception(error);
- }
- }
- }, Math.max(delay || MIN_DELAY), type);
- return id;
-}
-
-function unsetTimer(id) {
- let timer = timers[id];
- delete timers[id];
- if (timer) timer.cancel();
-}
-
-var immediates = new Map();
-
-var dispatcher = _ => {
- // Allow scheduling of a new dispatch loop.
- dispatcher.scheduled = false;
- // Take a snapshot of timer `id`'s that have being present before
- // starting a dispatch loop, in order to ignore timers registered
- // in side effect to dispatch while also skipping immediates that
- // were removed in side effect.
- let ids = [...immediates.keys()];
- for (let id of ids) {
- let immediate = immediates.get(id);
- if (immediate) {
- immediates.delete(id);
- try { immediate(); }
- catch (error) { console.exception(error); }
- }
- }
-}
-
-function setImmediate(callback, ...params) {
- let id = ++ lastID;
- // register new immediate timer with curried params.
- immediates.set(id, _ => callback.apply(callback, params));
- // if dispatch loop is not scheduled schedule one. Own scheduler
- if (!dispatcher.scheduled) {
- dispatcher.scheduled = true;
- threadManager.currentThread.dispatch(dispatcher,
- Ci.nsIThread.DISPATCH_NORMAL);
- }
- return id;
-}
-
-function clearImmediate(id) {
- immediates.delete(id);
-}
-
-// Bind timers so that toString-ing them looks same as on native timers.
-exports.setImmediate = setImmediate.bind(null);
-exports.clearImmediate = clearImmediate.bind(null);
-exports.setTimeout = setTimer.bind(null, TYPE_ONE_SHOT);
-exports.setInterval = setTimer.bind(null, TYPE_REPEATING_SLACK);
-exports.clearTimeout = unsetTimer.bind(null);
-exports.clearInterval = unsetTimer.bind(null);
-
-// all timers are cleared out on unload.
-unload(function() {
- immediates.clear();
- Object.keys(timers).forEach(unsetTimer)
-});
diff --git a/addon-sdk/source/lib/sdk/ui.js b/addon-sdk/source/lib/sdk/ui.js
deleted file mode 100644
index 7f9110b26..000000000
--- a/addon-sdk/source/lib/sdk/ui.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': 'experimental',
- 'engines': {
- 'Firefox': '> 28'
- }
-};
-
-exports.ActionButton = require('./ui/button/action').ActionButton;
-exports.ToggleButton = require('./ui/button/toggle').ToggleButton;
-exports.Sidebar = require('./ui/sidebar').Sidebar;
-exports.Frame = require('./ui/frame').Frame;
-exports.Toolbar = require('./ui/toolbar').Toolbar;
diff --git a/addon-sdk/source/lib/sdk/ui/button/action.js b/addon-sdk/source/lib/sdk/ui/button/action.js
deleted file mode 100644
index dfb092d0c..000000000
--- a/addon-sdk/source/lib/sdk/ui/button/action.js
+++ /dev/null
@@ -1,114 +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',
- 'engines': {
- 'Firefox': '> 28'
- }
-};
-
-const { Class } = require('../../core/heritage');
-const { merge } = require('../../util/object');
-const { Disposable } = require('../../core/disposable');
-const { on, off, emit, setListeners } = require('../../event/core');
-const { EventTarget } = require('../../event/target');
-const { getNodeView } = require('../../view/core');
-
-const view = require('./view');
-const { buttonContract, stateContract } = require('./contract');
-const { properties, render, state, register, unregister,
- getDerivedStateFor } = require('../state');
-const { events: stateEvents } = require('../state/events');
-const { events: viewEvents } = require('./view/events');
-const events = require('../../event/utils');
-
-const { getActiveTab } = require('../../tabs/utils');
-
-const { id: addonID } = require('../../self');
-const { identify } = require('../id');
-
-const buttons = new Map();
-
-const toWidgetId = id =>
- ('action-button--' + addonID.toLowerCase()+ '-' + id).
- replace(/[^a-z0-9_-]/g, '');
-
-const ActionButton = Class({
- extends: EventTarget,
- implements: [
- properties(stateContract),
- state(stateContract),
- Disposable
- ],
- setup: function setup(options) {
- let state = merge({
- disabled: false
- }, buttonContract(options));
-
- let id = toWidgetId(options.id);
-
- register(this, state);
-
- // Setup listeners.
- setListeners(this, options);
-
- buttons.set(id, this);
-
- view.create(merge({}, state, { id: id }));
- },
-
- dispose: function dispose() {
- let id = toWidgetId(this.id);
- buttons.delete(id);
-
- off(this);
-
- view.dispose(id);
-
- unregister(this);
- },
-
- get id() {
- return this.state().id;
- },
-
- click: function click() { view.click(toWidgetId(this.id)) }
-});
-exports.ActionButton = ActionButton;
-
-identify.define(ActionButton, ({id}) => toWidgetId(id));
-
-getNodeView.define(ActionButton, button =>
- view.nodeFor(toWidgetId(button.id))
-);
-
-var actionButtonStateEvents = events.filter(stateEvents,
- e => e.target instanceof ActionButton);
-
-var actionButtonViewEvents = events.filter(viewEvents,
- e => buttons.has(e.target));
-
-var clickEvents = events.filter(actionButtonViewEvents, e => e.type === 'click');
-var updateEvents = events.filter(actionButtonViewEvents, e => e.type === 'update');
-
-on(clickEvents, 'data', ({target: id, window}) => {
- let button = buttons.get(id);
- let state = getDerivedStateFor(button, getActiveTab(window));
-
- emit(button, 'click', state);
-});
-
-on(updateEvents, 'data', ({target: id, window}) => {
- render(buttons.get(id), window);
-});
-
-on(actionButtonStateEvents, 'data', ({target, window, state}) => {
- let id = toWidgetId(target.id);
- view.setIcon(id, window, state.icon);
- view.setLabel(id, window, state.label);
- view.setDisabled(id, window, state.disabled);
- view.setBadge(id, window, state.badge, state.badgeColor);
-});
diff --git a/addon-sdk/source/lib/sdk/ui/button/contract.js b/addon-sdk/source/lib/sdk/ui/button/contract.js
deleted file mode 100644
index ce6e33d95..000000000
--- a/addon-sdk/source/lib/sdk/ui/button/contract.js
+++ /dev/null
@@ -1,73 +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 { contract } = require('../../util/contract');
-const { isLocalURL } = require('../../url');
-const { isNil, isObject, isString } = require('../../lang/type');
-const { required, either, string, boolean, object, number } = require('../../deprecated/api-utils');
-const { merge } = require('../../util/object');
-const { freeze } = Object;
-
-const isIconSet = (icons) =>
- Object.keys(icons).
- every(size => String(size >>> 0) === size && isLocalURL(icons[size]));
-
-var iconSet = {
- is: either(object, string),
- map: v => isObject(v) ? freeze(merge({}, v)) : v,
- ok: v => (isString(v) && isLocalURL(v)) || (isObject(v) && isIconSet(v)),
- msg: 'The option "icon" must be a local URL or an object with ' +
- 'numeric keys / local URL values pair.'
-}
-
-var id = {
- is: string,
- ok: v => /^[a-z-_][a-z0-9-_]*$/i.test(v),
- msg: 'The option "id" must be a valid alphanumeric id (hyphens and ' +
- 'underscores are allowed).'
-};
-
-var label = {
- is: string,
- ok: v => isNil(v) || v.trim().length > 0,
- msg: 'The option "label" must be a non empty string'
-}
-
-var badge = {
- is: either(string, number),
- msg: 'The option "badge" must be a string or a number'
-}
-
-var badgeColor = {
- is: string,
- msg: 'The option "badgeColor" must be a string'
-}
-
-var stateContract = contract({
- label: label,
- icon: iconSet,
- disabled: boolean,
- badge: badge,
- badgeColor: badgeColor
-});
-
-exports.stateContract = stateContract;
-
-var buttonContract = contract(merge({}, stateContract.rules, {
- id: required(id),
- label: required(label),
- icon: required(iconSet)
-}));
-
-exports.buttonContract = buttonContract;
-
-exports.toggleStateContract = contract(merge({
- checked: boolean
-}, stateContract.rules));
-
-exports.toggleButtonContract = contract(merge({
- checked: boolean
-}, buttonContract.rules));
-
diff --git a/addon-sdk/source/lib/sdk/ui/button/toggle.js b/addon-sdk/source/lib/sdk/ui/button/toggle.js
deleted file mode 100644
index a226b3212..000000000
--- a/addon-sdk/source/lib/sdk/ui/button/toggle.js
+++ /dev/null
@@ -1,127 +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',
- 'engines': {
- 'Firefox': '> 28'
- }
-};
-
-const { Class } = require('../../core/heritage');
-const { merge } = require('../../util/object');
-const { Disposable } = require('../../core/disposable');
-const { on, off, emit, setListeners } = require('../../event/core');
-const { EventTarget } = require('../../event/target');
-const { getNodeView } = require('../../view/core');
-
-const view = require('./view');
-const { toggleButtonContract, toggleStateContract } = require('./contract');
-const { properties, render, state, register, unregister,
- setStateFor, getStateFor, getDerivedStateFor } = require('../state');
-const { events: stateEvents } = require('../state/events');
-const { events: viewEvents } = require('./view/events');
-const events = require('../../event/utils');
-
-const { getActiveTab } = require('../../tabs/utils');
-
-const { id: addonID } = require('../../self');
-const { identify } = require('../id');
-
-const buttons = new Map();
-
-const toWidgetId = id =>
- ('toggle-button--' + addonID.toLowerCase()+ '-' + id).
- replace(/[^a-z0-9_-]/g, '');
-
-const ToggleButton = Class({
- extends: EventTarget,
- implements: [
- properties(toggleStateContract),
- state(toggleStateContract),
- Disposable
- ],
- setup: function setup(options) {
- let state = merge({
- disabled: false,
- checked: false
- }, toggleButtonContract(options));
-
- let id = toWidgetId(options.id);
-
- register(this, state);
-
- // Setup listeners.
- setListeners(this, options);
-
- buttons.set(id, this);
-
- view.create(merge({ type: 'checkbox' }, state, { id: id }));
- },
-
- dispose: function dispose() {
- let id = toWidgetId(this.id);
- buttons.delete(id);
-
- off(this);
-
- view.dispose(id);
-
- unregister(this);
- },
-
- get id() {
- return this.state().id;
- },
-
- click: function click() {
- return view.click(toWidgetId(this.id));
- }
-});
-exports.ToggleButton = ToggleButton;
-
-identify.define(ToggleButton, ({id}) => toWidgetId(id));
-
-getNodeView.define(ToggleButton, button =>
- view.nodeFor(toWidgetId(button.id))
-);
-
-var toggleButtonStateEvents = events.filter(stateEvents,
- e => e.target instanceof ToggleButton);
-
-var toggleButtonViewEvents = events.filter(viewEvents,
- e => buttons.has(e.target));
-
-var clickEvents = events.filter(toggleButtonViewEvents, e => e.type === 'click');
-var updateEvents = events.filter(toggleButtonViewEvents, e => e.type === 'update');
-
-on(toggleButtonStateEvents, 'data', ({target, window, state}) => {
- let id = toWidgetId(target.id);
-
- view.setIcon(id, window, state.icon);
- view.setLabel(id, window, state.label);
- view.setDisabled(id, window, state.disabled);
- view.setChecked(id, window, state.checked);
- view.setBadge(id, window, state.badge, state.badgeColor);
-});
-
-on(clickEvents, 'data', ({target: id, window, checked }) => {
- let button = buttons.get(id);
- let windowState = getStateFor(button, window);
-
- let newWindowState = merge({}, windowState, { checked: checked });
-
- setStateFor(button, window, newWindowState);
-
- let state = getDerivedStateFor(button, getActiveTab(window));
-
- emit(button, 'click', state);
-
- emit(button, 'change', state);
-});
-
-on(updateEvents, 'data', ({target: id, window}) => {
- render(buttons.get(id), window);
-});
diff --git a/addon-sdk/source/lib/sdk/ui/button/view.js b/addon-sdk/source/lib/sdk/ui/button/view.js
deleted file mode 100644
index 63b7aea31..000000000
--- a/addon-sdk/source/lib/sdk/ui/button/view.js
+++ /dev/null
@@ -1,243 +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',
- 'engines': {
- 'Firefox': '> 28'
- }
-};
-
-const { Cu } = require('chrome');
-const { on, off, emit } = require('../../event/core');
-
-const { data } = require('sdk/self');
-
-const { isObject, isNil } = require('../../lang/type');
-
-const { getMostRecentBrowserWindow } = require('../../window/utils');
-const { ignoreWindow } = require('../../private-browsing/utils');
-const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
-const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI;
-
-const { events: viewEvents } = require('./view/events');
-
-const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
-
-const views = new Map();
-const customizedWindows = new WeakMap();
-
-const buttonListener = {
- onCustomizeStart: window => {
- for (let [id, view] of views) {
- setIcon(id, window, view.icon);
- setLabel(id, window, view.label);
- }
-
- customizedWindows.set(window, true);
- },
- onCustomizeEnd: window => {
- customizedWindows.delete(window);
-
- for (let [id, ] of views) {
- let placement = CustomizableUI.getPlacementOfWidget(id);
-
- if (placement)
- emit(viewEvents, 'data', { type: 'update', target: id, window: window });
- }
- },
- onWidgetAfterDOMChange: (node, nextNode, container) => {
- let { id } = node;
- let view = views.get(id);
- let window = node.ownerDocument.defaultView;
-
- if (view) {
- emit(viewEvents, 'data', { type: 'update', target: id, window: window });
- }
- }
-};
-
-CustomizableUI.addListener(buttonListener);
-
-require('../../system/unload').when( _ =>
- CustomizableUI.removeListener(buttonListener)
-);
-
-function getNode(id, window) {
- return !views.has(id) || ignoreWindow(window)
- ? null
- : CustomizableUI.getWidget(id).forWindow(window).node
-};
-
-function isInToolbar(id) {
- let placement = CustomizableUI.getPlacementOfWidget(id);
-
- return placement && CustomizableUI.getAreaType(placement.area) === 'toolbar';
-}
-
-
-function getImage(icon, isInToolbar, pixelRatio) {
- let targetSize = (isInToolbar ? 18 : 32) * pixelRatio;
- let bestSize = 0;
- let image = icon;
-
- if (isObject(icon)) {
- for (let size of Object.keys(icon)) {
- size = +size;
- let offset = targetSize - size;
-
- if (offset === 0) {
- bestSize = size;
- break;
- }
-
- let delta = Math.abs(offset) - Math.abs(targetSize - bestSize);
-
- if (delta < 0)
- bestSize = size;
- }
-
- image = icon[bestSize];
- }
-
- if (image.indexOf('./') === 0)
- return data.url(image.substr(2));
-
- return image;
-}
-
-function nodeFor(id, window=getMostRecentBrowserWindow()) {
- return customizedWindows.has(window) ? null : getNode(id, window);
-};
-exports.nodeFor = nodeFor;
-
-function create(options) {
- let { id, label, icon, type, badge } = options;
-
- if (views.has(id))
- throw new Error('The ID "' + id + '" seems already used.');
-
- CustomizableUI.createWidget({
- id: id,
- type: 'custom',
- removable: true,
- defaultArea: AREA_NAVBAR,
- allowedAreas: [ AREA_PANEL, AREA_NAVBAR ],
-
- onBuild: function(document) {
- let window = document.defaultView;
-
- let node = document.createElementNS(XUL_NS, 'toolbarbutton');
-
- let image = getImage(icon, true, window.devicePixelRatio);
-
- if (ignoreWindow(window))
- node.style.display = 'none';
-
- node.setAttribute('id', this.id);
- node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional badged-button');
- node.setAttribute('type', type);
- node.setAttribute('label', label);
- node.setAttribute('tooltiptext', label);
- node.setAttribute('image', image);
- node.setAttribute('constrain-size', 'true');
-
- views.set(id, {
- area: this.currentArea,
- icon: icon,
- label: label
- });
-
- node.addEventListener('command', function(event) {
- if (views.has(id)) {
- emit(viewEvents, 'data', {
- type: 'click',
- target: id,
- window: event.view,
- checked: node.checked
- });
- }
- });
-
- return node;
- }
- });
-};
-exports.create = create;
-
-function dispose(id) {
- if (!views.has(id)) return;
-
- views.delete(id);
- CustomizableUI.destroyWidget(id);
-}
-exports.dispose = dispose;
-
-function setIcon(id, window, icon) {
- let node = getNode(id, window);
-
- if (node) {
- icon = customizedWindows.has(window) ? views.get(id).icon : icon;
- let image = getImage(icon, isInToolbar(id), window.devicePixelRatio);
-
- node.setAttribute('image', image);
- }
-}
-exports.setIcon = setIcon;
-
-function setLabel(id, window, label) {
- let node = nodeFor(id, window);
-
- if (node) {
- node.setAttribute('label', label);
- node.setAttribute('tooltiptext', label);
- }
-}
-exports.setLabel = setLabel;
-
-function setDisabled(id, window, disabled) {
- let node = nodeFor(id, window);
-
- if (node)
- node.disabled = disabled;
-}
-exports.setDisabled = setDisabled;
-
-function setChecked(id, window, checked) {
- let node = nodeFor(id, window);
-
- if (node)
- node.checked = checked;
-}
-exports.setChecked = setChecked;
-
-function setBadge(id, window, badge, color) {
- let node = nodeFor(id, window);
-
- if (node) {
- // `Array.from` is needed to handle unicode symbol properly:
- // '𝐀𝐁'.length is 4 where Array.from('𝐀𝐁').length is 2
- let text = isNil(badge)
- ? ''
- : Array.from(String(badge)).slice(0, 4).join('');
-
- node.setAttribute('badge', text);
-
- let badgeNode = node.ownerDocument.getAnonymousElementByAttribute(node,
- 'class', 'toolbarbutton-badge');
-
- if (badgeNode)
- badgeNode.style.backgroundColor = isNil(color) ? '' : color;
- }
-}
-exports.setBadge = setBadge;
-
-function click(id) {
- let node = nodeFor(id);
-
- if (node)
- node.click();
-}
-exports.click = click;
diff --git a/addon-sdk/source/lib/sdk/ui/button/view/events.js b/addon-sdk/source/lib/sdk/ui/button/view/events.js
deleted file mode 100644
index 98909656a..000000000
--- a/addon-sdk/source/lib/sdk/ui/button/view/events.js
+++ /dev/null
@@ -1,18 +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',
- 'engines': {
- 'Firefox': '*',
- 'SeaMonkey': '*',
- 'Thunderbird': '*'
- }
-};
-
-var channel = {};
-
-exports.events = channel;
diff --git a/addon-sdk/source/lib/sdk/ui/component.js b/addon-sdk/source/lib/sdk/ui/component.js
deleted file mode 100644
index d1f12c95e..000000000
--- a/addon-sdk/source/lib/sdk/ui/component.js
+++ /dev/null
@@ -1,182 +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";
-
-// Internal properties not exposed to the public.
-const cache = Symbol("component/cache");
-const writer = Symbol("component/writer");
-const isFirstWrite = Symbol("component/writer/first-write?");
-const currentState = Symbol("component/state/current");
-const pendingState = Symbol("component/state/pending");
-const isWriting = Symbol("component/writing?");
-
-const isntNull = x => x !== null;
-
-const Component = function(options, children) {
- this[currentState] = null;
- this[pendingState] = null;
- this[writer] = null;
- this[cache] = null;
- this[isFirstWrite] = true;
-
- this[Component.construct](options, children);
-}
-Component.Component = Component;
-// Constructs component.
-Component.construct = Symbol("component/construct");
-// Called with `options` and `children` and must return
-// initial state back.
-Component.initial = Symbol("component/initial");
-
-// Function patches current `state` with a given update.
-Component.patch = Symbol("component/patch");
-// Function that replaces current `state` with a passed state.
-Component.reset = Symbol("component/reset");
-
-// Function that must return render tree from passed state.
-Component.render = Symbol("component/render");
-
-// Path of the component with in the mount point.
-Component.path = Symbol("component/path");
-
-Component.isMounted = component => !!component[writer];
-Component.isWriting = component => !!component[isWriting];
-
-// Internal method that mounts component to a writer.
-// Mounts component to a writer.
-Component.mount = (component, write) => {
- if (Component.isMounted(component)) {
- throw Error("Can not mount already mounted component");
- }
-
- component[writer] = write;
- Component.write(component);
-
- if (component[Component.mounted]) {
- component[Component.mounted]();
- }
-}
-
-// Unmounts component from a writer.
-Component.unmount = (component) => {
- if (Component.isMounted(component)) {
- component[writer] = null;
- if (component[Component.unmounted]) {
- component[Component.unmounted]();
- }
- } else {
- console.warn("Unmounting component that is not mounted is redundant");
- }
-};
- // Method invoked once after inital write occurs.
-Component.mounted = Symbol("component/mounted");
-// Internal method that unmounts component from the writer.
-Component.unmounted = Symbol("component/unmounted");
-// Function that must return true if component is changed
-Component.isUpdated = Symbol("component/updated?");
-Component.update = Symbol("component/update");
-Component.updated = Symbol("component/updated");
-
-const writeChild = base => (child, index) => Component.write(child, base, index)
-Component.write = (component, base, index) => {
- if (component === null) {
- return component;
- }
-
- if (!(component instanceof Component)) {
- const path = base ? `${base}${component.key || index}/` : `/`;
- return Object.assign({}, component, {
- [Component.path]: path,
- children: component.children && component.children.
- map(writeChild(path)).
- filter(isntNull)
- });
- }
-
- component[isWriting] = true;
-
- try {
-
- const current = component[currentState];
- const pending = component[pendingState] || current;
- const isUpdated = component[Component.isUpdated];
- const isInitial = component[isFirstWrite];
-
- if (isUpdated(current, pending) || isInitial) {
- if (!isInitial && component[Component.update]) {
- component[Component.update](pending, current)
- }
-
- // Note: [Component.update] could have caused more updates so can't use
- // `pending` as `component[pendingState]` may have changed.
- component[currentState] = component[pendingState] || current;
- component[pendingState] = null;
-
- const tree = component[Component.render](component[currentState]);
- component[cache] = Component.write(tree, base, index);
- if (component[writer]) {
- component[writer].call(null, component[cache]);
- }
-
- if (!isInitial && component[Component.updated]) {
- component[Component.updated](current, pending);
- }
- }
-
- component[isFirstWrite] = false;
-
- return component[cache];
- } finally {
- component[isWriting] = false;
- }
-};
-
-Component.prototype = Object.freeze({
- constructor: Component,
-
- [Component.mounted]: null,
- [Component.unmounted]: null,
- [Component.update]: null,
- [Component.updated]: null,
-
- get state() {
- return this[pendingState] || this[currentState];
- },
-
-
- [Component.construct](settings, items) {
- const initial = this[Component.initial];
- const base = initial(settings, items);
- const options = Object.assign(Object.create(null), base.options, settings);
- const children = base.children || items || null;
- const state = Object.assign(Object.create(null), base, {options, children});
- this[currentState] = state;
-
- if (this.setup) {
- this.setup(state);
- }
- },
- [Component.initial](options, children) {
- return Object.create(null);
- },
- [Component.patch](update) {
- this[Component.reset](Object.assign({}, this.state, update));
- },
- [Component.reset](state) {
- this[pendingState] = state;
- if (Component.isMounted(this) && !Component.isWriting(this)) {
- Component.write(this);
- }
- },
-
- [Component.isUpdated](before, after) {
- return before != after
- },
-
- [Component.render](state) {
- throw Error("Component must implement [Component.render] member");
- }
-});
-
-module.exports = Component;
diff --git a/addon-sdk/source/lib/sdk/ui/frame.js b/addon-sdk/source/lib/sdk/ui/frame.js
deleted file mode 100644
index 566353cdf..000000000
--- a/addon-sdk/source/lib/sdk/ui/frame.js
+++ /dev/null
@@ -1,16 +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",
- "engines": {
- "Firefox": "> 28"
- }
-};
-
-require("./frame/view");
-const { Frame } = require("./frame/model");
-
-exports.Frame = Frame;
diff --git a/addon-sdk/source/lib/sdk/ui/frame/model.js b/addon-sdk/source/lib/sdk/ui/frame/model.js
deleted file mode 100644
index 627310874..000000000
--- a/addon-sdk/source/lib/sdk/ui/frame/model.js
+++ /dev/null
@@ -1,154 +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",
- "engines": {
- "Firefox": "> 28"
- }
-};
-
-const { Class } = require("../../core/heritage");
-const { EventTarget } = require("../../event/target");
-const { emit, off, setListeners } = require("../../event/core");
-const { Reactor, foldp, send, merges } = require("../../event/utils");
-const { Disposable } = require("../../core/disposable");
-const { OutputPort } = require("../../output/system");
-const { InputPort } = require("../../input/system");
-const { identify } = require("../id");
-const { pairs, object, map, each } = require("../../util/sequence");
-const { patch, diff } = require("diffpatcher/index");
-const { isLocalURL } = require("../../url");
-const { compose } = require("../../lang/functional");
-const { contract } = require("../../util/contract");
-const { id: addonID, data: { url: resolve }} = require("../../self");
-const { Frames } = require("../../input/frame");
-
-
-const output = new OutputPort({ id: "frame-change" });
-const mailbox = new OutputPort({ id: "frame-mailbox" });
-const input = Frames;
-
-
-const makeID = url =>
- ("frame-" + addonID + "-" + url).
- split("/").join("-").
- split(".").join("-").
- replace(/[^A-Za-z0-9_\-]/g, "");
-
-const validate = contract({
- name: {
- is: ["string", "undefined"],
- ok: x => /^[a-z][a-z0-9-_]+$/i.test(x),
- msg: "The `option.name` must be a valid alphanumeric string (hyphens and " +
- "underscores are allowed) starting with letter."
- },
- url: {
- map: x => x.toString(),
- is: ["string"],
- ok: x => isLocalURL(x),
- msg: "The `options.url` must be a valid local URI."
- }
-});
-
-const Source = function({id, ownerID}) {
- this.id = id;
- this.ownerID = ownerID;
-};
-Source.postMessage = ({id, ownerID}, data, origin) => {
- send(mailbox, object([id, {
- inbox: {
- target: {id: id, ownerID: ownerID},
- timeStamp: Date.now(),
- data: data,
- origin: origin
- }
- }]));
-};
-Source.prototype.postMessage = function(data, origin) {
- Source.postMessage(this, data, origin);
-};
-
-const Message = function({type, data, source, origin, timeStamp}) {
- this.type = type;
- this.data = data;
- this.origin = origin;
- this.timeStamp = timeStamp;
- this.source = new Source(source);
-};
-
-
-const frames = new Map();
-const sources = new Map();
-
-const Frame = Class({
- extends: EventTarget,
- implements: [Disposable, Source],
- initialize: function(params={}) {
- const options = validate(params);
- const id = makeID(options.name || options.url);
-
- if (frames.has(id))
- throw Error("Frame with this id already exists: " + id);
-
- const initial = { id: id, url: resolve(options.url) };
- this.id = id;
-
- setListeners(this, params);
-
- frames.set(this.id, this);
-
- send(output, object([id, initial]));
- },
- get url() {
- const state = reactor.value[this.id];
- return state && state.url;
- },
- destroy: function() {
- send(output, object([this.id, null]));
- frames.delete(this.id);
- off(this);
- },
- // `JSON.stringify` serializes objects based of the return
- // value of this method. For convinienc we provide this method
- // to serialize actual state data.
- toJSON: function() {
- return { id: this.id, url: this.url };
- }
-});
-identify.define(Frame, frame => frame.id);
-
-exports.Frame = Frame;
-
-const reactor = new Reactor({
- onStep: (present, past) => {
- const delta = diff(past, present);
-
- each(([id, update]) => {
- const frame = frames.get(id);
- if (update) {
- if (!past[id])
- emit(frame, "register");
-
- if (update.outbox)
- emit(frame, "message", new Message(present[id].outbox));
-
- each(([ownerID, state]) => {
- const readyState = state ? state.readyState : "detach";
- const type = readyState === "loading" ? "attach" :
- readyState === "interactive" ? "ready" :
- readyState === "complete" ? "load" :
- readyState;
-
- // TODO: Cache `Source` instances somewhere to preserve
- // identity.
- emit(frame, type, {type: type,
- source: new Source({id: id, ownerID: ownerID})});
- }, pairs(update.owners));
- }
- }, pairs(delta));
- }
-});
-reactor.run(input);
diff --git a/addon-sdk/source/lib/sdk/ui/frame/view.html b/addon-sdk/source/lib/sdk/ui/frame/view.html
deleted file mode 100644
index 2a405b583..000000000
--- a/addon-sdk/source/lib/sdk/ui/frame/view.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <script>
- // HACK: This is not an ideal way to deliver chrome messages
- // to an inner frame content but seems only way that would
- // make `event.source` this (outer frame) window.
- window.onmessage = function(event) {
- var frame = document.querySelector("iframe");
- var content = frame.contentWindow;
- // If message is posted from chrome it has no `event.source`.
- if (event.source === null)
- content.postMessage(event.data, "*");
- };
- </script>
- </head>
- <body style="overflow: hidden"></body>
-</html>
diff --git a/addon-sdk/source/lib/sdk/ui/frame/view.js b/addon-sdk/source/lib/sdk/ui/frame/view.js
deleted file mode 100644
index 2eb4df2b7..000000000
--- a/addon-sdk/source/lib/sdk/ui/frame/view.js
+++ /dev/null
@@ -1,150 +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",
- "engines": {
- "Firefox": "> 28"
- }
-};
-
-const { Cu, Ci } = require("chrome");
-const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
-const { subscribe, send, Reactor, foldp, lift, merges, keepIf } = require("../../event/utils");
-const { InputPort } = require("../../input/system");
-const { OutputPort } = require("../../output/system");
-const { LastClosed } = require("../../input/browser");
-const { pairs, keys, object, each } = require("../../util/sequence");
-const { curry, compose } = require("../../lang/functional");
-const { getFrameElement, getOuterId,
- getByOuterId, getOwnerBrowserWindow } = require("../../window/utils");
-const { patch, diff } = require("diffpatcher/index");
-const { encode } = require("../../base64");
-const { Frames } = require("../../input/frame");
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-const HTML_NS = "http://www.w3.org/1999/xhtml";
-const OUTER_FRAME_URI = module.uri.replace(/\.js$/, ".html");
-
-const mailbox = new OutputPort({ id: "frame-mailbox" });
-
-const frameID = frame => frame.id.replace("outer-", "");
-const windowID = compose(getOuterId, getOwnerBrowserWindow);
-
-const getOuterFrame = (windowID, frameID) =>
- getByOuterId(windowID).document.getElementById("outer-" + frameID);
-
-const listener = ({target, source, data, origin, timeStamp}) => {
- // And sent received message to outbox so that frame API model
- // will deal with it.
- if (source && source !== target) {
- const frame = getFrameElement(target);
- const id = frameID(frame);
- send(mailbox, object([id, {
- outbox: {type: "message",
- source: {id: id, ownerID: windowID(frame)},
- data: data,
- origin: origin,
- timeStamp: timeStamp}}]));
- }
-};
-
-// Utility function used to create frame with a given `state` and
-// inject it into given `window`.
-const registerFrame = ({id, url}) => {
- CustomizableUI.createWidget({
- id: id,
- type: "custom",
- removable: true,
- onBuild: document => {
- let view = document.createElementNS(XUL_NS, "toolbaritem");
- view.setAttribute("id", id);
- view.setAttribute("flex", 2);
-
- let outerFrame = document.createElementNS(XUL_NS, "iframe");
- outerFrame.setAttribute("src", OUTER_FRAME_URI);
- outerFrame.setAttribute("id", "outer-" + id);
- outerFrame.setAttribute("data-is-sdk-outer-frame", true);
- outerFrame.setAttribute("type", "content");
- outerFrame.setAttribute("transparent", true);
- outerFrame.setAttribute("flex", 2);
- outerFrame.setAttribute("style", "overflow: hidden;");
- outerFrame.setAttribute("scrolling", "no");
- outerFrame.setAttribute("disablehistory", true);
- outerFrame.setAttribute("seamless", "seamless");
- outerFrame.addEventListener("load", function onload() {
- outerFrame.removeEventListener("load", onload, true);
-
- let doc = outerFrame.contentDocument;
-
- let innerFrame = doc.createElementNS(HTML_NS, "iframe");
- innerFrame.setAttribute("id", id);
- innerFrame.setAttribute("src", url);
- innerFrame.setAttribute("seamless", "seamless");
- innerFrame.setAttribute("sandbox", "allow-scripts");
- innerFrame.setAttribute("scrolling", "no");
- innerFrame.setAttribute("data-is-sdk-inner-frame", true);
- innerFrame.setAttribute("style", [ "border:none",
- "position:absolute", "width:100%", "top: 0",
- "left: 0", "overflow: hidden"].join(";"));
-
- doc.body.appendChild(innerFrame);
- }, true);
-
- view.appendChild(outerFrame);
-
- return view;
- }
- });
-};
-
-const unregisterFrame = CustomizableUI.destroyWidget;
-
-const deliverMessage = curry((frameID, data, windowID) => {
- const frame = getOuterFrame(windowID, frameID);
- const content = frame && frame.contentWindow;
-
- if (content)
- content.postMessage(data, content.location.origin);
-});
-
-const updateFrame = (id, {inbox, owners}, present) => {
- if (inbox) {
- const { data, target:{ownerID}, source } = present[id].inbox;
- if (ownerID)
- deliverMessage(id, data, ownerID);
- else
- each(deliverMessage(id, data), keys(present[id].owners));
- }
-
- each(setupView(id), pairs(owners));
-};
-
-const setupView = curry((frameID, [windowID, state]) => {
- if (state && state.readyState === "loading") {
- const frame = getOuterFrame(windowID, frameID);
- // Setup a message listener on contentWindow.
- frame.contentWindow.addEventListener("message", listener);
- }
-});
-
-
-const reactor = new Reactor({
- onStep: (present, past) => {
- const delta = diff(past, present);
-
- // Apply frame changes
- each(([id, update]) => {
- if (update === null)
- unregisterFrame(id);
- else if (past[id])
- updateFrame(id, update, present);
- else
- registerFrame(update);
- }, pairs(delta));
- },
- onEnd: state => each(unregisterFrame, keys(state))
-});
-reactor.run(Frames);
diff --git a/addon-sdk/source/lib/sdk/ui/id.js b/addon-sdk/source/lib/sdk/ui/id.js
deleted file mode 100644
index d17eb0a4e..000000000
--- a/addon-sdk/source/lib/sdk/ui/id.js
+++ /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';
-
-module.metadata = {
- 'stability': 'experimental'
-};
-
-const method = require('../../method/core');
-const { uuid } = require('../util/uuid');
-
-// NOTE: use lang/functional memoize when it is updated to use WeakMap
-function memoize(f) {
- const memo = new WeakMap();
-
- return function memoizer(o) {
- let key = o;
- if (!memo.has(key))
- memo.set(key, f.apply(this, arguments));
- return memo.get(key);
- };
-}
-
-var identify = method('identify');
-identify.define(Object, memoize(function() { return uuid(); }));
-exports.identify = identify;
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar.js b/addon-sdk/source/lib/sdk/ui/sidebar.js
deleted file mode 100644
index 59e35ea11..000000000
--- a/addon-sdk/source/lib/sdk/ui/sidebar.js
+++ /dev/null
@@ -1,311 +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',
- 'engines': {
- 'Firefox': '*'
- }
-};
-
-const { Class } = require('../core/heritage');
-const { merge } = require('../util/object');
-const { Disposable } = require('../core/disposable');
-const { off, emit, setListeners } = require('../event/core');
-const { EventTarget } = require('../event/target');
-const { URL } = require('../url');
-const { add, remove, has, clear, iterator } = require('../lang/weak-set');
-const { id: addonID, data } = require('../self');
-const { WindowTracker } = require('../deprecated/window-utils');
-const { isShowing } = require('./sidebar/utils');
-const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../window/utils');
-const { ns } = require('../core/namespace');
-const { remove: removeFromArray } = require('../util/array');
-const { show, hide, toggle } = require('./sidebar/actions');
-const { Worker } = require('../deprecated/sync-worker');
-const { contract: sidebarContract } = require('./sidebar/contract');
-const { create, dispose, updateTitle, updateURL, isSidebarShowing, showSidebar, hideSidebar } = require('./sidebar/view');
-const { defer } = require('../core/promise');
-const { models, views, viewsFor, modelFor } = require('./sidebar/namespace');
-const { isLocalURL } = require('../url');
-const { ensure } = require('../system/unload');
-const { identify } = require('./id');
-const { uuid } = require('../util/uuid');
-const { viewFor } = require('../view/core');
-
-const resolveURL = (url) => url ? data.url(url) : url;
-
-const sidebarNS = ns();
-
-const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
-
-var sidebars = {};
-
-const Sidebar = Class({
- implements: [ Disposable ],
- extends: EventTarget,
- setup: function(options) {
- // inital validation for the model information
- let model = sidebarContract(options);
-
- // save the model information
- models.set(this, model);
-
- // generate an id if one was not provided
- model.id = model.id || addonID + '-' + uuid();
-
- // further validation for the title and url
- validateTitleAndURLCombo({}, this.title, this.url);
-
- const self = this;
- const internals = sidebarNS(self);
- const windowNS = internals.windowNS = ns();
-
- // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=886148
- ensure(this, 'destroy');
-
- setListeners(this, options);
-
- let bars = [];
- internals.tracker = WindowTracker({
- onTrack: function(window) {
- if (!isBrowser(window))
- return;
-
- let sidebar = window.document.getElementById('sidebar');
- let sidebarBox = window.document.getElementById('sidebar-box');
-
- let bar = create(window, {
- id: self.id,
- title: self.title,
- sidebarurl: self.url
- });
- bars.push(bar);
- windowNS(window).bar = bar;
-
- bar.addEventListener('command', function() {
- if (isSidebarShowing(window, self)) {
- hideSidebar(window, self).catch(() => {});
- return;
- }
-
- showSidebar(window, self);
- }, false);
-
- function onSidebarLoad() {
- // check if the sidebar is ready
- let isReady = sidebar.docShell && sidebar.contentDocument;
- if (!isReady)
- return;
-
- // check if it is a web panel
- let panelBrowser = sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
- if (!panelBrowser) {
- bar.removeAttribute('checked');
- return;
- }
-
- let sbTitle = window.document.getElementById('sidebar-title');
- function onWebPanelSidebarCreated() {
- if (panelBrowser.contentWindow.location != resolveURL(model.url) ||
- sbTitle.value != model.title) {
- return;
- }
-
- let worker = windowNS(window).worker = Worker({
- window: panelBrowser.contentWindow,
- injectInDocument: true
- });
-
- function onWebPanelSidebarUnload() {
- windowNS(window).onWebPanelSidebarUnload = null;
-
- // uncheck the associated menuitem
- bar.setAttribute('checked', 'false');
-
- emit(self, 'hide', {});
- emit(self, 'detach', worker);
- windowNS(window).worker = null;
- }
- windowNS(window).onWebPanelSidebarUnload = onWebPanelSidebarUnload;
- panelBrowser.contentWindow.addEventListener('unload', onWebPanelSidebarUnload, true);
-
- // check the associated menuitem
- bar.setAttribute('checked', 'true');
-
- function onWebPanelSidebarReady() {
- panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', onWebPanelSidebarReady, false);
- windowNS(window).onWebPanelSidebarReady = null;
-
- emit(self, 'ready', worker);
- }
- windowNS(window).onWebPanelSidebarReady = onWebPanelSidebarReady;
- panelBrowser.contentWindow.addEventListener('DOMContentLoaded', onWebPanelSidebarReady, false);
-
- function onWebPanelSidebarLoad() {
- panelBrowser.contentWindow.removeEventListener('load', onWebPanelSidebarLoad, true);
- windowNS(window).onWebPanelSidebarLoad = null;
-
- // TODO: decide if returning worker is acceptable..
- //emit(self, 'show', { worker: worker });
- emit(self, 'show', {});
- }
- windowNS(window).onWebPanelSidebarLoad = onWebPanelSidebarLoad;
- panelBrowser.contentWindow.addEventListener('load', onWebPanelSidebarLoad, true);
-
- emit(self, 'attach', worker);
- }
- windowNS(window).onWebPanelSidebarCreated = onWebPanelSidebarCreated;
- panelBrowser.addEventListener('DOMWindowCreated', onWebPanelSidebarCreated, true);
- }
- windowNS(window).onSidebarLoad = onSidebarLoad;
- sidebar.addEventListener('load', onSidebarLoad, true); // removed properly
- },
- onUntrack: function(window) {
- if (!isBrowser(window))
- return;
-
- // hide the sidebar if it is showing
- hideSidebar(window, self).catch(() => {});
-
- // kill the menu item
- let { bar } = windowNS(window);
- if (bar) {
- removeFromArray(viewsFor(self), bar);
- dispose(bar);
- }
-
- // kill listeners
- let sidebar = window.document.getElementById('sidebar');
-
- if (windowNS(window).onSidebarLoad) {
- sidebar && sidebar.removeEventListener('load', windowNS(window).onSidebarLoad, true)
- windowNS(window).onSidebarLoad = null;
- }
-
- let panelBrowser = sidebar && sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
- if (windowNS(window).onWebPanelSidebarCreated) {
- panelBrowser && panelBrowser.removeEventListener('DOMWindowCreated', windowNS(window).onWebPanelSidebarCreated, true);
- windowNS(window).onWebPanelSidebarCreated = null;
- }
-
- if (windowNS(window).onWebPanelSidebarReady) {
- panelBrowser && panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', windowNS(window).onWebPanelSidebarReady, false);
- windowNS(window).onWebPanelSidebarReady = null;
- }
-
- if (windowNS(window).onWebPanelSidebarLoad) {
- panelBrowser && panelBrowser.contentWindow.removeEventListener('load', windowNS(window).onWebPanelSidebarLoad, true);
- windowNS(window).onWebPanelSidebarLoad = null;
- }
-
- if (windowNS(window).onWebPanelSidebarUnload) {
- panelBrowser && panelBrowser.contentWindow.removeEventListener('unload', windowNS(window).onWebPanelSidebarUnload, true);
- windowNS(window).onWebPanelSidebarUnload();
- }
- }
- });
-
- views.set(this, bars);
-
- add(sidebars, this);
- },
- get id() {
- return (modelFor(this) || {}).id;
- },
- get title() {
- return (modelFor(this) || {}).title;
- },
- set title(v) {
- // destroyed?
- if (!modelFor(this))
- return;
- // validation
- if (typeof v != 'string')
- throw Error('title must be a string');
- validateTitleAndURLCombo(this, v, this.url);
- // do update
- updateTitle(this, v);
- return modelFor(this).title = v;
- },
- get url() {
- return (modelFor(this) || {}).url;
- },
- set url(v) {
- // destroyed?
- if (!modelFor(this))
- return;
-
- // validation
- if (!isLocalURL(v))
- throw Error('the url must be a valid local url');
-
- validateTitleAndURLCombo(this, this.title, v);
-
- // do update
- updateURL(this, v);
- modelFor(this).url = v;
- },
- show: function(window) {
- return showSidebar(viewFor(window), this);
- },
- hide: function(window) {
- return hideSidebar(viewFor(window), this);
- },
- dispose: function() {
- const internals = sidebarNS(this);
-
- off(this);
-
- remove(sidebars, this);
-
- // stop tracking windows
- if (internals.tracker) {
- internals.tracker.unload();
- }
-
- internals.tracker = null;
- internals.windowNS = null;
-
- views.delete(this);
- models.delete(this);
- }
-});
-exports.Sidebar = Sidebar;
-
-function validateTitleAndURLCombo(sidebar, title, url) {
- url = resolveURL(url);
-
- if (sidebar.title == title && sidebar.url == url) {
- return false;
- }
-
- for (let window of windows(null, { includePrivate: true })) {
- let sidebar = window.document.querySelector('menuitem[sidebarurl="' + url + '"][label="' + title + '"]');
- if (sidebar) {
- throw Error('The provided title and url combination is invalid (already used).');
- }
- }
-
- return false;
-}
-
-isShowing.define(Sidebar, isSidebarShowing.bind(null, null));
-show.define(Sidebar, showSidebar.bind(null, null));
-hide.define(Sidebar, hideSidebar.bind(null, null));
-
-identify.define(Sidebar, function(sidebar) {
- return sidebar.id;
-});
-
-function toggleSidebar(window, sidebar) {
- // TODO: make sure this is not private
- window = window || getMostRecentBrowserWindow();
- if (isSidebarShowing(window, sidebar)) {
- return hideSidebar(window, sidebar);
- }
- return showSidebar(window, sidebar);
-}
-toggle.define(Sidebar, toggleSidebar.bind(null, null));
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar/actions.js b/addon-sdk/source/lib/sdk/ui/sidebar/actions.js
deleted file mode 100644
index 4a52984c9..000000000
--- a/addon-sdk/source/lib/sdk/ui/sidebar/actions.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';
-
-const method = require('../../../method/core');
-
-exports.show = method('show');
-exports.hide = method('hide');
-exports.toggle = method('toggle');
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar/contract.js b/addon-sdk/source/lib/sdk/ui/sidebar/contract.js
deleted file mode 100644
index b59c37c0b..000000000
--- a/addon-sdk/source/lib/sdk/ui/sidebar/contract.js
+++ /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 { contract } = require('../../util/contract');
-const { isValidURI, URL, isLocalURL } = require('../../url');
-const { isNil, isObject, isString } = require('../../lang/type');
-
-exports.contract = contract({
- id: {
- is: [ 'string', 'undefined' ],
- ok: v => /^[a-z0-9-_]+$/i.test(v),
- msg: 'The option "id" must be a valid alphanumeric id (hyphens and ' +
- 'underscores are allowed).'
- },
- title: {
- is: [ 'string' ],
- ok: v => v.length
- },
- url: {
- is: [ 'string' ],
- ok: v => isLocalURL(v),
- map: v => v.toString(),
- msg: 'The option "url" must be a valid local URI.'
- }
-});
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar/namespace.js b/addon-sdk/source/lib/sdk/ui/sidebar/namespace.js
deleted file mode 100644
index d79725d1a..000000000
--- a/addon-sdk/source/lib/sdk/ui/sidebar/namespace.js
+++ /dev/null
@@ -1,15 +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 models = exports.models = new WeakMap();
-const views = exports.views = new WeakMap();
-exports.buttons = new WeakMap();
-
-exports.viewsFor = function viewsFor(sidebar) {
- return views.get(sidebar);
-};
-exports.modelFor = function modelFor(sidebar) {
- return models.get(sidebar);
-};
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar/utils.js b/addon-sdk/source/lib/sdk/ui/sidebar/utils.js
deleted file mode 100644
index d6145c32e..000000000
--- a/addon-sdk/source/lib/sdk/ui/sidebar/utils.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 method = require('../../../method/core');
-
-exports.isShowing = method('isShowing');
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar/view.js b/addon-sdk/source/lib/sdk/ui/sidebar/view.js
deleted file mode 100644
index c91e69d3d..000000000
--- a/addon-sdk/source/lib/sdk/ui/sidebar/view.js
+++ /dev/null
@@ -1,214 +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',
- 'engines': {
- 'Firefox': '*'
- }
-};
-
-const { models, buttons, views, viewsFor, modelFor } = require('./namespace');
-const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../../window/utils');
-const { setStateFor } = require('../state');
-const { defer } = require('../../core/promise');
-const { isPrivateBrowsingSupported, data } = require('../../self');
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
-
-const resolveURL = (url) => url ? data.url(url) : url;
-
-function create(window, details) {
- let id = makeID(details.id);
- let { document } = window;
-
- if (document.getElementById(id))
- throw new Error('The ID "' + details.id + '" seems already used.');
-
- let menuitem = document.createElementNS(XUL_NS, 'menuitem');
- menuitem.setAttribute('id', id);
- menuitem.setAttribute('label', details.title);
- menuitem.setAttribute('sidebarurl', resolveURL(details.sidebarurl));
- menuitem.setAttribute('checked', 'false');
- menuitem.setAttribute('type', 'checkbox');
- menuitem.setAttribute('group', 'sidebar');
- menuitem.setAttribute('autoCheck', 'false');
-
- document.getElementById('viewSidebarMenu').appendChild(menuitem);
-
- return menuitem;
-}
-exports.create = create;
-
-function dispose(menuitem) {
- menuitem.parentNode.removeChild(menuitem);
-}
-exports.dispose = dispose;
-
-function updateTitle(sidebar, title) {
- let button = buttons.get(sidebar);
-
- for (let window of windows(null, { includePrivate: true })) {
- let { document } = window;
-
- // update the button
- if (button) {
- setStateFor(button, window, { label: title });
- }
-
- // update the menuitem
- let mi = document.getElementById(makeID(sidebar.id));
- if (mi) {
- mi.setAttribute('label', title)
- }
-
- // update sidebar, if showing
- if (isSidebarShowing(window, sidebar)) {
- document.getElementById('sidebar-title').setAttribute('value', title);
- }
- }
-}
-exports.updateTitle = updateTitle;
-
-function updateURL(sidebar, url) {
- let eleID = makeID(sidebar.id);
-
- url = resolveURL(url);
-
- for (let window of windows(null, { includePrivate: true })) {
- // update the menuitem
- let mi = window.document.getElementById(eleID);
- if (mi) {
- mi.setAttribute('sidebarurl', url)
- }
-
- // update sidebar, if showing
- if (isSidebarShowing(window, sidebar)) {
- showSidebar(window, sidebar, url);
- }
- }
-}
-exports.updateURL = updateURL;
-
-function isSidebarShowing(window, sidebar) {
- let win = window || getMostRecentBrowserWindow();
-
- // make sure there is a window
- if (!win) {
- return false;
- }
-
- // make sure there is a sidebar for the window
- let sb = win.document.getElementById('sidebar');
- let sidebarTitle = win.document.getElementById('sidebar-title');
- if (!(sb && sidebarTitle)) {
- return false;
- }
-
- // checks if the sidebar box is hidden
- let sbb = win.document.getElementById('sidebar-box');
- if (!sbb || sbb.hidden) {
- return false;
- }
-
- if (sidebarTitle.value == modelFor(sidebar).title) {
- let url = resolveURL(modelFor(sidebar).url);
-
- // checks if the sidebar is loading
- if (win.gWebPanelURI == url) {
- return true;
- }
-
- // checks if the sidebar loaded already
- let ele = sb.contentDocument && sb.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
- if (!ele) {
- return false;
- }
-
- if (ele.getAttribute('cachedurl') == url) {
- return true;
- }
-
- if (ele && ele.contentWindow && ele.contentWindow.location == url) {
- return true;
- }
- }
-
- // default
- return false;
-}
-exports.isSidebarShowing = isSidebarShowing;
-
-function showSidebar(window, sidebar, newURL) {
- window = window || getMostRecentBrowserWindow();
-
- let { promise, resolve, reject } = defer();
- let model = modelFor(sidebar);
-
- if (!newURL && isSidebarShowing(window, sidebar)) {
- resolve({});
- }
- else if (!isPrivateBrowsingSupported && isWindowPrivate(window)) {
- reject(Error('You cannot show a sidebar on private windows'));
- }
- else {
- sidebar.once('show', resolve);
-
- let menuitem = window.document.getElementById(makeID(model.id));
- menuitem.setAttribute('checked', true);
-
- window.openWebPanel(model.title, resolveURL(newURL || model.url));
- }
-
- return promise;
-}
-exports.showSidebar = showSidebar;
-
-
-function hideSidebar(window, sidebar) {
- window = window || getMostRecentBrowserWindow();
-
- let { promise, resolve, reject } = defer();
-
- if (!isSidebarShowing(window, sidebar)) {
- reject(Error('The sidebar is already hidden'));
- }
- else {
- sidebar.once('hide', resolve);
-
- // Below was taken from http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#4775
- // the code for window.todggleSideBar()..
- let { document } = window;
- let sidebarEle = document.getElementById('sidebar');
- let sidebarTitle = document.getElementById('sidebar-title');
- let sidebarBox = document.getElementById('sidebar-box');
- let sidebarSplitter = document.getElementById('sidebar-splitter');
- let commandID = sidebarBox.getAttribute('sidebarcommand');
- let sidebarBroadcaster = document.getElementById(commandID);
-
- sidebarBox.hidden = true;
- sidebarSplitter.hidden = true;
-
- sidebarEle.setAttribute('src', 'about:blank');
- //sidebarEle.docShell.createAboutBlankContentViewer(null);
-
- sidebarBroadcaster.removeAttribute('checked');
- sidebarBox.setAttribute('sidebarcommand', '');
- sidebarTitle.value = '';
- sidebarBox.hidden = true;
- sidebarSplitter.hidden = true;
-
- // TODO: perhaps this isn't necessary if the window is not most recent?
- window.gBrowser.selectedBrowser.focus();
- }
-
- return promise;
-}
-exports.hideSidebar = hideSidebar;
-
-function makeID(id) {
- return 'jetpack-sidebar-' + id;
-}
diff --git a/addon-sdk/source/lib/sdk/ui/state.js b/addon-sdk/source/lib/sdk/ui/state.js
deleted file mode 100644
index 152ce696d..000000000
--- a/addon-sdk/source/lib/sdk/ui/state.js
+++ /dev/null
@@ -1,239 +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';
-
-// The Button module currently supports only Firefox.
-// See: https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps
-module.metadata = {
- 'stability': 'experimental',
- 'engines': {
- 'Firefox': '*',
- 'SeaMonkey': '*',
- 'Thunderbird': '*'
- }
-};
-
-const { Ci } = require('chrome');
-
-const events = require('../event/utils');
-const { events: browserEvents } = require('../browser/events');
-const { events: tabEvents } = require('../tab/events');
-const { events: stateEvents } = require('./state/events');
-
-const { windows, isInteractive, getFocusedBrowser } = require('../window/utils');
-const { getActiveTab, getOwnerWindow } = require('../tabs/utils');
-
-const { ignoreWindow } = require('../private-browsing/utils');
-
-const { freeze } = Object;
-const { merge } = require('../util/object');
-const { on, off, emit } = require('../event/core');
-
-const { add, remove, has, clear, iterator } = require('../lang/weak-set');
-const { isNil } = require('../lang/type');
-
-const { viewFor } = require('../view/core');
-
-const components = new WeakMap();
-
-const ERR_UNREGISTERED = 'The state cannot be set or get. ' +
- 'The object may be not be registered, or may already have been unloaded.';
-
-const ERR_INVALID_TARGET = 'The state cannot be set or get for this target.' +
- 'Only window, tab and registered component are valid targets.';
-
-const isWindow = thing => thing instanceof Ci.nsIDOMWindow;
-const isTab = thing => thing.tagName && thing.tagName.toLowerCase() === 'tab';
-const isActiveTab = thing => isTab(thing) && thing === getActiveTab(getOwnerWindow(thing));
-const isEnumerable = window => !ignoreWindow(window);
-const browsers = _ =>
- windows('navigator:browser', { includePrivate: true }).filter(isInteractive);
-const getMostRecentTab = _ => getActiveTab(getFocusedBrowser());
-
-function getStateFor(component, target) {
- if (!isRegistered(component))
- throw new Error(ERR_UNREGISTERED);
-
- if (!components.has(component))
- return null;
-
- let states = components.get(component);
-
- if (target) {
- if (isTab(target) || isWindow(target) || target === component)
- return states.get(target) || null;
- else
- throw new Error(ERR_INVALID_TARGET);
- }
-
- return null;
-}
-exports.getStateFor = getStateFor;
-
-function getDerivedStateFor(component, target) {
- if (!isRegistered(component))
- throw new Error(ERR_UNREGISTERED);
-
- if (!components.has(component))
- return null;
-
- let states = components.get(component);
-
- let componentState = states.get(component);
- let windowState = null;
- let tabState = null;
-
- if (target) {
- // has a target
- if (isTab(target)) {
- windowState = states.get(getOwnerWindow(target), null);
-
- if (states.has(target)) {
- // we have a tab state
- tabState = states.get(target);
- }
- }
- else if (isWindow(target) && states.has(target)) {
- // we have a window state
- windowState = states.get(target);
- }
- }
-
- return freeze(merge({}, componentState, windowState, tabState));
-}
-exports.getDerivedStateFor = getDerivedStateFor;
-
-function setStateFor(component, target, state) {
- if (!isRegistered(component))
- throw new Error(ERR_UNREGISTERED);
-
- let isComponentState = target === component;
- let targetWindows = isWindow(target) ? [target] :
- isActiveTab(target) ? [getOwnerWindow(target)] :
- isComponentState ? browsers() :
- isTab(target) ? [] :
- null;
-
- if (!targetWindows)
- throw new Error(ERR_INVALID_TARGET);
-
- // initialize the state's map
- if (!components.has(component))
- components.set(component, new WeakMap());
-
- let states = components.get(component);
-
- if (state === null && !isComponentState) // component state can't be deleted
- states.delete(target);
- else {
- let base = isComponentState ? states.get(target) : null;
- states.set(target, freeze(merge({}, base, state)));
- }
-
- render(component, targetWindows);
-}
-exports.setStateFor = setStateFor;
-
-function render(component, targetWindows) {
- targetWindows = targetWindows ? [].concat(targetWindows) : browsers();
-
- for (let window of targetWindows.filter(isEnumerable)) {
- let tabState = getDerivedStateFor(component, getActiveTab(window));
-
- emit(stateEvents, 'data', {
- type: 'render',
- target: component,
- window: window,
- state: tabState
- });
-
- }
-}
-exports.render = render;
-
-function properties(contract) {
- let { rules } = contract;
- let descriptor = Object.keys(rules).reduce(function(descriptor, name) {
- descriptor[name] = {
- get: function() { return getDerivedStateFor(this)[name] },
- set: function(value) {
- let changed = {};
- changed[name] = value;
-
- setStateFor(this, this, contract(changed));
- }
- }
- return descriptor;
- }, {});
-
- return Object.create(Object.prototype, descriptor);
-}
-exports.properties = properties;
-
-function state(contract) {
- return {
- state: function state(target, state) {
- let nativeTarget = target === 'window' ? getFocusedBrowser()
- : target === 'tab' ? getMostRecentTab()
- : target === this ? null
- : viewFor(target);
-
- if (!nativeTarget && target !== this && !isNil(target))
- throw new Error(ERR_INVALID_TARGET);
-
- target = nativeTarget || target;
-
- // jquery style
- return arguments.length < 2
- ? getDerivedStateFor(this, target)
- : setStateFor(this, target, contract(state))
- }
- }
-}
-exports.state = state;
-
-const register = (component, state) => {
- add(components, component);
- setStateFor(component, component, state);
-}
-exports.register = register;
-
-const unregister = component => {
- remove(components, component);
-}
-exports.unregister = unregister;
-
-const isRegistered = component => has(components, component);
-exports.isRegistered = isRegistered;
-
-var tabSelect = events.filter(tabEvents, e => e.type === 'TabSelect');
-var tabClose = events.filter(tabEvents, e => e.type === 'TabClose');
-var windowOpen = events.filter(browserEvents, e => e.type === 'load');
-var windowClose = events.filter(browserEvents, e => e.type === 'close');
-
-var close = events.merge([tabClose, windowClose]);
-var activate = events.merge([windowOpen, tabSelect]);
-
-on(activate, 'data', ({target}) => {
- let [window, tab] = isWindow(target)
- ? [target, getActiveTab(target)]
- : [getOwnerWindow(target), target];
-
- if (ignoreWindow(window)) return;
-
- for (let component of iterator(components)) {
- emit(stateEvents, 'data', {
- type: 'render',
- target: component,
- window: window,
- state: getDerivedStateFor(component, tab)
- });
- }
-});
-
-on(close, 'data', function({target}) {
- for (let component of iterator(components)) {
- components.get(component).delete(target);
- }
-});
diff --git a/addon-sdk/source/lib/sdk/ui/state/events.js b/addon-sdk/source/lib/sdk/ui/state/events.js
deleted file mode 100644
index 98909656a..000000000
--- a/addon-sdk/source/lib/sdk/ui/state/events.js
+++ /dev/null
@@ -1,18 +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',
- 'engines': {
- 'Firefox': '*',
- 'SeaMonkey': '*',
- 'Thunderbird': '*'
- }
-};
-
-var channel = {};
-
-exports.events = channel;
diff --git a/addon-sdk/source/lib/sdk/ui/toolbar.js b/addon-sdk/source/lib/sdk/ui/toolbar.js
deleted file mode 100644
index c1becab2d..000000000
--- a/addon-sdk/source/lib/sdk/ui/toolbar.js
+++ /dev/null
@@ -1,16 +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",
- "engines": {
- "Firefox": "> 28"
- }
-};
-
-const { Toolbar } = require("./toolbar/model");
-require("./toolbar/view");
-
-exports.Toolbar = Toolbar;
diff --git a/addon-sdk/source/lib/sdk/ui/toolbar/model.js b/addon-sdk/source/lib/sdk/ui/toolbar/model.js
deleted file mode 100644
index 5c5428606..000000000
--- a/addon-sdk/source/lib/sdk/ui/toolbar/model.js
+++ /dev/null
@@ -1,151 +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",
- "engines": {
- "Firefox": "> 28"
- }
-};
-
-const { Class } = require("../../core/heritage");
-const { EventTarget } = require("../../event/target");
-const { off, setListeners, emit } = require("../../event/core");
-const { Reactor, foldp, merges, send } = require("../../event/utils");
-const { Disposable } = require("../../core/disposable");
-const { InputPort } = require("../../input/system");
-const { OutputPort } = require("../../output/system");
-const { identify } = require("../id");
-const { pairs, object, map, each } = require("../../util/sequence");
-const { patch, diff } = require("diffpatcher/index");
-const { contract } = require("../../util/contract");
-const { id: addonID } = require("../../self");
-
-// Input state is accumulated from the input received form the toolbar
-// view code & local output. Merging local output reflects local state
-// changes without complete roundloop.
-const input = foldp(patch, {}, new InputPort({ id: "toolbar-changed" }));
-const output = new OutputPort({ id: "toolbar-change" });
-
-// Takes toolbar title and normalizes is to an
-// identifier, also prefixes with add-on id.
-const titleToId = title =>
- ("toolbar-" + addonID + "-" + title).
- toLowerCase().
- replace(/\s/g, "-").
- replace(/[^A-Za-z0-9_\-]/g, "");
-
-const validate = contract({
- title: {
- is: ["string"],
- ok: x => x.length > 0,
- msg: "The `option.title` string must be provided"
- },
- items: {
- is:["undefined", "object", "array"],
- msg: "The `options.items` must be iterable sequence of items"
- },
- hidden: {
- is: ["boolean", "undefined"],
- msg: "The `options.hidden` must be boolean"
- }
-});
-
-// Toolbars is a mapping between `toolbar.id` & `toolbar` instances,
-// which is used to find intstance for dispatching events.
-var toolbars = new Map();
-
-const Toolbar = Class({
- extends: EventTarget,
- implements: [Disposable],
- initialize: function(params={}) {
- const options = validate(params);
- const id = titleToId(options.title);
-
- if (toolbars.has(id))
- throw Error("Toolbar with this id already exists: " + id);
-
- // Set of the items in the toolbar isn't mutable, as a matter of fact
- // it just defines desired set of items, actual set is under users
- // control. Conver test to an array and freeze to make sure users won't
- // try mess with it.
- const items = Object.freeze(options.items ? [...options.items] : []);
-
- const initial = {
- id: id,
- title: options.title,
- // By default toolbars are visible when add-on is installed, unless
- // add-on authors decides it should be hidden. From that point on
- // user is in control.
- collapsed: !!options.hidden,
- // In terms of state only identifiers of items matter.
- items: items.map(identify)
- };
-
- this.id = id;
- this.items = items;
-
- toolbars.set(id, this);
- setListeners(this, params);
-
- // Send initial state to the host so it can reflect it
- // into a user interface.
- send(output, object([id, initial]));
- },
-
- get title() {
- const state = reactor.value[this.id];
- return state && state.title;
- },
- get hidden() {
- const state = reactor.value[this.id];
- return state && state.collapsed;
- },
-
- destroy: function() {
- send(output, object([this.id, null]));
- },
- // `JSON.stringify` serializes objects based of the return
- // value of this method. For convinienc we provide this method
- // to serialize actual state data. Note: items will also be
- // serialized so they should probably implement `toJSON`.
- toJSON: function() {
- return {
- id: this.id,
- title: this.title,
- hidden: this.hidden,
- items: this.items
- };
- }
-});
-exports.Toolbar = Toolbar;
-identify.define(Toolbar, toolbar => toolbar.id);
-
-const dispose = toolbar => {
- toolbars.delete(toolbar.id);
- emit(toolbar, "detach");
- off(toolbar);
-};
-
-const reactor = new Reactor({
- onStep: (present, past) => {
- const delta = diff(past, present);
-
- each(([id, update]) => {
- const toolbar = toolbars.get(id);
-
- // Remove
- if (!update)
- dispose(toolbar);
- // Add
- else if (!past[id])
- emit(toolbar, "attach");
- // Update
- else
- emit(toolbar, update.collapsed ? "hide" : "show", toolbar);
- }, pairs(delta));
- }
-});
-reactor.run(input);
diff --git a/addon-sdk/source/lib/sdk/ui/toolbar/view.js b/addon-sdk/source/lib/sdk/ui/toolbar/view.js
deleted file mode 100644
index 4ef0c3d46..000000000
--- a/addon-sdk/source/lib/sdk/ui/toolbar/view.js
+++ /dev/null
@@ -1,248 +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",
- "engines": {
- "Firefox": "> 28"
- }
-};
-
-const { Cu } = require("chrome");
-const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
-const { subscribe, send, Reactor, foldp, lift, merges } = require("../../event/utils");
-const { InputPort } = require("../../input/system");
-const { OutputPort } = require("../../output/system");
-const { Interactive } = require("../../input/browser");
-const { CustomizationInput } = require("../../input/customizable-ui");
-const { pairs, map, isEmpty, object,
- each, keys, values } = require("../../util/sequence");
-const { curry, flip } = require("../../lang/functional");
-const { patch, diff } = require("diffpatcher/index");
-const prefs = require("../../preferences/service");
-const { getByOuterId } = require("../../window/utils");
-const { ignoreWindow } = require('../../private-browsing/utils');
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-const PREF_ROOT = "extensions.sdk-toolbar-collapsed.";
-
-
-// There are two output ports one for publishing changes that occured
-// and the other for change requests. Later is synchronous and is only
-// consumed here. Note: it needs to be synchronous to avoid race conditions
-// when `collapsed` attribute changes are caused by user interaction and
-// toolbar is destroyed between the ticks.
-const output = new OutputPort({ id: "toolbar-changed" });
-const syncoutput = new OutputPort({ id: "toolbar-change", sync: true });
-
-// Merge disptached changes and recevied changes from models to keep state up to
-// date.
-const Toolbars = foldp(patch, {}, merges([new InputPort({ id: "toolbar-changed" }),
- new InputPort({ id: "toolbar-change" })]));
-const State = lift((toolbars, windows, customizable) =>
- ({windows: windows, toolbars: toolbars, customizable: customizable}),
- Toolbars, Interactive, new CustomizationInput());
-
-// Shared event handler that makes `event.target.parent` collapsed.
-// Used as toolbar's close buttons click handler.
-const collapseToolbar = event => {
- const toolbar = event.target.parentNode;
- toolbar.collapsed = true;
-};
-
-const parseAttribute = x =>
- x === "true" ? true :
- x === "false" ? false :
- x === "" ? null :
- x;
-
-// Shared mutation observer that is used to observe `toolbar` node's
-// attribute mutations. Mutations are aggregated in the `delta` hash
-// and send to `ToolbarStateChanged` channel to let model know state
-// has changed.
-const attributesChanged = mutations => {
- const delta = mutations.reduce((changes, {attributeName, target}) => {
- const id = target.id;
- const field = attributeName === "toolbarname" ? "title" : attributeName;
- let change = changes[id] || (changes[id] = {});
- change[field] = parseAttribute(target.getAttribute(attributeName));
- return changes;
- }, {});
-
- // Calculate what are the updates from the current state and if there are
- // any send them.
- const updates = diff(reactor.value, patch(reactor.value, delta));
-
- if (!isEmpty(pairs(updates))) {
- // TODO: Consider sending sync to make sure that there won't be a new
- // update doing a delete in the meantime.
- send(syncoutput, updates);
- }
-};
-
-
-// Utility function creates `toolbar` with a "close" button and returns
-// it back. In addition it set's up a listener and observer to communicate
-// state changes.
-const addView = curry((options, {document, window}) => {
- if (ignoreWindow(window))
- return;
-
- let view = document.createElementNS(XUL_NS, "toolbar");
- view.setAttribute("id", options.id);
- view.setAttribute("collapsed", options.collapsed);
- view.setAttribute("toolbarname", options.title);
- view.setAttribute("pack", "end");
- view.setAttribute("customizable", "false");
- view.setAttribute("style", "padding: 2px 0; max-height: 40px;");
- view.setAttribute("mode", "icons");
- view.setAttribute("iconsize", "small");
- view.setAttribute("context", "toolbar-context-menu");
- view.setAttribute("class", "chromeclass-toolbar");
-
- let label = document.createElementNS(XUL_NS, "label");
- label.setAttribute("value", options.title);
- label.setAttribute("collapsed", "true");
- view.appendChild(label);
-
- let closeButton = document.createElementNS(XUL_NS, "toolbarbutton");
- closeButton.setAttribute("id", "close-" + options.id);
- closeButton.setAttribute("class", "close-icon");
- closeButton.setAttribute("customizable", false);
- closeButton.addEventListener("command", collapseToolbar);
-
- view.appendChild(closeButton);
-
- // In order to have a close button not costumizable, aligned on the right,
- // leaving the customizable capabilities of Australis, we need to create
- // a toolbar inside a toolbar.
- // This is should be a temporary hack, we should have a proper XBL for toolbar
- // instead. See:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=982005
- let toolbar = document.createElementNS(XUL_NS, "toolbar");
- toolbar.setAttribute("id", "inner-" + options.id);
- toolbar.setAttribute("defaultset", options.items.join(","));
- toolbar.setAttribute("customizable", "true");
- toolbar.setAttribute("style", "-moz-appearance: none; overflow: hidden");
- toolbar.setAttribute("mode", "icons");
- toolbar.setAttribute("iconsize", "small");
- toolbar.setAttribute("context", "toolbar-context-menu");
- toolbar.setAttribute("flex", "1");
-
- view.insertBefore(toolbar, closeButton);
-
- const observer = new document.defaultView.MutationObserver(attributesChanged);
- observer.observe(view, { attributes: true,
- attributeFilter: ["collapsed", "toolbarname"] });
-
- const toolbox = document.getElementById("navigator-toolbox");
- toolbox.appendChild(view);
-});
-const viewAdd = curry(flip(addView));
-
-const removeView = curry((id, {document}) => {
- const view = document.getElementById(id);
- if (view) view.remove();
-});
-
-const updateView = curry((id, {title, collapsed, isCustomizing}, {document}) => {
- const view = document.getElementById(id);
-
- if (!view)
- return;
-
- if (title)
- view.setAttribute("toolbarname", title);
-
- if (collapsed !== void(0))
- view.setAttribute("collapsed", Boolean(collapsed));
-
- if (isCustomizing !== void(0)) {
- view.querySelector("label").collapsed = !isCustomizing;
- view.querySelector("toolbar").style.visibility = isCustomizing
- ? "hidden" : "visible";
- }
-});
-
-const viewUpdate = curry(flip(updateView));
-
-// Utility function used to register toolbar into CustomizableUI.
-const registerToolbar = state => {
- // If it's first additon register toolbar as customizableUI component.
- CustomizableUI.registerArea("inner-" + state.id, {
- type: CustomizableUI.TYPE_TOOLBAR,
- legacy: true,
- defaultPlacements: [...state.items]
- });
-};
-// Utility function used to unregister toolbar from the CustomizableUI.
-const unregisterToolbar = CustomizableUI.unregisterArea;
-
-const reactor = new Reactor({
- onStep: (present, past) => {
- const delta = diff(past, present);
-
- each(([id, update]) => {
- // If update is `null` toolbar is removed, in such case
- // we unregister toolbar and remove it from each window
- // it was added to.
- if (update === null) {
- unregisterToolbar("inner-" + id);
- each(removeView(id), values(past.windows));
-
- send(output, object([id, null]));
- }
- else if (past.toolbars[id]) {
- // If `collapsed` state for toolbar was updated, persist
- // it for a future sessions.
- if (update.collapsed !== void(0))
- prefs.set(PREF_ROOT + id, update.collapsed);
-
- // Reflect update in each window it was added to.
- each(updateView(id, update), values(past.windows));
-
- send(output, object([id, update]));
- }
- // Hack: Mutation observers are invoked async, which means that if
- // client does `hide(toolbar)` & then `toolbar.destroy()` by the
- // time we'll get update for `collapsed` toolbar will be removed.
- // For now we check if `update.id` is present which will be undefined
- // in such cases.
- else if (update.id) {
- // If it is a new toolbar we create initial state by overriding
- // `collapsed` filed with value persisted in previous sessions.
- const state = patch(update, {
- collapsed: prefs.get(PREF_ROOT + id, update.collapsed),
- });
-
- // Register toolbar and add it each window known in the past
- // (note that new windows if any will be handled in loop below).
- registerToolbar(state);
- each(addView(state), values(past.windows));
-
- send(output, object([state.id, state]));
- }
- }, pairs(delta.toolbars));
-
- // Add views to every window that was added.
- each(window => {
- if (window)
- each(viewAdd(window), values(past.toolbars));
- }, values(delta.windows));
-
- each(([id, isCustomizing]) => {
- each(viewUpdate(getByOuterId(id), {isCustomizing: !!isCustomizing}),
- keys(present.toolbars));
-
- }, pairs(delta.customizable))
- },
- onEnd: state => {
- each(id => {
- unregisterToolbar("inner-" + id);
- each(removeView(id), values(state.windows));
- }, keys(state.toolbars));
- }
-});
-reactor.run(State);
diff --git a/addon-sdk/source/lib/sdk/uri/resource.js b/addon-sdk/source/lib/sdk/uri/resource.js
deleted file mode 100644
index 8a1dcbf2c..000000000
--- a/addon-sdk/source/lib/sdk/uri/resource.js
+++ /dev/null
@@ -1,37 +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 {Cc, Ci} = require("chrome");
-const ioService = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
-const resourceHandler = ioService.getProtocolHandler("resource").
- QueryInterface(Ci.nsIResProtocolHandler);
-
-const URI = (uri, base=null) =>
- ioService.newURI(uri, null, base && URI(base))
-
-const mount = (domain, uri) =>
- resourceHandler.setSubstitution(domain, ioService.newURI(uri, null, null));
-exports.mount = mount;
-
-const unmount = (domain, uri) =>
- resourceHandler.setSubstitution(domain, null);
-exports.unmount = unmount;
-
-const domain = 1;
-const path = 2;
-const resolve = (uri) => {
- const match = /resource\:\/\/([^\/]+)\/{0,1}([\s\S]*)/.exec(uri);
- const domain = match && match[1];
- const path = match && match[2];
- return !match ? null :
- !resourceHandler.hasSubstitution(domain) ? null :
- resourceHandler.resolveURI(URI(`/${path}`, `resource://${domain}/`));
-}
-exports.resolve = resolve;
diff --git a/addon-sdk/source/lib/sdk/url.js b/addon-sdk/source/lib/sdk/url.js
deleted file mode 100644
index ae16ac4a8..000000000
--- a/addon-sdk/source/lib/sdk/url.js
+++ /dev/null
@@ -1,349 +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, Cr, Cu } = require("chrome");
-
-const { Class } = require("./core/heritage");
-const base64 = require("./base64");
-var tlds = Cc["@mozilla.org/network/effective-tld-service;1"]
- .getService(Ci.nsIEffectiveTLDService);
-
-var ios = Cc['@mozilla.org/network/io-service;1']
- .getService(Ci.nsIIOService);
-
-var resProt = ios.getProtocolHandler("resource")
- .QueryInterface(Ci.nsIResProtocolHandler);
-
-var URLParser = Cc["@mozilla.org/network/url-parser;1?auth=no"]
- .getService(Ci.nsIURLParser);
-
-const { Services } = Cu.import("resource://gre/modules/Services.jsm");
-
-function newURI(uriStr, base) {
- try {
- let baseURI = base ? ios.newURI(base, null, null) : null;
- return ios.newURI(uriStr, null, baseURI);
- }
- catch (e) {
- if (e.result == Cr.NS_ERROR_MALFORMED_URI) {
- throw new Error("malformed URI: " + uriStr);
- }
- if (e.result == Cr.NS_ERROR_FAILURE ||
- e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
- throw new Error("invalid URI: " + uriStr);
- }
- }
-}
-
-function resolveResourceURI(uri) {
- var resolved;
- try {
- resolved = resProt.resolveURI(uri);
- }
- catch (e) {
- if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
- throw new Error("resource does not exist: " + uri.spec);
- }
- }
- return resolved;
-}
-
-var fromFilename = exports.fromFilename = function fromFilename(path) {
- var file = Cc['@mozilla.org/file/local;1']
- .createInstance(Ci.nsILocalFile);
- file.initWithPath(path);
- return ios.newFileURI(file).spec;
-};
-
-var toFilename = exports.toFilename = function toFilename(url) {
- var uri = newURI(url);
- if (uri.scheme == "resource")
- uri = newURI(resolveResourceURI(uri));
- if (uri.scheme == "chrome") {
- var channel = ios.newChannelFromURI2(uri,
- null, // aLoadingNode
- Services.scriptSecurityManager.getSystemPrincipal(),
- null, // aTriggeringPrincipal
- Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
- Ci.nsIContentPolicy.TYPE_OTHER);
- try {
- channel = channel.QueryInterface(Ci.nsIFileChannel);
- return channel.file.path;
- }
- catch (e) {
- if (e.result == Cr.NS_NOINTERFACE) {
- throw new Error("chrome url isn't on filesystem: " + url);
- }
- }
- }
- if (uri.scheme == "file") {
- var file = uri.QueryInterface(Ci.nsIFileURL).file;
- return file.path;
- }
- throw new Error("cannot map to filename: " + url);
-};
-
-function URL(url, base) {
- if (!(this instanceof URL)) {
- return new URL(url, base);
- }
-
- var uri = newURI(url, base);
-
- var userPass = null;
- try {
- userPass = uri.userPass ? uri.userPass : null;
- }
- catch (e) {
- if (e.result != Cr.NS_ERROR_FAILURE) {
- throw e;
- }
- }
-
- var host = null;
- try {
- host = uri.host;
- }
- catch (e) {
- if (e.result != Cr.NS_ERROR_FAILURE) {
- throw e;
- }
- }
-
- var port = null;
- try {
- port = uri.port == -1 ? null : uri.port;
- }
- catch (e) {
- if (e.result != Cr.NS_ERROR_FAILURE) {
- throw e;
- }
- }
-
- let fileName = "/";
- try {
- fileName = uri.QueryInterface(Ci.nsIURL).fileName;
- } catch (e) {
- if (e.result != Cr.NS_NOINTERFACE) {
- throw e;
- }
- }
-
- let uriData = [uri.path, uri.path.length, {}, {}, {}, {}, {}, {}];
- URLParser.parsePath.apply(URLParser, uriData);
- let [{ value: filepathPos }, { value: filepathLen },
- { value: queryPos }, { value: queryLen },
- { value: refPos }, { value: refLen }] = uriData.slice(2);
-
- let hash = uri.ref ? "#" + uri.ref : "";
- let pathname = uri.path.substr(filepathPos, filepathLen);
- let search = uri.path.substr(queryPos, queryLen);
- search = search ? "?" + search : "";
-
- this.__defineGetter__("fileName", () => fileName);
- this.__defineGetter__("scheme", () => uri.scheme);
- this.__defineGetter__("userPass", () => userPass);
- this.__defineGetter__("host", () => host);
- this.__defineGetter__("hostname", () => host);
- this.__defineGetter__("port", () => port);
- this.__defineGetter__("path", () => uri.path);
- this.__defineGetter__("pathname", () => pathname);
- this.__defineGetter__("hash", () => hash);
- this.__defineGetter__("href", () => uri.spec);
- this.__defineGetter__("origin", () => uri.prePath);
- this.__defineGetter__("protocol", () => uri.scheme + ":");
- this.__defineGetter__("search", () => search);
-
- Object.defineProperties(this, {
- toString: {
- value() {
- return new String(uri.spec).toString();
- },
- enumerable: false
- },
- valueOf: {
- value() {
- return new String(uri.spec).valueOf();
- },
- enumerable: false
- },
- toSource: {
- value() {
- return new String(uri.spec).toSource();
- },
- enumerable: false
- },
- // makes more sense to flatten to string, easier to travel across JSON
- toJSON: {
- value() {
- return new String(uri.spec).toString();
- },
- enumerable: false
- }
- });
-
- return this;
-};
-
-URL.prototype = Object.create(String.prototype);
-exports.URL = URL;
-
-/**
- * Parse and serialize a Data URL.
- *
- * See: http://tools.ietf.org/html/rfc2397
- *
- * Note: Could be extended in the future to decode / encode automatically binary
- * data.
- */
-const DataURL = Class({
-
- get base64 () {
- return "base64" in this.parameters;
- },
-
- set base64 (value) {
- if (value)
- this.parameters["base64"] = "";
- else
- delete this.parameters["base64"];
- },
- /**
- * Initialize the Data URL object. If a uri is given, it will be parsed.
- *
- * @param {String} [uri] The uri to parse
- *
- * @throws {URIError} if the Data URL is malformed
- */
- initialize: function(uri) {
- // Due to bug 751834 it is not possible document and define these
- // properties in the prototype.
-
- /**
- * An hashmap that contains the parameters of the Data URL. By default is
- * empty, that accordingly to RFC is equivalent to {"charset" : "US-ASCII"}
- */
- this.parameters = {};
-
- /**
- * The MIME type of the data. By default is empty, that accordingly to RFC
- * is equivalent to "text/plain"
- */
- this.mimeType = "";
-
- /**
- * The string that represent the data in the Data URL
- */
- this.data = "";
-
- if (typeof uri === "undefined")
- return;
-
- uri = String(uri);
-
- let matches = uri.match(/^data:([^,]*),(.*)$/i);
-
- if (!matches)
- throw new URIError("Malformed Data URL: " + uri);
-
- let mediaType = matches[1].trim();
-
- this.data = decodeURIComponent(matches[2].trim());
-
- if (!mediaType)
- return;
-
- let parametersList = mediaType.split(";");
-
- this.mimeType = parametersList.shift().trim();
-
- for (let parameter, i = 0; parameter = parametersList[i++];) {
- let pairs = parameter.split("=");
- let name = pairs[0].trim();
- let value = pairs.length > 1 ? decodeURIComponent(pairs[1].trim()) : "";
-
- this.parameters[name] = value;
- }
-
- if (this.base64)
- this.data = base64.decode(this.data);
-
- },
-
- /**
- * Returns the object as a valid Data URL string
- *
- * @returns {String} The Data URL
- */
- toString : function() {
- let parametersList = [];
-
- for (let name in this.parameters) {
- let encodedParameter = encodeURIComponent(name);
- let value = this.parameters[name];
-
- if (value)
- encodedParameter += "=" + encodeURIComponent(value);
-
- parametersList.push(encodedParameter);
- }
-
- // If there is at least a parameter, add an empty string in order
- // to start with a `;` on join call.
- if (parametersList.length > 0)
- parametersList.unshift("");
-
- let data = this.base64 ? base64.encode(this.data) : this.data;
-
- return "data:" +
- this.mimeType +
- parametersList.join(";") + "," +
- encodeURIComponent(data);
- }
-});
-
-exports.DataURL = DataURL;
-
-var getTLD = exports.getTLD = function getTLD (url) {
- let uri = newURI(url.toString());
- let tld = null;
- try {
- tld = tlds.getPublicSuffix(uri);
- }
- catch (e) {
- if (e.result != Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS &&
- e.result != Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
- throw e;
- }
- }
- return tld;
-};
-
-var isValidURI = exports.isValidURI = function (uri) {
- try {
- newURI(uri);
- }
- catch(e) {
- return false;
- }
- return true;
-}
-
-function isLocalURL(url) {
- if (String.indexOf(url, './') === 0)
- return true;
-
- try {
- return ['resource', 'data', 'chrome'].indexOf(URL(url).scheme) > -1;
- }
- catch(e) {}
-
- return false;
-}
-exports.isLocalURL = isLocalURL;
diff --git a/addon-sdk/source/lib/sdk/url/utils.js b/addon-sdk/source/lib/sdk/url/utils.js
deleted file mode 100644
index aa5759204..000000000
--- a/addon-sdk/source/lib/sdk/url/utils.js
+++ /dev/null
@@ -1,29 +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, Cr } = require("chrome");
-const IOService = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
-const { isValidURI } = require("../url");
-const { method } = require("../../method/core");
-
-function newURI (uri) {
- if (!isValidURI(uri))
- throw new Error("malformed URI: " + uri);
- return IOService.newURI(uri, null, null);
-}
-exports.newURI = newURI;
-
-var getURL = method('sdk/url:getURL');
-getURL.define(String, url => url);
-getURL.define(function (object) {
- return null;
-});
-exports.getURL = getURL;
diff --git a/addon-sdk/source/lib/sdk/util/array.js b/addon-sdk/source/lib/sdk/util/array.js
deleted file mode 100644
index 1d61a973e..000000000
--- a/addon-sdk/source/lib/sdk/util/array.js
+++ /dev/null
@@ -1,123 +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"
-};
-
-/**
- * Returns `true` if given `array` contain given `element` or `false`
- * otherwise.
- * @param {Array} array
- * Target array.
- * @param {Object|String|Number|Boolean} element
- * Element being looked up.
- * @returns {Boolean}
- */
-var has = exports.has = function has(array, element) {
- // shorter and faster equivalent of `array.indexOf(element) >= 0`
- return !!~array.indexOf(element);
-};
-var hasAny = exports.hasAny = function hasAny(array, elements) {
- if (arguments.length < 2)
- return false;
- if (!Array.isArray(elements))
- elements = [ elements ];
- return array.some(function (element) {
- return has(elements, element);
- });
-};
-
-/**
- * Adds given `element` to the given `array` if it does not contain it yet.
- * `true` is returned if element was added otherwise `false` is returned.
- * @param {Array} array
- * Target array.
- * @param {Object|String|Number|Boolean} element
- * Element to be added.
- * @returns {Boolean}
- */
-var add = exports.add = function add(array, element) {
- var result;
- if ((result = !has(array, element)))
- array.push(element);
-
- return result;
-};
-
-/**
- * Removes first occurrence of the given `element` from the given `array`. If
- * `array` does not contain given `element` `false` is returned otherwise
- * `true` is returned.
- * @param {Array} array
- * Target array.
- * @param {Object|String|Number|Boolean} element
- * Element to be removed.
- * @returns {Boolean}
- */
-exports.remove = function remove(array, element) {
- var result;
- if ((result = has(array, element)))
- array.splice(array.indexOf(element), 1);
-
- return result;
-};
-
-/**
- * Produces a duplicate-free version of the given `array`.
- * @param {Array} array
- * Source array.
- * @returns {Array}
- */
-function unique(array) {
- return array.reduce(function(result, item) {
- add(result, item);
- return result;
- }, []);
-};
-exports.unique = unique;
-
-/**
- * Produce an array that contains the union: each distinct element from all
- * of the passed-in arrays.
- */
-function union() {
- return unique(Array.concat.apply(null, arguments));
-};
-exports.union = union;
-
-exports.flatten = function flatten(array){
- var flat = [];
- for (var i = 0, l = array.length; i < l; i++) {
- flat = flat.concat(Array.isArray(array[i]) ? flatten(array[i]) : array[i]);
- }
- return flat;
-};
-
-function fromIterator(iterator) {
- let array = [];
- if (iterator.__iterator__) {
- for (let item of iterator)
- array.push(item);
- }
- else {
- for (let item of iterator)
- array.push(item);
- }
- return array;
-}
-exports.fromIterator = fromIterator;
-
-function find(array, predicate, fallback) {
- var index = 0;
- var count = array.length;
- while (index < count) {
- var value = array[index];
- if (predicate(value)) return value;
- else index = index + 1;
- }
- return fallback;
-}
-exports.find = find;
diff --git a/addon-sdk/source/lib/sdk/util/collection.js b/addon-sdk/source/lib/sdk/util/collection.js
deleted file mode 100644
index 194a29470..000000000
--- a/addon-sdk/source/lib/sdk/util/collection.js
+++ /dev/null
@@ -1,115 +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"
-};
-
-exports.Collection = Collection;
-
-/**
- * Adds a collection property to the given object. Setting the property to a
- * scalar value empties the collection and adds the value. Setting it to an
- * array empties the collection and adds all the items in the array.
- *
- * @param obj
- * The property will be defined on this object.
- * @param propName
- * The name of the property.
- * @param array
- * If given, this will be used as the collection's backing array.
- */
-exports.addCollectionProperty = function addCollProperty(obj, propName, array) {
- array = array || [];
- let publicIface = new Collection(array);
-
- Object.defineProperty(obj, propName, {
- configurable: true,
- enumerable: true,
-
- set: function set(itemOrItems) {
- array.splice(0, array.length);
- publicIface.add(itemOrItems);
- },
-
- get: function get() {
- return publicIface;
- }
- });
-};
-
-/**
- * A collection is ordered, like an array, but its items are unique, like a set.
- *
- * @param array
- * The collection is backed by an array. If this is given, it will be
- * used as the backing array. This way the caller can fully control the
- * collection. Otherwise a new empty array will be used, and no one but
- * the collection will have access to it.
- */
-function Collection(array) {
- array = array || [];
-
- /**
- * Provides iteration over the collection. Items are yielded in the order
- * they were added.
- */
- this.__iterator__ = function Collection___iterator__() {
- let items = array.slice();
- for (let i = 0; i < items.length; i++)
- yield items[i];
- };
-
- /**
- * The number of items in the collection.
- */
- this.__defineGetter__("length", function Collection_get_length() {
- return array.length;
- });
-
- /**
- * Adds a single item or an array of items to the collection. Any items
- * already contained in the collection are ignored.
- *
- * @param itemOrItems
- * An item or array of items.
- * @return The collection.
- */
- this.add = function Collection_add(itemOrItems) {
- let items = toArray(itemOrItems);
- for (let i = 0; i < items.length; i++) {
- let item = items[i];
- if (array.indexOf(item) < 0)
- array.push(item);
- }
- return this;
- };
-
- /**
- * Removes a single item or an array of items from the collection. Any items
- * not contained in the collection are ignored.
- *
- * @param itemOrItems
- * An item or array of items.
- * @return The collection.
- */
- this.remove = function Collection_remove(itemOrItems) {
- let items = toArray(itemOrItems);
- for (let i = 0; i < items.length; i++) {
- let idx = array.indexOf(items[i]);
- if (idx >= 0)
- array.splice(idx, 1);
- }
- return this;
- };
-};
-
-function toArray(itemOrItems) {
- let isArr = itemOrItems &&
- itemOrItems.constructor &&
- itemOrItems.constructor.name === "Array";
- return isArr ? itemOrItems : [itemOrItems];
-}
diff --git a/addon-sdk/source/lib/sdk/util/contract.js b/addon-sdk/source/lib/sdk/util/contract.js
deleted file mode 100644
index c689ea601..000000000
--- a/addon-sdk/source/lib/sdk/util/contract.js
+++ /dev/null
@@ -1,55 +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 { validateOptions: valid } = require("../deprecated/api-utils");
-const method = require("method/core");
-
-// Function takes property validation rules and returns function that given
-// an `options` object will return validated / normalized options back. If
-// option(s) are invalid validator will throw exception described by rules.
-// Returned will also have contain `rules` property with a given validation
-// rules and `properties` function that can be used to generate validated
-// property getter and setters can be mixed into prototype. For more details
-// see `properties` function below.
-function contract(rules) {
- const validator = (instance, options) => {
- return valid(options || instance || {}, rules);
- };
- validator.rules = rules
- validator.properties = function(modelFor) {
- return properties(modelFor, rules);
- }
- return validator;
-}
-exports.contract = contract
-
-// Function takes `modelFor` instance state model accessor functions and
-// a property validation rules and generates object with getters and setters
-// that can be mixed into prototype. Property accessors update model for the
-// given instance. If you wish to react to property updates you can always
-// override setters to put specific logic.
-function properties(modelFor, rules) {
- let descriptor = Object.keys(rules).reduce(function(descriptor, name) {
- descriptor[name] = {
- get: function() { return modelFor(this)[name] },
- set: function(value) {
- let change = {};
- change[name] = value;
- modelFor(this)[name] = valid(change, rules)[name];
- }
- }
- return descriptor
- }, {});
- return Object.create(Object.prototype, descriptor);
-}
-exports.properties = properties;
-
-const validate = method("contract/validate");
-exports.validate = validate;
diff --git a/addon-sdk/source/lib/sdk/util/deprecate.js b/addon-sdk/source/lib/sdk/util/deprecate.js
deleted file mode 100644
index 40f236de5..000000000
--- a/addon-sdk/source/lib/sdk/util/deprecate.js
+++ /dev/null
@@ -1,40 +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 { get, format } = require("../console/traceback");
-const { get: getPref } = require("../preferences/service");
-const PREFERENCE = "devtools.errorconsole.deprecation_warnings";
-
-function deprecateUsage(msg) {
- // Print caller stacktrace in order to help figuring out which code
- // does use deprecated thing
- let stack = get().slice(2);
-
- if (getPref(PREFERENCE))
- console.error("DEPRECATED: " + msg + "\n" + format(stack));
-}
-exports.deprecateUsage = deprecateUsage;
-
-function deprecateFunction(fun, msg) {
- return function deprecated() {
- deprecateUsage(msg);
- return fun.apply(this, arguments);
- };
-}
-exports.deprecateFunction = deprecateFunction;
-
-function deprecateEvent(fun, msg, evtTypes) {
- return function deprecateEvent(evtType) {
- if (evtTypes.indexOf(evtType) >= 0)
- deprecateUsage(msg);
- return fun.apply(this, arguments);
- };
-}
-exports.deprecateEvent = deprecateEvent;
diff --git a/addon-sdk/source/lib/sdk/util/dispatcher.js b/addon-sdk/source/lib/sdk/util/dispatcher.js
deleted file mode 100644
index 67d29dfed..000000000
--- a/addon-sdk/source/lib/sdk/util/dispatcher.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";
-
-module.metadata = {
- "stability": "experimental"
-};
-
-const method = require("method/core");
-
-// Utility function that is just an enhancement over `method` to
-// allow predicate based dispatch in addition to polymorphic
-// dispatch. Unfortunately polymorphic dispatch does not quite
-// cuts it in the world of XPCOM where no types / classes exist
-// and all the XUL nodes share same type / prototype.
-// Probably this is more generic and belongs some place else, but
-// we can move it later once this will be relevant.
-var dispatcher = hint => {
- const base = method(hint);
- // Make a map for storing predicate, implementation mappings.
- let implementations = new Map();
-
- // Dispatcher function goes through `predicate, implementation`
- // pairs to find predicate that matches first argument and
- // returns application of arguments on the associated
- // `implementation`. If no matching predicate is found delegates
- // to a `base` polymorphic function.
- let dispatch = (value, ...rest) => {
- for (let [predicate, implementation] of implementations) {
- if (predicate(value))
- return implementation(value, ...rest);
- }
-
- return base(value, ...rest);
- };
-
- // Expose base API.
- dispatch.define = base.define;
- dispatch.implement = base.implement;
- dispatch.toString = base.toString;
-
- // Add a `when` function to allow extending function via
- // predicates.
- dispatch.when = (predicate, implementation) => {
- if (implementations.has(predicate))
- throw TypeError("Already implemented for the given predicate");
- implementations.set(predicate, implementation);
- };
-
- return dispatch;
-};
-
-exports.dispatcher = dispatcher;
diff --git a/addon-sdk/source/lib/sdk/util/list.js b/addon-sdk/source/lib/sdk/util/list.js
deleted file mode 100644
index 6d7d2dea9..000000000
--- a/addon-sdk/source/lib/sdk/util/list.js
+++ /dev/null
@@ -1,90 +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 { Class } = require('../core/heritage');
-const listNS = require('../core/namespace').ns();
-
-const listOptions = {
- /**
- * List constructor can take any number of element to populate itself.
- * @params {Object|String|Number} element
- * @example
- * List(1,2,3).length == 3 // true
- */
- initialize: function List() {
- listNS(this).keyValueMap = [];
-
- for (let i = 0, ii = arguments.length; i < ii; i++)
- addListItem(this, arguments[i]);
- },
- /**
- * Number of elements in this list.
- * @type {Number}
- */
- get length() {
- return listNS(this).keyValueMap.length;
- },
- /**
- * Returns a string representing this list.
- * @returns {String}
- */
- toString: function toString() {
- return 'List(' + listNS(this).keyValueMap + ')';
- },
- /**
- * Custom iterator providing `List`s enumeration behavior.
- * We cant reuse `_iterator` that is defined by `Iterable` since it provides
- * iteration in an arbitrary order.
- * @see https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in
- * @param {Boolean} onKeys
- */
- __iterator__: function __iterator__(onKeys, onKeyValue) {
- let array = listNS(this).keyValueMap.slice(0),
- i = -1;
- for (let element of array)
- yield onKeyValue ? [++i, element] : onKeys ? ++i : element;
- },
-};
-listOptions[Symbol.iterator] = function iterator() {
- return listNS(this).keyValueMap.slice(0)[Symbol.iterator]();
-};
-const List = Class(listOptions);
-exports.List = List;
-
-function addListItem(that, value) {
- let list = listNS(that).keyValueMap,
- index = list.indexOf(value);
-
- if (-1 === index) {
- try {
- that[that.length] = value;
- }
- catch (e) {}
- list.push(value);
- }
-}
-exports.addListItem = addListItem;
-
-function removeListItem(that, element) {
- let list = listNS(that).keyValueMap,
- index = list.indexOf(element);
-
- if (0 <= index) {
- list.splice(index, 1);
- try {
- for (let length = list.length; index < length; index++)
- that[index] = list[index];
- that[list.length] = undefined;
- }
- catch(e){}
- }
-}
-exports.removeListItem = removeListItem;
-
-exports.listNS = listNS;
diff --git a/addon-sdk/source/lib/sdk/util/match-pattern.js b/addon-sdk/source/lib/sdk/util/match-pattern.js
deleted file mode 100644
index a0eb88b49..000000000
--- a/addon-sdk/source/lib/sdk/util/match-pattern.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 { URL } = require('../url');
-const cache = {};
-
-function MatchPattern(pattern) {
- if (cache[pattern]) return cache[pattern];
-
- if (typeof pattern.test == "function") {
- // For compatibility with -moz-document rules, we require the RegExp's
- // global, ignoreCase, and multiline flags to be set to false.
- if (pattern.global) {
- throw new Error("A RegExp match pattern cannot be set to `global` " +
- "(i.e. //g).");
- }
- if (pattern.multiline) {
- throw new Error("A RegExp match pattern cannot be set to `multiline` " +
- "(i.e. //m).");
- }
-
- this.regexp = pattern;
- }
- else {
- let firstWildcardPosition = pattern.indexOf("*");
- let lastWildcardPosition = pattern.lastIndexOf("*");
- if (firstWildcardPosition != lastWildcardPosition)
- throw new Error("There can be at most one '*' character in a wildcard.");
-
- if (firstWildcardPosition == 0) {
- if (pattern.length == 1)
- this.anyWebPage = true;
- else if (pattern[1] != ".")
- throw new Error("Expected a *.<domain name> string, got: " + pattern);
- else
- this.domain = pattern.substr(2);
- }
- else {
- if (pattern.indexOf(":") == -1) {
- throw new Error("When not using *.example.org wildcard, the string " +
- "supplied is expected to be either an exact URL to " +
- "match or a URL prefix. The provided string ('" +
- pattern + "') is unlikely to match any pages.");
- }
-
- if (firstWildcardPosition == -1)
- this.exactURL = pattern;
- else if (firstWildcardPosition == pattern.length - 1)
- this.urlPrefix = pattern.substr(0, pattern.length - 1);
- else {
- throw new Error("The provided wildcard ('" + pattern + "') has a '*' " +
- "in an unexpected position. It is expected to be the " +
- "first or the last character in the wildcard.");
- }
- }
- }
-
- cache[pattern] = this;
-}
-
-MatchPattern.prototype = {
- test: function MatchPattern_test(urlStr) {
- try {
- var url = URL(urlStr);
- }
- catch (err) {
- return false;
- }
-
- // Test the URL against a RegExp pattern. For compatibility with
- // -moz-document rules, we require the RegExp to match the entire URL,
- // so we not only test for a match, we also make sure the matched string
- // is the entire URL string.
- //
- // Assuming most URLs don't match most match patterns, we call `test` for
- // speed when determining whether or not the URL matches, then call `exec`
- // for the small subset that match to make sure the entire URL matches.
- if (this.regexp && this.regexp.test(urlStr) &&
- this.regexp.exec(urlStr)[0] == urlStr)
- return true;
-
- if (this.anyWebPage && /^(https?|ftp)$/.test(url.scheme))
- return true;
-
- if (this.exactURL && this.exactURL == urlStr)
- return true;
-
- // Tests the urlStr against domain and check if
- // wildcard submitted (*.domain.com), it only allows
- // subdomains (sub.domain.com) or from the root (http://domain.com)
- // and reject non-matching domains (otherdomain.com)
- // bug 856913
- if (this.domain && url.host &&
- (url.host === this.domain ||
- url.host.slice(-this.domain.length - 1) === "." + this.domain))
- return true;
-
- if (this.urlPrefix && 0 == urlStr.indexOf(this.urlPrefix))
- return true;
-
- return false;
- },
-
- toString: () => '[object MatchPattern]'
-};
-
-exports.MatchPattern = MatchPattern;
diff --git a/addon-sdk/source/lib/sdk/util/object.js b/addon-sdk/source/lib/sdk/util/object.js
deleted file mode 100644
index 9d202bb51..000000000
--- a/addon-sdk/source/lib/sdk/util/object.js
+++ /dev/null
@@ -1,104 +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 { flatten } = require('./array');
-
-/**
- * Merges all the properties of all arguments into first argument. If two or
- * more argument objects have own properties with the same name, the property
- * is overridden, with precedence from right to left, implying, that properties
- * of the object on the left are overridden by a same named property of the
- * object on the right.
- *
- * Any argument given with "falsy" value - commonly `null` and `undefined` in
- * case of objects - are skipped.
- *
- * @examples
- * var a = { bar: 0, a: 'a' }
- * var b = merge(a, { foo: 'foo', bar: 1 }, { foo: 'bar', name: 'b' });
- * b === a // true
- * b.a // 'a'
- * b.foo // 'bar'
- * b.bar // 1
- * b.name // 'b'
- */
-function merge(source) {
- let descriptor = {};
-
- // `Boolean` converts the first parameter to a boolean value. Any object is
- // converted to `true` where `null` and `undefined` becames `false`. Therefore
- // the `filter` method will keep only objects that are defined and not null.
- Array.slice(arguments, 1).filter(Boolean).forEach(function onEach(properties) {
- getOwnPropertyIdentifiers(properties).forEach(function(name) {
- descriptor[name] = Object.getOwnPropertyDescriptor(properties, name);
- });
- });
- return Object.defineProperties(source, descriptor);
-}
-exports.merge = merge;
-
-/**
- * Returns an object that inherits from the first argument and contains all the
- * properties from all following arguments.
- * `extend(source1, source2, source3)` is equivalent of
- * `merge(Object.create(source1), source2, source3)`.
- */
-function extend(source) {
- let rest = Array.slice(arguments, 1);
- rest.unshift(Object.create(source));
- return merge.apply(null, rest);
-}
-exports.extend = extend;
-
-function has(obj, key) {
- return obj.hasOwnProperty(key);
-}
-exports.has = has;
-
-function each(obj, fn) {
- for (let key in obj) has(obj, key) && fn(obj[key], key, obj);
-}
-exports.each = each;
-
-/**
- * Like `merge`, except no property descriptors are manipulated, for use
- * with platform objects. Identical to underscore's `extend`. Useful for
- * merging XPCOM objects
- */
-function safeMerge(source) {
- Array.slice(arguments, 1).forEach(function onEach (obj) {
- for (let prop in obj) source[prop] = obj[prop];
- });
- return source;
-}
-exports.safeMerge = safeMerge;
-
-/*
- * Returns a copy of the object without omitted properties
- */
-function omit(source, ...values) {
- let copy = {};
- let keys = flatten(values);
- for (let prop in source)
- if (!~keys.indexOf(prop))
- copy[prop] = source[prop];
- return copy;
-}
-exports.omit = omit;
-
-// get object's own property Symbols and/or Names, including nonEnumerables by default
-function getOwnPropertyIdentifiers(object, options = { names: true, symbols: true, nonEnumerables: true }) {
- const symbols = !options.symbols ? [] :
- Object.getOwnPropertySymbols(object);
- const names = !options.names ? [] :
- options.nonEnumerables ? Object.getOwnPropertyNames(object) :
- Object.keys(object);
- return [...names, ...symbols];
-}
-exports.getOwnPropertyIdentifiers = getOwnPropertyIdentifiers;
diff --git a/addon-sdk/source/lib/sdk/util/rules.js b/addon-sdk/source/lib/sdk/util/rules.js
deleted file mode 100644
index 98e3109b0..000000000
--- a/addon-sdk/source/lib/sdk/util/rules.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 { Class } = require('../core/heritage');
-const { MatchPattern } = require('./match-pattern');
-const { emit } = require('../event/core');
-const { EventTarget } = require('../event/target');
-const { List, addListItem, removeListItem } = require('./list');
-
-// Should deprecate usage of EventEmitter/compose
-const Rules = Class({
- implements: [
- EventTarget,
- List
- ],
- add: function(...rules) {
- return [].concat(rules).forEach(function onAdd(rule) {
- addListItem(this, rule);
- emit(this, 'add', rule);
- }, this);
- },
- remove: function(...rules) {
- return [].concat(rules).forEach(function onRemove(rule) {
- removeListItem(this, rule);
- emit(this, 'remove', rule);
- }, this);
- },
- get: function(rule) {
- let found = false;
- for (let i in this) if (this[i] === rule) found = true;
- return found;
- },
- // Returns true if uri matches atleast one stored rule
- matchesAny: function(uri) {
- return !!filterMatches(this, uri).length;
- },
- toString: () => '[object Rules]'
-});
-exports.Rules = Rules;
-
-function filterMatches(instance, uri) {
- let matches = [];
- for (let i in instance) {
- if (new MatchPattern(instance[i]).test(uri)) matches.push(instance[i]);
- }
- return matches;
-}
diff --git a/addon-sdk/source/lib/sdk/util/sequence.js b/addon-sdk/source/lib/sdk/util/sequence.js
deleted file mode 100644
index 28e3de255..000000000
--- a/addon-sdk/source/lib/sdk/util/sequence.js
+++ /dev/null
@@ -1,593 +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"
-};
-
-// Disclamer:
-// In this module we'll have some common argument / variable names
-// to hint their type or behavior.
-//
-// - `f` stands for "function" that is intended to be side effect
-// free.
-// - `p` stands for "predicate" that is function which returns logical
-// true or false and is intended to be side effect free.
-// - `x` / `y` single item of the sequence.
-// - `xs` / `ys` sequence of `x` / `y` items where `x` / `y` signifies
-// type of the items in sequence, so sequence is not of the same item.
-// - `_` used for argument(s) or variable(s) who's values are ignored.
-
-const { complement, flip, identity } = require("../lang/functional");
-const { isArray, isArguments, isMap, isSet, isGenerator,
- isString, isBoolean, isNumber } = require("../lang/type");
-
-const Sequence = function Sequence(iterator) {
- if (!isGenerator(iterator)) {
- throw TypeError("Expected generator argument");
- }
-
- this[Symbol.iterator] = iterator;
-};
-exports.Sequence = Sequence;
-
-const polymorphic = dispatch => x =>
- x === null ? dispatch.null(null) :
- x === void(0) ? dispatch.void(void(0)) :
- isArray(x) ? (dispatch.array || dispatch.indexed)(x) :
- isString(x) ? (dispatch.string || dispatch.indexed)(x) :
- isArguments(x) ? (dispatch.arguments || dispatch.indexed)(x) :
- isMap(x) ? dispatch.map(x) :
- isSet(x) ? dispatch.set(x) :
- isNumber(x) ? dispatch.number(x) :
- isBoolean(x) ? dispatch.boolean(x) :
- dispatch.default(x);
-
-const nogen = function*() {};
-const empty = () => new Sequence(nogen);
-exports.empty = empty;
-
-const seq = polymorphic({
- null: empty,
- void: empty,
- array: identity,
- string: identity,
- arguments: identity,
- map: identity,
- set: identity,
- default: x => x instanceof Sequence ? x : new Sequence(x)
-});
-exports.seq = seq;
-
-// Function to cast seq to string.
-const string = (...etc) => "".concat(...etc);
-exports.string = string;
-
-// Function for casting seq to plain object.
-const object = (...pairs) => {
- let result = {};
- for (let [key, value] of pairs)
- result[key] = value;
-
- return result;
-};
-exports.object = object;
-
-// Takes `getEnumerator` function that returns `nsISimpleEnumerator`
-// and creates lazy sequence of it's items. Note that function does
-// not take `nsISimpleEnumerator` itslef because that would allow
-// single iteration, which would not be consistent with rest of the
-// lazy sequences.
-const fromEnumerator = getEnumerator => seq(function* () {
- const enumerator = getEnumerator();
- while (enumerator.hasMoreElements())
- yield enumerator.getNext();
-});
-exports.fromEnumerator = fromEnumerator;
-
-// Takes `object` and returns lazy sequence of own `[key, value]`
-// pairs (does not include inherited and non enumerable keys).
-const pairs = polymorphic({
- null: empty,
- void: empty,
- map: identity,
- indexed: indexed => seq(function* () {
- const count = indexed.length;
- let index = 0;
- while (index < count) {
- yield [index, indexed[index]];
- index = index + 1;
- }
- }),
- default: object => seq(function* () {
- for (let key of Object.keys(object))
- yield [key, object[key]];
- })
-});
-exports.pairs = pairs;
-
-const names = polymorphic({
- null: empty,
- void: empty,
- default: object => seq(function*() {
- for (let name of Object.getOwnPropertyNames(object)) {
- yield name;
- }
- })
-});
-exports.names = names;
-
-const symbols = polymorphic({
- null: empty,
- void: empty,
- default: object => seq(function* () {
- for (let symbol of Object.getOwnPropertySymbols(object)) {
- yield symbol;
- }
- })
-});
-exports.symbols = symbols;
-
-const keys = polymorphic({
- null: empty,
- void: empty,
- indexed: indexed => seq(function* () {
- const count = indexed.length;
- let index = 0;
- while (index < count) {
- yield index;
- index = index + 1;
- }
- }),
- map: map => seq(function* () {
- for (let [key, _] of map)
- yield key;
- }),
- default: object => seq(function* () {
- for (let key of Object.keys(object))
- yield key;
- })
-});
-exports.keys = keys;
-
-
-const values = polymorphic({
- null: empty,
- void: empty,
- set: identity,
- indexed: indexed => seq(function* () {
- const count = indexed.length;
- let index = 0;
- while (index < count) {
- yield indexed[index];
- index = index + 1;
- }
- }),
- map: map => seq(function* () {
- for (let [_, value] of map) yield value;
- }),
- default: object => seq(function* () {
- for (let key of Object.keys(object)) yield object[key];
- })
-});
-exports.values = values;
-
-
-
-// Returns a lazy sequence of `x`, `f(x)`, `f(f(x))` etc.
-// `f` must be free of side-effects. Note that returned
-// sequence is infinite so it must be consumed partially.
-//
-// Implements clojure iterate:
-// http://clojuredocs.org/clojure_core/clojure.core/iterate
-const iterate = (f, x) => seq(function* () {
- let state = x;
- while (true) {
- yield state;
- state = f(state);
- }
-});
-exports.iterate = iterate;
-
-// Returns a lazy sequence of the items in sequence for which `p(item)`
-// returns `true`. `p` must be free of side-effects.
-//
-// Implements clojure filter:
-// http://clojuredocs.org/clojure_core/clojure.core/filter
-const filter = (p, sequence) => seq(function* () {
- if (sequence !== null && sequence !== void(0)) {
- for (let item of sequence) {
- if (p(item))
- yield item;
- }
- }
-});
-exports.filter = filter;
-
-// Returns a lazy sequence consisting of the result of applying `f` to the
-// set of first items of each sequence, followed by applying f to the set
-// of second items in each sequence, until any one of the sequences is
-// exhausted. Any remaining items in other sequences are ignored. Function
-// `f` should accept number-of-sequences arguments.
-//
-// Implements clojure map:
-// http://clojuredocs.org/clojure_core/clojure.core/map
-const map = (f, ...sequences) => seq(function* () {
- const count = sequences.length;
- // Optimize a single sequence case
- if (count === 1) {
- let [sequence] = sequences;
- if (sequence !== null && sequence !== void(0)) {
- for (let item of sequence)
- yield f(item);
- }
- }
- else {
- // define args array that will be recycled on each
- // step to aggregate arguments to be passed to `f`.
- let args = [];
- // define inputs to contain started generators.
- let inputs = [];
-
- let index = 0;
- while (index < count) {
- inputs[index] = sequences[index][Symbol.iterator]();
- index = index + 1;
- }
-
- // Run loop yielding of applying `f` to the set of
- // items at each step until one of the `inputs` is
- // exhausted.
- let done = false;
- while (!done) {
- let index = 0;
- let value = void(0);
- while (index < count && !done) {
- ({ done, value } = inputs[index].next());
-
- // If input is not exhausted yet store value in args.
- if (!done) {
- args[index] = value;
- index = index + 1;
- }
- }
-
- // If none of the inputs is exhasted yet, `args` contain items
- // from each input so we yield application of `f` over them.
- if (!done)
- yield f(...args);
- }
- }
-});
-exports.map = map;
-
-// Returns a lazy sequence of the intermediate values of the reduction (as
-// per reduce) of sequence by `f`, starting with `initial` value if provided.
-//
-// Implements clojure reductions:
-// http://clojuredocs.org/clojure_core/clojure.core/reductions
-const reductions = (...params) => {
- const count = params.length;
- let hasInitial = false;
- let f, initial, source;
- if (count === 2) {
- [f, source] = params;
- }
- else if (count === 3) {
- [f, initial, source] = params;
- hasInitial = true;
- }
- else {
- throw Error("Invoked with wrong number of arguments: " + count);
- }
-
- const sequence = seq(source);
-
- return seq(function* () {
- let started = hasInitial;
- let result = void(0);
-
- // If initial is present yield it.
- if (hasInitial)
- yield (result = initial);
-
- // For each item of the sequence accumulate new result.
- for (let item of sequence) {
- // If nothing has being yield yet set result to first
- // item and yield it.
- if (!started) {
- started = true;
- yield (result = item);
- }
- // Otherwise accumulate new result and yield it.
- else {
- yield (result = f(result, item));
- }
- }
-
- // If nothing has being yield yet it's empty sequence and no
- // `initial` was provided in which case we need to yield `f()`.
- if (!started)
- yield f();
- });
-};
-exports.reductions = reductions;
-
-// `f` should be a function of 2 arguments. If `initial` is not supplied,
-// returns the result of applying `f` to the first 2 items in sequence, then
-// applying `f` to that result and the 3rd item, etc. If sequence contains no
-// items, `f` must accept no arguments as well, and reduce returns the
-// result of calling f with no arguments. If sequence has only 1 item, it
-// is returned and `f` is not called. If `initial` is supplied, returns the
-// result of applying `f` to `initial` and the first item in sequence, then
-// applying `f` to that result and the 2nd item, etc. If sequence contains no
-// items, returns `initial` and `f` is not called.
-//
-// Implements clojure reduce:
-// http://clojuredocs.org/clojure_core/clojure.core/reduce
-const reduce = (...args) => {
- const xs = reductions(...args);
- let x;
- for (x of xs) void(0);
- return x;
-};
-exports.reduce = reduce;
-
-const each = (f, sequence) => {
- for (let x of seq(sequence)) void(f(x));
-};
-exports.each = each;
-
-
-const inc = x => x + 1;
-// Returns the number of items in the sequence. `count(null)` && `count()`
-// returns `0`. Also works on strings, arrays, Maps & Sets.
-
-// Implements clojure count:
-// http://clojuredocs.org/clojure_core/clojure.core/count
-const count = polymorphic({
- null: _ => 0,
- void: _ => 0,
- indexed: indexed => indexed.length,
- map: map => map.size,
- set: set => set.size,
- default: xs => reduce(inc, 0, xs)
-});
-exports.count = count;
-
-// Returns `true` if sequence has no items.
-
-// Implements clojure empty?:
-// http://clojuredocs.org/clojure_core/clojure.core/empty_q
-const isEmpty = sequence => {
- // Treat `null` and `undefined` as empty sequences.
- if (sequence === null || sequence === void(0))
- return true;
-
- // If contains any item non empty so return `false`.
- for (let _ of sequence)
- return false;
-
- // If has not returned yet, there was nothing to iterate
- // so it's empty.
- return true;
-};
-exports.isEmpty = isEmpty;
-
-const and = (a, b) => a && b;
-
-// Returns true if `p(x)` is logical `true` for every `x` in sequence, else
-// `false`.
-//
-// Implements clojure every?:
-// http://clojuredocs.org/clojure_core/clojure.core/every_q
-const isEvery = (p, sequence) => {
- if (sequence !== null && sequence !== void(0)) {
- for (let item of sequence) {
- if (!p(item))
- return false;
- }
- }
- return true;
-};
-exports.isEvery = isEvery;
-
-// Returns the first logical true value of (p x) for any x in sequence,
-// else `null`.
-//
-// Implements clojure some:
-// http://clojuredocs.org/clojure_core/clojure.core/some
-const some = (p, sequence) => {
- if (sequence !== null && sequence !== void(0)) {
- for (let item of sequence) {
- if (p(item))
- return true;
- }
- }
- return null;
-};
-exports.some = some;
-
-// Returns a lazy sequence of the first `n` items in sequence, or all items if
-// there are fewer than `n`.
-//
-// Implements clojure take:
-// http://clojuredocs.org/clojure_core/clojure.core/take
-const take = (n, sequence) => n <= 0 ? empty() : seq(function* () {
- let count = n;
- for (let item of sequence) {
- yield item;
- count = count - 1;
- if (count === 0) break;
- }
-});
-exports.take = take;
-
-// Returns a lazy sequence of successive items from sequence while
-// `p(item)` returns `true`. `p` must be free of side-effects.
-//
-// Implements clojure take-while:
-// http://clojuredocs.org/clojure_core/clojure.core/take-while
-const takeWhile = (p, sequence) => seq(function* () {
- for (let item of sequence) {
- if (!p(item))
- break;
-
- yield item;
- }
-});
-exports.takeWhile = takeWhile;
-
-// Returns a lazy sequence of all but the first `n` items in
-// sequence.
-//
-// Implements clojure drop:
-// http://clojuredocs.org/clojure_core/clojure.core/drop
-const drop = (n, sequence) => seq(function* () {
- if (sequence !== null && sequence !== void(0)) {
- let count = n;
- for (let item of sequence) {
- if (count > 0)
- count = count - 1;
- else
- yield item;
- }
- }
-});
-exports.drop = drop;
-
-// Returns a lazy sequence of the items in sequence starting from the
-// first item for which `p(item)` returns falsy value.
-//
-// Implements clojure drop-while:
-// http://clojuredocs.org/clojure_core/clojure.core/drop-while
-const dropWhile = (p, sequence) => seq(function* () {
- let keep = false;
- for (let item of sequence) {
- keep = keep || !p(item);
- if (keep) yield item;
- }
-});
-exports.dropWhile = dropWhile;
-
-// Returns a lazy sequence representing the concatenation of the
-// suplied sequences.
-//
-// Implements clojure conact:
-// http://clojuredocs.org/clojure_core/clojure.core/concat
-const concat = (...sequences) => seq(function* () {
- for (let sequence of sequences)
- for (let item of sequence)
- yield item;
-});
-exports.concat = concat;
-
-// Returns the first item in the sequence.
-//
-// Implements clojure first:
-// http://clojuredocs.org/clojure_core/clojure.core/first
-const first = sequence => {
- if (sequence !== null && sequence !== void(0)) {
- for (let item of sequence)
- return item;
- }
- return null;
-};
-exports.first = first;
-
-// Returns a possibly empty sequence of the items after the first.
-//
-// Implements clojure rest:
-// http://clojuredocs.org/clojure_core/clojure.core/rest
-const rest = sequence => drop(1, sequence);
-exports.rest = rest;
-
-// Returns the value at the index. Returns `notFound` or `undefined`
-// if index is out of bounds.
-const nth = (xs, n, notFound) => {
- if (n >= 0) {
- if (isArray(xs) || isArguments(xs) || isString(xs)) {
- return n < xs.length ? xs[n] : notFound;
- }
- else if (xs !== null && xs !== void(0)) {
- let count = n;
- for (let x of xs) {
- if (count <= 0)
- return x;
-
- count = count - 1;
- }
- }
- }
- return notFound;
-};
-exports.nth = nth;
-
-// Return the last item in sequence, in linear time.
-// If `sequence` is an array or string or arguments
-// returns in constant time.
-// Implements clojure last:
-// http://clojuredocs.org/clojure_core/clojure.core/last
-const last = polymorphic({
- null: _ => null,
- void: _ => null,
- indexed: indexed => indexed[indexed.length - 1],
- map: xs => reduce((_, x) => x, xs),
- set: xs => reduce((_, x) => x, xs),
- default: xs => reduce((_, x) => x, xs)
-});
-exports.last = last;
-
-// Return a lazy sequence of all but the last `n` (default 1) items
-// from the give `xs`.
-//
-// Implements clojure drop-last:
-// http://clojuredocs.org/clojure_core/clojure.core/drop-last
-const dropLast = flip((xs, n=1) => seq(function* () {
- let ys = [];
- for (let x of xs) {
- ys.push(x);
- if (ys.length > n)
- yield ys.shift();
- }
-}));
-exports.dropLast = dropLast;
-
-// Returns a lazy sequence of the elements of `xs` with duplicates
-// removed
-//
-// Implements clojure distinct
-// http://clojuredocs.org/clojure_core/clojure.core/distinct
-const distinct = sequence => seq(function* () {
- let items = new Set();
- for (let item of sequence) {
- if (!items.has(item)) {
- items.add(item);
- yield item;
- }
- }
-});
-exports.distinct = distinct;
-
-// Returns a lazy sequence of the items in `xs` for which
-// `p(x)` returns false. `p` must be free of side-effects.
-//
-// Implements clojure remove
-// http://clojuredocs.org/clojure_core/clojure.core/remove
-const remove = (p, xs) => filter(complement(p), xs);
-exports.remove = remove;
-
-// Returns the result of applying concat to the result of
-// `map(f, xs)`. Thus function `f` should return a sequence.
-//
-// Implements clojure mapcat
-// http://clojuredocs.org/clojure_core/clojure.core/mapcat
-const mapcat = (f, sequence) => seq(function* () {
- const sequences = map(f, sequence);
- for (let sequence of sequences)
- for (let item of sequence)
- yield item;
-});
-exports.mapcat = mapcat;
diff --git a/addon-sdk/source/lib/sdk/util/uuid.js b/addon-sdk/source/lib/sdk/util/uuid.js
deleted file mode 100644
index 6d0f2de53..000000000
--- a/addon-sdk/source/lib/sdk/util/uuid.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": "unstable"
-};
-
-const { Cc, Ci, components: { ID: parseUUID } } = require('chrome');
-const { generateUUID } = Cc['@mozilla.org/uuid-generator;1'].
- getService(Ci.nsIUUIDGenerator);
-
-// Returns `uuid`. If `id` is passed then it's parsed to `uuid` and returned
-// if not then new one is generated.
-exports.uuid = function uuid(id) {
- return id ? parseUUID(id) : generateUUID();
-};
diff --git a/addon-sdk/source/lib/sdk/view/core.js b/addon-sdk/source/lib/sdk/view/core.js
deleted file mode 100644
index 5e82e9b5d..000000000
--- a/addon-sdk/source/lib/sdk/view/core.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"
-};
-
-var { Ci } = require("chrome");
-var method = require("../../method/core");
-
-// Returns DOM node associated with a view for
-// the given `value`. If `value` has no view associated
-// it returns `null`. You can implement this method for
-// this type to define what the result should be for it.
-var getNodeView = method("getNodeView");
-getNodeView.define(x =>
- x instanceof Ci.nsIDOMNode ? x :
- x instanceof Ci.nsIDOMWindow ? x :
- null);
-exports.getNodeView = getNodeView;
-exports.viewFor = getNodeView;
-
-var getActiveView = method("getActiveView");
-exports.getActiveView = getActiveView;
diff --git a/addon-sdk/source/lib/sdk/webextension.js b/addon-sdk/source/lib/sdk/webextension.js
deleted file mode 100644
index d1c4385e2..000000000
--- a/addon-sdk/source/lib/sdk/webextension.js
+++ /dev/null
@@ -1,43 +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"
-};
-
-let webExtension;
-let waitForWebExtensionAPI;
-
-module.exports = {
- initFromBootstrapAddonParam(data) {
- if (webExtension) {
- throw new Error("'sdk/webextension' module has been already initialized");
- }
-
- webExtension = data.webExtension;
- },
-
- startup() {
- if (!webExtension) {
- return Promise.reject(new Error(
- "'sdk/webextension' module is currently disabled. " +
- "('hasEmbeddedWebExtension' option is missing or set to false)"
- ));
- }
-
- // NOTE: calling `startup` more than once raises an "Embedded Extension already started"
- // error, but given that SDK addons are going to have access to the startup method through
- // an SDK module that can be required in any part of the addon, it will be nicer if any
- // additional startup calls return the startup promise instead of raising an exception,
- // so that the SDK addon can access the API object in the other addon modules without the
- // need to manually pass this promise around.
- if (!waitForWebExtensionAPI) {
- waitForWebExtensionAPI = webExtension.startup();
- }
-
- return waitForWebExtensionAPI;
- }
-};
diff --git a/addon-sdk/source/lib/sdk/window/browser.js b/addon-sdk/source/lib/sdk/window/browser.js
deleted file mode 100644
index 380b5a486..000000000
--- 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));
diff --git a/addon-sdk/source/lib/sdk/window/events.js b/addon-sdk/source/lib/sdk/window/events.js
deleted file mode 100644
index b1d3a1f3e..000000000
--- 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();
diff --git a/addon-sdk/source/lib/sdk/window/helpers.js b/addon-sdk/source/lib/sdk/window/helpers.js
deleted file mode 100644
index 56cfcaba7..000000000
--- a/addon-sdk/source/lib/sdk/window/helpers.js
+++ /dev/null
@@ -1,81 +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 eventHandler() {
- target.removeEventListener(evt, eventHandler, capture);
- deferred.resolve(target);
- }, capture);
-
- return deferred.promise;
-}
-exports.promise = promise;
diff --git a/addon-sdk/source/lib/sdk/window/namespace.js b/addon-sdk/source/lib/sdk/window/namespace.js
deleted file mode 100644
index b486f888d..000000000
--- 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();
diff --git a/addon-sdk/source/lib/sdk/window/utils.js b/addon-sdk/source/lib/sdk/window/utils.js
deleted file mode 100644
index db91a0fed..000000000
--- a/addon-sdk/source/lib/sdk/window/utils.js
+++ /dev/null
@@ -1,460 +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 { Cc, Ci } = require('chrome');
-const array = require('../util/array');
-const { defer } = require('sdk/core/promise');
-const { dispatcher } = require("../util/dispatcher");
-
-const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
- getService(Ci.nsIWindowWatcher);
-const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
- getService(Ci.nsIAppShellService);
-const WM = Cc['@mozilla.org/appshell/window-mediator;1'].
- getService(Ci.nsIWindowMediator);
-const io = Cc['@mozilla.org/network/io-service;1'].
- getService(Ci.nsIIOService);
-const FM = Cc["@mozilla.org/focus-manager;1"].
- getService(Ci.nsIFocusManager);
-
-const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
-
-const prefs = require("../preferences/service");
-const BROWSER = 'navigator:browser',
- URI_BROWSER = prefs.get('browser.chromeURL', null),
- NAME = '_blank',
- FEATURES = 'chrome,all,dialog=no,non-private';
-
-function isWindowPrivate(win) {
- if (!win)
- return false;
-
- // if the pbService is undefined, the PrivateBrowsingUtils.jsm is available,
- // and the app is Firefox, then assume per-window private browsing is
- // enabled.
- try {
- return win.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsILoadContext)
- .usePrivateBrowsing;
- }
- catch(e) {}
-
- // Sometimes the input is not a nsIDOMWindow.. but it is still a winodw.
- try {
- return !!win.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing;
- }
- catch (e) {}
-
- return false;
-}
-exports.isWindowPrivate = isWindowPrivate;
-
-function getMostRecentBrowserWindow() {
- return getMostRecentWindow(BROWSER);
-}
-exports.getMostRecentBrowserWindow = getMostRecentBrowserWindow;
-
-function getHiddenWindow() {
- return appShellService.hiddenDOMWindow;
-}
-exports.getHiddenWindow = getHiddenWindow;
-
-function getMostRecentWindow(type) {
- return WM.getMostRecentWindow(type);
-}
-exports.getMostRecentWindow = getMostRecentWindow;
-
-/**
- * Returns the ID of the window's current inner window.
- */
-function getInnerId(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
-};
-exports.getInnerId = getInnerId;
-
-/**
- * Returns the ID of the window's outer window.
- */
-function getOuterId(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
-};
-exports.getOuterId = getOuterId;
-
-/**
- * Returns window by the outer window id.
- */
-const getByOuterId = WM.getOuterWindowWithId;
-exports.getByOuterId = getByOuterId;
-
-const getByInnerId = WM.getCurrentInnerWindowWithId;
-exports.getByInnerId = getByInnerId;
-
-/**
- * Returns `nsIXULWindow` for the given `nsIDOMWindow`.
- */
-function getXULWindow(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIWebNavigation).
- QueryInterface(Ci.nsIDocShellTreeItem).
- treeOwner.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIXULWindow);
-};
-exports.getXULWindow = getXULWindow;
-
-function getDOMWindow(xulWindow) {
- return xulWindow.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindow);
-}
-exports.getDOMWindow = getDOMWindow;
-
-/**
- * Returns `nsIBaseWindow` for the given `nsIDOMWindow`.
- */
-function getBaseWindow(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIWebNavigation).
- QueryInterface(Ci.nsIDocShell).
- QueryInterface(Ci.nsIDocShellTreeItem).
- treeOwner.
- QueryInterface(Ci.nsIBaseWindow);
-}
-exports.getBaseWindow = getBaseWindow;
-
-/**
- * Returns the `nsIDOMWindow` toplevel window for any child/inner window
- */
-function getToplevelWindow(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
-}
-exports.getToplevelWindow = getToplevelWindow;
-
-function getWindowDocShell(window) {
- return window.gBrowser.docShell;
-}
-exports.getWindowDocShell = getWindowDocShell;
-
-function getWindowLoadingContext(window) {
- return getWindowDocShell(window).
- QueryInterface(Ci.nsILoadContext);
-}
-exports.getWindowLoadingContext = getWindowLoadingContext;
-
-const isTopLevel = window => window && getToplevelWindow(window) === window;
-exports.isTopLevel = isTopLevel;
-
-/**
- * Takes hash of options and serializes it to a features string that
- * can be used passed to `window.open`. For more details on features string see:
- * https://developer.mozilla.org/en/DOM/window.open#Position_and_size_features
- */
-function serializeFeatures(options) {
- return Object.keys(options).reduce(function(result, name) {
- let value = options[name];
-
- // the chrome and private features are special
- if ((name == 'private' || name == 'chrome' || name == 'all'))
- return result + ((value === true) ? ',' + name : '');
-
- return result + ',' + name + '=' +
- (value === true ? 'yes' : value === false ? 'no' : value);
- }, '').substr(1);
-}
-
-/**
- * Opens a top level window and returns it's `nsIDOMWindow` representation.
- * @params {String} uri
- * URI of the document to be loaded into window.
- * @params {nsIDOMWindow} options.parent
- * Used as parent for the created window.
- * @params {String} options.name
- * Optional name that is assigned to the window.
- * @params {Object} options.features
- * Map of key, values like: `{ width: 10, height: 15, chrome: true, private: true }`.
- */
-function open(uri, options) {
- uri = uri || URI_BROWSER;
- options = options || {};
-
- if (!uri)
- throw new Error('browser.chromeURL is undefined, please provide an explicit uri');
-
- if (['chrome', 'resource', 'data'].indexOf(io.newURI(uri, null, null).scheme) < 0)
- throw new Error('only chrome, resource and data uris are allowed');
-
- let newWindow = windowWatcher.
- openWindow(options.parent || null,
- uri,
- options.name || null,
- options.features ? serializeFeatures(options.features) : null,
- options.args || null);
-
- return newWindow;
-}
-exports.open = open;
-
-function onFocus(window) {
- let { resolve, promise } = defer();
-
- if (isFocused(window)) {
- resolve(window);
- }
- else {
- window.addEventListener("focus", function focusListener() {
- window.removeEventListener("focus", focusListener, true);
- resolve(window);
- }, true);
- }
-
- return promise;
-}
-exports.onFocus = onFocus;
-
-var isFocused = dispatcher("window-isFocused");
-isFocused.when(x => x instanceof Ci.nsIDOMWindow, (window) => {
- const FM = Cc["@mozilla.org/focus-manager;1"].
- getService(Ci.nsIFocusManager);
-
- let childTargetWindow = {};
- FM.getFocusedElementForWindow(window, true, childTargetWindow);
- childTargetWindow = childTargetWindow.value;
-
- let focusedChildWindow = {};
- if (FM.activeWindow) {
- FM.getFocusedElementForWindow(FM.activeWindow, true, focusedChildWindow);
- focusedChildWindow = focusedChildWindow.value;
- }
-
- return (focusedChildWindow === childTargetWindow);
-});
-exports.isFocused = isFocused;
-
-/**
- * Opens a top level window and returns it's `nsIDOMWindow` representation.
- * Same as `open` but with more features
- * @param {Object} options
- *
- */
-function openDialog(options) {
- options = options || {};
-
- let features = options.features || FEATURES;
- let featureAry = features.toLowerCase().split(',');
-
- if (!!options.private) {
- // add private flag if private window is desired
- if (!array.has(featureAry, 'private')) {
- featureAry.push('private');
- }
-
- // remove the non-private flag ig a private window is desired
- let nonPrivateIndex = featureAry.indexOf('non-private');
- if (nonPrivateIndex >= 0) {
- featureAry.splice(nonPrivateIndex, 1);
- }
-
- features = featureAry.join(',');
- }
-
- let browser = getMostRecentBrowserWindow();
-
- // if there is no browser then do nothing
- if (!browser)
- return undefined;
-
- let newWindow = browser.openDialog.apply(
- browser,
- array.flatten([
- options.url || URI_BROWSER,
- options.name || NAME,
- features,
- options.args || null
- ])
- );
-
- return newWindow;
-}
-exports.openDialog = openDialog;
-
-/**
- * Returns an array of all currently opened windows.
- * Note that these windows may still be loading.
- */
-function windows(type, options) {
- options = options || {};
- let list = [];
- let winEnum = WM.getEnumerator(type);
- while (winEnum.hasMoreElements()) {
- let window = winEnum.getNext().QueryInterface(Ci.nsIDOMWindow);
- // Only add non-private windows when pb permission isn't set,
- // unless an option forces the addition of them.
- if (!window.closed && (options.includePrivate || !isWindowPrivate(window))) {
- list.push(window);
- }
- }
- return list;
-}
-exports.windows = windows;
-
-/**
- * Check if the given window is interactive.
- * i.e. if its "DOMContentLoaded" event has already been fired.
- * @params {nsIDOMWindow} window
- */
-const isInteractive = window =>
- window.document.readyState === "interactive" ||
- isDocumentLoaded(window) ||
- // XUL documents stays '"uninitialized"' until it's `readyState` becomes
- // `"complete"`.
- isXULDocumentWindow(window) && window.document.readyState === "interactive";
-exports.isInteractive = isInteractive;
-
-/**
- * Check if the given browser window has finished the startup.
- * @params {nsIDOMWindow} window
- */
-const isStartupFinished = (window) =>
- isBrowser(window) &&
- window.gBrowserInit &&
- window.gBrowserInit.delayedStartupFinished;
-
-exports.isStartupFinished = isStartupFinished;
-
-const isXULDocumentWindow = ({document}) =>
- document.documentElement &&
- document.documentElement.namespaceURI === XUL_NS;
-
-/**
- * Check if the given window is completely loaded.
- * i.e. if its "load" event has already been fired and all possible DOM content
- * is done loading (the whole DOM document, images content, ...)
- * @params {nsIDOMWindow} window
- */
-function isDocumentLoaded(window) {
- return window.document.readyState == "complete";
-}
-exports.isDocumentLoaded = isDocumentLoaded;
-
-function isBrowser(window) {
- try {
- return window.document.documentElement.getAttribute("windowtype") === BROWSER;
- }
- catch (e) {}
- return false;
-};
-exports.isBrowser = isBrowser;
-
-function getWindowTitle(window) {
- return window && window.document ? window.document.title : null;
-}
-exports.getWindowTitle = getWindowTitle;
-
-function isXULBrowser(window) {
- return !!(isBrowser(window) && window.XULBrowserWindow);
-}
-exports.isXULBrowser = isXULBrowser;
-
-/**
- * Returns the most recent focused window
- */
-function getFocusedWindow() {
- let window = WM.getMostRecentWindow(BROWSER);
-
- return window ? window.document.commandDispatcher.focusedWindow : null;
-}
-exports.getFocusedWindow = getFocusedWindow;
-
-/**
- * Returns the focused browser window if any, or the most recent one.
- * Opening new window, updates most recent window, but focus window
- * changes later; so most recent window and focused window are not always
- * the same.
- */
-function getFocusedBrowser() {
- let window = FM.activeWindow;
- return isBrowser(window) ? window : getMostRecentBrowserWindow()
-}
-exports.getFocusedBrowser = getFocusedBrowser;
-
-/**
- * Returns the focused element in the most recent focused window
- */
-function getFocusedElement() {
- let window = WM.getMostRecentWindow(BROWSER);
-
- return window ? window.document.commandDispatcher.focusedElement : null;
-}
-exports.getFocusedElement = getFocusedElement;
-
-function getFrames(window) {
- return Array.slice(window.frames).reduce(function(frames, frame) {
- return frames.concat(frame, getFrames(frame));
- }, []);
-}
-exports.getFrames = getFrames;
-
-function getScreenPixelsPerCSSPixel(window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
-}
-exports.getScreenPixelsPerCSSPixel = getScreenPixelsPerCSSPixel;
-
-function getOwnerBrowserWindow(node) {
- /**
- Takes DOM node and returns browser window that contains it.
- **/
- let window = getToplevelWindow(node.ownerDocument.defaultView);
- // If anchored window is browser then it's target browser window.
- return isBrowser(window) ? window : null;
-}
-exports.getOwnerBrowserWindow = getOwnerBrowserWindow;
-
-function getParentWindow(window) {
- try {
- return window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem).parent
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
- }
- catch (e) {}
- return null;
-}
-exports.getParentWindow = getParentWindow;
-
-
-function getParentFrame(window) {
- try {
- return window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem).parent
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
- }
- catch (e) {}
- return null;
-}
-exports.getParentWindow = getParentWindow;
-
-// The element in which the window is embedded, or `null`
-// if the window is top-level. Similar to `window.frameElement`
-// but can cross chrome-content boundries.
-const getFrameElement = target =>
- (target instanceof Ci.nsIDOMDocument ? target.defaultView : target).
- QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils).
- containerElement;
-exports.getFrameElement = getFrameElement;
diff --git a/addon-sdk/source/lib/sdk/windows.js b/addon-sdk/source/lib/sdk/windows.js
deleted file mode 100644
index 06dbe70b2..000000000
--- 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;
-});
diff --git a/addon-sdk/source/lib/sdk/windows/fennec.js b/addon-sdk/source/lib/sdk/windows/fennec.js
deleted file mode 100644
index 3c3b6c313..000000000
--- 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);
- }
-});
diff --git a/addon-sdk/source/lib/sdk/windows/firefox.js b/addon-sdk/source/lib/sdk/windows/firefox.js
deleted file mode 100644
index 1eb1d8488..000000000
--- 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)));
diff --git a/addon-sdk/source/lib/sdk/windows/observer.js b/addon-sdk/source/lib/sdk/windows/observer.js
deleted file mode 100644
index 5ba2535f1..000000000
--- 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();
diff --git a/addon-sdk/source/lib/sdk/windows/tabs-fennec.js b/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
deleted file mode 100644
index 0ef5ec9f5..000000000
--- 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, false);
-
- // TabSelect
- window.BrowserApp.deck.addEventListener(EVENTS.activate.dom, onTabSelect, false);
- },
- 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, false);
- window.BrowserApp.deck.removeEventListener(EVENTS.activate.dom, onTabSelect, false);
-}
-
-// 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);
-}
diff --git a/addon-sdk/source/lib/sdk/worker/utils.js b/addon-sdk/source/lib/sdk/worker/utils.js
deleted file mode 100644
index fca19be63..000000000
--- 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;
diff --git a/addon-sdk/source/lib/sdk/zip/utils.js b/addon-sdk/source/lib/sdk/zip/utils.js
deleted file mode 100644
index e600380cb..000000000
--- a/addon-sdk/source/lib/sdk/zip/utils.js
+++ /dev/null
@@ -1,16 +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");
-
-function getZipReader(aFile) {
- return new Promise(resolve => {
- let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
- createInstance(Ci.nsIZipReader);
- zipReader.open(aFile);
- resolve(zipReader);
- });
-};
-exports.getZipReader = getZipReader;