summaryrefslogtreecommitdiff
path: root/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder
diff options
context:
space:
mode:
authorRuben Rodriguez <ruben@gnu.org>2015-11-28 15:24:36 -0600
committerRuben Rodriguez <ruben@gnu.org>2015-11-28 16:27:06 -0600
commite4a3586a14996bbece3b26c9e3b7704ea6af8615 (patch)
tree499bdd16b3a90c30b01e4b47a5882d13b4800f50 /data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder
parent4dbc2fae927bb02ef243c87938e638af9afee8fa (diff)
LibreJS upgraded to 6.0.10
Diffstat (limited to 'data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder')
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/.npmignore6
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/README.md22
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning-mod.js19
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.css47
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.html29
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.js3
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon-warning.md0
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon.md28
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addonprovider.md50
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/awesomebar.md61
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/content-policy.md0
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/l10n.md41
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/listen.md23
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/menuitems.md66
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/panic.md45
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/toolbarbutton.md84
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/unload+.md20
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userscript.md44
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userstyles.md26
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/xulkeys.md55
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/data/test.user.js6
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/lib/main.js11
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/package.json8
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/folder.js51
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/unload.js92
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/addon.js80
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/manager.js15
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/provider.js52
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/application/restart.js22
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/instances.js36
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/net-utils.js7
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/services.js57
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/xpcom-utils.js3
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/events.js23
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/request.js45
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/response.js44
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connections.js8
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/permissions.js88
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/policy.js143
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/devtools/gcli.js23
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/download.js95
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/l10n.js76
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/panic.js92
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/redirect.js52
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/about.js84
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/resource.js43
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/GM_xmlhttpRequester.js238
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/convert-2-regexp.js23
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/greasemonkey-api.js76
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-header-parser.js31
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-manager.js44
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-sandbox.js24
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/storage.js126
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/awesomebar.js205
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/findbar/suggestion.js77
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/menuitems.js218
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/actions.js9
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/contract.js30
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/state.js8
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/utils.js31
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/toolbarbutton.js179
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/utils.js28
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/validate.js31
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/warning.js43
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/web-panel.js289
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userscript.js116
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userstyles.js72
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/utils/addonmanager.js19
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/browser.js180
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/key.js43
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/listen.js29
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/namespace.js3
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/zip/utils.js13
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/package.json60
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/black.pngbin0 -> 2801 bytes
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/index.html4
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-folder.js90
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-warning.js3
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-connection-request.js57
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-permissions.js35
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-policy.js155
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-download.js58
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-find-suggestion.js3
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-listen.js152
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-menuitems.js169
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-panic.js103
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-redirect.js49
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-about.js43
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-resource.js3
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-storage.js134
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-toolbarbutton.js165
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-unload+.js150
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userscripts.js8
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.css0
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.js116
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-web-panel.js563
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test.pngbin0 -> 2873 bytes
97 files changed, 6230 insertions, 0 deletions
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/.npmignore b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/.npmignore
new file mode 100644
index 0000000..bc7dd61
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/.npmignore
@@ -0,0 +1,6 @@
+.DS_Store
+*.xpi
+.project
+.settings
+*.zip
+
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/README.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/README.md
new file mode 100644
index 0000000..635b0cf
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/README.md
@@ -0,0 +1,22 @@
+# Add-on Pathfinder
+
+The Add-on Pathfinder is the collection of Jetpack modules made to be used with the
+[Add-on SDK](https://github.com/mozilla/addon-sdk).
+
+## Highlights
+
+* Toolbar buttons
+* Menuitems
+* GCLI
+* Downloads
+* About/Resource Schemes
+* UserStyles
+* UserScripts
+* XUL Help
+* ZIP Utilities
+* Content policies
+* Content Permissions
+* Awesomebar
+* Modifying Request Headers
+* Redirects
+* Much much more!...
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning-mod.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning-mod.js
new file mode 100644
index 0000000..8d09cc0
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning-mod.js
@@ -0,0 +1,19 @@
+'use strict';
+
+let $ = function(id) document.getElementById(id);
+
+function doAndClose(func) {
+ func();
+ window.close();
+}
+
+$('cancel-btn').addEventListener('click', doAndClose(function() self.port.emit("cancel")), false);
+$('ok-btn').addEventListener('click', doAndClose(function() self.port.emit("accept")), false);
+
+self.port.on('load', function(data) {
+ $('errorTitle').innerHTML = data.errorTitle || '';
+ $('errorShortDesc').innerHTML = data.errorShortDesc || '';
+ $('errorLongDesc').innerHTML = data.errorLongDesc || '';
+ $('cancel-btn').setAttribute('value', data.cancelButtonLabel || 'Decline');
+ $('ok-btn').setAttribute('value', data.okButtonLabel || 'Accept');
+});
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.css
new file mode 100644
index 0000000..ae6a6cc
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.css
@@ -0,0 +1,47 @@
+html, body {
+ background-color: white;
+ color: #222;
+ font-family: helvetica, arial, sans-serif;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+#content {
+ height: 100%;
+ width: 90%;
+ margin: auto;
+}
+
+#banner {
+ background: url("/content/gfx/jetpack.png") no-repeat right center;
+ height: 138px;
+ font-size: 22pt;
+ font-weight: normal;
+ padding-left: 0;
+ padding-right: 300px;
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+
+#banner a {
+ color: black;
+}
+
+#featureName {
+ font-style: italic;
+}
+
+#featureContentContainer {
+ height: 100%;
+}
+
+#featureContent {
+ height: 100%;
+ min-height: 200px;
+ width: 100%;
+}
+
+#confirmationShortDesc {
+ font-size: 14pt;
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.html
new file mode 100644
index 0000000..124782c
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="blacklist">
+ <head>
+ <title></title>
+ <script type="application/javascript;version=1.8" src="warning.js"></script>
+ <link rel="stylesheet" type="text/css" media="all" href="chrome://global/skin/netError.css"/>
+ <link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/blacklist_favicon.png"/>
+ </head>
+ <body>
+ <div id="errorPageContainer">
+ <div>
+ <h1 id="errorTitle"></h1>
+ </div>
+
+ <div id="errorLongContent">
+ <div id="errorShortDesc"></div>
+
+ <div id="errorLongDesc"></div>
+
+ <div id="buttons">
+ <p>
+ <input id="cancel-btn" type="button" value="#cancelButtonLabel#"/>
+ <input id="ok-btn" type="button" value="#okButtonLabel#"/>
+ </p>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.js
new file mode 100644
index 0000000..429d26d
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.js
@@ -0,0 +1,3 @@
+'use strict';
+
+
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon-warning.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon-warning.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon-warning.md
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon.md
new file mode 100644
index 0000000..d75edcc
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon.md
@@ -0,0 +1,28 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+
+The `addon` API provides a simple way to create
+Add-on wrapper instances for the [Extension Manager](about:addons).
+
+## Example ##
+
+ exports.main = function(options) {
+
+ };
+
+<api name="Addon">
+@class
+
+Module exports `Addon` constructor allowing users to create a
+add-on category provider to the Extension Manager.
+
+<api name="Addon">
+@constructor
+Creates a add-on wrapper instance.
+
+@param options {Object}
+Options for the add-on wrapper, with the following parameters:
+
+</api>
+
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addonprovider.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addonprovider.md
new file mode 100644
index 0000000..41ea550
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addonprovider.md
@@ -0,0 +1,50 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+
+The `addonprovider` API provides a simple way to create
+new Add-on types for the [Extension Manager](about:addons).
+
+## Example ##
+
+ exports.main = function(options) {
+
+ };
+
+<api name="AddonProvider">
+@class
+
+Module exports `AddonProvider` constructor allowing users to create a
+add-on category provider to the Extension Manager.
+
+<api name="AddonProvider">
+@constructor
+Creates a add-on provider.
+
+@param options {Object}
+Options for the add-on provider, with the following parameters:
+
+@prop type {String}
+A unique string that will identify the type of add-ons that your provider
+will provide. This is internal users never see it.
+
+@prop localeKey {String}
+A label to be used in the Extension Manager, which users see.
+
+@prop uiPriority {Number}
+A number to represent the order to display your Add-on type in the Extension
+Manager side navigation.
+
+@prop getAddonByID {Function}
+A function that returns the appropriate `Addon`.
+
+@prop getAddons {Function}
+A function that returns the appropriate `Addon`s.
+
+</api>
+
+<api name="destroy">
+@method
+Removes the add-on provider.
+</api>
+
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/awesomebar.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/awesomebar.md
new file mode 100644
index 0000000..dcfbb1f
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/awesomebar.md
@@ -0,0 +1,61 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+
+The `awesomebar` API provides a simple way to create AwesomeBar suggestions.
+
+## Example ##
+
+ // add github search
+ AwesomeBarSuggestion({
+ icon: self.data.url("github_16.png"),
+ matches: /^(?:@[\w\d_-]+|github\s)/i,
+ onSearch: function(query, suggest) {
+ query = query.trim();
+ if (/^github\s/i.test(query)) {
+ query = query.replace(/^github\s/i, "");
+ suggest({
+ title: 'Search Github for: ' + query,
+ favicon: self.data.url("github_16.png"),
+ url: 'https://github.com/search?q=' + encodeURIComponent(query)
+ }, true);
+ } else {
+ var username = query.match(/^@([\w\d_-]+)/)[1];
+ suggest({
+ title: 'Github user: ' + username,
+ label: "View user profile for @" + username,
+ favicon: self.data.url("github_16.png"),
+ url: 'https://github.com/' + username
+ }, true);
+ }
+ }
+ });
+
+<api name="AwesomeBarSuggestion">
+@class
+ A `AwesomeBarSuggestion` constructor is exported, which allows one to create a
+ AwesomeBar suggestions.
+
+<api name="AwesomeBarSuggestion">
+@constructor
+ Creates a AwesomeBar suggestion handler.
+
+@param options {object}
+ Options for the AwesomeBar suggester, with the following parameters:
+
+@prop matches {string}
+ A regular expression which is tested againsted the location bar input string.
+
+@prop [icon] {string}
+ A URL for a 16x16 icon image.
+
+@prop onSearch {function}
+ Function that is invoked when the match pattern matches the location bar input
+ string. If will receive too arguments, `query` which is the input string, and
+ `suggest` which is a function that can be made to return suggestions.
+</api>
+
+<api name="destroy">
+@method
+ Removes the AwesomeBar suggester.
+</api>
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/content-policy.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/content-policy.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/content-policy.md
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/l10n.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/l10n.md
new file mode 100644
index 0000000..2207d16
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/l10n.md
@@ -0,0 +1,41 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+The `l10n` module allows one to localize their Jetpack.
+
+## Example ##
+
+ var _ = require("l10n").l10n({
+ filename: "text.properties",
+ baseURL: require("self").data.url("locale")
+ });
+ console.log(_("hello.world"));
+
+<api name="l10n">
+@function
+ Creates and returns a function which can be used to access translations by
+ key.
+
+ Translations should be grouped together in a folder which contains a folder
+ for each locale being supported whose name is the locale being supported
+ (examples: "en", "en-US", "ja", "ja-JP"). Inside each locale's folder should
+ be a `.properties` file with a name that is the same for every locale. Here
+ is a example of how you might organize things:
+
+ - data/
+ - locale/
+ - en/
+ - text.properties
+ - ja/
+ - text.properties
+
+@param options {object}
+
+
+@prop filename {string}
+ The name of the file storing the translations.
+@prop baseURL {string}
+ The url to the folder containing the locale folders.
+@prop [defaultLocale] {string}
+ Defines the locale to use when you don't have translations for the user's
+ locale. The default is `"en"`.
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/listen.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/listen.md
new file mode 100644
index 0000000..d19c6c6
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/listen.md
@@ -0,0 +1,23 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+The `listen` module allows modules to register listeners to elements that are
+automatically removed when the module unloads.
+
+<api name="listen">
+@function
+ Add listeners to run when unloading in a unload queue. Optionally scope the
+ callback to a container, e.g., window. Provide a way to run all the callbacks.
+
+@param container {object}
+ A container for the node, which a "unload" event will be attached to, this is
+ used to cancel the unload magic that would occur, to avoid memory leaks.
+@param node {object}
+ The node to listen to.
+@param event {string}
+ The event type, for example: "load", "click", ...
+@param callback {function}
+ A function to be called when the event occurs on the node.
+@param [capture] {boolean}
+ Indicates if the event should be captured. [See the `useCapture`
+ documentation here](https://developer.mozilla.org/en/DOM/element.addEventListener).
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/menuitems.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/menuitems.md
new file mode 100644
index 0000000..2017c9c
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/menuitems.md
@@ -0,0 +1,66 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+
+The `menuitems` API is a simple way to create
+[Menuitems](https://developer.mozilla.org/en/XUL/PopupGuide/MenuItems), which
+can perform an action when clicked, and display state.
+
+## Example ##
+
+ exports.main = function(options) {
+ // create menuitem for the File menu,
+ // and insert it before the 'Quit' menuitem
+ require("menuitems").Menuitem({
+ id: "myextprefix-some-mi-id",
+ menuid: "menu_FilePopup",
+ insertbefore: "menu_FileQuitItem",
+ "label": _("label"),
+ "accesskey": _("label.ak"),
+ image: self.data.url("icon.png"),
+ className: 'pizazz',
+ disabled: false,
+ checked: false,
+ onCommand: function() {
+ // do something
+ }
+ });
+ };
+
+<api name="Menuitem">
+@class
+
+Module exports `Menuitem` constructor allowing users to create a
+[`menuitem`](https://developer.mozilla.org/en/XUL/menuitem).
+
+<api name="Menuitem">
+@constructor
+Creates a `menuitem`.
+
+@param options {Object}
+ Options for the `menuitem`, with the following parameters:
+
+@prop id {String}
+A id for the `menuitem`, this should be namespaced.
+
+@prop menuid {String}
+The id of the parent `<menu>` node.
+
+@prop label {String}
+A label for the `menuitem`.
+
+@prop image {String}
+A image url for the `menuitem`.
+
+@prop className {String}
+A default space delimited list of class names for the menuitem.
+
+@prop disabled {Boolean}
+When a menuitem is disabled it cannot be used, but is still displayed.
+
+@prop checked {Boolean}
+Displays a check beside the menuitem.
+
+@prop [onCommand] {Function}
+ A option function that is invoked when the `menuitem` is executed.
+</api>
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/panic.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/panic.md
new file mode 100644
index 0000000..3155341
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/panic.md
@@ -0,0 +1,45 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+The `panic` API provides a simple way to create a panic, which
+can be used to anything that is desired in a panic situation, like entering
+private browsing mode, closing/replacing/hiding tabs, or anything else you
+can imagine.
+
+## Example ##
+
+ // create a panic that lasts 5 mins
+ require('panic').panic(5*60*1000);
+
+<api name="inPanic">
+@property {boolean}
+ This read-only boolean is true if there is a panic going on.
+</api>
+
+<api name="panic">
+@function
+ Starts a panic.
+@param milliseconds {Number}
+ Optional number of milliseconds that the panic should last for, this would
+ be useful if you want ensure that certain things are but on hold until the
+ panic subsides.
+</api>
+
+<api name="start">
+@event
+Emitted immediately after a panic begins
+
+ var panic = require('panic');
+ panic.on("start", function() {
+ // Do something when a panic starts
+ });
+</api>
+
+<api name="end">
+@event
+Emitted immediately after the panic ends
+
+ var panic = require('panic');
+ panic.on("start", function() {
+ // Do something when a panic ends
+ });
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/toolbarbutton.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/toolbarbutton.md
new file mode 100644
index 0000000..87f4cf2
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/toolbarbutton.md
@@ -0,0 +1,84 @@
+The `toolbarbutton` API provides a simple way to create
+[toolbar buttons](https://developer.mozilla.org/en/XUL/toolbarbutton), which
+can perform an action when clicked.
+
+## Example ##
+
+ // create toolbarbutton
+ var tbb = require("toolbarbutton").ToolbarButton({
+ id: "TBB-TEST",
+ label: "TBB TEST",
+ onCommand: function () {
+ tbb.destroy(); // kills the toolbar button
+ }
+ });
+
+ if (require('self').loadReason == "install") {
+ tbb.moveTo({
+ toolbarID: "nav-bar",
+ forceMove: false // only move from palette
+ });
+ }
+
+<api name="ToolbarButton">
+@class
+
+Module exports `ToolbarButton` constructor allowing users to create a
+toolbar button.
+
+<api name="ToolbarButton">
+@constructor
+Creates a toolbarbutton.
+
+@param options {Object}
+ Options for the toolbarbutton, with the following parameters:
+
+@prop id {String}
+A id for the toolbar button, this should be namespaced.
+
+@prop label {String}
+A label for the toolbar button.
+
+@prop image {String}
+A image url for the toolbar button.
+
+@prop [onCommand] {Function}
+ A option function that is invoked when the toolbar button is pressed.
+
+@prop [panel] {Panel}
+ A optional panel.
+</api>
+
+<api name="destroy">
+@method
+Removes the toolbar button from all open windows and no longer adds the
+toolbar button to new windows.
+</api>
+
+<api name="moveTo">
+@method
+Moves the toolbar button on all open windows to the desired location.
+
+@param options {Object}
+Options which describe the position to move the toolbar button to, with the
+following parameters:
+
+@prop toolbarID {String}
+The id of the toolbar which you want to add the toolbar button to.
+
+Example toolbar IDs:
+
+- **toolbar-menubar**: The menu bar.
+- **nav-bar**: The navigation bar.
+- **TabsToolbar**: The tabs bar.
+- **addon-bar**: The addon bar.
+
+@prop insertbefore {String}
+The id of the element which the toolbar button should be inserted before.
+
+@prop forceMove {Boolean}
+If `forceMove` is `false`, then the move will only occur if the toolbar button
+is not already being used. If `true`, then the move will happen no matter where
+the toolbar button is.
+</api>
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/unload+.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/unload+.md
new file mode 100644
index 0000000..78693ef
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/unload+.md
@@ -0,0 +1,20 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+The `unload+` module allows modules to register callbacks that are called
+when they are unloaded, and associate unload functions to containers to have the
+unloader automatically deleted when the container unloads.
+
+<api name="unload">
+@function
+ Save callbacks to run when unloading in a unload queue. Optionally scope the
+ callback to a container, e.g., window. Provide a way to run all the callbacks.
+
+@param callback {function}
+ A function to be called when the module unloads.
+@param [container] {object}
+ Optional container object; if the container "unloads" before the module
+ unloads, then the associated callback is removed from the unload queue.
+@returns {function}
+ Returns a function which will allow one to remove the callback from the unload
+ queue.
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userscript.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userscript.md
new file mode 100644
index 0000000..1bc8d4e
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userscript.md
@@ -0,0 +1,44 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+The `userscript` module allows modules to create user scripts which automatically
+start running on windows opened after the user script is created.
+
+
+## Example ##
+ var scripts = ["test.user.js"];
+ var self = require("self");
+ var {UserScript} = require("userscript");
+ exports.main = function() {
+ scripts.forEach(function(scriptName, index) {
+ UserScript(self.data.url(scriptName));
+ });
+ };
+
+
+<api name="UserScript">
+@class
+
+The module exports a `UserScript` constructor which allowing one to create a
+user script.
+
+<api name="UserScript">
+@constructor
+Creates a user script.
+
+@param aURL {String}
+ The url of a user script on the local file system, so this url can be a
+ `resource:`, `file:`, or `chrome:` for example.
+</api>
+
+<api name="enabled">
+@property {Boolean}
+Allows one to get and change the status of the a user script. A disabled user
+script will not be injected in to newly opened windows.
+</api>
+
+<api name="destroy">
+@method
+The user script will no longer be injected into new windows, you will have to
+create a new user script in order to run the script again.
+</api>
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userstyles.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userstyles.md
new file mode 100644
index 0000000..7debf98
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userstyles.md
@@ -0,0 +1,26 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+The `userstyles` module allows one to load css/userstyles for content or chrome
+pages.
+
+## Example ##
+
+ // loads a user stylesheet
+ require("userstyles").load(require("self").data.url("style.css"));
+
+<api name="load">
+@function
+ Loads css (aka userstyles) to the browser which will be automatically removed
+ when the add-on unloads.
+
+@param url {string}
+ The url of a css file.
+
+@param options {object}
+ Some options for the stylesheet.
+
+@prop type {String}
+ The type for the stylesheet, there are two types 'agent' and 'user'.
+ The default should be used when possible, which is 'user'.
+
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/xulkeys.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/xulkeys.md
new file mode 100644
index 0000000..4117827
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/xulkeys.md
@@ -0,0 +1,55 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+Some add-ons may wish to define keyboard shortcuts for certain operations. This
+module exposes an API to create
+[xul based hotkeys](https://developer.mozilla.org/en/XUL/key).
+
+## Example ##
+
+ var keyID = "ADDON:EXAMPLE-HOTKEY@ERIKVOLD.COM:CMD-ALT-R";
+ const { XulKey } = require("xulkeys");
+
+ XulKey({
+ id: keyID,
+ modifiers: "accel,alt",
+ key: "R",
+ onCommand: function() {
+ console.log("pressed");
+ }
+ });
+
+<api name="XulKey">
+@class
+
+This module exports a `XulKey` constructor which allows one to create xul based
+hotkeys.
+
+<api name="XulKey">
+@constructor
+Creates a hotkey whose `onCommand` listener method is invoked when the key
+comboination provided is pressed.
+
+@param options {Object}
+ Options that define the hotkey, with the following properties:
+
+@prop [id] {string}
+ A namespaced unique id for the key element.
+@prop key {string}
+ The key to listen for.
+@prop [modifiers] {string}
+ A list of modifier keys that should be pressed to invoke the hotkey.
+ Multiple keys may be separated by spaces or commas.
+
+ "accel"
+ "meta,shift"
+ "control alt"
+
+ See the [MDN documentation on the modifiers
+ attribute](https://developer.mozilla.org/en/XUL/Attribute/modifiers) for a
+ full list of acceptable values.
+
+@prop onCommand {function}
+ A function that is invoked when the hotkey is pressed.
+</api>
+
+</api>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/data/test.user.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/data/test.user.js
new file mode 100644
index 0000000..5911b8e
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/data/test.user.js
@@ -0,0 +1,6 @@
+// ==UserScript==
+// @name test
+// @namespace test
+// @include http://erikvold.com/*
+// @exclude *google*
+// ==/UserScript==
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/lib/main.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/lib/main.js
new file mode 100644
index 0000000..b0a92ef
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/lib/main.js
@@ -0,0 +1,11 @@
+
+var scripts = [ "test.user.js"];
+
+var self = require("self");
+var {UserScript} = require("userscript");
+
+exports.main = function() {
+ scripts.forEach(function(scriptName, index) {
+ var script = UserScript(self.data.url(scriptName));
+ });
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/package.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/package.json
new file mode 100644
index 0000000..9a5b737
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "test",
+ "fullName": "test",
+ "author": "Erik Vold <erikvvold@gmail.com>",
+ "id": "superbgwo@erikvold.com",
+ "version": "0.0.1",
+ "dependencies": ["addon-kit", "api-utils", "userscripts", "vold-utils"]
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/folder.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/folder.js
new file mode 100644
index 0000000..4b590c5
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/folder.js
@@ -0,0 +1,51 @@
+'use strict';
+
+const JETPACK_DIR_BASENAME = "jetpack";
+const PATH_TEST = /^[\s\.\\\/]/;
+
+const { Cc, Ci } = require('chrome');
+const file = require('sdk/io/file');
+const jpSelf = require('sdk/self');
+
+let storeFile = Cc['@mozilla.org/file/directory_service;1']
+ .getService(Ci.nsIProperties)
+ .get('ProfD', Ci.nsIFile);
+storeFile.append(JETPACK_DIR_BASENAME);
+storeFile.append(jpSelf.id);
+storeFile.append('addon-folder');
+
+const ADDON_FOLDER_PATH = storeFile.path + '/';
+
+// make the addon-folder container folder
+file.mkpath(ADDON_FOLDER_PATH);
+
+function ioFileWrap(funcName, preMode) {
+ preMode = preMode || "";
+ return function(filepath, mode) {
+ filepath = filepath || '';
+ if (PATH_TEST.test(filepath)) {
+ throw 'The provided filepath "' + filepath + '"" is not valid';
+ }
+ return file[funcName](ADDON_FOLDER_PATH + filepath, preMode + mode);
+ }
+}
+exports.isFile = ioFileWrap('isFile');
+exports.exists = ioFileWrap('exists');
+
+exports.remove = function(filepath) {
+ if (exports.isFile(filepath)) {
+ file.remove(ADDON_FOLDER_PATH + filepath);
+ }
+ else {
+ file.rmdir(ADDON_FOLDER_PATH + filepath);
+ }
+};
+exports.read = ioFileWrap('read');
+exports.write = ioFileWrap('open', 'w');
+exports.mkpath = ioFileWrap('mkpath');
+exports.list = ioFileWrap('list');
+
+exports.destroy = function destroy() {
+ // remove the addon-folder container folder
+ file.rmdir(ADDON_FOLDER_PATH);
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/unload.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/unload.js
new file mode 100644
index 0000000..78803e7
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/unload.js
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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("sdk/core/heritage");
+const unloadNS = require("sdk/core/namespace").ns();
+const { when: unload } = require("sdk/system/unload");
+
+var Unloader = exports.Unloader = Class({
+ initialize: function Unloader() {
+ unloadNS(this).unloaders = [];
+ unloadNS(this).unloadersUnload = unloadersUnload.bind(null, unloadNS(this).unloaders);
+
+ // run the unloaders on unload
+ unload(unloadNS(this).unloadersUnload);
+ },
+ unload: function unload(callback, container) {
+ // Calling with no arguments runs all the unloader callbacks
+ if (callback == null) {
+ unloadNS(this).unloadersUnload();
+ return null;
+ }
+
+ let windowRemover = windowUnloader.bind(null, unloader, unloadNS(this).unloaders);
+
+ // The callback is bound to the lifetime of the container if we have one
+ if (container != null) {
+ // Remove the unloader when the container unloads
+ container.addEventListener("unload", windowRemover, false);
+
+ // Wrap the callback to additionally remove the unload listener
+ let origCallback = callback;
+ callback = function() {
+ container.removeEventListener("unload", windowRemover, false);
+ origCallback();
+ }
+ }
+
+ // Wrap the callback in a function that ignores failures
+ function unloader() {
+ try {
+ callback();
+ }
+ catch(e) {
+ console.error(e);
+ }
+ }
+ unloadNS(this).unloaders.push(unloader);
+
+ // Provide a way to remove the unloader
+ return removeUnloader.bind(null, unloader, unloadNS(this).unloaders);
+ }
+});
+
+function sliceUnloader(unloader, unloaders) {
+ let index = unloaders.indexOf(unloader);
+ if (index < 0)
+ return [];
+ return unloaders.splice(index, 1);
+}
+// wraps sliceUnloader and doesn't return anything
+function removeUnloader(unloader, unloaders) {
+ sliceUnloader.apply(null, arguments);
+}
+function windowUnloader(unloader, unloaders) {
+ sliceUnloader.apply(null, arguments).forEach(function(u) u());
+}
+function unloadersUnload(unloaders) {
+ // run all the pending unloaders
+ unloaders.slice().forEach(function(u) u());
+ // clear the unload array
+ unloaders.length = 0;
+}
+
+/**
+ * Save callbacks to run when unloading. Optionally scope the callback to a
+ * container, e.g., window. Provide a way to run all the callbacks.
+ *
+ * @usage unload(): Run all callbacks and release them.
+ *
+ * @usage unload(callback): Add a callback to run on unload.
+ * @param [function] callback: 0-parameter function to call on unload.
+ * @return [function]: A 0-parameter function that undoes adding the callback.
+ *
+ * @usage unload(callback, container) Add a scoped callback to run on unload.
+ * @param [function] callback: 0-parameter function to call on unload.
+ * @param [node] container: Remove the callback when this container unloads.
+ * @return [function]: A 0-parameter function that undoes adding the callback.
+ */
+const gUnload = Unloader();
+exports.unload = gUnload.unload.bind(gUnload);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/addon.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/addon.js
new file mode 100644
index 0000000..815f8ed
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/addon.js
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const {Cc, Ci, Cu} = require("chrome");
+const {AddonManager, AddonAuthor} = require("../utils/addonmanager");
+const DO_NOTHING = function(){};
+
+// https://developer.mozilla.org/en/Addons/Add-on_Manager/Addon
+function Addon(options) {
+
+ this.appDisabled = !!options.appDisabled || false;
+ this.blocklistState = (options.blocked) ? 2 : 0;
+ if (options.creator) {
+ this.creator = new AddonAuthor(options.creator.name);
+ }
+ this.id = options.id;
+ if (typeof options.isActive != "undefined") this.isActive = !!options.isActive;
+ if (typeof options.isCompatible != "undefined") this.isCompatible = !!options.isCompatible;
+ if (typeof options.isPlatformCompatible != "undefined") this.isPlatformCompatible = !!options.isPlatformCompatible;
+ this.name = options.name || "";
+ //this.pendingOperations =
+ this.description = options.description || "";
+ if (options.iconURL) this.iconURL = options.iconURL;
+
+ // METHODS
+ this.uninstall = function() {
+ options.uninstall && options.uninstall();
+ };
+ this.cancelUninstall = function() {
+ options.cancelUninstall && options.cancelUninstall();
+ };
+
+ if (options.getResourceURI) {
+ this.getResourceURI = function(aPath) {
+ return options.getResourceURI(aPath);
+ };
+ this.getXPI = function() {
+ return options.getResourceURI("").QueryInterface(Ci.nsIFileURL).file;
+ }
+ }
+
+ return this;
+};
+
+Addon.prototype = {
+ // req'd
+ appDisabled: false,
+ blocklistState: 0,
+ creator: null,
+ id: null,
+ isActive: true,
+ isCompatible: true,
+ isPlatformCompatible: true,
+ name: null,
+ pendingOperations: AddonManager.PENDING_NONE,
+ permissions: AddonManager.PERM_CAN_UNINSTALL,
+ providesUpdatesSecurely: false,
+ scope: AddonManager.SCOPE_PROFILE,
+ type: null,
+ userDisabled: false,
+ version: null,
+
+ //not reqd
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
+ contributors: [],
+ description: "",
+ translators: [],
+ sourceURI: null,
+
+
+ // METHODS
+ uninstall: DO_NOTHING,
+ findUpdates: DO_NOTHING,
+ cancelUninstall: DO_NOTHING,
+ hasResource: DO_NOTHING
+};
+
+exports.Addon = Addon;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/manager.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/manager.js
new file mode 100644
index 0000000..cc9388e
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/manager.js
@@ -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/. */
+'use strict';
+
+const {AddonManager, AddonManagerPrivate} = require("../utils/addonmanager");
+const Addon = require("addon").Addon;
+
+exports.getAddonByID = exports.getAddonById = function(aID, aCallback) {
+ // get the addon obj
+ AddonManager.getAddonByID(aID, function (addon) {
+ // return a wrapped addon
+ aCallback(new Addon(addon));
+ });
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/provider.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/provider.js
new file mode 100644
index 0000000..681dcd9
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/provider.js
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 unload = require("sdk/system/unload").when;
+
+const {AddonManager, AddonManagerPrivate, AddonType} = require("../utils/addonmanager");
+
+var defaultUIPriority = 6001; // this increases when it is used
+
+exports.AddonProvider = function(options) {
+ var types = null;
+
+ // AddonManagerPrivate.AddonType DNE in Gecko (FF) < 6
+ if (AddonType) {
+ types = [new AddonType(
+ options.type, // TODO: RANDOMIZE?
+ null,
+ options.localeKey,
+ AddonManager.VIEW_TYPE_LIST,
+ options.uiPriority || defaultUIPriority++)];
+ }
+
+ var provider = {
+ getAddonByID: function(aId, aCallback) {
+ aCallback(options.getAddonByID(aId));
+ },
+
+ getAddonsByTypes: function(aTypes, aCallback) {
+ if (aTypes && aTypes.indexOf(options.type) < 0) {
+ // not the right type, return nothing
+ aCallback([]);
+ }
+ else {
+ // the right type, return all addons
+ aCallback(options.getAddons());
+ }
+ },
+
+ getInstallsByTypes: function(aTypes, aCallback) {
+ aCallback([]);
+ }
+ };
+ AddonManagerPrivate.registerProvider(provider, types);
+
+ unload(function() {
+ AddonManagerPrivate.unregisterProvider(provider);
+ });
+
+ return this;
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/application/restart.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/application/restart.js
new file mode 100644
index 0000000..7d97f37
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/application/restart.js
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Cc, Ci } = require("chrome");
+
+exports.restart = function restart() {
+ let canceled = Cc["@mozilla.org/supports-PRBool;1"]
+ .createInstance(Ci.nsISupportsPRBool);
+
+ Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService)
+ .notifyObservers(canceled, "quit-application-requested", "restart");
+
+ if (canceled.data) return false; // somebody canceled our quit request
+
+ // restart
+ Cc['@mozilla.org/toolkit/app-startup;1'].getService(Ci.nsIAppStartup)
+ .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
+
+ return true;
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/instances.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/instances.js
new file mode 100644
index 0000000..da9edb8
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/instances.js
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Cc, Ci, Cu } = require("chrome");
+
+var Instances = exports.Instances = {
+ get bis() Cc["@mozilla.org/binaryinputstream;1"]
+ .createInstance(Ci.nsIBinaryInputStream),
+ get ch() Cc["@mozilla.org/security/hash;1"]
+ .createInstance(Ci.nsICryptoHash),
+ get dp() Cc["@mozilla.org/xmlextras/domparser;1"]
+ .createInstance(Ci.nsIDOMParser),
+ get ds() Cc["@mozilla.org/xmlextras/xmlserializer;1"]
+ .createInstance(Ci.nsIDOMSerializer),
+ get fos() Cc["@mozilla.org/network/file-output-stream;1"]
+ .createInstance(Ci.nsIFileOutputStream),
+ get sfos() Cc["@mozilla.org/network/safe-file-output-stream;1"]
+ .createInstance(Ci.nsIFileOutputStream)
+ .QueryInterface(Ci.nsISafeOutputStream),
+ get fp() Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker),
+ get lf() Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile),
+ get process() Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess),
+ get se() Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError)
+ .QueryInterface(Ci.nsIScriptError2),
+ get ss() Cc["@mozilla.org/supports-string;1"]
+ .createInstance(Ci.nsISupportsString),
+ get suc() Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Ci.nsIScriptableUnicodeConverter),
+ get timer() Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
+ get wbp() Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+ .createInstance(Ci.nsIWebBrowserPersist),
+ get xhr() Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+ .createInstance(Ci.nsIXMLHttpRequest)
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/net-utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/net-utils.js
new file mode 100644
index 0000000..a657d20
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/net-utils.js
@@ -0,0 +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/. */
+'use strict';
+
+require("chrome").Cu.import("resource://gre/modules/NetUtil.jsm", this);
+exports.NetUtil = NetUtil;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/services.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/services.js
new file mode 100644
index 0000000..9df8b59
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/services.js
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Cc, Ci, Cu } = require("chrome");
+Cu.import("resource://gre/modules/Services.jsm", this);
+
+const global = this;
+var Services = exports.Services = {};
+(function(inc, tools){
+ inc("resource://gre/modules/XPCOMUtils.jsm", global);
+ inc("resource://gre/modules/Services.jsm", tools);
+ Services.__proto__ = tools.Services;
+})(Cu.import, {});
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "as", "@mozilla.org/alerts-service;1", "nsIAlertsService");
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "ass", "@mozilla.org/appshell/appShellService;1",
+ "nsIAppShellService");
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "cb", "@mozilla.org/widget/clipboardhelper;1",
+ "nsIClipboardHelper");
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "cs", "@mozilla.org/consoleservice;1", "nsIConsoleService");
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "eps", "@mozilla.org/uriloader/external-protocol-service;1",
+ "nsIExternalProtocolService");
+
+if (Cc["@mozilla.org/privatebrowsing;1"]) {
+ XPCOMUtils.defineLazyServiceGetter(
+ Services, "pbs", "@mozilla.org/privatebrowsing;1",
+ "nsIPrivateBrowsingService");
+} else {
+ Services.pbs = {privateBrowsingEnabled: false};
+}
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "sis", "@mozilla.org/scriptableinputstream;1",
+ "nsIScriptableInputStream");
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "suhtml", "@mozilla.org/feed-unescapehtml;1",
+ "nsIScriptableUnescapeHTML");
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "tld", "@mozilla.org/network/effective-tld-service;1",
+ "nsIEffectiveTLDService");
+
+XPCOMUtils.defineLazyServiceGetter(
+ Services, "uuid", "@mozilla.org/uuid-generator;1",
+ "nsIUUIDGenerator");
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/xpcom-utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/xpcom-utils.js
new file mode 100644
index 0000000..f453b34
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/xpcom-utils.js
@@ -0,0 +1,3 @@
+
+require("chrome").Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
+exports.XPCOMUtils = XPCOMUtils;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/events.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/events.js
new file mode 100644
index 0000000..7d9071b
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/events.js
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 events = require('sdk/system/events');
+const { on, once, off, emit } = require('sdk/event/core');
+
+function onRequest(evt) {
+ emit(exports, 'modify-request', evt);
+}
+events.on('http-on-modify-request', onRequest);
+
+/*
+function onResponse(evt) {
+ emit(exports, 'examine-response', evt);
+}
+events.on('http-on-examine-response', onResponse);
+*/
+
+exports.on = on.bind(null, exports);
+exports.once = once.bind(null, exports);
+exports.off = off.bind(null, exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/request.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/request.js
new file mode 100644
index 0000000..bf93ca0
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/request.js
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Ci } = require('chrome');
+const { List, addListItem, removeListItem } = require('sdk/util/list');
+const { ns } = require('sdk/core/namespace');
+const { Class } = require('sdk/core/heritage');
+const { Disposable } = require('sdk/core/disposable');
+
+const events = require('./events');
+
+const REQUEST_RULES = List();
+const requestNS = ns();
+
+function onRequest(evt) {
+ for each (let rule in REQUEST_RULES) {
+ applyRequestHeaders(rule, evt)
+ }
+}
+events.on('modify-request', onRequest);
+
+const RequestRule = Class({
+ implements: [ Disposable ],
+ initialize: function(details) {
+ requestNS(this).details = details;
+ addListItem(REQUEST_RULES, this);
+ },
+ dispose: function() {
+ removeListItem(REQUEST_RULES, this);
+ }
+});
+exports.RequestRule = RequestRule;
+
+function applyRequestHeaders(rule, evt) {
+ let channel = evt.subject.QueryInterface(Ci.nsIHttpChannel);
+ let requestURL = channel.URI.spec
+
+ let details = requestNS(rule).details;
+ let { headers: rules } = details;
+ for each (let key in Object.keys(rules)) {
+ channel.setRequestHeader(key, rules[key] + '', false);
+ }
+} \ No newline at end of file
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/response.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/response.js
new file mode 100644
index 0000000..c0ed791
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/response.js
@@ -0,0 +1,44 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Ci } = require('chrome');
+const { List, addListItem, removeListItem } = require('sdk/util/list');
+const { ns } = require('sdk/core/namespace');
+const { Class } = require('sdk/core/heritage');
+
+const events = require('./events');
+
+const RESPONSE_RULES = List();
+
+const requestNS = ns();
+
+function onResponse(evt) {
+ for each (let rule in RESPONSE_RULES) {
+ applyResponseHeaders(rule, evt)
+ }
+}
+events.on('examine-response', onResponse);
+
+const ResponseRule = Class({
+ initialize: function(details) {
+ requestNS(this).details = details;
+ addListItem(RESPONSE_RULES, this);
+ },
+ destroy: function() {
+ removeListItem(RESPONSE_RULES, this);
+ }
+});
+exports.ResponseRule = ResponseRule;
+
+function applyResponseHeaders(rule, evt) {
+ let channel = evt.subject.QueryInterface(Ci.nsIHttpChannel);
+ let requestURL = channel.URI.spec
+
+ let details = requestNS(rule).details;
+ let { headers: rules } = details;
+ for each (let key in Object.keys(rules)) {
+ channel.setResponseHeader(key, rules[key], false);
+ }
+} \ No newline at end of file
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connections.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connections.js
new file mode 100644
index 0000000..b81eba1
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connections.js
@@ -0,0 +1,8 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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.RequestRule = require('./connection/request').RequestRule;
+//exports.ResponseRule = require('./connection/response').ResponseRule;
+
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/permissions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/permissions.js
new file mode 100644
index 0000000..49cc955
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/permissions.js
@@ -0,0 +1,88 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Cc, Ci, Cu } = require('chrome');
+const { List, addListItem } = require('sdk/util/list');
+const { URL } = require('sdk/url');
+
+const { Services } = require('../chrome/services');
+
+const { nsIPermissionManager } = Ci;
+
+const UNKNOWN = nsIPermissionManager.UNKNOWN_ACTION; // 0
+const ALLOW = nsIPermissionManager.ALLOW_ACTION; // 1
+const BLOCK = nsIPermissionManager.DENY_ACTION; // 2
+const SESSION = Ci.nsICookiePermission.ACCESS_SESSION; // 8
+
+function getKey(obj, val) {
+ for (let key in obj)
+ if (obj[key] == val)
+ return key;
+
+ return undefined;
+}
+
+const PERMISSIONS = {
+ 'session': SESSION,
+ 'allow': ALLOW,
+ 'deny': BLOCK
+};
+
+const TYPES = {
+ 'images': 'image',
+ 'popups': 'popup',
+ 'desktop-notifications': 'desktop-notification',
+ 'installs': 'install',
+ 'location': 'geo',
+ 'fullscreen': 'fullscreen',
+ 'pointer-lock': 'pointerLock'
+}
+
+const PM = Cc['@mozilla.org/permissionmanager;1'].
+ getService(nsIPermissionManager);
+
+function add(options) {
+ let uri = Services.io.newURI(options.url, null, null);
+ if (!/^https?/.test(uri.scheme)) {
+ throw new Error('invalid content url, only https or http schemes are accepted');
+ }
+
+ PM.add(uri,
+ TYPES[options.type],
+ PERMISSIONS[options.permission]);
+}
+
+function remove(options) {
+ PM.remove(URL(options.url).host, TYPES[options.type]);
+}
+
+function removeAll() {
+ PM.removeAll();
+}
+
+// TODO: cache entries after first request, and observe new additions with the "perm-changed" event
+
+exports.permissions = {
+ add: add,
+ remove: remove,
+ removeAll: removeAll,
+ get permissions() {
+ let list = List();
+ let permissions = PM.enumerator;
+ while (permissions.hasMoreElements()) {
+ let permission = permissions.getNext().QueryInterface(Ci.nsIPermission);
+
+ addListItem(list, {
+ type: getKey(TYPES, permission.type),
+ host: String(permission.host),
+ permission: getKey(PERMISSIONS, Number(permission.capability))
+ //'expire-time': Number(permission.expireTime),
+ });
+ }
+ return list;
+ },
+ TYPES: TYPES,
+ PERMISSIONS: PERMISSIONS
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/policy.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/policy.js
new file mode 100644
index 0000000..b764272
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/policy.js
@@ -0,0 +1,143 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Cc, Ci } = require('chrome');
+const { Class } = require('sdk/core/heritage');
+const CP_NS = require('sdk/core/namespace').ns();
+const { ensure } = require('sdk/system/unload');
+const { validateOptions } = require('sdk/deprecated/api-utils');
+const { id: ADDON_ID } = require('sdk/self');
+const xpcom = require('sdk/platform/xpcom');
+
+const CM = Cc["@mozilla.org/categorymanager;1"]
+ .getService(Ci.nsICategoryManager);
+
+const ACCEPT = exports.ACCEPT = Ci.nsIContentPolicy.ACCEPT;
+const REJECT = exports.REJECT = Ci.nsIContentPolicy.REJECT_REQUEST;
+
+const accept = function() ACCEPT;
+
+let ContentPolicy_ID = 0;
+
+const RULES = {
+ description: {
+ map: function(v) {
+ return v ? v : '';
+ },
+ is: ['string']
+ },
+ contract: {
+ map: function(v) {
+ if (v === undefined) {
+ v = '@erikvold.com/content-policy.' + ADDON_ID + ';' + ContentPolicy_ID++;
+ }
+ return v;
+ },
+ is: ['string']
+ },
+ entry: {
+ is: ['string', 'undefined']
+ },
+ shouldLoad: {
+ is: ['function', 'undefined']
+ },
+ shouldProcess: {
+ is: ['function', 'undefined']
+ },
+};
+
+function getType(aType) {
+ switch (aType) {
+ case Ci.nsIContentPolicy.TYPE_SCRIPT:
+ return 'script';
+ case Ci.nsIContentPolicy.TYPE_IMAGE:
+ return 'image';
+ case Ci.nsIContentPolicy.TYPE_STYLESHEET:
+ return 'stylesheet';
+ case Ci.nsIContentPolicy.TYPE_OBJECT:
+ return 'object';
+ case Ci.nsIContentPolicy.TYPE_DOCUMENT:
+ return 'document';
+ case Ci.nsIContentPolicy.TYPE_SUBDOCUMENT:
+ return 'subdocument';
+ case Ci.nsIContentPolicy.TYPE_REFRESH:
+ return 'refresh';
+ case Ci.nsIContentPolicy.TYPE_XBL:
+ return 'xbl';
+ case Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST:
+ return 'xhr';
+ case Ci.nsIContentPolicy.TYPE_PING:
+ return 'ping';
+ // TODO: support more types
+ }
+ return 'other';
+}
+const getTypeMemod = memoize(getType, 12, 1);
+
+function makeDetails(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess) {
+ return {
+ type: getTypeMemod(aContentType),
+ location: aContentLocation.spec,
+ origin: aRequestOrigin.spec,
+ context: null, // TODO: support this in a safe way somehow..
+ mimeTypeGuess: String(aMimeTypeGuess)
+ };
+}
+
+let ContentPolicy = exports.ContentPolicy = Class({
+ initialize: function(options) {
+ const self = this;
+ options = CP_NS(self).options = validateOptions(options, RULES);
+ CP_NS(self).shouldLoad = options.shouldLoad || accept;
+ CP_NS(self).shouldProcess = options.shouldProcess || accept;
+
+ let factory = CP_NS(this).factory = xpcom.Factory({
+ Component: getProvider(self),
+ description: options.description,
+ contract: options.contract
+ });
+
+ let entry = options.entry || options.contract;
+ CM.addCategoryEntry('content-policy', entry, factory.contract, false, true);
+ ensure(this, 'destroy');
+ },
+ destroy: function() {
+ // already destroyed?
+ if (!CP_NS(this).options)
+ return;
+
+ let options = CP_NS(this).options;
+ CP_NS(this).options = null;
+ CP_NS(this).shouldLoad = accept;
+ CP_NS(this).shouldProcess = accept;
+
+ CM.deleteCategoryEntry('content-policy', options.entry || options.contract, false);
+ }
+});
+
+function getProvider(self) {
+ return Class({
+ extends: xpcom.Unknown,
+ interfaces: ['nsIContentPolicy'],
+ shouldLoad: function (aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aExtra) {
+ let load = CP_NS(self).shouldLoad(makeDetails.apply(null, arguments));
+ return (load == REJECT || (!load && load !== undefined)) ? REJECT : ACCEPT;
+ },
+ shouldProcess: function (aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aExtra) {
+ let load = CP_NS(self).shouldProcess(makeDetails.apply(null, arguments));
+ return (load == REJECT || (!load && load !== undefined)) ? REJECT : ACCEPT;
+ }
+ });
+}
+
+function memoize(func) {
+ let cache = Object.create(null);
+ return function(a) {
+ let key = a.toString();
+ if (key in cache)
+ return cache[key];
+ return cache[key] = func.call(null, a);
+ };
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/devtools/gcli.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/devtools/gcli.js
new file mode 100644
index 0000000..e1bb17f
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/devtools/gcli.js
@@ -0,0 +1,23 @@
+'use strict';
+
+const { Cu } = require('chrome');
+const { when: unload } = require('unload');
+
+try {
+ // Starting with FF 23, gcli.jsm moved to another location
+ Cu.import("resource://gre/modules/devtools/gcli.jsm");
+} catch(e) {
+ try {
+ Cu.import("resource:///modules/devtools/gcli.jsm");
+ } catch(e) {
+ console.error("Unable to load gcli.jsm");
+ }
+}
+
+function addCommand(cmd) {
+ let name = cmd.name;
+ gcli.addCommand(cmd);
+ unload(gcli.removeCommand.bind(gcli, name));
+}
+exports.addCommand = addCommand;
+exports.removeCommand = gcli.removeCommand;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/download.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/download.js
new file mode 100644
index 0000000..20fef54
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/download.js
@@ -0,0 +1,95 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Ci, Cc, Cu } = require('chrome');
+const { Class } = require('sdk/core/heritage');
+const { on, off, emit, setListeners } = require('sdk/event/core');
+const { EventTarget } = require("sdk/event/target");
+const { ns } = require("sdk/core/namespace");
+const { validateOptions } = require("sdk/deprecated/api-utils");
+const { isValidURI } = require("sdk/url");
+
+const PROGRESS_LISTENER_NS = ns();
+
+const { Services } = Cu.import('resource://gre/modules/Services.jsm', {});
+
+const rules = {
+ url: {
+ // Also converts a URL instance to string, bug 857902
+ map: function (url) url.toString(),
+ ok: isValidURI
+ },
+ destination: {
+ is: ['string']
+ }
+};
+
+const Download = Class({
+ extends: EventTarget,
+ initialize: function(options) {
+ // Setup listeners.
+ setListeners(this, options);
+
+ options = validateOptions(options, rules);
+
+ const wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+ .createInstance(Ci.nsIWebBrowserPersist);
+ let listener = ProgressListener({
+ download: this
+ });
+
+ wbp.progressListener = listener;
+
+ let localFile = Cc["@mozilla.org/file/local;1"]
+ .createInstance(Ci.nsILocalFile);
+ localFile.initWithPath(options.destination);
+ localFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
+ localFile = localFile.QueryInterface(Ci.nsIFile);
+
+ let uri = Services.io.newURI(options.url, null, null);
+ wbp.saveURI(uri, null, null, null, null, localFile, null);
+ }
+});
+exports.Download = Download;
+
+const ProgressListener = Class({
+ initialize: function(options) {
+ const internals = PROGRESS_LISTENER_NS(this);
+ internals.options = options;
+ this.onStateChange = this.onStateChange.bind(this);
+ },
+ get options() PROGRESS_LISTENER_NS(this).options,
+ get download() this.options.download,
+ onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
+ },
+ onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
+ emit(this.download, 'progress', {
+ current: aCurTotalProgress,
+ total: aMaxTotalProgress
+ })
+ },
+ onSecurityChange: function(aWebProgress, aRequest, aState) {
+ },
+ onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+ if (!(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP))
+ return;
+
+ try {
+ var { responseStatus, requestSucceeded } = aRequest.QueryInterface(Ci.nsIHttpChannel);
+ }
+ catch (e) {
+ //console.exception(e);
+ }
+
+ emit(this.download, 'complete', {
+ responseStatus: responseStatus,
+ requestSucceeded: requestSucceeded
+ });
+
+ return;
+ },
+ onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {
+ }
+});
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/l10n.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/l10n.js
new file mode 100644
index 0000000..22ed58c
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/l10n.js
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 global = this;
+const {Cc,Ci,Cu} = require("chrome");
+Cu.import("resource://gre/modules/Services.jsm", global);
+
+exports.locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIXULChromeRegistry).getSelectedLocale("global");
+
+exports.l10n = (function(global) {
+ let splitter = /(\w+)-\w+/;
+
+ // get user's locale
+ let locale = exports.locale;
+
+ function getStr(aStrBundle, aKey) {
+ if (!aStrBundle) return false;
+ try {
+ return aStrBundle.GetStringFromName(aKey);
+ } catch (e) {
+ //console.log(e);
+ }
+ return "";
+ }
+
+ function l10n(options) {
+ var filename = options.filename;
+ var baseURL = options.baseURL;
+ var defaultLocale = options.defaultLocale || "en";
+ function filepath(locale) {
+ var path = baseURL + "/" + locale + "/" + filename;
+ //console.log(path);
+ return path;
+ }
+
+ let defaultBundle = Services.strings.createBundle(filepath(locale));
+
+ let defaultBasicBundle;
+ let (locale_base = locale.match(splitter)) {
+ if (locale_base) {
+ defaultBasicBundle = Services.strings.createBundle(
+ filepath(locale_base[1]));
+ }
+ }
+
+ let addonsDefaultBundle =
+ Services.strings.createBundle(filepath(defaultLocale));
+
+ return _ = function l10n_underscore(aKey, aLocale) {
+ let localeBundle, localeBasicBundle;
+ if (aLocale) {
+ localeBundle = Services.strings.createBundle(filepath(aLocale));
+
+ let locale_base = aLocale.match(splitter)
+ if (locale_base)
+ localeBasicBundle = Services.strings.createBundle(
+ filepath(locale_base[1]));
+ }
+
+ var x = getStr(localeBundle, aKey)
+ || getStr(localeBasicBundle, aKey)
+ || getStr(defaultBundle, aKey)
+ || getStr(defaultBasicBundle, aKey)
+ || getStr(addonsDefaultBundle, aKey);
+ return x;
+ }
+ }
+
+ return l10n;
+})(this);
+
+require("unload").when(Services.strings.flushBundles);
+
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/panic.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/panic.js
new file mode 100644
index 0000000..a478077
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/panic.js
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { setTimeout } = require('sdk/timers');
+const { get, set } = require('sdk/preferences/service');
+const { add, notify } = require('sdk/deprecated/observer-service');
+const { on, once, emit, off } = require('sdk/event/core');
+const { loadReason } = require('sdk/self');
+
+const { unload } = require('./addon/unload');
+
+const PREF_NAME = 'security.addon.panic';
+function inPanic() get(PREF_NAME, false);
+function setPanic(value) set(PREF_NAME, value);
+
+const PREF_END_NAME = 'security.addon.panic_end';
+function getEndTime() get(PREF_END_NAME, 0) * 1;
+function setEndTime(timestamp) set(PREF_END_NAME, timestamp + "");
+
+Object.defineProperty(exports, "inPanic", {
+ get: function() inPanic()
+});
+
+const panic = function (ms) {
+ ms = ms || 0;
+ let endTime = Date.now() + ms;
+
+ // check that the current end timestamp is not greater
+ if (getEndTime() >= endTime)
+ return;
+
+ // set the end timestamp (to handle the reboot situation)
+ setEndTime(endTime);
+
+ // notify system of a panic
+ notify('panic-start');
+
+ // end the panic
+ setTimeout(function() {
+ // check that the end timestamp was not extended by another panic
+ // NOTE: another instance of panic module could have caused the old panic
+ if (getEndTime() != endTime) return;
+
+ notify('panic-end');
+ }, ms);
+};
+exports.panic = panic;
+
+// internal object used to emit on, instead of `exports`, so that outside code
+// cannot emit on this object.
+const panicEmitter = {};
+
+// create and expose event listener related methods for this module
+exports.on = on.bind(null, panicEmitter);
+exports.once = once.bind(null, panicEmitter);
+exports.off = off.bind(null, panicEmitter);
+
+// listen to 'panic-start' events in the observer-service since they may come
+// from other instances of this module
+add('panic-start', function () {
+ setPanic(true);
+ emit(panicEmitter, 'start');
+});
+// listen to 'panic-end' events for the same reason as for 'panic-start'
+add('panic-end', function () {
+ setPanic(false);
+ emit(panicEmitter, 'end');
+});
+
+// cleanup prefs on startup, since the add-on could be installed before or
+// during startup
+if (loadReason == 'startup') {
+ // check the end timestamp (for the reboot situation)
+ if (getEndTime() <= Date.now()) {
+ setEndTime(0);
+
+ if (inPanic()) {
+ setPanic(false);
+ }
+ }
+}
+
+// clean up prefs on shutdown, don't do cleanup on other reasons because there
+// may be other instances of the module running
+unload(function(reason) {
+ if (reason == 'shutdown') {
+ setPanic(false);
+ setEndTime(0);
+ }
+});
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/redirect.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/redirect.js
new file mode 100644
index 0000000..ffd46db
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/redirect.js
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Ci } = require('chrome');
+const { List, addListItem, removeListItem } = require('sdk/util/list');
+const { ns } = require('sdk/core/namespace');
+const { Class } = require('sdk/core/heritage');
+const { Disposable } = require('sdk/core/disposable');
+const { newURI } = require('sdk/url/utils');
+
+const events = require('./connection/events');
+
+const REDIRECTS = List();
+const requestNS = ns();
+
+function onRequest({ subject }) {
+ let channel = subject.QueryInterface(Ci.nsIHttpChannel);
+ for each (let redirect in REDIRECTS)
+ if (applyRedirect(redirect, channel))
+ break;
+ return;
+}
+events.on('modify-request', onRequest);
+
+const Redirect = Class({
+ implements: [ Disposable ],
+ initialize: function(details) {
+ details.to = newURI(details.to.toString());
+ requestNS(this).details = details;
+
+ addListItem(REDIRECTS, this);
+ },
+ dispose: function() {
+ removeListItem(REDIRECTS, this);
+ },
+ get from() requestNS(this).details.from,
+ get to() requestNS(this).details.to.spec
+});
+exports.Redirect = Redirect;
+
+function applyRedirect(redirect, channel) {
+ let { from, to } = requestNS(redirect).details;
+
+ if (channel.URI.spec == from) {
+ channel.redirectTo(to);
+ // emit(rule, 'redirect', {});
+ return true;
+ }
+ return false;
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/about.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/about.js
new file mode 100644
index 0000000..7d94b78
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/about.js
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { Cr, Cu, Ci, Cc, Cm } = require('chrome');
+const { when: unload } = require('sdk/system/unload');
+const { validateOptions : validate } = require('sdk/deprecated/api-utils');
+const { uuid } = require('sdk/util/uuid');
+const { URL, isValidURI } = require('sdk/url');
+const tabs = require('sdk/tabs');
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const validOptions = {
+ what: {
+ is: ['string'],
+ ok: function(what) {
+ if (what.match(/^[a-z0-9-]+$/i))
+ return true;
+ return false;
+ },
+ map: function(url) url.toLowerCase()
+ },
+ url: {
+ map: function(url) url.toString(),
+ ok: isValidURI
+ },
+ useChrome: {
+ is: ['undefined', 'null', 'boolean'],
+ map: function(use) !!use
+ }
+};
+
+function add(options) {
+ let { what, url, useChrome } = validate(options, validOptions);
+ let classID = uuid();
+
+ let aboutModule = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+ newChannel: function (aURI) {
+ let chan = Services.io.newChannel(url, null, null);
+ if (useChrome)
+ chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
+ return chan;
+ },
+ getURIFlags: function () Ci.nsIAboutModule.ALLOW_SCRIPT
+ };
+
+ let factory = {
+ createInstance: function(aOuter, aIID) {
+ if (aOuter)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return aboutModule.QueryInterface(aIID);
+ },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
+ };
+
+ // register about:what
+ Cm.QueryInterface(Ci.nsIComponentRegistrar).
+ registerFactory(classID, '', '@mozilla.org/network/protocol/about;1?what='+what, factory);
+
+ let remover = unloader.bind(null, what, factory, classID);
+ unload(remover);
+
+ return undefined;
+}
+exports.add = add;
+
+function unloader(what, factory, classID) {
+ // unregister about:what
+ Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(classID, factory);
+ let regEx = new RegExp('^' + what, 'i');
+
+ // AMO policy, see http://maglione-k.users.sourceforge.net/bootstrapped.xhtml
+ // close about:what tabs
+ for each (let tab in tabs) {
+ let url = URL(tab.url);
+ if (url.scheme === 'about' && url.path.match(regEx)) {
+ tab.close();
+ }
+ }
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/resource.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/resource.js
new file mode 100644
index 0000000..81a4061
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/resource.js
@@ -0,0 +1,43 @@
+/*jshint asi:true globalstrict:true*/
+'use strict';
+
+const { Cc, Ci } = require('chrome')
+const ioService = Cc['@mozilla.org/network/io-service;1'].
+ getService(Ci.nsIIOService);
+const resourceHandler = ioService.getProtocolHandler('resource').
+ QueryInterface(Ci.nsIResProtocolHandler)
+
+function get(root) {
+ /**
+ Gets the substitution for the `root` key.
+ **/
+ try {
+ return resourceHandler.getSubstitution(root).spec;
+ }
+ catch (error) {}
+ return null;
+}
+exports.get = get;
+
+function has(root) {
+ /**
+ Returns `true` if the substitution exists and `false` otherwise.
+ **/
+ return resourceHandler.hasSubstitution(root);
+}
+exports.has = has;
+
+function set(root, uri) {
+ /**
+ Sets the substitution for the root key:
+
+ resource://root/path ==> baseURI.resolve(path)
+
+ A `null` `uri` removes substitution. A root key should
+ always be lowercase. However, this may not be enforced.
+ **/
+ uri = !uri ? null :
+ uri instanceof Ci.nsIURI ? uri : ioService.newURI(uri, null, null);
+ resourceHandler.setSubstitution(root, uri);
+}
+exports.set = set;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/GM_xmlhttpRequester.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/GM_xmlhttpRequester.js
new file mode 100644
index 0000000..8ca3f5b
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/GM_xmlhttpRequester.js
@@ -0,0 +1,238 @@
+'use strict';
+
+function Scriptish_stringBundle(a) a;
+
+const {Cc, Ci, Cu, Cr} = require("chrome");
+var {Instances} = require("../chrome/instances");
+var {XPCOMUtils} = require("../chrome/xpcom-utils");
+var {NetUtil} = require("../chrome/net-utils");
+
+const MIME_JSON = /^(application|text)\/(?:x-)?json/i;
+
+/**
+ * Abstract base class for (chained) request notification callback overrides
+ *
+ * Use such overrides sparely, as the individual request performance might
+ * degrade quite a bit.
+ *
+ * @param req XMLHttpRequest (chrome)
+ * @author Nils Maier
+ */
+function NotificationCallbacks(req) {
+ throw new Error("trying to initiate an abstract NotificationCallbacks");
+}
+NotificationCallbacks.prototype = {
+ init: function(req) {
+ // rewrite notification callbacks
+ this._channel = req.channel;
+ this._notificationCallbacks = this._channel.notificationCallbacks;
+ this._channel.notificationCallbacks = this;
+ },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]),
+ getInterface: function(iid) {
+ try {
+ return this.query(iid);
+ }
+ catch (ex) {
+ return this.queryOriginal(iid);
+ }
+ },
+ queryOriginal: function(iid) {
+ if (this._notificationCallbacks) {
+ return this._notificationCallbacks.getInterface(iid);
+ }
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+}
+
+/**
+ * Ignore (specific) redirects
+ * @param req XMLHttpRequest (chrome)
+ * @author Nils Maier
+ */
+function IgnoreRedirect(req, ignoreFlags) {
+ this.init(req);
+ this.ignoreFlags = ignoreFlags;
+}
+IgnoreRedirect.prototype = {
+ __proto__: NotificationCallbacks.prototype,
+ query: XPCOMUtils.generateQI([Ci.nsIChannelEventSink]),
+ asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
+ if (this.ignoreFlags & flags) {
+ // must throw here, not call callback.onRedirectVerifyCallback,
+ // or else it will completely cancel the request
+ throw Cr.NS_ERROR_UNEXPECTED;
+ }
+
+ try {
+ let ces = this.queryOriginal(Ci.nsIChannelEventSink);
+ if (ces) {
+ ces.asyncOnChannelRedirect(oldChannel, newChannel, flags, callback);
+ return;
+ }
+ }
+ catch (ex) {}
+
+ callback.onRedirectVerifyCallback(Cr.NS_OK);
+ }
+};
+
+
+function GM_xmlhttpRequester(unsafeContentWin, originUrl, aScript) {
+ this.unsafeContentWin = unsafeContentWin;
+ this.originUrl = originUrl;
+ this.script = aScript;
+}
+exports.GM_xmlhttpRequester = GM_xmlhttpRequester;
+
+// this function gets called by user scripts in content security scope to
+// start a cross-domain xmlhttp request.
+//
+// details should look like:
+// {method,url,onload,onerror,onreadystatechange,headers,data}
+// headers should be in the form {name:value,name:value,etc}
+// can't support mimetype because i think it's only used for forcing
+// text/xml and we can't support that
+GM_xmlhttpRequester.prototype.contentStartRequest = function(details) {
+ try {
+ // Validate and parse the (possibly relative) given URL.
+ var uri = NetUtil.newURI(details.url, null, NetUtil.newURI(this.originUrl));
+ var url = uri.spec;
+ } catch (e) {
+ // A malformed URL won't be parsed properly.
+ //throw new Error(Scriptish_stringBundle("error.api.reqURL") + ": " + details.url);
+ console.error(e);
+ }
+
+ // check if the script is allowed to access the url
+ if (!this.script.matchesDomain(url))
+ throw new Error(
+ "User script is attempting access to restricted domain '" + uri.host + "'",
+ this.script.fileURL);
+
+ // This is important - without it, GM_xmlhttpRequest can be used to get
+ // access to things like files and chrome. Careful.
+ switch (uri.scheme) {
+ case "http":
+ case "https":
+ case "ftp":
+ var req = Instances.xhr;
+ this.chromeStartRequest(url, details, req);
+ break;
+ default:
+ throw new Error(Scriptish_stringBundle("error.api.reqURL.scheme") + ": " + details.url);
+ }
+
+ return {
+ abort: function() {
+ req.abort();
+ }
+ };
+};
+
+// this function is intended to be called in chrome's security context, so
+// that it can access other domains without security warning
+GM_xmlhttpRequester.prototype.chromeStartRequest =
+ function(safeUrl, details, req) {
+ this.setupRequestEvent(this.unsafeContentWin, req, "onload", details);
+ this.setupRequestEvent(this.unsafeContentWin, req, "onerror", details);
+ this.setupRequestEvent(
+ this.unsafeContentWin, req, "onreadystatechange", details);
+
+ if (details.mozBackgroundRequest) req.mozBackgroundRequest = true;
+
+ req.open(
+ details.method || "GET",
+ safeUrl,
+ true,
+ details.user || "",
+ details.password || ""
+ );
+
+ if (details.overrideMimeType) req.overrideMimeType(details.overrideMimeType);
+
+ if (details.ignoreCache)
+ req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; // bypass cache
+
+ if (details.ignoreRedirect)
+ new IgnoreRedirect(req,
+ Ci.nsIChannelEventSink.REDIRECT_TEMPORARY | Ci.nsIChannelEventSink.REDIRECT_PERMANENT);
+ if (details.ignoreTempRedirect)
+ new IgnoreRedirect(req, Ci.nsIChannelEventSink.REDIRECT_TEMPORARY);
+ if (details.ignorePermanentRedirect)
+ new IgnoreRedirect(req, Ci.nsIChannelEventSink.REDIRECT_PERMANENT);
+
+ let redirectionLimit = null;
+ if (details.failOnRedirect) {
+ redirectionLimit = 0;
+ }
+ if ("redirectionLimit" in details) {
+ if (details.redirectionLimit < 0 || details.redirectionLimit > 10) {
+ throw new Error("redirectionLimit must be within (0, 10), but it is " + details.redirectionLimit);
+ }
+ redirectionLimit = details.redirectionLimit;
+ }
+ if (redirectionLimit !== null && req.channel instanceof Ci.nsIHttpChannel) {
+ req.channel.redirectionLimit = redirectionLimit;
+ }
+
+ if (details.headers) {
+ var headers = details.headers;
+
+ for (var prop in headers) {
+ if (Object.prototype.hasOwnProperty.call(headers, prop))
+ req.setRequestHeader(prop, headers[prop]);
+ }
+ }
+
+ var body = details.data ? details.data : null;
+ if (details.binary) req.sendAsBinary(body);
+ else req.send(body);
+}
+
+// arranges for the specified 'event' on xmlhttprequest 'req' to call the
+// method by the same name which is a property of 'details' in the content
+// window's security context.
+GM_xmlhttpRequester.prototype.setupRequestEvent =
+ function(unsafeContentWin, req, event, details) {
+ var origMimeType = details.overrideMimeType;
+ var script = this.script;
+
+ if (details[event]) {
+ req[event] = function() {
+ var responseState = {
+ // can't support responseXML because security won't
+ // let the browser call properties on it
+ responseText: req.responseText,
+ readyState: req.readyState,
+ responseHeaders: null,
+ status: null,
+ statusText: null,
+ finalUrl: null
+ };
+ if (4 == req.readyState && 'onerror' != event) {
+ responseState.responseHeaders = req.getAllResponseHeaders();
+ responseState.status = req.status;
+ responseState.statusText = req.statusText;
+ if (MIME_JSON.test(origMimeType)
+ || MIME_JSON.test(details.overrideMimeType)
+ || MIME_JSON.test(req.channel.contentType)) {
+ try {
+ responseState.responseJSON = JSON.parse(req.responseText);
+ } catch (e) {
+ responseState.responseJSON = {};
+ }
+ }
+ responseState.finalUrl = req.channel.URI.spec;
+ }
+
+ GM_apiSafeCallback(
+ unsafeContentWin, script, details, details[event], [responseState]);
+ }
+ }
+}
+
+// TODO: replace!!
+function GM_apiSafeCallback(aWindow, aScript, aThis, aCb, aArgs) {
+ aCb.apply(aThis, aArgs);
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/convert-2-regexp.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/convert-2-regexp.js
new file mode 100644
index 0000000..9b79f30
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/convert-2-regexp.js
@@ -0,0 +1,23 @@
+'use strict';
+
+const RE_REGEXP = /^\/(.*)\/(i)?$/;
+const RE_ESCAPE = /[{}()\[\]\\^$.?]/g;
+const RE_WILD = /\*+/g;
+const RE_TLD = /^\^[^\/]*(?:\/\/)?[^\/]*\\\.tld(?:\/.*)?\$$/;
+
+exports.convert2RegExp = function Scriptish_convert2RegExp(aPattern, aNoTLD, forceString) {
+ var s = aPattern.toString().trim(), m;
+
+ // Already a regexp?
+ if (!forceString && (m = s.match(RE_REGEXP))) {
+ return new RegExp(m[1], m[2]);
+ }
+
+ var res = "^" + s
+ .replace(RE_ESCAPE, "\\$&")
+ .replace(RE_WILD, ".*")
+ + "$";
+ var regExp = new RegExp(res, "i");
+ regExp.isTLD = !aNoTLD && RE_TLD.test(res);
+ return regExp;
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/greasemonkey-api.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/greasemonkey-api.js
new file mode 100644
index 0000000..e465883
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/greasemonkey-api.js
@@ -0,0 +1,76 @@
+'use strict';
+
+var { Services } = require("services");
+var prefService = require("preferences-service");
+var tabs = require("tabs");
+var clipboard = require("clipboard");
+var {GM_xmlhttpRequester} = require("GM_xmlhttpRequester");
+
+const NS_XHTML = "http://www.w3.org/1999/xhtml";
+
+function GM_API(aScript, aURL, aWinID, aSafeWin, aUnsafeContentWin, aChromeWin) {
+ var document = aSafeWin.document;
+ var windowID = aWinID;
+ var xhr = new GM_xmlhttpRequester(aUnsafeContentWin, aURL, aScript);
+
+ this.GM_addStyle = function GM_addStyle(css) {
+ var head = document.getElementsByTagName("head")[0];
+ var style = document.createElement("style");
+ if (head) {
+ style.textContent = css;
+ style.type = "text/css";
+ head.appendChild(style);
+ }
+ return style;
+ };
+
+ // TODO: use simple storage
+ this.GM_getValue = function GM_getValue(name, defVal) {
+ return prefService.get(aScript.prefPrefix + name, defVal);
+ };
+ this.GM_setValue = function GM_setValue(name, val) {
+ return prefService.set(aScript.prefPrefix + name, val);
+ };
+
+ this.GM_safeHTMLParser = function GM_safeHTMLParser(aHTMLStr) {
+ //if (!GM_apiLeakCheck("GM_safeHTMLParser")) return;
+ let doc = document.implementation.createDocument(NS_XHTML, "html", null);
+ let body = document.createElementNS(NS_XHTML, "body");
+ doc.documentElement.appendChild(body);
+ body.appendChild(Services.suhtml.parseFragment(aHTMLStr, false, null, body));
+ return doc;
+ }
+
+ this.GM_xmlhttpRequest = function GM_xmlhttpRequest() {
+ //if (!GM_apiLeakCheck("GM_xmlhttpRequest")) return;
+ return xhr.contentStartRequest.apply(xhr, arguments);
+ };
+};
+exports.GM_API = GM_API;
+
+GM_API.prototype.GM_openInTab =
+ function GM_openInTab(aURL, aLoadInBackground, aReuse) {
+ if (aReuse) {
+ for each (var tab in tabs) {
+ if (tab.url == aURL) {
+ if (!aLoadInBackground)
+ tab.activate();
+ return;
+ }
+ }
+ }
+
+ tabs.open({
+ url: aURL,
+ inBackground: aLoadInBackground
+ });
+};
+
+GM_API.prototype.GM_setClipboard = function GM_setClipboard(aData, aType) {
+ return clipboard.set(aData, aType);
+};
+
+GM_API.prototype.GM_generateUUID = function GM_generateUUID() (
+ Services.uuid.generateUUID().toString());
+
+GM_API.prototype.GM_registerMenuCommand = function() {};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-header-parser.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-header-parser.js
new file mode 100644
index 0000000..41f7ffd
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-header-parser.js
@@ -0,0 +1,31 @@
+'use strict';
+
+exports.parse = function(aSource) {
+ var headers = {};
+ var foundMeta = false;
+ var line;
+
+ // do not 'optimize' by reusing this reg exp! it should not be reused!
+ var metaRegExp = /\/\/[ \t]*(?:==(\/?UserScript)==|\@(\S+)(?:[ \t]+([^\r\f\n]+))?)/g;
+
+ // read one line at a time looking for start meta delimiter or EOF
+ while (line = metaRegExp.exec(aSource)) {
+ if (line[1]) {
+ if ("userscript" == line[1].toLowerCase()) {
+ foundMeta = true; // start
+ continue;
+ } else {
+ break; // done
+ }
+ }
+ if (!foundMeta) continue;
+
+ var header = line[2].toLowerCase();
+ var value = line[3];
+
+ if (!headers[header]) headers[header] = [value];
+ else headers[header].push(value);
+ }
+
+ return headers;
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-manager.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-manager.js
new file mode 100644
index 0000000..f1eec70
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-manager.js
@@ -0,0 +1,44 @@
+'use strict';
+
+var { Services } = require("../chrome/services");
+var obs = require("sdk/deprecated/observer-service");
+
+var sandboxFactory = require("./userscript-sandbox");
+
+var userscripts = [];
+
+// TODO: register obs only when there is a userscript
+obs.add("content-document-global-created", docReady);
+obs.add("chrome-document-global-created", docReady);
+
+function docReady(safeWin, data) {
+ let href = (safeWin.location.href
+ || (safeWin.frameElement && safeWin.frameElement.src)) || "";
+
+ safeWin.addEventListener("load", function() {
+ userscripts.forEach(function(script) {
+ // check that the userscript should be run on this page
+ if (!script.matchesURL(href))
+ return;
+
+ sandboxFactory.evalInSandbox(
+ script._source,
+ sandboxFactory.createSandbox(safeWin, script, href),
+ script.jsversion);
+ });
+ }, true);
+}
+
+exports.register = function(aScript) {
+ unregister(aScript);
+ userscripts.push(aScript);
+};
+
+var unregister = exports.unregister = function unregister(aScript) {
+ for (var i = userscripts.length - 1; ~i; i--) {
+ if (userscripts[i] == aScript) {
+ userscripts.splice(i, 1);
+ break;
+ }
+ }
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-sandbox.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-sandbox.js
new file mode 100644
index 0000000..1c92066
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-sandbox.js
@@ -0,0 +1,24 @@
+'use strict';
+
+var { Cc, Ci, Cu } = require('chrome');
+var {GM_API} = require("./greasemonkey-api");
+
+exports.createSandbox = function createSandbox(safeWin, userScript, aURL) {
+ var script = userScript.source;
+ var sandbox = new Cu.Sandbox(safeWin);
+ sandbox.window = safeWin;
+ sandbox.document = sandbox.window.document;
+ sandbox.__proto__ = safeWin;
+ var api = new GM_API(userScript, aURL, null, safeWin, safeWin.wrappedJSObject);
+
+ for (var key in api) {
+ sandbox[key] = api[key];
+ }
+
+ return sandbox;
+};
+
+exports.evalInSandbox = function(code, sandbox, jsVersion) {
+ jsVersion = jsVersion || "1.8";
+ Cu.evalInSandbox("(function(){"+code+"})();", sandbox, jsVersion);
+}; \ No newline at end of file
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/storage.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/storage.js
new file mode 100644
index 0000000..3ed13d0
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/storage.js
@@ -0,0 +1,126 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Cc, Ci, Cu, components } = require('chrome');
+const { id } = require('sdk/self');
+const unload = require('sdk/system/unload');
+const { defer } = require('sdk/core/promise');
+
+const { Instances } = require('./chrome/instances');
+const { Services } = require('./chrome/services');
+const { NetUtil } = require('./chrome/net-utils');
+
+const { FileUtils } = Cu.import('resource://gre/modules/FileUtils.jsm', {});
+
+const JETPACK_DIR_BASENAME = "jetpack";
+
+let saving = false;
+
+function getStorageFile() {
+ const file = Services.dirsvc.get('ProfD', Ci.nsIFile);
+ file.append(JETPACK_DIR_BASENAME);
+ file.append(id);
+ file.append('pathfinder');
+ file.append('storage');
+
+ if (!file.exists())
+ file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0755', 8));
+
+ file.append('storage.blob');
+ return file;
+}
+
+function get(options) {
+ options = options || {};
+ let charset = options.charset || 'UTF-8';
+
+ const { promise, resolve } = defer();
+ const file = getStorageFile();
+ const channel = NetUtil.newChannel(file);
+
+ if (!file.exists()) {
+ resolve({ data: '' });
+ }
+ else {
+ NetUtil.asyncFetch(channel, function(iStream, aResult) {
+ if (!components.isSuccessCode(aResult)) {
+ reject();
+ }
+ else {
+ let text = NetUtil.readInputStreamToString(iStream, iStream.available());
+
+ let conv = Instances.suc;
+ conv.charset = charset;
+
+ text = conv.ConvertToUnicode(text);
+
+ resolve({
+ data: text,
+ charset: charset
+ });
+ }
+ });
+ }
+
+ return promise;
+}
+exports.get = get;
+
+function set({ data, charset }) {
+ charset = charset || 'UTF-8';
+ data = data || '';
+ const { promise, resolve, reject } = defer();
+ const file = getStorageFile();
+
+ if (data == '') {
+ if (file.exists()) {
+ file.remove(false);
+ }
+
+ resolve({
+ data: '',
+ charset: charset
+ });
+ }
+ else {
+ const converter = Instances.suc;
+ converter.charset = "UTF-8";
+
+ if (isSaving()) {
+ throw Error('Storage is currently in the process of saving..');
+ }
+ saving = true;
+
+ let iStream = converter.convertToInputStream(data);
+ let oStream = FileUtils.openSafeFileOutputStream(file);
+
+ NetUtil.asyncCopy(
+ iStream,
+ oStream,
+ function(aResult) {
+ FileUtils.closeSafeFileOutputStream(oStream);
+ saving = false;
+
+ if (!components.isSuccessCode(aResult)) {
+ reject();
+ }
+ else {
+ resolve({
+ data: data,
+ charset: charset
+ });
+ }
+ }
+ );
+ }
+
+ return promise;
+}
+exports.set = set;
+
+function isSaving() {
+ return saving;
+}
+exports.isSaving = isSaving;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/awesomebar.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/awesomebar.js
new file mode 100644
index 0000000..641dc14
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/awesomebar.js
@@ -0,0 +1,205 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const {Cc, Ci, Cu, Cm, components} = require('chrome');
+Cu.import("resource://gre/modules/AddonManager.jsm", this);
+Cu.import("resource://gre/modules/Services.jsm", this);
+Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
+
+var {unload} = require("../addon/unload");
+var {listen} = require("../xul/listen");
+var {watchWindows} = require("window-watcher");
+var {clearTimeout, setTimeout} = require("timer");
+
+let handlers = [];
+
+// public api for adding a keyword and search handler
+// TODO: validate, yo
+exports.AwesomeBarSuggestion = function AwesomeBarSuggestion(options) {
+ var i = handlers.push(options) - 1;
+ var destroyed = false;
+
+ return {
+ destroy: function() {
+ if (destroyed) return;
+ destroyed = true;
+ handlers[i] = null;
+ }
+ };
+};
+
+// Bool check if a given string matches a given handler
+function handlerMatch(query, handler) !!(handler && handler.matches.test(query));
+
+// Get first registered handler that matches a given string
+function getMatchingHandler(query) handlers.filter(function(handler) handlerMatch(query, handler)).shift()
+
+// Add functionality to search from the location bar and hook up autocomplete
+function addAddressBarSearch(window) {
+ let {change} = makeWindowHelpers(window);
+ let {BrowserUI, gBrowser, gURLBar} = window;
+
+ // Check the input to see if the add-on icon should be shown
+ // Called when the location bar fires the input event
+ function onLocationBarInput() {
+ if (skipCheck())
+ return;
+
+ let icon = "";
+ let handler = getMatchingHandler(urlbar.value);
+ if (handler && handler.icon)
+ icon = handler.icon;
+ setIcon(icon);
+ }
+
+ // Implement these functions depending on the platform
+ let setIcon, skipCheck, urlbar;
+
+ // mobile
+ if (gBrowser == null) {
+ setIcon = function(url) BrowserUI._updateIcon(url);
+ skipCheck = function() false;
+ urlbar = BrowserUI._edit;
+
+ // Check the input on various events
+ listen(window, BrowserUI._edit, "input", onLocationBarInput);
+
+ // Convert inputs to twitter urls
+ change(window.Browser, "getShortcutOrURI", function(orig) {
+ return function(uri, data) {
+ return orig.call(this, uri, data);
+ };
+ });
+ }
+ // desktop
+ else {
+ setIcon = function(url) window.PageProxySetIcon(url);
+ skipCheck = function() gURLBar.getAttribute("pageproxystate") == "valid" &&
+ !gURLBar.hasAttribute("focused");
+ urlbar = gURLBar;
+
+ // Check the input on various events
+ listen(window, gURLBar, "input", onLocationBarInput);
+ listen(window, gBrowser.tabContainer, "TabSelect", onLocationBarInput);
+
+ // Convert inputs to twitter urls
+ change(gURLBar, "_canonizeURL", function(orig) {
+ return function(event) {
+ return orig.call(this, event);
+ };
+ });
+ }
+
+ // Provide a way to set the autocomplete search engines and initialize
+ function setSearch(engines) {
+ urlbar.setAttribute("autocompletesearch", engines);
+ urlbar.mSearchNames = null;
+ urlbar.initSearchNames();
+ };
+
+ // Add in the twitter search and remove on cleanup
+ let origSearch = urlbar.getAttribute("autocompletesearch");
+ setSearch(require('self').id + " " + origSearch);
+ unload(function() setSearch(origSearch));
+}
+
+// Add an autocomplete search engine to provide location bar suggestions
+function addAutocomplete() {
+ const contract = "@mozilla.org/autocomplete/search;1?name=" + require('self').id;
+ const desc = "Jetpack Autocomplete";
+ const uuid = components.ID("504A8466-8D3D-11E0-A57E-D2F94824019B");
+
+ // Keep a timer to send a delayed no match
+ let timer;
+ function clearTimer() {
+ if (timer != null)
+ clearTimeout(timer);
+ timer = null;
+ }
+
+ // call back in one second
+ function setTimer(callback) {
+ timer = setTimeout(callback, 1000);
+ }
+
+ // Implement the autocomplete search that handles twitter queries
+ let search = {
+ createInstance: function(outer, iid) search.QueryInterface(iid),
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch]),
+
+ // Handle searches from the location bar
+ startSearch: function(query, param, previous, listener) {
+
+ // Always clear the timer on a new search
+ clearTimer();
+
+ function suggest(o, done) {
+ listener.onSearchResult(search, {
+ getCommentAt: function() o.title,
+ getImageAt: function() o.favicon,
+ getLabelAt: function() o.label || o.url,
+ getValueAt: function() o.url,
+ getStyleAt: function() "favicon",
+ get matchCount() 1,
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult]),
+ removeValueAt: function() {},
+ searchResult: Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
+ get searchString() query,
+ });
+ }
+
+ // TODO: if no search yet, but matched keyword, show example text
+
+ // if there's a query string and a match
+ if (query.length) {
+ let handler = getMatchingHandler(query);
+ if (handler) {
+ if (query) {
+ handler.onSearch(query, suggest);
+ }
+ }
+ }
+ // Send a delayed NOMATCH so the autocomplete doesn't close early
+ else {
+ setTimer(function() {
+ listener.onSearchResult(search, {
+ searchResult: Ci.nsIAutoCompleteResult.RESULT_NOMATCH,
+ });
+ });
+ }
+ },
+
+ // Nothing to cancel other than a delayed search as results are synchronous
+ stopSearch: function() {
+ clearTimer();
+ },
+ };
+
+ // Register this autocomplete search service and clean up when necessary
+ const registrar = Ci.nsIComponentRegistrar;
+ Cm.QueryInterface(registrar).registerFactory(uuid, desc, contract, search);
+ unload(function() {
+ Cm.QueryInterface(registrar).unregisterFactory(uuid, search);
+ });
+}
+
+// Add support to the browser
+watchWindows(addAddressBarSearch);
+addAutocomplete();
+
+// Take a window and create various helper properties and functions
+function makeWindowHelpers(window) {
+ // Replace a value with another value or a function of the original value
+ function change(obj, prop, val) {
+ let orig = obj[prop];
+ obj[prop] = typeof val == "function" ? val(orig) : val;
+ unload(function() obj[prop] = orig, window);
+ }
+
+ return {
+ change: change,
+ };
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/findbar/suggestion.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/findbar/suggestion.js
new file mode 100644
index 0000000..efbc665
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/findbar/suggestion.js
@@ -0,0 +1,77 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 winUtils = require('sdk/deprecated/window-utils');
+const { Class } = require('sdk/core/heritage');
+const { validateOptions } = require('sdk/deprecated/api-utils');
+const { isBrowser } = require('sdk/window/utils');
+const { unload } = require('../../addon/unload');
+const { listen } = require('../../xul/listen');
+
+const findsuggestionNS = require('sdk/core/namespace').ns();
+const NS_XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
+
+function FindSuggestionOptions(options) {
+ return validateOptions(options, {
+ word: { is: ['string'] },
+ //onClick: { is: ['undefined', 'function'] }
+ });
+}
+
+const FindSuggestion = Class({
+ initialize: function(options) {
+ options = findsuggestionNS(this).options = FindSuggestionOptions(options);
+ let unloaders = findsuggestionNS(this).unloaders = [];
+
+ winUtils.WindowTracker({
+ onTrack: function(window) {
+ if (!isBrowser(window)) return;
+
+ let findBar = window.gFindBar;
+ let findContainer = findBar.getElement('findbar-container');
+
+ // Show these suggestions in the findbar
+ let ele = window.document.createElementNS(NS_XUL, 'label');
+ ele.setAttribute('value', options.word);
+ ele.style.margin = '2px';
+ ele.style.cursor = 'pointer';
+ ele.style.fontWeight = 'bold';
+ findContainer.appendChild(ele);
+
+ ele.addEventListener('click', suggestionClick.bind({
+ findBar: findBar
+ }), false);
+
+ // Clear out the suggestions when removing the add-on
+ function clearSuggestion() {
+ findContainer.removeChild(ele);
+ }
+
+ // save a destroyer
+ unloaders.push(
+ destroyer.bind(null, unload(clearSuggestion, window), clearSuggestion));
+ }
+ });
+ },
+ destroy: function() findsuggestionNS(this).unloaders.forEach(function(x) x())
+});
+exports.FindSuggestion = FindSuggestion;
+
+function suggestionClick(event) {
+ let suggestion = event.target.value;
+ let findField = this.findBar._findField;
+
+ if (findField.value === suggestion) {
+ this.findBar.onFindAgainCommand(false);
+ }
+ else {
+ findField.value = suggestion;
+ findBar._find();
+ }
+}
+function destroyer(remover, clearSuggestion) {
+ clearSuggestion();
+ remover();
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/menuitems.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/menuitems.js
new file mode 100644
index 0000000..5e34106
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/menuitems.js
@@ -0,0 +1,218 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 windowUtils = require("sdk/deprecated/window-utils");
+const { Class } = require("sdk/core/heritage");
+const { validateOptions } = require("sdk/deprecated/api-utils");
+const { on, emit, once, off } = require("sdk/event/core");
+const { isBrowser } = require("sdk/window/utils");
+const { EventTarget } = require('sdk/event/target');
+const menuitemNS = require("sdk/core/namespace").ns();
+
+const { unload } = require('../addon/unload');
+
+const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+function MenuitemOptions(options) {
+ return validateOptions(options, {
+ id: { is: ['string'] },
+ menuid: { is: ['undefined', 'string'] },
+ insertbefore: { is: ['undefined', 'string', 'object', 'number'] },
+ label: { is: ["string"] },
+ include: { is: ['string', 'undefined'] },
+ disabled: { is: ["undefined", "boolean"], map: function(v) !!v},
+ accesskey: { is: ["undefined", "string"] },
+ key: { is: ["undefined", "string"] },
+ checked: { is: ['undefined', 'boolean'] },
+ className: { is: ["undefined", "string"] },
+ onCommand: { is: ['undefined', 'function'] },
+ useChrome: { map: function(v) !!v }
+ });
+}
+
+let Menuitem = Class({
+ extends: EventTarget,
+ initialize: function(options) {
+ options = menuitemNS(this).options = MenuitemOptions(options);
+ EventTarget.prototype.initialize.call(this, options);
+
+ menuitemNS(this).destroyed = false;
+ menuitemNS(this).unloaders = [];
+ menuitemNS(this).menuitems = addMenuitems(this, options).menuitems;
+ },
+ get id() menuitemNS(this).options.id,
+ get label() menuitemNS(this).options.label,
+ set label(val) updateProperty(this, 'label', val),
+ get checked() menuitemNS(this).options.checked,
+ set checked(val) updateProperty(this, 'checked', !!val),
+ get disabled() menuitemNS(this).options.disabled,
+ set disabled(val) updateProperty(this, 'disabled', !!val),
+ get key() menuitemNS(this).options.key,
+ set key(val) updateProperty(this, 'key', val),
+ clone: function (overwrites) {
+ let opts = Object.clone(menuitemNS(this).options);
+ for (let key in overwrites) {
+ opts[key] = ovrewrites[key];
+ }
+ return Menuitem(opts);
+ },
+ get menuid() menuitemNS(this).options.menuid,
+ set menuid(val) {
+ let options = menuitemNS(this).options;
+ options.menuid = val;
+
+ forEachMI(function(menuitem, i, $) {
+ updateMenuitemParent(menuitem, options, $);
+ });
+ },
+ destroy: function() {
+ if (!menuitemNS(this).destroyed) {
+ menuitemNS(this).destroyed = true;
+ menuitemNS(this).unloaders.forEach(function(u) u());
+ menuitemNS(this).unloaders = null;
+ menuitemNS(this).menuitems = null;
+ }
+ return true;
+ }
+});
+
+function addMenuitems(self, options) {
+ let menuitems = [];
+
+ // setup window tracker
+ windowUtils.WindowTracker({
+ onTrack: function (window) {
+ if (menuitemNS(self).destroyed) return;
+ if (options.include) {
+ if (options.include != window.location) return;
+ }
+ else if (!isBrowser(window)) {
+ return;
+ }
+
+ // add the new menuitem to a menu
+ var menuitem = updateMenuitemAttributes(
+ window.document.createElementNS(NS_XUL, "menuitem"), options);
+ var menuitems_i = menuitems.push(menuitem) - 1;
+
+ // add the menutiem to the ui
+ let added = updateMenuitemParent(menuitem, options, function(id) window.document.getElementById(id));
+
+ menuitem.addEventListener("command", function() {
+ if (!self.disabled)
+ emit(self, 'command', options.useChrome ? window : null);
+ }, true);
+
+ // add unloader
+ let unloader = function unloader() {
+ menuitem.parentNode && menuitem.parentNode.removeChild(menuitem);
+ menuitems[menuitems_i] = null;
+ };
+
+ menuitemNS(self).unloaders.push(function() {
+ remover();
+ unloader();
+ });
+
+ let remover = unload(unloader, window);
+ }
+
+ });
+
+ return { menuitems: menuitems };
+}
+
+function updateMenuitemParent(menuitem, options, $) {
+ // add the menutiem to the ui
+ if (Array.isArray(options.menuid)) {
+ let ids = options.menuid;
+ for (var len = ids.length, i = 0; i < len; i++) {
+ if (tryParent($(ids[i]), menuitem, options.insertbefore))
+ return true;
+ }
+ }
+ else {
+ return tryParent($(options.menuid), menuitem, options.insertbefore);
+ }
+
+ return false;
+}
+
+function updateMenuitemAttributes(menuitem, options) {
+ menuitem.setAttribute("id", options.id);
+ menuitem.setAttribute("label", options.label);
+
+ if (options.accesskey)
+ menuitem.setAttribute("accesskey", options.accesskey);
+
+ if (options.key)
+ menuitem.setAttribute("key", options.key);
+
+ menuitem.setAttribute("disabled", !!options.disabled);
+
+ if (options.image) {
+ menuitem.classList.add("menuitem-iconic");
+ menuitem.style.listStyleImage = "url('" + options.image + "')";
+ }
+
+ if (options.checked)
+ menuitem.setAttribute('checked', options.checked);
+
+ if (options.className)
+ options.className.split(/\s+/).forEach(function(name) menuitem.classList.add(name));
+
+ return menuitem;
+}
+
+function updateProperty(menuitem, key, val) {
+ menuitemNS(menuitem).options[key] = val;
+
+ forEachMI(function(menuitem) {
+ menuitem.setAttribute(key, val);
+ }, menuitem);
+ return val;
+}
+
+function forEachMI(callback, menuitem) {
+ menuitemNS(menuitem).menuitems.forEach(function(mi, i) {
+ if (!mi) return;
+ callback(mi, i, function(id) mi.ownerDocument.getElementById(id));
+ });
+}
+
+function tryParent(parent, menuitem, before) {
+ if (parent) {
+ if (!before) {
+ parent.appendChild(menuitem);
+ return true;
+ }
+
+ parent.insertBefore(menuitem, insertBefore(parent, before));
+ return true;
+ }
+
+ return false;
+}
+
+function insertBefore(parent, insertBefore) {
+ if (typeof insertBefore == "number") {
+ switch (insertBefore) {
+ case MenuitemExport.FIRST_CHILD:
+ return parent.firstChild;
+ }
+ return null;
+ }
+ else if (typeof insertBefore == "string") {
+ return parent.querySelector("#" + insertBefore);
+ }
+ return insertBefore;
+}
+
+function MenuitemExport(options) {
+ return Menuitem(options);
+}
+MenuitemExport.FIRST_CHILD = 1;
+
+exports.Menuitem = MenuitemExport;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/actions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/actions.js
new file mode 100644
index 0000000..12076ca
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/actions.js
@@ -0,0 +1,9 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const method = require('method/core');
+
+exports.show = method('show');
+exports.hide = method('hide');
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/contract.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/contract.js
new file mode 100644
index 0000000..244e60e
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/contract.js
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { contract } = require('sdk/util/contract');
+const { isValidURI } = require('sdk/url');
+
+let string = { is: ['string'] };
+
+exports.contract = contract({
+ id: {
+ is: [ 'string' ],
+ ok: function (v) /^[a-z0-9-_]+$/i.test(v),
+ msg: 'The option "id" must be a valid alphanumeric id (hyphens and ' +
+ 'underscores are allowed).'
+ },
+ title: {
+ is: [ 'string' ],
+ ok: function (v) v.length
+ },
+ url: {
+ is: [ 'string' ],
+ ok: function(url) {
+ return isValidURI(url);
+ },
+ map: function(v) v.toString(),
+ msg: 'The option "url" must be a valid URI.'
+ }
+});
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/state.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/state.js
new file mode 100644
index 0000000..05225da
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/state.js
@@ -0,0 +1,8 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const method = require('method/core');
+
+exports.isShowing = method('isShowing');
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/utils.js
new file mode 100644
index 0000000..4576c5b
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/utils.js
@@ -0,0 +1,31 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If 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 { getMostRecentBrowserWindow } = require('sdk/window/utils');
+
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+function create(window, details) {
+ let { document } = window;
+
+ let menuitem = document.createElementNS(XUL_NS, 'menuitem');
+ menuitem.setAttribute('id', details.id);
+ menuitem.setAttribute('label', details.title);
+ menuitem.setAttribute('checked', 'false');
+ menuitem.setAttribute('sidebarurl', details.sidebarurl);
+ menuitem.setAttribute('type', 'checkbox');
+ menuitem.setAttribute('group', 'sidebar');
+ menuitem.setAttribute('autoCheck', 'false');
+
+ document.getElementById('viewSidebarMenu').appendChild(menuitem);
+
+ return menuitem;
+}
+exports.create = create;
+
+function dispose(menuitem) {
+ menuitem.parentNode.removeChild(menuitem);
+}
+exports.dispose = dispose;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/toolbarbutton.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/toolbarbutton.js
new file mode 100644
index 0000000..38bfb2e
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/toolbarbutton.js
@@ -0,0 +1,179 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 winUtils = require("sdk/deprecated/window-utils");
+const { isBrowser } = require('sdk/window/utils');
+const { Class } = require('sdk/core/heritage');
+const TBB_NS = require('sdk/core/namespace').ns();
+
+const { validate: validateOptions } = require('./validate');
+const { getToolbarButtons, toolbarbuttonExists } = require('./utils');
+const { unload } = require("../addon/unload");
+const { listen } = require("../xul/listen");
+
+const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+exports.ToolbarButton = Class({
+ initialize: function(options) {
+ TBB_NS(this).unloaders = [];
+
+ const self = this;
+ TBB_NS(this).destroyed = false;
+ TBB_NS(this).destroyFuncs = [];
+ let safeOptions = TBB_NS(this).options = validateOptions(options);
+
+ winUtils.WindowTracker({
+ onTrack: function (window) {
+ if (!isBrowser(window) || TBB_NS(self).destroyed)
+ return;
+
+ let doc = window.document;
+ let $ = function(id) doc.getElementById(id);
+
+ // create toolbar button
+ let tbb = doc.createElementNS(NS_XUL, "toolbarbutton");
+ tbb.setAttribute("id", safeOptions.id);
+ tbb.setAttribute("type", "button");
+ if (safeOptions.image)
+ tbb.setAttribute("image", safeOptions.image);
+ tbb.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional");
+ tbb.setAttribute("label", safeOptions.label);
+ tbb.setAttribute('tooltiptext', safeOptions.tooltiptext);
+ tbb.addEventListener("command", function() {
+ if (safeOptions.onCommand)
+ safeOptions.onCommand({}); // TODO: provide something?
+
+ if (safeOptions.panel) {
+ safeOptions.panel.show(tbb);
+ }
+ }, true);
+
+ // add toolbarbutton to palette
+ ($("navigator-toolbox") || $("mail-toolbox")).palette.appendChild(tbb);
+
+ // find a toolbar to insert the toolbarbutton into
+ if (TBB_NS(self).options.toolbarID) {
+ var tb = $(TBB_NS(self).options.toolbarID);
+ }
+ if (!tb) {
+ var tb = toolbarbuttonExists(doc, safeOptions.id);
+ }
+
+ // found a toolbar to use?
+ if (tb) {
+ let b4;
+
+ // find the toolbarbutton to insert before
+ if (TBB_NS(self).options.insertbefore) {
+ b4 = $(TBB_NS(self).options.insertbefore);
+ }
+ if (!b4) {
+ let currentset = tb.getAttribute("currentset").split(",");
+ let i = currentset.indexOf(safeOptions.id) + 1;
+
+ // was the toolbarbutton id found in the curent set?
+ if (i > 0) {
+ let len = currentset.length;
+ // find a toolbarbutton to the right which actually exists
+ for (; i < len; i++) {
+ b4 = $(currentset[i]);
+ if (b4) break;
+ }
+ }
+ }
+
+ tb.insertItem(safeOptions.id, b4, null, false);
+ }
+
+ var saveTBNodeInfo = function(e) {
+ TBB_NS(self).options.toolbarID = tbb.parentNode.getAttribute("id") || "";
+ TBB_NS(self).options.insertbefore = (tbb.nextSibling || "")
+ && tbb.nextSibling.getAttribute("id").replace(/^wrapper-/i, "");
+ };
+
+ window.addEventListener("aftercustomization", saveTBNodeInfo, false);
+
+ // add unloader to unload+'s queue
+ var unloadFunc = function() {
+ tbb.parentNode.removeChild(tbb);
+ window.removeEventListener("aftercustomization", saveTBNodeInfo, false);
+ };
+ var index = TBB_NS(self).destroyFuncs.push(unloadFunc) - 1;
+ listen(window, window, "unload", function() {
+ TBB_NS(self).destroyFuncs[index] = null;
+ }, false);
+ TBB_NS(self).unloaders.push(unload(unloadFunc, window));
+ }
+ });
+ },
+ destroy: function() {
+ if (TBB_NS(this).destroyed) return;
+ TBB_NS(this).destroyed = true;
+
+ let options = TBB_NS(this).options;
+
+ if (options.panel)
+ options.panel.destroy();
+
+ // run unload functions
+ TBB_NS(this).destroyFuncs.forEach(function(f) f && f());
+ TBB_NS(this).destroyFuncs.length = 0;
+
+ // remove unload functions from unload+'s queue
+ TBB_NS(this).unloaders.forEach(function(f) f());
+ TBB_NS(this).unloaders.length = 0;
+ },
+ moveTo: function(pos) {
+ if (TBB_NS(this).destroyed) return;
+
+ let options = TBB_NS(this).options;
+
+ // record the new position for future windows
+ TBB_NS(this).options.toolbarID = pos.toolbarID;
+ TBB_NS(this).options.insertbefore = pos.insertbefore;
+
+ // change the current position for open windows
+ for each (var window in winUtils.windowIterator()) {
+ if (!isBrowser(window)) continue;
+
+ let $ = function (id) window.document.getElementById(id);
+
+ // if the move isn't being forced and it is already in the window, abort
+ if (!pos.forceMove && $(this.id)) continue;
+
+ var tb = $(TBB_NS(this).options.toolbarID);
+ var b4 = $(TBB_NS(this).options.insertbefore);
+
+ // TODO: if b4 dne, but insertbefore is in currentset, then find toolbar to right
+
+ if (tb) tb.insertItem(this.id, b4, null, false);
+ };
+ },
+ get id() TBB_NS(this).options.id,
+ get label() TBB_NS(this).options.label,
+ set label(value) {
+ TBB_NS(this).options.label = value;
+ getToolbarButtons(function(tbb) {
+ tbb.label = value;
+ }, this.id);
+ return value;
+ },
+ setIcon: function setIcon(options) {
+ let val = TBB_NS(this).options.image = options.image || options.url;
+ getToolbarButtons(function(tbb) {
+ tbb.image = val;
+ }, this.id);
+ return val;
+ },
+ get image() TBB_NS(this).options.image,
+ set image(value) this.setIcon({image: value}),
+ get tooltiptext() TBB_NS(this).options.tooltiptext,
+ set tooltiptext(value) {
+ TBB_NS(this).options.tooltiptext = value;
+ getToolbarButtons(function(tbb) {
+ tbb.setAttribute('tooltiptext', value);
+ }, this.id);
+ }
+});
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/utils.js
new file mode 100644
index 0000000..6ad0304
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/utils.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const winUtils = require("sdk/deprecated/window-utils");
+const { isBrowser } = require('sdk/window/utils');
+
+const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+function getToolbarButtons(callback, id) {
+ let buttons = [];
+ for each (var window in winUtils.windowIterator()) {
+ if (!isBrowser(window)) continue;
+ let tbb = window.document.getElementById(id);
+ if (tbb) buttons.push(tbb);
+ }
+ if (callback) buttons.forEach(callback);
+ return buttons;
+}
+exports.getToolbarButtons = getToolbarButtons;
+
+function toolbarbuttonExists(doc, id) {
+ var toolbars = doc.getElementsByTagNameNS(NS_XUL, "toolbar");
+ for (var i = toolbars.length - 1; ~i; i--) {
+ if ((new RegExp("(?:^|,)" + id + "(?:,|$)")).test(toolbars[i].getAttribute("currentset")))
+ return toolbars[i];
+ }
+ return false;
+}
+exports.toolbarbuttonExists = toolbarbuttonExists;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/validate.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/validate.js
new file mode 100644
index 0000000..3de6d30
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/validate.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const { validateOptions } = require('sdk/deprecated/api-utils');
+const { Panel } = require('sdk/panel');
+
+ const RULES = {
+ image: { is: ["null", "undefined", "string"] },
+ tooltiptext: {
+ is: ["null", "undefined", "string"],
+ defaultValue: ''
+ },
+ id: {
+ is: ["string"],
+ ok: function (v) v.length > 0,
+ msg: 'BAD ID',
+ readonly: true
+ },
+ label: {
+ is: ["string"],
+ ok: function (v) v.length > 0,
+ msg: 'BAD Label'
+ },
+ panel: {
+ is: ["null", "undefined", "object"],
+ ok: function(v) !v || v instanceof Panel
+ },
+ onCommand: {
+ is: ["null", "undefined", "function"],
+ }
+};
+exports.validate = function(o) validateOptions(o, RULES);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/warning.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/warning.js
new file mode 100644
index 0000000..bf2b449
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/warning.js
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 self = require('sdk/self');
+const tabs = require('sdk/tabs');
+const { Class } = require('sdk/core/heritage');
+const { on, emit, once, off } = require('sdk/event/core');
+const { EventTarget } = require('sdk/event/target');
+
+const awNS = require('sdk/core/namespace').ns();
+
+let AddonWarning = Class({
+ extends: EventTarget,
+ initialize: function initialize(options) {
+ EventTarget.prototype.initialize.call(this, options);
+ awNS(this).options = options;
+ },
+ open: function() {
+ let self = this;
+ let options = awNS(self).options;
+
+ tabs.open({
+ url: module.uri.replace(/lib\/addon-warning\.js/, 'data/warning.html'),
+ onReady: function(tab) {
+ let worker = tab.attach({
+ contentScriptFile: module.uri.replace(/lib\/addon-warning\.js/, 'data/warning-mod.js')
+ });
+
+ worker.port.on('cancel', function(data) {
+ emit(self, 'cancel');
+ });
+ worker.port.on('accept', function(data) {
+ emit(self, 'accept');
+ });
+
+ worker.port.emit('load', options);
+ }
+ });
+ }
+});
+exports.AddonWarning = AddonWarning;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/web-panel.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/web-panel.js
new file mode 100644
index 0000000..f61c958
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/web-panel.js
@@ -0,0 +1,289 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+module.metadata = {
+ 'stability': 'experimental',
+ 'engines': {
+ 'Firefox': '*'
+ }
+};
+
+const { Class } = require('sdk/core/heritage');
+const { merge } = require('sdk/util/object');
+const { Disposable } = require('sdk/core/disposable');
+const { off, emit, setListeners } = require('sdk/event/core');
+const { EventTarget } = require('sdk/event/target');
+const { URL } = require('sdk/url');
+const { add, remove, has, clear, iterator } = require('sdk/lang/weak-set');
+const { WindowTracker } = require('sdk/deprecated/window-utils');
+const { isBrowser, getMostRecentBrowserWindow, windows } = require('sdk/window/utils');
+const { ns } = require('sdk/core/namespace');
+const { remove: removeFromArray } = require('sdk/util/array');
+const { Worker: WorkerTrait } = require('sdk/content/worker');
+
+const { create, dispose } = require('./sidebar/utils');
+const { show, hide } = require('./sidebar/actions');
+const { isShowing } = require('./sidebar/state');
+const { contract } = require('./sidebar/contract');
+
+const Worker = WorkerTrait.resolve({
+ _injectInDocument: '__injectInDocument'
+}).compose({
+ get _injectInDocument() false
+});
+
+const sidebarNS = ns();
+
+const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
+
+let sidebars = {};
+let models = new WeakMap();
+let views = new WeakMap();
+
+function viewsFor(sidebar) views.get(sidebar);
+function modelFor(sidebar) models.get(sidebar);
+
+const WebPanel = Class({
+ implements: [ Disposable ],
+ extends: EventTarget,
+ setup: function(options) {
+ let self = this;
+
+ const windowNS = ns();
+
+ let model = merge({}, contract(options));
+
+ models.set(this, model);
+
+ setListeners(this, options);
+
+ let bars = [];
+ sidebarNS(self).tracker = WindowTracker({
+ onTrack: function(window) {
+ if (!isBrowser(window))
+ return;
+
+ let sidebar = window.document.getElementById('sidebar');
+ let sidebarBox = window.document.getElementById('sidebar-box');
+
+ let bar = create(window, {
+ id: makeID(model.id),
+ title: model.title,
+ sidebarurl: model.url
+ });
+ bars.push(bar);
+ windowNS(window).bar = bar;
+
+ bar.addEventListener('command', function() {
+ if (isSidebarShowing(window, self)) {
+ hideSidebar(window, self);
+ return;
+ }
+
+ showSidebar(window, self);
+ }, false);
+
+ function onSidebarLoad() {
+ // check if the sidebar is ready
+ let isReady = sidebar.docShell && sidebar.contentDocument;
+ if (!isReady)
+ return;
+
+ // check if it is a web panel
+ let panelBrowser = sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
+ if (!panelBrowser) {
+ bar.removeAttribute('checked');
+ return;
+ }
+
+ let sbTitle = window.document.getElementById('sidebar-title');
+ function onWebPanelSidebarLoad() {
+ if (panelBrowser.contentWindow.location != model.url ||
+ sbTitle.value != model.title) {
+ return;
+ }
+
+ let worker = windowNS(window).worker = Worker({
+ window: panelBrowser.contentWindow
+ });
+
+ function onWebPanelSidebarUnload() {
+ panelBrowser.removeEventListener('unload', onWebPanelSidebarUnload, true);
+
+ windowNS(window).onWebPanelSidebarLoad = null;
+
+ // uncheck the associated menuitem
+ bar.setAttribute('checked', 'false');
+
+ emit(self, 'hide', null);
+ emit(self, 'detach', worker);
+ }
+ windowNS(window).onWebPanelSidebarUnload = onWebPanelSidebarUnload;
+ panelBrowser.contentWindow.addEventListener('unload', onWebPanelSidebarUnload, false);
+
+ // check the associated menuitem
+ bar.setAttribute('checked', 'true');
+
+ emit(self, 'show', null);
+ emit(self, 'attach', worker);
+ }
+ windowNS(window).onWebPanelSidebarLoad = onWebPanelSidebarLoad;
+ panelBrowser.addEventListener('DOMWindowCreated', onWebPanelSidebarLoad, true);
+ }
+ windowNS(window).onSidebarLoad = onSidebarLoad;
+ sidebar.addEventListener('load', onSidebarLoad, true);
+ },
+ onUntrack: function(window) {
+ if (!isBrowser(window))
+ return;
+
+ let { bar } = windowNS(window);
+ if (bar) {
+ removeFromArray(viewsFor(self), bar);
+ dispose(bar);
+ }
+
+ let sidebar = window.document.getElementById('sidebar');
+ if (!sidebar)
+ return;
+
+ if (windowNS(window).onSidebarLoad) {
+ sidebar.removeEventListener('load', windowNS(window).onSidebarLoad, true)
+ windowNS(window).onSidebarLoad = null;
+ }
+
+ if (windowNS(window).onWebPanelSidebarLoad) {
+ let webPanel = sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
+ webPanel && webPanel.removeEventListener('DOMWindowCreated', windowNS(window).onWebPanelSidebarLoad, true);
+ windowNS(window).onWebPanelSidebarLoad = null;
+ }
+
+ if (windowNS(window).onWebPanelSidebarUnload) {
+ windowNS(window).onWebPanelSidebarUnload();
+ }
+ }
+ });
+
+ views.set(this, bars);
+
+ add(sidebars, this);
+ },
+ get id() modelFor(this).id,
+ get title() modelFor(this).title,
+ get url() modelFor(this).url,
+ show: function() show(this),
+ hide: function() hide(this),
+ dispose: function() {
+ off(this);
+
+ let wins = windows('navigator:browser', { includePrivate: true });
+ for each (let win in wins) {
+ hideSidebar(win, this);
+ }
+
+ remove(sidebars, this);
+
+ // stop tracking windows
+ sidebarNS(this).tracker.unload();
+ sidebarNS(this).tracker = null;
+
+ views.delete(this);
+ }
+});
+exports.WebPanel = WebPanel;
+
+function showSidebar(window, sidebar) {
+ let model = modelFor(sidebar);
+ //let window = window || getMostRecentBrowserWindow();
+
+ window.openWebPanel(model.title, model.url);
+
+ let menuitem = window.document.getElementById(makeID(model.id));
+ menuitem.setAttribute('checked', true);
+}
+show.define(WebPanel, showSidebar.bind(null, null));
+
+function hideSidebar(window, sidebar) {
+ //window = window || getMostRecentBrowserWindow();
+
+ if (!isSidebarShowing(window, sidebar))
+ return;
+
+ // return window.toggleSidebar();
+
+ // Below was taken from http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#4775
+ // the code for window.todggleSideBar()..
+ let { document } = window;
+ //let sidebar = document.getElementById('sidebar');
+ let sidebarTitle = document.getElementById('sidebar-title');
+ let sidebarBox = document.getElementById('sidebar-box');
+ let sidebarSplitter = document.getElementById('sidebar-splitter');
+ let commandID = sidebarBox.getAttribute('sidebarcommand');
+ let sidebarBroadcaster = document.getElementById(commandID);
+
+ sidebarBox.hidden = true;
+ sidebarSplitter.hidden = true;
+
+ sidebar.setAttribute('src', 'about:blank');
+ //sidebar.docShell.createAboutBlankContentViewer(null);
+
+ sidebarBroadcaster.removeAttribute('checked');
+ sidebarBox.setAttribute('sidebarcommand', '');
+ sidebarTitle.value = '';
+ sidebarBox.hidden = true;
+ sidebarSplitter.hidden = true;
+
+ // TODO: perhaps this isn't necessary if the window is not most recent?
+ window.gBrowser.selectedBrowser.focus();
+}
+hide.define(WebPanel, hideSidebar.bind(null, null));
+
+function isSidebarShowing(window, sidebar) {
+ let win = window || getMostRecentBrowserWindow();
+
+ // make sure there is a window
+ if (!win) {
+ return false;
+ }
+
+ // make sure there is a sidebar for the window
+ let sb = win.document.getElementById('sidebar');
+ let sidebarTitle = win.document.getElementById('sidebar-title');
+ if (!(sb && sidebarTitle)) {
+ return false;
+ }
+
+ // checks if the sidebar box is hidden
+ let sbb = win.document.getElementById('sidebar-box');
+ if (!sbb || sbb.hidden) {
+ return false;
+ }
+
+ // checks if the sidebar is loading
+ if (win.gWebPanelURI == modelFor(sidebar).url) {
+ return false;
+ }
+
+ if (sidebarTitle.value == modelFor(sidebar).title) {
+ // checks if the sidebar loaded already
+ let ele = sb.contentDocument && sb.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
+
+ if (ele.getAttribute('cachedurl') == modelFor(sidebar).url) {
+ return true;
+ }
+
+ if (ele && ele.contentWindow && ele.contentWindow.location == modelFor(sidebar).url) {
+ return true;
+ }
+ }
+
+ // default
+ return false;
+}
+isShowing.define(WebPanel, isSidebarShowing.bind(null, null));
+
+function makeID(id) {
+ return 'pathfinder-sidebar-' + id;
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userscript.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userscript.js
new file mode 100644
index 0000000..9890200
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userscript.js
@@ -0,0 +1,116 @@
+'use strict';
+
+var file = require("sdk/io/file");
+var url = require("sdk/url");
+
+var convert2RegExp = require("./scriptish/convert-2-regexp").convert2RegExp;
+var userscriptParser = require("./scriptish/userscript-header-parser").parse;
+var manager = require("./scriptish/userscript-manager");
+
+const JSVersions = ['1.6', '1.7', '1.8'/*, '1.8.1'*/];
+
+var UserScript = exports.UserScript = function UserScript(aURL) {
+ var script = new Script(aURL);
+ manager.register(script);
+
+ return {
+ destory: function() {
+ manager.unregister(script);
+ },
+ get enabled() script.enabled,
+ set enabled(aVal) script.enabled = !!aVal
+ };
+}
+
+function Script(aURL) {
+ this._url = url.URL(aURL);
+ this._filepath = url.toFilename(aURL);
+ this._source = file.read(this._filepath);
+ var header = userscriptParser(this._source);
+
+ this._name = (header.name && header.name[0]) || Script.parseScriptName(aURL);
+ this._namespace = (header.namespace && header.namespace[0]) || this.url.host;
+ this._description = (header.description && header.description[0]) || "";
+ this.enabled = true;
+ this._includes = (header.include || []).map(convert2RegExp);
+ this._excludes = (header.exclude || []).map(convert2RegExp);
+ this._requires = (header.require || []);
+ this._resources = (header.resource || []);
+ if (header.jsversion) {
+ for (var i = header.jsversion.length - 1; ~i; i--) {
+ let val = header.jsversion[i];
+ if (~JSVersions.indexOf(val)) {
+ this.jsversion = val;
+ break;
+ }
+ }
+ }
+}
+
+Script.prototype = {
+ get prefPrefix () {
+ return ["greasemonkey.scriptvals.",
+ this._namespace,
+ "/",
+ this._name,
+ "."].join("");
+ },
+
+ // TODO: actually implement this!
+ matchesDomain: function() {
+ return true;
+ },
+
+ matchesURL: function(url) {
+ var test = function(pattern) {
+ return pattern.test(url);
+ }
+
+ return this.enabled
+ && this._includes.some(test)
+ && !this._excludes.some(test);
+ },
+
+ _changed: function(event, data) {
+ if(this._config) {
+ this._config._changed(this, event, data);
+ }
+ },
+
+ get name() { return this._name; },
+ get namespace() { return this._namespace; },
+ get description() { return this._description; },
+
+ get enabled() { return this._enabled; },
+ set enabled(enabled) {
+ this._enabled = enabled;
+ this._changed("edit-enabled", enabled);
+ },
+
+ get includes() { return this._includes.concat(); },
+ get excludes() { return this._excludes.concat(); },
+ addInclude: function(url) {
+ this._includes.push(url);
+ this._changed("edit-include-add", url);
+ },
+ removeIncludeAt: function(index) {
+ this._includes.splice(index, 1);
+ this._changed("edit-include-remove", index);
+ },
+ addExclude: function(url) {
+ this._excludes.push(url);
+ this._changed("edit-exclude-add", url);
+ },
+ removeExcludeAt: function(index) {
+ this._excludes.splice(index, 1);
+ this._changed("edit-exclude-remove", index);
+ },
+
+ get requires() { return this._requires.concat(); },
+ get resources() { return this._resources.concat(); },
+ get unwrap() { return this._unwrap; }
+};
+
+
+Script.parseScriptName = function(aURL) ((
+ /\/([^\/]+)\.user(?:-\d+)?\.js(?:[\?#].*)?$/.test(aURL || "")) ? RegExp.$1 : "");
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userstyles.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userstyles.js
new file mode 100644
index 0000000..0cc3414
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userstyles.js
@@ -0,0 +1,72 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Cc, Ci } = require("chrome");
+const { unload } = require('./addon/unload');
+
+const sss = Cc["@mozilla.org/content/style-sheet-service;1"]
+ .getService(Ci.nsIStyleSheetService);
+
+function getURI(aURL) Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService).newURI(aURL, null, null);
+
+function setOptions(url, options) {
+ let newOptions = {};
+ options = options || {};
+
+ newOptions.uri = getURI(url);
+ newOptions.type = (options.type || 'user').toLowerCase();
+ newOptions.type = (newOptions.type == 'agent') ? sss.AGENT_SHEET : sss.USER_SHEET;
+
+ return newOptions;
+};
+
+// capture the unload callbacks for removing the unload function from
+// the queue as they are no longer needed when a URL is unregistered manually
+var unloaders = {};
+
+function removeUnload(url) {
+ if (typeof unloaders[url] === "function") {
+ unloaders[url].call(null);
+ delete unloaders[url];
+ }
+}
+
+/**
+ * Load various packaged styles for the add-on and undo on unload
+ *
+ * @usage load(aURL): Load specified style
+ * @param [string] aURL: Style file to load
+ * @param [object] options:
+ */
+const loadSS = exports.load = function loadSS(url, options) {
+ let { uri, type } = setOptions(url, options);
+
+ // load the stylesheet
+ sss.loadAndRegisterSheet(uri, type);
+
+ // remove the unloader for this URL if it exists
+ removeUnload(url);
+
+ // unload the stylesheet on unload
+ unloaders[url] = unload(unregisterSS.bind(null, url, options));
+};
+
+const registeredSS = exports.registered = function registeredSS(url, options) {
+ let { uri, type } = setOptions(url, options);
+
+ // check that the stylesheet is registered
+ return !!sss.sheetRegistered(uri, type);
+};
+
+const unregisterSS = exports.unload = function unregisterSS(url, options) {
+ let { uri, type } = setOptions(url, options);
+
+ // remove the unloader our load function setup if it exists
+ removeUnload(url);
+
+ // unregister the stylesheet
+ sss.unregisterSheet(uri, type);
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/utils/addonmanager.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/utils/addonmanager.js
new file mode 100644
index 0000000..3e301a2
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/utils/addonmanager.js
@@ -0,0 +1,19 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const {Cc, Ci, Cu} = require("chrome");
+
+Cu.import("resource://gre/modules/AddonManager.jsm", this);
+
+exports.AddonManager = AddonManager;
+exports.AddonManagerPrivate = AddonManagerPrivate;
+
+exports.AddonType = AddonManagerPrivate.AddonType;
+exports.AddonAuthor =
+ AddonManagerPrivate.AddonAuthor || function AddonAuthor(name, url) {
+ this.name = name;
+ this.url = url;
+ this.toString = function() this.name
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/browser.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/browser.js
new file mode 100644
index 0000000..5b1ed47
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/browser.js
@@ -0,0 +1,180 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { WindowTracker } = require("sdk/deprecated/window-utils");
+const { isBrowser, windows } = require('sdk/window/utils');
+const { validateOptions } = require("sdk/deprecated/api-utils");
+const { Class } = require("sdk/core/heritage");
+const { ns } = require("sdk/core/namespace");
+const { ensure } = require('sdk/system/unload');
+
+const { xulNS } = require('./namespace');
+
+const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+const VALID_POSITIONS = ['top'];
+
+// Converts anything that isn't false, null or undefined into a string
+function stringOrNull(val) val ? String(val) : val;
+
+const XUL_SKELETON = Class({
+ setup: function setup(attributes) {
+ const internals = xulNS(this);
+ internals.attributes = attributes;
+ ensure(this, 'destroy');
+ },
+ appendChild: function appendChild(node) {
+ const ID = this.getAttribute('id');
+
+ // keep note to update parent in future windows
+ xulNS(node).parentID = ID;
+ xulNS(node).insertBeforeID = null;
+
+ // update parent on current windows
+ windows().forEach(function(window) {
+ let parent = window.document.getElementById(ID);
+ let { element } = xulNS(node).windowsNS(window);
+ parent.appendChild(element);
+ });
+ },
+ insertBefore: function(node, beforeNode) {
+ const ID = this.getAttribute('id');
+ const B4_ID = (typeof beforeNode == 'string') ? beforeNode : beforeNode.getAttribute('id');
+
+ // keep note to update parent in future windows
+ xulNS(node).parentID = ID;
+ xulNS(node).insertBeforeID = B4_ID;
+
+ // update parent on current windows
+ windows().forEach(function(window) {
+ let parent = window.document.getElementById(ID);
+ let before = window.document.getElementById(B4_ID);
+ let { element } = xulNS(node).windowsNS(window);
+
+ parent.insertBefore(element, before);
+ });
+ },
+ addEventListener: function addEventListener(type, listener, useCapture) {
+ internals.eles.forEach(function(ele) {
+ ele.addEventListener(type, listener, useCapture);
+ });
+ },
+ removeEventListener: function removeEventListener(type, listener, useCapture) {
+ internals.eles.forEach(function(ele) {
+ ele.removeEventListener(type, listener, useCapture);
+ });
+ },
+ getAttribute: function getAttribute(attr) {
+ return xulNS(this).attributes[attr];
+ },
+ setAttribute: function setAttribute(attr, value) {
+ const internals = xulNS(this);
+ internals.eles.forEach(function(ele) {
+ ele.setAttribute(attr, value);
+ });
+ internals.attributes[attr] = value;
+ },
+ destroy: function() {
+ const internals = xulNS(this);
+ internals.attributes = null;
+ }
+});
+
+const XUL = Class({
+ implements: [ XUL_SKELETON ],
+ initialize: function(nodeName, attributes) {
+ const self = this;
+ const internals = xulNS(this);
+ internals.windowsNS = ns();
+ internals.eles = [];
+ internals.attributes = attributes;
+
+ XUL_SKELETON.prototype.setup.call(this, attributes);
+
+ // Set Window Tracker
+ internals.windowtracker = WindowTracker({
+ onTrack: function(window) {
+ if (!isBrowser(window)) return;
+ let ele = window.document.createElementNS(NS_XUL, nodeName);
+
+ Object.keys(attributes).forEach(function(key) {
+ ele.setAttribute(key, attributes[key]);
+ })
+
+ internals.eles.push(ele);
+ internals.windowsNS(window).element = ele;
+
+ // update parent?
+ if (internals.parentID) {
+ let parent = window.document.getElementById(internals.parentID);
+ if (internals.insertBeforeID) {
+ let before = window.document.getElementById(internals.insertBeforeID);
+ parent.insertBefore(ele, before);
+ }
+ else {
+ parent.appendChild(ele);
+ }
+ }
+ },
+ onUntrack: function(window) {
+ if (!isBrowser(window)) return;
+ let { element } = internals.windowsNS(window);
+ element.parentNode.removeChild(element);
+ internals.windowsNS(window).element = null;
+ }
+ });
+ },
+ destroy: function() {
+ XUL_SKELETON.prototype.destroy.call(this);
+ const internals = xulNS(this);
+ internals.windowtracker.unload();
+ internals.windowtracker = null;
+ internals.windowsNS = null;
+ }
+});
+exports.XUL = XUL;
+
+const XUL_GETTER = Class({
+ implements: [ XUL_SKELETON ],
+ initialize: function(attributes) {
+ const self = this;
+ const internals = xulNS(this);
+ internals.windowsNS = ns();
+ internals.eles = [];
+ internals.attributes = attributes;
+
+ XUL_SKELETON.prototype.setup.call(this, attributes);
+
+ // Set Window Tracker
+ internals.windowtracker = WindowTracker({
+ onTrack: function(window) {
+ if (!isBrowser(window)) return;
+ let ele = window.document.getElementById(attributes.id);
+ internals.eles.push(ele);
+ internals.windowsNS(window).element = ele;
+
+ // update parent?
+ if (internals.parentID) {
+ let parent = window.document.getElementById(internals.parentID);
+ parent.appendChild(ele);
+ }
+ }
+ });
+ },
+ destroy: function() {
+ const internals = xulNS(this);
+
+ XUL_SKELETON.prototype.destroy.call(this);
+
+ internals.windowtracker.unload();
+ internals.windowtracker = null;
+ internals.windowsNS = null;
+ }
+});
+exports.XUL_GETTER = XUL_GETTER;
+
+function getXULById(id) {
+ return XUL_GETTER({ id: id });
+}
+exports.getXULById = getXULById;
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/key.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/key.js
new file mode 100644
index 0000000..c855fc3
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/key.js
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+exports.XulKey = function XulKey(options) {
+ var delegate = {
+ onTrack: function (window) {
+ if ("chrome://browser/content/browser.xul" != window.location) return;
+
+ let doc = window.document;
+ function $(id) doc.getElementById(id);
+ function xul(type) doc.createElementNS(NS_XUL, type);
+
+ var onCmd = function() {
+ options.onCommand && options.onCommand();
+ };
+
+ var keyset = xul("keyset");
+
+ // add hotkey
+ var key = xul("key");
+ key.setAttribute("id", options.id);
+ key.setAttribute("key", options.key);
+ if (options.modifiers)
+ key.setAttribute("modifiers", options.modifiers);
+ key.setAttribute("oncommand", "void(0);");
+ key.addEventListener("command", onCmd, true);
+ ($("mainKeyset") || $("mailKeys")).parentNode.appendChild(keyset).appendChild(key);
+
+ // add unloader
+ require("unload+").unload(function() {
+ key.removeEventListener("command", onCmd, true); // must do for some reason..
+ keyset.parentNode.removeChild(keyset);
+ }, window);
+ },
+ onUntrack: function (window) {}
+ };
+ var winUtils = require("window-utils");
+ var tracker = new winUtils.WindowTracker(delegate);
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/listen.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/listen.js
new file mode 100644
index 0000000..5536e30
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/listen.js
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { unload } = require('../addon/unload');
+
+/**
+ * Helper that adds event listeners and remembers to remove on unload
+ */
+function listen(window, node, event, func, capture) {
+ // Default to use capture
+ if (capture == null)
+ capture = true;
+
+ node.addEventListener(event, func, capture);
+ function undoListen() {
+ node.removeEventListener(event, func, capture);
+ }
+
+ // Undo the listener on unload and provide a way to undo everything
+ let undoUnload = unload(undoListen, window);
+ return function() {
+ undoListen();
+ undoUnload();
+ };
+}
+exports.listen = listen;
+
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/namespace.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/namespace.js
new file mode 100644
index 0000000..1a67716
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/namespace.js
@@ -0,0 +1,3 @@
+'use strict';
+const { ns } = require('sdk/core/namespace');
+exports.xulNS = ns();
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/zip/utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/zip/utils.js
new file mode 100644
index 0000000..fa5796c
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/zip/utils.js
@@ -0,0 +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 { Cc, Ci, Cu } = require("chrome");
+
+exports.getZipReader = function(aFile) {
+ var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
+ .createInstance(Ci.nsIZipReader);
+ zipReader.open(aFile);
+ return zipReader;
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/package.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/package.json
new file mode 100644
index 0000000..3f0d03a
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/package.json
@@ -0,0 +1,60 @@
+{
+ "_args": [
+ [
+ "pathfinder@git+https://github.com/OverByThere/addon-pathfinder.git",
+ "/home/nik/src/librejs/node_modules/menuitem"
+ ]
+ ],
+ "_from": "git+https://github.com/OverByThere/addon-pathfinder.git",
+ "_id": "pathfinder@1.0.1",
+ "_inCache": true,
+ "_location": "/pathfinder",
+ "_phantomChildren": {},
+ "_requested": {
+ "hosted": {
+ "directUrl": "https://raw.githubusercontent.com/OverByThere/addon-pathfinder/master/package.json",
+ "gitUrl": "git://github.com/OverByThere/addon-pathfinder.git",
+ "httpsUrl": "git+https://github.com/OverByThere/addon-pathfinder.git",
+ "shortcut": "github:OverByThere/addon-pathfinder",
+ "ssh": "git@github.com:OverByThere/addon-pathfinder.git",
+ "sshUrl": "git+ssh://git@github.com/OverByThere/addon-pathfinder.git",
+ "type": "github"
+ },
+ "name": "pathfinder",
+ "raw": "pathfinder@git+https://github.com/OverByThere/addon-pathfinder.git",
+ "rawSpec": "git+https://github.com/OverByThere/addon-pathfinder.git",
+ "scope": null,
+ "spec": "git+https://github.com/OverByThere/addon-pathfinder.git",
+ "type": "hosted"
+ },
+ "_requiredBy": [
+ "/menuitem"
+ ],
+ "_resolved": "git+https://github.com/OverByThere/addon-pathfinder.git#bad1110fc9427bafd6d7fc1a1d4594cf8086ab94",
+ "_shasum": "e8e99972c3ac7a562fb84e8331b9df88ca2a9098",
+ "_shrinkwrap": null,
+ "_spec": "pathfinder@git+https://github.com/OverByThere/addon-pathfinder.git",
+ "_where": "/home/nik/src/librejs/node_modules/menuitem",
+ "author": {
+ "name": "Erik Vold"
+ },
+ "bugs": {
+ "url": "https://github.com/OverByThere/menuitem/issues"
+ },
+ "dependencies": {},
+ "description": "The Add-on Pathfinder is the collection of Jetpack modules made to be used with the [Add-on SDK](https://github.com/mozilla/addon-sdk).",
+ "devDependencies": {},
+ "gitHead": "bad1110fc9427bafd6d7fc1a1d4594cf8086ab94",
+ "homepage": "https://github.com/OverByThere/menuitem#readme",
+ "installable": true,
+ "license": "MPL 2.0",
+ "name": "pathfinder",
+ "optionalDependencies": {},
+ "readme": "# Add-on Pathfinder\n\nThe Add-on Pathfinder is the collection of Jetpack modules made to be used with the\n[Add-on SDK](https://github.com/mozilla/addon-sdk).\n\n## Highlights\n\n* Toolbar buttons\n* Menuitems\n* GCLI\n* Downloads\n* About/Resource Schemes\n* UserStyles\n* UserScripts\n* XUL Help\n* ZIP Utilities\n* Content policies\n* Content Permissions\n* Awesomebar\n* Modifying Request Headers\n* Redirects\n* Much much more!...\n",
+ "readmeFilename": "README.md",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/OverByThere/menuitem.git"
+ },
+ "version": "1.0.1"
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/black.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/black.png
new file mode 100644
index 0000000..ee11b09
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/black.png
Binary files differ
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/index.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/index.html
new file mode 100644
index 0000000..7e49348
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/index.html
@@ -0,0 +1,4 @@
+<html>
+ <title></title>
+ <body></body>
+</html>
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-folder.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-folder.js
new file mode 100644
index 0000000..4b98c42
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-folder.js
@@ -0,0 +1,90 @@
+'use strict';
+
+const JETPACK_DIR_BASENAME = "jetpack";
+
+const FOLDER = require('pathfinder/addon/folder');
+
+const { Loader } = require('sdk/test/loader');
+const { Cc, Ci } = require('chrome');
+const file = require('sdk/io/file');
+const jpSelf = require('sdk/self');
+
+let storeFile = Cc['@mozilla.org/file/directory_service;1']
+ .getService(Ci.nsIProperties)
+ .get('ProfD', Ci.nsIFile);
+storeFile.append(JETPACK_DIR_BASENAME);
+storeFile.append(jpSelf.id);
+storeFile.append('addon-folder');
+
+const ADDON_FOLDER_PATH = storeFile.path;
+
+exports.testFolderCreated = function(assert) {
+ let loader = Loader(module);
+ assert.ok(file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + ' was created');
+ FOLDER.destroy();
+ assert.ok(!file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + ' was destroyed');
+ loader.require('pathfinder/addon/folder');
+ assert.ok(file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + ' was created');
+ loader.unload();
+ assert.ok(file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + 'exists after unload');
+}
+
+exports.testFileLifecycle = function(assert, done) {
+ let filename = 'test.json';
+ let fileStream = FOLDER.write(filename);
+ try {
+ fileStream.writeAsync('{}', function(err) {
+ assert.equal(FOLDER.exists(filename), true, 'the file was created');
+
+ if (err)
+ assert.fail(err);
+ else
+ assert.equal(FOLDER.read(filename), '{}', 'the file was written correctly');
+
+ let entries = FOLDER.list();
+ assert.ok(entries.length > 0, 'there is more than one entry');
+ for each (let entry in entries) {
+ assert.equal(entry, filename, filename + ' is the only entry listed');
+ }
+
+ let testFile = Cc['@mozilla.org/file/directory_service;1']
+ .getService(Ci.nsIProperties)
+ .get('ProfD', Ci.nsIFile);
+ testFile.append(JETPACK_DIR_BASENAME);
+ testFile.append(jpSelf.id);
+ testFile.append('addon-folder');
+ testFile.append(filename);
+
+ assert.ok(testFile.exists(), 'the test file does exist.')
+
+ FOLDER.remove(filename);
+
+ assert.equal(FOLDER.exists(filename), false, 'the file was removed');
+
+ done();
+ });
+ }
+ catch(e) {
+ assert.fail(e);
+ fileStream.close();
+ done();
+ }
+}
+
+exports.testBackPath = function(assert, done) {
+ let filename = '../../test.json';
+ let fileStream = { close: function(){} };
+ try {
+ fileStream = FOLDER.write(filename);
+ assert.fail(filename + ' should not be useable');
+ }
+ catch(e) {
+ assert.pass(e);
+ }
+
+ fileStream.close();
+ done();
+}
+
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-warning.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-warning.js
new file mode 100644
index 0000000..777c279
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-warning.js
@@ -0,0 +1,3 @@
+'use strict';
+
+const warning = require('pathfinder/ui/warning');
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-connection-request.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-connection-request.js
new file mode 100644
index 0000000..fcd278d
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-connection-request.js
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { Ci } = require('chrome');
+const tabs = require('sdk/tabs');
+const { data } = require('sdk/self');
+const { Loader } = require('sdk/test/loader');
+const httpd = require('sdk/test/httpd');
+
+const { RequestRule } = require('pathfinder/connections');
+
+exports.testNewHeader = function(assert, done) {
+ let rule = RequestRule({
+ headers: {
+ 'X-TEST-HEADER': 'TEST'
+ }
+ });
+
+ let serverPort = 8058;
+ let url = 'http://localhost:' + serverPort + '/test.txt';
+ let server = httpd.startServerAsync(serverPort);
+ const contents = "testNewHeader";
+ let requestCount = 0;
+
+ server.registerPathHandler("/test.txt", function handle(request, response) {
+ requestCount++;
+
+ if (requestCount == 1) {
+ try {
+ assert.equal(request.getHeader('X-TEST-HEADER'), 'TEST', 'the new test header value is correct');
+ }
+ catch (e) {
+ assert.fail(e);
+ }
+ rule.destroy();
+ }
+ response.write(contents);
+ });
+
+ tabs.open({
+ url: url,
+ onReady: function(tab) {
+ if (requestCount == 1) {
+ tab.reload();
+ }
+ else {
+ server.stop(function() {
+ done();
+ });
+ }
+ }
+ })
+}
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-permissions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-permissions.js
new file mode 100644
index 0000000..c9a6da2
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-permissions.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const { permissions } = require('pathfinder/content/permissions');
+
+exports.testAddRemovePermission = function(assert) {
+ permissions.add({
+ url: 'http://erikvold.com/',
+ permission: 'deny',
+ type: 'images'
+ });
+
+ let found = false;
+ for each (let permission in permissions.permissions) {
+ if (permission.host == 'erikvold.com') {
+ found = true;
+ assert.equal(permission.permission, 'deny');
+ assert.equal(permission.type, 'images');
+ }
+ }
+ assert.ok(found, 'erikvold.com permission was found');
+
+ permissions.remove({
+ url: 'http://erikvold.com/',
+ type: 'images'
+ });
+
+ for each (let permission in permissions.permissions) {
+ if (permission.host == 'erikvold.com') {
+ assert.fail('there should not be a permission for erikvold.com');
+ }
+ }
+ assert.pass('permission was removed!');
+};
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-policy.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-policy.js
new file mode 100644
index 0000000..5a811df
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-policy.js
@@ -0,0 +1,155 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { Loader } = require('sdk/test/loader');
+const tabs = require('sdk/tabs');
+const timers = require('sdk/timers');
+
+const cp = require('pathfinder/content/policy');
+
+exports.testConstants = function(assert) {
+ assert.ok(cp.REJECT != undefined, 'REJECT constant exists');
+ assert.ok(cp.ACCEPT != undefined, 'ACCEPT constant exists');
+ assert.ok(cp.ContentPolicy != undefined, 'ContentPolicy constant exists');
+};
+
+exports.testContentPolicyDestroy = function(assert, done) {
+ const loader = Loader(module);
+ const httpd = loader.require('sdk/test/httpd');
+ const { ContentPolicy } = loader.require('pathfinder/content/policy')
+ const { startServerAsync } = httpd;
+ const { setTimeout } = timers;
+
+ let tabsCount = tabs.length;
+ let tab1;
+
+ let serverPort = 8056;
+ let server = httpd.startServerAsync(serverPort);
+ const contents = '<!DOCTYPE html><html><head></head><body>testContentPolicyDestroy</body></html>';
+ // test.html
+ let testPageRequests = 0;
+ server.registerPathHandler('/test.html', function handle(request, response) {
+ testPageRequests++;
+ response.write(contents);
+ });
+
+ let url = 'http://localhost:' + serverPort + '/test.html';
+ let policy = ContentPolicy({
+ shouldLoad: function({ location }) {
+ if (location != url)
+ return true;
+
+ setTimeout(function() {
+ policy.destroy();
+
+ tabs.open({
+ url: url,
+ inBackground: true,
+ onReady: function (tab2) {
+ assert.equal(tab2.url, url, url);
+ tab2.close(function() tab1.close());
+ }
+ });
+ assert.pass('tab2 opening..');
+ }, 0);
+ return false;
+ }
+ });
+ assert.pass('Content policy is setup');
+
+ setTimeout(function() {
+ tabs.open({
+ url: url,
+ inBackground: true,
+ onOpen: function (tab) {
+ tab1 = tab;
+ assert.equal(tab1.url, 'about:blank', 'tab1 opened - about:blank');
+ },
+ onReady: function() {
+ assert.fail('tab1 loaded..');
+ },
+ onClose: function() {
+ assert.equal(testPageRequests, 1, 'test page was only requested once');
+ //assert.equal(tabsCount, tabs.length, 'all test tabs are closed');
+ loader.unload();
+ done();
+ }
+ });
+
+ assert.pass('tab1 opening..');
+ }, 500);
+};
+
+exports.testContentPolicyUnload = function(assert, done) {
+ const loader = Loader(module);
+ const { ContentPolicy } = loader.require('pathfinder/content/policy');
+ const { setTimeout } = loader.require('sdk/timers');
+
+ let tabsCount = tabs.length;
+ let tab1;
+ let otherTabs = [];
+ let calls = 0;
+ let expectedCalls = 1;
+ let url = 'data:text/html;charset=utf-8,testContentPolicyUnload';
+ let policy = ContentPolicy({
+ contract: '@erikvold.com/content-policy.TEST;unload',
+ shouldLoad: function({ location }) {
+ if (location != url)
+ return true;
+
+ calls++;
+ setTimeout(function() {
+ loader.unload();
+
+ assert.pass('tab2 opening..');
+ tabs.open({
+ url: url,
+ inBackground: true,
+ onOpen: function(tab) {
+ otherTabs.push(tab);
+ },
+ onReady: function (tab2) {
+ assert.equal(tab2.url, url, url);
+ expectedCalls = otherTabs.length;
+
+ // close tabs
+ (function ender() {
+ if (otherTabs.length <= 0)
+ return tab1.close();
+ otherTabs.pop().close();
+ ender(otherTabs);
+ })()
+ }
+ });
+ assert.pass('tab2 open called.');
+ }, 0);
+
+ return false;
+ }
+ });
+ assert.pass('Content policy is setup');
+
+ setTimeout(function() {
+ assert.pass('tab1 opening..');
+ tabs.open({
+ url: url,
+ inBackground: true,
+ onOpen: function (tab) {
+ tab1 = tab;
+ assert.equal(tab1.url, 'about:blank', 'tab1 opened - about:blank');
+ },
+ onReady: function() {
+ assert.fail('tab1 loaded..');
+ },
+ onClose: function() {
+ assert.equal(calls, expectedCalls, 'content policy only rejected expected number of times');
+ //assert.equal(tabsCount, tabs.length, 'all test tabs are closed');
+ done();
+ }
+ });
+ }, 500);
+};
+
+require('test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-download.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-download.js
new file mode 100644
index 0000000..30b4b69
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-download.js
@@ -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';
+
+const { Ci, Cc, Cu } = require('chrome');
+const { pathFor } = require("sdk/system");
+const { Loader } = require("sdk/test/loader");
+const { Request } = require('sdk/request');
+const options = require("@test/options");
+
+const { Download } = require('pathfinder/download');
+
+const { Services } = require('pathfinder/chrome/services');
+
+exports.testDownload = function(assert, done) {
+ const loader = Loader(module);
+ const httpd = loader.require('sdk/test/httpd');
+
+ let serverPort = 8057;
+ let server = httpd.startServerAsync(serverPort);
+ const contents = "testDownload";
+
+ server.registerPathHandler("/test.txt", function handle(request, response) {
+ response.write(contents);
+ });
+
+ let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ file.append("test.txt");
+
+ assert.ok(!file.exists(), 'Download does not exist yet');
+
+ let download = Download({
+ url: "http://localhost:" + serverPort + "/test.txt",
+ destination: file.path,
+ onComplete: function() {
+ assert.ok(file.exists(), 'Download was successful');
+
+ Request({
+ url: Services.io.newFileURI(file).spec,
+ overrideMimeType: "text/plain; charset=latin1",
+ onComplete: function ({ text }) {
+ assert.equal(text, contents, 'the file content is correct');
+ file.remove(false);
+ assert.ok(!file.exists(), 'File was removed');
+
+ server.stop(function() {
+ loader.unload();
+ done();
+ });
+ }
+ }).get();
+ }
+ });
+ assert.ok(!!download, 'Download started');
+}
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-find-suggestion.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-find-suggestion.js
new file mode 100644
index 0000000..18e3de3
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-find-suggestion.js
@@ -0,0 +1,3 @@
+'use strict';
+
+require('pathfinder/ui/findbar/suggestion');
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-listen.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-listen.js
new file mode 100644
index 0000000..0967b4f
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-listen.js
@@ -0,0 +1,152 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { Loader } = require('sdk/test/loader');
+const { getMostRecentBrowserWindow } = require('sdk/window/utils');
+const { open, close, promise: windowPromise } = require('sdk/window/helpers');
+const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+const { listen: gListen } = require('pathfinder/xul/listen');
+
+// from https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent
+function simulateClick(ele) {
+ let window = ele.ownerDocument.defaultView;
+ let { document } = window;
+ var evt = document.createEvent("MouseEvents");
+ evt.initMouseEvent("click", true, true, window,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ ele.dispatchEvent(evt);
+}
+
+function makeEle(window) {
+ window = window || getMostRecentBrowserWindow();
+ let ele = window.document.createElementNS(NS_XUL, 'toolbar');
+ return {
+ window: window,
+ document: window.document,
+ ele: ele
+ }
+}
+
+exports.testSuccessiveListenersCaptureTrue = function(assert, done) {
+ const loader = Loader(module);
+ const { listen } = loader.require('pathfinder/xul/listen');
+ let { window, document, ele } = makeEle();
+ let aHappened = false;
+
+ listen(window, ele, 'click', function() {
+ aHappened = true;
+ }, true);
+ listen(window, ele, 'click', function() {
+ assert.ok(aHappened, 'the first listener attached was the first called.')
+ loader.unload();
+ done();
+ }, true);
+
+ simulateClick(ele);
+}
+
+exports.testSuccessiveListeners = function(assert, done) {
+ const loader = Loader(module);
+ const { listen } = loader.require('pathfinder/xul/listen');
+ let { window, document, ele } = makeEle();
+ let aHappened = false;
+
+ listen(window, ele, 'click', function() {
+ aHappened = true;
+ }, false);
+ listen(window, ele, 'click', function() {
+ assert.ok(aHappened, 'the first listener attached was the first called.')
+ loader.unload();
+ done();
+ }, false);
+
+ simulateClick(ele);
+}
+
+exports.testSuccessiveListenersAcrossLoaders = function(assert, done) {
+ const loader = Loader(module);
+ const { listen } = loader.require('pathfinder/xul/listen');
+ let { window, document, ele } = makeEle();
+ let aHappened = false;
+
+ listen(window, ele, 'click', function() {
+ aHappened = true;
+ }, false);
+ let remover = gListen(window, ele, 'click', function() {
+ assert.ok(aHappened, 'the first listener attached was the first called.');
+ remover();
+ loader.unload();
+ done();
+ }, false);
+
+ simulateClick(ele);
+}
+
+exports.testRemover = function(assert, done) {
+ const loader = Loader(module);
+ const { listen } = loader.require('pathfinder/xul/listen');
+ let { window, document, ele } = makeEle();
+ let aHappened = false;
+
+ let remover1 = listen(window, ele, 'click', function() {
+ aHappened = true;
+ }, false);
+ let remover = gListen(window, ele, 'click', function() {
+ assert.ok(!aHappened, 'the first listener attached was removed');
+ remover();
+ loader.unload();
+ done();
+ }, false);
+
+ remover1();
+ simulateClick(ele);
+}
+
+exports.testWindowUnloadEvent = function(assert, done) {
+ let eHappened = false;
+ let { window, ele: ele1 } = makeEle();
+ let remover2, remover1 = gListen(window, ele1, 'click', function() {
+ assert.ok(!eHappened, 'listeners are removed when parent window unloads');
+ remover1();
+ remover2();
+ done();
+ });
+
+ open().then(function(window) {
+ let { document, ele: ele2 } = makeEle(window);
+
+ remover2 = gListen(window, ele2, 'click', function() {
+ eHappened = true;
+ });
+
+ windowPromise(window, 'unload').then(function() {
+ simulateClick(ele2);
+ simulateClick(ele1);
+ });
+ close(window);
+ });
+}
+
+exports.testListenWorksOnUnload = function(assert, done) {
+ const loader = Loader(module);
+ const { listen } = loader.require('pathfinder/xul/listen');
+ let { window, document, ele } = makeEle();
+
+ listen(window, ele, 'click', function() {
+ assert.fail('should not be here');
+ }, false);
+
+ let remover = gListen(window, ele, 'click', function() {
+ remover();
+ assert.pass('ending listen unload test');
+ done();
+ }, false);
+
+ loader.unload();
+ simulateClick(ele);
+}
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-menuitems.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-menuitems.js
new file mode 100644
index 0000000..db55a36
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-menuitems.js
@@ -0,0 +1,169 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 windowUtils = require('sdk/deprecated/window-utils');
+const menuitems = require('pathfinder/ui/menuitems');
+
+let window = windowUtils.activeBrowserWindow;
+let document = window.document;
+function $(id) document.getElementById(id);
+
+function createMI(options, test) {
+ test.equal(!$(options.id), true);
+ var mi = new menuitems.Menuitem(options);
+ return mi;
+}
+
+exports.testMIDoesNotExist = function(assert) {
+ var options = {
+ id: "test-mi-dne",
+ label: "test"
+ };
+ createMI(options, assert);
+ assert.equal(!!$(options.id), false, 'menuitem does not exists');
+};
+
+exports.testMIDoesExist = function(assert) {
+ var options = {
+ id: "test-mi-exists",
+ label: "test",
+ menuid: 'menu_FilePopup'
+ };
+ let mi = createMI(options, assert);
+ let menuitem = $(options.id);
+ assert.equal(!!menuitem, true, 'menuitem exists');
+ assert.equal(menuitem.id, options.id, 'menuitem id is ok');
+ assert.equal(menuitem.getAttribute('label'), options.label, 'menuitem label is ok');
+ assert.equal(menuitem.parentNode.id, options.menuid, 'in the file menu');
+ assert.equal(menuitem.getAttribute('disabled'), 'false', 'menuitem not disabled');
+ assert.equal(menuitem.getAttribute('accesskey'), '', 'menuitem accesskey is ok');
+ assert.equal(menuitem.getAttribute('class'), '', 'menuitem class is ok');
+ assert.equal(menuitem.nextSibling, undefined, 'menuitem is last');
+ assert.equal(menuitem.hasAttribute("checked"), false, 'menuitem not checked');
+ mi.destroy();
+ assert.ok(!$(options.id), 'menuitem is gone');
+ assert.equal(menuitem.parentNode, null, 'menuitem has no parent');
+};
+
+exports.testMIOnClick = function(assert, done) {
+ let options = {
+ id: "test-mi-onclick",
+ label: "test",
+ menuid: 'menu_FilePopup',
+ onCommand: function() {
+ mi.destroy();
+ assert.pass('onCommand worked!');
+ done();
+ }
+ };
+
+ let e = document.createEvent("UIEvents");
+ e.initUIEvent("command", true, true, window, 1);
+
+ var mi = createMI(options, assert);
+ let menuitem = $(options.id);
+ assert.equal(!!menuitem, true, 'menuitem exists');
+ menuitem.dispatchEvent(e);
+};
+
+exports.testMIDisabled = function(assert, done) {
+ let commandIsOK = false;
+ let count = 0;
+ let options = {
+ id: "test-mi-disabled",
+ label: "test",
+ disabled: true,
+ menuid: 'menu_FilePopup',
+ onCommand: function() {
+ count++;
+ if (!commandIsOK) {
+ assert.fail('onCommand was called, that is not ok');
+ return;
+ }
+
+ mi.destroy();
+ assert.equal(count, 1, 'onCommand was called the correct number of times!');
+ done();
+ }
+ };
+
+ let e = document.createEvent("UIEvents");
+ e.initUIEvent("command", true, true, window, 1);
+
+ var mi = createMI(options, assert);
+ let menuitem = $(options.id);
+ assert.equal(!!menuitem, true, 'menuitem exists');
+ assert.equal(menuitem.getAttribute('disabled'), 'true', 'menuitem not disabled');
+ menuitem.dispatchEvent(e);
+ mi.disabled = false;
+ assert.equal(menuitem.getAttribute('disabled'), 'false', 'menuitem not disabled');
+ commandIsOK = true;
+ menuitem.dispatchEvent(e);
+};
+
+exports.testMIChecked = function(assert) {
+ let options = {
+ id: "test-mi-checked",
+ label: "test",
+ disabled: true,
+ menuid: 'menu_FilePopup',
+ checked: true
+ };
+
+ let mi = createMI(options, assert);
+ let menuitem = $(options.id);
+ assert.equal(!!menuitem, true, 'menuitem exists');
+ assert.equal(menuitem.getAttribute("checked"), "true", 'menuitem checked');
+ mi.checked = false;
+ assert.equal(menuitem.getAttribute("checked"), "false", 'menuitem checked');
+ mi.destroy();
+};
+
+exports.testMIClass = function(assert) {
+ let options = {
+ id: "test-mi-class",
+ label: "pizazz",
+ className: "pizazz",
+ menuid: 'menu_FilePopup',
+ };
+
+ var mi = createMI(options, assert);
+ let menuitem = $(options.id);
+ assert.equal(!!menuitem, true, 'menuitem exists');
+ assert.equal(menuitem.getAttribute('class'), 'pizazz', 'menuitem not disabled');
+ mi.destroy();
+};
+
+exports.testInsertBeforeExists = function(assert) {
+ let options = {
+ id: 'test-mi-insertbefore',
+ label: 'insertbefore',
+ insertbefore:'menu_FileQuitItem',
+ menuid: 'menu_FilePopup',
+ };
+
+ var mi = createMI(options, assert);
+ let menuitem = $(options.id);
+ assert.equal(!!menuitem, true, 'menuitem exists');
+ assert.equal(menuitem.nextSibling, $('menu_FileQuitItem'), 'menuitem not disabled');
+ mi.destroy();
+};
+
+exports.testInsertBeforeDoesNotExist = function(assert) {
+ let options = {
+ id: 'test-mi-insertbefore',
+ label: 'insertbefore',
+ insertbefore:'menu_ZZZDNE',
+ menuid: 'menu_FilePopup',
+ };
+
+ var mi = createMI(options, assert);
+ let menuitem = $(options.id);
+ assert.equal(!!menuitem, true, 'menuitem exists');
+ assert.equal(menuitem.nextSibling, null, 'menuitem not disabled');
+ mi.destroy();
+};
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-panic.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-panic.js
new file mode 100644
index 0000000..49d3a76
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-panic.js
@@ -0,0 +1,103 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 panic = require('pathfinder/panic');
+const prefs = require('sdk/preferences/service');
+const { Loader } = require('sdk/test/loader');
+
+const PREF_END_NAME = 'security.addon.panic_end';
+
+// TEST: the inPanic variable and panic events
+exports.testPanicInPanic = function(assert, done) {
+ assert.equal(panic.inPanic, false, "not in a panic");
+ panic.once('start', function() {
+ assert.pass('"start" event was fired');
+ assert.equal(panic.inPanic, true, "in a panic");
+
+ panic.once('end', function() {
+ assert.pass('"end" event was fired');
+ assert.equal(panic.inPanic, false, "not in a panic");
+
+ done();
+ });
+ });
+
+ panic.panic();
+};
+
+// TEST: on and off methods
+exports.testPanicOnOff = function(assert, done) {
+ let count = 0;
+
+ panic.on('start', function panicOn() {
+ panic.off('start', panicOn);
+ count++;
+
+ panic.once('start', function() {
+ if (count > 1) {
+ assert.fail('panic.on was called too many times');
+ }
+ else {
+ assert.pass('panic.on was only called once');
+ }
+
+ panic.once('end', function() {
+ done();
+ });
+ });
+
+ panic.once('end', function() {
+ panic.panic(50);
+ });
+ });
+
+ panic.panic();
+};
+
+// TEST: panic emits in multiple instances
+exports.testPanicFiresInMultipleInstances = function(assert, done) {
+ let count = 0;
+
+ let loader = Loader(module);
+ let panic2 = loader.require('panic');
+
+ let testCounter = function() {
+ if (++count < 2) return;
+ assert.pass('panic was fired on multiple instances');
+
+ panic.once('end', function() {
+ loader.unload();
+ done();
+ });
+ };
+ panic.once('start', testCounter);
+ panic2.once('start', testCounter);
+
+ panic.panic();
+};
+
+exports.testEndTimestamp = function(assert, done) {
+ let ms = 0;
+ let min = Date.now() + ms;
+ let endTimestamp;
+
+ panic.once('end', function() {
+ let now = Date.now();
+ let max = (now + ms);
+
+ assert.ok(min <= endTimestamp, endTimestamp + ' is gte ' + min);
+ assert.ok(min <= now, now + ' event is gte to ' + min);
+ assert.ok(max >= endTimestamp, 'timestamp is lte to max');
+ assert.ok(max >= now, 'end event is lte to max');
+
+ done();
+ });
+
+ panic.panic(ms);
+
+ endTimestamp = prefs.get(PREF_END_NAME);
+};
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-redirect.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-redirect.js
new file mode 100644
index 0000000..071b09d
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-redirect.js
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 tabs = require('sdk/tabs');
+const { data } = require('sdk/self');
+const { Loader } = require("sdk/test/loader");
+
+const { Redirect } = require('pathfinder/redirect');
+
+function getData(url) {
+ return 'data:text/javascript;charset=utf-8,' + encodeURIComponent(url);
+}
+
+exports.testRedirect = function(assert, done) {
+ const loader = Loader(module);
+ const httpd = loader.require('sdk/test/httpd');
+ const { startServerAsync } = httpd;
+
+ let serverPort = 8058;
+ let server = httpd.startServerAsync(serverPort);
+ const contents = "testRedirect";
+
+ server.registerPathHandler("/test.txt", function handle(request, response) {
+ response.write(contents);
+ });
+
+ let details = {
+ from: 'http://localhost:' + serverPort + '/test.txt',
+ to: getData('exptected')
+ };
+ let redirect = Redirect(JSON.parse(JSON.stringify(details)));
+
+ tabs.open({
+ url: details.from,
+ onReady: function(tab) {
+ assert.equal(tab.url, details.to, 'The final destination is correct!');
+ redirect.destroy();
+
+ server.stop(function() {
+ loader.unload();
+ tab.close(done);
+ });
+ }
+ });
+}
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-about.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-about.js
new file mode 100644
index 0000000..5d7873f
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-about.js
@@ -0,0 +1,43 @@
+'use strict';
+
+const { Loader } = require('sdk/test/loader');
+const tabs = require('sdk/tabs')
+
+function openTabGetContent(url, callback) {
+ tabs.open({
+ url: 'about:test',
+ inBackground: true,
+ onReady: function(tab) {
+ let worker = tab.attach({
+ contentScript: 'self.port.emit("body", document.body.innerHTML)'
+ })
+ worker.port.on('body', function(msg) {
+ tab.close(function() {
+ callback(msg);
+ });
+ });
+ }
+ })
+}
+
+exports.testAddAboutWhat = function(assert, done) {
+ const loader = Loader(module);
+ const { add } = loader.require('pathfinder/scheme/about');
+
+ add({
+ what: 'test',
+ url: 'data:text/html;charset=utf-8,<body>test</body>'
+ });
+
+ openTabGetContent('about:test', function(msg) {
+ assert.equal(msg, 'test', 'about:test content is "test"');
+ loader.unload();
+ openTabGetContent('about:test', function(msg) {
+ assert.notEqual(msg, 'test', 'about:test content is "test"');
+ done();
+ });
+ });
+
+}
+
+require('test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-resource.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-resource.js
new file mode 100644
index 0000000..da6fd3b
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-resource.js
@@ -0,0 +1,3 @@
+'use strict';
+
+require('pathfinder/scheme/resource');
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-storage.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-storage.js
new file mode 100644
index 0000000..14187cd
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-storage.js
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { Loader } = require('sdk/test/loader');
+const { before, after } = require('sdk/test/utils');
+
+const { get, set } = require('pathfinder/storage');
+
+exports.testGetNothing = function(assert, done) {
+ get().then(function({ data }) {
+ assert.equal(data, '', 'the data is blank!');
+ done();
+ });
+};
+
+exports.testSetThenGet = function(assert, done) {
+ const randomData = Math.random() + '';
+
+ // SET TO A RANDOM VALUE
+ set({ data: randomData }).then(function({ data }) {
+ assert.pass('setting was successful');
+ assert.equal(data, randomData, 'the data returned from set is correct [' + randomData + ']');
+ }, function(e) {
+ assert.fail('setting was unsuccessful');
+ assert.fail(e);
+ }).then(function() get()).then(function({ data }) {
+ assert.pass('getting was successful');
+ assert.equal(data, randomData, 'the data returned from get is correct [' + randomData + ']');
+ }, function(e) {
+ assert.fail('getting was unsuccessful');
+ assert.fail(e);
+ })
+ // SET AGAIN
+ .then(function() set({ data: 'test' })).then(function({ data }) {
+ assert.pass('setting was successful');
+ assert.equal(data, 'test', 'the data returned from set is correct [test]');
+ }, function(e) {
+ assert.fail('setting was unsuccessful');
+ assert.fail(e);
+ }).then(function() get()).then(function({ data }) {
+ assert.pass('getting was successful');
+ assert.equal(data, 'test', 'the data returned from get is correct [test]');
+ }, function(e) {
+ assert.fail('getting was unsuccessful');
+ assert.fail(e);
+ }).
+ // SET TO BLANK
+ then(function() set({ data: '' })).then(function({ data }) {
+ assert.pass('setting was successful');
+ assert.equal(data, '', 'the data returned from set is correct');
+ }, function(e) {
+ assert.fail('setting was unsuccessful');
+ assert.fail(e);
+ }).then(function() get()).then(function({ data }) {
+ assert.pass('getting was successful');
+ assert.equal(data, '', 'the data returned from get is correct');
+ }, function(e) {
+ assert.fail('getting was unsuccessful');
+ assert.fail(e);
+ }).
+ // SET TO BLANK AGAIN
+ then(function() set({ data: '' })).then(function({ data }) {
+ assert.pass('setting was successful');
+ assert.equal(data, '', 'the data returned from set is correct');
+ }, function(e) {
+ assert.fail('setting was unsuccessful');
+ assert.fail(e);
+ }).then(function() get()).then(function({ data }) {
+ assert.pass('getting was successful');
+ assert.equal(data, '', 'the data returned from get is correct');
+ }, function(e) {
+ assert.fail('getting was unsuccessful');
+ assert.fail(e);
+ }).then(done, assert.fail);
+};
+
+exports.testSettingJSON = function(assert, done) {
+ const json = JSON.stringify({
+ num: 1,
+ str: 'string',
+ bool: true,
+ obj: { x: 'x' },
+ ary: [ 1, 2, 3 ]
+ });
+
+ set({ data: json }).then(function({ data }) {
+ assert.pass('setting was successful');
+ assert.equal(data, json, 'the data returned from set is correct json');
+ }, function(e) {
+ assert.fail('setting was unsuccessful');
+ assert.fail(e);
+ }).then(function() get()).then(function({ data }) {
+ assert.pass('getting was successful');
+ assert.equal(data, json, 'the data returned from get is correct json');
+ }, function(e) {
+ assert.fail('getting was unsuccessful');
+ assert.fail(e);
+ }).
+ // SET TO BLANK AGAIN
+ then(function() set({ data: '' })).then(function({ data }) {
+ assert.pass('setting was successful');
+ assert.equal(data, '', 'the data returned from set is correct');
+ }, function(e) {
+ assert.fail('setting was unsuccessful');
+ assert.fail(e);
+ }).then(function() get()).then(function({ data }) {
+ assert.pass('getting was successful');
+ assert.equal(data, '', 'the data returned from get is correct');
+ }, function(e) {
+ assert.fail('getting was unsuccessful');
+ assert.fail(e);
+ }).then(done, assert.fail);
+};
+
+before(exports, function(name, assert, done) {
+ let loader = Loader(module);
+ loader.require('pathfinder/storage');
+ let file = loader.sandbox('pathfinder/storage').getStorageFile();
+ assert.pass(file.exists(), false, 'the storage file DNE');
+ loader.unload();
+ done();
+});
+after(exports, function(name, assert, done) {
+ let loader = Loader(module);
+ loader.require('pathfinder/storage');
+ let file = loader.sandbox('pathfinder/storage').getStorageFile();
+ assert.pass(file.exists(), false, 'the storage file DNE');
+ loader.unload();
+ done();
+});
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-toolbarbutton.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-toolbarbutton.js
new file mode 100644
index 0000000..1cfb269
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-toolbarbutton.js
@@ -0,0 +1,165 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 = require("sdk/windows").browserWindows;
+const toolbarbutton = require("pathfinder/ui/toolbarbutton");
+//const { Loader } = require('sdk/test/loader');
+const winUtils = require('sdk/window/utils');
+
+const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+const TEST_ICON_URL = module.uri.replace(/[^\.\\\/]*\.js$/, "test.png");
+const TEST_ICON_BLACK_URL = module.uri.replace(/[^\.\\\/]*\.js$/, "black.png");
+
+function $(id) winUtils.getMostRecentBrowserWindow().document.getElementById(id);
+
+function createToolbarButton(options, test) {
+ test.assertEqual(!$(options.id), true);
+
+ var tbb = toolbarbutton.ToolbarButton(options);
+ test.assertEqual(!$(options.id), true);
+
+ tbb.moveTo(options);
+ if (options.toolbarID)
+ test.assertEqual(!$(options.id), false);
+
+ return tbb;
+}
+
+function buttonExists(button, options, test) {
+ test.assertEqual(!button, false, 'test button');
+ test.assertEqual(button.parentNode, $(options.toolbarID), 'test parent');
+ test.assertEqual(button.id, options.id, 'test id');
+ if (options.label)
+ test.assertEqual(button.label, options.label, 'test label');
+ if (options.image)
+ test.assertEqual(button.image, options.image);
+ else
+ test.assertEqual(button.image, "");
+}
+
+exports.testTBBExists = function(test) {
+ var options = {
+ id: "test-tbb",
+ label: "test",
+ toolbarID: "nav-bar",
+ forceMove: true
+ };
+
+ var tbb = createToolbarButton(options, test);
+ buttonExists($(options.id), options, test);
+ tbb.destroy();
+ test.assertEqual(!$(options.id), true);
+ var tbb = createToolbarButton(options, test);
+ tbb.destroy();
+};
+
+exports.testTBBDoesNotExist = function(test) {
+ var options = {
+ id: "test-tbb2",
+ label: "test"
+ };
+ var tbb = createToolbarButton(options, test);
+ var tbbEle = $(options.id);
+ test.assertEqual(!tbbEle, true, 'toolbar button dne');
+ tbb.destroy();
+};
+
+exports.testTBBLabelChange = function(test) {
+ test.waitUntilDone();
+
+ var options = {
+ id: "test-tbb3",
+ label: "test",
+ toolbarID: "nav-bar",
+ forceMove: true
+ };
+
+ let tbb = createToolbarButton(options, test);
+ buttonExists($(options.id), options, test);
+ tbb.label = 'test change';
+ test.assertEqual($(options.id).label, 'test change', 'the label is changed');
+ test.assertEqual(tbb.label, 'test change', 'the label is changed');
+
+ tbb.destroy();
+ test.done();
+};
+
+exports.testTBBPropertyChange = function(test) {
+ test.waitUntilDone();
+
+ var options = {
+ id: "test-tbb4",
+ label: "test",
+ toolbarID: "nav-bar",
+ forceMove: true,
+ image: TEST_ICON_URL,
+ tooltiptext: 'a'
+ };
+
+ let tbb = createToolbarButton(options, test);
+ buttonExists($(options.id), options, test);
+ test.assertEqual($(options.id).image, TEST_ICON_URL, 'the image is correct');
+ test.assertEqual(tbb.image, TEST_ICON_URL, 'the image is correct');
+ test.assertEqual(tbb.tooltiptext, 'a', 'the tooltiptext is correct');
+ tbb.setIcon({url: TEST_ICON_BLACK_URL});
+ test.assertEqual($(options.id).image, TEST_ICON_BLACK_URL, 'the image is changed');
+ test.assertEqual(tbb.image, TEST_ICON_BLACK_URL, 'the image is changed');
+ tbb.tooltiptext = 'b';
+ test.assertEqual($(options.id).getAttribute('tooltiptext'), 'b', 'the tooltiptext is changed');
+ test.assertEqual(tbb.tooltiptext, 'b', 'the tooltiptext is changed');
+
+ tbb.destroy();
+ test.done();
+};
+
+exports.testTBBIteratorWithNonBrowserWindow = function(test) {
+ test.waitUntilDone();
+
+ let scratchpad = winUtils.getMostRecentBrowserWindow().Scratchpad.openScratchpad();
+ let options = {
+ id: "test-tbb5",
+ label: "TEST",
+ toolbarID: "nav-bar",
+ image: TEST_ICON_URL
+ };
+ windows.open({
+ onOpen: function(window) {
+ let tbb = createToolbarButton(options, test);
+ test.assertEqual(windows.length, 2);
+
+ scratchpad.close();
+ tbb.destroy();
+ window.close(function() test.done());
+ }
+ })
+};
+
+exports.testTBBIterator2 = function(test) {
+ test.waitUntilDone();
+
+ let window1 = winUtils.getMostRecentBrowserWindow();
+ let options = {
+ id: "test-tbb6",
+ label: "TEST",
+ toolbarID: "nav-bar",
+ image: TEST_ICON_URL
+ };
+ let button = window1.document.createElementNS(NS_XUL, "toolbarbutton");
+ button.setAttribute('id', options.id);
+ window1.document.getElementById(options.toolbarID).appendChild(button);
+ test.assert(!!$(options.id));
+
+ windows.open({
+ onOpen: function(window) {
+ let tbb = createToolbarButton(options, test);
+ test.assertEqual(windows.length, 2);
+
+ tbb.destroy();
+ button.parentNode.removeChild(button);
+ window.close(function() test.done());
+ }
+ })
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-unload+.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-unload+.js
new file mode 100644
index 0000000..edb9dff
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-unload+.js
@@ -0,0 +1,150 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 timer = require("sdk/timers");
+var { Cc,Ci } = require("chrome");
+const windowUtils = require("sdk/deprecated/window-utils");
+const { Loader } = require('sdk/test/loader');
+
+function makeEmptyWindow() {
+ var xulNs = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ var blankXul = ('<?xml version="1.0"?>' +
+ '<?xml-stylesheet href="chrome://global/skin/" ' +
+ ' type="text/css"?>' +
+ '<window xmlns="' + xulNs + '">' +
+ '</window>');
+ var url = "data:application/vnd.mozilla.xul+xml," + escape(blankXul);
+ var features = ["chrome", "width=10", "height=10"];
+
+ var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
+ .getService(Ci.nsIWindowWatcher);
+ return ww.openWindow(null, url, null, features.join(","), null);
+}
+
+exports.testUnloading = function(assert) {
+ var loader = Loader(module);
+ var {unload} = loader.require("pathfinder/addon/unload");
+ var unloadCalled = 0;
+
+ function unloader() {
+ unloadCalled++;
+ }
+ unload(unloader);
+
+ function unloader2() unloadCalled++;
+ var removeUnloader2 = unload(unloader2);
+
+ function unloader3() unloadCalled++;
+ unload(unloader3);
+
+ // remove unloader2
+ removeUnloader2();
+
+ loader.unload();
+
+ assert.equal(unloadCalled, 2, "Unloader functions are called on unload.");
+};
+
+exports.testUnloadingWindow = function(assert, done) {
+ var loader = Loader(module);
+ var {unload} = loader.require("pathfinder/addon/unload");
+ var unloadCalled = 0;
+ var finished = false;
+ var myWindow;
+
+ var delegate = {
+ onTrack: function(window) {
+ if (window == myWindow) {
+ assert.pass("onTrack() called with our test window");
+
+ let unloader = function unloader() {
+ unloadCalled++;
+ }
+ unload(unloader, window);
+ unload(unloader);
+
+ timer.setTimeout(function() {
+ window.close();
+
+ assert.equal(unloadCalled, 1, "unloader was still called.");
+
+ if (window.closed) {
+ assert.pass("window closed");
+ }
+ else {
+ assert.fail("window is not closed!");
+ }
+
+ timer.setTimeout(function() {
+ assert.equal(unloadCalled, 1, "unloader was called.");
+
+ unload(function() {
+ assert.equal(unloadCalled, 2, "two unloaders called.");
+
+ if (finished) {
+ assert.pass("finished");
+ done();
+ }
+ else {
+ assert.fail("not finished!");
+ }
+ });
+
+ loader.unload();
+ }, 1);
+ }, 1);
+ }
+ },
+ onUntrack: function(window) {
+ if (window == myWindow) {
+ assert.pass("onUntrack() called with our test window");
+
+ if (!finished) {
+ finished = true;
+ myWindow = null;
+ wt.unload();
+ }
+ else {
+ assert.fail("finishTest() called multiple times.");
+ }
+ }
+ }
+ };
+
+ var wt = new windowUtils.WindowTracker(delegate);
+ myWindow = makeEmptyWindow();
+};
+
+exports.testUnloaderExecutionOnWindowClose = function(assert, done) {
+ var loader = Loader(module);
+ var {unload} = loader.require("pathfinder/addon/unload");
+ var unloadCalled = 0;
+ var finished = false;
+ var myWindow;
+ var unloaderRan = false;
+
+ var delegate = {
+ onTrack: function(window) {
+ if (window != myWindow) return;
+
+ unload(function() unloaderRan = true, window);
+ window.close();
+ },
+ onUntrack: function(window) {
+ if (window != myWindow) return;
+
+ loader.require('sdk/timers').setTimeout(function() {
+ assert.ok(unloaderRan, 'test complete');
+ loader.unload();
+ done();
+ }, 0);
+ }
+ };
+
+ var wt = new windowUtils.WindowTracker(delegate);
+ myWindow = makeEmptyWindow();
+};
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userscripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userscripts.js
new file mode 100644
index 0000000..e43199c
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userscripts.js
@@ -0,0 +1,8 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.css
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.js
new file mode 100644
index 0000000..50b741e
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.js
@@ -0,0 +1,116 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { Loader } = require('sdk/test/loader');
+
+const userstyles = require('userstyles');
+
+const TEST_CSS_URL = module.uri.replace(/\.js$/, '.css');
+const TEST_FNF_URL = module.uri.replace(/\.js$/, '.x.css');
+
+// TEST: userstyles.load
+exports.testLoad = function(assert) {
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.');
+
+ userstyles.load(TEST_CSS_URL);
+ assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.');
+
+ userstyles.unload(TEST_CSS_URL);
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was unregistered.');
+};
+
+// TEST: userstyles.load file not found
+exports.testLoadFNF = function(assert) {
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is not registered.');
+
+ try {
+ userstyles.load(TEST_FNF_URL);
+ assert.fail('trying to load a file that does not exist should throw an error');
+ }
+ catch(e) {
+ assert.pass('trying to load a file that does not exist throws an error');
+ }
+
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was not registered.');
+};
+
+// TEST: userstyles.load for 'agent' type
+exports.testLoadAgent = function(assert) {
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is not registered.');
+ assert.equal(userstyles.registered(TEST_CSS_URL, {type: 'agent'}), false, 'css is not registered.');
+
+ userstyles.load(TEST_CSS_URL, {type: 'AgeNt'});
+ assert.ok(userstyles.registered(TEST_CSS_URL, {type: 'AGENT'}), 'css was registered.');
+
+ try {
+ userstyles.unload(TEST_CSS_URL);
+ assert.fail('unregister did not throw an error');
+ }
+ catch(e) {
+ assert.pass('unregister did throw an error');
+ }
+ assert.equal(userstyles.registered(TEST_CSS_URL, {type: 'agent'}), true, 'css was not unregistered.');
+
+ userstyles.unload(TEST_CSS_URL, {type: 'agent'});
+ assert.equal(userstyles.registered(TEST_CSS_URL, {type: 'agent'}), false, 'css was unregistered.');
+};
+
+exports.testUnload = function(assert) {
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.');
+ let loader = Loader(module);
+
+ loader.require('userstyles').load(TEST_CSS_URL);
+ assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.');
+
+ loader.unload();
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was unregistered.');
+}
+
+exports.testUnloadWithMultipleLoads = function(assert) {
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.');
+ let loader = Loader(module);
+
+ // first load
+ loader.require('userstyles').load(TEST_CSS_URL);
+ assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.');
+
+ // now unload
+ loader.require('userstyles').unload(TEST_CSS_URL);
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.');
+
+ // now load again
+ loader.require('userstyles').load(TEST_CSS_URL);
+ assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.');
+
+ // send addon unload message and see if we fail
+ loader.unload();
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.');
+}
+
+exports.testUnloadWithMultipleLoaders = function(assert) {
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.');
+ let loader = Loader(module);
+
+ // first load
+ loader.require('userstyles').load(TEST_CSS_URL);
+ assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.');
+
+ // now unload
+ loader.require('userstyles').unload(TEST_CSS_URL);
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.');
+
+ // now load again
+ userstyles.load(TEST_CSS_URL);
+ assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.');
+
+ // send addon unload message and see if we fail
+ loader.unload();
+ assert.equal(userstyles.registered(TEST_CSS_URL), true, 'css is still registered.');
+
+ userstyles.unload(TEST_CSS_URL);
+ assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was unregistered.');
+}
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-web-panel.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-web-panel.js
new file mode 100644
index 0000000..e97779a
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-web-panel.js
@@ -0,0 +1,563 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If 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 { Loader } = require('sdk/test/loader');
+const { getMostRecentBrowserWindow } = require('sdk/window/utils');
+const { open, close, focus, promise: windowPromise } = require('sdk/window/helpers');
+const { setTimeout } = require('sdk/timers');
+const { isPrivate } = require('sdk/private-browsing');
+const { data } = require('sdk/self');
+const { fromIterator } = require('sdk/util/array');
+const { URL } = require('sdk/url');
+
+const { WebPanel } = require('pathfinder/ui/web-panel');
+const { show, hide } = require('pathfinder/ui/sidebar/actions');
+const { isShowing } = require('pathfinder/ui/sidebar/state');
+
+const BUILTIN_SIDEBAR_MENUITEMS = [
+ 'menu_socialSidebar',
+ 'menu_historySidebar',
+ 'menu_bookmarksSidebar'
+];
+
+const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
+
+function isSidebarShowing(window) {
+ window = window || getMostRecentBrowserWindow();
+ let sidebar = window.document.getElementById('sidebar-box');
+ return !sidebar.hidden;
+}
+
+function getSidebarMenuitems(window) {
+ window = window || getMostRecentBrowserWindow();
+ return fromIterator(window.document.querySelectorAll('#viewSidebarMenu menuitem'));
+}
+
+function getExtraSidebarMenuitems() {
+ let menuitems = getSidebarMenuitems();
+ return menuitems.filter(function(mi) {
+ return BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) < 0;
+ });
+}
+
+function makeID(id) {
+ return 'pathfinder-sidebar-' + id;
+}
+
+function simulateClick(ele) {
+ let window = ele.ownerDocument.defaultView;
+ let { document } = window;
+ var evt = document.createEvent("XULCommandEvent");
+ evt.initCommandEvent("command", true, true, window,
+ 0, false, false, false, false, null);
+ ele.dispatchEvent(evt);
+}
+
+exports.testSidebarBasicLifeCycle = function(assert, done) {
+ let testName = 'testSidebarBasicLifeCycle';
+ let window = getMostRecentBrowserWindow();
+ assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE');
+ let sidebarXUL = window.document.getElementById('sidebar');
+ assert.ok(sidebarXUL, 'sidebar xul element does exist');
+ assert.ok(!getExtraSidebarMenuitems().length, 'there are no extra sidebar menuitems');
+
+ assert.equal(isSidebarShowing(window), false, 'sidebar is not showing 1');
+ let sidebarDetails = {
+ id: testName,
+ title: 'test',
+ url: 'data:text/html;charset=utf-8,'+testName
+ };
+ let sidebar = WebPanel(sidebarDetails);
+
+ // test the sidebar attributes
+ for each(let key in Object.keys(sidebarDetails)) {
+ assert.equal(sidebarDetails[key], sidebar[key], 'the attributes match the input');
+ }
+
+ assert.pass('The Sidebar constructor worked');
+
+ let extraMenuitems = getExtraSidebarMenuitems();
+ assert.equal(extraMenuitems.length, 1, 'there is one extra sidebar menuitems');
+
+ let ele = window.document.getElementById(makeID(testName));
+ assert.equal(ele, extraMenuitems[0], 'the only extra menuitem is the one for our sidebar.')
+ assert.ok(ele, 'sidebar element was added');
+ assert.ok(ele.getAttribute('checked'), 'false', 'the sidebar is not displayed');
+ assert.equal(ele.getAttribute('label'), sidebar.title, 'the sidebar title is the menuitem label')
+
+ assert.equal(isSidebarShowing(window), false, 'sidebar is not showing 2');
+ sidebar.on('show', function() {
+ assert.pass('the show event was fired');
+ assert.equal(isSidebarShowing(window), true, 'sidebar is not showing 3');
+ assert.equal(isShowing(sidebar), true, 'the sidebar is showing');
+ assert.equal(ele.getAttribute('checked'), 'true', 'the sidebar is displayed');
+
+ sidebar.once('hide', function() {
+ assert.pass('the hide event was fired');
+ assert.equal(ele.getAttribute('checked'), 'false', 'the sidebar menuitem is not checked');
+ assert.equal(isShowing(sidebar), false, 'the sidebar is not showing');
+ assert.equal(isSidebarShowing(window), false, 'the sidebar elemnt is hidden');
+
+ sidebar.once('detach', function() {
+ sidebar.destroy();
+
+ let sidebarMI = getSidebarMenuitems();
+ for each (let mi in sidebarMI) {
+ assert.ok(BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) >= 0, 'the menuitem is for a built-in sidebar')
+ assert.equal(mi.getAttribute('checked'), "false", 'no sidebar menuitem is checked');
+ }
+
+ assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE');
+ assert.pass('calling destroy worked without error');
+
+ done();
+ });
+ });
+
+ sidebar.hide();
+ assert.pass('hiding sidebar..');
+ });
+
+ sidebar.show();
+ assert.pass('showing sidebar..');
+}
+
+exports.testSideBarIsInNewWindows = function(assert, done) {
+ let testName = 'testSideBarOnNewWindow';
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+testName
+ });
+
+ let startWindow = getMostRecentBrowserWindow();
+ let ele = startWindow.document.getElementById(makeID(testName));
+ assert.ok(ele, 'sidebar element was added');
+
+ open().then(function(window) {
+ let ele = window.document.getElementById(makeID(testName));
+ assert.ok(ele, 'sidebar element was added');
+
+ sidebar.destroy();
+ assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE');
+ assert.ok(!startWindow.document.getElementById(makeID(testName)), 'sidebar id DNE');
+
+ close(window).then(done, assert.fail);
+ })
+}
+
+exports.testSideBarIsNotInNewPrivateWindows = function(assert, done) {
+ let testName = 'testSideBarOnNewWindow';
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+testName
+ });
+
+ let startWindow = getMostRecentBrowserWindow();
+ let ele = startWindow.document.getElementById(makeID(testName));
+ assert.ok(ele, 'sidebar element was added');
+
+ open(null, { features: { private: true } }).then(function(window) {
+ let ele = window.document.getElementById(makeID(testName));
+ assert.ok(isPrivate(window), 'the new window is private');
+ assert.equal(ele, null, 'sidebar element was not added');
+
+ sidebar.destroy();
+ assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE');
+ assert.ok(!startWindow.document.getElementById(makeID(testName)), 'sidebar id DNE');
+
+ close(window).then(done, assert.fail);
+ })
+}
+
+exports.testSideBarIsShowingInNewWindows = function(assert, done) {
+ let testName = 'testSideBarIsShowingInNewWindows';
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: URL('data:text/html;charset=utf-8,'+testName)
+ });
+
+ let startWindow = getMostRecentBrowserWindow();
+ let ele = startWindow.document.getElementById(makeID(testName));
+ assert.ok(ele, 'sidebar element was added');
+
+ let oldEle = ele;
+ sidebar.once('show', function() {
+ assert.pass('show event fired');
+
+ sidebar.once('attach', function() {
+ assert.pass('attach event fired');
+
+ sidebar.once('show', function() {
+ let window = getMostRecentBrowserWindow();
+ assert.notEqual(startWindow, window, 'window is new');
+
+ let sb = window.document.getElementById('sidebar');
+ if (sb && sb.docShell && sb.contentDocument && sb.contentDocument.getElementById('web-panels-browser')) {
+ end();
+ }
+ else {
+ sb.addEventListener('DOMWindowCreated', end, false);
+ }
+
+ function end() {
+ sb.removeEventListener('DOMWindowCreated', end, false);
+ let webPanelBrowser = sb.contentDocument.getElementById('web-panels-browser');
+
+ let ele = window.document.getElementById(makeID(testName));
+
+ assert.ok(ele, 'sidebar element was added 2');
+ assert.equal(ele.getAttribute('checked'), 'true', 'the sidebar is checked');
+ assert.notEqual(ele, oldEle, 'there are two different sidebars');
+
+ assert.equal(isShowing(sidebar), true, 'the sidebar is showing in new window');
+
+ webPanelBrowser.contentWindow.addEventListener('load', function onload() {
+ webPanelBrowser.contentWindow.addEventListener('load', onload, false);
+
+ sidebar.destroy();
+
+ assert.equal(isShowing(sidebar), false, 'the sidebar is not showing');
+ assert.ok(!isSidebarShowing(window), 'sidebar in most recent window is not showing');
+ assert.ok(!isSidebarShowing(startWindow), 'sidebar in most start window is not showing');
+ assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE');
+ assert.ok(!startWindow.document.getElementById(makeID(testName)), 'sidebar id DNE');
+
+ setTimeout(function() {
+ close(window).then(done, assert.fail);
+ });
+ }, false);
+ }
+ });
+
+ startWindow.OpenBrowserWindow();
+ });
+ });
+
+ show(sidebar);
+ assert.pass('showing the sidebar');
+}
+
+exports.testShowingOneSidebarAfterAnother = function(assert, done) {
+ let testName = 'testShowingOneSidebarAfterAnother';
+
+ let sidebar1 = WebPanel({
+ id: testName + '1',
+ title: testName + '1',
+ url: 'data:text/html;charset=utf-8,'+ testName + 1
+ });
+ let sidebar2 = WebPanel({
+ id: testName + '2',
+ title: testName + '2',
+ url: 'data:text/html;charset=utf-8,'+ testName + 2
+ });
+
+ let window = getMostRecentBrowserWindow();
+ let IDs = [ sidebar1.id, sidebar2.id ];
+
+ let extraMenuitems = getExtraSidebarMenuitems(window);
+ assert.equal(extraMenuitems.length, 2, 'there are two extra sidebar menuitems');
+
+ function testShowing(sb1, sb2, sbEle) {
+ assert.equal(isShowing(sidebar1), sb1);
+ assert.equal(isShowing(sidebar2), sb2);
+ assert.equal(isSidebarShowing(window), sbEle);
+ }
+ testShowing(false, false, false);
+
+ sidebar1.once('show', function() {
+ testShowing(true, false, true);
+ for each (let mi in getExtraSidebarMenuitems(window)) {
+ let menuitemID = mi.getAttribute('id').replace(/^pathfinder-sidebar-/, '');
+ assert.ok(IDs.indexOf(menuitemID) >= 0, 'the extra menuitem is for one of our test sidebars');
+ assert.equal(mi.getAttribute('checked'), menuitemID == sidebar1.id ? 'true' : 'false', 'the test sidebar menuitem has the correct checked value');
+ }
+
+ sidebar2.once('show', function() {
+ testShowing(false, true, true);
+ for each (let mi in getExtraSidebarMenuitems(window)) {
+ let menuitemID = mi.getAttribute('id').replace(/^pathfinder-sidebar-/, '');
+ assert.ok(IDs.indexOf(menuitemID) >= 0, 'the extra menuitem is for one of our test sidebars');
+ assert.equal(mi.getAttribute('checked'), menuitemID == sidebar2.id ? 'true' : 'false', 'the test sidebar menuitem has the correct checked value');
+ }
+
+ sidebar1.destroy();
+ sidebar2.destroy();
+
+ testShowing(false, false, false);
+
+ done();
+ });
+
+ show(sidebar2);
+ assert.pass('showing sidebar 2');
+ })
+ show(sidebar1);
+ assert.pass('showing sidebar 1');
+}
+
+exports.testSidebarUnload = function(assert, done) {
+ let loader = Loader(module);
+
+ let testName = 'testSidebarUnload';
+ let window = getMostRecentBrowserWindow();
+
+ assert.equal(isPrivate(window), false, 'the current window is not private');
+
+ let sidebar = loader.require('pathfinder/ui/web-panel').WebPanel({
+ id: testName,
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+ testName,
+ onShow: function() {
+ assert.pass('onShow works for Sidebar');
+ loader.unload();
+
+ let sidebarMI = getSidebarMenuitems();
+ for each (let mi in sidebarMI) {
+ assert.ok(BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) >= 0, 'the menuitem is for a built-in sidebar')
+ assert.equal(mi.getAttribute('checked'), 'false', 'no sidebar menuitem is checked');
+ }
+ assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE');
+ assert.equal(isSidebarShowing(window), false, 'the sidebar is not showing');
+
+ done();
+ }
+ })
+
+ sidebar.show();
+ assert.pass('showing the sidebar');
+}
+
+exports.testRemoteContent = function(assert) {
+ let testName = 'testRemoteContent';
+ try {
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: 'http://dne.xyz.mozilla.org'
+ });
+ assert.ok('the web panel was created!');
+ sidebar.destroy();
+ }
+ catch(e) {
+ assert.fail('sidebar was not created..');
+ }
+}
+
+exports.testInvalidURL = function(assert) {
+ let testName = 'testInvalidURL';
+ try {
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: 'http:mozilla.org'
+ });
+ assert.pass('remote uris are fine');
+ sidebar.destroy();
+ }
+ catch(e) {
+ assert.ok(/The option "url" must be a valid URI./.test(e), 'invalid URIs are not acceptable');
+ }
+}
+
+exports.testInvalidURLType = function(assert) {
+ let testName = 'testInvalidURLType';
+ try {
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName
+ });
+ assert.fail('a bad sidebar was created..');
+ sidebar.destroy();
+ }
+ catch(e) {
+ assert.ok(/The option "url" must be a valid URI./.test(e), 'invalid URIs are not acceptable');
+ }
+}
+
+exports.testInvalidTitle = function(assert) {
+ let testName = 'testInvalidTitle';
+ try {
+ let sidebar = WebPanel({
+ id: testName,
+ title: '',
+ url: 'data:text/html;charset=utf-8,'+testName
+ });
+ assert.fail('a bad sidebar was created..');
+ sidebar.destroy();
+ }
+ catch(e) {
+ assert.equal('The option "title" must be one of the following types: string', e.message, 'invalid titles are not acceptable');
+ }
+}
+
+exports.testInvalidID = function(assert) {
+ let testName = 'testInvalidTitle';
+ try {
+ let sidebar = WebPanel({
+ id: '!',
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+testName
+ });
+ assert.fail('a bad sidebar was created..');
+ sidebar.destroy();
+ }
+ catch(e) {
+ assert.ok(/The option "id" must be a valid alphanumeric id/.test(e), 'invalid ids are not acceptable');
+ }
+}
+
+exports.testSidebarIsNotOpenInNewPrivateWindow = function(assert, done) {
+ let testName = 'testSidebarIsNotOpenInNewPrivateWindow';
+ let window = getMostRecentBrowserWindow();
+
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+testName
+ });
+
+ sidebar.on('show', function() {
+ assert.equal(isPrivate(window), false, 'the new window is not private');
+ assert.equal(isSidebarShowing(window), true, 'the sidebar is showing');
+ assert.equal(isShowing(sidebar), true, 'the sidebar is showing');
+
+ let window2 = window.OpenBrowserWindow({private: true});
+ windowPromise(window2, 'load').then(focus).then(function() {
+ // TODO: find better alt to setTimeout...
+ setTimeout(function() {
+ assert.equal(isPrivate(window2), true, 'the new window is private');
+ assert.equal(isSidebarShowing(window), true, 'the sidebar is showing in old window still');
+ assert.equal(isSidebarShowing(window2), false, 'the sidebar is not showing in the new private window');
+ assert.equal(isShowing(sidebar), false, 'the sidebar is not showing');
+ sidebar.destroy();
+ close(window2).then(done);
+ }, 500)
+ })
+ });
+
+ sidebar.show();
+}
+
+// TEST: edge case where web panel is destroyed while loading
+exports.testDestroyEdgeCaseBug = function(assert, done) {
+ let testName = 'testDestroyEdgeCaseBug';
+ let window = getMostRecentBrowserWindow();
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+testName
+ });
+
+ // NOTE: purposely not listening to show event b/c the event happens
+ // between now and then.
+ sidebar.show();
+
+ assert.equal(isPrivate(window), false, 'the new window is not private');
+ assert.equal(isSidebarShowing(window), true, 'the sidebar is showing');
+
+ //assert.equal(isShowing(sidebar), true, 'the sidebar is showing');
+
+ open(null, { features: { private: true } }).then(focus).then(function(window2) {
+ assert.equal(isPrivate(window2), true, 'the new window is private');
+ assert.equal(isSidebarShowing(window2), false, 'the sidebar is not showing');
+ assert.equal(isShowing(sidebar), false, 'the sidebar is not showing');
+
+ sidebar.destroy();
+ assert.pass('destroying the sidebar');
+
+ close(window2).then(function() focus(window)).then(function(window) {
+ let loader = Loader(module);
+
+ assert.equal(window, getMostRecentBrowserWindow(), 'window is current window');
+ assert.equal(isPrivate(window), false, 'the current window is not private!');
+
+ let sidebar = loader.require('pathfinder/ui/web-panel').WebPanel({
+ id: testName,
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+ testName,
+ onShow: function() {
+ assert.pass('onShow works for Sidebar');
+ loader.unload();
+
+ let sidebarMI = getSidebarMenuitems();
+ for each (let mi in sidebarMI) {
+ assert.ok(BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) >= 0, 'the menuitem is for a built-in sidebar')
+ assert.equal(mi.getAttribute('checked'), 'false', 'no sidebar menuitem is checked');
+ }
+ assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE');
+ assert.equal(isSidebarShowing(window), false, 'the sidebar is not showing');
+
+ done();
+ }
+ })
+
+ assert.pass('showing the sidebar1');
+ sidebar.show();
+ assert.pass('showing the sidebar2');
+
+ });
+ });
+}
+
+exports.testClickingACheckedMenuitem = function(assert, done) {
+ let testName = 'testClickingACheckedMenuitem';
+ let window = getMostRecentBrowserWindow();
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: 'data:text/html;charset=utf-8,'+testName,
+ onShow: function() {
+ sidebar.once('hide', function() {
+ assert.pass('clicking the menuitem after the sidebar has shown hides it.');
+ sidebar.destroy();
+ done();
+ });
+ let menuitem = window.document.getElementById(makeID(sidebar.id));
+ simulateClick(menuitem);
+ }
+ });
+
+ sidebar.show();
+}
+
+exports.testAddonGlobalDNE = function(assert, done) {
+ let testName = 'testAddonGlobal';
+ let url = 'data:text/html;charset=utf-8,'+encodeURIComponent('<script>window.addEventListener("message", function() window.postMessage({ addon: !!window.addon }, "*"), false)</script>');
+ let sidebar = WebPanel({
+ id: testName,
+ title: testName,
+ url: url
+ });
+
+ sidebar.on('attach', function(worker) {
+ assert.pass('sidebar was attached');
+ assert.ok(!!worker, 'attach event has worker');
+
+ let sidebarXUL = getMostRecentBrowserWindow().document.getElementById('sidebar');
+ let window = sidebarXUL.contentDocument.getElementById(WEB_PANEL_BROWSER_ID).contentWindow;
+
+ window.addEventListener('load', function() {
+ let count = 0;
+ window.addEventListener('message', function({ data: msg }) {
+ if (++count != 2) return;
+
+ assert.equal(msg.addon, false, 'the addon global DNE');
+
+ sidebar.destroy();
+
+ done();
+ }, false);
+ window.postMessage('', '*');
+ }, false);
+
+ });
+
+ show(sidebar);
+}
+
+require('sdk/test').run(exports);
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test.png
new file mode 100644
index 0000000..5469a50
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test.png
Binary files differ