Merge f-t to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2015-05-09 14:36:54 -07:00
commit 2e152fdfd0
311 changed files with 5835 additions and 11942 deletions

View File

@ -29,16 +29,8 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
EXTRA_JS_MODULES.commonjs.sdk.deprecated += [
'source/lib/sdk/deprecated/api-utils.js',
'source/lib/sdk/deprecated/cortex.js',
'source/lib/sdk/deprecated/errors.js',
'source/lib/sdk/deprecated/events.js',
'source/lib/sdk/deprecated/light-traits.js',
'source/lib/sdk/deprecated/list.js',
'source/lib/sdk/deprecated/memory.js',
'source/lib/sdk/deprecated/symbiont.js',
'source/lib/sdk/deprecated/sync-worker.js',
'source/lib/sdk/deprecated/traits-worker.js',
'source/lib/sdk/deprecated/traits.js',
'source/lib/sdk/deprecated/unit-test-finder.js',
'source/lib/sdk/deprecated/unit-test.js',
'source/lib/sdk/deprecated/window-utils.js',
@ -91,7 +83,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
'source/lib/sdk/test/memory.js',
'source/lib/sdk/test/options.js',
'source/lib/sdk/test/runner.js',
'source/lib/sdk/test/tmp-file.js',
'source/lib/sdk/test/utils.js',
]
@ -128,12 +119,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
]
EXTRA_JS_MODULES.commonjs.sdk.windows += [
'source/lib/sdk/windows/dom.js',
'source/lib/sdk/windows/fennec.js',
'source/lib/sdk/windows/firefox.js',
'source/lib/sdk/windows/observer.js',
'source/lib/sdk/windows/tabs-fennec.js',
'source/lib/sdk/windows/tabs-firefox.js',
]
EXTRA_JS_MODULES.commonjs += [
@ -183,10 +172,22 @@ EXTRA_JS_MODULES.commonjs.framescript += [
'source/lib/framescript/util.js',
]
EXTRA_JS_MODULES.commonjs['jetpack-id'] += [
'source/lib/jetpack-id/index.js',
]
EXTRA_JS_MODULES.commonjs.method += [
'source/lib/method/core.js',
]
EXTRA_JS_MODULES.commonjs['mozilla-toolkit-versioning'] += [
'source/lib/mozilla-toolkit-versioning/index.js',
]
EXTRA_JS_MODULES.commonjs['mozilla-toolkit-versioning'].lib += [
'source/lib/mozilla-toolkit-versioning/lib/utils.js',
]
EXTRA_JS_MODULES.commonjs.node += [
'source/lib/node/os.js',
]
@ -218,7 +219,6 @@ EXTRA_JS_MODULES.commonjs.sdk += [
'source/lib/sdk/timers.js',
'source/lib/sdk/ui.js',
'source/lib/sdk/url.js',
'source/lib/sdk/widget.js',
'source/lib/sdk/windows.js',
]
@ -277,10 +277,6 @@ EXTRA_JS_MODULES.commonjs.sdk.deprecated.events += [
'source/lib/sdk/deprecated/events/assembler.js',
]
EXTRA_JS_MODULES.commonjs.sdk.deprecated.traits += [
'source/lib/sdk/deprecated/traits/core.js',
]
EXTRA_JS_MODULES.commonjs.sdk.dom += [
'source/lib/sdk/dom/events.js',
]
@ -306,7 +302,6 @@ EXTRA_JS_MODULES.commonjs.sdk.input += [
'source/lib/sdk/input/customizable-ui.js',
'source/lib/sdk/input/frame.js',
'source/lib/sdk/input/system.js',
'source/lib/sdk/input/window.js',
]
EXTRA_JS_MODULES.commonjs.sdk.io += [

View File

@ -9,6 +9,7 @@ doc/modules/
doc/status.md5
packages/*
node_modules
cache
# Python
*.pyc
@ -18,3 +19,18 @@ node_modules
# Windows
*Thumbs.db
# Ignore subtrees
# git@github.com:jsantell/jetpack-id.git
lib/jetpack-id/*
!lib/jetpack-id/index.js
!lib/jetpack-id/package.json
# git@github.com:jsantell/mozilla-toolkit-versioning.git
lib/mozilla-toolkit-versioning/*
!lib/mozilla-toolkit-versioning/index.js
!lib/mozilla-toolkit-versioning/lib
lib/mozilla-toolkit-versioning/lib/*
!lib/mozilla-toolkit-versioning/lib/*.js
!lib/mozilla-toolkit-versioning/package.json

View File

@ -8,6 +8,7 @@ bin/
modules/
node_modules/
examples/
cache/
# Python
python-lib/

View File

@ -1,24 +1,26 @@
sudo: false
language: node_js
node_js:
- "iojs"
- "0.10"
env:
- JPM_FX_DEBUG=0
- JPM_FX_DEBUG=1
notifications:
irc: "irc.mozilla.org#jetpack"
cache:
directories:
- cache
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 -extension RANDR"
before_script:
- npm install mozilla-download -g
- npm install jpm -g
- cd ..
- mozilla-download --branch nightly -c prerelease --host ftp.mozilla.org firefox
- npm install fx-download -g
- npm install gulp -g
- bash bin/fx-download.sh
- export JPM_FIREFOX_BINARY=$TRAVIS_BUILD_DIR/../firefox/firefox
- cd $TRAVIS_BUILD_DIR
script:
- npm test

View File

@ -1,19 +1,19 @@
## Overview
- Changes should follow the [design guidelines], as well as the [coding style guide]
- All changes must be accompanied by tests
- In order to land, changes must have been reviewed by one of the Jetpack reviewers
- Changes should have additional API review when needed
- Changes should have additional review from a Mozilla platform domain-expert when needed
- All changes need tests
- In order to land, changes need a review by one of the Jetpack reviewers
- Changes may need an API review
- Changes may need a review from a Mozilla platform domain-expert
If you have questions, ask in [#jetpack on IRC][jetpack irc channel] or on the [Jetpack mailing list].
## How to Make Code Contributions
If you'd like to contribute the Jetpack project, follow these steps:
To write code for the Jetpack project, follow these steps:
1. Look for your issue in the list of [bugs already filed][open bugs]. If you want to contribute, but don't already know what you want to do, we keep a list of [good first bugs].
2. If no bug exists, [submit one][submit bug].
1. Look for your issue in the list of [bugs already filed][open bugs]. If you don't already know what you want to do, we keep a list of [good first bugs].
2. If no bug exists, [make one][make bug].
3. Get the code: get a [GitHub][GitHub] account, fork the [Add-on SDK repo][Add-on SDK repo], and clone it to your machine.
4. Make your changes. Changes should follow the [design guidelines] as well as the [coding style guide].
5. Write tests: [unit testing introduction][test intro], [unit testing API][test API].
@ -24,7 +24,7 @@ If you'd like to contribute the Jetpack project, follow these steps:
10. Flag the attachment for code review from one of the Jetpack reviewers listed below. This step is optional, but could speed things up.
11. Address any issues mentioned in the review.
Finally, once review is approved, a team member will do the merging
Finally, once the review is positive, a team member will do the merging
## Good First Bugs
@ -32,7 +32,7 @@ There is a list of [good first bugs here][good first bugs].
## Reviewers
All changes must be reviewed by someone on the Jetpack review crew:
All changes need a review by someone on the Jetpack review crew:
- [@mossop]
- [@gozala]
@ -50,7 +50,7 @@ For API and developer ergonomics review, ask [@gozala].
[jetpack irc channel]:irc://irc.mozilla.org/#jetpack
[Jetpack mailing list]:http://groups.google.com/group/mozilla-labs-jetpack
[open bugs]:https://bugzilla.mozilla.org/buglist.cgi?quicksearch=product%3ASDK
[submit bug]:https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK&component=general
[make bug]:https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK&component=general
[test intro]:https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Unit_testing
[test API]:https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/test_assert
[coding style guide]:https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide

View File

@ -6,7 +6,7 @@ If you find a problem, please [report the bug here](https://bugzilla.mozilla.org
## Developing Add-ons
These resources should provide some help:
These resources offer some help:
* [Add-on SDK Documentation](https://developer.mozilla.org/en-US/Add-ons/SDK)
* [Community Developed Modules](https://github.com/mozilla/addon-sdk/wiki/Community-developed-modules)
@ -17,7 +17,7 @@ These resources should provide some help:
## Contributing Code
Please read these two guides if you wish to contribute some patches to the addon-sdk:
Please read these two guides if you wish to make some patches to the addon-sdk:
* [Contribute Guide](https://github.com/mozilla/addon-sdk/blob/master/CONTRIBUTING.md)
* [Style Guide](https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide)
@ -29,3 +29,4 @@ We use [bugzilla](https://bugzilla.mozilla.org/) as our issue tracker, here are
* [File a bug](https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK)
* [Open bugs](https://bugzilla.mozilla.org/buglist.cgi?bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&columnlist=bug_severity%2Cpriority%2Cassigned_to%2Cbug_status%2Ctarget_milestone%2Cresolution%2Cshort_desc%2Cchangeddate&product=Add-on%20SDK&query_format=advanced&order=priority)
* [Good first bugs](https://bugzilla.mozilla.org/buglist.cgi?status_whiteboard=[good+first+bug]&&resolution=---&product=Add-on+SDK)
* [Good next bugs](https://bugzilla.mozilla.org/buglist.cgi?status_whiteboard=[good+next+bug]&&resolution=---&product=Add-on+SDK)

View File

@ -0,0 +1,7 @@
#!/bin/sh
if [ "$JPM_FX_DEBUG" = "1" ]; then
fx-download --branch nightly -c prerelease --host ftp.mozilla.org ../firefox --debug
else
fx-download --branch nightly -c prerelease --host ftp.mozilla.org ../firefox
fi

View File

View File

@ -11,13 +11,17 @@ var mocha = new Mocha({
timeout: 900000
});
var isDebug = require("./node-scripts/utils").isDebug;
exports.run = function(type) {
return new Promise(function(resolve) {
type = type || "";
[
(/^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
(/^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
(!isDebug && /^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
(!isDebug && /^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
(/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"),
(!isDebug && /^(docs)?$/.test(type)) && require.resolve("../bin/node-scripts/test.docs"),
(!isDebug && /^(ini)?$/.test(type)) && require.resolve("../bin/node-scripts/test.ini"),
].sort().forEach(function(filepath) {
filepath && mocha.addFile(filepath);
})

View File

@ -0,0 +1,64 @@
/* 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 path = require("path");
var cp = require("child_process");
var fs = require("fs");
var Promise = require("promise");
var patcher = require("patch-editor");
var readParam = require("./utils").readParam;
var isKeeper = /\/addon-sdk\/source/;
function apply(options) {
return clean(options).then(function() {
return new Promise(function(resolve) {
var patch = path.resolve(readParam("patch"));
var proc = cp.spawn("git", ["apply", patch]);
proc.stdout.pipe(process.stdout);
proc.stderr.pipe(process.stderr);
proc.on("close", resolve);
});
});
}
exports.apply = apply;
function clean(options) {
return new Promise(function(resolve) {
var patch = path.resolve(readParam("patch"));
if (!patch) {
throw new Error("no --patch was provided.");
}
console.log("Cleaning patch " + patch);
patcher.getChunks({ patch: patch }).then(function(chunks) {
var keepers = [];
for (var i = chunks.length - 1; i >= 0; i--) {
var chunk = chunks[i];
var files = chunk.getFilesChanged();
// check if the file changed is related to the addon-sdk/source directory
var keepIt = files.map(function(file) {
return (isKeeper.test(file));
}).reduce(function(prev, curr) {
return prev || curr;
}, false);
if (keepIt) {
keepers.push(chunk);
}
}
var contents = "\n" + keepers.join("\n") + "\n";
contents = contents.replace(/\/addon-sdk\/source/g, "");
fs.writeFileSync(patch, contents, { encoding: "utf8" });
console.log("Done cleaning patch.");
}).then(resolve).catch(console.error);
});
}
exports.clean = clean;

View File

@ -8,6 +8,7 @@ var path = require("path");
var fs = require("fs");
var jpm = utils.run;
var readParam = utils.readParam;
var isDebug = utils.isDebug;
var addonsPath = path.join(__dirname, "..", "..", "test", "addons");
@ -40,6 +41,14 @@ function fileFilter(root, file) {
if (/^(l10n-properties|simple-prefs|page-mod-debugger)/.test(file)) {
return false;
}
// filter additional add-ons when using debug builds
if (isDebug) {
if (/^(chrome|e10s)/.test(file)) {
return false;
}
}
if (matcher && !matcher.test(file)) {
return false;
}

View File

@ -0,0 +1,145 @@
/* 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 createHash = require('crypto').createHash;
var fs = require("fs");
var fsExtra = require("fs-extra")
var path = require("path");
var Promise = require("promise");
var chai = require("chai");
var expect = chai.expect;
var teacher = require("teacher");
var rootURI = path.join(__dirname, "..", "..");
// get a list of words that fail spell check but are still acceptable
var NEW_WORDS = fs.readFileSync(path.join(__dirname, "words.txt")).toString().trim().split("\n");
var CACHE_PATH = path.join(__dirname, "..", "..", "cache", "spellchecks.json");
var CACHE = {};
try {
CACHE = JSON.parse(fs.readFileSync(CACHE_PATH).toString());
}
catch (e) {}
function md5(str) {
return createHash("md5").update(str).digest("utf8");
}
function addCacheHash(hash) {
CACHE[hash] = true;
fsExtra.ensureFileSync(CACHE_PATH);
fsExtra.writeJSONSync(CACHE_PATH, CACHE);
}
describe("Spell Checking", function () {
it("Spellcheck CONTRIBUTING.md", function (done) {
var readme = path.join(rootURI, "CONTRIBUTING.md");
fs.readFile(readme, function (err, data) {
if (err) {
throw err;
}
var text = data.toString();
var hash = md5(text);
// skip this test if we know we have done the
// exact same test with positive results before
if (CACHE[hash]) {
expect(CACHE[hash]).to.be.equal(true);
return done();
}
teacher.check(text, function(err, data) {
expect(err).to.be.equal(null);
var results = data || [];
results = results.filter(function(result) {
if (NEW_WORDS.indexOf(result.string.toLowerCase()) != -1) {
return false;
}
// ignore anything that starts with a dash
if (result.string[0] == "-") {
return false;
}
if (!(new RegExp(result.string)).test(text)) {
return false;
}
return true;
})
if (results.length > 0) {
console.log(results);
}
else {
addCacheHash(hash);
}
expect(results.length).to.be.equal(0);
setTimeout(done, 500);
});
});
});
it("Spellcheck README.md", function (done) {
var readme = path.join(rootURI, "README.md");
fs.readFile(readme, function (err, data) {
if (err) {
throw err;
}
var text = data.toString();
var hash = md5(text);
// skip this test if we know we have done the
// exact same test with positive results before
if (CACHE[hash]) {
expect(CACHE[hash]).to.be.equal(true);
return done();
}
teacher.check(text, function(err, data) {
expect(err).to.be.equal(null);
var results = data || [];
results = results.filter(function(result) {
if (NEW_WORDS.indexOf(result.string.toLowerCase()) != -1) {
return false;
}
// ignore anything that starts with a dash
if (result.string[0] == "-") {
return false;
}
// ignore anything that we don't find in the original text,
// for some reason "bootstrap.js" becomes "bootstrapjs".
if (!(new RegExp(result.string)).test(text)) {
return false;
}
return true;
})
if (results.length > 0) {
console.log(results);
}
else {
addCacheHash(hash);
}
expect(results.length).to.be.equal(0);
done();
});
});
});
});

View File

@ -0,0 +1,39 @@
/* 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 fs = require("fs");
var path = require("path");
var Promise = require("promise");
var chai = require("chai");
var expect = chai.expect;
var ini = require("./update-ini");
var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
describe("Checking ini files", function () {
it("Check test/addons/jetpack-addon.ini", function (done) {
fs.readFile(addonINI, function (err, data) {
if (err) {
throw err;
}
var text = data.toString();
var expected = "";
ini.makeAddonIniContent()
.then(function(contents) {
expected = contents;
setTimeout(function end() {
expect(expected.trim()).to.be.equal(text.trim());
done();
});
});
});
});
});

View File

@ -0,0 +1,58 @@
/* 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 path = require("path");
var cp = require("child_process");
var fs = require("fs");
var Promise = require("promise");
var parser = require("ini-parser");
var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
var addonsDir = path.resolve("./test/addons/");
function updateAddonINI() {
return new Promise(function(resolve) {
console.log("Start updating " + addonINI);
makeAddonIniContent().
then(function(contents) {
fs.writeFileSync(addonINI, contents, { encoding: "utf8" });
console.log("Done updating " + addonINI);
resolve();
});
})
}
exports.updateAddonINI = updateAddonINI;
function makeAddonIniContent() {
return new Promise(function(resolve) {
var data = parser.parse(fs.readFileSync(addonINI, { encoding: "utf8" }).toString());
var result = {};
fs.readdir(addonsDir, function(err, files) {
var folders = files.filter(function(file) {
return fs.statSync(path.resolve(addonsDir, file)).isDirectory();
}).sort();
folders.forEach(function(folder) {
var oldData = data[folder + ".xpi"];
result[folder] = oldData ? oldData : {};
});
// build ini file
var contents = [];
Object.keys(result).sort().forEach(function(key) {
contents.push("[" + key + ".xpi]");
Object.keys(result[key]).forEach(function(dataKey) {
contents.push(dataKey + " = " + result[key][dataKey]);
});
});
contents = contents.join("\n") + "\n";
return resolve(contents);
});
});
}
exports.makeAddonIniContent = makeAddonIniContent;

View File

@ -17,13 +17,25 @@ var sdk = path.join(__dirname, "..", "..");
var prefsPath = path.join(sdk, "test", "preferences", "test-preferences.js");
var e10sPrefsPath = path.join(sdk, "test", "preferences", "test-e10s-preferences.js");
var OUTPUT_FILTERS = [
/[^\n\r]+WARNING\: NS_ENSURE_SUCCESS\(rv, rv\) failed[^\n]+\n\r?/
];
var isDebug = (process.env["JPM_FX_DEBUG"] == "1");
exports.isDebug = isDebug;
function spawn (cmd, options) {
options = options || {};
var env = _.extend({}, options.env, process.env);
if (isDebug) {
env["MOZ_QUIET"] = 1;
}
var e10s = options.e10s || false;
return child_process.spawn("node", [
jpm, cmd, "-v",
jpm, cmd, "-v", "--tbpl",
"--prefs", e10s ? e10sPrefsPath : prefsPath,
"-o", sdk,
"-f", options.filter || ""
@ -37,16 +49,34 @@ exports.spawn = spawn;
function run (cmd, options, p) {
return new Promise(function(resolve) {
var output = [];
var proc = spawn(cmd, options);
proc.stderr.pipe(process.stderr);
proc.stdout.on("data", function (data) {
for (var i = OUTPUT_FILTERS.length - 1; i >= 0; i--) {
if (OUTPUT_FILTERS[i].test(data)) {
return null;
}
}
output.push(data);
return null;
});
if (p) {
proc.stdout.pipe(p.stdout);
}
else {
proc.stdout.on("data", function (data) {
data = (data || "") + "";
if (/TEST-/.test(data)) {
DEFAULT_PROCESS.stdout.write(data.replace(/[\s\n]+$/, "") + "\n");
}
});
}
proc.on("close", function(code) {
var out = output.join("");
var buildDisplayed = /Build \d+/.test(out);
var noTests = /No tests were run/.test(out);
var hasSuccess = /All tests passed!/.test(out);
var hasFailure = /There were test failures\.\.\./.test(out);
@ -54,6 +84,7 @@ function run (cmd, options, p) {
DEFAULT_PROCESS.stdout.write(out);
}
expect(code).to.equal(hasFailure ? 1 : 0);
expect(buildDisplayed).to.equal(true);
expect(hasFailure).to.equal(false);
expect(hasSuccess).to.equal(true);
expect(noTests).to.equal(false);

View File

@ -0,0 +1,12 @@
addon-sdk
github
stackoverflow
bugzilla
irc
erikvold
jsantell
mossop
gozala
zer0
autonome
0c0w3

View File

@ -6,5 +6,5 @@
"version": "0.0.1",
"author": "Irakli Gozalishvili",
"main": "./index.js",
"license": "MPL 2.0"
"license": "MPL-2.0"
}

View File

@ -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/. -->
This add-on enables users to add notes, or annotations, to Web pages.
Usage
-----
To switch the annotator on, left-click the pencil icon in the Add-on Bar. The
icon should turn yellow: this indicates that the annotator is active. To switch
it off, click it again. Switching it on/off only stops you from entering
annotations: existing annotations are still displayed.
When the annotator is active and the user moves the mouse over a page element
that can be annotated, the annotator highlights that elements by giving it a
yellow background.
If the user clicks on a highlighted element the add-on opens a dialog for the
user to enter the annotation. When the user hits <return> the annotation is
saved.
Elements which have been annotated are displayed with a yellow border: when the
user moves the mouse over one of these elements, the add-on displays the
annotation associated with that element.
To view all annotations in a list, right-click the pencil icon.
The add-on is deactivated in private browsing mode, meaning that new annotations
can't be created although existing ones are still shown. On exiting private
browsing the add-on returns to its previous activation state.
Known Issues/Limitations
------------------------
It is not possible to delete annotations, or to edit them after creating them,
but it would be simple to add this.
When right-clicking the annotator icon the add-on bar's context-menu is shown:
this is tracked by
[bug 626326](https://bugzilla.mozilla.org/show_bug.cgi?id=626326).
The list of annotations should be anchored to the widget. The annotation
editor, and the annotation itself, should be anchored to the element which is
annotated. The will be done when the implementation of panel-anchoring is
extended.

View File

@ -1,31 +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/. -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Annotation</title>
<style type="text/css" media="all">
body {
font: 100% arial, helvetica, sans-serif;
}
div {
text-align:left;
}
</style>
</head>
<body>
<div id = "annotation">
</div>
</body>
</html>

View File

@ -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/. */
/*
Initialize annotation content.
*/
self.on('message', function(message) {
$('#annotation').text(message);
});

View File

@ -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/. -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Annotation</title>
<style type="text/css" media="all">
body, html {
font: 100% arial, helvetica, sans-serif;
padding: 0;
margin: 0;
position: fixed;
}
textarea {
width: 100%;
height: 100%;
margin: 10px;
padding: 0;
color: inherit !important;
font: inherit !important;
background: transparent;
border: none;
}
</style>
</head>
<body>
<textarea rows='10' cols='20' id='annotation-box'>
</textarea>
</body>
</html>

View File

@ -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/. */
/*
On a return key, send the content of the textArea back to the add-on,
and zero the textArea for the next time.
*/
var textArea = document.getElementById('annotation-box');
textArea.onkeyup = function(event) {
if (event.keyCode == 13) {
self.postMessage(textArea.value);
textArea.value = '';
}
};
self.on('message', function() {
var textArea = document.getElementById('annotation-box');
textArea.value = '';
textArea.focus();
});

View File

@ -1,154 +0,0 @@
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

View File

@ -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/.
#annotation-list .annotation-details
{
padding: 10px;
margin: 10px;
border: solid 3px #EEE;
background-color: white;
}
#annotation-list .url, .selection-text, .annotation-text
{
padding: 5px;
margin: 5px;
}
#annotation-list .selection-text,#annotation-list .annotation-text
{
border: solid 1px #EEE;
}
#annotation-list .annotation-text
{
font-style: italic;
}
body
{
background-color: #F5F5F5;
font: 100% arial, helvetica, sans-serif;
}
h1
{
font-family: georgia,serif;
font-size: 1.5em;
text-align:center;
}

View File

@ -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/. -->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Saved annotations</title>
<link rel="stylesheet" type="text/css" href="annotation-list.css" />
</head>
<body>
<div id="annotation-list">
</div>
<div id="template">
<div class="annotation-details">
<a class="url"></a>
<div class="selection-text"></div>
<div class="annotation-text"></div>
</div>
</div>
</body>
</html>

View File

@ -1,31 +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/. */
/*
Construct the HTML for the annotation list.
Bind a function to click events on the link that send a message back to
the add-on code, so it can open the link in the main browser.
*/
self.on("message", function onMessage(storedAnnotations) {
var annotationList = $('#annotation-list');
annotationList.empty();
storedAnnotations.forEach(
function(storedAnnotation) {
var annotationHtml = $('#template .annotation-details').clone();
annotationHtml.find('.url').text(storedAnnotation.url)
.attr('href', storedAnnotation.url);
annotationHtml.find('.url').bind('click', function(event) {
event.stopPropagation();
event.preventDefault();
self.postMessage(storedAnnotation.url);
});
annotationHtml.find('.selection-text')
.text(storedAnnotation.anchorText);
annotationHtml.find('.annotation-text')
.text(storedAnnotation.annotationText);
annotationList.append(annotationHtml);
});
});

View File

@ -1,50 +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/. */
/*
Locate anchors for annotations and prepare to display the annotations.
For each annotation, if its URL matches this page,
- get the ancestor whose ID matches the ID in the anchor
- look for a <p> element whose content contains the anchor text
That's considered a match. Then we:
- highlight the anchor element
- add an 'annotated' class to tell the selector to skip this element
- embed the annottion text as a new attribute
For all annotated elements:
- bind 'mouseenter' and 'mouseleave' events to the element, to send 'show'
and 'hide' messages back to the add-on.
*/
self.on('message', function onMessage(annotations) {
annotations.forEach(
function(annotation) {
if(annotation.url == document.location.toString()) {
createAnchor(annotation);
}
});
$('.annotated').css('border', 'solid 3px yellow');
$('.annotated').bind('mouseenter', function(event) {
self.port.emit('show', $(this).attr('annotation'));
event.stopPropagation();
event.preventDefault();
});
$('.annotated').bind('mouseleave', function() {
self.port.emit('hide');
});
});
function createAnchor(annotation) {
annotationAnchorAncestor = $('#' + annotation.ancestorId)[0] || document.body;
annotationAnchor = $(annotationAnchorAncestor).parent().find(
':contains("' + annotation.anchorText + '")').last();
annotationAnchor.addClass('annotated');
annotationAnchor.attr('annotation', annotation.annotationText);
}

View File

@ -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/. */
/*
The selector locates elements that are suitable for annotation and enables
the user to select them.
On 'mouseenter' events associated with <p> elements:
- if the selector is active and the element is not already annotated
- find the nearest ancestor which has an id attribute: this is supposed to
make identification of this element more accurate
- highlight the element
- bind 'click' for the element to send a message back to the add-on, including
all the information associated with the anchor.
*/
var matchedElement = null;
var originalBgColor = null;
var active = false;
function resetMatchedElement() {
if (matchedElement) {
matchedElement.css('background-color', originalBgColor);
matchedElement.unbind('click.annotator');
}
}
self.on('message', function onMessage(activation) {
active = activation;
if (!active) {
resetMatchedElement();
}
});
function getInnerText(element) {
// jQuery.text() returns content of <script> tags, we need to ignore those
var list = [];
element.find("*").andSelf().contents()
.filter(function () {
return this.nodeType == 3 && this.parentNode.tagName != "SCRIPT";
})
.each(function () {
list.push(this.nodeValue);
});
return list.join("");
}
$('*').mouseenter(function() {
if (!active || $(this).hasClass('annotated')) {
return;
}
resetMatchedElement();
ancestor = $(this).closest("[id]");
matchedElement = $(this).first();
originalBgColor = matchedElement.css('background-color');
matchedElement.css('background-color', 'yellow');
matchedElement.bind('click.annotator', function(event) {
event.stopPropagation();
event.preventDefault();
self.port.emit('show',
[
document.location.toString(),
ancestor.attr("id"),
getInnerText(matchedElement)
]
);
});
});
$('*').mouseout(function() {
resetMatchedElement();
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -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/. */
/*
Listen for left and right click events and send the corresponding message
to the content script.
*/
this.addEventListener('click', function(event) {
if(event.button == 0 && event.shiftKey == false)
self.port.emit('left-click');
if(event.button == 2 || (event.button == 0 && event.shiftKey == true))
self.port.emit('right-click');
event.preventDefault();
}, true);

View File

@ -1,266 +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/. */
var widgets = require('sdk/widget');
var pageMod = require('sdk/page-mod');
var data = require('sdk/self').data;
var panels = require('sdk/panel');
var simpleStorage = require('sdk/simple-storage');
var notifications = require("sdk/notifications");
/*
Global variables
* Boolean to indicate whether the add-on is switched on or not
* Array for all workers associated with the 'selector' page mod
* Array for all workers associated with the 'matcher' page mod
*/
var annotatorIsOn = false;
var selectors = [];
var matchers = [];
if (!simpleStorage.storage.annotations)
simpleStorage.storage.annotations = [];
/*
Update the matchers: call this whenever the set of annotations changes
*/
function updateMatchers() {
matchers.forEach(function (matcher) {
matcher.postMessage(simpleStorage.storage.annotations);
});
}
/*
Constructor for an Annotation object
*/
function Annotation(annotationText, anchor) {
this.annotationText = annotationText;
this.url = anchor[0];
this.ancestorId = anchor[1];
this.anchorText = anchor[2];
}
/*
Function to deal with a new annotation.
Create a new annotation object, store it, and
notify all the annotators of the change.
*/
function handleNewAnnotation(annotationText, anchor) {
var newAnnotation = new Annotation(annotationText, anchor);
simpleStorage.storage.annotations.push(newAnnotation);
updateMatchers();
}
/*
Function to tell the selector page mod that the add-on has become (in)active
*/
function activateSelectors() {
selectors.forEach(
function (selector) {
selector.postMessage(annotatorIsOn);
});
}
/*
Toggle activation: update the on/off state and notify the selectors.
*/
function toggleActivation() {
annotatorIsOn = !annotatorIsOn;
activateSelectors();
return annotatorIsOn;
}
function detachWorker(worker, workerArray) {
var index = workerArray.indexOf(worker);
if(index != -1) {
workerArray.splice(index, 1);
}
}
exports.main = function() {
/*
The widget provides a mechanism to switch the selector on or off, and to
view the list of annotations.
The selector is switched on/off with a left-click, and the list of annotations
is displayed on a right-click.
*/
var widget = widgets.Widget({
id: 'toggle-switch',
label: 'Annotator',
contentURL: data.url('widget/pencil-off.png'),
contentScriptWhen: 'ready',
contentScriptFile: data.url('widget/widget.js')
});
widget.port.on('left-click', function() {
console.log('activate/deactivate');
widget.contentURL = toggleActivation() ?
data.url('widget/pencil-on.png') :
data.url('widget/pencil-off.png');
});
widget.port.on('right-click', function() {
console.log('show annotation list');
annotationList.show();
});
/*
The selector page-mod enables the user to select page elements to annotate.
It is attached to all pages but only operates if the add-on is active.
The content script highlights any page elements which can be annotated. If the
user clicks a highlighted element it sends a message to the add-on containing
information about the element clicked, which is called the anchor of the
annotation.
When we receive this message we assign the anchor to the annotationEditor and
display it.
*/
var selector = pageMod.PageMod({
include: ['*'],
contentScriptWhen: 'ready',
contentScriptFile: [data.url('jquery-1.4.2.min.js'),
data.url('selector.js')],
onAttach: function(worker) {
worker.postMessage(annotatorIsOn);
selectors.push(worker);
worker.port.on('show', function(data) {
annotationEditor.annotationAnchor = data;
annotationEditor.show();
});
worker.on('detach', function () {
detachWorker(this, selectors);
});
}
});
/*
The annotationEditor panel is the UI component used for creating
new annotations. It contains a text area for the user to
enter the annotation.
When we are ready to display the editor we assign its 'anchor' property
and call its show() method.
Its content script sends the content of the text area to the add-on
when the user presses the return key.
When we receives this message we create a new annotation using the anchor
and the text the user entered, store it, and hide the panel.
*/
var annotationEditor = panels.Panel({
width: 220,
height: 220,
contentURL: data.url('editor/annotation-editor.html'),
contentScriptFile: data.url('editor/annotation-editor.js'),
onMessage: function(annotationText) {
if (annotationText)
handleNewAnnotation(annotationText, this.annotationAnchor);
annotationEditor.hide();
},
onShow: function() {
this.postMessage('focus');
}
});
/*
The annotationList panel is the UI component that lists all the annotations
the user has entered.
On its 'show' event we pass it the array of annotations.
The content script creates the HTML elements for the annotations, and
intercepts clicks on the links, passing them back to the add-on to open them
in the browser.
*/
var annotationList = panels.Panel({
width: 420,
height: 200,
contentURL: data.url('list/annotation-list.html'),
contentScriptFile: [data.url('jquery-1.4.2.min.js'),
data.url('list/annotation-list.js')],
contentScriptWhen: 'ready',
onShow: function() {
this.postMessage(simpleStorage.storage.annotations);
},
onMessage: function(message) {
require('sdk/tabs').open(message);
}
});
/*
We listen for the OverQuota event from simple-storage.
If it fires we just notify the user and delete the most
recent annotations until we are back in quota.
*/
simpleStorage.on("OverQuota", function () {
notifications.notify({
title: 'Storage space exceeded',
text: 'Removing recent annotations'});
while (simpleStorage.quotaUsage > 1)
simpleStorage.storage.annotations.pop();
});
/*
The matcher page-mod locates anchors on web pages and prepares for the
annotation to be displayed.
It is attached to all pages, and when it is attached we pass it the complete
list of annotations. It looks for anchors in its page. If it finds one it
highlights the anchor and binds mouseenter/mouseout events to 'show' and 'hide'
messages to the add-on.
When the add-on receives the 'show' message it assigns the annotation text to
the annotation panel and shows it.
Note that the matcher is active whether or not the add-on is active:
'inactive' only means that the user can't create new add-ons, they can still
see old ones.
*/
var matcher = pageMod.PageMod({
include: ['*'],
contentScriptWhen: 'ready',
contentScriptFile: [data.url('jquery-1.4.2.min.js'),
data.url('matcher.js')],
onAttach: function(worker) {
if(simpleStorage.storage.annotations) {
worker.postMessage(simpleStorage.storage.annotations);
}
worker.port.on('show', function(data) {
annotation.content = data;
annotation.show();
});
worker.port.on('hide', function() {
annotation.content = null;
annotation.hide();
});
worker.on('detach', function () {
detachWorker(this, matchers);
});
matchers.push(worker);
}
});
/*
The annotation panel is the UI component that displays an annotation.
When we are ready to show it we assign its 'content' attribute to contain
the annotation text, and that gets sent to the content process in onShow().
*/
var annotation = panels.Panel({
width: 200,
height: 180,
contentURL: data.url('annotation/annotation.html'),
contentScriptFile: [data.url('jquery-1.4.2.min.js'),
data.url('annotation/annotation.js')],
contentScriptWhen: 'ready',
onShow: function() {
this.postMessage(this.content);
}
});
}

View File

@ -1,11 +0,0 @@
{
"license": "MPL 2.0",
"name": "annotator",
"contributors": [],
"author": "Will Bamberg",
"keywords": [],
"version": "0.1.1",
"id": "anonid0-annotator@jetpack",
"description": "Add notes to Web pages",
"main": "./lib/main.js"
}

View File

@ -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";
exports.testMain = function(assert) {
assert.pass("TODO: Write some tests.");
};
require("sdk/test").run(exports);

View File

@ -6,5 +6,5 @@
"version": "0.0.1",
"author": "Irakli Gozalishvili",
"main": "./index.js",
"license": "MPL 2.0"
"license": "MPL-2.0"
}

View File

@ -1,13 +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 is a port to the SDK of the
[Library Detector add-on](https://addons.mozilla.org/en-US/firefox/addon/library-detector/).
The original Library Detector is written by
[Paul Bakaus](http://paulbakaus.com/) and made available under the
[MIT License](http://www.opensource.org/licenses/mit-license.php).
It only recognizes a subset of the libraries recognized by the original,
just to keep the SDK download package size and on-disk footprint as small
as possible.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -1,97 +0,0 @@
/*
The code in this file is adapted from the original
Library Detector add-on
(https://addons.mozilla.org/en-US/firefox/addon/library-detector/) written by
Paul Bakaus (http://paulbakaus.com/) and made available under the
MIT License (http://www.opensource.org/licenses/mit-license.php).
*/
var LD_tests = {
'jQuery': {
test: function(win) {
var jq = win.jQuery || win.$ || win.$jq || win.$j;
if(jq && jq.fn && jq.fn.jquery) {
return { version: jq.fn.jquery };
} else {
return false;
}
}
},
'jQuery UI': {
//phonehome: 'http://jqueryui.com/phone_home',
test: function(win) {
var jq = win.jQuery || win.$ || win.$jq || win.$j;
if(jq && jq.fn && jq.fn.jquery && jq.ui) {
var plugins = 'accordion,datepicker,dialog,draggable,droppable,progressbar,resizable,selectable,slider,menu,grid,tabs'.split(','), concat = [];
for (var i=0; i < plugins.length; i++) { if(jq.ui[plugins[i]]) concat.push(plugins[i].substr(0,1).toUpperCase() + plugins[i].substr(1)); };
return { version: jq.ui.version, details: concat.length ? 'Plugins used: '+concat.join(',') : '' };
} else {
return false;
}
}
},
'MooTools': {
test: function(win) {
if(win.MooTools && win.MooTools.version) {
return { version: win.MooTools.version };
} else {
return false;
}
}
},
'YUI': {
test: function(win) {
if(win.YAHOO && win.YAHOO.VERSION) {
return { version: win.YAHOO.VERSION };
} else {
return false;
}
}
},
'Closure': {
test: function(win) {
if(win.goog) {
return { version: '2.0' };
}
return false;
}
},
'Modernizr': {
test: function(win) {
if(win.Modernizr) {
return { version: win.Modernizr._version };
}
return false;
}
},
};
function testLibraries() {
var win = unsafeWindow;
var libraryList = [];
for(var i in LD_tests) {
var passed = LD_tests[i].test(win);
if (passed) {
let libraryInfo = {
name: i,
version: passed.version
};
libraryList.push(libraryInfo);
}
}
self.postMessage(libraryList);
}
testLibraries();

View File

@ -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/. -->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Library detector</title>
<script type="text/javascript">
addon.on('message', function (libraryInfo) {
document.body.innerHTML = libraryInfo;
});
</script>
</head>
<body></body>
</html>

View File

@ -1,50 +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/. -->
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Library detector</title>
<style type="text/css" media="all">
img {
display: inline;
width: 16px;
height: 16px;
}
</style>
<script type="text/javascript">
var icons = {
'jQuery' : 'jquery.ico',
'jQuery UI' : 'jquery_ui.ico',
'MooTools' : 'mootools.png',
'YUI' : 'yui.ico',
'Closure' : 'closure.ico',
'Modernizr': 'modernizr.ico',
};
// Listen for mouse events over icons, in order to send a message up to
// the panel and update its content with library name and version
window.addEventListener('mouseover', function (event) {
if (event.target.tagName == 'IMG') {
addon.port.emit('setLibraryInfo', event.target.title);
}
}, false);
addon.port.on('update', function (libraries) {
// Cleanup previous content
document.body.innerHTML = '';
// Create new updated list of icons
libraries.forEach(function(library) {
var img = document.createElement('img');
img.setAttribute('src', 'icons/' + icons[library.name]);
img.setAttribute('title', library.name + "<br>Version: " +
library.version);
document.body.appendChild(img);
});
});
</script>
</head>
<body></body>
</html>

View File

@ -1,67 +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 tabs = require('sdk/tabs');
const widgets = require('sdk/widget');
const data = require('sdk/self').data;
const pageMod = require('sdk/page-mod');
const panel = require('sdk/panel');
const ICON_WIDTH = 16;
function updateWidgetView(tab) {
let widgetView = widget.getView(tab.window);
if (!tab.libraries) {
tab.libraries = [];
}
widgetView.port.emit("update", tab.libraries);
widgetView.width = tab.libraries.length * ICON_WIDTH;
}
var widget = widgets.Widget({
id: "library-detector",
label: "Library Detector",
contentURL: data.url("widget.html"),
panel: panel.Panel({
width: 240,
height: 60,
contentURL: data.url("panel.html")
})
});
widget.port.on('setLibraryInfo', function(libraryInfo) {
widget.panel.postMessage(libraryInfo);
});
pageMod.PageMod({
include: "*",
contentScriptWhen: 'end',
contentScriptFile: (data.url('library-detector.js')),
onAttach: function(worker) {
worker.on('message', function(libraryList) {
if (!worker.tab.libraries) {
worker.tab.libraries = [];
}
libraryList.forEach(function(library) {
if (worker.tab.libraries.indexOf(library) == -1) {
worker.tab.libraries.push(library);
}
});
if (worker.tab == tabs.activeTab) {
updateWidgetView(worker.tab);
}
});
}
});
tabs.on('activate', function(tab) {
updateWidgetView(tab);
});
/*
For change of location
*/
tabs.on('ready', function(tab) {
tab.libraries = [];
});

View File

@ -1,10 +0,0 @@
{
"name": "library-detector-sdk",
"license": "MPL 2.0",
"author": "",
"version": "0.1.1",
"title": "library-detector-sdk",
"id": "jid1-R4rSVNkBANnvGQ@jetpack",
"description": "a basic add-on",
"main": "./lib/main.js"
}

View File

@ -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";
exports.testMain = function(assert) {
assert.pass("TODO: Write some tests.");
};
require("sdk/test").run(exports);

View File

@ -4,6 +4,6 @@
"keywords": [],
"author": "Brian Warner",
"contributors": [],
"license": "MPL 2.0",
"license": "MPL-2.0",
"id": "reading-data-example@jetpack.mozillalabs.com"
}

View File

@ -4,7 +4,7 @@
"id": "theme@jetpack",
"description": "How to create new theme for devtools",
"author": "Jan Odvarko",
"license": "MPL 2.0",
"license": "MPL-2.0",
"version": "0.1.0",
"main": "lib/main"
}

View File

@ -4,7 +4,7 @@
"main": "./lib/main.js",
"description": "a toolbar api example",
"author": "",
"license": "MPL 2.0",
"license": "MPL-2.0",
"version": "0.1.1",
"engines": {
"firefox": ">=27.0 <=30.0"

View File

@ -4,7 +4,7 @@
"id": "ui-button-apis@mozilla.org",
"description": "A Button API example",
"author": "jeff@canuckistani.ca (Jeff Griffiths | @canuckistani)",
"license": "MPL 2.0",
"license": "MPL-2.0",
"version": "0.1.1",
"main": "./lib/main.js"
}

View File

@ -4,20 +4,41 @@
"use strict";
var gulp = require('gulp');
var patch = require("./bin/node-scripts/apply-patch");
var ini = require("./bin/node-scripts/update-ini");
gulp.task('test', function(done) {
require("./bin/jpm-test").run().then(done);
});
gulp.task('test:addons', function(done) {
require("./bin/jpm-test").run("addons").then(done);
require("./bin/jpm-test").run("addons").catch(console.error).then(done);
});
gulp.task('test:docs', function(done) {
require("./bin/jpm-test").run("docs").catch(console.error).then(done);
});
gulp.task('test:examples', function(done) {
require("./bin/jpm-test").run("examples").then(done);
require("./bin/jpm-test").run("examples").catch(console.error).then(done);
});
gulp.task('test:modules', function(done) {
require("./bin/jpm-test").run("modules").then(done);
require("./bin/jpm-test").run("modules").catch(console.error).then(done);
});
gulp.task('test:ini', function(done) {
test("ini").catch(console.error).then(done);
});
gulp.task('patch:clean', function(done) {
patch.clean().catch(console.error).then(done);
});
gulp.task('patch:apply', function(done) {
patch.apply().catch(console.error).then(done);
});
gulp.task('update:ini', function(done) {
ini.updateAddonINI().catch(console.error).then(done);
});

View File

@ -72,6 +72,9 @@ addMessageListener("sdk/event/message", onInMessage);
addMessageListener("sdk/port/message", onInPort);
const observer = {
handleEvent: ({target, type}) => {
observer.observe(target, type);
},
observe: (document, topic, data) => {
// When frame associated with message manager is removed from document `docShell`
// is set to `null` but observer is still kept alive. At this point accesing
@ -82,21 +85,21 @@ const observer = {
observerService.removeObserver(observer, topic);
}
else if (document === content.document) {
if (topic === "content-document-interactive") {
if (topic.endsWith("-document-interactive")) {
sendAsyncMessage("sdk/event/ready", {
type: "ready",
readyState: document.readyState,
uri: document.documentURI
});
}
if (topic === "content-document-loaded") {
if (topic.endsWith("-document-loaded")) {
sendAsyncMessage("sdk/event/load", {
type: "load",
readyState: document.readyState,
uri: document.documentURI
});
}
if (topic === "content-page-hidden") {
if (topic === "unload") {
channels.clear();
sendAsyncMessage("sdk/event/unload", {
type: "unload",
@ -110,6 +113,8 @@ const observer = {
observerService.addObserver(observer, "content-document-interactive", false);
observerService.addObserver(observer, "content-document-loaded", false);
observerService.addObserver(observer, "content-page-hidden", false);
observerService.addObserver(observer, "chrome-document-interactive", false);
observerService.addObserver(observer, "chrome-document-loaded", false);
addEventListener("unload", observer, false);
})(this);

View File

@ -126,7 +126,7 @@ const Panel = Class({
return isUninitialized ? Promise.resolve(this) :
when(this, "unload").then(getTarget);
},
postMessage: function(data, ports) {
postMessage: function(data, ports=[]) {
const manager = managerFor(this);
manager.sendAsyncMessage("sdk/event/message", {
type: "message",
@ -227,11 +227,11 @@ createView.define(Panel, (panel, document) => {
const frame = document.createElement("iframe");
setAttributes(frame, {
"sandbox": "allow-scripts",
// It would be great if we could allow remote iframes for sandboxing
// panel documents in a content process, but for now platform implementation
// is buggy on linux so this is disabled.
// "remote": true,
"type": "content",
// We end up using chrome iframe with forced message manager
// as fixing a swapFrameLoader seemed like a giant task (see
// Bug 1075490).
"type": "chrome",
"forcemessagemanager": true,
"transparent": true,
"seamless": "seamless",
});

View File

@ -1,6 +1,7 @@
/* 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/. */
!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.volcan=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
"use strict";

View File

@ -0,0 +1,53 @@
/* 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/. */
/**
* Takes parsed `package.json` manifest and returns
* valid add-on id for it.
*/
function getID(manifest) {
manifest = manifest || {};
if (manifest.id) {
if (typeof manifest.id !== "string") {
return null;
}
// If manifest.id is already valid (as domain or GUID), use it
if (isValidAOMName(manifest.id)) {
return manifest.id;
}
// Otherwise, this ID is invalid so return `null`
return null;
}
// If no `id` defined, turn `name` into a domain ID,
// as we transition to `name` being an id, similar to node/npm, but
// append a '@' to make it compatible with Firefox requirements
if (manifest.name) {
if (typeof manifest.name !== "string") {
return null;
}
var modifiedName = "@" + manifest.name;
return isValidAOMName(modifiedName) ? modifiedName : null;
}
// If no `id` or `name` property, return null as this manifest
// is invalid
return null;
}
module.exports = getID;
/**
* Regex taken from XPIProvider.jsm in the Addon Manager to validate proper
* IDs that are able to be used.
* http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm#209
*/
function isValidAOMName (s) {
return /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}|[a-z0-9-\._]*\@[a-z0-9-\._]+)$/i.test(s || "");
}

View File

@ -0,0 +1,28 @@
{
"name": "jetpack-id",
"version": "1.0.0",
"description": "Creates an ID from a Firefox Jetpack manifest",
"main": "index.js",
"repository": {
"type": "git",
"url": "http://github.com/jsantell/jetpack-id"
},
"author": {
"name": "Jordan Santell",
"url": "http://github.com/jsantell"
},
"license": "MPL-2.0",
"scripts": {
"test": "./node_modules/.bin/mocha --reporter spec --ui bdd"
},
"keywords": [
"jetpack",
"addon",
"mozilla",
"firefox"
],
"devDependencies": {
"mocha": "*",
"chai": "*"
}
}

View File

@ -0,0 +1,112 @@
/* 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/. */
var versionParse = require('./lib/utils').versionParse;
var COMPARATORS = ['>=', '<=', '>', '<', '=', '~', '^'];
exports.parse = function (input) {
input = input || '';
input = input.trim();
if (!input)
throw new Error('`parse` argument must be a populated string.');
// Handle the "*" case
if (input === "*") {
return { min: undefined, max: undefined };
}
var inputs = input.split(' ');
var min;
var max;
// 1.2.3 - 2.3.4
if (inputs.length === 3 && inputs[1] === '-') {
return { min: inputs[0], max: inputs[2] };
}
inputs.forEach(function (input) {
var parsed = parseExpression(input);
var version = parsed.version;
var comparator = parsed.comparator;
// 1.2.3
if (inputs.length === 1 && !comparator)
min = max = version;
// Parse min
if (~comparator.indexOf('>')) {
if (~comparator.indexOf('='))
min = version; // >=1.2.3
else
min = increment(version); // >1.2.3
}
else if (~comparator.indexOf('<')) {
if (~comparator.indexOf('='))
max = version; // <=1.2.3
else
max = decrement(version); // <1.2.3
}
});
return {
min: min,
max : max
};
};
function parseExpression (input) {
for (var i = 0; i < COMPARATORS.length; i++)
if (~input.indexOf(COMPARATORS[i]))
return {
comparator: COMPARATORS[i],
version: input.substr(COMPARATORS[i].length)
};
return { version: input, comparator: '' };
}
/**
* Takes a version string ('1.2.3') and returns a version string
* that'll parse as one less than the input string ('1.2.3.-1').
*
* @param {String} vString
* @return {String}
*/
function decrement (vString) {
return vString + (vString.charAt(vString.length - 1) === '.' ? '' : '.') + '-1';
}
exports.decrement = decrement;
/**
* Takes a version string ('1.2.3') and returns a version string
* that'll parse as greater than the input string by the smallest margin
* possible ('1.2.3.1').
* listed as number-A, string-B, number-C, string-D in
* Mozilla's Toolkit Format.
* https://developer.mozilla.org/en-US/docs/Toolkit_version_format
*
* @param {String} vString
* @return {String}
*/
function increment (vString) {
var match = versionParse(vString);
var a = match[1];
var b = match[2];
var c = match[3];
var d = match[4];
var lastPos = vString.length - 1;
var lastChar = vString.charAt(lastPos);
if (!b) {
return vString + (lastChar === '.' ? '' : '.') + '1';
}
if (!c) {
return vString + '1';
}
if (!d) {
return vString.substr(0, lastPos) + (++lastChar);
}
return vString.substr(0, lastPos) + String.fromCharCode(lastChar.charCodeAt(0) + 1);
}
exports.increment = increment;

View File

@ -0,0 +1,15 @@
/* 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/. */
/**
* Breaks up a version string into the 4 components
* defined in:
* https://developer.mozilla.org/en-US/docs/Toolkit_version_format
* @params {String} val
* @return {String}
*/
function versionParse (val) {
return val.match(/^([0-9\.]*)([a-zA-Z]*)([0-9\.]*)([a-zA-Z]*)$/);
}
exports.versionParse = versionParse;

View File

@ -0,0 +1,21 @@
{
"name": "mozilla-toolkit-versioning",
"version": "0.0.2",
"description": "Parser for Mozilla's toolkit version format",
"main": "index.js",
"scripts": {
"test": "./node_modules/.bin/mocha --reporter spec --ui bdd"
},
"repository": {
"type": "git",
"url": "git://github.com/jsantell/mozilla-toolkit-versioning.git"
},
"author": "Jordan Santell",
"license": "MIT",
"dependencies": {},
"devDependencies": {
"mocha": "^1.21.4",
"chai": "^1.9.1",
"mozilla-version-comparator": "^1.0.2"
}
}

View File

@ -16,7 +16,6 @@ module.metadata = {
const { Cc, Ci } = require("chrome");
const { DataURL } = require("./url");
const errors = require("./deprecated/errors");
const apiUtils = require("./deprecated/api-utils");
/*
While these data flavors resemble Internet media types, they do

View File

@ -110,7 +110,7 @@ Object.freeze({
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 on a symbiont if exception is thrown in
// emit `error` event if exception is thrown in
// the Worker global scope.
// @see http://www.w3.org/TR/workers/#workerutils

View File

@ -9,22 +9,7 @@ module.metadata = {
const { deprecateUsage } = require('../util/deprecate');
Object.defineProperty(exports, "Loader", {
get: function() {
deprecateUsage('`sdk/content/content` is deprecated. Please use `sdk/content/loader` directly.');
return require('./loader').Loader;
}
});
Object.defineProperty(exports, "Symbiont", {
get: function() {
deprecateUsage('Both `sdk/content/content` and `sdk/deprecated/symbiont` are deprecated. ' +
'`sdk/core/heritage` supersedes Symbiont for inheritance.');
return require('../deprecated/symbiont').Symbiont;
}
});
Object.defineProperty(exports, "Worker", {
Object.defineProperty(exports, "Worker", {
get: function() {
deprecateUsage('`sdk/content/content` is deprecated. Please use `sdk/content/worker` directly.');
return require('./worker').Worker;

View File

@ -1,16 +1,13 @@
/* 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 { EventEmitter } = require('../deprecated/events');
const { isValidURI, isLocalURL, URL } = require('../url');
const file = require('../io/file');
const { contract } = require('../util/contract');
const { isString, isNil, instanceOf } = require('../lang/type');
const { validateOptions,
@ -19,7 +16,8 @@ const { validateOptions,
const isJSONable = (value) => {
try {
JSON.parse(JSON.stringify(value));
} catch (e) {
}
catch (e) {
return false;
}
return true;
@ -75,102 +73,4 @@ function Allow(script) ({
set script(value) script = !!value
})
/**
* Trait is intended to be used in some composition. It provides set of core
* properties and bounded validations to them. Trait is useful for all the
* compositions providing high level APIs for interaction with content.
* Property changes emit `"propertyChange"` events on instances.
*/
const Loader = EventEmitter.compose({
/**
* Permissions for the content, with the following keys:
* @property {Object} [allow = { script: true }]
* @property {Boolean} [allow.script = true]
* Whether or not to execute script in the content. Defaults to true.
*/
get allow() this._allow || (this._allow = Allow(true)),
set allow(value) this.allow.script = value && value.script,
_allow: null,
/**
* The content to load. Either a string of HTML or a URL.
* @type {String}
*/
get contentURL() this._contentURL,
set contentURL(value) {
value = validate(value, valid.contentURL);
if (this._contentURL != value) {
this._emit('propertyChange', {
contentURL: this._contentURL = value
});
}
},
_contentURL: null,
/**
* When to load the content scripts.
* Possible values are "end" (default), which loads them once all page
* contents have been loaded, "ready", which loads them once DOM nodes are
* ready (ie like DOMContentLoaded event), and "start", which loads them once
* the `window` object for the page has been created, but before any scripts
* specified by the page have been loaded.
* Property change emits `propertyChange` event on instance with this key
* and new value.
* @type {'start'|'ready'|'end'}
*/
get contentScriptWhen() this._contentScriptWhen,
set contentScriptWhen(value) {
value = validate(value, valid.contentScriptWhen);
if (value !== this._contentScriptWhen) {
this._emit('propertyChange', {
contentScriptWhen: this._contentScriptWhen = value
});
}
},
_contentScriptWhen: 'end',
/**
* Options avalaible from the content script as `self.options`.
* The value of options can be of any type (object, array, string, etc.)
* but only jsonable values will be available as frozen objects from the
* content script.
* Property change emits `propertyChange` event on instance with this key
* and new value.
* @type {Object}
*/
get contentScriptOptions() this._contentScriptOptions,
set contentScriptOptions(value) this._contentScriptOptions = value,
_contentScriptOptions: null,
/**
* The URLs of content scripts.
* Property change emits `propertyChange` event on instance with this key
* and new value.
* @type {String[]}
*/
get contentScriptFile() this._contentScriptFile,
set contentScriptFile(value) {
value = validate(value, valid.contentScriptFile);
if (value != this._contentScriptFile) {
this._emit('propertyChange', {
contentScriptFile: this._contentScriptFile = value
});
}
},
_contentScriptFile: null,
/**
* The texts of content script.
* Property change emits `propertyChange` event on instance with this key
* and new value.
* @type {String|undefined}
*/
get contentScript() this._contentScript,
set contentScript(value) {
value = validate(value, valid.contentScript);
if (value != this._contentScript) {
this._emit('propertyChange', {
contentScript: this._contentScript = value
});
}
},
_contentScript: null
});
exports.Loader = Loader;
exports.contract = contract(valid);

View File

@ -116,7 +116,7 @@ const WorkerSandbox = Class({
// (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, Widget, ... scope.
// 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,
@ -214,7 +214,7 @@ const WorkerSandbox = Class({
}
// Inject our `console` into target document if worker doesn't have a tab
// (e.g Panel, PageWorker, Widget).
// (e.g Panel, PageWorker).
// `worker.tab` can't be used because bug 804935.
if (!isWindowInTab(window)) {
let win = getUnsafeWindow(window);

View File

@ -34,6 +34,8 @@ const WorkerChild = Class({
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'));
@ -53,7 +55,7 @@ const WorkerChild = Class({
this.frozenMessages = [];
this.on('pageshow', () => {
this.frozen = false;
this.frozenMessages.forEach(args => this.receive(null, this.id, args));
this.frozenMessages.forEach(args => this.sandbox.emit(...args));
this.frozenMessages = [];
});
this.on('pagehide', () => {
@ -65,6 +67,7 @@ const WorkerChild = Class({
receive(process, id, args) {
if (id !== this.id)
return;
args = JSON.parse(args);
if (this.frozen)
this.frozenMessages.push(args);
@ -76,8 +79,7 @@ const WorkerChild = Class({
},
send(...args) {
args = JSON.parse(JSON.stringify(args, exceptions));
process.port.emit('sdk/worker/event', this.id, args);
process.port.emit('sdk/worker/event', this.id, JSON.stringify(args, exceptions));
},
// notifications
@ -131,7 +133,7 @@ function exceptions(key, value) {
let keepAlive = new Map();
process.port.on('sdk/worker/create', (process, options) => {
options.window = getByInnerId(options.window);
options.window = getByInnerId(options.windowId);
if (!options.window)
return;

View File

@ -67,6 +67,7 @@ const Worker = Class({
let model = modelFor(this);
if (id !== model.id || !model.attached)
return;
args = JSON.parse(args);
if (model.destroyed && args[0] != 'detach')
return;
@ -86,7 +87,7 @@ const Worker = Class({
return;
}
processes.port.emit('sdk/worker/message', model.id, args);
processes.port.emit('sdk/worker/message', model.id, JSON.stringify(args));
},
// properties
@ -127,15 +128,26 @@ attach.define(Worker, function(worker, window) {
if (tab)
frame = frames.getFrameForBrowser(getBrowserForTab(tab));
merge(model.options, {
id: String(uuid()),
window: getInnerId(window),
url: String(window.location)
});
function makeStringArray(arrayOrValue) {
if (!arrayOrValue)
return [];
return [String(v) for (v of [].concat(arrayOrValue))];
}
processes.port.emit('sdk/worker/create', model.options);
let id = String(uuid());
let childOptions = {
id,
windowId: getInnerId(window),
contentScript: makeStringArray(model.options.contentScript),
contentScriptFile: makeStringArray(model.options.contentScriptFile),
contentScriptOptions: model.options.contentScriptOptions ?
JSON.stringify(model.options.contentScriptOptions) :
null,
}
connect(worker, frame, model.options);
processes.port.emit('sdk/worker/create', childOptions);
connect(worker, frame, { id, url: String(window.location) });
})
connect.define(Worker, function(worker, frame, { id, url }) {

View File

@ -449,7 +449,7 @@ function workerMessageReceived(process, id, args) {
if (internal(this).id != id)
return;
emit(this, ...args);
emit(this, ...JSON.parse(args));
}
// All things that have a label on the context menu extend this

View File

@ -1,8 +1,6 @@
/* 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/.
*/
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
/*

View File

@ -1,14 +1,12 @@
/* 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 memory = require("./memory");
const { merge } = require("../util/object");
const { union } = require("../util/array");
const { isNil, isRegExp } = require("../lang/type");

View File

@ -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": "deprecated"
};
const getOwnIdentifiers = x => [...Object.getOwnPropertyNames(x),
...Object.getOwnPropertySymbols(x)];
// `var` is being used in the module in order to make it reusable in
// environments in which `let` and `const` is not yet supported.
// Returns `object`'s property value, where `name` is a name of the property.
function get(object, name) {
return object[name];
}
// Assigns `value` to the `object`'s property, where `name` is the name of the
// property.
function set(object, name, value) {
return object[name] = value;
}
/**
* Given an `object` containing a property with the given `name`, create
* a property descriptor that can be used to define alias/proxy properties
* on other objects. A change in the value of an alias will propagate
* to the aliased property and vice versa.
*/
function createAliasProperty(object, name) {
// Getting own property descriptor of an `object` for the given `name` as
// we are going to create proxy analog.
var property = Object.getOwnPropertyDescriptor(object, name);
var descriptor = {
configurable: property.configurable,
enumerable: property.enumerable,
alias: true
};
// If the original property has a getter and/or setter, bind a
// corresponding getter/setter in the alias descriptor to the original
// object, so the `this` object in the getter/setter is the original object
// rather than the alias.
if ("get" in property && property.get)
descriptor.get = property.get.bind(object);
if ("set" in property && property.set)
descriptor.set = property.set.bind(object);
// If original property was a value property.
if ("value" in property) {
// If original property is a method using it's `object` bounded copy.
if (typeof property.value === "function") {
descriptor.value = property.value.bind(object);
// Also preserving writability of the original property.
descriptor.writable = property.writable;
}
// If the original property was just a data property, we create proxy
// accessors using our custom get/set functions to propagate changes to the
// original `object` and vice versa.
else {
descriptor.get = get.bind(null, object, name);
descriptor.set = set.bind(null, object, name);
}
}
return descriptor;
}
// Defines property on `object` object with a name `alias` if given if not
// defaults to `name` that represents an alias of `source[name]`. If aliased
// property was an assessor or a method `this` pseudo-variable will be `source`
// when invoked. If aliased property was a data property changes on any of the
// aliases will propagate to the `source[name]` and also other way round.
function defineAlias(source, target, name, alias) {
return Object.defineProperty(target, alias || name,
createAliasProperty(source, name));
}
/**
* Function takes any `object` and returns a proxy for its own public
* properties. By default properties are considered to be public if they don't
* start with `"_"`, but default behavior can be overridden if needed, by
* passing array of public property `names` as a second argument. By default
* returned object will be direct decedent of the given `object`'s prototype,
* but this can be overridden by passing third optional argument, that will be
* used as `prototype` instead.
* @param {Object} object
* Object to create cortex for.
* @param {String[]} [names]
* Optional array of public property names.
* @param {Object} [prototype]
* Optional argument that will be used as `prototype` of the returned object,
* if not provided `Object.getPrototypeOf(object)` is used instead.
*/
exports.Cortex = function Cortex(object, names, prototype) {
// Creating a cortex object from the given `prototype`, if one was not
// provided then `prototype` of a given `object` is used. This allows
// consumer to define expected behavior `instanceof`. In common case
// `prototype` argument can be omitted to preserve same behavior of
// `instanceof` as on original `object`.
var cortex = Object.create(prototype || Object.getPrototypeOf(object));
// Creating alias properties on the `cortex` object for all the own
// properties of the original `object` that are contained in `names` array.
// If `names` array is not provided then all the properties that don't
// start with `"_"` are aliased.
getOwnIdentifiers(object).forEach(function (name) {
if ((!names && "_" !== name.toString().charAt(0)) || (names && ~names.indexOf(name)))
defineAlias(object, cortex, name);
});
return cortex;
}

View File

@ -1,64 +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"
};
function logToConsole(e) {
console.exception(e);
}
var catchAndLog = exports.catchAndLog = function(callback,
defaultResponse,
logException) {
if (!logException)
logException = logToConsole;
return function() {
try {
return callback.apply(this, arguments);
} catch (e) {
logException(e);
return defaultResponse;
}
};
};
exports.catchAndLogProps = function catchAndLogProps(object,
props,
defaultResponse,
logException) {
if (typeof(props) == "string")
props = [props];
props.forEach(
function(property) {
object[property] = catchAndLog(object[property],
defaultResponse,
logException);
});
};
/**
* Catch and return an exception while calling the callback. If the callback
* doesn't throw, return the return value of the callback in a way that makes it
* possible to distinguish between a return value and an exception.
*
* This function is useful when you need to pass the result of a call across
* a process boundary (across which exceptions don't propagate). It probably
* doesn't need to be factored out into this module, since it is only used by
* a single caller, but putting it here works around bug 625560.
*/
exports.catchAndReturn = function(callback) {
return function() {
try {
return { returnValue: callback.apply(this, arguments) };
}
catch (exception) {
return { exception: exception };
}
};
};

View File

@ -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": "deprecated"
};
const ERROR_TYPE = 'error',
UNCAUGHT_ERROR = 'An error event was dispatched for which there was'
+ ' no listener.',
BAD_LISTENER = 'The event listener must be a function.';
/**
* This object is used to create an `EventEmitter` that, useful for composing
* objects that emit events. It implements an interface like `EventTarget` from
* DOM Level 2, which is implemented by Node objects in implementations that
* support the DOM Event Model.
* @see http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget
* @see http://nodejs.org/api.html#EventEmitter
* @see http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/events/EventDispatcher.html
*/
const eventEmitter = {
/**
* 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: function on(type, listener) {
if ('function' !== typeof listener)
throw new Error(BAD_LISTENER);
let listeners = this._listeners(type);
if (0 > listeners.indexOf(listener))
listeners.push(listener);
// Use of `_public` is required by the legacy traits code that will go away
// once bug-637633 is fixed.
return this._public || this;
},
/**
* 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: function once(type, listener) {
this.on(type, function selfRemovableListener() {
this.removeListener(type, selfRemovableListener);
listener.apply(this, arguments);
});
},
/**
* Unregister `listener` for the specified event type.
* @param {String} type
* The type of event.
* @param {Function} listener
* The listener function that processes the event.
*/
removeListener: function removeListener(type, listener) {
if ('function' !== typeof listener)
throw new Error(BAD_LISTENER);
let listeners = this._listeners(type),
index = listeners.indexOf(listener);
if (0 <= index)
listeners.splice(index, 1);
// Use of `_public` is required by the legacy traits code, that will go away
// once bug-637633 is fixed.
return this._public || this;
},
/**
* Hash of listeners on this EventEmitter.
*/
_events: null,
/**
* Returns an array of listeners for the specified event `type`. This array
* can be manipulated, e.g. to remove listeners.
* @param {String} type
* The type of event.
*/
_listeners: function listeners(type) {
let events = this._events || (this._events = {});
return (events.hasOwnProperty(type) && events[type]) || (events[type] = []);
},
/**
* Execute each of the listeners in order with the supplied arguments.
* Returns `true` if listener for this event was called, `false` if there are
* no listeners for this event `type`.
*
* 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 propagate to a
* caller of this method.
*
* **It's recommended to have a default 'error' listener in all the complete
* composition that in worst case may dump errors to the console.**
*
* @param {String} type
* The type of event.
* @params {Object|Number|String|Boolean}
* Arguments that will be passed to listeners.
* @returns {Boolean}
*/
_emit: function _emit(type, event) {
let args = Array.slice(arguments);
// Use of `_public` is required by the legacy traits code that will go away
// once bug-637633 is fixed.
args.unshift(this._public || this);
return this._emitOnObject.apply(this, args);
},
/**
* A version of _emit that lets you specify the object on which listeners are
* called. This is a hack that is sometimes necessary when such an object
* (exports, for example) cannot be an EventEmitter for some reason, but other
* object(s) managing events for the object are EventEmitters. Once bug
* 577782 is fixed, this method shouldn't be necessary.
*
* @param {object} targetObj
* The object on which listeners will be called.
* @param {string} type
* The event name.
* @param {value} event
* The first argument to pass to listeners.
* @param {value} ...
* More arguments to pass to listeners.
* @returns {boolean}
*/
_emitOnObject: function _emitOnObject(targetObj, type, event /* , ... */) {
let listeners = this._listeners(type).slice(0);
// If there is no 'error' event listener then throw.
if (type === ERROR_TYPE && !listeners.length)
console.exception(event);
if (!listeners.length)
return false;
let params = Array.slice(arguments, 2);
for (let listener of listeners) {
try {
listener.apply(targetObj, params);
} catch(e) {
// Bug 726967: Ignore exceptions being throws while notifying the error
// in order to avoid infinite loops.
if (type !== ERROR_TYPE)
this._emit(ERROR_TYPE, e);
else
console.exception("Exception in error event listener " + e);
}
}
return true;
},
/**
* Removes all the event listeners for the specified event `type`.
* @param {String} type
* The type of event.
*/
_removeAllListeners: function _removeAllListeners(type) {
if (typeof type == "undefined") {
this._events = null;
return this;
}
this._listeners(type).splice(0);
return this;
}
};
exports.EventEmitter = require("./traits").Trait.compose(eventEmitter);
exports.EventEmitterTrait = require('./light-traits').Trait(eventEmitter);

View File

@ -1,15 +1,13 @@
/* 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");
/**
* Trait may be used for building objects / composing traits that wish to handle
* multiple dom events from multiple event targets in one place. Event targets
* 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

View File

@ -1,599 +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"
};
// `var` is being used in the module in order to make it reusable in
// environments in which `let` is not yet supported.
// Shortcut to `Object.prototype.hasOwnProperty.call`.
// owns(object, name) would be the same as
// Object.prototype.hasOwnProperty.call(object, name);
var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
/**
* Whether or not given property descriptors are equivalent. They are
* equivalent either if both are marked as 'conflict' or 'required' property
* or if all the properties of descriptors are equal.
* @param {Object} actual
* @param {Object} expected
*/
function equivalentDescriptors(actual, expected) {
return (actual.conflict && expected.conflict) ||
(actual.required && expected.required) ||
equalDescriptors(actual, expected);
}
/**
* Whether or not given property descriptors define equal properties.
*/
function equalDescriptors(actual, expected) {
return actual.get === expected.get &&
actual.set === expected.set &&
actual.value === expected.value &&
!!actual.enumerable === !!expected.enumerable &&
!!actual.configurable === !!expected.configurable &&
!!actual.writable === !!expected.writable;
}
// Utilities that throwing exceptions for a properties that are marked
// as "required" or "conflict" properties.
function throwConflictPropertyError(name) {
throw new Error("Remaining conflicting property: `" + name + "`");
}
function throwRequiredPropertyError(name) {
throw new Error("Missing required property: `" + name + "`");
}
/**
* Generates custom **required** property descriptor. Descriptor contains
* non-standard property `required` that is equal to `true`.
* @param {String} name
* property name to generate descriptor for.
* @returns {Object}
* custom property descriptor
*/
function RequiredPropertyDescriptor(name) {
// Creating function by binding first argument to a property `name` on the
// `throwConflictPropertyError` function. Created function is used as a
// getter & setter of the created property descriptor. This way we ensure
// that we throw exception late (on property access) if object with
// `required` property was instantiated using built-in `Object.create`.
var accessor = throwRequiredPropertyError.bind(null, name);
return { get: accessor, set: accessor, required: true };
}
/**
* Generates custom **conflicting** property descriptor. Descriptor contains
* non-standard property `conflict` that is equal to `true`.
* @param {String} name
* property name to generate descriptor for.
* @returns {Object}
* custom property descriptor
*/
function ConflictPropertyDescriptor(name) {
// For details see `RequiredPropertyDescriptor` since idea is same.
var accessor = throwConflictPropertyError.bind(null, name);
return { get: accessor, set: accessor, conflict: true };
}
/**
* Tests if property is marked as `required` property.
*/
function isRequiredProperty(object, name) {
return !!object[name].required;
}
/**
* Tests if property is marked as `conflict` property.
*/
function isConflictProperty(object, name) {
return !!object[name].conflict;
}
/**
* Function tests whether or not method of the `source` object with a given
* `name` is inherited from `Object.prototype`.
*/
function isBuiltInMethod(name, source) {
var target = Object.prototype[name];
// If methods are equal then we know it's `true`.
return target == source ||
// If `source` object comes form a different sandbox `==` will evaluate
// to `false`, in that case we check if functions names and sources match.
(String(target) === String(source) && target.name === source.name);
}
/**
* Function overrides `toString` and `constructor` methods of a given `target`
* object with a same-named methods of a given `source` if methods of `target`
* object are inherited / copied from `Object.prototype`.
* @see create
*/
function overrideBuiltInMethods(target, source) {
if (isBuiltInMethod("toString", target.toString)) {
Object.defineProperty(target, "toString", {
value: source.toString,
configurable: true,
enumerable: false
});
}
if (isBuiltInMethod("constructor", target.constructor)) {
Object.defineProperty(target, "constructor", {
value: source.constructor,
configurable: true,
enumerable: false
});
}
}
/**
* Composes new trait with the same own properties as the original trait,
* except that all property names appearing in the first argument are replaced
* by "required" property descriptors.
* @param {String[]} keys
* Array of strings property names.
* @param {Object} trait
* A trait some properties of which should be excluded.
* @returns {Object}
* @example
* var newTrait = exclude(["name", ...], trait)
*/
function exclude(names, trait) {
var map = {};
Object.keys(trait).forEach(function(name) {
// If property is not excluded (the array of names does not contain it),
// or it is a "required" property, copy it to the property descriptor `map`
// that will be used for creation of resulting trait.
if (!~names.indexOf(name) || isRequiredProperty(trait, name))
map[name] = { value: trait[name], enumerable: true };
// For all the `names` in the exclude name array we create required
// property descriptors and copy them to the `map`.
else
map[name] = { value: RequiredPropertyDescriptor(name), enumerable: true };
});
return Object.create(Trait.prototype, map);
}
/**
* Composes new instance of `Trait` with a properties of a given `trait`,
* except that all properties whose name is an own property of `renames` will
* be renamed to `renames[name]` and a `"required"` property for name will be
* added instead.
*
* For each renamed property, a required property is generated. If
* the `renames` map two properties to the same name, a conflict is generated.
* If the `renames` map a property to an existing unrenamed property, a
* conflict is generated.
*
* @param {Object} renames
* An object whose own properties serve as a mapping from old names to new
* names.
* @param {Object} trait
* A new trait with renamed properties.
* @returns {Object}
* @example
*
* // Return trait with `bar` property equal to `trait.foo` and with
* // `foo` and `baz` "required" properties.
* var renamedTrait = rename({ foo: "bar", baz: null }), trait);
*
* // t1 and t2 are equivalent traits
* var t1 = rename({a: "b"}, t);
* var t2 = compose(exclude(["a"], t), { a: { required: true }, b: t[a] });
*/
function rename(renames, trait) {
var map = {};
// Loop over all the properties of the given `trait` and copy them to a
// property descriptor `map` that will be used for the creation of the
// resulting trait. Also, rename properties in the `map` as specified by
// `renames`.
Object.keys(trait).forEach(function(name) {
var alias;
// If the property is in the `renames` map, and it isn't a "required"
// property (which should never need to be aliased because "required"
// properties never conflict), then we must try to rename it.
if (owns(renames, name) && !isRequiredProperty(trait, name)) {
alias = renames[name];
// If the `map` already has the `alias`, and it isn't a "required"
// property, that means the `alias` conflicts with an existing name for a
// provided trait (that can happen if >=2 properties are aliased to the
// same name). In this case we mark it as a conflicting property.
// Otherwise, everything is fine, and we copy property with an `alias`
// name.
if (owns(map, alias) && !map[alias].value.required) {
map[alias] = {
value: ConflictPropertyDescriptor(alias),
enumerable: true
};
}
else {
map[alias] = {
value: trait[name],
enumerable: true
};
}
// Regardless of whether or not the rename was successful, we check to
// see if the original `name` exists in the map (such a property
// could exist if previous another property was aliased to this `name`).
// If it isn't, we mark it as "required", to make sure the caller
// provides another value for the old name, which methods of the trait
// might continue to reference.
if (!owns(map, name)) {
map[name] = {
value: RequiredPropertyDescriptor(name),
enumerable: true
};
}
}
// Otherwise, either the property isn't in the `renames` map (thus the
// caller is not trying to rename it) or it is a "required" property.
// Either way, we don't have to alias the property, we just have to copy it
// to the map.
else {
// The property isn't in the map yet, so we copy it over.
if (!owns(map, name)) {
map[name] = { value: trait[name], enumerable: true };
}
// The property is already in the map (that means another property was
// aliased with this `name`, which creates a conflict if the property is
// not marked as "required"), so we have to mark it as a "conflict"
// property.
else if (!isRequiredProperty(trait, name)) {
map[name] = {
value: ConflictPropertyDescriptor(name),
enumerable: true
};
}
}
});
return Object.create(Trait.prototype, map);
}
/**
* Composes new resolved trait, with all the same properties as the original
* `trait`, except that all properties whose name is an own property of
* `resolutions` will be renamed to `resolutions[name]`.
*
* If `resolutions[name]` is `null`, the value is mapped to a property
* descriptor that is marked as a "required" property.
*/
function resolve(resolutions, trait) {
var renames = {};
var exclusions = [];
// Go through each mapping in `resolutions` object and distribute it either
// to `renames` or `exclusions`.
Object.keys(resolutions).forEach(function(name) {
// If `resolutions[name]` is a truthy value then it's a mapping old -> new
// so we copy it to `renames` map.
if (resolutions[name])
renames[name] = resolutions[name];
// Otherwise it's not a mapping but an exclusion instead in which case we
// add it to the `exclusions` array.
else
exclusions.push(name);
});
// First `exclude` **then** `rename` and order is important since
// `exclude` and `rename` are not associative.
return rename(renames, exclude(exclusions, trait));
}
/**
* Create a Trait (a custom property descriptor map) that represents the given
* `object`'s own properties. Property descriptor map is a "custom", because it
* inherits from `Trait.prototype` and it's property descriptors may contain
* two attributes that is not part of the ES5 specification:
*
* - "required" (this property must be provided by another trait
* before an instance of this trait can be created)
* - "conflict" (when the trait is composed with another trait,
* a unique value for this property is provided by two or more traits)
*
* Data properties bound to the `Trait.required` singleton exported by
* this module will be marked as "required" properties.
*
* @param {Object} object
* Map of properties to compose trait from.
* @returns {Trait}
* Trait / Property descriptor map containing all the own properties of the
* given argument.
*/
function trait(object) {
var map;
var trait = object;
if (!(object instanceof Trait)) {
// If the passed `object` is not already an instance of `Trait`, we create
// a property descriptor `map` containing descriptors for the own properties
// of the given `object`. `map` is then used to create a `Trait` instance
// after all properties are mapped. Note that we can't create a trait and
// then just copy properties into it since that will fail for inherited
// read-only properties.
map = {};
// Each own property of the given `object` is mapped to a data property
// whose value is a property descriptor.
Object.keys(object).forEach(function (name) {
// If property of an `object` is equal to a `Trait.required`, it means
// that it was marked as "required" property, in which case we map it
// to "required" property.
if (Trait.required ==
Object.getOwnPropertyDescriptor(object, name).value) {
map[name] = {
value: RequiredPropertyDescriptor(name),
enumerable: true
};
}
// Otherwise property is mapped to it's property descriptor.
else {
map[name] = {
value: Object.getOwnPropertyDescriptor(object, name),
enumerable: true
};
}
});
trait = Object.create(Trait.prototype, map);
}
return trait;
}
/**
* Compose a property descriptor map that inherits from `Trait.prototype` and
* contains property descriptors for all the own properties of the passed
* traits.
*
* If two or more traits have own properties with the same name, the returned
* trait will contain a "conflict" property for that name. Composition is a
* commutative and associative operation, and the order of its arguments is
* irrelevant.
*/
function compose(trait1, trait2/*, ...*/) {
// Create a new property descriptor `map` to which all the own properties
// of the passed traits are copied. This map will be used to create a `Trait`
// instance that will be the result of this composition.
var map = {};
// Properties of each passed trait are copied to the composition.
Array.prototype.forEach.call(arguments, function(trait) {
// Copying each property of the given trait.
Object.keys(trait).forEach(function(name) {
// If `map` already owns a property with the `name` and it is not
// marked "required".
if (owns(map, name) && !map[name].value.required) {
// If the source trait's property with the `name` is marked as
// "required", we do nothing, as the requirement was already resolved
// by a property in the `map` (because it already contains a
// non-required property with that `name`). But if properties are just
// different, we have a name clash and we substitute it with a property
// that is marked "conflict".
if (!isRequiredProperty(trait, name) &&
!equivalentDescriptors(map[name].value, trait[name])
) {
map[name] = {
value: ConflictPropertyDescriptor(name),
enumerable: true
};
}
}
// Otherwise, the `map` does not have an own property with the `name`, or
// it is marked "required". Either way, the trait's property is copied to
// the map (if the property of the `map` is marked "required", it is going
// to be resolved by the property that is being copied).
else {
map[name] = { value: trait[name], enumerable: true };
}
});
});
return Object.create(Trait.prototype, map);
}
/**
* `defineProperties` is like `Object.defineProperties`, except that it
* ensures that:
* - An exception is thrown if any property in a given `properties` map
* is marked as "required" property and same named property is not
* found in a given `prototype`.
* - An exception is thrown if any property in a given `properties` map
* is marked as "conflict" property.
* @param {Object} object
* Object to define properties on.
* @param {Object} properties
* Properties descriptor map.
* @returns {Object}
* `object` that was passed as a first argument.
*/
function defineProperties(object, properties) {
// Create a map into which we will copy each verified property from the given
// `properties` description map. We use it to verify that none of the
// provided properties is marked as a "conflict" property and that all
// "required" properties are resolved by a property of an `object`, so we
// can throw an exception before mutating object if that isn't the case.
var verifiedProperties = {};
// Coping each property from a given `properties` descriptor map to a
// verified map of property descriptors.
Object.keys(properties).forEach(function(name) {
// If property is marked as "required" property and we don't have a same
// named property in a given `object` we throw an exception. If `object`
// has same named property just skip this property since required property
// is was inherited and there for requirement was satisfied.
if (isRequiredProperty(properties, name)) {
if (!(name in object))
throwRequiredPropertyError(name);
}
// If property is marked as "conflict" property we throw an exception.
else if (isConflictProperty(properties, name)) {
throwConflictPropertyError(name);
}
// If property is not marked neither as "required" nor "conflict" property
// we copy it to verified properties map.
else {
verifiedProperties[name] = properties[name];
}
});
// If no exceptions were thrown yet, we know that our verified property
// descriptor map has no properties marked as "conflict" or "required",
// so we just delegate to the built-in `Object.defineProperties`.
return Object.defineProperties(object, verifiedProperties);
}
/**
* `create` is like `Object.create`, except that it ensures that:
* - An exception is thrown if any property in a given `properties` map
* is marked as "required" property and same named property is not
* found in a given `prototype`.
* - An exception is thrown if any property in a given `properties` map
* is marked as "conflict" property.
* @param {Object} prototype
* prototype of the composed object
* @param {Object} properties
* Properties descriptor map.
* @returns {Object}
* An object that inherits form a given `prototype` and implements all the
* properties defined by a given `properties` descriptor map.
*/
function create(prototype, properties) {
// Creating an instance of the given `prototype`.
var object = Object.create(prototype);
// Overriding `toString`, `constructor` methods if they are just inherited
// from `Object.prototype` with a same named methods of the `Trait.prototype`
// that will have more relevant behavior.
overrideBuiltInMethods(object, Trait.prototype);
// Trying to define given `properties` on the `object`. We use our custom
// `defineProperties` function instead of build-in `Object.defineProperties`
// that behaves exactly the same, except that it will throw if any
// property in the given `properties` descriptor is marked as "required" or
// "conflict" property.
return defineProperties(object, properties);
}
/**
* Composes new trait. If two or more traits have own properties with the
* same name, the new trait will contain a "conflict" property for that name.
* "compose" is a commutative and associative operation, and the order of its
* arguments is not significant.
*
* **Note:** Use `Trait.compose` instead of calling this function with more
* than one argument. The multiple-argument functionality is strictly for
* backward compatibility.
*
* @params {Object} trait
* Takes traits as an arguments
* @returns {Object}
* New trait containing the combined own properties of all the traits.
* @example
* var newTrait = compose(trait_1, trait_2, ..., trait_N)
*/
function Trait(trait1, trait2) {
// If the function was called with one argument, the argument should be
// an object whose properties are mapped to property descriptors on a new
// instance of Trait, so we delegate to the trait function.
// If the function was called with more than one argument, those arguments
// should be instances of Trait or plain property descriptor maps
// whose properties should be mixed into a new instance of Trait,
// so we delegate to the compose function.
return trait2 === undefined ? trait(trait1) : compose.apply(null, arguments);
}
Object.freeze(Object.defineProperties(Trait.prototype, {
toString: {
value: function toString() {
return "[object " + this.constructor.name + "]";
}
},
/**
* `create` is like `Object.create`, except that it ensures that:
* - An exception is thrown if this trait defines a property that is
* marked as required property and same named property is not
* found in a given `prototype`.
* - An exception is thrown if this trait contains property that is
* marked as "conflict" property.
* @param {Object}
* prototype of the compared object
* @returns {Object}
* An object with all of the properties described by the trait.
*/
create: {
value: function createTrait(prototype) {
return create(undefined === prototype ? Object.prototype : prototype,
this);
},
enumerable: true
},
/**
* Composes a new resolved trait, with all the same properties as the original
* trait, except that all properties whose name is an own property of
* `resolutions` will be renamed to the value of `resolutions[name]`. If
* `resolutions[name]` is `null`, the property is marked as "required".
* @param {Object} resolutions
* An object whose own properties serve as a mapping from old names to new
* names, or to `null` if the property should be excluded.
* @returns {Object}
* New trait with the same own properties as the original trait but renamed.
*/
resolve: {
value: function resolveTrait(resolutions) {
return resolve(resolutions, this);
},
enumerable: true
}
}));
/**
* @see compose
*/
Trait.compose = Object.freeze(compose);
Object.freeze(compose.prototype);
/**
* Constant singleton, representing placeholder for required properties.
* @type {Object}
*/
Trait.required = Object.freeze(Object.create(Object.prototype, {
toString: {
value: Object.freeze(function toString() {
return "<Trait.required>";
})
}
}));
Object.freeze(Trait.required.toString.prototype);
exports.Trait = Object.freeze(Trait);

View File

@ -1,125 +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 { Trait } = require('../deprecated/traits');
/**
* @see https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/util_list
*/
const Iterable = Trait.compose({
/**
* Hash map of key-values to iterate over.
* Note: That this property can be a getter if you need dynamic behavior.
* @type {Object}
*/
_keyValueMap: Trait.required,
/**
* Custom iterator providing `Iterable`s enumeration behavior.
* @param {Boolean} onKeys
*/
__iterator__: function __iterator__(onKeys, onKeyValue) {
let map = this._keyValueMap;
for (let key in map)
yield onKeyValue ? [key, map[key]] : onKeys ? key : map[key];
}
});
exports.Iterable = Iterable;
/**
* An ordered collection (also known as a sequence) disallowing duplicate
* elements. List is composed out of `Iterable` there for it provides custom
* enumeration behavior that is similar to array (enumerates only on the
* elements of the list). List is a base trait and is meant to be a part of
* composition, since all of it's API is private except length property.
*/
const listOptions = {
_keyValueMap: null,
/**
* List constructor can take any number of element to populate itself.
* @params {Object|String|Number} element
* @example
* List(1,2,3).length == 3 // true
*/
constructor: function List() {
this._keyValueMap = [];
for (let i = 0, ii = arguments.length; i < ii; i++)
this._add(arguments[i]);
},
/**
* Number of elements in this list.
* @type {Number}
*/
get length() this._keyValueMap.length,
/**
* Returns a string representing this list.
* @returns {String}
*/
toString: function toString() 'List(' + this._keyValueMap + ')',
/**
* Returns `true` if this list contains the specified `element`.
* @param {Object|Number|String} element
* @returns {Boolean}
*/
_has: function _has(element) 0 <= this._keyValueMap.indexOf(element),
/**
* Appends the specified `element` to the end of this list, if it doesn't
* contains it. Ignores the call if `element` is already contained.
* @param {Object|Number|String} element
*/
_add: function _add(element) {
let list = this._keyValueMap,
index = list.indexOf(element);
if (0 > index)
list.push(this._public[list.length] = element);
},
/**
* Removes specified `element` from this list, if it contains it.
* Ignores the call if `element` is not contained.
* @param {Object|Number|String} element
*/
_remove: function _remove(element) {
let list = this._keyValueMap,
index = list.indexOf(element);
if (0 <= index) {
delete this._public[list.length - 1];
list.splice(index, 1);
for (let length = list.length; index < length; index++)
this._public[index] = list[index];
}
},
/**
* Removes all of the elements from this list.
*/
_clear: function _clear() {
for (let i = 0, ii = this._keyValueMap.length; i < ii; i ++)
delete this._public[i];
this._keyValueMap.splice(0);
},
/**
* 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 = this._keyValueMap.slice(0),
i = -1;
for (let element of array)
yield onKeyValue ? [++i, element] : onKeys ? ++i : element;
},
};
listOptions[Symbol.iterator] = function* iterator() {
let array = this._keyValueMap.slice(0);
for (let element of array)
yield element;
}
const List = Trait.resolve({ toString: null }).compose(listOptions);
exports.List = List;

View File

@ -1,228 +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 { Worker } = require('./traits-worker');
const { Loader } = require('../content/loader');
const hiddenFrames = require('../frame/hidden-frame');
const { on, off } = require('../system/events');
const unload = require('../system/unload');
const { getDocShell } = require("../frame/utils");
const { ignoreWindow } = require('../private-browsing/utils');
// Everything coming from add-on's xpi considered an asset.
const assetsURI = require('../self').data.url().replace(/data\/$/, "");
/**
* This trait is layered on top of `Worker` and in contrast to symbiont
* Worker constructor requires `content` option that represents content
* that will be loaded in the provided frame, if frame is not provided
* Worker will create hidden one.
*/
const Symbiont = Worker.resolve({
constructor: '_initWorker',
destroy: '_workerDestroy'
}).compose(Loader, {
/**
* The constructor requires all the options that are required by
* `require('content').Worker` with the difference that the `frame` option
* is optional. If `frame` is not provided, `contentURL` is expected.
* @param {Object} options
* @param {String} options.contentURL
* URL of a content to load into `this._frame` and create worker for.
* @param {Element} [options.frame]
* iframe element that is used to load `options.contentURL` into.
* if frame is not provided hidden iframe will be created.
*/
constructor: function Symbiont(options) {
options = options || {};
if ('contentURL' in options)
this.contentURL = options.contentURL;
if ('contentScriptWhen' in options)
this.contentScriptWhen = options.contentScriptWhen;
if ('contentScriptOptions' in options)
this.contentScriptOptions = options.contentScriptOptions;
if ('contentScriptFile' in options)
this.contentScriptFile = options.contentScriptFile;
if ('contentScript' in options)
this.contentScript = options.contentScript;
if ('allow' in options)
this.allow = options.allow;
if ('onError' in options)
this.on('error', options.onError);
if ('onMessage' in options)
this.on('message', options.onMessage);
if ('frame' in options) {
this._initFrame(options.frame);
}
else {
let self = this;
this._hiddenFrame = hiddenFrames.HiddenFrame({
onReady: function onFrame() {
self._initFrame(this.element);
},
onUnload: function onUnload() {
// Bug 751211: Remove reference to _frame when hidden frame is
// automatically removed on unload, otherwise we are going to face
// "dead object" exception
self.destroy();
}
});
hiddenFrames.add(this._hiddenFrame);
}
unload.ensure(this._public, "destroy");
},
destroy: function destroy() {
this._workerDestroy();
this._unregisterListener();
this._frame = null;
if (this._hiddenFrame) {
hiddenFrames.remove(this._hiddenFrame);
this._hiddenFrame = null;
}
},
/**
* XUL iframe or browser elements with attribute `type` being `content`.
* Used to create `ContentSymbiont` from.
* @type {nsIFrame|nsIBrowser}
*/
_frame: null,
/**
* Listener to the `'frameReady"` event (emitted when `iframe` is ready).
* Removes listener, sets right permissions to the frame and loads content.
*/
_initFrame: function _initFrame(frame) {
if (this._loadListener)
this._unregisterListener();
this._frame = frame;
if (getDocShell(frame)) {
this._reallyInitFrame(frame);
}
else {
if (this._waitForFrame) {
off('content-document-global-created', this._waitForFrame);
}
this._waitForFrame = this.__waitForFrame.bind(this, frame);
on('content-document-global-created', this._waitForFrame);
}
},
__waitForFrame: function _waitForFrame(frame, { subject: win }) {
if (frame.contentWindow == win) {
off('content-document-global-created', this._waitForFrame);
delete this._waitForFrame;
this._reallyInitFrame(frame);
}
},
_reallyInitFrame: function _reallyInitFrame(frame) {
getDocShell(frame).allowJavascript = this.allow.script;
frame.setAttribute("src", this._contentURL);
// Inject `addon` object in document if we load a document from
// one of our addon folder and if no content script are defined. bug 612726
let isDataResource =
typeof this._contentURL == "string" &&
this._contentURL.indexOf(assetsURI) == 0;
let hasContentScript =
(Array.isArray(this.contentScript) ? this.contentScript.length > 0
: !!this.contentScript) ||
(Array.isArray(this.contentScriptFile) ? this.contentScriptFile.length > 0
: !!this.contentScriptFile);
// If we have to inject `addon` we have to do it before document
// script execution, so during `start`:
this._injectInDocument = isDataResource && !hasContentScript;
if (this._injectInDocument)
this.contentScriptWhen = "start";
if ((frame.contentDocument.readyState == "complete" ||
(frame.contentDocument.readyState == "interactive" &&
this.contentScriptWhen != 'end' )) &&
frame.contentDocument.location == this._contentURL) {
// In some cases src doesn't change and document is already ready
// (for ex: when the user moves a widget while customizing toolbars.)
this._onInit();
return;
}
let self = this;
if ('start' == this.contentScriptWhen) {
this._loadEvent = 'start';
on('document-element-inserted',
this._loadListener = function onStart({ subject: doc }) {
let window = doc.defaultView;
if (ignoreWindow(window)) {
return;
}
if (window && window == frame.contentWindow) {
self._unregisterListener();
self._onInit();
}
});
return;
}
let eventName = 'end' == this.contentScriptWhen ? 'load' : 'DOMContentLoaded';
this._loadEvent = eventName;
frame.addEventListener(eventName,
this._loadListener = function _onReady(event) {
if (event.target != frame.contentDocument)
return;
self._unregisterListener();
self._onInit();
}, true);
},
/**
* Unregister listener that watchs for document being ready to be injected.
* This listener is registered in `Symbiont._initFrame`.
*/
_unregisterListener: function _unregisterListener() {
if (this._waitForFrame) {
off('content-document-global-created', this._waitForFrame);
delete this._waitForFrame;
}
if (!this._loadListener)
return;
if (this._loadEvent == "start") {
off('document-element-inserted', this._loadListener);
}
else {
this._frame.removeEventListener(this._loadEvent, this._loadListener,
true);
}
this._loadListener = null;
},
/**
* Called by Symbiont itself when the frame is ready to load
* content scripts according to contentScriptWhen. Overloaded by Panel.
*/
_onInit: function () {
this._initWorker({ window: this._frame.contentWindow });
}
});
exports.Symbiont = Symbiont;

View File

@ -90,7 +90,7 @@ const Worker = Class({
* 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
* symbiont.
* worker.
*
* `message` event listeners can be set either by calling
* `self.on` with a first argument string `"message"` or by

View File

@ -1,636 +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/traits-worker` was previously `content/worker` and kept
* only due to `deprecated/symbiont` using it, which is necessary for
* `widget`, until that reaches deprecation EOL.
*
*/
"use strict";
module.metadata = {
"stability": "deprecated"
};
const { Trait } = require('./traits');
const { EventEmitter, EventEmitterTrait } = require('./events');
const { Ci, Cu, Cc } = require('chrome');
const timer = require('../timers');
const { URL } = require('../url');
const unload = require('../system/unload');
const observers = require('../system/events');
const { Cortex } = require('./cortex');
const { sandbox, evaluate, load } = require("../loader/sandbox");
const { merge } = require('../util/object');
const { getInnerId } = require("../window/utils");
const { getTabForWindow } = require('../tabs/helpers');
const { getTabForContentWindow } = require('../tabs/utils');
/* Trick the linker in order to ensure shipping these files in the XPI.
require('../content/content-worker.js');
Then, retrieve URL of these files in the XPI:
*/
let prefix = module.uri.split('deprecated/traits-worker.js')[0];
const CONTENT_WORKER_URL = prefix + 'content/content-worker.js';
// 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 = require('@loader/options').metadata['permissions'] || {};
const EXPANDED_PRINCIPALS = permissions['cross-domain-content'] || [];
const JS_VERSION = '1.8';
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.";
const WorkerSandbox = EventEmitter.compose({
/**
* Emit a message to the worker content sandbox
*/
emit: function emit() {
// First ensure having a regular array
// (otherwise, `arguments` would be mapped to an object by `stringify`)
let array = Array.slice(arguments);
// JSON.stringify is buggy with cross-sandbox values,
// it may return "{}" on functions. Use a replacer to match them correctly.
function replacer(k, v) {
return typeof v === "function" ? undefined : v;
}
// Ensure having an asynchronous behavior
let self = this;
timer.setTimeout(function () {
self._emitToContent(JSON.stringify(array, replacer));
}, 0);
},
/**
* 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() {
let args = Array.slice(arguments);
return this._emitToContent(Cu.cloneInto(args, this._addonWorker._window));
},
/**
* Method called by the worker sandbox when it needs to send a message
*/
_onContentEvent: function onContentEvent(args) {
// As `emit`, we ensure having an asynchronous behavior
let self = this;
timer.setTimeout(function () {
// We emit event to chrome/addon listeners
self._emit.apply(self, JSON.parse(args));
}, 0);
},
/**
* Configures sandbox and loads content scripts into it.
* @param {Worker} worker
* content worker
*/
constructor: function WorkerSandbox(worker) {
this._addonWorker = worker;
// Ensure that `emit` has always the right `this`
this.emit = this.emit.bind(this);
this.emitSync = this.emitSync.bind(this);
// We receive a wrapped window, that may be an xraywrapper if it's content
let window = worker._window;
let proto = window;
// Eventually use expanded principal sandbox feature, if some are given.
//
// But prevent it when the Worker isn't used for a content script but for
// injecting `addon` object into a Panel, Widget, ... scope.
// 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 = []
if (EXPANDED_PRINCIPALS.length > 0 && !worker._injectInDocument) {
principals = EXPANDED_PRINCIPALS.concat(window);
// 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");
}
// Create the sandbox and bind it to window in order for content scripts to
// have access to all standard globals (window, document, ...)
let content = this._sandbox = sandbox(principals, {
sandboxPrototype: proto,
wantXrays: !worker._injectInDocument,
wantGlobalProperties: wantGlobalProperties,
sameZoneAs: window,
metadata: {
SDKContentScript: true,
'inner-window-id': getInnerId(window)
}
});
// 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() content,
get top() top,
get parent() 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 chromeAPI = 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,
},
}, ContentWorker, {cloneFunctions: true});
let onEvent = Cu.exportFunction(this._onContentEvent.bind(this), ContentWorker);
let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options);
this._emitToContent = result;
// Handle messages send by this script:
let self = this;
// console.xxx calls
this.on("console", function consoleListener(kind) {
console[kind].apply(console, Array.slice(arguments, 1));
});
// self.postMessage calls
this.on("message", function postMessage(data) {
// destroyed?
if (self._addonWorker)
self._addonWorker._emit('message', data);
});
// self.port.emit calls
this.on("event", function portEmit(name, args) {
// destroyed?
if (self._addonWorker)
self._addonWorker._onContentScriptEvent.apply(self._addonWorker, arguments);
});
// unwrap, recreate and propagate async Errors thrown from content-script
this.on("error", function onError({instanceOfError, value}) {
if (self._addonWorker) {
let error = value;
if (instanceOfError) {
error = new Error(value.message, value.fileName, value.lineNumber);
error.stack = value.stack;
error.name = value.name;
}
self._addonWorker._emit('error', error);
}
});
// Inject `addon` global into target document if document is trusted,
// `addon` in document is equivalent to `self` in content script.
if (worker._injectInDocument) {
let win = window.wrappedJSObject ? window.wrappedJSObject : window;
Object.defineProperty(win, "addon", {
value: content.self,
configurable: true
}
);
}
// Inject our `console` into target document if worker doesn't have a tab
// (e.g Panel, PageWorker, Widget).
// `worker.tab` can't be used because bug 804935.
if (!getTabForContentWindow(window)) {
let win = window.wrappedJSObject ? window.wrappedJSObject : 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;
};
// 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) {
if (Array.isArray(contentScriptFile))
this._importScripts.apply(this, contentScriptFile);
else
this._importScripts(contentScriptFile);
}
if (contentScript) {
this._evaluate(
Array.isArray(contentScript) ? contentScript.join(';\n') : contentScript
);
}
},
destroy: function destroy() {
this.emitSync("detach");
this._sandbox = null;
this._addonWorker = null;
},
/**
* JavaScript sandbox where all the content scripts are evaluated.
* {Sandbox}
*/
_sandbox: null,
/**
* Reference to the addon side of the worker.
* @type {Worker}
*/
_addonWorker: null,
/**
* Evaluates code in the sandbox.
* @param {String} code
* JavaScript source to evaluate.
* @param {String} [filename='javascript:' + code]
* Name of the file
*/
_evaluate: function(code, filename) {
try {
evaluate(this._sandbox, code, filename || 'javascript:' + code);
}
catch(e) {
this._addonWorker._emit('error', e);
}
},
/**
* 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.
*/
_importScripts: function _importScripts(url) {
let urls = Array.slice(arguments, 0);
for (let contentScriptFile of urls) {
try {
let uri = URL(contentScriptFile);
if (uri.scheme === 'resource')
load(this._sandbox, String(uri));
else
throw Error("Unsupported `contentScriptFile` url: " + String(uri));
}
catch(e) {
this._addonWorker._emit('error', e);
}
}
}
});
/**
* 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 = EventEmitter.compose({
on: Trait.required,
_removeAllListeners: Trait.required,
// List of messages fired before worker is initialized
get _earlyEvents() {
delete this._earlyEvents;
this._earlyEvents = [];
return this._earlyEvents;
},
/**
* 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
* symbiont.
*
* `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 args = ['message'].concat(Array.slice(arguments));
if (!this._inited) {
this._earlyEvents.push(args);
return;
}
processMessage.apply(this, args);
},
/**
* EventEmitter, that behaves (calls listeners) asynchronously.
* A way to send customized messages to / from the worker.
* Events from in the worker can be observed / emitted via
* worker.on / worker.emit.
*/
get port() {
// We generate dynamically this attribute as it needs to be accessible
// before Worker.constructor gets called. (For ex: Panel)
// create an event emitter that receive and send events from/to the worker
this._port = EventEmitterTrait.create({
emit: this._emitEventToContent.bind(this)
});
// expose wrapped port, that exposes only public properties:
// We need to destroy this getter in order to be able to set the
// final value. We need to update only public port attribute as we never
// try to access port attribute from private API.
delete this._public.port;
this._public.port = Cortex(this._port);
// Replicate public port to the private object
delete this.port;
this.port = this._public.port;
return this._port;
},
/**
* Same object than this.port but private API.
* Allow access to _emit, in order to send event to port.
*/
_port: null,
/**
* Emit a custom event to the content script,
* i.e. emit this event on `self.port`
*/
_emitEventToContent: function () {
let args = ['event'].concat(Array.slice(arguments));
if (!this._inited) {
this._earlyEvents.push(args);
return;
}
processMessage.apply(this, args);
},
// 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,
constructor: function Worker(options) {
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;
this._setListeners(options);
unload.ensure(this._public, "destroy");
// Ensure that worker._port is initialized for contentWorker to be able
// to send events during worker initialization.
this.port;
this._documentUnload = this._documentUnload.bind(this);
this._pageShow = this._pageShow.bind(this);
this._pageHide = this._pageHide.bind(this);
if ("window" in options) this._attach(options.window);
},
_setListeners: function(options) {
if ('onError' in options)
this.on('error', options.onError);
if ('onMessage' in options)
this.on('message', options.onMessage);
if ('onDetach' in options)
this.on('detach', options.onDetach);
},
_attach: function(window) {
this._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
this._windowID = getInnerId(this._window);
observers.on("inner-window-destroyed", this._documentUnload);
// Listen to pagehide event in order to freeze the content script
// while the document is frozen in bfcache:
this._window.addEventListener("pageshow", this._pageShow, true);
this._window.addEventListener("pagehide", this._pageHide, true);
// will set this._contentWorker pointing to the private API:
this._contentWorker = WorkerSandbox(this);
// Mainly enable worker.port.emit to send event to the content worker
this._inited = true;
this._frozen = false;
// Process all events and messages that were fired before the
// worker was initialized.
this._earlyEvents.forEach((function (args) {
processMessage.apply(this, args);
}).bind(this));
},
_documentUnload: function _documentUnload({ subject, data }) {
let innerWinID = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
if (innerWinID != this._windowID) return false;
this._workerCleanup();
return true;
},
_pageShow: function _pageShow() {
this._contentWorker.emitSync("pageshow");
this._emit("pageshow");
this._frozen = false;
},
_pageHide: function _pageHide() {
this._contentWorker.emitSync("pagehide");
this._emit("pagehide");
this._frozen = true;
},
get url() {
// this._window will be null after detach
return this._window ? this._window.document.location.href : null;
},
get tab() {
// this._window will be null after detach
if (this._window)
return getTabForWindow(this._window);
return null;
},
/**
* Tells content worker to unload itself and
* removes all the references from itself.
*/
destroy: function destroy() {
this._workerCleanup();
this._inited = true;
this._removeAllListeners();
},
/**
* Remove all internal references to the attached document
* Tells _port to unload itself and removes all the references from itself.
*/
_workerCleanup: function _workerCleanup() {
// maybe unloaded before content side is created
// As Symbiont call worker.constructor on document load
if (this._contentWorker)
this._contentWorker.destroy();
this._contentWorker = null;
if (this._window) {
this._window.removeEventListener("pageshow", this._pageShow, true);
this._window.removeEventListener("pagehide", this._pageHide, true);
}
this._window = null;
// This method may be called multiple times,
// avoid dispatching `detach` event more than once
if (this._windowID) {
this._windowID = null;
observers.off("inner-window-destroyed", this._documentUnload);
this._earlyEvents.length = 0;
this._emit("detach");
}
this._inited = false;
},
/**
* Receive an event from the content script that need to be sent to
* worker.port. Provide a way for composed object to catch all events.
*/
_onContentScriptEvent: function _onContentScriptEvent() {
this._port._emit.apply(this._port, arguments);
},
/**
* 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,
/**
* Flag to enable `addon` object injection in document. (bug 612726)
* @type {Boolean}
*/
_injectInDocument: false
});
/**
* 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 () {
if (!this._contentWorker)
throw new Error(ERR_DESTROYED);
if (this._frozen)
throw new Error(ERR_FROZEN);
this._contentWorker.emit.apply(null, Array.slice(arguments));
}
exports.Worker = Worker;

View File

@ -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": "deprecated"
};
const {
compose: _compose,
override: _override,
resolve: _resolve,
trait: _trait,
//create: _create,
required,
} = require('./traits/core');
const { getOwnPropertyIdentifiers } = require('../util/object');
const defineProperties = Object.defineProperties;
const freeze = Object.freeze;
const create = Object.create;
/**
* Work around bug 608959 by defining the _create function here instead of
* importing it from traits/core. For docs on this function, see the create
* function in that module.
*
* FIXME: remove this workaround in favor of importing the function once that
* bug has been fixed.
*/
function _create(proto, trait) {
let properties = {},
keys = getOwnPropertyIdentifiers(trait);
for (let key of keys) {
let descriptor = trait[key];
if (descriptor.required &&
!Object.prototype.hasOwnProperty.call(proto, key))
throw new Error('Missing required property: ' + key);
else if (descriptor.conflict)
throw new Error('Remaining conflicting property: ' + key);
else
properties[key] = descriptor;
}
return Object.create(proto, properties);
}
/**
* Placeholder for `Trait.prototype`
*/
let TraitProto = Object.prototype;
function Get(key) this[key]
function Set(key, value) this[key] = value
/**
* Creates anonymous trait descriptor from the passed argument, unless argument
* is a trait constructor. In later case trait's already existing properties
* descriptor is returned.
* This is module's internal function and is used as a gateway to a trait's
* internal properties descriptor.
* @param {Function} $
* Composed trait's constructor.
* @returns {Object}
* Private trait property of the composition.
*/
function TraitDescriptor(object)
(
'function' == typeof object &&
(object.prototype == TraitProto || object.prototype instanceof Trait)
) ? object._trait(TraitDescriptor) : _trait(object)
function Public(instance, trait) {
let result = {},
keys = getOwnPropertyIdentifiers(trait);
for (let key of keys) {
if (typeof key === 'string' && '_' === key.charAt(0) && '__iterator__' !== key )
continue;
let property = trait[key],
descriptor = {
configurable: property.configurable,
enumerable: property.enumerable
};
if (property.get)
descriptor.get = property.get.bind(instance);
if (property.set)
descriptor.set = property.set.bind(instance);
if ('value' in property) {
let value = property.value;
if ('function' === typeof value) {
descriptor.value = property.value.bind(instance);
descriptor.writable = property.writable;
} else {
descriptor.get = Get.bind(instance, key);
descriptor.set = Set.bind(instance, key);
}
}
result[key] = descriptor;
}
return result;
}
/**
* This is private function that composes new trait with privates.
*/
function Composition(trait) {
function Trait() {
let self = _create({}, trait);
self._public = create(Trait.prototype, Public(self, trait));
delete self._public.constructor;
if (Object === self.constructor)
self.constructor = Trait;
else
return self.constructor.apply(self, arguments) || self._public;
return self._public;
}
defineProperties(Trait, {
prototype: { value: freeze(create(TraitProto, {
constructor: { value: constructor, writable: true }
}))}, // writable is `true` to avoid getters in custom ES5
displayName: { value: (trait.constructor || constructor).name },
compose: { value: compose, enumerable: true },
override: { value: override, enumerable: true },
resolve: { value: resolve, enumerable: true },
required: { value: required, enumerable: true },
_trait: { value: function _trait(caller)
caller === TraitDescriptor ? trait : undefined
}
});
return freeze(Trait);
}
/**
* Composes new trait out of itself and traits / property maps passed as an
* arguments. If two or more traits / property maps have properties with the
* same name, the new trait will contain a "conflict" property for that name.
* This is a commutative and associative operation, and the order of its
* arguments is not significant.
* @params {Object|Function}
* List of Traits or property maps to create traits from.
* @returns {Function}
* New trait containing the combined properties of all the traits.
*/
function compose() {
let traits = Array.slice(arguments, 0);
traits.push(this);
return Composition(_compose.apply(null, traits.map(TraitDescriptor)));
}
/**
* Composes a new trait with all of the combined properties of `this` and the
* argument traits. In contrast to `compose`, `override` immediately resolves
* all conflicts resulting from this composition by overriding the properties of
* later traits. Trait priority is from left to right. I.e. the properties of
* the leftmost trait are never overridden.
* @params {Object} trait
* @returns {Object}
*/
function override() {
let traits = Array.slice(arguments, 0);
traits.push(this);
return Composition(_override.apply(null, traits.map(TraitDescriptor)));
}
/**
* Composes new resolved trait, with all the same properties as this
* trait, except that all properties whose name is an own property of
* `resolutions` will be renamed to `resolutions[name]`. If it is
* `resolutions[name]` is `null` value is changed into a required property
* descriptor.
*/
function resolve(resolutions)
Composition(_resolve(resolutions, TraitDescriptor(this)))
/**
* Base Trait, that all the traits are composed of.
*/
const Trait = Composition({
/**
* Internal property holding public API of this instance.
*/
_public: { value: null, configurable: true, writable: true },
toString: { value: function() '[object ' + this.constructor.name + ']' }
});
TraitProto = Trait.prototype;
exports.Trait = Trait;

View File

@ -1,319 +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"
};
// Design inspired by: http://www.traitsjs.org/
const { getOwnPropertyIdentifiers } = require('../../util/object');
const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
const hasOwn = Object.prototype.hasOwnProperty;
const _create = Object.create;
function doPropertiesMatch(object1, object2, name) {
// If `object1` has property with the given `name`
return name in object1 ?
// then `object2` should have it with the same value.
name in object2 && object1[name] === object2[name] :
// otherwise `object2` should not have property with the given `name`.
!(name in object2);
}
/**
* Compares two trait custom property descriptors if they are the same. If
* both are `conflict` or all the properties of descriptor are equal returned
* value will be `true`, otherwise it will be `false`.
* @param {Object} desc1
* @param {Object} desc2
*/
function areSame(desc1, desc2) {
return ('conflict' in desc1 && desc1.conflict &&
'conflict' in desc2 && desc2.conflict) ||
(doPropertiesMatch(desc1, desc2, 'get') &&
doPropertiesMatch(desc1, desc2, 'set') &&
doPropertiesMatch(desc1, desc2, 'value') &&
doPropertiesMatch(desc1, desc2, 'enumerable') &&
doPropertiesMatch(desc1, desc2, 'required') &&
doPropertiesMatch(desc1, desc2, 'conflict'));
}
/**
* Converts array to an object whose own property names represent
* values of array.
* @param {String[]} names
* @returns {Object}
* @example
* Map(['foo', ...]) => { foo: true, ...}
*/
function Map(names) {
let map = {};
for (let name of names)
map[name] = true;
return map;
}
const ERR_CONFLICT = 'Remaining conflicting property: ',
ERR_REQUIRED = 'Missing required property: ';
/**
* Constant singleton, representing placeholder for required properties.
* @type {Object}
*/
const required = { toString: function()'<Trait.required>' };
exports.required = required;
/**
* Generates custom **required** property descriptor. Descriptor contains
* non-standard property `required` that is equal to `true`.
* @param {String} name
* property name to generate descriptor for.
* @returns {Object}
* custom property descriptor
*/
function Required(name) {
function required() { throw new Error(ERR_REQUIRED + name) }
return {
get: required,
set: required,
required: true
};
}
/**
* Generates custom **conflicting** property descriptor. Descriptor contains
* non-standard property `conflict` that is equal to `true`.
* @param {String} name
* property name to generate descriptor for.
* @returns {Object}
* custom property descriptor
*/
function Conflict(name) {
function conflict() { throw new Error(ERR_CONFLICT + name) }
return {
get: conflict,
set: conflict,
conflict: true
};
}
/**
* Function generates custom properties descriptor of the `object`s own
* properties. All the inherited properties are going to be ignored.
* Properties with values matching `required` singleton will be marked as
* 'required' properties.
* @param {Object} object
* Set of properties to generate trait from.
* @returns {Object}
* Properties descriptor of all of the `object`'s own properties.
*/
function trait(properties) {
let result = {},
keys = getOwnPropertyIdentifiers(properties);
for (let key of keys) {
let descriptor = getOwnPropertyDescriptor(properties, key);
result[key] = (required === descriptor.value) ? Required(key) : descriptor;
}
return result;
}
exports.Trait = exports.trait = trait;
/**
* Composes new trait. If two or more traits have own properties with the
* same name, the new trait will contain a 'conflict' property for that name.
* 'compose' is a commutative and associative operation, and the order of its
* arguments is not significant.
*
* @params {Object} trait
* Takes traits as an arguments
* @returns {Object}
* New trait containing the combined own properties of all the traits.
* @example
* var newTrait = compose(trait_1, trait_2, ..., trait_N);
*/
function compose(trait1, trait2) {
let traits = Array.slice(arguments, 0),
result = {};
for (let trait of traits) {
let keys = getOwnPropertyIdentifiers(trait);
for (let key of keys) {
let descriptor = trait[key];
// if property already exists and it's not a requirement
if (hasOwn.call(result, key) && !result[key].required) {
if (descriptor.required)
continue;
if (!areSame(descriptor, result[key]))
result[key] = Conflict(key);
} else {
result[key] = descriptor;
}
}
}
return result;
}
exports.compose = compose;
/**
* Composes new trait with the same own properties as the original trait,
* except that all property names appearing in the first argument are replaced
* by 'required' property descriptors.
* @param {String[]} keys
* Array of strings property names.
* @param {Object} trait
* A trait some properties of which should be excluded.
* @returns {Object}
* @example
* var newTrait = exclude(['name', ...], trait)
*/
function exclude(keys, trait) {
let exclusions = Map(keys),
result = {};
keys = getOwnPropertyIdentifiers(trait);
for (let key of keys) {
if (!hasOwn.call(exclusions, key) || trait[key].required)
result[key] = trait[key];
else
result[key] = Required(key);
}
return result;
}
/**
* Composes a new trait with all of the combined properties of the argument
* traits. In contrast to `compose`, `override` immediately resolves all
* conflicts resulting from this composition by overriding the properties of
* later traits. Trait priority is from left to right. I.e. the properties of
* the leftmost trait are never overridden.
* @params {Object} trait
* @returns {Object}
* @examples
* // override is associative:
* override(t1,t2,t3)
* // is equivalent to
* override(t1, override(t2, t3))
* // or
* to override(override(t1, t2), t3)
*
* // override is not commutative:
* override(t1,t2)
* // is not equivalent to
* override(t2,t1)
*/
function override() {
let traits = Array.slice(arguments, 0),
result = {};
for (let trait of traits) {
let keys = getOwnPropertyIdentifiers(trait);
for (let key of keys) {
let descriptor = trait[key];
if (!hasOwn.call(result, key) || result[key].required)
result[key] = descriptor;
}
}
return result;
}
exports.override = override;
/**
* Composes a new trait with the same properties as the original trait, except
* that all properties whose name is an own property of map will be renamed to
* map[name], and a 'required' property for name will be added instead.
* @param {Object} map
* An object whose own properties serve as a mapping from old names to new
* names.
* @param {Object} trait
* A trait object
* @returns {Object}
* @example
* var newTrait = rename(map, trait);
*/
function rename(map, trait) {
let result = {},
keys = getOwnPropertyIdentifiers(trait);
for (let key of keys) {
// must be renamed & it's not requirement
if (hasOwn.call(map, key) && !trait[key].required) {
let alias = map[key];
if (hasOwn.call(result, alias) && !result[alias].required)
result[alias] = Conflict(alias);
else
result[alias] = trait[key];
if (!hasOwn.call(result, key))
result[key] = Required(key);
} else { // must not be renamed or its a requirement
// property is not in result trait yet
if (!hasOwn.call(result, key))
result[key] = trait[key];
// property is already in resulted trait & it's not requirement
else if (!trait[key].required)
result[key] = Conflict(key);
}
}
return result;
}
/**
* Composes new resolved trait, with all the same properties as the original
* trait, except that all properties whose name is an own property of
* resolutions will be renamed to `resolutions[name]`. If it is
* `resolutions[name]` is `null` value is changed into a required property
* descriptor.
* function can be implemented as `rename(map,exclude(exclusions, trait))`
* where map is the subset of mappings from oldName to newName and exclusions
* is an array of all the keys that map to `null`.
* Note: it's important to **first** `exclude`, **then** `rename`, since
* `exclude` and rename are not associative.
* @param {Object} resolutions
* An object whose own properties serve as a mapping from old names to new
* names, or to `null` if the property should be excluded.
* @param {Object} trait
* A trait object
* @returns {Object}
* Resolved trait with the same own properties as the original trait.
*/
function resolve(resolutions, trait) {
let renames = {},
exclusions = [],
keys = getOwnPropertyIdentifiers(resolutions);
for (let key of keys) { // pre-process renamed and excluded properties
if (resolutions[key]) // old name -> new name
renames[key] = resolutions[key];
else // name -> undefined
exclusions.push(key);
}
return rename(renames, exclude(exclusions, trait));
}
exports.resolve = resolve;
/**
* `create` is like `Object.create`, except that it ensures that:
* - an exception is thrown if 'trait' still contains required properties
* - an exception is thrown if 'trait' still contains conflicting
* properties
* @param {Object}
* prototype of the completed object
* @param {Object} trait
* trait object to be turned into a complete object
* @returns {Object}
* An object with all of the properties described by the trait.
*/
function create(proto, trait) {
let properties = {},
keys = getOwnPropertyIdentifiers(trait);
for (let key of keys) {
let descriptor = trait[key];
if (descriptor.required && !hasOwn.call(proto, key))
throw new Error(ERR_REQUIRED + key);
else if (descriptor.conflict)
throw new Error(ERR_CONFLICT + key);
else
properties[key] = descriptor;
}
return _create(proto, properties);
}
exports.create = create;

View File

@ -14,7 +14,7 @@ const { getTabs, closeTab, getURI, getTabId, getSelectedTab } = require("../tabs
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 { cleanUI } = require("../test/utils");
const findAndRunTests = function findAndRunTests(options) {
var TestFinder = require("./unit-test-finder").TestFinder;

View File

@ -8,13 +8,9 @@ module.metadata = {
};
const { Cc, Ci } = require('chrome');
const { EventEmitter } = require('../deprecated/events');
const { Trait } = require('../deprecated/traits');
const { when } = require('../system/unload');
const events = require('../system/events');
const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser,
getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils');
const errors = require('../deprecated/errors');
const { deprecateFunction } = require('../util/deprecate');
const { ignoreWindow } = require('sdk/private-browsing/utils');
const { isPrivateBrowsingSupported } = require('../self');
@ -124,13 +120,18 @@ WindowTracker.prototype = {
this._unregWindow(window);
},
handleEvent: errors.catchAndLog(function handleEvent(event) {
if (event.type == 'load' && event.target) {
var window = event.target.defaultView;
if (window)
this._regWindow(window);
handleEvent: function handleEvent(event) {
try {
if (event.type == 'load' && event.target) {
var window = event.target.defaultView;
if (window)
this._regWindow(window);
}
}
}),
catch(e) {
console.exception(e);
}
},
_onToplevelWindowReady: function _onToplevelWindowReady({subject}) {
let window = subject;
@ -140,47 +141,22 @@ WindowTracker.prototype = {
this._regWindow(window);
},
observe: errors.catchAndLog(function observe(subject, topic, data) {
var window = subject.QueryInterface(Ci.nsIDOMWindow);
// ignore private windows if they are not supported
if (ignoreWindow(window))
return;
if (topic == 'domwindowclosed')
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;
const WindowTrackerTrait = Trait.compose({
_onTrack: Trait.required,
_onUntrack: Trait.required,
constructor: function WindowTrackerTrait() {
WindowTracker({
onTrack: this._onTrack.bind(this),
onUntrack: this._onUntrack.bind(this)
});
}
});
exports.WindowTrackerTrait = WindowTrackerTrait;
var gDocsToClose = [];
function onDocUnload(event) {
var index = gDocsToClose.indexOf(event.target);
if (index == -1)
throw new Error('internal error: unloading document not found');
var document = gDocsToClose.splice(index, 1)[0];
// Just in case, let's remove the event listener too.
document.defaultView.removeEventListener('unload', onDocUnload, false);
}
onDocUnload = require('./errors').catchAndLog(onDocUnload);
exports.closeOnUnload = function closeOnUnload(window) {
window.addEventListener('unload', onDocUnload, false);
gDocsToClose.push(window.document);
};
Object.defineProperties(exports, {
activeWindow: {
enumerable: true,
@ -219,9 +195,3 @@ exports.isBrowser = deprecateFunction(isBrowser,
);
exports.hiddenWindow = appShellService.hiddenDOMWindow;
when(
function() {
gDocsToClose.slice().forEach(
function(doc) { doc.defaultView.close(); });
});

View File

@ -86,6 +86,14 @@ exports.once = once;
* 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();
@ -101,7 +109,7 @@ function emit (target, type, ...args) {
let listener = listeners[index];
// Dispatch only if listener is still registered.
if (~state.indexOf(listener))
listener.apply(target, args);
listener.apply(thisArg, args);
}
catch (error) {
// If exception is not thrown by a error listener and error listener is
@ -114,7 +122,7 @@ function emit (target, type, ...args) {
// Also emit on `"*"` so that one could listen for all events.
if (type !== '*') emit(target, '*', type, ...args);
}
exports.emit = emit;
exports.emitOnObject = emitOnObject;
/**
* Removes an event `listener` for the given event `type` on the given event

View File

@ -9,7 +9,6 @@ module.metadata = {
};
const { Cc, Ci } = require("chrome");
const errors = require("../deprecated/errors");
const { Class } = require("../core/heritage");
const { List, addListItem, removeListItem } = require("../util/list");
const { EventTarget } = require("../event/target");

View File

@ -1,80 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { windows, isInteractive, isDocumentLoaded,
getOuterId, isTopLevel } = require("../window/utils");
const { InputPort } = require("./system");
const { lift, merges, foldp, keepIf, start, Input } = require("../event/utils");
const { patch } = require("diffpatcher/index");
const { on } = require("../event/core");
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(null, {includePrivates: 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 opened top level window.
const LastOpened = lift(Update, new InputPort({topic: "domwindowopened"}));
exports.LastOpened = LastOpened;
// Signal represents delta for last top level window close.
const LastClosed = lift(Delete, 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(isTopLevel, 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(isTopLevel, 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 currently opened top level windows, updated
// to new set any time window is opened or closed.
const Opened = foldp(patch, opened, merges([LastOpened, LastClosed]));
Opened[start] = initialize;
exports.Opened = Opened;
// 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;

View File

@ -5,7 +5,7 @@
"use strict";
module.metadata = {
"stability": "experimental"
"stability": "deprecated"
};
const {Cc,Ci,Cr} = require("chrome");

View File

@ -884,6 +884,7 @@ 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;

View File

@ -32,7 +32,7 @@ const InputStreamPump = CC("@mozilla.org/network/input-stream-pump;1",
const threadManager = Cc["@mozilla.org/thread-manager;1"].
getService(Ci.nsIThreadManager);
const eventTarget = Cc["@mozilla.org/network/socket-transport-service;1"].
const eventTarget = Cc["@mozilla.org/network/stream-transport-service;1"].
getService(Ci.nsIEventTarget);
let isFunction = value => typeof(value) === "function"

View File

@ -125,9 +125,7 @@ exports.isGenerator = isGenerator;
* isArray([1, 2, 3]) // true
* isArray({ 0: 'foo', length: 1 }) // false
*/
var isArray = Array.isArray || function isArray(value) {
Object.prototype.toString.call(value) === "[object Array]";
}
var isArray = Array.isArray;
exports.isArray = isArray;
/**
@ -137,7 +135,7 @@ exports.isArray = isArray;
* isArguments([1,2,3]); // false
*/
function isArguments(value) {
Object.prototype.toString.call(value) === "[object Arguments]";
return Object.prototype.toString.call(value) === "[object Arguments]";
}
exports.isArguments = isArguments;

View File

@ -1,8 +1,6 @@
/* 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/.
*/
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
module.metadata = {

View File

@ -10,7 +10,6 @@ module.metadata = {
const { Cc, Ci, Cr } = require("chrome");
const apiUtils = require("./deprecated/api-utils");
const errors = require("./deprecated/errors");
const { isString, isUndefined, instanceOf } = require('./lang/type');
const { URL, isLocalURL } = require('./url');
const { data } = require('./self');
@ -34,9 +33,15 @@ catch (err) {
exports.notify = function notifications_notify(options) {
let valOpts = validateOptions(options);
let clickObserver = !valOpts.onClick ? null : {
observe: function notificationClickObserved(subject, topic, data) {
if (topic === "alertclickcallback")
errors.catchAndLog(valOpts.onClick).call(exports, valOpts.data);
observe: (subject, topic, data) => {
if (topic === "alertclickcallback") {
try {
valOpts.onClick.call(exports, valOpts.data);
}
catch(e) {
console.exception(e);
}
}
}
};
function notifyWithOpts(notifyFn) {

View File

@ -125,9 +125,12 @@ const PageMod = Class({
}
}
model.childOptions = omit(model, ["include", "exclude"]);
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);
},

View File

@ -27,6 +27,7 @@ const { has } = require('./util/array');
const { Rules } = require('./util/rules');
const { merge } = require('./util/object');
const { data } = require('./self');
const { getActiveView } = require("./view/core");
const views = new WeakMap();
const workers = new WeakMap();
@ -181,3 +182,5 @@ function pageFromDoc(doc) {
return page;
return null;
}
getActiveView.define(Page, viewFor);

View File

@ -1,7 +1,6 @@
/* 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 = {
@ -9,7 +8,6 @@ module.metadata = {
};
const { Cc, Ci } = require('chrome');
const { EventEmitter } = require('../deprecated/events');
const { isValidURI, URL } = require('../url');
const { contract } = require('../util/contract');
const { extend } = require('../util/object');
@ -22,7 +20,7 @@ const validItem = {
group: {
is: ['object', 'number', 'undefined', 'null'],
ok: function (value) {
return value &&
return value &&
(value.toString && value.toString() === '[object Group]') ||
typeof value === 'number' ||
value.type === 'group';
@ -48,7 +46,7 @@ const validTitle = {
const validURL = {
url: {
is: ['string'],
is: ['string'],
ok: isValidURI,
msg: 'The `url` property must be a valid URL.'
}

View File

@ -46,7 +46,7 @@ let pathMapping = Object.keys(options.paths)
let { getNewLoaderID } = require('../../framescript/FrameScriptManager.jsm');
let PATH = options.paths[''];
const childOptions = omit(options, ['modules', 'globals']);
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 {

View File

@ -164,6 +164,8 @@ 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() response(this).request.responseURL,
get text() response(this).request.responseText,
get xml() {
throw new Error("Sorry, the 'xml' property is no longer available. " +

View File

@ -9,7 +9,6 @@ module.metadata = {
const { Cc, Ci, CC } = require('chrome');
const options = require('@loader/options');
const file = require('./io/file');
const runtime = require("./system/runtime");
const { when: unload } = require("./system/unload");

View File

@ -7,11 +7,6 @@ module.metadata = {
"stability": "unstable"
};
const { modelFor } = require("./model/core");
const { viewFor } = require("./view/core");
const { isTab } = require("./tabs/utils");
if (require("./system/xul-app").is("Fennec")) {
module.exports = require("./windows/tabs-fennec").tabs;
}
@ -20,14 +15,3 @@ else {
}
const tabs = module.exports;
// Implement `modelFor` function for the Tab instances.
// Finds a right model by iterating over all tab models
// and finding one that wraps given `view`.
modelFor.when(isTab, view => {
for (let model of tabs) {
if (viewFor(model) === view)
return model;
}
return null;
});

Some files were not shown because too many files have changed in this diff Show More