From 75139375b76cb277546da2429d8e983ca6758f61 Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Wed, 2 Jan 2013 14:56:40 -0800 Subject: added addon-sdk-1.7, without any changes --- tools/addon-sdk-1.7/LICENSE | 30 + tools/addon-sdk-1.7/README | 36 + tools/addon-sdk-1.7/bin/activate | 86 + tools/addon-sdk-1.7/bin/activate.bat | 135 + tools/addon-sdk-1.7/bin/activate.ps1 | 99 + tools/addon-sdk-1.7/bin/cfx | 33 + tools/addon-sdk-1.7/bin/cfx.bat | 6 + tools/addon-sdk-1.7/bin/deactivate.bat | 23 + .../integration-scripts/buildbot-run-cfx-helper | 14 + .../bin/integration-scripts/integration-check | 364 ++ tools/addon-sdk-1.7/examples/annotator/README.md | 46 + .../annotator/data/annotation/annotation.html | 31 + .../annotator/data/annotation/annotation.js | 11 + .../annotator/data/editor/annotation-editor.html | 39 + .../annotator/data/editor/annotation-editor.js | 23 + .../examples/annotator/data/jquery-1.4.2.min.js | 154 + .../annotator/data/list/annotation-list.css | 40 + .../annotator/data/list/annotation-list.html | 26 + .../annotator/data/list/annotation-list.js | 31 + .../examples/annotator/data/matcher.js | 50 + .../examples/annotator/data/selector.js | 73 + .../examples/annotator/data/widget/pencil-off.png | Bin 0 -> 1740 bytes .../examples/annotator/data/widget/pencil-on.png | Bin 0 -> 2054 bytes .../examples/annotator/data/widget/widget.js | 17 + tools/addon-sdk-1.7/examples/annotator/lib/main.js | 294 ++ .../addon-sdk-1.7/examples/annotator/package.json | 9 + .../examples/annotator/tests/test-main.js | 7 + .../examples/library-detector/README.md | 13 + .../library-detector/data/icons/closure.ico | Bin 0 -> 1150 bytes .../library-detector/data/icons/jquery.ico | Bin 0 -> 3638 bytes .../library-detector/data/icons/jquery_ui.ico | Bin 0 -> 1150 bytes .../library-detector/data/icons/modernizr.ico | Bin 0 -> 1150 bytes .../library-detector/data/icons/mootools.png | Bin 0 -> 386 bytes .../examples/library-detector/data/icons/yui.ico | Bin 0 -> 6598 bytes .../library-detector/data/library-detector.js | 97 + .../examples/library-detector/data/widget.js | 14 + .../examples/library-detector/lib/main.js | 107 + .../examples/library-detector/package.json | 9 + .../examples/library-detector/test/test-main.js | 7 + .../examples/reading-data/data/mom.png | Bin 0 -> 4778 bytes .../examples/reading-data/data/sample.html | 7 + .../examples/reading-data/lib/main.js | 44 + .../examples/reading-data/package.json | 9 + .../examples/reading-data/tests/test-main.js | 24 + .../addon-sdk-1.7/examples/reddit-panel/README.md | 14 + .../examples/reddit-panel/data/jquery-1.4.4.min.js | 167 + .../examples/reddit-panel/data/panel.js | 35 + .../examples/reddit-panel/lib/main.js | 31 + .../examples/reddit-panel/package.json | 9 + .../examples/reddit-panel/tests/test-main.js | 21 + tools/addon-sdk-1.7/packages/addon-kit/README.md | 12 + .../packages/addon-kit/data/index.html | 12 + .../packages/addon-kit/data/moz_favicon.ico | Bin 0 -> 1406 bytes .../addon-kit/data/pagemod-css-include-file.css | 1 + .../packages/addon-kit/data/test-context-menu.js | 5 + .../packages/addon-kit/data/test-page-mod.html | 12 + .../packages/addon-kit/data/test-page-worker.html | 12 + .../packages/addon-kit/data/test-page-worker.js | 29 + .../packages/addon-kit/data/test.html | 12 + .../packages/addon-kit/docs/clipboard.md | 62 + .../packages/addon-kit/docs/context-menu.md | 719 +++ .../packages/addon-kit/docs/hotkeys.md | 78 + .../packages/addon-kit/docs/notifications.md | 64 + .../packages/addon-kit/docs/page-mod.md | 412 ++ .../packages/addon-kit/docs/page-worker.md | 325 ++ .../addon-sdk-1.7/packages/addon-kit/docs/panel.md | 607 +++ .../packages/addon-kit/docs/passwords.md | 568 +++ .../packages/addon-kit/docs/private-browsing.md | 50 + .../packages/addon-kit/docs/request.md | 203 + .../packages/addon-kit/docs/selection.md | 90 + .../addon-sdk-1.7/packages/addon-kit/docs/self.md | 79 + .../packages/addon-kit/docs/simple-prefs.md | 75 + .../packages/addon-kit/docs/simple-storage.md | 220 + .../addon-sdk-1.7/packages/addon-kit/docs/tabs.md | 385 ++ .../packages/addon-kit/docs/timers.md | 52 + .../packages/addon-kit/docs/widget.md | 909 ++++ .../packages/addon-kit/docs/windows.md | 191 + .../packages/addon-kit/lib/addon-page.js | 33 + .../packages/addon-kit/lib/clipboard.js | 230 + .../packages/addon-kit/lib/context-menu.js | 1492 ++++++ .../packages/addon-kit/lib/hotkeys.js | 37 + tools/addon-sdk-1.7/packages/addon-kit/lib/l10n.js | 149 + .../packages/addon-kit/lib/notifications.js | 79 + .../packages/addon-kit/lib/page-mod.js | 319 ++ .../packages/addon-kit/lib/page-worker.js | 65 + .../addon-sdk-1.7/packages/addon-kit/lib/panel.js | 381 ++ .../packages/addon-kit/lib/passwords.js | 59 + .../packages/addon-kit/lib/private-browsing.js | 61 + .../packages/addon-kit/lib/request.js | 208 + .../packages/addon-kit/lib/selection.js | 421 ++ .../packages/addon-kit/lib/simple-prefs.js | 68 + .../packages/addon-kit/lib/simple-storage.js | 237 + tools/addon-sdk-1.7/packages/addon-kit/lib/tabs.js | 28 + .../addon-sdk-1.7/packages/addon-kit/lib/timers.js | 8 + .../addon-sdk-1.7/packages/addon-kit/lib/widget.js | 923 ++++ .../packages/addon-kit/lib/windows.js | 210 + .../packages/addon-kit/locale/en-GB.properties | 11 + .../packages/addon-kit/locale/eo.properties | 5 + .../packages/addon-kit/locale/fr-FR.properties | 14 + .../addon-sdk-1.7/packages/addon-kit/package.json | 12 + .../packages/addon-kit/tests/helpers.js | 23 + .../addon-kit/tests/pagemod-test-helpers.js | 67 + .../packages/addon-kit/tests/test-addon-page.js | 51 + .../packages/addon-kit/tests/test-clipboard.js | 64 + .../addon-kit/tests/test-context-menu.html | 45 + .../packages/addon-kit/tests/test-context-menu.js | 2067 ++++++++ .../packages/addon-kit/tests/test-hotkeys.js | 160 + .../packages/addon-kit/tests/test-l10n.js | 97 + .../packages/addon-kit/tests/test-module.js | 37 + .../packages/addon-kit/tests/test-notifications.js | 46 + .../packages/addon-kit/tests/test-page-mod.js | 526 ++ .../packages/addon-kit/tests/test-page-worker.js | 366 ++ .../packages/addon-kit/tests/test-panel.js | 466 ++ .../packages/addon-kit/tests/test-passwords.js | 281 ++ .../addon-kit/tests/test-private-browsing.js | 204 + .../packages/addon-kit/tests/test-request.js | 340 ++ .../packages/addon-kit/tests/test-selection.js | 458 ++ .../packages/addon-kit/tests/test-simple-prefs.js | 175 + .../addon-kit/tests/test-simple-storage.js | 311 ++ .../packages/addon-kit/tests/test-tabs.js | 900 ++++ .../packages/addon-kit/tests/test-timers.js | 12 + .../packages/addon-kit/tests/test-widget.js | 1010 ++++ .../packages/addon-kit/tests/test-windows.js | 309 ++ tools/addon-sdk-1.7/packages/api-utils/README.md | 35 + .../packages/api-utils/data/content-proxy.js | 847 ++++ .../api-utils/data/test-content-symbiont.js | 5 + .../api-utils/data/test-message-manager.js | 6 + .../api-utils/data/test-trusted-document.html | 17 + .../packages/api-utils/data/worker.js | 247 + .../packages/api-utils/docs/api-utils.md | 157 + .../packages/api-utils/docs/app-strings.md | 65 + .../addon-sdk-1.7/packages/api-utils/docs/base.md | 207 + .../packages/api-utils/docs/byte-streams.md | 68 + .../packages/api-utils/docs/collection.md | 77 + .../packages/api-utils/docs/content.md | 15 + .../packages/api-utils/docs/content/loader.md | 92 + .../packages/api-utils/docs/content/proxy.md | 241 + .../packages/api-utils/docs/content/symbiont.md | 140 + .../packages/api-utils/docs/content/worker.md | 130 + .../packages/api-utils/docs/cortex.md | 160 + .../packages/api-utils/docs/cuddlefish.md | 7 + .../packages/api-utils/docs/environment.md | 43 + .../packages/api-utils/docs/errors.md | 42 + .../packages/api-utils/docs/event/core.md | 51 + .../packages/api-utils/docs/event/target.md | 95 + .../packages/api-utils/docs/events.md | 78 + .../addon-sdk-1.7/packages/api-utils/docs/file.md | 151 + .../packages/api-utils/docs/frame/utils.md | 53 + .../packages/api-utils/docs/globals.md | 100 + .../packages/api-utils/docs/hidden-frame.md | 83 + .../addon-sdk-1.7/packages/api-utils/docs/httpd.md | 31 + .../packages/api-utils/docs/light-traits.md | 295 ++ .../addon-sdk-1.7/packages/api-utils/docs/list.md | 98 + .../packages/api-utils/docs/match-pattern.md | 246 + .../packages/api-utils/docs/memory.md | 7 + .../packages/api-utils/docs/message-manager.md | 13 + .../packages/api-utils/docs/namespace.md | 71 + .../packages/api-utils/docs/observer-service.md | 73 + .../packages/api-utils/docs/plain-text-console.md | 7 + .../packages/api-utils/docs/preferences-service.md | 116 + .../packages/api-utils/docs/promise.md | 394 ++ .../packages/api-utils/docs/querystring.md | 37 + .../packages/api-utils/docs/runtime.md | 75 + .../packages/api-utils/docs/sandbox.md | 51 + .../packages/api-utils/docs/tab-browser.md | 140 + .../packages/api-utils/docs/text-streams.md | 102 + .../packages/api-utils/docs/traceback.md | 66 + .../packages/api-utils/docs/traits.md | 244 + .../packages/api-utils/docs/unit-test.md | 393 ++ .../packages/api-utils/docs/unload.md | 61 + tools/addon-sdk-1.7/packages/api-utils/docs/url.md | 85 + .../addon-sdk-1.7/packages/api-utils/docs/uuid.md | 27 + .../packages/api-utils/docs/window-utils.md | 88 + .../packages/api-utils/docs/window/utils.md | 90 + tools/addon-sdk-1.7/packages/api-utils/docs/xhr.md | 95 + .../addon-sdk-1.7/packages/api-utils/docs/xpcom.md | 216 + .../packages/api-utils/docs/xul-app.md | 76 + .../packages/api-utils/lib/api-utils.js | 153 + .../packages/api-utils/lib/app-strings.js | 63 + .../addon-sdk-1.7/packages/api-utils/lib/array.js | 69 + tools/addon-sdk-1.7/packages/api-utils/lib/base.js | 177 + .../packages/api-utils/lib/byte-streams.js | 102 + .../packages/api-utils/lib/channel.js | 46 + .../packages/api-utils/lib/collection.js | 108 + .../packages/api-utils/lib/content.js | 11 + .../packages/api-utils/lib/content/loader.js | 179 + .../packages/api-utils/lib/content/symbiont.js | 183 + .../packages/api-utils/lib/content/worker.js | 491 ++ .../addon-sdk-1.7/packages/api-utils/lib/cortex.js | 109 + .../packages/api-utils/lib/cuddlefish.js | 302 ++ .../packages/api-utils/lib/dom/events.js | 136 + .../packages/api-utils/lib/dom/events/keys.js | 60 + tools/addon-sdk-1.7/packages/api-utils/lib/env!.js | 20 + .../packages/api-utils/lib/environment.js | 54 + .../addon-sdk-1.7/packages/api-utils/lib/errors.js | 60 + .../packages/api-utils/lib/event/core.js | 147 + .../packages/api-utils/lib/event/target.js | 76 + .../addon-sdk-1.7/packages/api-utils/lib/events.js | 178 + .../packages/api-utils/lib/events/assembler.js | 53 + tools/addon-sdk-1.7/packages/api-utils/lib/file.js | 192 + .../packages/api-utils/lib/find-tests.js | 5 + .../packages/api-utils/lib/frame/utils.js | 59 + .../packages/api-utils/lib/functional.js | 159 + .../packages/api-utils/lib/globals!.js | 93 + .../packages/api-utils/lib/hidden-frame.js | 166 + .../addon-sdk-1.7/packages/api-utils/lib/httpd.js | 5166 ++++++++++++++++++++ .../packages/api-utils/lib/keyboard/hotkeys.js | 107 + .../packages/api-utils/lib/keyboard/observer.js | 53 + .../packages/api-utils/lib/keyboard/utils.js | 186 + .../packages/api-utils/lib/l10n/locale.js | 122 + .../packages/api-utils/lib/l10n/plural-rules.js | 387 ++ .../packages/api-utils/lib/light-traits.js | 596 +++ tools/addon-sdk-1.7/packages/api-utils/lib/list.js | 114 + .../packages/api-utils/lib/match-pattern.js | 103 + .../addon-sdk-1.7/packages/api-utils/lib/memory.js | 114 + .../packages/api-utils/lib/message-manager.js | 203 + .../packages/api-utils/lib/namespace.js | 43 + .../packages/api-utils/lib/observer-service.js | 175 + .../packages/api-utils/lib/passwords/utils.js | 101 + .../packages/api-utils/lib/plain-text-console.js | 82 + .../packages/api-utils/lib/preferences-service.js | 124 + .../packages/api-utils/lib/process.js | 76 + .../packages/api-utils/lib/promise.js | 219 + .../packages/api-utils/lib/querystring.js | 117 + .../packages/api-utils/lib/runtime.js | 15 + .../packages/api-utils/lib/sandbox.js | 46 + .../addon-sdk-1.7/packages/api-utils/lib/self!.js | 48 + .../addon-sdk-1.7/packages/api-utils/lib/system.js | 120 + .../packages/api-utils/lib/tab-browser.js | 727 +++ .../packages/api-utils/lib/tabs/events.js | 26 + .../packages/api-utils/lib/tabs/observer.js | 93 + .../packages/api-utils/lib/tabs/tab.js | 264 + .../packages/api-utils/lib/tabs/utils.js | 59 + tools/addon-sdk-1.7/packages/api-utils/lib/test.js | 108 + .../packages/api-utils/lib/test/assert.js | 331 ++ .../packages/api-utils/lib/text-streams.js | 240 + .../addon-sdk-1.7/packages/api-utils/lib/timer.js | 78 + .../packages/api-utils/lib/traceback.js | 123 + .../addon-sdk-1.7/packages/api-utils/lib/traits.js | 183 + .../packages/api-utils/lib/traits/core.js | 317 ++ tools/addon-sdk-1.7/packages/api-utils/lib/type.js | 340 ++ .../packages/api-utils/lib/unit-test-finder.js | 76 + .../packages/api-utils/lib/unit-test.js | 440 ++ .../addon-sdk-1.7/packages/api-utils/lib/unload.js | 63 + tools/addon-sdk-1.7/packages/api-utils/lib/url.js | 113 + .../packages/api-utils/lib/utils/data.js | 71 + .../packages/api-utils/lib/utils/object.js | 46 + .../packages/api-utils/lib/utils/registry.js | 57 + .../packages/api-utils/lib/utils/thumbnail.js | 43 + tools/addon-sdk-1.7/packages/api-utils/lib/uuid.js | 13 + .../packages/api-utils/lib/window-utils.js | 278 ++ .../packages/api-utils/lib/window/utils.js | 110 + .../packages/api-utils/lib/windows/dom.js | 27 + .../packages/api-utils/lib/windows/loader.js | 120 + .../packages/api-utils/lib/windows/observer.js | 53 + .../packages/api-utils/lib/windows/tabs.js | 178 + tools/addon-sdk-1.7/packages/api-utils/lib/xhr.js | 150 + .../addon-sdk-1.7/packages/api-utils/lib/xpcom.js | 207 + .../packages/api-utils/lib/xul-app.js | 63 + .../addon-sdk-1.7/packages/api-utils/package.json | 14 + .../tests/commonjs-test-adapter/asserts.js | 54 + .../packages/api-utils/tests/fixtures/es5.js | 8 + .../tests/fixtures/sandbox-complex-character.js | 5 + .../api-utils/tests/fixtures/sandbox-normal.js | 7 + .../packages/api-utils/tests/helpers.js | 24 + .../packages/api-utils/tests/loader/fixture.js | 6 + .../packages/api-utils/tests/modules/add.js | 9 + .../packages/api-utils/tests/modules/async1.js | 14 + .../packages/api-utils/tests/modules/async2.js | 8 + .../api-utils/tests/modules/badExportAndReturn.js | 10 + .../packages/api-utils/tests/modules/badFirst.js | 9 + .../packages/api-utils/tests/modules/badSecond.js | 8 + .../packages/api-utils/tests/modules/blue.js | 9 + .../packages/api-utils/tests/modules/castor.js | 10 + .../packages/api-utils/tests/modules/cheetah.js | 9 + .../packages/api-utils/tests/modules/color.js | 7 + .../packages/api-utils/tests/modules/dupe.js | 15 + .../packages/api-utils/tests/modules/dupeNested.js | 15 + .../api-utils/tests/modules/dupeSetExports.js | 8 + .../api-utils/tests/modules/exportsEquals.js | 5 + .../packages/api-utils/tests/modules/green.js | 10 + .../packages/api-utils/tests/modules/lion.js | 7 + .../packages/api-utils/tests/modules/orange.js | 10 + .../packages/api-utils/tests/modules/pollux.js | 10 + .../packages/api-utils/tests/modules/red.js | 16 + .../packages/api-utils/tests/modules/setExports.js | 5 + .../packages/api-utils/tests/modules/subtract.js | 9 + .../packages/api-utils/tests/modules/tiger.js | 8 + .../api-utils/tests/modules/traditional1.js | 12 + .../api-utils/tests/modules/traditional2.js | 6 + .../packages/api-utils/tests/modules/types/cat.js | 5 + .../packages/api-utils/tests/test-api-utils.js | 241 + .../packages/api-utils/tests/test-app-strings.js | 62 + .../packages/api-utils/tests/test-array.js | 40 + .../packages/api-utils/tests/test-base.js | 240 + .../packages/api-utils/tests/test-byte-streams.js | 169 + .../packages/api-utils/tests/test-collection.js | 127 + .../api-utils/tests/test-commonjs-test-adapter.js | 11 + .../api-utils/tests/test-content-loader.js | 226 + .../packages/api-utils/tests/test-content-proxy.js | 807 +++ .../api-utils/tests/test-content-symbiont.js | 190 + .../api-utils/tests/test-content-worker.js | 465 ++ .../packages/api-utils/tests/test-cortex.js | 122 + .../packages/api-utils/tests/test-dom.js | 88 + .../packages/api-utils/tests/test-environment.js | 50 + .../packages/api-utils/tests/test-errors.js | 70 + .../packages/api-utils/tests/test-event-core.js | 217 + .../packages/api-utils/tests/test-event-target.js | 167 + .../packages/api-utils/tests/test-events.js | 267 + .../packages/api-utils/tests/test-file.js | 273 ++ .../packages/api-utils/tests/test-frame-utils.js | 67 + .../packages/api-utils/tests/test-functional.js | 170 + .../packages/api-utils/tests/test-globals.js | 22 + .../packages/api-utils/tests/test-hidden-frame.js | 51 + .../packages/api-utils/tests/test-httpd.js | 72 + .../api-utils/tests/test-keyboard-observer.js | 36 + .../api-utils/tests/test-keyboard-utils.js | 62 + .../packages/api-utils/tests/test-l10n-locale.js | 141 + .../api-utils/tests/test-l10n-plural-rules.js | 82 + .../packages/api-utils/tests/test-light-traits.js | 11 + .../packages/api-utils/tests/test-list.js | 207 + .../packages/api-utils/tests/test-loader.js | 35 + .../packages/api-utils/tests/test-match-pattern.js | 127 + .../packages/api-utils/tests/test-memory.js | 19 + .../api-utils/tests/test-message-manager.js | 600 +++ .../packages/api-utils/tests/test-modules.js | 148 + .../packages/api-utils/tests/test-namespace.js | 95 + .../api-utils/tests/test-observer-service.js | 77 + .../api-utils/tests/test-passwords-utils.js | 142 + .../api-utils/tests/test-plain-text-console.js | 68 + .../api-utils/tests/test-preferences-service.js | 112 + .../packages/api-utils/tests/test-process.js | 36 + .../packages/api-utils/tests/test-promise.js | 311 ++ .../packages/api-utils/tests/test-querystring.js | 206 + .../packages/api-utils/tests/test-registry.js | 80 + .../packages/api-utils/tests/test-require.js | 29 + .../packages/api-utils/tests/test-sandbox.js | 113 + .../packages/api-utils/tests/test-self.js | 54 + .../packages/api-utils/tests/test-set-exports.js | 35 + .../packages/api-utils/tests/test-tab-browser.js | 493 ++ .../packages/api-utils/tests/test-tab-observer.js | 39 + .../packages/api-utils/tests/test-tab.js | 110 + .../packages/api-utils/tests/test-text-streams.js | 156 + .../packages/api-utils/tests/test-timer.js | 131 + .../packages/api-utils/tests/test-traceback.js | 118 + .../packages/api-utils/tests/test-traits-core.js | 838 ++++ .../packages/api-utils/tests/test-traits.js | 398 ++ .../packages/api-utils/tests/test-type.js | 92 + .../packages/api-utils/tests/test-unit-test.js | 251 + .../packages/api-utils/tests/test-unload.js | 161 + .../packages/api-utils/tests/test-url.js | 204 + .../packages/api-utils/tests/test-uuid.js | 27 + .../packages/api-utils/tests/test-window-loader.js | 120 + .../api-utils/tests/test-window-observer.js | 48 + .../packages/api-utils/tests/test-window-utils.js | 321 ++ .../packages/api-utils/tests/test-window-utils2.js | 67 + .../packages/api-utils/tests/test-xhr.js | 75 + .../packages/api-utils/tests/test-xpcom.js | 217 + .../packages/api-utils/tests/test-xul-app.js | 45 + .../packages/api-utils/tests/traits/assert.js | 98 + .../api-utils/tests/traits/descriptor-tests.js | 335 ++ .../api-utils/tests/traits/inheritance-tests.js | 104 + .../api-utils/tests/traits/object-tests.js | 321 ++ .../packages/api-utils/tests/traits/utils.js | 56 + .../addon-sdk-1.7/packages/test-harness/README.md | 12 + .../packages/test-harness/docs/harness.md | 6 + .../packages/test-harness/docs/run-tests.md | 13 + .../packages/test-harness/lib/harness.js | 324 ++ .../packages/test-harness/lib/run-tests.js | 101 + .../packages/test-harness/package.json | 8 + .../packages/test-harness/tests/test-packaging.js | 18 + .../python-lib/cuddlefish/__init__.py | 797 +++ .../python-lib/cuddlefish/_version.py | 171 + .../cuddlefish/app-extension/application.ini | 11 + .../cuddlefish/app-extension/bootstrap.js | 216 + .../cuddlefish/app-extension/install.rdf | 33 + tools/addon-sdk-1.7/python-lib/cuddlefish/bunch.py | 34 + .../python-lib/cuddlefish/docs/__init__.py | 4 + .../python-lib/cuddlefish/docs/apiparser.py | 392 ++ .../python-lib/cuddlefish/docs/apirenderer.py | 302 ++ .../python-lib/cuddlefish/docs/generate.py | 292 ++ .../python-lib/cuddlefish/docs/renderapi.readme.md | 210 + .../python-lib/cuddlefish/docs/webdocs.py | 193 + .../python-lib/cuddlefish/manifest.py | 751 +++ .../cuddlefish/mobile-utils/bootstrap.js | 78 + .../python-lib/cuddlefish/mobile-utils/install.rdf | 39 + .../python-lib/cuddlefish/options_defaults.py | 26 + .../python-lib/cuddlefish/options_xul.py | 64 + .../python-lib/cuddlefish/packaging.py | 435 ++ .../python-lib/cuddlefish/preflight.py | 77 + tools/addon-sdk-1.7/python-lib/cuddlefish/prefs.py | 115 + .../python-lib/cuddlefish/property_parser.py | 106 + tools/addon-sdk-1.7/python-lib/cuddlefish/rdf.py | 190 + .../addon-sdk-1.7/python-lib/cuddlefish/runner.py | 696 +++ .../python-lib/cuddlefish/templates.py | 83 + .../python-lib/cuddlefish/tests/__init__.py | 65 + .../cuddlefish/tests/addons/simplest-test/main.js | 17 + .../tests/addons/simplest-test/package.json | 6 + .../addons/simplest-test/tests/test-minimal.js | 7 + .../packages/explicit-icon/explicit-icon.png | 0 .../packages/explicit-icon/explicit-icon64.png | 0 .../packages/explicit-icon/lib/main.js | 4 + .../packages/explicit-icon/package.json | 5 + .../packages/implicit-icon/icon.png | 0 .../packages/implicit-icon/icon64.png | 0 .../packages/implicit-icon/lib/main.js | 4 + .../packages/implicit-icon/package.json | 3 + .../bug-588119-files/packages/no-icon/lib/main.js | 4 + .../bug-588119-files/packages/no-icon/package.json | 3 + .../packages/bar/lib/bar-loader.js | 4 + .../bug-588661-files/packages/bar/package.json | 3 + .../packages/foo/lib/foo-loader.js | 4 + .../bug-588661-files/packages/foo/package.json | 4 + .../tests/bug-611495-files/jspath-one/docs/main.md | 5 + .../tests/bug-611495-files/jspath-one/lib/main.js | 8 + .../tests/bug-611495-files/jspath-one/package.json | 5 + .../packages/commonjs-naming/doc/foo.md | 5 + .../packages/commonjs-naming/lib/foo-loader.js | 5 + .../packages/commonjs-naming/package.json | 3 + .../packages/commonjs-naming/test/test-foo.js | 7 + .../packages/original-naming/docs/foo.md | 5 + .../packages/original-naming/lib/foo-loader.js | 5 + .../packages/original-naming/package.json | 3 + .../packages/original-naming/tests/test-foo.js | 7 + .../packages/default-lib/doc/foo.md | 5 + .../packages/default-lib/lib/foo.js | 5 + .../packages/default-lib/lib/loader.js | 5 + .../packages/default-lib/package.json | 3 + .../packages/default-lib/test/test-foo.js | 7 + .../packages/default-locale/locale/emptyFolder | 0 .../packages/default-locale/package.json | 1 + .../packages/default-root/doc/foo.md | 5 + .../bug-652227-files/packages/default-root/foo.js | 5 + .../packages/default-root/loader.js | 5 + .../packages/default-root/package.json | 3 + .../packages/default-root/test/test-foo.js | 7 + .../packages/explicit-dir-lib/alt-lib/foo.js | 5 + .../packages/explicit-dir-lib/alt-lib/loader.js | 5 + .../packages/explicit-dir-lib/doc/foo.md | 5 + .../packages/explicit-dir-lib/package.json | 4 + .../packages/explicit-dir-lib/test/test-foo.js | 7 + .../packages/explicit-lib/alt2-lib/foo.js | 5 + .../packages/explicit-lib/alt2-lib/loader.js | 5 + .../packages/explicit-lib/doc/foo.md | 5 + .../packages/explicit-lib/package.json | 4 + .../packages/explicit-lib/test/test-foo.js | 7 + .../packages/extra-options/docs/main.md | 5 + .../packages/extra-options/lib/main.js | 8 + .../packages/extra-options/package.json | 6 + .../tests/bug-715340-files/pkg-1-pack/package.json | 10 + .../bug-715340-files/pkg-2-unpack/package.json | 10 + .../tests/bug-715340-files/pkg-3-pack/package.json | 9 + .../packages/foo/lib/bar-e10s-adapter.js | 11 + .../e10s-adapter-files/packages/foo/lib/bar.js | 5 + .../e10s-adapter-files/packages/foo/lib/foo.js | 5 + .../e10s-adapter-files/packages/foo/package.json | 1 + .../cuddlefish/tests/linker-files/five/lib/main.js | 5 + .../tests/linker-files/five/package.json | 3 + .../linker-files/four-deps/four-a/lib/misc.js | 5 + .../linker-files/four-deps/four-a/package.json | 4 + .../linker-files/four-deps/four-a/topfiles/main.js | 5 + .../cuddlefish/tests/linker-files/four/lib/main.js | 5 + .../tests/linker-files/four/package.json | 3 + .../cuddlefish/tests/linker-files/one/lib/main.js | 9 + .../tests/linker-files/one/lib/subdir/three.js | 6 + .../cuddlefish/tests/linker-files/one/lib/two.js | 8 + .../cuddlefish/tests/linker-files/one/package.json | 4 + .../tests/linker-files/seven/data/text.data | 1 + .../tests/linker-files/seven/lib/main.js | 6 + .../tests/linker-files/seven/lib/unused.js | 5 + .../tests/linker-files/seven/package.json | 4 + .../tests/linker-files/six/lib/unused.js | 5 + .../cuddlefish/tests/linker-files/six/package.json | 3 + .../tests/linker-files/six/unreachable.js | 5 + .../linker-files/three-deps/three-a/data/msg.txt | 1 + .../three-deps/three-a/data/subdir/submsg.txt | 1 + .../linker-files/three-deps/three-a/lib/main.js | 8 + .../three-deps/three-a/lib/subdir/subfile.js | 5 + .../linker-files/three-deps/three-a/lib/unused.js | 5 + .../three-deps/three-a/locale/fr-FR.properties | 5 + .../linker-files/three-deps/three-a/package.json | 3 + .../linker-files/three-deps/three-b/lib/main.js | 5 + .../three-deps/three-b/locale/fr-FR.properties | 6 + .../linker-files/three-deps/three-b/package.json | 3 + .../linker-files/three-deps/three-c/lib/main.js | 5 + .../linker-files/three-deps/three-c/lib/sub/foo.js | 6 + .../three-deps/three-c/locale/fr-FR.properties | 9 + .../linker-files/three-deps/three-c/package.json | 3 + .../tests/linker-files/three/lib/main.js | 8 + .../tests/linker-files/three/package.json | 3 + .../tests/linker-files/three/tests/nontest.js | 5 + .../tests/linker-files/three/tests/test-one.js | 5 + .../tests/linker-files/three/tests/test-two.js | 5 + .../packages/no-prefs/lib/main.js | 4 + .../packages/no-prefs/package.json | 6 + .../packages/simple-prefs/lib/main.js | 4 + .../packages/simple-prefs/package.json | 18 + .../static-files/doc/dev-guide-source/index.md | 7 + .../static-files/doc/dev-guide-source/no_h1.md | 7 + .../static-files/doc/static-files/another.html | 5 + .../tests/static-files/doc/static-files/base.html | 161 + .../tests/static-files/doc/static-files/index.html | 27 + .../tests/static-files/docs/APIreference.html | 469 ++ .../tests/static-files/docs/APIsample.md | 162 + .../packages/aardvark/doc/aardvark-feeder.md | 12 + .../static-files/packages/aardvark/doc/main.md | 0 .../static-files/packages/aardvark/lib/ignore_me | 3 + .../static-files/packages/aardvark/lib/main.js | 8 + .../aardvark/lib/surprise.js/ignore_me_too | 2 + .../static-files/packages/aardvark/package.json | 7 + .../packages/anteater_files/lib/main.js | 8 + .../packages/anteater_files/package.json | 8 + .../static-files/packages/api-utils/lib/loader.js | 7 + .../static-files/packages/api-utils/package.json | 5 + .../packages/barbeque/lib/bar-module.js | 7 + .../static-files/packages/barbeque/package.json | 4 + .../static-files/packages/minimal/docs/main.md | 5 + .../static-files/packages/minimal/lib/main.js | 8 + .../static-files/packages/minimal/package.json | 4 + .../xpi-template/components/harness.js | 8 + .../python-lib/cuddlefish/tests/test_apiparser.py | 538 ++ .../cuddlefish/tests/test_apirenderer.py | 31 + .../python-lib/cuddlefish/tests/test_generate.py | 173 + .../python-lib/cuddlefish/tests/test_init.py | 148 + .../python-lib/cuddlefish/tests/test_licenses.py | 88 + .../python-lib/cuddlefish/tests/test_linker.py | 234 + .../python-lib/cuddlefish/tests/test_manifest.py | 254 + .../python-lib/cuddlefish/tests/test_packaging.py | 116 + .../python-lib/cuddlefish/tests/test_preflight.py | 147 + .../cuddlefish/tests/test_property_parser.py | 75 + .../python-lib/cuddlefish/tests/test_rdf.py | 45 + .../python-lib/cuddlefish/tests/test_runner.py | 27 + .../python-lib/cuddlefish/tests/test_util.py | 22 + .../python-lib/cuddlefish/tests/test_version.py | 28 + .../python-lib/cuddlefish/tests/test_webdocs.py | 97 + .../python-lib/cuddlefish/tests/test_xpi.py | 412 ++ tools/addon-sdk-1.7/python-lib/cuddlefish/util.py | 23 + .../python-lib/cuddlefish/version_comparator.py | 206 + tools/addon-sdk-1.7/python-lib/cuddlefish/xpi.py | 155 + tools/addon-sdk-1.7/python-lib/jetpack_sdk_env.py | 66 + tools/addon-sdk-1.7/python-lib/markdown/AUTHORS | 43 + tools/addon-sdk-1.7/python-lib/markdown/LICENSE | 30 + .../addon-sdk-1.7/python-lib/markdown/__init__.py | 603 +++ .../python-lib/markdown/blockparser.py | 95 + .../python-lib/markdown/blockprocessors.py | 460 ++ .../python-lib/markdown/commandline.py | 96 + .../python-lib/markdown/etree_loader.py | 33 + .../python-lib/markdown/extensions/__init__.py | 0 .../python-lib/markdown/extensions/abbr.py | 95 + .../python-lib/markdown/extensions/codehilite.py | 224 + .../python-lib/markdown/extensions/def_list.py | 104 + .../python-lib/markdown/extensions/extra.py | 49 + .../python-lib/markdown/extensions/fenced_code.py | 117 + .../python-lib/markdown/extensions/footnotes.py | 293 ++ .../python-lib/markdown/extensions/headerid.py | 195 + .../python-lib/markdown/extensions/html_tidy.py | 62 + .../python-lib/markdown/extensions/imagelinks.py | 119 + .../python-lib/markdown/extensions/meta.py | 90 + .../python-lib/markdown/extensions/rss.py | 114 + .../python-lib/markdown/extensions/tables.py | 97 + .../python-lib/markdown/extensions/toc.py | 140 + .../python-lib/markdown/extensions/wikilinks.py | 155 + tools/addon-sdk-1.7/python-lib/markdown/html4.py | 274 ++ .../python-lib/markdown/inlinepatterns.py | 371 ++ tools/addon-sdk-1.7/python-lib/markdown/odict.py | 162 + .../python-lib/markdown/postprocessors.py | 77 + .../python-lib/markdown/preprocessors.py | 214 + .../python-lib/markdown/treeprocessors.py | 329 ++ .../addon-sdk-1.7/python-lib/mozrunner/__init__.py | 690 +++ .../python-lib/mozrunner/killableprocess.py | 316 ++ tools/addon-sdk-1.7/python-lib/mozrunner/qijo.py | 166 + .../python-lib/mozrunner/winprocess.py | 383 ++ tools/addon-sdk-1.7/python-lib/mozrunner/wpk.py | 80 + .../python-lib/plural-rules-generator.py | 174 + .../python-lib/simplejson/LICENSE.txt | 19 + .../python-lib/simplejson/__init__.py | 376 ++ .../addon-sdk-1.7/python-lib/simplejson/decoder.py | 343 ++ .../addon-sdk-1.7/python-lib/simplejson/encoder.py | 385 ++ .../addon-sdk-1.7/python-lib/simplejson/scanner.py | 67 + tools/addon-sdk-1.7/python-lib/simplejson/tool.py | 44 + 580 files changed, 73798 insertions(+) create mode 100644 tools/addon-sdk-1.7/LICENSE create mode 100644 tools/addon-sdk-1.7/README create mode 100644 tools/addon-sdk-1.7/bin/activate create mode 100644 tools/addon-sdk-1.7/bin/activate.bat create mode 100644 tools/addon-sdk-1.7/bin/activate.ps1 create mode 100755 tools/addon-sdk-1.7/bin/cfx create mode 100644 tools/addon-sdk-1.7/bin/cfx.bat create mode 100644 tools/addon-sdk-1.7/bin/deactivate.bat create mode 100755 tools/addon-sdk-1.7/bin/integration-scripts/buildbot-run-cfx-helper create mode 100644 tools/addon-sdk-1.7/bin/integration-scripts/integration-check create mode 100644 tools/addon-sdk-1.7/examples/annotator/README.md create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.html create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.html create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/jquery-1.4.2.min.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.css create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.html create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/matcher.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/selector.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/widget/pencil-off.png create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/widget/pencil-on.png create mode 100644 tools/addon-sdk-1.7/examples/annotator/data/widget/widget.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/lib/main.js create mode 100644 tools/addon-sdk-1.7/examples/annotator/package.json create mode 100644 tools/addon-sdk-1.7/examples/annotator/tests/test-main.js create mode 100755 tools/addon-sdk-1.7/examples/library-detector/README.md create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/icons/closure.ico create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/icons/jquery.ico create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/icons/jquery_ui.ico create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/icons/modernizr.ico create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/icons/mootools.png create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/icons/yui.ico create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/library-detector.js create mode 100755 tools/addon-sdk-1.7/examples/library-detector/data/widget.js create mode 100755 tools/addon-sdk-1.7/examples/library-detector/lib/main.js create mode 100755 tools/addon-sdk-1.7/examples/library-detector/package.json create mode 100644 tools/addon-sdk-1.7/examples/library-detector/test/test-main.js create mode 100644 tools/addon-sdk-1.7/examples/reading-data/data/mom.png create mode 100644 tools/addon-sdk-1.7/examples/reading-data/data/sample.html create mode 100644 tools/addon-sdk-1.7/examples/reading-data/lib/main.js create mode 100644 tools/addon-sdk-1.7/examples/reading-data/package.json create mode 100644 tools/addon-sdk-1.7/examples/reading-data/tests/test-main.js create mode 100644 tools/addon-sdk-1.7/examples/reddit-panel/README.md create mode 100644 tools/addon-sdk-1.7/examples/reddit-panel/data/jquery-1.4.4.min.js create mode 100644 tools/addon-sdk-1.7/examples/reddit-panel/data/panel.js create mode 100644 tools/addon-sdk-1.7/examples/reddit-panel/lib/main.js create mode 100644 tools/addon-sdk-1.7/examples/reddit-panel/package.json create mode 100644 tools/addon-sdk-1.7/examples/reddit-panel/tests/test-main.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/README.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/index.html create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/moz_favicon.ico create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/pagemod-css-include-file.css create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/test-context-menu.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/test-page-mod.html create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/test-page-worker.html create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/test-page-worker.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/data/test.html create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/clipboard.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/context-menu.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/hotkeys.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/notifications.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/page-mod.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/page-worker.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/panel.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/passwords.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/private-browsing.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/request.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/selection.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/self.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/simple-prefs.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/simple-storage.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/tabs.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/timers.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/widget.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/docs/windows.md create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/addon-page.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/clipboard.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/context-menu.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/hotkeys.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/l10n.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/notifications.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/page-mod.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/page-worker.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/panel.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/passwords.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/private-browsing.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/request.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/selection.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/simple-prefs.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/simple-storage.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/tabs.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/timers.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/widget.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/lib/windows.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/locale/en-GB.properties create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/locale/eo.properties create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/locale/fr-FR.properties create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/package.json create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/helpers.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/pagemod-test-helpers.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-addon-page.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-clipboard.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-context-menu.html create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-context-menu.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-hotkeys.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-l10n.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-module.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-notifications.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-mod.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-worker.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-panel.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-passwords.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-private-browsing.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-request.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-selection.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-prefs.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-storage.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-tabs.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-timers.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-widget.js create mode 100644 tools/addon-sdk-1.7/packages/addon-kit/tests/test-windows.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/README.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/data/content-proxy.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/data/test-content-symbiont.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/data/test-message-manager.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/data/test-trusted-document.html create mode 100644 tools/addon-sdk-1.7/packages/api-utils/data/worker.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/api-utils.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/app-strings.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/base.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/byte-streams.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/collection.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/content.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/content/loader.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/content/proxy.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/content/symbiont.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/content/worker.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/cortex.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/cuddlefish.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/environment.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/errors.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/event/core.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/event/target.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/events.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/file.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/frame/utils.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/globals.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/hidden-frame.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/httpd.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/light-traits.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/list.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/match-pattern.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/memory.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/message-manager.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/namespace.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/observer-service.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/plain-text-console.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/preferences-service.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/promise.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/querystring.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/runtime.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/sandbox.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/tab-browser.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/text-streams.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/traceback.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/traits.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/unit-test.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/unload.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/url.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/uuid.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/window-utils.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/window/utils.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/xhr.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/xpcom.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/docs/xul-app.md create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/api-utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/app-strings.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/array.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/base.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/byte-streams.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/channel.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/collection.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/content.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/content/loader.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/content/symbiont.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/content/worker.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/cortex.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/cuddlefish.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/dom/events.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/dom/events/keys.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/env!.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/environment.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/errors.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/event/core.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/event/target.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/events.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/events/assembler.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/file.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/find-tests.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/frame/utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/functional.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/globals!.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/hidden-frame.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/httpd.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/keyboard/hotkeys.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/keyboard/observer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/keyboard/utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/l10n/locale.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/l10n/plural-rules.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/light-traits.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/list.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/match-pattern.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/memory.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/message-manager.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/namespace.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/observer-service.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/passwords/utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/plain-text-console.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/preferences-service.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/process.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/promise.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/querystring.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/runtime.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/sandbox.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/self!.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/system.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/tab-browser.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/tabs/events.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/tabs/observer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/tabs/tab.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/tabs/utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/test.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/test/assert.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/text-streams.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/timer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/traceback.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/traits.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/traits/core.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/type.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/unit-test-finder.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/unit-test.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/unload.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/url.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/utils/data.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/utils/object.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/utils/registry.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/utils/thumbnail.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/uuid.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/window-utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/window/utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/windows/dom.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/windows/loader.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/windows/observer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/windows/tabs.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/xhr.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/xpcom.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/lib/xul-app.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/package.json create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/commonjs-test-adapter/asserts.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/fixtures/es5.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/fixtures/sandbox-complex-character.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/fixtures/sandbox-normal.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/helpers.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/loader/fixture.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/add.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/async1.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/async2.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/badExportAndReturn.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/badFirst.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/badSecond.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/blue.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/castor.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/cheetah.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/color.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/dupe.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/dupeNested.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/dupeSetExports.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/exportsEquals.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/green.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/lion.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/orange.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/pollux.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/red.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/setExports.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/subtract.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/tiger.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/traditional1.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/traditional2.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/modules/types/cat.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-api-utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-app-strings.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-array.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-base.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-byte-streams.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-collection.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-commonjs-test-adapter.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-content-loader.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-content-proxy.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-content-symbiont.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-content-worker.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-cortex.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-dom.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-environment.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-errors.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-event-core.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-event-target.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-events.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-file.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-frame-utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-functional.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-globals.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-hidden-frame.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-httpd.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-keyboard-observer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-keyboard-utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-l10n-locale.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-l10n-plural-rules.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-light-traits.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-list.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-loader.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-match-pattern.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-memory.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-message-manager.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-modules.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-namespace.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-observer-service.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-passwords-utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-plain-text-console.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-preferences-service.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-process.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-promise.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-querystring.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-registry.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-require.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-sandbox.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-self.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-set-exports.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-tab-browser.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-tab-observer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-tab.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-text-streams.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-timer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-traceback.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-traits-core.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-traits.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-type.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-unit-test.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-unload.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-url.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-uuid.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-window-loader.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-window-observer.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-window-utils.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-window-utils2.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-xhr.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-xpcom.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/test-xul-app.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/traits/assert.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/traits/descriptor-tests.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/traits/inheritance-tests.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/traits/object-tests.js create mode 100644 tools/addon-sdk-1.7/packages/api-utils/tests/traits/utils.js create mode 100644 tools/addon-sdk-1.7/packages/test-harness/README.md create mode 100644 tools/addon-sdk-1.7/packages/test-harness/docs/harness.md create mode 100644 tools/addon-sdk-1.7/packages/test-harness/docs/run-tests.md create mode 100644 tools/addon-sdk-1.7/packages/test-harness/lib/harness.js create mode 100644 tools/addon-sdk-1.7/packages/test-harness/lib/run-tests.js create mode 100644 tools/addon-sdk-1.7/packages/test-harness/package.json create mode 100644 tools/addon-sdk-1.7/packages/test-harness/tests/test-packaging.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/_version.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/application.ini create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/bootstrap.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/install.rdf create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/bunch.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apiparser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apirenderer.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/generate.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/renderapi.readme.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/webdocs.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/manifest.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/bootstrap.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/install.rdf create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/options_defaults.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/options_xul.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/packaging.py create mode 100755 tools/addon-sdk-1.7/python-lib/cuddlefish/preflight.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/prefs.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/property_parser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/rdf.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/runner.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/templates.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon64.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon64.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/lib/bar-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/lib/foo-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/docs/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/lib/foo-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/docs/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/lib/foo-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/tests/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/locale/emptyFolder create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/docs/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-1-pack/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-2-unpack/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-3-pack/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar-e10s-adapter.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/lib/misc.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/topfiles/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/subdir/three.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/two.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/data/text.data create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/unused.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/lib/unused.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/unreachable.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/msg.txt create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/subdir/submsg.txt create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/subdir/subfile.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/unused.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/locale/fr-FR.properties create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/locale/fr-FR.properties create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/sub/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/locale/fr-FR.properties create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/nontest.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-one.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-two.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/index.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/no_h1.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/another.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/base.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/index.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIreference.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIsample.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/aardvark-feeder.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/ignore_me create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/surprise.js/ignore_me_too create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/lib/bar-module.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/docs/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/xpi-template/components/harness.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apiparser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apirenderer.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_generate.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_init.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_licenses.py create mode 100755 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_linker.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_manifest.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_packaging.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_preflight.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_property_parser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_rdf.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_runner.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_util.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_version.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_webdocs.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_xpi.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/util.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/version_comparator.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/xpi.py create mode 100644 tools/addon-sdk-1.7/python-lib/jetpack_sdk_env.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/AUTHORS create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/LICENSE create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/blockparser.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/blockprocessors.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/commandline.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/etree_loader.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/abbr.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/codehilite.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/def_list.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/extra.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/fenced_code.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/footnotes.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/headerid.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/html_tidy.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/imagelinks.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/meta.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/rss.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/tables.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/toc.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/extensions/wikilinks.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/html4.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/inlinepatterns.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/odict.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/postprocessors.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/preprocessors.py create mode 100644 tools/addon-sdk-1.7/python-lib/markdown/treeprocessors.py create mode 100644 tools/addon-sdk-1.7/python-lib/mozrunner/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/mozrunner/killableprocess.py create mode 100644 tools/addon-sdk-1.7/python-lib/mozrunner/qijo.py create mode 100644 tools/addon-sdk-1.7/python-lib/mozrunner/winprocess.py create mode 100644 tools/addon-sdk-1.7/python-lib/mozrunner/wpk.py create mode 100644 tools/addon-sdk-1.7/python-lib/plural-rules-generator.py create mode 100644 tools/addon-sdk-1.7/python-lib/simplejson/LICENSE.txt create mode 100644 tools/addon-sdk-1.7/python-lib/simplejson/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/simplejson/decoder.py create mode 100644 tools/addon-sdk-1.7/python-lib/simplejson/encoder.py create mode 100644 tools/addon-sdk-1.7/python-lib/simplejson/scanner.py create mode 100644 tools/addon-sdk-1.7/python-lib/simplejson/tool.py (limited to 'tools') diff --git a/tools/addon-sdk-1.7/LICENSE b/tools/addon-sdk-1.7/LICENSE new file mode 100644 index 0000000..ad8d321 --- /dev/null +++ b/tools/addon-sdk-1.7/LICENSE @@ -0,0 +1,30 @@ +The files which make up the SDK are developed by Mozilla and licensed +under the MPL 2.0 (http://mozilla.org/MPL/2.0/), with the exception of the +components listed below, which are made available by their authors under +the licenses listed alongside. + +syntaxhighlighter +------------------ +doc/static-files/syntaxhighlighter +Made available under the MIT license. + +jQuery +------ +examples/reddit-panel/data/jquery-1.4.4.min.js +examples/annotator/data/jquery-1.4.2.min.js +Made available under the MIT license. + +simplejson +---------- +python-lib/simplejson +Made available under the MIT license. + +Python Markdown +--------------- +python-lib/markdown +Made available under the BSD license. + +LibraryDetector +--------------- +examples/library-detector/data/library-detector.js +Made available under the MIT license. diff --git a/tools/addon-sdk-1.7/README b/tools/addon-sdk-1.7/README new file mode 100644 index 0000000..edebf5f --- /dev/null +++ b/tools/addon-sdk-1.7/README @@ -0,0 +1,36 @@ +Add-on SDK README +================== + +Before proceeding, please make sure you've installed Python 2.5, +2.6, or 2.7 (if it's not already on your system): + + http://python.org/download/ + +Note that Python 3.0 and 3.1 are not supported in this release. + +For Windows users, MozillaBuild (https://wiki.mozilla.org/MozillaBuild) +will install the correct version of Python and the MSYS package, which +will make it easier to work with the SDK. + +To get started, first enter the same directory that this README file +is in (the SDK's root directory) using a shell program. On Unix systems +or on Windows with MSYS, you can execute the following command: + + source bin/activate + +Windows users using cmd.exe should instead run: + + bin\activate.bat + +Then run: + + cfx docs + +This should start a documentation server and open a web browser +with further instructions. + + +Bugs +------- + +* file a bug: https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK \ No newline at end of file diff --git a/tools/addon-sdk-1.7/bin/activate b/tools/addon-sdk-1.7/bin/activate new file mode 100644 index 0000000..8f2d9dd --- /dev/null +++ b/tools/addon-sdk-1.7/bin/activate @@ -0,0 +1,86 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + if [ -n "$_OLD_VIRTUAL_PATH" ] ; then + PATH="$_OLD_VIRTUAL_PATH" + export PATH + unset _OLD_VIRTUAL_PATH + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then + hash -r + fi + + if [ -n "$_OLD_VIRTUAL_PS1" ] ; then + PS1="$_OLD_VIRTUAL_PS1" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + if [ -n "$_OLD_PYTHONPATH" ] ; then + PYTHONPATH="$_OLD_PYTHONPATH" + export PYTHONPATH + unset _OLD_PYTHONPATH + fi + + unset CUDDLEFISH_ROOT + + unset VIRTUAL_ENV + if [ ! "$1" = "nondestructive" ] ; then + # Self destruct! + unset deactivate + fi +} + +# unset irrelavent variables +deactivate nondestructive + +_OLD_PYTHONPATH="$PYTHONPATH" +_OLD_VIRTUAL_PATH="$PATH" + +VIRTUAL_ENV="`pwd`" + +if [ "x$OSTYPE" = "xmsys" ] ; then + CUDDLEFISH_ROOT="`pwd -W | sed s,/,\\\\\\\\,g`" + PATH="`pwd`/bin:$PATH" + # msys will convert any env vars with PATH in it to use msys + # form and will unconvert before launching + PYTHONPATH="`pwd -W`/python-lib;$PYTHONPATH" +else + CUDDLEFISH_ROOT="$VIRTUAL_ENV" + PYTHONPATH="$VIRTUAL_ENV/python-lib:$PYTHONPATH" + PATH="$VIRTUAL_ENV/bin:$PATH" +fi + +VIRTUAL_ENV="`pwd`" + +export CUDDLEFISH_ROOT +export PYTHONPATH +export PATH + +_OLD_VIRTUAL_PS1="$PS1" +if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" +else + PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" +fi +export PS1 + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then + hash -r +fi + +python -c "from jetpack_sdk_env import welcome; welcome()" diff --git a/tools/addon-sdk-1.7/bin/activate.bat b/tools/addon-sdk-1.7/bin/activate.bat new file mode 100644 index 0000000..5a6b885 --- /dev/null +++ b/tools/addon-sdk-1.7/bin/activate.bat @@ -0,0 +1,135 @@ +@echo off +rem This Source Code Form is subject to the terms of the Mozilla Public +rem License, v. 2.0. If a copy of the MPL was not distributed with this +rem file, You can obtain one at http://mozilla.org/MPL/2.0/. + +set VIRTUAL_ENV=%~dp0 +set VIRTUAL_ENV=%VIRTUAL_ENV:~0,-5% +set CUDDLEFISH_ROOT=%VIRTUAL_ENV% + +SET PYTHONKEY=SOFTWARE\Python\PythonCore + +rem look for 32-bit windows and python, or 64-bit windows and python + +SET PYTHONVERSION=2.7 +call:CheckPython PYTHONINSTALL %PYTHONKEY%\%PYTHONVERSION%\InstallPath +if "%PYTHONINSTALL%" NEQ "" goto FoundPython + +SET PYTHONVERSION=2.6 +call:CheckPython PYTHONINSTALL %PYTHONKEY%\%PYTHONVERSION%\InstallPath +if "%PYTHONINSTALL%" NEQ "" goto FoundPython + +SET PYTHONVERSION=2.5 +call:CheckPython PYTHONINSTALL %PYTHONKEY%\%PYTHONVERSION%\InstallPath +if "%PYTHONINSTALL%" NEQ "" goto FoundPython + +if not defined ProgramFiles(x86) goto win32 + +rem look for 32-bit python on 64-bit windows + +SET PYTHONKEY=SOFTWARE\Wow6432Node\Python\PythonCore + +SET PYTHONVERSION=2.7 +call:CheckPython PYTHONINSTALL %PYTHONKEY%\%PYTHONVERSION%\InstallPath +if "%PYTHONINSTALL%" NEQ "" goto FoundPython + +SET PYTHONVERSION=2.6 +call:CheckPython PYTHONINSTALL %PYTHONKEY%\%PYTHONVERSION%\InstallPath +if "%PYTHONINSTALL%" NEQ "" goto FoundPython + +SET PYTHONVERSION=2.5 +call:CheckPython PYTHONINSTALL %PYTHONKEY%\%PYTHONVERSION%\InstallPath +if "%PYTHONINSTALL%" NEQ "" goto FoundPython + +:win32 + +SET PYTHONVERSION= +set PYTHONKEY= +echo Warning: Failed to find Python installation directory +goto :EOF + +:FoundPython + +if defined _OLD_PYTHONPATH ( + set PYTHONPATH=%_OLD_PYTHONPATH% +) +if not defined PYTHONPATH ( + set PYTHONPATH=; +) +set _OLD_PYTHONPATH=%PYTHONPATH% +set PYTHONPATH=%VIRTUAL_ENV%\python-lib;%PYTHONPATH% + +if not defined PROMPT ( + set PROMPT=$P$G +) + +if defined _OLD_VIRTUAL_PROMPT ( + set PROMPT=%_OLD_VIRTUAL_PROMPT% +) + +set _OLD_VIRTUAL_PROMPT=%PROMPT% +set PROMPT=(%VIRTUAL_ENV%) %PROMPT% + +if defined _OLD_VIRTUAL_PATH goto OLDPATH +goto SKIPPATH +:OLDPATH +PATH %_OLD_VIRTUAL_PATH% + +:SKIPPATH +set _OLD_VIRTUAL_PATH=%PATH% +PATH %VIRTUAL_ENV%\bin;%PYTHONINSTALL%;%PATH% +set PYTHONKEY= +set PYTHONINSTALL= +set PYTHONVERSION= +set key= +set reg= +set _tokens= +cd "%VIRTUAL_ENV%" +python -c "from jetpack_sdk_env import welcome; welcome()" +GOTO :EOF + +:CheckPython +::CheckPython(retVal, key) +::Reads the registry at %2% and checks if a Python exists there. +::Checks both HKLM and HKCU, then checks the executable actually exists. +SET key=%2% +SET "%~1=" +SET reg=reg +if defined ProgramFiles(x86) ( + rem 32-bit cmd on 64-bit windows + if exist %WINDIR%\sysnative\reg.exe SET reg=%WINDIR%\sysnative\reg.exe +) +rem On Vista+, the last line of output is: +rem (default) REG_SZ the_value +rem (but note the word "default" will be localized. +rem On XP, the last line of output is: +rem \tREG_SZ\tthe_value +rem (not sure if "NO NAME" is localized or not!) +rem SO: we use ")>" as the tokens to split on, then nuke +rem the REG_SZ and any tabs or spaces. +FOR /F "usebackq tokens=2 delims=)>" %%A IN (`%reg% QUERY HKLM\%key% /ve 2^>NUL`) DO SET "%~1=%%A" +rem Remove the REG_SZ +set PYTHONINSTALL=%PYTHONINSTALL:REG_SZ=% +rem Remove tabs (note the literal \t in the next line +set PYTHONINSTALL=%PYTHONINSTALL: =% +rem Remove spaces. +set PYTHONINSTALL=%PYTHONINSTALL: =% +if exist %PYTHONINSTALL%\python.exe goto :EOF +rem It may be a 32bit Python directory built from source, in which case the +rem executable is in the PCBuild directory. +if exist %PYTHONINSTALL%\PCBuild\python.exe (set "PYTHONINSTALL=%PYTHONINSTALL%\PCBuild" & goto :EOF) +rem Or maybe a 64bit build directory. +if exist %PYTHONINSTALL%\PCBuild\amd64\python.exe (set "PYTHONINSTALL=%PYTHONINSTALL%\PCBuild\amd64" & goto :EOF) + +rem And try HKCU +FOR /F "usebackq tokens=2 delims=)>" %%A IN (`%reg% QUERY HKCU\%key% /ve 2^>NUL`) DO SET "%~1=%%A" +set PYTHONINSTALL=%PYTHONINSTALL:REG_SZ=% +set PYTHONINSTALL=%PYTHONINSTALL: =% +set PYTHONINSTALL=%PYTHONINSTALL: =% +if exist %PYTHONINSTALL%\python.exe goto :EOF +if exist %PYTHONINSTALL%\PCBuild\python.exe (set "PYTHONINSTALL=%PYTHONINSTALL%\PCBuild" & goto :EOF) +if exist %PYTHONINSTALL%\PCBuild\amd64\python.exe (set "PYTHONINSTALL=%PYTHONINSTALL%\PCBuild\amd64" & goto :EOF) +rem can't find it here, so arrange to try the next key +set PYTHONINSTALL= + +GOTO :EOF diff --git a/tools/addon-sdk-1.7/bin/activate.ps1 b/tools/addon-sdk-1.7/bin/activate.ps1 new file mode 100644 index 0000000..5d939d4 --- /dev/null +++ b/tools/addon-sdk-1.7/bin/activate.ps1 @@ -0,0 +1,99 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$Env:VIRTUAL_ENV = (gl); +$Env:CUDDLEFISH_ROOT = $Env:VIRTUAL_ENV; + +# http://stackoverflow.com/questions/5648931/powershell-test-if-registry-value-exists/5652674#5652674 +Function Test-RegistryValue { + param( + [Alias("PSPath")] + [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [String]$Path + , + [Parameter(Position = 1, Mandatory = $true)] + [String]$Name + , + [Switch]$PassThru + ) + + process { + if (Test-Path $Path) { + $Key = Get-Item -LiteralPath $Path + if ($Key.GetValue($Name, $null) -ne $null) { + if ($PassThru) { + Get-ItemProperty $Path $Name + } else { + $true + } + } else { + $false + } + } else { + $false + } + } +} + +$WINCURVERKEY = 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion'; +$WIN64 = (Test-RegistryValue $WINCURVERKEY 'ProgramFilesDir (x86)'); + +if($WIN64) { + $PYTHONKEY='HKLM:SOFTWARE\Wow6432Node\Python\PythonCore'; +} +else { + $PYTHONKEY='HKLM:SOFTWARE\Python\PythonCore'; +} + +$Env:PYTHONVERSION = ''; +$Env:PYTHONINSTALL = ''; + +foreach ($version in @('2.6', '2.5', '2.4')) { + if (Test-RegistryValue "$PYTHONKEY\$version\InstallPath" '(default)') { + $Env:PYTHONVERSION = $version; + } +} + +if ($Env:PYTHONVERSION) { + $Env:PYTHONINSTALL = (Get-Item "$PYTHONKEY\$version\InstallPath)").'(default)'; +} + +if ($Env:PYTHONINSTALL) { + $Env:Path += ";$Env:PYTHONINSTALL"; +} + +if (Test-Path Env:_OLD_PYTHONPATH) { + $Env:PYTHONPATH = $Env:_OLD_PYTHONPATH; +} +else { + $Env:PYTHONPATH = ''; +} + +$Env:_OLD_PYTHONPATH=$Env:PYTHONPATH; +$Env:PYTHONPATH= "$Env:VIRTUAL_ENV\python-lib;$Env:PYTHONPATH"; + +if (Test-Path Function:_OLD_VIRTUAL_PROMPT) { + Set-Content Function:Prompt (Get-Content Function:_OLD_VIRTUAL_PROMPT); +} +else { + function global:_OLD_VIRTUAL_PROMPT {} +} + +Set-Content Function:_OLD_VIRTUAL_PROMPT (Get-Content Function:Prompt); + +function global:prompt { "($Env:VIRTUAL_ENV) $(_OLD_VIRTUAL_PROMPT)"; }; + +if (Test-Path Env:_OLD_VIRTUAL_PATH) { + $Env:PATH = $Env:_OLD_VIRTUAL_PATH; +} +else { + $Env:_OLD_VIRTUAL_PATH = $Env:PATH; +} + +$Env:Path="$Env:VIRTUAL_ENV\bin;$Env:Path" + +[System.Console]::WriteLine("Note: this PowerShell SDK activation script is experimental.") + +python -c "from jetpack_sdk_env import welcome; welcome()" + diff --git a/tools/addon-sdk-1.7/bin/cfx b/tools/addon-sdk-1.7/bin/cfx new file mode 100755 index 0000000..2be9d19 --- /dev/null +++ b/tools/addon-sdk-1.7/bin/cfx @@ -0,0 +1,33 @@ +#! /usr/bin/env python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import os +import sys + +# set the cuddlefish "root directory" for this process if it's not already +# set in the environment +cuddlefish_root = os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))) + +if 'CUDDLEFISH_ROOT' not in os.environ: + os.environ['CUDDLEFISH_ROOT'] = cuddlefish_root + +# add our own python-lib path to the python module search path. +python_lib_dir = os.path.join(cuddlefish_root, "python-lib") +if python_lib_dir not in sys.path: + sys.path.append(python_lib_dir) + +# now export to env so sub-processes get it too +if 'PYTHONPATH' not in os.environ: + os.environ['PYTHONPATH'] = python_lib_dir +elif python_lib_dir not in os.environ['PYTHONPATH'].split(os.pathsep): + paths = os.environ['PYTHONPATH'].split(os.pathsep) + paths.insert(0, python_lib_dir) + os.environ['PYTHONPATH'] = os.pathsep.join(paths) + +import cuddlefish + +if __name__ == '__main__': + cuddlefish.run() diff --git a/tools/addon-sdk-1.7/bin/cfx.bat b/tools/addon-sdk-1.7/bin/cfx.bat new file mode 100644 index 0000000..215b034 --- /dev/null +++ b/tools/addon-sdk-1.7/bin/cfx.bat @@ -0,0 +1,6 @@ +@echo off +rem This Source Code Form is subject to the terms of the Mozilla Public +rem License, v. 2.0. If a copy of the MPL was not distributed with this +rem file, You can obtain one at http://mozilla.org/MPL/2.0/. + +python "%VIRTUAL_ENV%\bin\cfx" %* diff --git a/tools/addon-sdk-1.7/bin/deactivate.bat b/tools/addon-sdk-1.7/bin/deactivate.bat new file mode 100644 index 0000000..e6bcd92 --- /dev/null +++ b/tools/addon-sdk-1.7/bin/deactivate.bat @@ -0,0 +1,23 @@ +@echo off +rem This Source Code Form is subject to the terms of the Mozilla Public +rem License, v. 2.0. If a copy of the MPL was not distributed with this +rem file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) +set _OLD_VIRTUAL_PROMPT= + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) +set _OLD_VIRTUAL_PATH= + +if defined _OLD_PYTHONPATH ( + set "PYTHONPATH=%_OLD_PYTHONPATH%" +) +set _OLD_PYTHONPATH= + +set CUDDLEFISH_ROOT= + +:END diff --git a/tools/addon-sdk-1.7/bin/integration-scripts/buildbot-run-cfx-helper b/tools/addon-sdk-1.7/bin/integration-scripts/buildbot-run-cfx-helper new file mode 100755 index 0000000..56c76ad --- /dev/null +++ b/tools/addon-sdk-1.7/bin/integration-scripts/buildbot-run-cfx-helper @@ -0,0 +1,14 @@ +#!/bin/bash +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +source ./bin/activate +if [ type -P xvfb-run ] +then + xvfb-run cfx $* +else + cfx $* +fi +deactivate diff --git a/tools/addon-sdk-1.7/bin/integration-scripts/integration-check b/tools/addon-sdk-1.7/bin/integration-scripts/integration-check new file mode 100644 index 0000000..d64472f --- /dev/null +++ b/tools/addon-sdk-1.7/bin/integration-scripts/integration-check @@ -0,0 +1,364 @@ +#!/usr/bin/env python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import signal +import threading +import urllib2, urllib +import zipfile +import tarfile +import subprocess +import optparse +import sys, re +#import win32api + + +class SDK: + def __init__(self): + try: + # Take the current working directory + self.default_path = os.getcwd() + if sys.platform == "win32": + self.mswindows = True + else: + self.mswindows = False + # Take the default home path of the user. + home = os.path.expanduser('~') + + # The following are the parameters that can be used to pass a dynamic URL, a specific path or a binry. The binary is not used yet. It will be used in version 2.0 + # If a dynamic path is to be mentioned, it should start with a '/'. For eg. "/Desktop" + parser = optparse.OptionParser() + parser.add_option('-u', '--url', dest = 'url', default = 'https://ftp.mozilla.org/pub/mozilla.org/labs/jetpack/addon-sdk-latest.zip') + parser.add_option('-p', '--path', dest = 'path', default = self.default_path) + parser.add_option('-b', '--binary', dest = 'binary')#, default='/Applications/Firefox.app') + (options, args) = parser.parse_args() + + # Get the URL from the parameter + self.link = options.url + # Set the base path for the user. If the user supplies the path, use the home variable as well. Else, take the default path of this script as the installation directory. + if options.path!=self.default_path: + if self.mswindows: + self.base_path = home + str(options.path).strip() + '\\' + else: + self.base_path = home + str(options.path).strip() + '/' + else: + if self.mswindows: + self.base_path = str(options.path).strip() + '\\' + else: + self.base_path = str(options.path).strip() + '/' + assert ' ' not in self.base_path, "You cannot have a space in your home path. Please remove the space before you continue." + print('Your Base path is =' + self.base_path) + + # This assignment is not used in this program. It will be used in version 2 of this script. + self.bin = options.binary + # if app or bin is empty, dont pass anything + + # Search for the .zip file or tarball file in the URL. + i = self.link.rfind('/') + + self.fname = self.link[i+1:] + z = re.search('zip',self.fname,re.I) + g = re.search('gz',self.fname,re.I) + if z: + print 'zip file present in the URL.' + self.zip = True + self.gz = False + elif g: + print 'gz file present in the URL' + self.gz = True + self.zip = False + else: + print 'zip/gz file not present. Check the URL.' + return + print("File name is =" + self.fname) + + # Join the base path and the zip/tar file name to crate a complete Local file path. + self.fpath = self.base_path + self.fname + print('Your local file path will be=' + self.fpath) + except AssertionError, e: + print e.args[0] + sys.exit(1) + + # Download function - to download the SDK from the URL to the local machine. + def download(self,url,fpath,fname): + try: + # Start the download + print("Downloading...Please be patient!") + urllib.urlretrieve(url,filename = fname) + print('Download was successful.') + except ValueError: # Handles broken URL errors. + print 'The URL is ether broken or the file does not exist. Please enter the correct URL.' + raise + except urllib2.URLError: # Handles URL errors + print '\nURL not correct. Check again!' + raise + + # Function to extract the downloaded zipfile. + def extract(self, zipfilepath, extfile): + try: + # Timeout is set to 30 seconds. + timeout = 30 + # Change the directory to the location of the zip file. + try: + os.chdir(zipfilepath) + except OSError: + # Will reach here if zip file doesnt exist + print 'O/S Error:' + zipfilepath + 'does not exist' + raise + + # Get the folder name of Jetpack to get the exact version number. + if self.zip: + try: + f = zipfile.ZipFile(extfile, "r") + except IOError as (errno, strerror): # Handles file errors + print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror) + raise + list = f.namelist()[0] + temp_name = list.split('/') + print('Folder Name= ' +temp_name[0]) + self.folder_name = temp_name[0] + elif self.gz: + try: + f = tarfile.open(extfile,'r') + except IOError as (errno, strerror): # Handles file errors + print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror) + raise + list = f.getnames()[0] + temp_name = list.split('/') + print('Folder Name= ' +temp_name[0]) + self.folder_name = temp_name[0] + + print ('Starting to Extract...') + + # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned- + # timeout, the process is killed. + kill_check = threading.Event() + + if self.zip: + # Call the command to unzip the file. + if self.mswindows: + zipfile.ZipFile.extractall(f) + else: + p = subprocess.Popen('unzip '+extfile, stdout=subprocess.PIPE, shell=True) + pid = p.pid + elif self.gz: + # Call the command to untar the file. + if self.mswindows: + tarfile.TarFile.extractall(f) + else: + p = subprocess.Popen('tar -xf '+extfile, stdout=subprocess.PIPE, shell=True) + pid = p.pid + + #No need to handle for windows because windows automatically replaces old files with new files. It does not ask the user(as it does in Mac/Unix) + if self.mswindows==False: + watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows )) + watch.start() + (stdout, stderr) = p.communicate() + watch.cancel() # if it's still waiting to run + success = not kill_check.isSet() + + # Abort process if process fails. + if not success: + raise RuntimeError + kill_check.clear() + print('Extraction Successful.') + except RuntimeError: + print "Ending the program" + sys.exit(1) + except: + print "Error during file extraction: ", sys.exc_info()[0] + raise + + # Function to run the cfx testall comands and to make sure the SDK is not broken. + def run_testall(self, home_path, folder_name): + try: + timeout = 500 + + self.new_dir = home_path + folder_name + try: + os.chdir(self.new_dir) + except OSError: + # Will reach here if the jetpack 0.X directory doesnt exist + print 'O/S Error: Jetpack directory does not exist at ' + self.new_dir + raise + print '\nStarting tests...' + # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned- + # timeout, the process is killed. + kill_check = threading.Event() + + # Set the path for the logs. They will be in the parent directory of the Jetpack SDK. + log_path = home_path + 'tests.log' + + # Subprocess call to set up the jetpack environment and to start the tests. Also sends the output to a log file. + if self.bin != None: + if self.mswindows: + p = subprocess.Popen("bin\\activate && cfx testall -a firefox -b \"" + self.bin + "\"" , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + proc_handle = p._handle + (stdout,stderr) = p.communicate() + else: + p = subprocess.Popen('. bin/activate; cfx testall -a firefox -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + pid = p.pid + (stdout,stderr) = p.communicate() + elif self.bin == None: + if self.mswindows: + p=subprocess.Popen('bin\\activate && cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + proc_handle = p._handle + (stdout,stderr) = p.communicate() + else: + p = subprocess.Popen('. bin/activate; cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + pid = p.pid + (stdout,stderr) = p.communicate() + + #Write the output to log file + f=open(log_path,"w") + f.write(stdout+stderr) + f.close() + + #Watchdog for timeout process + if self.mswindows: + watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows)) + else: + watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows)) + watch.start() + watch.cancel() # if it's still waiting to run + success = not kill_check.isSet() + if not success: + raise RuntimeError + kill_check.clear() + + if p.returncode!=0: + print('\nAll tests were not successful. Check the test-logs in the jetpack directory.') + result_sdk(home_path) + #sys.exit(1) + raise RuntimeError + else: + ret_code=result_sdk(home_path) + if ret_code==0: + print('\nAll tests were successful. Yay \o/ . Running a sample package test now...') + else: + print ('\nThere were errors during the tests.Take a look at logs') + raise RuntimeError + except RuntimeError: + print "Ending the program" + sys.exit(1) + except: + print "Error during the testall command execution:", sys.exc_info()[0] + raise + + def package(self, example_dir): + try: + timeout = 30 + + print '\nNow Running packaging tests...' + + kill_check = threading.Event() + + # Set the path for the example logs. They will be in the parent directory of the Jetpack SDK. + exlog_path = example_dir + 'test-example.log' + # Subprocess call to test the sample example for packaging. + if self.bin!=None: + if self.mswindows: + p = subprocess.Popen('bin\\activate && cfx run --pkgdir examples\\reading-data --static-args="{\"quitWhenDone\":true}" -b \"" + self.bin + "\"' , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + proc_handle = p._handle + (stdout, stderr) = p.communicate() + else: + p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data --static-args=\'{\"quitWhenDone\":true}\' -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + pid = p.pid + (stdout, stderr) = p.communicate() + elif self.bin==None: + if self.mswindows: + p = subprocess.Popen('bin\\activate && cfx run --pkgdir examples\\reading-data --static-args="{\"quitWhenDone\":true}"', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + proc_handle = p._handle + (stdout, stderr) = p.communicate() + else: + p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data --static-args=\'{\"quitWhenDone\":true}\' ', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + pid = p.pid + (stdout, stderr) = p.communicate() + + #Write the output to log file + f=open(exlog_path,"w") + f.write(stdout+stderr) + f.close() + + #Watch dog for timeout process + if self.mswindows: + watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows)) + else: + watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows)) + watch.start() + watch.cancel() # if it's still waiting to run + success = not kill_check.isSet() + if not success: + raise RuntimeError + kill_check.clear() + + if p.returncode != 0: + print('\nSample tests were not executed correctly. Check the test-example log in jetpack diretory.') + result_example(example_dir) + raise RuntimeError + else: + ret_code=result_example(example_dir) + if ret_code==0: + print('\nAll tests pass. The SDK is working! Yay \o/') + else: + print ('\nTests passed with warning.Take a look at logs') + sys.exit(1) + + except RuntimeError: + print "Ending program" + sys.exit(1) + except: + print "Error during running sample tests:", sys.exc_info()[0] + raise + +def result_sdk(sdk_dir): + log_path = sdk_dir + 'tests.log' + print 'Results are logged at:' + log_path + try: + f = open(log_path,'r') + # Handles file errors + except IOError : + print 'I/O error - Cannot open test log at ' + log_path + raise + + for line in reversed(open(log_path).readlines()): + if line.strip()=='FAIL': + print ('\nOverall result - FAIL. Look at the test log at '+log_path) + return 1 + return 0 + + +def result_example(sdk_dir): + exlog_path = sdk_dir + 'test-example.log' + print 'Sample test results are logged at:' + exlog_path + try: + f = open(exlog_path,'r') + # Handles file errors + except IOError : + print 'I/O error - Cannot open sample test log at ' + exlog_path + raise + + #Read the file in reverse and check for the keyword 'FAIL'. + for line in reversed(open(exlog_path).readlines()): + if line.strip()=='FAIL': + print ('\nOverall result for Sample tests - FAIL. Look at the test log at '+exlog_path) + return 1 + return 0 + +def kill_process(process, kill_check, mswindows): + print '\nProcess Timedout. Killing the process. Please Rerun this script.' + if mswindows: + win32api.TerminateProcess(process, -1) + else: + os.kill(process, signal.SIGKILL) + kill_check.set()# tell the main routine to kill. Used SIGKILL to hard kill the process. + return + +if __name__ == "__main__": + obj = SDK() + obj.download(obj.link,obj.fpath,obj.fname) + obj.extract(obj.base_path,obj.fname) + obj.run_testall(obj.base_path,obj.folder_name) + obj.package(obj.base_path) diff --git a/tools/addon-sdk-1.7/examples/annotator/README.md b/tools/addon-sdk-1.7/examples/annotator/README.md new file mode 100644 index 0000000..d376240 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/README.md @@ -0,0 +1,46 @@ + + +This add-on enables users to add notes, or annotations, to Web pages. + +Usage +----- + +To switch the annotator on, left-click the pencil icon in the Add-on Bar. The +icon should turn yellow: this indicates that the annotator is active. To switch +it off, click it again. Switching it on/off only stops you from entering +annotations: existing annotations are still displayed. + +When the annotator is active and the user moves the mouse over a page element +that can be annotated, the annotator highlights that elements by giving it a +yellow background. + +If the user clicks on a highlighted element the add-on opens a dialog for the +user to enter the annotation. When the user hits the annotation is +saved. + +Elements which have been annotated are displayed with a yellow border: when the +user moves the mouse over one of these elements, the add-on displays the +annotation associated with that element. + +To view all annotations in a list, right-click the pencil icon. + +The add-on is deactivated in private browsing mode, meaning that new annotations +can't be created although existing ones are still shown. On exiting private +browsing the add-on returns to its previous activation state. + +Known Issues/Limitations +------------------------ + +It is not possible to delete annotations, or to edit them after creating them, +but it would be simple to add this. + +When right-clicking the annotator icon the add-on bar's context-menu is shown: +this is tracked by +[bug 626326](https://bugzilla.mozilla.org/show_bug.cgi?id=626326). + +The list of annotations should be anchored to the widget. The annotation +editor, and the annotation itself, should be anchored to the element which is +annotated. The will be done when the implementation of panel-anchoring is +extended. diff --git a/tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.html b/tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.html new file mode 100644 index 0000000..f61c5e1 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.html @@ -0,0 +1,31 @@ + + + + + + + Annotation + + + + + + +
+
+ + + diff --git a/tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.js b/tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.js new file mode 100644 index 0000000..c1f57aa --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/annotation/annotation.js @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +Initialize annotation content. +*/ + +self.on('message', function(message) { + $('#annotation').text(message); +}); diff --git a/tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.html b/tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.html new file mode 100644 index 0000000..6125999 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.html @@ -0,0 +1,39 @@ + + + + + + + Annotation + + + + + + + + + + + diff --git a/tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.js b/tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.js new file mode 100644 index 0000000..2fe5888 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/editor/annotation-editor.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/. */ + +/* +On a return key, send the content of the textArea back to the add-on, +and zero the textArea for the next time. +*/ + +var textArea = document.getElementById('annotation-box'); + +textArea.onkeyup = function(event) { + if (event.keyCode == 13) { + self.postMessage(textArea.value); + textArea.value = ''; + } +}; + +self.on('message', function() { + var textArea = document.getElementById('annotation-box'); + textArea.value = ''; + textArea.focus(); +}); diff --git a/tools/addon-sdk-1.7/examples/annotator/data/jquery-1.4.2.min.js b/tools/addon-sdk-1.7/examples/annotator/data/jquery-1.4.2.min.js new file mode 100644 index 0000000..7c24308 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/jquery-1.4.2.min.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.css b/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.css new file mode 100644 index 0000000..9063682 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.css @@ -0,0 +1,40 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#annotation-list .annotation-details + { + padding: 10px; + margin: 10px; + border: solid 3px #EEE; + background-color: white; + } + +#annotation-list .url, .selection-text, .annotation-text + { + padding: 5px; + margin: 5px; + } + +#annotation-list .selection-text,#annotation-list .annotation-text + { + border: solid 1px #EEE; + } + +#annotation-list .annotation-text + { + font-style: italic; + } + +body + { + background-color: #F5F5F5; + font: 100% arial, helvetica, sans-serif; + } + +h1 + { + font-family: georgia,serif; + font-size: 1.5em; + text-align:center; + } diff --git a/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.html b/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.html new file mode 100644 index 0000000..32a5409 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.html @@ -0,0 +1,26 @@ + + + + + + Saved annotations + + + + +
+
+ +
+
+ +
+
+
+
+ + + + diff --git a/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.js b/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.js new file mode 100644 index 0000000..5653ba5 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/list/annotation-list.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/. */ + +/* +Construct the HTML for the annotation list. + +Bind a function to click events on the link that send a message back to +the add-on code, so it can open the link in the main browser. +*/ + +self.on("message", function onMessage(storedAnnotations) { + var annotationList = $('#annotation-list'); + annotationList.empty(); + storedAnnotations.forEach( + function(storedAnnotation) { + var annotationHtml = $('#template .annotation-details').clone(); + annotationHtml.find('.url').text(storedAnnotation.url) + .attr('href', storedAnnotation.url); + annotationHtml.find('.url').bind('click', function(event) { + event.stopPropagation(); + event.preventDefault(); + self.postMessage(storedAnnotation.url); + }); + annotationHtml.find('.selection-text') + .text(storedAnnotation.anchorText); + annotationHtml.find('.annotation-text') + .text(storedAnnotation.annotationText); + annotationList.append(annotationHtml); + }); +}); diff --git a/tools/addon-sdk-1.7/examples/annotator/data/matcher.js b/tools/addon-sdk-1.7/examples/annotator/data/matcher.js new file mode 100644 index 0000000..86d6bc7 --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/matcher.js @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +Locate anchors for annotations and prepare to display the annotations. + +For each annotation, if its URL matches this page, +- get the ancestor whose ID matches the ID in the anchor +- look for a

element whose content contains the anchor text + +That's considered a match. Then we: +- highlight the anchor element +- add an 'annotated' class to tell the selector to skip this element +- embed the annottion text as a new attribute + +For all annotated elements: +- bind 'mouseenter' and 'mouseleave' events to the element, to send 'show' + and 'hide' messages back to the add-on. +*/ + +self.on('message', function onMessage(annotations) { + annotations.forEach( + function(annotation) { + if(annotation.url == document.location.toString()) { + createAnchor(annotation); + } + }); + + $('.annotated').css('border', 'solid 3px yellow'); + + $('.annotated').bind('mouseenter', function(event) { + self.port.emit('show', $(this).attr('annotation')); + event.stopPropagation(); + event.preventDefault(); + }); + + $('.annotated').bind('mouseleave', function() { + self.port.emit('hide'); + }); +}); + + +function createAnchor(annotation) { + annotationAnchorAncestor = $('#' + annotation.ancestorId)[0] || document.body; + annotationAnchor = $(annotationAnchorAncestor).parent().find( + ':contains("' + annotation.anchorText + '")').last(); + annotationAnchor.addClass('annotated'); + annotationAnchor.attr('annotation', annotation.annotationText); +} diff --git a/tools/addon-sdk-1.7/examples/annotator/data/selector.js b/tools/addon-sdk-1.7/examples/annotator/data/selector.js new file mode 100644 index 0000000..f42dbfa --- /dev/null +++ b/tools/addon-sdk-1.7/examples/annotator/data/selector.js @@ -0,0 +1,73 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +The selector locates elements that are suitable for annotation and enables +the user to select them. + +On 'mouseenter' events associated with

elements: +- if the selector is active and the element is not already annotated +- find the nearest ancestor which has an id attribute: this is supposed to +make identification of this element more accurate +- highlight the element +- bind 'click' for the element to send a message back to the add-on, including +all the information associated with the anchor. +*/ + +var matchedElement = null; +var originalBgColor = null; +var active = false; + +function resetMatchedElement() { + if (matchedElement) { + matchedElement.css('background-color', originalBgColor); + matchedElement.unbind('click.annotator'); + } +} + +self.on('message', function onMessage(activation) { + active = activation; + if (!active) { + resetMatchedElement(); + } +}); + +function getInnerText(element) { + // jQuery.text() returns content of ` in the page header. + +* **in the "main.js" file**: remove the `contentScriptFile` option in +the `Page()` constructor. + + + + +@class +A `Page` object loads the page specified by its `contentURL` option and +executes any content scripts that have been supplied to it in the +`contentScript` and `contentScriptFile` options. + +The page is not displayed to the user. + +The page worker is loaded as soon as the `Page` object is created and stays +loaded until its `destroy` method is called or the add-on is unloaded. + + +@constructor + Creates an uninitialized page worker instance. +@param [options] {object} + The *`options`* parameter is optional, and if given it should be an object + with any of the following keys: + @prop [contentURL] {string} + The URL of the content to load in the panel. + @prop [allow] {object} + An object with keys to configure the permissions on the page worker. The + boolean key `script` controls if scripts from the page are allowed to run. + `script` defaults to true. + @prop [contentScriptFile] {string,array} + A local file URL or an array of local file URLs of content scripts to load. + Content scripts specified by this option are loaded *before* those specified + by the `contentScript` option. See + [Working with Content Scripts](dev-guide/guides/content-scripts/index.html) + for help on setting this property. + @prop [contentScript] {string,array} + A string or an array of strings containing the texts of content scripts to + load. Content scripts specified by this option are loaded *after* those + specified by the `contentScriptFile` option. + @prop [contentScriptWhen="end"] {string} + When to load the content scripts. This may take one of the following + values: + + * "start": load content scripts immediately after the document + element for the page is inserted into the DOM, but before the DOM content + itself has been loaded + * "ready": load content scripts once DOM content has been loaded, + corresponding to the + [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) + event + * "end": load content scripts once all the content (DOM, JS, CSS, + images) for the page has been loaded, at the time the + [window.onload event](https://developer.mozilla.org/en/DOM/window.onload) + fires + + This property is optional and defaults to "end". + + @prop [onMessage] {function} + Use this to add a listener to the page worker's `message` event. + + + +@property {EventEmitter} +[EventEmitter](packages/api-utils/events.html) object that allows you to: + +* send events to the content script using the `port.emit` function +* receive events from the content script using the `port.on` function + +See the guide to + +communicating using port for details. + + + +@property {string} +The URL of content to load. This can point to +local content loaded from your add-on's "data" directory or remote content. +Setting it loads the content immediately. + + + +@property {object} + A object describing permissions for the content. It contains a single key + named `script` whose value is a boolean that indicates whether or not to + execute script in the content. `script` defaults to true. + + + +@property {string,array} +A local file URL or an array of local file URLs of content scripts to load. + + + +@property {string,array} +A string or an array of strings containing the texts of content scripts to +load. + + + +@property {string} + When to load the content scripts. This may have one of the following + values: + + * "start": load content scripts immediately after the document + element for the page is inserted into the DOM, but before the DOM content + itself has been loaded + * "ready": load content scripts once DOM content has been loaded, + corresponding to the + [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) + event + * "end": load content scripts once all the content (DOM, JS, CSS, + images) for the page has been loaded, at the time the + [window.onload event](https://developer.mozilla.org/en/DOM/window.onload) + fires + + + + +@method +Unloads the page worker. After you destroy a page worker, its memory is freed +and you must create a new instance if you need to load another page. + + + +@method +Sends a message to the content scripts. +@param message {value} +The message to send. Must be JSON-able. + + + +@method +Registers an event listener with the page worker. See +[Working with Events](dev-guide/guides/events.html) for help with +events. +@param type {string} +The type of event to listen for. +@param listener {function} +The listener function that handles the event. + + + +@method +Unregisters an event listener from the page worker. +@param type {string} +The type of event for which `listener` was registered. +@param listener {function} +The listener function that was registered. + + + +@event +If you listen to this event you can receive message events from content +scripts associated with this page worker. When a content script posts a +message using `self.postMessage()`, the message is delivered to the add-on +code in the page worker's `message` event. + +@argument {value} +Listeners are passed a single argument which is the message posted +from the content script. The message can be any +JSON-serializable value + + + +@event +This event is emitted when an uncaught runtime error occurs in one of the +page worker's content scripts. + +@argument {Error} +Listeners are passed a single argument, the +[Error](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error) +object. + + + diff --git a/tools/addon-sdk-1.7/packages/addon-kit/docs/panel.md b/tools/addon-sdk-1.7/packages/addon-kit/docs/panel.md new file mode 100644 index 0000000..0a85db9 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/docs/panel.md @@ -0,0 +1,607 @@ + + + + + +This module exports a single constructor function `Panel` which constructs a +new panel. + +A panel is a dialog. Its content is specified as HTML and you can +execute scripts in it, so the appearance and behaviour of the panel +is limited only by what you can do using HTML, CSS and JavaScript. + +The screenshot below shows a panel whose content is built from the +list of currently open tabs: + + + +Panels are useful for presenting temporary interfaces to users in a way that is +easier for users to ignore and dismiss than a modal dialog, since panels are +hidden the moment users interact with parts of the application interface outside +them. + +A panel's content is loaded as soon as it is created, before the panel is shown, +and the content remains loaded when a panel is hidden, so it is possible +to keep a panel around in the background, updating its content as appropriate +in preparation for the next time it is shown. + +Your add-on can receive notifications when a panel is shown or hidden by +listening to its `show` and `hide` events. + +## Panel Content ## + +The panel's content is specified as HTML, which is loaded from the URL +supplied in the `contentURL` option to the panel's constructor. + +You can load remote HTML into the panel: + + var panel = require("panel").Panel({ + width: 180, + height: 180, + contentURL: "https://en.wikipedia.org/w/index.php?title=Jetpack&useformat=mobile" + }); + + panel.show(); + + + +You can also load HTML that's been packaged with your add-on, and this is +most probably how you will create dialogs. To do this, save +the HTML in your add-on's `data` directory and load it using the `data.url()` +method exported by the +[`self`](packages/addon-kit/self.html) module, like this: + + var panel = require("panel").Panel({ + contentURL: require("self").data.url("myFile.html") + }); + + panel.show(); + +## Updating Panel Content ## + +You can update the panel's content simply by setting the panel's `contentURL` +property. + +Here's an add-on that adds two widgets to the add-on bar, one which +shows Google's mobile site and one which shows Bing's mobile site. The widgets +share a panel object, and switch between the two sites by updating the panel's +`contentURL` property: + + var panel = require("panel").Panel({ + contentURL: "about:blank", + onHide: function () { + panel.contentURL = "about:blank"; + } + }); + + require("widget").Widget({ + id: "bing", + label: "Bing", + contentURL: "http://www.bing.com/favicon.ico", + panel: panel, + onClick: function() { + panel.contentURL = "http://m.bing.com/"; + } + }); + + require("widget").Widget({ + id: "google", + label: "Google", + contentURL: "http://www.google.com/favicon.ico", + panel: panel, + onClick: function() { + panel.contentURL = "http://www.google.com/xhtml"; + } + }); + +## Scripting Panel Content ## + +You can't directly access your panel's content from your main add-on code. +To access the panel's content, you need to load a script into the panel. +In the SDK these scripts are called "content scripts" because they're +explicitly used for interacting with web content. + +While content scripts can access the content they're attached to, they can't +use the SDK's APIs. So implementing a complete solution usually means you +have to send messages between the content script and the main add-on code. + +* You can specify one or more content scripts to load into a panel using the +`contentScript` or `contentScriptFile` options to the +[`Panel()` constructor](packages/addon-kit/panel.html#Panel%28options%29). + +* You can communicate with the script using either the +[`postMessage()`](dev-guide/guides/content-scripts/using-postmessage.html) +API or (preferably, usually) the +[`port`](dev-guide/guides/content-scripts/using-port.html) API. + +For example, here's an add-on whose content script intercepts mouse clicks +on links inside the panel, and sends the target URL to the main add-on +code. The content script sends messages using `self.port.emit()` and the +add-on script receives them using `panel.port.on()`. + + var myScript = "window.addEventListener('click', function(event) {" + + " var t = event.target;" + + " if (t.nodeName == 'A')" + + " self.port.emit('click-link', t.toString());" + + "}, false);" + + var panel = require("panel").Panel({ + contentURL: "http://www.bbc.co.uk/mobile/index.html", + contentScript: myScript + }); + + panel.port.on("click-link", function(url) { + console.log(url); + }); + + panel.show(); + +This example uses `contentScript` to supply the script as a string. It's +usually better practice to use `contentScriptFile`, which is a URL pointing +to a script file saved under your add-on's `data` directory. + +

+

Unless your content script is extremely simple and consists only of a +static string, don't use contentScript: if you do, you may +have problems getting your add-on approved on AMO.

+

Instead, keep the script in a separate file and load it using +contentScriptFile. This makes your code easier to maintain, +secure, debug and review.

+
+ + + +### Getting User Input ### + +The following add-on adds a widget which displays a panel when +clicked. The panel just contains a ` +

+ +

+ +

+ + diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-context-menu.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-context-menu.js new file mode 100644 index 0000000..c398933 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-context-menu.js @@ -0,0 +1,2067 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +let {Cc,Ci} = require("chrome"); +const { Loader } = require('./helpers'); + +// These should match the same constants in the module. +const ITEM_CLASS = "jetpack-context-menu-item"; +const SEPARATOR_ID = "jetpack-context-menu-separator"; +const OVERFLOW_THRESH_DEFAULT = 10; +const OVERFLOW_THRESH_PREF = + "extensions.addon-sdk.context-menu.overflowThreshold"; +const OVERFLOW_MENU_ID = "jetpack-content-menu-overflow-menu"; +const OVERFLOW_POPUP_ID = "jetpack-content-menu-overflow-popup"; + +const TEST_DOC_URL = module.uri.replace(/\.js$/, ".html"); + +// Destroying items that were previously created should cause them to be absent +// from the menu. +exports.testConstructDestroy = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + // Create an item. + let item = new loader.cm.Item({ label: "item" }); + test.assertEqual(item.parentMenu, null, "item's parent menu should be null"); + + test.showMenu(null, function (popup) { + + // It should be present when the menu is shown. + test.checkMenu([item], [], []); + popup.hidePopup(); + + // Destroy the item. Multiple destroys should be harmless. + item.destroy(); + item.destroy(); + test.showMenu(null, function (popup) { + + // It should be removed from the menu. + test.checkMenu([], [], [item]); + test.done(); + }); + }); +}; + + +// Destroying an item twice should not cause an error. +exports.testDestroyTwice = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ label: "item" }); + item.destroy(); + item.destroy(); + + test.pass("Destroying an item twice should not cause an error."); + test.done(); +}; + + +// CSS selector contexts should cause their items to be present in the menu +// when the menu is invoked on nodes that match the selectors. +exports.testSelectorContextMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + data: "item", + context: loader.cm.SelectorContext("img") + }); + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("image"), function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); + }); +}; + + +// CSS selector contexts should cause their items to be present in the menu +// when the menu is invoked on nodes that have ancestors that match the +// selectors. +exports.testSelectorAncestorContextMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + data: "item", + context: loader.cm.SelectorContext("a[href]") + }); + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("span-link"), function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); + }); +}; + + +// CSS selector contexts should cause their items to be absent from the menu +// when the menu is not invoked on nodes that match or have ancestors that +// match the selectors. +exports.testSelectorContextNoMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + data: "item", + context: loader.cm.SelectorContext("img") + }); + + test.showMenu(null, function (popup) { + test.checkMenu([], [item], []); + test.done(); + }); +}; + + +// Page contexts should cause their items to be present in the menu when the +// menu is not invoked on an active element. +exports.testPageContextMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let items = [ + new loader.cm.Item({ + label: "item 0" + }), + new loader.cm.Item({ + label: "item 1", + context: undefined + }), + new loader.cm.Item({ + label: "item 2", + context: loader.cm.PageContext() + }), + new loader.cm.Item({ + label: "item 3", + context: [loader.cm.PageContext()] + }) + ]; + + test.showMenu(null, function (popup) { + test.checkMenu(items, [], []); + test.done(); + }); +}; + + +// Page contexts should cause their items to be absent from the menu when the +// menu is invoked on an active element. +exports.testPageContextNoMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let items = [ + new loader.cm.Item({ + label: "item 0" + }), + new loader.cm.Item({ + label: "item 1", + context: undefined + }), + new loader.cm.Item({ + label: "item 2", + context: loader.cm.PageContext() + }), + new loader.cm.Item({ + label: "item 3", + context: [loader.cm.PageContext()] + }) + ]; + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("image"), function (popup) { + test.checkMenu([], items, []); + test.done(); + }); + }); +}; + + +// Selection contexts should cause items to appear when a selection exists. +exports.testSelectionContextMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = loader.cm.Item({ + label: "item", + context: loader.cm.SelectionContext() + }); + + test.withTestDoc(function (window, doc) { + window.getSelection().selectAllChildren(doc.body); + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); + }); +}; + + +// Selection contexts should cause items to appear when a selection exists in +// a text field. +exports.testSelectionContextMatchInTextField = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = loader.cm.Item({ + label: "item", + context: loader.cm.SelectionContext() + }); + + test.withTestDoc(function (window, doc) { + let textfield = doc.getElementById("textfield"); + textfield.setSelectionRange(0, textfield.value.length); + test.showMenu(textfield, function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); + }); +}; + + +// Selection contexts should not cause items to appear when a selection does +// not exist in a text field. +exports.testSelectionContextNoMatchInTextField = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = loader.cm.Item({ + label: "item", + context: loader.cm.SelectionContext() + }); + + test.withTestDoc(function (window, doc) { + let textfield = doc.getElementById("textfield"); + textfield.setSelectionRange(0, 0); + test.showMenu(textfield, function (popup) { + test.checkMenu([], [item], []); + test.done(); + }); + }); +}; + + +// Selection contexts should not cause items to appear when a selection does +// not exist. +exports.testSelectionContextNoMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = loader.cm.Item({ + label: "item", + context: loader.cm.SelectionContext() + }); + + test.showMenu(null, function (popup) { + test.checkMenu([], [item], []); + test.done(); + }); +}; + + +// URL contexts should cause items to appear on pages that match. +exports.testURLContextMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let items = [ + loader.cm.Item({ + label: "item 0", + context: loader.cm.URLContext(TEST_DOC_URL) + }), + loader.cm.Item({ + label: "item 1", + context: loader.cm.URLContext([TEST_DOC_URL, "*.bogus.com"]) + }) + ]; + + test.withTestDoc(function (window, doc) { + test.showMenu(null, function (popup) { + test.checkMenu(items, [], []); + test.done(); + }); + }); +}; + + +// URL contexts should not cause items to appear on pages that do not match. +exports.testURLContextNoMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let items = [ + loader.cm.Item({ + label: "item 0", + context: loader.cm.URLContext("*.bogus.com") + }), + loader.cm.Item({ + label: "item 1", + context: loader.cm.URLContext(["*.bogus.com", "*.gnarly.com"]) + }) + ]; + + test.withTestDoc(function (window, doc) { + test.showMenu(null, function (popup) { + test.checkMenu([], items, []); + test.done(); + }); + }); +}; + + +// Removing a non-matching URL context after its item is created and the page is +// loaded should cause the item's content script to be evaluated. +exports.testURLContextRemove = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let shouldBeEvaled = false; + let context = loader.cm.URLContext("*.bogus.com"); + let item = loader.cm.Item({ + label: "item", + context: context, + contentScript: 'self.postMessage("ok");', + onMessage: function (msg) { + test.assert(shouldBeEvaled, + "content script should be evaluated when expected"); + shouldBeEvaled = false; + test.done(); + } + }); + + test.withTestDoc(function (window, doc) { + shouldBeEvaled = true; + item.context.remove(context); + }); +}; + + +// Adding a non-matching URL context after its item is created and the page is +// loaded should cause the item's worker to be destroyed. +exports.testURLContextAdd = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = loader.cm.Item({ label: "item" }); + + test.withTestDoc(function (window, doc) { + let privatePropsKey = loader.globalScope.PRIVATE_PROPS_KEY; + let workerReg = item.valueOf(privatePropsKey)._workerReg; + + let found = false; + for each (let winWorker in workerReg.winWorkers) { + if (winWorker.win === window) { + found = true; + break; + } + } + this.test.assert(found, "window should be present in worker registry"); + + item.context.add(loader.cm.URLContext("*.bogus.com")); + + for each (let winWorker in workerReg.winWorkers) + this.test.assertNotEqual(winWorker.win, window, + "window should not be present in worker registry"); + + test.done(); + }); +}; + + +// Content contexts that return true should cause their items to be present +// in the menu. +exports.testContentContextMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + contentScript: 'self.on("context", function () true);' + }); + + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); +}; + + +// Content contexts that return false should cause their items to be absent +// from the menu. +exports.testContentContextNoMatch = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + contentScript: 'self.on("context", function () false);' + }); + + test.showMenu(null, function (popup) { + test.checkMenu([], [item], []); + test.done(); + }); +}; + + +// Content contexts that return a string should cause their items to be present +// in the menu and the items' labels to be updated. +exports.testContentContextMatchString = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "first label", + contentScript: 'self.on("context", function () "second label");' + }); + + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + test.assertEqual(item.label, "second label", + "item's label should be updated"); + test.done(); + }); +}; + + +// Ensure that contentScripFile is working correctly +exports.testContentScriptFile = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + // Reject remote files + test.assertRaises(function() { + new loader.cm.Item({ + label: "item", + contentScriptFile: "http://mozilla.com/context-menu.js" + }); + }, + "The 'contentScriptFile' option must be a local file URL " + + "or an array of local file URLs.", + "Item throws when contentScriptFile is a remote URL"); + + // But accept files from data folder + let item = new loader.cm.Item({ + label: "item", + contentScriptFile: require("self").data.url("test-context-menu.js") + }); + + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); +}; + + +// The args passed to context listeners should be correct. +exports.testContentContextArgs = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + let callbacks = 0; + + let item = new loader.cm.Item({ + label: "item", + contentScript: 'self.on("context", function (node) {' + + ' let Ci = Components.interfaces;' + + ' self.postMessage(node instanceof Ci.nsIDOMHTMLElement);' + + ' return false;' + + '});', + onMessage: function (isElt) { + test.assert(isElt, "node should be an HTML element"); + if (++callbacks == 2) test.done(); + } + }); + + test.showMenu(null, function () { + if (++callbacks == 2) test.done(); + }); +}; + +// Multiple contexts imply intersection, not union, and content context +// listeners should not be called if all declarative contexts are not current. +exports.testMultipleContexts = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + context: [loader.cm.SelectorContext("a[href]"), loader.cm.PageContext()], + contentScript: 'self.on("context", function () self.postMessage());', + onMessage: function () { + test.fail("Context listener should not be called"); + } + }); + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("span-link"), function (popup) { + test.checkMenu([], [item], []); + test.done(); + }); + }); +}; + +// Once a context is removed, it should no longer cause its item to appear. +exports.testRemoveContext = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let ctxt = loader.cm.SelectorContext("img"); + let item = new loader.cm.Item({ + label: "item", + context: ctxt + }); + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("image"), function (popup) { + + // The item should be present at first. + test.checkMenu([item], [], []); + popup.hidePopup(); + + // Remove the img context and check again. + item.context.remove(ctxt); + test.showMenu(doc.getElementById("image"), function (popup) { + test.checkMenu([], [item], []); + test.done(); + }); + }); + }); +}; + + +// Lots of items should overflow into the overflow submenu. +exports.testOverflow = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let items = []; + for (let i = 0; i < OVERFLOW_THRESH_DEFAULT + 1; i++) { + let item = new loader.cm.Item({ label: "item " + i }); + items.push(item); + } + + test.showMenu(null, function (popup) { + test.checkMenu(items, [], []); + test.done(); + }); +}; + + +// Module unload should cause all items to be removed. +exports.testUnload = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ label: "item" }); + + test.showMenu(null, function (popup) { + + // The menu should contain the item. + test.checkMenu([item], [], []); + popup.hidePopup(); + + // Unload the module. + loader.unload(); + test.showMenu(null, function (popup) { + + // The item should be removed from the menu. + test.checkMenu([], [], [item]); + test.done(); + }); + }); +}; + + +// Using multiple module instances to add items without causing overflow should +// work OK. Assumes OVERFLOW_THRESH_DEFAULT <= 2. +exports.testMultipleModulesAdd = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + // Use each module to add an item, then unload each module in turn. + let item0 = new loader0.cm.Item({ label: "item 0" }); + let item1 = new loader1.cm.Item({ label: "item 1" }); + + test.showMenu(null, function (popup) { + + // The menu should contain both items. + test.checkMenu([item0, item1], [], []); + popup.hidePopup(); + + // Unload the first module. + loader0.unload(); + test.showMenu(null, function (popup) { + + // The first item should be removed from the menu. + test.checkMenu([item1], [], [item0]); + popup.hidePopup(); + + // Unload the second module. + loader1.unload(); + test.showMenu(null, function (popup) { + + // Both items should be removed from the menu. + test.checkMenu([], [], [item0, item1]); + test.done(); + }); + }); + }); +}; + + +// Using multiple module instances to add items causing overflow should work OK. +exports.testMultipleModulesAddOverflow = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + // Use module 0 to add OVERFLOW_THRESH_DEFAULT items. + let items0 = []; + for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i++) { + let item = new loader0.cm.Item({ label: "item 0 " + i }); + items0.push(item); + } + + // Use module 1 to add one item. + let item1 = new loader1.cm.Item({ label: "item 1" }); + + let allItems = items0.concat(item1); + + test.showMenu(null, function (popup) { + + // The menu should contain all items in overflow. + test.checkMenu(allItems, [], []); + popup.hidePopup(); + + // Unload the first module. + loader0.unload(); + test.showMenu(null, function (popup) { + + // The first items should be removed from the menu, which should not + // overflow. + test.checkMenu([item1], [], items0); + popup.hidePopup(); + + // Unload the second module. + loader1.unload(); + test.showMenu(null, function (popup) { + + // All items should be removed from the menu. + test.checkMenu([], [], allItems); + test.done(); + }); + }); + }); +}; + + +// Using multiple module instances to modify the menu without causing overflow +// should work OK. This test creates two loaders and: +// loader0 create item -> loader1 create item -> loader0.unload -> +// loader1.unload +exports.testMultipleModulesDiffContexts1 = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + let item0 = new loader0.cm.Item({ + label: "item 0", + context: loader0.cm.SelectorContext("img") + }); + + let item1 = new loader1.cm.Item({ label: "item 1" }); + + test.showMenu(null, function (popup) { + + // The menu should contain item1. + test.checkMenu([item1], [item0], []); + popup.hidePopup(); + + // Unload module 0. + loader0.unload(); + test.showMenu(null, function (popup) { + + // item0 should be removed from the menu. + test.checkMenu([item1], [], [item0]); + popup.hidePopup(); + + // Unload module 1. + loader1.unload(); + test.showMenu(null, function (popup) { + + // Both items should be removed from the menu. + test.checkMenu([], [], [item0, item1]); + test.done(); + }); + }); + }); +}; + + +// Using multiple module instances to modify the menu without causing overflow +// should work OK. This test creates two loaders and: +// loader1 create item -> loader0 create item -> loader0.unload -> +// loader1.unload +exports.testMultipleModulesDiffContexts2 = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + let item1 = new loader1.cm.Item({ label: "item 1" }); + + let item0 = new loader0.cm.Item({ + label: "item 0", + context: loader0.cm.SelectorContext("img") + }); + + test.showMenu(null, function (popup) { + + // The menu should contain item1. + test.checkMenu([item1], [item0], []); + popup.hidePopup(); + + // Unload module 0. + loader0.unload(); + test.showMenu(null, function (popup) { + + // item0 should be removed from the menu. + test.checkMenu([item1], [], [item0]); + popup.hidePopup(); + + // Unload module 1. + loader1.unload(); + test.showMenu(null, function (popup) { + + // Both items should be removed from the menu. + test.checkMenu([], [], [item0, item1]); + test.done(); + }); + }); + }); +}; + + +// Using multiple module instances to modify the menu without causing overflow +// should work OK. This test creates two loaders and: +// loader0 create item -> loader1 create item -> loader1.unload -> +// loader0.unload +exports.testMultipleModulesDiffContexts3 = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + let item0 = new loader0.cm.Item({ + label: "item 0", + context: loader0.cm.SelectorContext("img") + }); + + let item1 = new loader1.cm.Item({ label: "item 1" }); + + test.showMenu(null, function (popup) { + + // The menu should contain item1. + test.checkMenu([item1], [item0], []); + popup.hidePopup(); + + // Unload module 1. + loader1.unload(); + test.showMenu(null, function (popup) { + + // item1 should be removed from the menu. + test.checkMenu([], [item0], [item1]); + popup.hidePopup(); + + // Unload module 0. + loader0.unload(); + test.showMenu(null, function (popup) { + + // Both items should be removed from the menu. + test.checkMenu([], [], [item0, item1]); + test.done(); + }); + }); + }); +}; + + +// Using multiple module instances to modify the menu without causing overflow +// should work OK. This test creates two loaders and: +// loader1 create item -> loader0 create item -> loader1.unload -> +// loader0.unload +exports.testMultipleModulesDiffContexts4 = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + let item1 = new loader1.cm.Item({ label: "item 1" }); + + let item0 = new loader0.cm.Item({ + label: "item 0", + context: loader0.cm.SelectorContext("img") + }); + + test.showMenu(null, function (popup) { + + // The menu should contain item1. + test.checkMenu([item1], [item0], []); + popup.hidePopup(); + + // Unload module 1. + loader1.unload(); + test.showMenu(null, function (popup) { + + // item1 should be removed from the menu. + test.checkMenu([], [item0], [item1]); + popup.hidePopup(); + + // Unload module 0. + loader0.unload(); + test.showMenu(null, function (popup) { + + // Both items should be removed from the menu. + test.checkMenu([], [], [item0, item1]); + test.done(); + }); + }); + }); +}; + + +// Test interactions between a loaded module, unloading another module, and the +// menu separator and overflow submenu. +exports.testMultipleModulesAddRemove = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + let item = new loader0.cm.Item({ label: "item" }); + + test.showMenu(null, function (popup) { + + // The menu should contain the item. + test.checkMenu([item], [], []); + popup.hidePopup(); + + // Remove the item. + item.destroy(); + test.showMenu(null, function (popup) { + + // The item should be removed from the menu. + test.checkMenu([], [], [item]); + popup.hidePopup(); + + // Unload module 1. + loader1.unload(); + test.showMenu(null, function (popup) { + + // There shouldn't be any errors involving the menu separator or + // overflow submenu. + test.checkMenu([], [], [item]); + test.done(); + }); + }); + }); +}; + + +// An item's click listener should work. +exports.testItemClick = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + data: "item data", + contentScript: 'self.on("click", function (node, data) {' + + ' let Ci = Components.interfaces;' + + ' self.postMessage({' + + ' isElt: node instanceof Ci.nsIDOMHTMLElement,' + + ' data: data' + + ' });' + + '});', + onMessage: function (data) { + test.assertEqual(this, item, "`this` inside onMessage should be item"); + test.assert(data.isElt, "node should be an HTML element"); + test.assertEqual(data.data, item.data, "data should be item data"); + test.done(); + } + }); + + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + let elt = test.getItemElt(popup, item); + elt.click(); + }); +}; + + +// A menu's click listener should work and receive bubbling clicks from +// sub-items appropriately. This also tests menus and ensures that when a CSS +// selector context matches the clicked node's ancestor, the matching ancestor +// is passed to listeners as the clicked node. +exports.testMenuClick = function (test) { + // Create a top-level menu, submenu, and item, like this: + // topMenu -> submenu -> item + // Click the item and make sure the click bubbles. + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "submenu item", + data: "submenu item data" + }); + + let submenu = new loader.cm.Menu({ + label: "submenu", + items: [item] + }); + + let topMenu = new loader.cm.Menu({ + label: "top menu", + contentScript: 'self.on("click", function (node, data) {' + + ' let Ci = Components.interfaces;' + + ' self.postMessage({' + + ' isAnchor: node instanceof Ci.nsIDOMHTMLAnchorElement,' + + ' data: data' + + ' });' + + '});', + onMessage: function (data) { + test.assertEqual(this, topMenu, "`this` inside top menu should be menu"); + test.assert(data.isAnchor, "Clicked node should be anchor"); + test.assertEqual(data.data, item.data, + "Clicked item data should be correct"); + test.done(); + }, + items: [submenu], + context: loader.cm.SelectorContext("a") + }); + + test.withTestDoc(function (window, doc) { + test.showMenu(doc.getElementById("span-link"), function (popup) { + test.checkMenu([topMenu], [], []); + let topMenuElt = test.getItemElt(popup, topMenu); + let topMenuPopup = topMenuElt.firstChild; + let submenuElt = test.getItemElt(topMenuPopup, submenu); + let submenuPopup = submenuElt.firstChild; + let itemElt = test.getItemElt(submenuPopup, item); + itemElt.click(); + }); + }); +}; + +// Click listeners should work when multiple modules are loaded. +exports.testItemClickMultipleModules = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + let item0 = loader0.cm.Item({ + label: "loader 0 item", + contentScript: 'self.on("click", self.postMessage);', + onMessage: function () { + test.fail("loader 0 item should not emit click event"); + } + }); + let item1 = loader1.cm.Item({ + label: "loader 1 item", + contentScript: 'self.on("click", self.postMessage);', + onMessage: function () { + test.pass("loader 1 item clicked as expected"); + test.done(); + } + }); + + test.showMenu(null, function (popup) { + test.checkMenu([item0, item1], [], []); + let item1Elt = test.getItemElt(popup, item1); + item1Elt.click(); + }); +}; + + +// Adding a separator to a submenu should work OK. +exports.testSeparator = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let menu = new loader.cm.Menu({ + label: "submenu", + items: [new loader.cm.Separator()] + }); + + test.showMenu(null, function (popup) { + test.checkMenu([menu], [], []); + test.done(); + }); +}; + + +// Existing context menu modifications should apply to new windows. +exports.testNewWindow = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ label: "item" }); + + test.withNewWindow(function () { + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); + }); +}; + + +// When a new window is opened, items added by an unloaded module should not +// be present in the menu. +exports.testNewWindowMultipleModules = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + let item = new loader.cm.Item({ label: "item" }); + + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + popup.hidePopup(); + loader.unload(); + test.withNewWindow(function () { + test.showMenu(null, function (popup) { + test.checkMenu([], [], []); + test.done(); + }); + }); + }); +}; + + +// Items in the context menu should be sorted according to locale. +exports.testSorting = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + // Make an unsorted items list. It'll look like this: + // item 1, item 0, item 3, item 2, item 5, item 4, ... + let items = []; + for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i += 2) { + items.push(new loader.cm.Item({ label: "item " + (i + 1) })); + items.push(new loader.cm.Item({ label: "item " + i })); + } + + test.showMenu(null, function (popup) { + test.checkMenu(items, [], []); + test.done(); + }); +}; + + +// Items in the overflow menu should be sorted according to locale. +exports.testSortingOverflow = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + // Make an unsorted items list. It'll look like this: + // item 1, item 0, item 3, item 2, item 5, item 4, ... + let items = []; + for (let i = 0; i < OVERFLOW_THRESH_DEFAULT * 2; i += 2) { + items.push(new loader.cm.Item({ label: "item " + (i + 1) })); + items.push(new loader.cm.Item({ label: "item " + i })); + } + + test.showMenu(null, function (popup) { + test.checkMenu(items, [], []); + test.done(); + }); +}; + + +// Multiple modules shouldn't interfere with sorting. +exports.testSortingMultipleModules = function (test) { + test = new TestHelper(test); + let loader0 = test.newLoader(); + let loader1 = test.newLoader(); + + let items0 = []; + let items1 = []; + for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i++) { + if (i % 2) { + let item = new loader0.cm.Item({ label: "item " + i }); + items0.push(item); + } + else { + let item = new loader1.cm.Item({ label: "item " + i }); + items1.push(item); + } + } + let allItems = items0.concat(items1); + + test.showMenu(null, function (popup) { + + // All items should be present and sorted. + test.checkMenu(allItems, [], []); + popup.hidePopup(); + loader0.unload(); + loader1.unload(); + test.showMenu(null, function (popup) { + + // All items should be removed. + test.checkMenu([], [], allItems); + test.done(); + }); + }); +}; + + +// The binary search of insertionPoint should work OK. +exports.testInsertionPoint = function (test) { + function mockElts(labels) { + return labels.map(function (label) { + return { label: label, getAttribute: function (l) label }; + }); + } + + test = new TestHelper(test); + let loader = test.newLoader(); + let insertionPoint = loader.globalScope.insertionPoint; + + let ip = insertionPoint("a", []); + test.assertStrictEqual(ip, null, "Insertion point should be null"); + + ip = insertionPoint("a", mockElts(["b"])); + test.assertEqual(ip.label, "b", "Insertion point should be 'b'"); + + ip = insertionPoint("c", mockElts(["b"])); + test.assertStrictEqual(ip, null, "Insertion point should be null"); + + ip = insertionPoint("b", mockElts(["a", "c"])); + test.assertEqual(ip.label, "c", "Insertion point should be 'c'"); + + ip = insertionPoint("c", mockElts(["a", "b", "d"])); + test.assertEqual(ip.label, "d", "Insertion point should be 'd'"); + + ip = insertionPoint("a", mockElts(["b", "c", "d"])); + test.assertEqual(ip.label, "b", "Insertion point should be 'b'"); + + ip = insertionPoint("d", mockElts(["a", "b", "c"])); + test.assertStrictEqual(ip, null, "Insertion point should be null"); + + test.done(); +}; + + +// Content click handlers and context handlers should be able to communicate, +// i.e., they're eval'ed in the same worker and sandbox. +exports.testContentCommunication = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ + label: "item", + contentScript: 'var potato;' + + 'self.on("context", function () {' + + ' potato = "potato";' + + ' return true;' + + '});' + + 'self.on("click", function () {' + + ' self.postMessage(potato);' + + '});', + }); + + item.on("message", function (data) { + test.assertEqual(data, "potato", "That's a lot of potatoes!"); + test.done(); + }); + + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + let elt = test.getItemElt(popup, item); + elt.click(); + }); +}; + + +// When the context menu is invoked on a tab that was already open when the +// module was loaded, it should contain the expected items and content workers +// should function as expected. +exports.testLoadWithOpenTab = function (test) { + test = new TestHelper(test); + test.withTestDoc(function (window, doc) { + let loader = test.newLoader(); + let item = new loader.cm.Item({ + label: "item", + contentScript: + 'self.on("click", function () self.postMessage("click"));', + onMessage: function (msg) { + if (msg === "click") + test.done(); + } + }); + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + test.getItemElt(popup, item).click(); + }); + }); +}; + + +// Setting an item's label before the menu is ever shown should correctly change +// its label and, if necessary, its order within the menu. +exports.testSetLabelBeforeShow = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let items = [ + new loader.cm.Item({ label: "a" }), + new loader.cm.Item({ label: "b" }) + ] + items[0].label = "z"; + test.assertEqual(items[0].label, "z"); + + test.showMenu(null, function (popup) { + test.checkMenu([items[1], items[0]], [], []); + test.done(); + }); +}; + + +// Setting an item's label after the menu is shown should correctly change its +// label and, if necessary, its order within the menu. +exports.testSetLabelAfterShow = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let items = [ + new loader.cm.Item({ label: "a" }), + new loader.cm.Item({ label: "b" }) + ]; + + test.showMenu(null, function (popup) { + test.checkMenu(items, [], []); + popup.hidePopup(); + + items[0].label = "z"; + test.assertEqual(items[0].label, "z"); + test.showMenu(null, function (popup) { + test.checkMenu([items[1], items[0]], [], []); + test.done(); + }); + }); +}; + + +// Setting an item's label before the menu is ever shown should correctly change +// its label and, if necessary, its order within the menu if the item is in the +// overflow submenu. +exports.testSetLabelBeforeShowOverflow = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let prefs = loader.loader.require("preferences-service"); + prefs.set(OVERFLOW_THRESH_PREF, 0); + + let items = [ + new loader.cm.Item({ label: "a" }), + new loader.cm.Item({ label: "b" }) + ] + items[0].label = "z"; + test.assertEqual(items[0].label, "z"); + + test.showMenu(null, function (popup) { + test.checkMenu([items[1], items[0]], [], []); + prefs.set(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT); + test.done(); + }); +}; + + +// Setting an item's label after the menu is shown should correctly change its +// label and, if necessary, its order within the menu if the item is in the +// overflow submenu. +exports.testSetLabelAfterShowOverflow = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let prefs = loader.loader.require("preferences-service"); + prefs.set(OVERFLOW_THRESH_PREF, 0); + + let items = [ + new loader.cm.Item({ label: "a" }), + new loader.cm.Item({ label: "b" }) + ]; + + test.showMenu(null, function (popup) { + test.checkMenu(items, [], []); + popup.hidePopup(); + + items[0].label = "z"; + test.assertEqual(items[0].label, "z"); + test.showMenu(null, function (popup) { + test.checkMenu([items[1], items[0]], [], []); + prefs.set(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT); + test.done(); + }); + }); +}; + + +// Setting the label of an item in a Menu should work. +exports.testSetLabelMenuItem = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let menu = loader.cm.Menu({ + label: "menu", + items: [loader.cm.Item({ label: "a" })] + }); + menu.items[0].label = "z"; + + test.assertEqual(menu.items[0].label, "z"); + + test.showMenu(null, function (popup) { + test.checkMenu([menu], [], []); + test.done(); + }); +}; + + +// Menu.addItem() should work. +exports.testMenuAddItem = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let menu = loader.cm.Menu({ + label: "menu", + items: [ + loader.cm.Item({ label: "item 0" }) + ] + }); + menu.addItem(loader.cm.Item({ label: "item 1" })); + menu.addItem(loader.cm.Item({ label: "item 2" })); + + test.assertEqual(menu.items.length, 3, + "menu should have correct number of items"); + for (let i = 0; i < 3; i++) { + test.assertEqual(menu.items[i].label, "item " + i, + "item label should be correct"); + test.assertEqual(menu.items[i].parentMenu, menu, + "item's parent menu should be correct"); + } + + test.showMenu(null, function (popup) { + test.checkMenu([menu], [], []); + test.done(); + }); +}; + + +// Adding the same item twice to a menu should work as expected. +exports.testMenuAddItemTwice = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let menu = loader.cm.Menu({ + label: "menu", + items: [] + }); + let subitem = loader.cm.Item({ label: "item 1" }) + menu.addItem(subitem); + menu.addItem(loader.cm.Item({ label: "item 0" })); + menu.addItem(subitem); + + test.assertEqual(menu.items.length, 2, + "menu should have correct number of items"); + for (let i = 0; i < 2; i++) { + test.assertEqual(menu.items[i].label, "item " + i, + "item label should be correct"); + } + + test.showMenu(null, function (popup) { + test.checkMenu([menu], [], []); + test.done(); + }); +}; + + +// Menu.removeItem() should work. +exports.testMenuRemoveItem = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let subitem = loader.cm.Item({ label: "item 1" }); + let menu = loader.cm.Menu({ + label: "menu", + items: [ + loader.cm.Item({ label: "item 0" }), + subitem, + loader.cm.Item({ label: "item 2" }) + ] + }); + + // Removing twice should be harmless. + menu.removeItem(subitem); + menu.removeItem(subitem); + + test.assertEqual(subitem.parentMenu, null, + "item's parent menu should be correct"); + + test.assertEqual(menu.items.length, 2, + "menu should have correct number of items"); + test.assertEqual(menu.items[0].label, "item 0", + "item label should be correct"); + test.assertEqual(menu.items[1].label, "item 2", + "item label should be correct"); + + test.showMenu(null, function (popup) { + test.checkMenu([menu], [], []); + test.done(); + }); +}; + + +// Adding an item currently contained in one menu to another menu should work. +exports.testMenuItemSwap = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let subitem = loader.cm.Item({ label: "item" }); + let menu0 = loader.cm.Menu({ + label: "menu 0", + items: [subitem] + }); + let menu1 = loader.cm.Menu({ + label: "menu 1", + items: [] + }); + menu1.addItem(subitem); + + test.assertEqual(menu0.items.length, 0, + "menu should have correct number of items"); + + test.assertEqual(menu1.items.length, 1, + "menu should have correct number of items"); + test.assertEqual(menu1.items[0].label, "item", + "item label should be correct"); + + test.assertEqual(subitem.parentMenu, menu1, + "item's parent menu should be correct"); + + test.showMenu(null, function (popup) { + test.checkMenu([menu0, menu1], [], []); + test.done(); + }); +}; + + +// Destroying an item should remove it from its parent menu. +exports.testMenuItemDestroy = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let subitem = loader.cm.Item({ label: "item" }); + let menu = loader.cm.Menu({ + label: "menu", + items: [subitem] + }); + subitem.destroy(); + + test.assertEqual(menu.items.length, 0, + "menu should have correct number of items"); + test.assertEqual(subitem.parentMenu, null, + "item's parent menu should be correct"); + + test.showMenu(null, function (popup) { + test.checkMenu([menu], [], []); + test.done(); + }); +}; + + +// Setting Menu.items should work. +exports.testMenuItemsSetter = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let menu = loader.cm.Menu({ + label: "menu", + items: [ + loader.cm.Item({ label: "old item 0" }), + loader.cm.Item({ label: "old item 1" }) + ] + }); + menu.items = [ + loader.cm.Item({ label: "new item 0" }), + loader.cm.Item({ label: "new item 1" }), + loader.cm.Item({ label: "new item 2" }) + ]; + + test.assertEqual(menu.items.length, 3, + "menu should have correct number of items"); + for (let i = 0; i < 3; i++) { + test.assertEqual(menu.items[i].label, "new item " + i, + "item label should be correct"); + test.assertEqual(menu.items[i].parentMenu, menu, + "item's parent menu should be correct"); + } + + test.showMenu(null, function (popup) { + test.checkMenu([menu], [], []); + test.done(); + }); +}; + + +// Setting Item.data should work. +exports.testItemDataSetter = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let item = loader.cm.Item({ label: "old item 0", data: "old" }); + item.data = "new"; + + test.assertEqual(item.data, "new", "item should have correct data"); + + test.showMenu(null, function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); +}; + + +// Open the test doc, load the module, make sure items appear when context- +// clicking the iframe. +exports.testAlreadyOpenIframe = function (test) { + test = new TestHelper(test); + test.withTestDoc(function (window, doc) { + let loader = test.newLoader(); + let item = new loader.cm.Item({ + label: "item" + }); + test.showMenu(doc.getElementById("iframe"), function (popup) { + test.checkMenu([item], [], []); + test.done(); + }); + }); +}; + + +// Test image support. +exports.testItemImage = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let imageURL = require("self").data.url("moz_favicon.ico"); + let item = new loader.cm.Item({ label: "item", image: imageURL }); + let menu = new loader.cm.Menu({ label: "menu", image: imageURL, items: [] }); + + test.showMenu(null, function (popup) { + test.checkMenu([item, menu], [], []); + + let imageURL2 = require("self").data.url("dummy.ico"); + item.image = imageURL2; + menu.image = imageURL2; + test.checkMenu([item, menu], [], []); + + item.image = null; + menu.image = null; + test.checkMenu([item, menu], [], []); + + test.done(); + }); +}; + + +// Menu.destroy should destroy the item tree rooted at that menu. +exports.testMenuDestroy = function (test) { + test = new TestHelper(test); + let loader = test.newLoader(); + + let menu = loader.cm.Menu({ + label: "menu", + items: [ + loader.cm.Item({ label: "item 0" }), + loader.cm.Menu({ + label: "item 1", + items: [ + loader.cm.Item({ label: "subitem 0" }), + loader.cm.Item({ label: "subitem 1" }), + loader.cm.Item({ label: "subitem 2" }) + ] + }), + loader.cm.Item({ label: "item 2" }) + ] + }); + menu.destroy(); + + let numRegistryEntries = 0; + loader.globalScope.browserManager.browserWins.forEach(function (bwin) { + for (let itemID in bwin.items) + numRegistryEntries++; + }); + test.assertEqual(numRegistryEntries, 0, "All items should be unregistered."); + + test.showMenu(null, function (popup) { + test.checkMenu([], [], [menu]); + test.done(); + }); +}; + + +// NO TESTS BELOW THIS LINE! /////////////////////////////////////////////////// + +// Run only a dummy test if context-menu doesn't support the host app. +if (!require("xul-app").is("Firefox")) { + for (let [prop, val] in Iterator(exports)) + if (/^test/.test(prop) && typeof(val) === "function") + delete exports[prop]; + exports.testAppNotSupported = function (test) { + test.pass("context-menu does not support this application."); + }; +} + + +// This makes it easier to run tests by handling things like opening the menu, +// opening new windows, making assertions, etc. Methods on |test| can be called +// on instances of this class. Don't forget to call done() to end the test! +// WARNING: This looks up items in popups by comparing labels, so don't give two +// items the same label. +function TestHelper(test) { + // default waitUntilDone timeout is 10s, which is too short on the win7 + // buildslave + test.waitUntilDone(30*1000); + this.test = test; + this.loaders = []; + this.browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. + getService(Ci.nsIWindowMediator). + getMostRecentWindow("navigator:browser"); +} + +TestHelper.prototype = { + get contextMenuPopup() { + return this.browserWindow.document.getElementById("contentAreaContextMenu"); + }, + + get contextMenuSeparator() { + return this.browserWindow.document.getElementById(SEPARATOR_ID); + }, + + get overflowPopup() { + return this.browserWindow.document.getElementById(OVERFLOW_POPUP_ID); + }, + + get overflowSubmenu() { + return this.browserWindow.document.getElementById(OVERFLOW_MENU_ID); + }, + + get tabBrowser() { + return this.browserWindow.gBrowser; + }, + + // Methods on the wrapped test can be called on this object. + __noSuchMethod__: function (methodName, args) { + this.test[methodName].apply(this.test, args); + }, + + // Asserts that absentItems -- an array of items that should not match the + // current context -- aren't present in the menu. + checkAbsentItems: function (presentItems, absentItems) { + for (let i = 0; i < absentItems.length; i++) { + let item = absentItems[i]; + let elt = this.getItemElt(this.contextMenuPopup, item); + + // The implementation actually hides items rather than removing or not + // adding them in the first place, but that's an implementation detail. + this.test.assert(!elt || elt.hidden, + "Item should not be present in top-level menu"); + + if (this.shouldOverflow(presentItems)) { + elt = getItemElt(this.overflowPopup, item); + this.test.assert(!elt || elt.hidden, + "Item should not be present in overflow submenu"); + } + } + }, + + // Asserts that elt, a DOM element representing item, looks OK. + checkItemElt: function (elt, item) { + let itemType = this.getItemType(item); + + switch (itemType) { + case "Item": + this.test.assertEqual(elt.localName, "menuitem", + "Item DOM element should be a xul:menuitem"); + if (typeof(item.data) === "string") { + this.test.assertEqual(elt.getAttribute("value"), item.data, + "Item should have correct data"); + } + break + case "Menu": + this.test.assertEqual(elt.localName, "menu", + "Menu DOM element should be a xul:menu"); + let subPopup = elt.firstChild; + this.test.assert(subPopup, "xul:menu should have a child"); + this.test.assertEqual(subPopup.localName, "menupopup", + "xul:menu's first child should be a menupopup"); + break; + case "Separator": + this.test.assertEqual(elt.localName, "menuseparator", + "Separator DOM element should be a xul:menuseparator"); + break; + } + + if (itemType === "Item" || itemType === "Menu") { + this.test.assertEqual(elt.getAttribute("label"), item.label, + "Item should have correct title"); + if (typeof(item.image) === "string") + this.test.assertEqual(elt.getAttribute("image"), item.image, + "Item should have correct image"); + else + this.test.assert(!elt.hasAttribute("image"), + "Item should not have image"); + } + }, + + // Asserts that the context menu looks OK given the arguments. presentItems + // are items that should match the current context. absentItems are items + // that shouldn't. removedItems are items that have been removed from the + // menu. + checkMenu: function (presentItems, absentItems, removedItems) { + this.checkSeparator(presentItems); + this.checkOverflow(presentItems); + this.checkPresentItems(presentItems); + this.checkAbsentItems(presentItems, absentItems); + this.checkRemovedItems(removedItems); + this.checkSort(presentItems); + }, + + // Asserts that the overflow submenu is present or absent as appropriate for + // presentItems. + checkOverflow: function (presentItems) { + let submenu = this.overflowSubmenu; + if (this.shouldOverflow(presentItems)) { + this.test.assert(submenu && !submenu.hidden, + "Overflow submenu should be present"); + this.test.assert(submenu.localName, "menu", + "Overflow submenu should be a "); + let overflowPopup = this.overflowPopup; + this.test.assert(overflowPopup, + "Overflow submenu popup should be present"); + this.test.assert(overflowPopup.localName, "menupopup", + "Overflow submenu popup should be a "); + } + else { + this.test.assert(!submenu || submenu.hidden, + "Overflow submenu should be absent"); + } + }, + + // Asserts that the items that are present in the menu because they match the + // current context look OK. + checkPresentItems: function (presentItems) { + function recurse(popup, items, isTopLevel) { + items.forEach(function (item) { + let elt = this.getItemElt(popup, item); + + if (isTopLevel) { + if (this.shouldOverflow(items)) { + this.test.assert(!elt || elt.hidden, + "Item should not be present in top-level menu"); + + let overflowPopup = this.overflowPopup; + this.test.assert(overflowPopup, + "Overflow submenu should be present"); + + elt = this.getItemElt(overflowPopup, item); + this.test.assert(elt && !elt.hidden, + "Item should be present in overflow submenu"); + } + else { + this.test.assert(elt && !elt.hidden, + "Item should be present in top-level menu"); + } + } + else { + this.test.assert(elt && !elt.hidden, + "Item should be present in menu"); + } + + this.checkItemElt(elt, item); + if (this.getItemType(item) === "Menu") + recurse.call(this, elt.firstChild, item.items, false); + }, this); + } + + recurse.call(this, this.contextMenuPopup, presentItems, true); + }, + + // Asserts that items that have been removed from the menu are really removed. + checkRemovedItems: function (removedItems) { + for (let i = 0; i < removedItems.length; i++) { + let item = removedItems[i]; + + let elt = this.getItemElt(this.contextMenuPopup, item); + this.test.assert(!elt, "Item should be removed from top-level menu"); + + let overflowPopup = this.overflowPopup; + if (overflowPopup) { + elt = this.getItemElt(overflowPopup, item); + this.test.assert(!elt, "Item should be removed from overflow submenu"); + } + } + }, + + // Asserts that the menu separator separating standard items from our items + // looks OK. + checkSeparator: function (presentItems) { + let sep = this.contextMenuSeparator; + if (presentItems.length) { + this.test.assert(sep && !sep.hidden, "Menu separator should be present"); + this.test.assertEqual(sep.localName, "menuseparator", + "Menu separator should be a "); + } + else { + this.test.assert(!sep || sep.hidden, "Menu separator should be absent"); + } + }, + + // Asserts that our items are sorted. + checkSort: function (presentItems) { + // Get the first item in sorted order, get its elt, walk the nextSibling + // chain, making sure each is greater than the previous. + if (presentItems.length) { + let sorted = presentItems.slice(0). + sort(function (a, b) a.label.localeCompare(b.label)); + let elt = this.shouldOverflow(presentItems) ? + this.getItemElt(this.overflowPopup, sorted[0]) : + this.getItemElt(this.contextMenuPopup, sorted[0]); + let numElts = 1; + while (elt.nextSibling && + elt.nextSibling.className.split(/\s+/).indexOf(ITEM_CLASS) >= 0) { + let eltLabel = elt.getAttribute("label"); + let nextLabel = elt.nextSibling.getAttribute("label"); + this.test.assert(eltLabel.localeCompare(nextLabel) < 0, + "Item label should be < next item's label"); + elt = elt.nextSibling; + numElts++; + } + this.test.assertEqual(numElts, presentItems.length, + "The first item in sorted order should have the " + + "first element in sorted order"); + } + }, + + // Attaches an event listener to node. The listener is automatically removed + // when it's fired (so it's assumed it will fire), and callback is called + // after a short delay. Since the module we're testing relies on the same + // event listeners to do its work, this is to give them a little breathing + // room before callback runs. Inside callback |this| is this object. + delayedEventListener: function (node, event, callback, useCapture) { + const self = this; + node.addEventListener(event, function handler(evt) { + node.removeEventListener(event, handler, useCapture); + require("timer").setTimeout(function () { + try { + callback.call(self, evt); + } + catch (err) { + self.test.exception(err); + self.test.done(); + } + }, 20); + }, useCapture); + }, + + // Call to finish the test. + done: function () { + function commonDone() { + if (this.tab) { + this.tabBrowser.removeTab(this.tab); + this.tabBrowser.selectedTab = this.oldSelectedTab; + } + while (this.loaders.length) { + let browserManager = this.loaders[0].globalScope.browserManager; + let topLevelItems = browserManager.topLevelItems.slice(); + let privatePropsKey = this.loaders[0].globalScope.PRIVATE_PROPS_KEY; + let workerRegs = topLevelItems.map(function (item) { + return item.valueOf(privatePropsKey)._workerReg; + }); + + this.loaders[0].unload(); + + // Make sure the browser manager is cleaned up. + this.test.assertEqual(browserManager.browserWins.length, 0, + "browserManager should have no windows left"); + this.test.assertEqual(browserManager.topLevelItems.length, 0, + "browserManager should have no items left"); + this.test.assert(!("contentWins" in browserManager), + "browserManager should have no content windows left"); + + // Make sure the items' worker registries are cleaned up. + topLevelItems.forEach(function (item) { + this.test.assert(!("_workerReg" in item.valueOf(privatePropsKey)), + "item's worker registry should be removed"); + }, this); + workerRegs.forEach(function (workerReg) { + this.test.assertEqual(Object.keys(workerReg.winWorkers).length, 0, + "worker registry should be empty"); + this.test.assertEqual( + Object.keys(workerReg.winsWithoutWorkers).length, 0, + "worker registry list of windows without workers should be empty"); + }, this); + } + this.test.done(); + } + + function closeBrowserWindow() { + if (this.oldBrowserWindow) { + this.delayedEventListener(this.browserWindow, "unload", commonDone, + false); + this.browserWindow.close(); + this.browserWindow = this.oldBrowserWindow; + delete this.oldBrowserWindow; + } + else { + commonDone.call(this); + } + }; + + if (this.contextMenuPopup.state == "closed") { + closeBrowserWindow.call(this); + } + else { + this.delayedEventListener(this.contextMenuPopup, "popuphidden", + function () closeBrowserWindow.call(this), + false); + this.contextMenuPopup.hidePopup(); + } + }, + + // Returns the DOM element in popup corresponding to item. + // WARNING: The element is found by comparing labels, so don't give two items + // the same label. + getItemElt: function (popup, item) { + let nodes = popup.childNodes; + for (let i = nodes.length - 1; i >= 0; i--) { + if (this.getItemType(item) === "Separator") { + if (nodes[i].localName === "menuseparator") + return nodes[i]; + } + else if (nodes[i].getAttribute("label") === item.label) + return nodes[i]; + } + return null; + }, + + // Returns "Item", "Menu", or "Separator". + getItemType: function (item) { + // Could use instanceof here, but that would require accessing the loader + // that created the item, and I don't want to A) somehow search through the + // this.loaders list to find it, and B) assume there are any live loaders at + // all. + return /^\[object (Item|Menu|Separator)/.exec(item.toString())[1]; + }, + + // Returns a wrapper around a new loader: { loader, cm, unload, globalScope }. + // loader is a Cuddlefish sandboxed loader, cm is the context menu module, + // globalScope is the context menu module's global scope, and unload is a + // function that unloads the loader and associated resources. + newLoader: function () { + const self = this; + let loader = Loader(module); + let wrapper = { + loader: loader, + cm: loader.require("context-menu"), + globalScope: loader.sandbox("context-menu"), + unload: function () { + loader.unload(); + let idx = self.loaders.indexOf(wrapper); + if (idx < 0) + throw new Error("Test error: tried to unload nonexistent loader"); + self.loaders.splice(idx, 1); + } + }; + this.loaders.push(wrapper); + return wrapper; + }, + + // Returns true if the number of presentItems crosses the overflow threshold. + shouldOverflow: function (presentItems) { + return presentItems.length > + (this.loaders.length ? + this.loaders[0].loader.require("preferences-service"). + get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT) : + OVERFLOW_THRESH_DEFAULT); + }, + + // Opens the context menu on the current page. If targetNode is null, the + // menu is opened in the top-left corner. onShowncallback is passed the + // popup. + showMenu: function(targetNode, onshownCallback) { + function sendEvent() { + this.delayedEventListener(this.browserWindow, "popupshowing", + function (e) { + let popup = e.target; + onshownCallback.call(this, popup); + }, false); + + let rect = targetNode ? + targetNode.getBoundingClientRect() : + { left: 0, top: 0, width: 0, height: 0 }; + let contentWin = this.browserWindow.content; + contentWin. + QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIDOMWindowUtils). + sendMouseEvent("contextmenu", + rect.left + (rect.width / 2), + rect.top + (rect.height / 2), + 2, 1, 0); + } + + // If a new tab or window has not yet been opened, open a new tab now. For + // some reason using the tab already opened when the test starts causes + // leaks. See bug 566351 for details. + if (!targetNode && !this.oldSelectedTab && !this.oldBrowserWindow) { + this.oldSelectedTab = this.tabBrowser.selectedTab; + this.tab = this.tabBrowser.addTab("about:blank"); + let browser = this.tabBrowser.getBrowserForTab(this.tab); + + this.delayedEventListener(browser, "load", function () { + this.tabBrowser.selectedTab = this.tab; + sendEvent.call(this); + }, true); + } + else + sendEvent.call(this); + }, + + // Opens a new browser window. The window will be closed automatically when + // done() is called. + withNewWindow: function (onloadCallback) { + let win = this.browserWindow.OpenBrowserWindow(); + this.delayedEventListener(win, "load", onloadCallback, true); + this.oldBrowserWindow = this.browserWindow; + this.browserWindow = win; + }, + + // Opens a new tab with our test page in the current window. The tab will + // be closed automatically when done() is called. + withTestDoc: function (onloadCallback) { + this.oldSelectedTab = this.tabBrowser.selectedTab; + this.tab = this.tabBrowser.addTab(TEST_DOC_URL); + let browser = this.tabBrowser.getBrowserForTab(this.tab); + + this.delayedEventListener(browser, "load", function () { + this.tabBrowser.selectedTab = this.tab; + onloadCallback.call(this, browser.contentWindow, browser.contentDocument); + }, true); + } +}; diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-hotkeys.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-hotkeys.js new file mode 100644 index 0000000..0e0ecd6 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-hotkeys.js @@ -0,0 +1,160 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If 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 { Hotkey } = require("hotkeys"); +const { keyDown } = require("dom/events/keys"); +const { Loader } = require('./helpers'); + +exports["test hotkey: function key"] = function(assert, done) { + var element = require("window-utils").activeBrowserWindow.document.documentElement; + var showHotKey = Hotkey({ + combo: "f1", + onPress: function() { + assert.pass("first callback is called"); + keyDown(element, "f2"); + showHotKey.destroy(); + } + }); + + var hideHotKey = Hotkey({ + combo: "f2", + onPress: function() { + assert.pass("second callback is called"); + hideHotKey.destroy(); + done(); + } + }); + + keyDown(element, "f1"); +}; + +exports["test hotkey: accel alt shift"] = function(assert, done) { + var element = require("window-utils").activeBrowserWindow.document.documentElement; + var showHotKey = Hotkey({ + combo: "accel-shift-6", + onPress: function() { + assert.pass("first callback is called"); + keyDown(element, "accel-alt-shift-6"); + showHotKey.destroy(); + } + }); + + var hideHotKey = Hotkey({ + combo: "accel-alt-shift-6", + onPress: function() { + assert.pass("second callback is called"); + hideHotKey.destroy(); + done(); + } + }); + + keyDown(element, "accel-shift-6"); +}; + +exports["test hotkey meta & control"] = function(assert, done) { + var element = require("window-utils").activeBrowserWindow.document.documentElement; + var showHotKey = Hotkey({ + combo: "meta-3", + onPress: function() { + assert.pass("first callback is called"); + keyDown(element, "alt-control-shift-b"); + showHotKey.destroy(); + } + }); + + var hideHotKey = Hotkey({ + combo: "Ctrl-Alt-Shift-B", + onPress: function() { + assert.pass("second callback is called"); + hideHotKey.destroy(); + done(); + } + }); + + keyDown(element, "meta-3"); +}; + +exports["test hotkey: control-1 / meta--"] = function(assert, done) { + var element = require("window-utils").activeBrowserWindow.document.documentElement; + var showHotKey = Hotkey({ + combo: "control-1", + onPress: function() { + assert.pass("first callback is called"); + keyDown(element, "meta--"); + showHotKey.destroy(); + } + }); + + var hideHotKey = Hotkey({ + combo: "meta--", + onPress: function() { + assert.pass("second callback is called"); + hideHotKey.destroy(); + done(); + } + }); + + keyDown(element, "control-1"); +}; + +exports["test invalid combos"] = function(assert) { + assert.throws(function() { + Hotkey({ + combo: "d", + onPress: function() {} + }); + }, "throws if no modifier is present"); + assert.throws(function() { + Hotkey({ + combo: "alt", + onPress: function() {} + }); + }, "throws if no key is present"); + assert.throws(function() { + Hotkey({ + combo: "alt p b", + onPress: function() {} + }); + }, "throws if more then one key is present"); +}; + +exports["test no exception on unmodified keypress"] = function(assert) { + var element = require("window-utils").activeBrowserWindow.document.documentElement; + var someHotkey = Hotkey({ + combo: "control-alt-1", + onPress: function() { + } + }); + keyDown(element, "a"); + assert.pass("No exception throw, unmodified keypress passed"); +}; + +exports["test hotkey: automatic destroy"] = function(assert, done) { + // Hacky way to be able to create unloadable modules via makeSandboxedLoader. + let loader = Loader(module); + + var called = false; + var element = loader.require("window-utils").activeBrowserWindow.document.documentElement; + var hotkey = loader.require("hotkeys").Hotkey({ + combo: "accel-shift-x", + onPress: function() { + called = true; + } + }); + + // Unload the module so that previous hotkey is automatically destroyed + loader.unload(); + + // Ensure that the hotkey is really destroyed + keyDown(element, "accel-shift-x"); + + require("timer").setTimeout(function () { + assert.ok(!called, "Hotkey is destroyed and not called."); + done(); + }, 0); +}; + +require("test").run(exports); diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-l10n.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-l10n.js new file mode 100644 index 0000000..259b160 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-l10n.js @@ -0,0 +1,97 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const prefs = require("preferences-service"); +const { Loader } = require('./helpers'); + +const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; +const PREF_SELECTED_LOCALE = "general.useragent.locale"; + +function setLocale(locale) { + prefs.set(PREF_MATCH_OS_LOCALE, false); + prefs.set(PREF_SELECTED_LOCALE, locale); +} + +function resetLocale() { + prefs.reset(PREF_MATCH_OS_LOCALE); + prefs.reset(PREF_SELECTED_LOCALE); +} + +exports.testExactMatching = function(test) { + let loader = Loader(module); + setLocale("fr-FR"); + + let _ = loader.require("l10n").get; + test.assertEqual(_("Not translated"), "Not translated", + "Key not translated"); + test.assertEqual(_("Translated"), "Oui", + "Simple key translated"); + + // Placeholders + test.assertEqual(_("placeholderString", "works"), "Placeholder works", + "Value with placeholder"); + test.assertEqual(_("Placeholder %s", "works"), "Placeholder works", + "Key without value but with placeholder"); + test.assertEqual(_("Placeholders %2s %1s %s.", "working", "are", "correctly"), + "Placeholders are working correctly.", + "Multiple placeholders"); + + // Plurals + test.assertEqual(_("downloadsCount", 0), + "0 téléchargement", + "PluralForm form 'one' for 0 in french"); + test.assertEqual(_("downloadsCount", 1), + "1 téléchargement", + "PluralForm form 'one' for 1 in french"); + test.assertEqual(_("downloadsCount", 2), + "2 téléchargements", + "PluralForm form 'other' for n > 1 in french"); + + loader.unload(); + resetLocale(); +} + +exports.testEnUsLocaleName = function(test) { + let loader = Loader(module); + setLocale("en-US"); + + let _ = loader.require("l10n").get; + test.assertEqual(_("Not translated"), "Not translated"); + test.assertEqual(_("Translated"), "Yes"); + + // Check plural forms regular matching + test.assertEqual(_("downloadsCount", 0), + "0 downloads", + "PluralForm form 'other' for 0 in english"); + test.assertEqual(_("downloadsCount", 1), + "one download", + "PluralForm form 'one' for 1 in english"); + test.assertEqual(_("downloadsCount", 2), + "2 downloads", + "PluralForm form 'other' for n != 1 in english"); + + // Check optional plural forms + test.assertEqual(_("pluralTest", 0), + "optional zero form", + "PluralForm form 'zero' can be optionaly specified. (Isn't mandatory in english)"); + test.assertEqual(_("pluralTest", 1), + "fallback to other", + "If the specific plural form is missing, we fallback to 'other'"); + + loader.unload(); + resetLocale(); +} + +exports.testShortLocaleName = function(test) { + let loader = Loader(module); + setLocale("eo"); + + let _ = loader.require("l10n").get; + test.assertEqual(_("Not translated"), "Not translated"); + test.assertEqual(_("Translated"), "jes"); + + loader.unload(); + resetLocale(); +} + diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-module.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-module.js new file mode 100644 index 0000000..957d075 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-module.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** Disabled because of Bug 672199 +exports["test module exports are frozen"] = function(assert) { + assert.ok(Object.isFrozen(require("addon-kit/hotkeys")), + "module exports are frozen"); +}; + +exports["test redefine exported property"] = function(assert) { + let hotkeys = require("addon-kit/hotkeys"); + let { Hotkey } = hotkeys; + try { Object.defineProperty(hotkeys, 'Hotkey', { value: {} }); } catch(e) {} + assert.equal(hotkeys.Hotkey, Hotkey, "exports can't be redefined"); +}; +*/ + +exports["test can't delete exported property"] = function(assert) { + let hotkeys = require("addon-kit/hotkeys"); + let { Hotkey } = hotkeys; + + try { delete hotkeys.Hotkey; } catch(e) {} + assert.equal(hotkeys.Hotkey, Hotkey, "exports can't be deleted"); +}; + +exports["test can't override exported property"] = function(assert) { + let hotkeys = require("addon-kit/hotkeys"); + let { Hotkey } = hotkeys; + + try { hotkeys.Hotkey = Object } catch(e) {} + assert.equal(hotkeys.Hotkey, Hotkey, "exports can't be overriden"); +}; + +require("test").run(exports); diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-notifications.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-notifications.js new file mode 100644 index 0000000..b0e1f37 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-notifications.js @@ -0,0 +1,46 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:set ts=2 sw=2 sts=2 et filetype=javascript + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { Loader } = require('./helpers'); + +exports.testOnClick = function (test) { + let [loader, mockAlertServ] = makeLoader(module); + let notifs = loader.require("notifications"); + let data = "test data"; + let opts = { + onClick: function (clickedData) { + test.assertEqual(this, notifs, "|this| should be notifications module"); + test.assertEqual(clickedData, data, + "data passed to onClick should be correct"); + }, + data: data, + title: "test title", + text: "test text", + iconURL: "test icon URL" + }; + notifs.notify(opts); + mockAlertServ.click(); + loader.unload(); +}; + +// Returns [loader, mockAlertService]. +function makeLoader(test) { + let loader = Loader(module); + let mockAlertServ = { + showAlertNotification: function (imageUrl, title, text, textClickable, + cookie, alertListener, name) { + this._cookie = cookie; + this._alertListener = alertListener; + }, + click: function () { + this._alertListener.observe(null, "alertclickcallback", this._cookie); + } + }; + loader.require("notifications"); + let scope = loader.sandbox("notifications"); + scope.notify = mockAlertServ.showAlertNotification.bind(mockAlertServ); + return [loader, mockAlertServ]; +}; diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-mod.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-mod.js new file mode 100644 index 0000000..14a3ef9 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-mod.js @@ -0,0 +1,526 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If 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 pageMod = require("page-mod"); +var testPageMod = require("pagemod-test-helpers").testPageMod; +const { Loader } = require('./helpers'); +const tabs = require("tabs"); + +/* XXX This can be used to delay closing the test Firefox instance for interactive + * testing or visual inspection. This test is registered first so that it runs + * the last. */ +exports.delay = function(test) { + if (false) { + test.waitUntilDone(60000); + require("timer").setTimeout(function() {test.done();}, 4000); + } else + test.pass(); +} + +/* Tests for the PageMod APIs */ + +exports.testPageMod1 = function(test) { + let mods = testPageMod(test, "about:", [{ + include: /about:/, + contentScriptWhen: 'end', + contentScript: 'new ' + function WorkerScope() { + window.document.body.setAttribute("JEP-107", "worked"); + }, + onAttach: function() { + test.assertEqual(this, mods[0], "The 'this' object is the page mod."); + } + }], + function(win, done) { + test.assertEqual( + win.document.body.getAttribute("JEP-107"), + "worked", + "PageMod.onReady test" + ); + done(); + } + ); +}; + +exports.testPageMod2 = function(test) { + testPageMod(test, "about:", [{ + include: "about:*", + contentScript: [ + 'new ' + function contentScript() { + window.AUQLUE = function() { return 42; } + try { + window.AUQLUE() + } + catch(e) { + throw new Error("PageMod scripts executed in order"); + } + document.documentElement.setAttribute("first", "true"); + }, + 'new ' + function contentScript() { + document.documentElement.setAttribute("second", "true"); + } + ] + }], function(win, done) { + test.assertEqual(win.document.documentElement.getAttribute("first"), + "true", + "PageMod test #2: first script has run"); + test.assertEqual(win.document.documentElement.getAttribute("second"), + "true", + "PageMod test #2: second script has run"); + test.assertEqual("AUQLUE" in win, false, + "PageMod test #2: scripts get a wrapped window"); + done(); + }); +}; + +exports.testPageModIncludes = function(test) { + var asserts = []; + function createPageModTest(include, expectedMatch) { + // Create an 'onload' test function... + asserts.push(function(test, win) { + var matches = include in win.localStorage; + test.assert(expectedMatch ? matches : !matches, + "'" + include + "' match test, expected: " + expectedMatch); + }); + // ...and corresponding PageMod options + return { + include: include, + contentScript: 'new ' + function() { + self.on("message", function(msg) { + window.localStorage[msg] = true; + }); + }, + // The testPageMod callback with test assertions is called on 'end', + // and we want this page mod to be attached before it gets called, + // so we attach it on 'start'. + contentScriptWhen: 'start', + onAttach: function(worker) { + worker.postMessage(this.include[0]); + } + }; + } + + testPageMod(test, "about:buildconfig", [ + createPageModTest("*", false), + createPageModTest("*.google.com", false), + createPageModTest("about:*", true), + createPageModTest("about:", false), + createPageModTest("about:buildconfig", true) + ], + function (win, done) { + test.waitUntil(function () win.localStorage["about:buildconfig"], + "about:buildconfig page-mod to be executed") + .then(function () { + asserts.forEach(function(fn) { + fn(test, win); + }); + done(); + }); + } + ); +}; + +exports.testPageModErrorHandling = function(test) { + test.assertRaises(function() { + new pageMod.PageMod(); + }, + 'pattern is undefined', + "PageMod() throws when 'include' option is not specified."); +}; + +/* Tests for internal functions. */ +exports.testCommunication1 = function(test) { + let workerDone = false, + callbackDone = null; + + testPageMod(test, "about:", [{ + include: "about:*", + contentScriptWhen: 'end', + contentScript: 'new ' + function WorkerScope() { + self.on('message', function(msg) { + document.body.setAttribute('JEP-107', 'worked'); + self.postMessage(document.body.getAttribute('JEP-107')); + }) + }, + onAttach: function(worker) { + worker.on('error', function(e) { + test.fail('Errors where reported'); + }); + worker.on('message', function(value) { + test.assertEqual( + "worked", + value, + "test comunication" + ); + workerDone = true; + if (callbackDone) + callbackDone(); + }); + worker.postMessage('do it!') + } + }], + function(win, done) { + (callbackDone = function() { + if (workerDone) { + test.assertEqual( + 'worked', + win.document.body.getAttribute('JEP-107'), + 'attribute should be modified' + ); + done(); + } + })(); + } + ); +}; + +exports.testCommunication2 = function(test) { + let callbackDone = null, + window; + + testPageMod(test, "about:credits", [{ + include: "about:*", + contentScriptWhen: 'start', + contentScript: 'new ' + function WorkerScope() { + document.documentElement.setAttribute('AUQLUE', 42); + window.addEventListener('load', function listener() { + self.postMessage('onload'); + }, false); + self.on("message", function() { + self.postMessage(document.documentElement.getAttribute("test")) + }); + }, + onAttach: function(worker) { + worker.on('error', function(e) { + test.fail('Errors where reported'); + }); + worker.on('message', function(msg) { + if ('onload' == msg) { + test.assertEqual( + '42', + window.document.documentElement.getAttribute('AUQLUE'), + 'PageMod scripts executed in order' + ); + window.document.documentElement.setAttribute('test', 'changes in window'); + worker.postMessage('get window.test') + } else { + test.assertEqual( + 'changes in window', + msg, + 'PageMod test #2: second script has run' + ) + callbackDone(); + } + }); + } + }], + function(win, done) { + window = win; + callbackDone = done; + } + ); +}; + +exports.testEventEmitter = function(test) { + let workerDone = false, + callbackDone = null; + + testPageMod(test, "about:", [{ + include: "about:*", + contentScript: 'new ' + function WorkerScope() { + self.port.on('addon-to-content', function(data) { + self.port.emit('content-to-addon', data); + }); + }, + onAttach: function(worker) { + worker.on('error', function(e) { + test.fail('Errors were reported : '+e); + }); + worker.port.on('content-to-addon', function(value) { + test.assertEqual( + "worked", + value, + "EventEmitter API works!" + ); + if (callbackDone) + callbackDone(); + else + workerDone = true; + }); + worker.port.emit('addon-to-content', 'worked'); + } + }], + function(win, done) { + if (workerDone) + done(); + else + callbackDone = done; + } + ); +}; + +// Execute two concurrent page mods on same document to ensure that their +// JS contexts are different +exports.testMixedContext = function(test) { + let doneCallback = null; + let messages = 0; + let modObject = { + include: "data:text/html,", + contentScript: 'new ' + function WorkerScope() { + // Both scripts will execute this, + // context is shared if one script see the other one modification. + let isContextShared = "sharedAttribute" in document; + self.postMessage(isContextShared); + document.sharedAttribute = true; + }, + onAttach: function(w) { + w.on("message", function (isContextShared) { + if (isContextShared) { + test.fail("Page mod contexts are mixed."); + doneCallback(); + } + else if (++messages == 2) { + test.pass("Page mod contexts are different."); + doneCallback(); + } + }); + } + }; + testPageMod(test, "data:text/html,", [modObject, modObject], + function(win, done) { + doneCallback = done; + } + ); +}; + +exports.testHistory = function(test) { + // We need a valid url in order to have a working History API. + // (i.e do not work on data: or about: pages) + // Test bug 679054. + let url = require("self").data.url("test-page-mod.html"); + let callbackDone = null; + testPageMod(test, url, [{ + include: url, + contentScriptWhen: 'end', + contentScript: 'new ' + function WorkerScope() { + history.pushState({}, "", "#"); + history.replaceState({foo: "bar"}, "", "#"); + self.postMessage(history.state); + }, + onAttach: function(worker) { + worker.on('message', function (data) { + test.assertEqual(JSON.stringify(data), JSON.stringify({foo: "bar"}), + "History API works!"); + callbackDone(); + }); + } + }], + function(win, done) { + callbackDone = done; + } + ); +}; + +exports.testRelatedTab = function(test) { + test.waitUntilDone(); + + let tab; + let { PageMod } = require("page-mod"); + let pageMod = new PageMod({ + include: "about:*", + onAttach: function(worker) { + test.assertEqual(tab, worker.tab, "Worker.tab is valid"); + pageMod.destroy(); + tab.close(); + test.done(); + } + }); + + tabs.open({ + url: "about:", + onOpen: function onOpen(t) { + tab = t; + } + }); + +}; + +exports['test tab worker on message'] = function(test) { + test.waitUntilDone(); + + let { browserWindows } = require("windows"); + let tabs = require("tabs"); + let { PageMod } = require("page-mod"); + + let url1 = "data:text/html,tab1

worker1.tab

"; + let url2 = "data:text/html,tab2

worker2.tab

"; + let worker1 = null; + + let mod = PageMod({ + include: "data:text/html,*", + contentScriptWhen: "ready", + contentScript: "self.postMessage('#1');", + onAttach: function onAttach(worker) { + worker.on("message", function onMessage() { + this.tab.attach({ + contentScriptWhen: "ready", + contentScript: "self.postMessage({ url: window.location.href, title: document.title });", + onMessage: function onMessage(data) { + test.assertEqual(this.tab.url, data.url, "location is correct"); + test.assertEqual(this.tab.title, data.title, "title is correct"); + if (this.tab.url === url1) { + worker1 = this; + tabs.open({ url: url2, inBackground: true }); + } + else if (this.tab.url === url2) { + mod.destroy(); + worker1.tab.close(); + worker1.destroy(); + worker.tab.close(); + worker.destroy(); + test.done(); + } + } + }); + }); + } + }); + + tabs.open(url1); +}; + +exports.testAutomaticDestroy = function(test) { + test.waitUntilDone(); + let loader = Loader(module); + + let pageMod = loader.require("page-mod").PageMod({ + include: "about:*", + contentScriptWhen: "start", + onAttach: function(w) { + test.fail("Page-mod should have been detroyed during module unload"); + } + }); + + // Unload the page-mod module so that our page mod is destroyed + loader.unload(); + + // Then create a second tab to ensure that it is correctly destroyed + let tabs = require("tabs"); + tabs.open({ + url: "about:", + onReady: function onReady(tab) { + test.pass("check automatic destroy"); + tab.close(); + test.done(); + } + }); + +} + +exports.testPageModCss = function(test) { + let [pageMod] = testPageMod(test, + 'data:text/html,
css test
', [{ + include: "data:*", + contentStyle: "div { height: 100px; }", + contentStyleFile: + require("self").data.url("pagemod-css-include-file.css") + }], + function(win, done) { + let div = win.document.querySelector("div"); + test.assertEqual( + div.clientHeight, + 100, + "PageMod contentStyle worked" + ); + test.assertEqual( + div.offsetHeight, + 120, + "PageMod contentStyleFile worked" + ); + done(); + } + ); +}; + +exports.testPageModCssList = function(test) { + let [pageMod] = testPageMod(test, + 'data:text/html,
css test
', [{ + include: "data:*", + contentStyleFile: [ + // Highlight evaluation order in this list + "data:text/css,div { border: 1px solid black; }", + "data:text/css,div { border: 10px solid black; }", + // Highlight evaluation order between contentStylesheet & contentStylesheetFile + "data:text/css,div { height: 1000px; }", + // Highlight precedence between the author and user style sheet + "data:text/css,div { width: 200px; max-width: 640px!important}", + ], + contentStyle: [ + "div { height: 10px; }", + "div { height: 100px; }" + ] + }], + function(win, done) { + let div = win.document.querySelector("div"), + style = win.getComputedStyle(div); + + test.assertEqual( + div.clientHeight, + 100, + "PageMod contentStyle list works and is evaluated after contentStyleFile" + ); + + test.assertEqual( + div.offsetHeight, + 120, + "PageMod contentStyleFile list works" + ); + + test.assertEqual( + style.width, + "320px", + "PageMod author/user style sheet precedence works" + ); + + test.assertEqual( + style.maxWidth, + "640px", + "PageMod author/user style sheet precedence with !important works" + ); + + done(); + } + ); +}; + +exports.testPageModCssDestroy = function(test) { + let [pageMod] = testPageMod(test, + 'data:text/html,
css test
', [{ + include: "data:*", + contentStyle: "div { width: 100px!important; }" + }], + + function(win, done) { + let div = win.document.querySelector("div"), + style = win.getComputedStyle(div); + + test.assertEqual( + style.width, + "100px", + "PageMod contentStyle worked" + ); + + pageMod.destroy(); + test.assertEqual( + style.width, + "200px", + "PageMod contentStyle is removed after destroy" + ); + + done(); + + } + ); +}; diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-worker.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-worker.js new file mode 100644 index 0000000..5fc3bec --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-page-worker.js @@ -0,0 +1,366 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +let tests = {}, Pages, Page; +const { Loader } = require('./helpers'); + +const ERR_DESTROYED = + "The page has been destroyed and can no longer be used."; + +tests.testSimplePageCreation = function(test) { + test.waitUntilDone(); + + let page = new Page({ + contentScript: "self.postMessage(window.location.href)", + contentScriptWhen: "end", + onMessage: function (message) { + test.assertEqual(message, "about:blank", + "Page Worker should start with a blank page by default"); + test.assertEqual(this, page, "The 'this' object is the page itself."); + test.done(); + } + }); +} + +/* + * Tests that we can't be tricked by document overloads as we have access + * to wrapped nodes + */ +tests.testWrappedDOM = function(test) { + test.waitUntilDone(); + + let page = Page({ + allow: { script: true }, + contentURL: "data:text/html,", + contentScript: "window.addEventListener('load', function () " + + "self.postMessage([typeof(document.getElementById), " + + "typeof(window.scrollTo)]), true)", + onMessage: function (message) { + test.assertEqual(message[0], + "function", + "getElementById from content script is the native one"); + + test.assertEqual(message[1], + "function", + "scrollTo from content script is the native one"); + + test.done(); + } + }); +} + +/* +// We do not offer unwrapped access to DOM since bug 601295 landed +// See 660780 to track progress of unwrap feature +tests.testUnwrappedDOM = function(test) { + test.waitUntilDone(); + + let page = Page({ + allow: { script: true }, + contentURL: "data:text/html,", + contentScript: "window.addEventListener('load', function () " + + "self.postMessage([typeof(unsafeWindow.document.getElementById), " + + "typeof(unsafeWindow.scrollTo)]), true)", + onMessage: function (message) { + test.assertEqual(message[0], + "number", + "document inside page is free to be changed"); + + test.assertEqual(message[1], + "number", + "window inside page is free to be changed"); + + test.done(); + } + }); +} +*/ + +tests.testPageProperties = function(test) { + let page = new Page(); + + for each (let prop in ['contentURL', 'allow', 'contentScriptFile', + 'contentScript', 'contentScriptWhen', 'on', + 'postMessage', 'removeListener']) { + test.assert(prop in page, prop + " property is defined on page."); + } + + test.assert(function () page.postMessage("foo") || true, + "postMessage doesn't throw exception on page."); +} + +tests.testConstructorAndDestructor = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let Pages = loader.require("page-worker"); + let global = loader.sandbox("page-worker"); + + let pagesReady = 0; + + let page1 = Pages.Page({ + contentScript: "self.postMessage('')", + contentScriptWhen: "end", + onMessage: pageReady + }); + let page2 = Pages.Page({ + contentScript: "self.postMessage('')", + contentScriptWhen: "end", + onMessage: pageReady + }); + + test.assertNotEqual(page1, page2, + "Page 1 and page 2 should be different objects."); + + function pageReady() { + if (++pagesReady == 2) { + page1.destroy(); + page2.destroy(); + + test.assert(isDestroyed(page1), "page1 correctly unloaded."); + test.assert(isDestroyed(page2), "page2 correctly unloaded."); + + loader.unload(); + test.done(); + } + } +} + +tests.testAutoDestructor = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let Pages = loader.require("page-worker"); + + let page = Pages.Page({ + contentScript: "self.postMessage('')", + contentScriptWhen: "end", + onMessage: function() { + loader.unload(); + test.assert(isDestroyed(page), "Page correctly unloaded."); + test.done(); + } + }); +} + +tests.testValidateOptions = function(test) { + test.assertRaises( + function () Page({ contentURL: 'home' }), + "The `contentURL` option must be a valid URL.", + "Validation correctly denied a non-URL contentURL" + ); + + test.assertRaises( + function () Page({ onMessage: "This is not a function."}), + "The event listener must be a function.", + "Validation correctly denied a non-function onMessage." + ); + + test.pass("Options validation is working."); +} + +tests.testContentAndAllowGettersAndSetters = function(test) { + test.waitUntilDone(); + let content = "data:text/html,"; + let page = Page({ + contentURL: content, + contentScript: "self.postMessage(window.localStorage.allowScript)", + contentScriptWhen: "end", + onMessage: step0 + }); + + function step0(message) { + test.assertEqual(message, "3", + "Correct value expected for allowScript - 3"); + test.assertEqual(page.contentURL, content, + "Correct content expected"); + page.removeListener('message', step0); + page.on('message', step1); + page.allow = { script: false }; + page.contentURL = content = + "data:text/html,"; + } + + function step1(message) { + test.assertEqual(message, "3", + "Correct value expected for allowScript - 3"); + test.assertEqual(page.contentURL, content, "Correct content expected"); + page.removeListener('message', step1); + page.on('message', step2); + page.allow = { script: true }; + page.contentURL = content = + "data:text/html,"; + } + + function step2(message) { + test.assertEqual(message, "g", + "Correct value expected for allowScript - g"); + test.assertEqual(page.contentURL, content, "Correct content expected"); + page.removeListener('message', step2); + page.on('message', step3); + page.allow.script = false; + page.contentURL = content = + "data:text/html,"; + } + + function step3(message) { + test.assertEqual(message, "g", + "Correct value expected for allowScript - g"); + test.assertEqual(page.contentURL, content, "Correct content expected"); + page.removeListener('message', step3); + page.on('message', step4); + page.allow.script = true; + page.contentURL = content = + "data:text/html,"; + } + + function step4(message) { + test.assertEqual(message, "4", + "Correct value expected for allowScript - 4"); + test.assertEqual(page.contentURL, content, "Correct content expected"); + test.done(); + } + +} + +tests.testOnMessageCallback = function(test) { + test.waitUntilDone(); + + Page({ + contentScript: "self.postMessage('')", + contentScriptWhen: "end", + onMessage: function() { + test.pass("onMessage callback called"); + test.done(); + } + }); +} + +tests.testMultipleOnMessageCallbacks = function(test) { + test.waitUntilDone(); + + let count = 0; + let page = Page({ + contentScript: "self.postMessage('')", + contentScriptWhen: "end", + onMessage: function() count += 1 + }); + page.on('message', function() count += 2); + page.on('message', function() count *= 3); + page.on('message', function() + test.assertEqual(count, 9, "All callbacks were called, in order.")); + page.on('message', function() test.done()); + +} + +tests.testLoadContentPage = function(test) { + + test.waitUntilDone(); + + let page = Page({ + onMessage: function(message) { + // The message is an array whose first item is the test method to call + // and the rest of whose items are arguments to pass it. + test[message.shift()].apply(test, message); + }, + contentURL: require("self").data.url("test-page-worker.html"), + contentScriptFile: require("self").data.url("test-page-worker.js"), + contentScriptWhen: "ready" + }); + +} + +tests.testAllowScriptDefault = function(test) { + + test.waitUntilDone(); + + let page = Page({ + onMessage: function(message) { + test.assert(message, "Script is allowed to run by default."); + test.done(); + }, + contentURL: "data:text/html,", + contentScript: "self.postMessage(document.documentElement.getAttribute('foo'))", + contentScriptWhen: "ready" + }); +} + +tests.testAllowScript = function(test) { + + test.waitUntilDone(); + + let page = Page({ + onMessage: function(message) { + test.assert(message, "Script runs when allowed to do so."); + test.done(); + }, + allow: { script: true }, + contentURL: "data:text/html,", + contentScript: "self.postMessage(document.documentElement.hasAttribute('foo') && " + + " document.documentElement.getAttribute('foo') == 3)", + contentScriptWhen: "ready" + }); +} + +tests.testPingPong = function(test) { + test.waitUntilDone(); + let page = Page({ + contentURL: 'data:text/html,ping-pong', + contentScript: 'self.on("message", function(message) self.postMessage("pong"));' + + 'self.postMessage("ready");', + onMessage: function(message) { + if ('ready' == message) { + page.postMessage('ping'); + } + else { + test.assert(message, 'pong', 'Callback from contentScript'); + test.done(); + } + } + }); +}; + +tests.testMultipleDestroys = function(test) { + let page = Page(); + page.destroy(); + page.destroy(); + test.pass("Multiple destroys should not cause an error"); +}; + + +function isDestroyed(page) { + try { + page.postMessage("foo"); + } + catch (err if err.message == ERR_DESTROYED) { + return true; + } + return false; +} + + +let pageWorkerSupported = true; + +try { + Pages = require("page-worker"); + Page = Pages.Page; +} +catch (ex if ex.message == [ + "The page-worker module currently supports only Firefox and Thunderbird. ", + "In the future, we would like it to support other applications, however. ", + "Please see https://bugzilla.mozilla.org/show_bug.cgi?id=546740 for more ", + "information." + ].join("")) { + pageWorkerSupported = false; +} + +if (pageWorkerSupported) { + for (let test in tests) { + exports[test] = tests[test]; + } +} else { + exports.testPageWorkerNotSupported = function(test) { + test.pass("The page-worker module is not supported on this app."); + } +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-panel.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-panel.js new file mode 100644 index 0000000..e05400e --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-panel.js @@ -0,0 +1,466 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +let { Cc, Ci } = require("chrome"); +let panels = require('panel'); +let tests = {}, panels, Panel; +const { Loader } = require('./helpers'); + +tests.testPanel = function(test) { + test.waitUntilDone(); + let panel = Panel({ + contentURL: "about:buildconfig", + contentScript: "self.postMessage(1); self.on('message', function() self.postMessage(2));", + onMessage: function (message) { + test.assertEqual(this, panel, "The 'this' object is the panel."); + switch(message) { + case 1: + test.pass("The panel was loaded."); + panel.postMessage(''); + break; + case 2: + test.pass("The panel posted a message and received a response."); + panel.destroy(); + test.done(); + break; + } + } + }); +}; + +tests.testPanelEmit = function(test) { + test.waitUntilDone(); + let panel = Panel({ + contentURL: "about:buildconfig", + contentScript: "self.port.emit('loaded');" + + "self.port.on('addon-to-content', " + + " function() self.port.emit('received'));", + }); + panel.port.on("loaded", function () { + test.pass("The panel was loaded and sent a first event."); + panel.port.emit("addon-to-content"); + }); + panel.port.on("received", function () { + test.pass("The panel posted a message and received a response."); + panel.destroy(); + test.done(); + }); +}; + +tests.testPanelEmitEarly = function(test) { + test.waitUntilDone(); + let panel = Panel({ + contentURL: "about:buildconfig", + contentScript: "self.port.on('addon-to-content', " + + " function() self.port.emit('received'));", + }); + panel.port.on("received", function () { + test.pass("The panel posted a message early and received a response."); + panel.destroy(); + test.done(); + }); + panel.port.emit("addon-to-content"); +}; + +tests.testShowHidePanel = function(test) { + test.waitUntilDone(); + let panel = Panel({ + contentScript: "self.postMessage('')", + contentScriptWhen: "end", + onMessage: function (message) { + panel.show(); + }, + onShow: function () { + test.pass("The panel was shown."); + test.assertEqual(this, panel, "The 'this' object is the panel."); + test.assertEqual(this.isShowing, true, "panel.isShowing == true."); + panel.hide(); + }, + onHide: function () { + test.pass("The panel was hidden."); + test.assertEqual(this, panel, "The 'this' object is the panel."); + test.assertEqual(this.isShowing, false, "panel.isShowing == false."); + panel.destroy(); + test.done(); + } + }); +}; + +tests.testDocumentReload = function(test) { + test.waitUntilDone(); + let content = + ""; + let messageCount = 0; + let panel = Panel({ + contentURL: "data:text/html," + encodeURIComponent(content), + contentScript: "self.postMessage(window.location.href)", + onMessage: function (message) { + messageCount++; + if (messageCount == 1) { + test.assertMatches(message, /data:text\/html,/, "First document had a content script"); + } + else if (messageCount == 2) { + test.assertEqual(message, "about:blank", "Second document too"); + panel.destroy(); + test.done(); + } + } + }); +}; + +tests.testParentResizeHack = function(test) { + let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. + getService(Ci.nsIWindowMediator). + getMostRecentWindow("navigator:browser"); + let docShell = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell); + if (!("allowWindowControl" in docShell)) { + // bug 635673 is not fixed in this firefox build + test.pass("allowWindowControl attribute that allow to fix browser window " + + "resize is not available on this build."); + return; + } + + test.waitUntilDone(30000); + + let previousWidth = browserWindow.outerWidth, previousHeight = browserWindow.outerHeight; + + let content = "" + + "Try to resize browser window"; + let panel = Panel({ + contentURL: "data:text/html," + encodeURIComponent(content), + contentScript: "self.on('message', function(message){" + + " if (message=='resize') " + + " unsafeWindow.contentResize();" + + "});", + contentScriptWhen: "ready", + onMessage: function (message) { + + }, + onShow: function () { + panel.postMessage('resize'); + require("timer").setTimeout(function () { + test.assertEqual(previousWidth,browserWindow.outerWidth,"Size doesn't change by calling resizeTo/By/..."); + test.assertEqual(previousHeight,browserWindow.outerHeight,"Size doesn't change by calling resizeTo/By/..."); + panel.destroy(); + test.done(); + },0); + } + }); + panel.show(); +} + +tests.testResizePanel = function(test) { + test.waitUntilDone(); + + // These tests fail on Linux if the browser window in which the panel + // is displayed is not active. And depending on what other tests have run + // before this one, it might not be (the untitled window in which the test + // runner executes is often active). So we make sure the browser window + // is focused by focusing it before running the tests. Then, to be the best + // possible test citizen, we refocus whatever window was focused before we + // started running these tests. + + let activeWindow = Cc["@mozilla.org/embedcomp/window-watcher;1"]. + getService(Ci.nsIWindowWatcher). + activeWindow; + let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. + getService(Ci.nsIWindowMediator). + getMostRecentWindow("navigator:browser"); + + + function onFocus() { + browserWindow.removeEventListener("focus", onFocus, true); + + let panel = Panel({ + contentScript: "self.postMessage('')", + contentScriptWhen: "end", + height: 10, + width: 10, + onMessage: function (message) { + panel.show(); + }, + onShow: function () { + panel.resize(100,100); + panel.hide(); + }, + onHide: function () { + test.assert((panel.width == 100) && (panel.height == 100), + "The panel was resized."); + if (activeWindow) + activeWindow.focus(); + test.done(); + } + }); + } + + if (browserWindow === activeWindow) { + onFocus(); + } + else { + browserWindow.addEventListener("focus", onFocus, true); + browserWindow.focus(); + } +}; + +tests.testHideBeforeShow = function(test) { + test.waitUntilDone(); + let showCalled = false; + let panel = Panel({ + onShow: function () { + showCalled = true; + }, + onHide: function () { + test.assert(!showCalled, 'must not emit show if was hidden before'); + test.done(); + } + }); + panel.show(); + panel.hide(); +}; + +tests.testSeveralShowHides = function(test) { + test.waitUntilDone(); + let hideCalled = 0; + let panel = panels.Panel({ + contentURL: "about:buildconfig", + onShow: function () { + panel.hide(); + }, + onHide: function () { + hideCalled++; + if (hideCalled < 3) + panel.show(); + else { + test.pass("onHide called three times as expected"); + test.done(); + } + } + }); + panel.on('error', function(e) { + test.fail('error was emitted:' + e.message + '\n' + e.stack); + }); + panel.show(); +}; + +tests.testAnchorAndArrow = function(test) { + test.waitUntilDone(20000); + let count = 0; + function newPanel(tab, anchor) { + let panel = panels.Panel({ + contentURL: "data:text/html,Anchor: " + + anchor.id + "", + width: 200, + height: 100, + onShow: function () { + count++; + panel.destroy(); + if (count==5) { + test.pass("All anchored panel test displayed"); + tab.close(function () { + test.done(); + }); + } + } + }); + panel.show(anchor); + } + + let tabs= require("tabs"); + let url = 'data:text/html,' + + 'foo' + + '' + + '
Top Left
' + + '
Top Right
' + + '
Bottom Left
' + + '
Bottom right
' + + ''; + + tabs.open({ + url: url, + onReady: function(tab) { + let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. + getService(Ci.nsIWindowMediator). + getMostRecentWindow("navigator:browser"); + let window = browserWindow.content; + newPanel(tab, window.document.getElementById('tl')); + newPanel(tab, window.document.getElementById('tr')); + newPanel(tab, window.document.getElementById('bl')); + newPanel(tab, window.document.getElementById('br')); + let anchor = browserWindow.document.getElementById("identity-box"); + newPanel(tab, anchor); + } + }); + + + +}; + +tests.testPanelTextColor = function(test) { + test.waitUntilDone(); + let html = "" + + "

Foo

"; + let panel = Panel({ + contentURL: "data:text/html," + encodeURI(html), + contentScript: "self.port.emit('color', " + + "window.getComputedStyle(document.body.firstChild, null). " + + " getPropertyValue('color'));" + }); + panel.port.on("color", function (color) { + test.assertEqual(color, "rgb(255, 255, 0)", + "The panel text color style is preserved when a style exists."); + panel.destroy(); + test.done(); + }); +}; + +// Bug 696552: Ensure panel.contentURL modification support +tests.testChangeContentURL = function(test) { + test.waitUntilDone(); + + let panel = Panel({ + contentURL: "about:blank", + contentScript: "self.port.emit('ready', document.location.href);" + }); + let count = 0; + panel.port.on("ready", function (location) { + count++; + if (count == 1) { + test.assertEqual(location, "about:blank"); + test.assertEqual(panel.contentURL, "about:blank"); + panel.contentURL = "about:buildconfig"; + } + else { + test.assertEqual(location, "about:buildconfig"); + test.assertEqual(panel.contentURL, "about:buildconfig"); + panel.destroy(); + test.done(); + } + }); +}; + +function makeEventOrderTest(options) { + let expectedEvents = []; + + return function(test) { + let panel = panels.Panel({ contentURL: "about:buildconfig" }); + + function expect(event, cb) { + expectedEvents.push(event); + panel.on(event, function() { + test.assertEqual(event, expectedEvents.shift()); + if (cb) + require("timer").setTimeout(cb, 1); + }); + return {then: expect}; + } + + test.waitUntilDone(); + options.test(test, expect, panel); + } +} + +tests.testAutomaticDestroy = function(test) { + let loader = Loader(module); + let panel = loader.require("panel").Panel({ + contentURL: "about:buildconfig", + contentScript: + "self.port.on('event', function() self.port.emit('event-back'));" + }); + + loader.unload(); + + panel.port.on("event-back", function () { + test.fail("Panel should have been destroyed on module unload"); + }); + panel.port.emit("event"); + test.pass("check automatic destroy"); +}; + +tests.testWaitForInitThenShowThenDestroy = makeEventOrderTest({ + test: function(test, expect, panel) { + expect('inited', function() { panel.show(); }). + then('show', function() { panel.destroy(); }). + then('hide', function() { test.done(); }); + } +}); + +tests.testShowThenWaitForInitThenDestroy = makeEventOrderTest({ + test: function(test, expect, panel) { + panel.show(); + expect('inited'). + then('show', function() { panel.destroy(); }). + then('hide', function() { test.done(); }); + } +}); + +tests.testShowThenHideThenDestroy = makeEventOrderTest({ + test: function(test, expect, panel) { + panel.show(); + expect('show', function() { panel.hide(); }). + then('hide', function() { panel.destroy(); test.done(); }); + } +}); + +tests.testContentURLOption = function(test) { + const URL_STRING = "about:buildconfig"; + const HTML_CONTENT = "Test

This is a test.

"; + + let (panel = Panel({ contentURL: URL_STRING })) { + test.pass("contentURL accepts a string URL."); + test.assertEqual(panel.contentURL, URL_STRING, + "contentURL is the string to which it was set."); + } + + let dataURL = "data:text/html," + encodeURIComponent(HTML_CONTENT); + let (panel = Panel({ contentURL: dataURL })) { + test.pass("contentURL accepts a data: URL."); + } + + let (panel = Panel({})) { + test.assert(panel.contentURL == null, + "contentURL is undefined."); + } + + test.assertRaises(function () Panel({ contentURL: "foo" }), + "The `contentURL` option must be a valid URL.", + "Panel throws an exception if contentURL is not a URL."); +}; + +let panelSupported = true; + +try { + panels = require("panel"); + Panel = panels.Panel; +} +catch(ex if ex.message == [ + "The panel module currently supports only Firefox. In the future ", + "we would like it to support other applications, however. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps ", + "for more information." + ].join("")) { + panelSupported = false; +} + +if (panelSupported) { + for (let test in tests) + exports[test] = tests[test]; +} +else { + exports.testPanelNotSupported = function(test) { + test.pass("The panel module is not supported on this app."); + } +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-passwords.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-passwords.js new file mode 100644 index 0000000..bfb137a --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-passwords.js @@ -0,0 +1,281 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If 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 { store, search, remove } = require("passwords"); + +exports["test store requires `password` field"] = function(assert, done) { + store({ + username: "foo", + realm: "bar", + onComplete: function onComplete() { + assert.fail("onComplete should not be called"); + }, + onError: function onError() { + assert.pass("'`password` is required"); + done(); + } + }); +}; + +exports["test store requires `username` field"] = function(assert, done) { + store({ + password: "foo", + realm: "bar", + onComplete: function onComplete() { + assert.fail("onComplete should not be called"); + }, + onError: function onError() { + assert.pass("'`username` is required"); + done(); + } + }); +}; + +exports["test onComplete is optional"] = function(assert, done) { + store({ + realm: "bla", + username: "bla", + password: "bla", + onError: function onError() { + assert.fail("onError was called"); + } + }); + assert.pass("exception is not thrown if `onComplete is missing") + done(); +}; + +exports["test exceptions in onComplete are reported"] = function(assert, done) { + store({ + realm: "throws", + username: "error", + password: "boom!", + onComplete: function onComplete(error) { + throw new Error("Boom!") + }, + onError: function onError(error) { + assert.equal(error.message, "Boom!", "Error thrown is reported"); + done(); + } + }); +}; + +exports["test store requires `realm` field"] = function(assert, done) { + store({ + username: "foo", + password: "bar", + onComplete: function onComplete() { + assert.fail("onComplete should not be called"); + }, + onError: function onError() { + assert.pass("'`realm` is required"); + done(); + } + }); +}; + +exports["test can't store same login twice"] = function(assert, done) { + store({ + username: "user", + password: "pass", + realm: "realm", + onComplete: function onComplete() { + assert.pass("credential saved"); + + store({ + username: "user", + password: "pass", + realm: "realm", + onComplete: function onComplete() { + assert.fail("onComplete should not be called"); + }, + onError: function onError() { + assert.pass("re-saving credential failed"); + + remove({ + username: "user", + password: "pass", + realm: "realm", + onComplete: function onComplete() { + assert.pass("credential was removed"); + done(); + }, + onError: function onError() { + assert.fail("remove should not fail"); + } + }); + } + }); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); +}; + +exports["test remove fails if no login found"] = function(assert, done) { + remove({ + username: "foo", + password: "bar", + realm: "baz", + onComplete: function onComplete() { + assert.fail("should not be able to remove unstored credentials"); + }, + onError: function onError() { + assert.pass("can't remove unstored credentials"); + done(); + } + }); +}; + +exports["test addon associated credentials"] = function(assert, done) { + store({ + username: "foo", + password: "bar", + realm: "baz", + onComplete: function onComplete() { + search({ + username: "foo", + password: "bar", + realm: "baz", + onComplete: function onComplete([credential]) { + assert.equal(credential.url.indexOf("addon:"), 0, + "`addon:` uri is used for add-on credentials"); + assert.equal(credential.username, "foo", + "username matches"); + assert.equal(credential.password, "bar", + "password matches"); + assert.equal(credential.realm, "baz", "realm matches"); + assert.equal(credential.formSubmitURL, null, + "`formSubmitURL` is `null` for add-on credentials"); + assert.equal(credential.usernameField, "", "usernameField is empty"); + assert.equal(credential.passwordField, "", "passwordField is empty"); + + remove({ + username: credential.username, + password: credential.password, + realm: credential.realm, + onComplete: function onComplete() { + assert.pass("credential is removed"); + done(); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); +}; + +exports["test web page associated credentials"] = function(assert, done) { + store({ + url: "http://bar.foo.com/authentication/?login", + formSubmitURL: "http://login.foo.com/authenticate.cgi", + username: "user", + password: "pass", + usernameField: "user-f", + passwordField: "pass-f", + onComplete: function onComplete() { + search({ + username: "user", + password: "pass", + url: "http://bar.foo.com", + formSubmitURL: "http://login.foo.com", + onComplete: function onComplete([credential]) { + assert.equal(credential.url, "http://bar.foo.com", "url matches"); + assert.equal(credential.username, "user", "username matches"); + assert.equal(credential.password, "pass", "password matches"); + assert.equal(credential.realm, null, "realm is null"); + assert.equal(credential.formSubmitURL, "http://login.foo.com", + "formSubmitURL matches"); + assert.equal(credential.usernameField, "user-f", + "usernameField is matches"); + assert.equal(credential.passwordField, "pass-f", + "passwordField matches"); + + remove({ + url: credential.url, + formSubmitURL: credential.formSubmitURL, + username: credential.username, + password: credential.password, + usernameField: credential.usernameField, + passwordField: credential.passwordField, + + onComplete: function onComplete() { + assert.pass("credential is removed"); + done(); + }, + onError: function onError(e) { + assert.fail("onError should not be called"); + } + }); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); +}; + +exports["test site authentication credentials"] = function(assert, done) { + store({ + url: "http://authentication.com", + username: "U", + password: "P", + realm: "R", + onComplete: function onComplete() { + search({ + url: "http://authentication.com", + username: "U", + password: "P", + realm: "R", + onComplete: function onComplete([credential]) { + assert.equal(credential.url,"http://authentication.com", + "url matches"); + assert.equal(credential.username, "U", "username matches"); + assert.equal(credential.password, "P", "password matches"); + assert.equal(credential.realm, "R", "realm matches"); + assert.equal(credential.formSubmitURL, null, "formSubmitURL is null"); + assert.equal(credential.usernameField, "", "usernameField is empty"); + assert.equal(credential.passwordField, "", "passwordField is empty"); + + remove({ + url: credential.url, + username: credential.username, + password: credential.password, + realm: credential.realm, + onComplete: function onComplete() { + assert.pass("credential is removed"); + done(); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); + }, + onError: function onError() { + assert.fail("onError should not be called"); + } + }); +}; + +require("test").run(exports); diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-private-browsing.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-private-browsing.js new file mode 100644 index 0000000..1d60f6b --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-private-browsing.js @@ -0,0 +1,204 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +let pb = require("private-browsing"); +let {Cc,Ci} = require("chrome"); +const { Loader } = require('./helpers'); + +let pbService; +// Currently, only Firefox implements the private browsing service. +if (require("xul-app").is("Firefox")) { + pbService = Cc["@mozilla.org/privatebrowsing;1"]. + getService(Ci.nsIPrivateBrowsingService); +} + +if (pbService) { + + // tests that isActive has the same value as the private browsing service + // expects + exports.testGetIsActive = function (test) { + test.assertEqual(pb.isActive, false, + "private-browsing.isActive is correct without modifying PB service"); + + pbService.privateBrowsingEnabled = true; + test.assert(pb.isActive, + "private-browsing.isActive is correct after modifying PB service"); + + // Switch back to normal mode. + pbService.privateBrowsingEnabled = false; + }; + + // tests that activating does put the browser into private browsing mode + exports.testActivateDeactivate = function (test) { + test.waitUntilDone(); + pb.once("start", function onStart() { + test.assertEqual(pbService.privateBrowsingEnabled, true, + "private browsing mode was activated"); + pb.deactivate(); + }); + pb.once("stop", function onStop() { + test.assertEqual(pbService.privateBrowsingEnabled, false, + "private browsing mode was deactivate"); + test.done(); + }); + pb.activate(); + }; + + exports.testStart = function(test) { + test.waitUntilDone(); + pb.on("start", function onStart() { + test.assertEqual(this, pb, "`this` should be private-browsing module"); + test.assert(pbService.privateBrowsingEnabled, + 'private mode is active when "start" event is emitted'); + test.assert(pb.isActive, + '`isActive` is `true` when "start" event is emitted'); + pb.removeListener("start", onStart); + test.done(); + }); + pb.activate(); + }; + + exports.testStop = function(test) { + test.waitUntilDone(); + pb.on("stop", function onStop() { + test.assertEqual(this, pb, "`this` should be private-browsing module"); + test.assertEqual(pbService.privateBrowsingEnabled, false, + "private mode is disabled when stop event is emitted"); + test.assertEqual(pb.isActive, false, + "`isActive` is `false` when stop event is emitted"); + pb.removeListener("stop", onStop); + test.done(); + }); + pb.activate(); + pb.deactivate(); + }; + + exports.testAutomaticUnload = function(test) { + test.waitUntilDone(); + // Create another private browsing instance and unload it + let loader = Loader(module); + let pb2 = loader.require("private-browsing"); + let called = false; + pb2.on("start", function onStart() { + called = true; + test.fail("should not be called:x"); + }); + loader.unload(); + + // Then switch to private mode in order to check that the previous instance + // is correctly destroyed + pb.activate(); + pb.once("start", function onStart() { + require("timer").setTimeout(function () { + test.assert(!called, + "First private browsing instance is destroyed and inactive"); + + // Must reset to normal mode, so that next test starts with it. + pb.deactivate(); + test.done(); + }, 0); + }); + }; + + exports.testBothListeners = function(test) { + test.waitUntilDone(); + let stop = false; + let start = false; + + function onStop() { + test.assertEqual(stop, false, + "stop callback must be called only once"); + test.assertEqual(pbService.privateBrowsingEnabled, false, + "private mode is disabled when stop event is emitted"); + test.assertEqual(pb.isActive, false, + "`isActive` is `false` when stop event is emitted"); + + pb.on("start", finish); + pb.removeListener("start", onStart); + pb.removeListener("start", onStart2); + pb.activate(); + stop = true; + } + + function onStart() { + test.assertEqual(false, start, + "stop callback must be called only once"); + test.assert(pbService.privateBrowsingEnabled, + "private mode is active when start event is emitted"); + test.assert(pb.isActive, + "`isActive` is `true` when start event is emitted"); + + pb.on("stop", onStop); + pb.deactivate(); + start = true; + } + + function onStart2() { + test.assert(start, "start listener must be called already"); + test.assertEqual(false, stop, "stop callback must not be called yet"); + } + + function finish() { + test.assert(pbService.privateBrowsingEnabled, true, + "private mode is active when start event is emitted"); + test.assert(pb.isActive, + "`isActive` is `true` when start event is emitted"); + + pb.removeListener("start", finish); + pb.removeListener("stop", onStop); + + pb.deactivate(); + pb.once("stop", function () { + test.assertEqual(pbService.privateBrowsingEnabled, false); + test.assertEqual(pb.isActive, false); + + test.done(); + }); + } + + pb.on("start", onStart); + pb.on("start", onStart2); + pbService.privateBrowsingEnabled = true; + }; + + exports["test activate private mode via handler"] = function(test) { + const tabs = require("tabs"); + + test.waitUntilDone(); + function onReady(tab) { + if (tab.url == "about:robots") + tab.close(function() pb.activate()); + } + function cleanup(tab) { + if (tab.url == "about:") { + tabs.removeListener("ready", cleanup); + tab.close(function onClose() { + test.done(); + }); + } + } + + tabs.on("ready", onReady); + pb.once("start", function onStart() { + test.pass("private mode was activated"); + pb.deactivate(); + }); + pb.once("stop", function onStop() { + test.pass("private mode was deactivated"); + tabs.removeListener("ready", onReady); + tabs.on("ready", cleanup); + }); + tabs.once("open", function onOpen() { + tabs.open("about:robots"); + }); + tabs.open("about:"); + }; +} +else { + // tests for the case where private browsing doesn't exist + exports.testNoImpl = function (test) { + test.assertEqual(pb.isActive, false, + "pb.isActive returns false when private browsing isn't supported"); + }; +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-request.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-request.js new file mode 100644 index 0000000..42425d7 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-request.js @@ -0,0 +1,340 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { Request } = require("addon-kit/request"); +const { pathFor } = require("api-utils/system"); +const { startServerAsync } = require("api-utils/httpd"); +const file = require("api-utils/file"); + +const basePath = pathFor("TmpD") +const port = 8099; + + +exports.testOptionsValidator = function(test) { + // First, a simple test to make sure we didn't break normal functionality. + test.assertRaises(function () { + Request({ + url: null + }); + }, 'The option "url" must be one of the following types: string'); + + // Next we'll have a Request that doesn't throw from c'tor, but from a setter. + let req = Request({ + url: "http://playground.zpao.com/jetpack/request/text.php", + onComplete: function () {} + }); + test.assertRaises(function () { + req.url = null; + }, 'The option "url" must be one of the following types: string'); + // The url shouldn't have changed, so check that + test.assertEqual(req.url, "http://playground.zpao.com/jetpack/request/text.php"); +} + +exports.testContentValidator = function(test) { + test.waitUntilDone(); + Request({ + url: "data:text/html,response", + content: { 'key1' : null, 'key2' : 'some value' }, + onComplete: function(response) { + test.assertEqual(response.text, "response?key1=null&key2=some+value"); + test.done(); + } + }).get(); +}; + +// All tests below here require a network connection. They will be commented out +// when checked in. If you'd like to run them, simply uncomment them. +// +// When we have the means, these tests will be converted so that they don't +// require an external server nor a network connection. + +// This is a request to a file that exists. +exports.testStatus200 = function (test) { + let srv = startServerAsync(port, basePath); + let content = "Look ma, no hands!\n"; + let basename = "test-request.txt" + prepareFile(basename, content); + + test.waitUntilDone(); + var req = Request({ + url: "http://localhost:" + port + "/" + basename, + onComplete: function (response) { + test.assertEqual(this, req, "`this` should be request"); + test.assertEqual(response.status, 200); + test.assertEqual(response.statusText, "OK"); + test.assertEqual(response.headers["Content-Type"], "text/plain"); + test.assertEqual(response.text, content); + srv.stop(function() test.done()); + } + }).get(); +} + +// This tries to get a file that doesn't exist +exports.testStatus404 = function (test) { + var srv = startServerAsync(port, basePath); + + test.waitUntilDone(); + Request({ + // the following URL doesn't exist + url: "http://localhost:" + port + "/test-request-404.txt", + onComplete: function (response) { + test.assertEqual(response.status, 404); + test.assertEqual(response.statusText, "Not Found"); + srv.stop(function() test.done()); + } + }).get(); +} + +/* +// a simple file with a known header +exports.testKnownHeader = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/headers.php", + onComplete: function (response) { + test.assertEqual(response.headers["x-zpao-header"], "Jamba Juice"); + test.done(); + } + }).get(); +} + +// complex headers +exports.testKnownHeader = function (test) { + let headers = { + "x-zpao-header": "Jamba Juice is: delicious", + "x-zpao-header-2": "foo, bar", + "Set-Cookie": "foo=bar\nbaz=foo" + } + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/complex_headers.php", + onComplete: function (response) { + for (k in headers) { + test.assertEqual(response.headers[k], headers[k]); + } + test.done(); + } + }).get(); +} +*/ + +exports.testSimpleJSON = function (test) { + let srv = startServerAsync(port, basePath); + let json = { foo: "bar" }; + let basename = "test-request.json"; + prepareFile(basename, JSON.stringify(json)); + + test.waitUntilDone(); + Request({ + url: "http://localhost:" + port + "/" + basename, + onComplete: function (response) { + assertDeepEqual(test, response.json, json); + srv.stop(function() test.done()); + } + }).get(); +} + +exports.testInvalidJSON = function (test) { + let srv = startServerAsync(port, basePath); + let basename = "test-request-invalid.json"; + prepareFile(basename, '"this": "isn\'t JSON"'); + + test.waitUntilDone(); + Request({ + url: "http://localhost:" + port + "/" + basename, + onComplete: function (response) { + test.assertEqual(response.json, null); + srv.stop(function() test.done()); + } + }).get(); +} + +/* +exports.testGetWithParamsNotContent = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar", + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : { foo: "bar" } + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} + +exports.testGetWithContent = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php", + content: { foo: "bar" }, + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : { foo: "bar" } + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} + +exports.testGetWithParamsAndContent = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar", + content: { baz: "foo" }, + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : { foo: "bar", baz: "foo" } + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} + +exports.testSimplePost = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php", + content: { foo: "bar" }, + onComplete: function (response) { + let expected = { + "POST": { foo: "bar" }, + "GET" : [] + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).post(); +} + +exports.testEncodedContent = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php", + content: "foo=bar&baz=foo", + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : { foo: "bar", baz: "foo" } + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} + +exports.testEncodedContentWithSpaces = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php", + content: "foo=bar+hop!&baz=foo", + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : { foo: "bar hop!", baz: "foo" } + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} + +exports.testGetWithArray = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php", + content: { foo: [1, 2], baz: "foo" }, + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : { foo: [1, 2], baz: "foo" } + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} + +exports.testGetWithNestedArray = function (test) { + test.waitUntilDone(); + Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php", + content: { foo: [1, 2, [3, 4]], bar: "baz" }, + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : this.content + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} + +exports.testGetWithNestedArray = function (test) { + test.waitUntilDone(); + let request = Request({ + url: "http://playground.zpao.com/jetpack/request/getpost.php", + content: { + foo: [1, 2, { + omg: "bbq", + "all your base!": "are belong to us" + }], + bar: "baz" + }, + onComplete: function (response) { + let expected = { + "POST": [], + "GET" : request.content + }; + assertDeepEqual(test, response.json, expected); + test.done(); + } + }).get(); +} +*/ + +// This is not a proper testing for deep equal, but it's good enough for my uses +// here. It will do type coercion to check equality, but that's good here. Data +// coming from the server will be stringified and so "0" should be equal to 0. +function assertDeepEqual(test, obj1, obj2, msg) { + function equal(o1, o2) { + // cover our non-object cases well enough + if (o1 == o2) + return true; + if (typeof(o1) != typeof(o2)) + return false; + if (typeof(o1) != "object") + return o1 == o2; + + let e = true; + for (let [key, val] in Iterator(o1)) { + e = e && key in o2 && equal(o2[key], val); + if (!e) + break; + } + for (let [key, val] in Iterator(o2)) { + e = e && key in o1 && equal(o1[key], val); + if (!e) + break; + } + return e; + } + msg = msg || "objects not equal - " + JSON.stringify(obj1) + " != " + + JSON.stringify(obj2); + test.assert(equal(obj1, obj2), msg); +} + +function prepareFile(basename, content) { + let filePath = file.join(basePath, basename); + let fileStream = file.open(filePath, 'w'); + fileStream.write(content); + fileStream.close(); +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-selection.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-selection.js new file mode 100644 index 0000000..06feb7e --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-selection.js @@ -0,0 +1,458 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +let timer = require("timer"); +let {Cc,Ci} = require("chrome"); + +// Arbitrary delay needed to avoid weird behavior. +// TODO: We need to find all uses of this and replace them +// with more deterministic solutions. +const ARB_DELAY = 100; + +// Select all divs elements in an HTML document +function selectAllDivs(window) { + let divs = window.document.getElementsByTagName("div"); + let s = window.getSelection(); + if (s.rangeCount > 0) + s.removeAllRanges(); + for (let i = 0; i < divs.length; i++) { + let range = window.document.createRange(); + range.selectNode(divs[i]); + s.addRange(range); + } +} + +function selectTextarea(window, from, to) { + let textarea = window.document.getElementsByTagName("textarea")[0]; + + from = from || 0; + to = to || textarea.value.length; + + textarea.setSelectionRange(from, to); + textarea.focus(); +} + +function primeTestCase(html, test, callback) { + let tabBrowser = require("tab-browser"); + let dataURL = "data:text/html," + encodeURI(html); + let tracker = tabBrowser.whenContentLoaded( + function(window) { + if (window.document.location.href != dataURL) + return; + callback(window, test); + timer.setTimeout(function() { + tracker.unload(); + test.done(); + window.close(); + }, + ARB_DELAY); + } + ); + tabBrowser.addTab(dataURL); +} + +const DIV1 = '
bar
'; +const DIV2 = '
noodles
'; +const HTML_MULTIPLE = '' + DIV1 + DIV2 + ''; +const HTML_SINGLE = '' + DIV1 + ''; + +// Tests of contiguous + +exports.testContiguousMultiple = function testContiguousMultiple(test) { + let selection = require("selection"); + primeTestCase(HTML_MULTIPLE, test, function(window, test) { + selectAllDivs(window); + test.assertEqual(selection.isContiguous, false, + "selection.isContiguous multiple works."); + }); + + test.waitUntilDone(5000); +}; + +exports.testContiguousSingle = function testContiguousSingle(test) { + let selection = require("selection"); + primeTestCase(HTML_SINGLE, test, function(window, test) { + selectAllDivs(window); + test.assertEqual(selection.isContiguous, true, + "selection.isContiguous single works."); + }); + + test.waitUntilDone(5000); +}; + +exports.testContiguousWithoutSelection = + function testContiguousWithoutSelection(test) { + let selection = require("selection"); + primeTestCase(HTML_SINGLE, test, function(window, test) { + test.assertEqual(selection.isContiguous, false, + "selection.isContiguous without selection works."); + }); + + test.waitUntilDone(5000); +}; + +/** + * Test that setting the contiguous property has no effect. + */ +/*exports.testSetContiguous = function testSetContiguous(test) { + let selection = require("selection"); + primeTestCase(HTML_MULTIPLE, test, function(window, test) { + selectAllDivs(window); + try { + selection.isContiguous = true; + test.assertEqual(selection.isContiguous, false, + "setting selection.isContiguous doesn't work (as expected)."); + } + catch (e) { + test.pass("setting selection.isContiguous doesn't work (as expected)."); + } + }); + + test.waitUntilDone(5000); +};*/ + + +// HTML tests + +exports.testGetHTMLSingleSelection = function testGetHTMLSingleSelection(test) { + let selection = require("selection"); + primeTestCase(HTML_SINGLE, test, function(window, test) { + selectAllDivs(window); + test.assertEqual(selection.html, DIV1, "get html selection works"); + }); + + test.waitUntilDone(5000); +}; + +/* Myk's comments: This is fine. However, it reminds me to figure out and + specify whether iteration is ordered. If so, we'll want to change this + test in the future to test that the discontiguous selections are returned in + the appropriate order. In the meantime, add a comment to that effect here */ +exports.testGetHTMLMultipleSelection = + function testGetHTMLMultipleSelection(test) { + let selection = require("selection"); + primeTestCase(HTML_MULTIPLE, test, function(window, test) { + selectAllDivs(window); + let assertions = false; + for each (let i in selection) { + test.assertEqual(true, [DIV1, DIV2].some(function(t) t == i.html), + "get multiple selection html works"); + assertions = true; + } + // Ensure we ran at least one assertEqual() + test.assert(assertions, "No assertions were called"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetHTMLNull = function testGetHTMLNull(test) { + let selection = require("selection"); + primeTestCase(HTML_SINGLE, test, function(window, test) { + test.assertEqual(selection.html, null, "get html null works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetHTMLWeird = function testGetHTMLWeird(test) { + let selection = require("selection"); + // If the getter is used when there are contiguous selections, the first + // selection should be returned + primeTestCase(HTML_MULTIPLE, test, function(window, test) { + selectAllDivs(window); + test.assertEqual(selection.html, DIV1, "get html weird works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetHTMLNullInTextareaSelection = + function testGetHTMLNullInTextareaSelection(test) { + let selection = require("selection"); + + primeTestCase(TEXT_FIELD, test, function(window, test) { + selectTextarea(window); + + test.assertEqual(selection.html, null, "get html null in textarea works") + }); + + test.waitUntilDone(5000); +}; + +const REPLACEMENT_HTML = "Lorem ipsum dolor sit amet"; + +exports.testSetHTMLSelection = function testSetHTMLSelection(test) { + let selection = require("selection"); + primeTestCase(HTML_SINGLE, test, function(window, test) { + selectAllDivs(window); + selection.html = REPLACEMENT_HTML; + test.assertEqual(selection.html, "" + REPLACEMENT_HTML + + "", "selection html works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testSetHTMLException = function testSetHTMLException(test) { + let selection = require("selection"); + primeTestCase(HTML_SINGLE, test, function(window, test) { + try { + selection.html = REPLACEMENT_HTML; + test.fail("set HTML throws when there's no selection."); + } + catch (e) { + test.pass("set HTML throws when there's no selection."); + } + }); + + test.waitUntilDone(5000); +}; + +const TEXT1 = "foo"; +const TEXT2 = "noodles"; +const TEXT_MULTIPLE = "
" + TEXT1 + "
" + TEXT2 + + "
"; +const TEXT_SINGLE = "
" + TEXT1 + "
"; +const TEXT_FIELD = ""; + +// Text tests + +exports.testSetHTMLinTextareaSelection = + function testSetHTMLinTextareaSelection(test) { + let selection = require("selection"); + + primeTestCase(TEXT_FIELD, test, function(window, test) { + selectTextarea(window); + + // HTML string is set as plain text in textareas, that's because + // `selection.html` and `selection.text` are basically aliases when a + // value is set. See bug 677269 + selection.html = REPLACEMENT_HTML; + + test.assertEqual(selection.text, REPLACEMENT_HTML, + "set selection html in textarea works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetTextSingleSelection = + function testGetTextSingleSelection(test) { + let selection = require("selection"); + primeTestCase(TEXT_SINGLE, test, function(window, test) { + selectAllDivs(window); + test.assertEqual(selection.text, TEXT1, "get text selection works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetTextMultipleSelection = + function testGetTextMultipleSelection(test) { + let selection = require("selection"); + primeTestCase(TEXT_MULTIPLE, test, function(window, test) { + selectAllDivs(window); + let assertions = false; + for each (let i in selection) { + test.assertEqual(true, [TEXT1, TEXT2].some(function(t) t == i.text), + "get multiple selection text works"); + assertions = true; + } + // Ensure we ran at least one assertEqual() + test.assert(assertions, "No assertions were called"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetTextNull = function testGetTextNull(test) { + let selection = require("selection"); + primeTestCase(TEXT_SINGLE, test, function(window, test) { + test.assertEqual(selection.text, null, "get text null works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetTextWeird = function testGetTextWeird(test) { + let selection = require("selection"); + // If the getter is used when there are contiguous selections, the first + // selection should be returned + primeTestCase(TEXT_MULTIPLE, test, function(window, test) { + selectAllDivs(window); + test.assertEqual(selection.text, TEXT1, "get text weird works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testGetTextNullInTextareaSelection = + function testGetTextInTextareaSelection(test) { + let selection = require("selection"); + + primeTestCase(TEXT_FIELD, test, function(window, test) { + test.assertEqual(selection.text, null, "get text null in textarea works") + }); + + test.waitUntilDone(5000); +}; + +exports.testGetTextInTextareaSelection = + function testGetTextInTextareaSelection(test) { + let selection = require("selection"); + + primeTestCase(TEXT_FIELD, test, function(window, test) { + selectTextarea(window); + + test.assertEqual(selection.text, TEXT1, "get text null in textarea works") + }); + + test.waitUntilDone(5000); +}; + +const REPLACEMENT_TEXT = "Lorem ipsum dolor sit amet"; + +exports.testSetTextSelection = function testSetTextSelection(test) { + let selection = require("selection"); + primeTestCase(TEXT_SINGLE, test, function(window, test) { + selectAllDivs(window); + selection.text = REPLACEMENT_TEXT; + test.assertEqual(selection.text, REPLACEMENT_TEXT, "selection text works"); + }); + + test.waitUntilDone(5000); +}; + +exports.testSetHTMLException = function testSetHTMLException(test) { + let selection = require("selection"); + primeTestCase(TEXT_SINGLE, test, function(window, test) { + try { + selection.text = REPLACEMENT_TEXT; + test.fail("set HTML throws when there's no selection."); + } + catch (e) { + test.pass("set HTML throws when there's no selection."); + } + }); + + test.waitUntilDone(5000); +}; + +exports.testSetTextInTextareaSelection = + function testSetTextInTextareaSelection(test) { + let selection = require("selection"); + + primeTestCase(TEXT_FIELD, test, function(window, test) { + selectTextarea(window); + + selection.text = REPLACEMENT_TEXT; + + test.assertEqual(selection.text, REPLACEMENT_TEXT, + "set selection text in textarea works"); + }); + + test.waitUntilDone(5000); +}; + +// Iterator tests + +exports.testIterator = function testIterator(test) { + let selection = require("selection"); + let selectionCount = 0; + primeTestCase(TEXT_MULTIPLE, test, function(window, test) { + selectAllDivs(window); + for each (let i in selection) + selectionCount++; + test.assertEqual(2, selectionCount, "iterator works."); + }); + + test.waitUntilDone(5000); +}; + +exports.testIteratorWithTextareaSelection = + function testIteratorWithTextareaSelection(test) { + let selection = require("selection"); + let selectionCount = 0; + + primeTestCase(TEXT_FIELD, test, function(window, test) { + selectTextarea(window); + + for each (let i in selection) + selectionCount++; + + test.assertEqual(1, selectionCount, "iterator works in textarea."); + }); + + test.waitUntilDone(5000); +}; + +/* onSelect tests */ + +/* +function sendSelectionSetEvent(window) { + const Ci = Components.interfaces; + let utils = window.QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIDOMWindowUtils); + if (!utils.sendSelectionSetEvent(0, 1, false)) + dump("**** sendSelectionSetEvent did not select anything\n"); + else + dump("**** sendSelectionSetEvent succeeded\n"); +} + +// testOnSelect() requires nsIDOMWindowUtils, which is only available in +// Firefox 3.7+. +exports.testOnSelect = function testOnSelect(test) { + let selection = require("selection"); + let callbackCount = 0; + primeTestCase(TEXT_SINGLE, test, function(window, test) { + selection.onSelect = function() {callbackCount++}; + // Now simulate the user selecting stuff + sendSelectionSetEvent(window); + selection.text = REPLACEMENT_TEXT; + test.assertEqual(1, callbackCount, "onSelect text listener works."); + //test.pass(); + //test.done(); + }); + + test.waitUntilDone(5000); +}; + +// testOnSelectExceptionNoBubble() requires nsIDOMWindowUtils, which is only +// available in Firefox 3.7+. +exports.testOnSelectExceptionNoBubble = + function testOnSelectTextSelection(test) { + let selection = require("selection"); + primeTestCase(HTML_SINGLE, test, function(window, test) { + selection.onSelect = function() { + throw new Error("Exception thrown in testOnSelectExceptionNoBubble"); + }; + // Now simulate the user selecting stuff + sendSelectionSetEvent(window); + test.pass("onSelect catches exceptions."); + }); + + test.waitUntilDone(5000); +}; +*/ + +// If the module doesn't support the app we're being run in, require() will +// throw. In that case, remove all tests above from exports, and add one dummy +// test that passes. +try { + require("selection"); +} +catch (err) { + // This bug should be mentioned in the error message. + let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=560716"; + if (err.message.indexOf(bug) < 0) + throw err; + for (let [prop, val] in Iterator(exports)) { + if (/^test/.test(prop) && typeof(val) === "function") + delete exports[prop]; + } + exports.testAppNotSupported = function (test) { + test.pass("The selection module does not support this application."); + }; +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-prefs.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-prefs.js new file mode 100644 index 0000000..7452a8a --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-prefs.js @@ -0,0 +1,175 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +const { Loader } = require("./helpers"); +const { setTimeout } = require("timers"); +const { notify } = require("observer-service"); +const { jetpackID } = require("@packaging"); + +exports.testSetGetBool = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs").prefs; + + test.assertEqual(sp.test, undefined, "Value should not exist"); + sp.test = true; + test.assert(sp.test, "Value read should be the value previously set"); + + loader.unload(); + test.done(); +}; + +exports.testSetGetInt = function(test) { + test.waitUntilDone(); + + // Load the module once, set a value. + let loader = Loader(module); + let sp = loader.require("simple-prefs").prefs; + + test.assertEqual(sp["test-int"], undefined, "Value should not exist"); + sp["test-int"] = 1; + test.assertEqual(sp["test-int"], 1, "Value read should be the value previously set"); + + loader.unload(); + test.done(); +}; + +exports.testSetComplex = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs").prefs; + + try { + sp["test-complex"] = {test: true}; + test.fail("Complex values are not allowed"); + } + catch (e) { + test.pass("Complex values are not allowed"); + } + + loader.unload(); + test.done(); +}; + +exports.testSetGetString = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs").prefs; + + test.assertEqual(sp["test-string"], undefined, "Value should not exist"); + sp["test-string"] = "test"; + test.assertEqual(sp["test-string"], "test", "Value read should be the value previously set"); + + loader.unload(); + test.done(); +}; + +exports.testHasAndRemove = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs").prefs; + + sp.test = true; + test.assert(("test" in sp), "Value exists"); + delete sp.test; + test.assertEqual(sp.test, undefined, "Value should be undefined"); + + loader.unload(); + test.done(); + +}; + +exports.testPrefListener = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs"); + + let listener = function(prefName) { + test.assertEqual(prefName, "test-listen", "The prefs listener heard the right event"); + test.done(); + }; + + sp.on("test-listen", listener); + + sp.prefs["test-listen"] = true; + loader.unload(); +}; + +exports.testBtnListener = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs"); + + sp.on("test-btn-listen", function() { + test.pass("Button press event was heard"); + test.done(); + }); + notify((jetpackID + "-cmdPressed"), "", "test-btn-listen"); + + loader.unload(); +}; + +exports.testPrefRemoveListener = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs"); + let counter = 0; + + let listener = function() { + test.pass("The prefs listener was not removed yet"); + + if (++counter > 1) + test.fail("The prefs listener was not removed"); + + sp.removeListener("test-listen2", listener); + + sp.prefs["test-listen2"] = false; + + setTimeout(function() { + test.pass("The prefs listener was removed"); + loader.unload(); + test.done(); + }, 250); + }; + + sp.on("test-listen2", listener); + + // emit change + sp.prefs["test-listen2"] = true; +}; + +// Bug 710117: Test that simple-pref listeners are removed on unload +exports.testPrefUnloadListener = function(test) { + test.waitUntilDone(); + + let loader = Loader(module); + let sp = loader.require("simple-prefs"); + let counter = 0; + + let listener = function() { + test.assertEqual(++counter, 1, "This listener should only be called once"); + + loader.unload(); + + // this may not execute after unload, but definitely shouldn't fire listener + sp.prefs["test-listen3"] = false; + // this should execute, but also definitely shouldn't fire listener + require("simple-prefs").prefs["test-listen3"] = false; // + + test.done(); + }; + + sp.on("test-listen3", listener); + + // emit change + sp.prefs["test-listen3"] = true; +}; diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-storage.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-storage.js new file mode 100644 index 0000000..25d0770 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-simple-storage.js @@ -0,0 +1,311 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:set ts=2 sw=2 sts=2 et filetype=javascript + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const file = require("file"); +const prefs = require("preferences-service"); + +const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota"; + +let {Cc,Ci} = require("chrome"); + +const { Loader } = require("./helpers"); +const options = require("@packaging"); + +let storeFile = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties). + get("ProfD", Ci.nsIFile); +storeFile.append("jetpack"); +storeFile.append(options.jetpackID); +storeFile.append("simple-storage"); +storeFile.append("store.json"); +let storeFilename = storeFile.path; + +function manager(loader) loader.sandbox("simple-storage").manager; + +exports.testSetGet = function (test) { + test.waitUntilDone(); + + // Load the module once, set a value. + let loader = Loader(module); + let ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function (storage) { + test.assert(file.exists(storeFilename), "Store file should exist"); + + // Load the module again and make sure the value stuck. + loader = Loader(module); + ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function (storage) { + file.remove(storeFilename); + test.done(); + }; + test.assertEqual(ss.storage.foo, val, "Value should persist"); + loader.unload(); + }; + let val = "foo"; + ss.storage.foo = val; + test.assertEqual(ss.storage.foo, val, "Value read should be value set"); + loader.unload(); +}; + +exports.testSetGetRootArray = function (test) { + setGetRoot(test, [1, 2, 3], function (arr1, arr2) { + if (arr1.length !== arr2.length) + return false; + for (let i = 0; i < arr1.length; i++) { + if (arr1[i] !== arr2[i]) + return false; + } + return true; + }); +}; + +exports.testSetGetRootBool = function (test) { + setGetRoot(test, true); +}; + +exports.testSetGetRootFunction = function (test) { + setGetRootError(test, function () {}, + "Setting storage to a function should fail"); +}; + +exports.testSetGetRootNull = function (test) { + setGetRoot(test, null); +}; + +exports.testSetGetRootNumber = function (test) { + setGetRoot(test, 3.14); +}; + +exports.testSetGetRootObject = function (test) { + setGetRoot(test, { foo: 1, bar: 2 }, function (obj1, obj2) { + for (let [prop, val] in Iterator(obj1)) { + if (!(prop in obj2) || obj2[prop] !== val) + return false; + } + for (let [prop, val] in Iterator(obj2)) { + if (!(prop in obj1) || obj1[prop] !== val) + return false; + } + return true; + }); +}; + +exports.testSetGetRootString = function (test) { + setGetRoot(test, "sho' 'nuff"); +}; + +exports.testSetGetRootUndefined = function (test) { + setGetRootError(test, undefined, "Setting storage to undefined should fail"); +}; + +exports.testEmpty = function (test) { + let loader = Loader(module); + let ss = loader.require("simple-storage"); + loader.unload(); + test.assert(!file.exists(storeFilename), "Store file should not exist"); +}; + +exports.testMalformed = function (test) { + let stream = file.open(storeFilename, "w"); + stream.write("i'm not json"); + stream.close(); + let loader = Loader(module); + let ss = loader.require("simple-storage"); + let empty = true; + for (let key in ss.storage) { + empty = false; + break; + } + test.assert(empty, "Malformed storage should cause root to be empty"); + loader.unload(); +}; + +// Go over quota and handle it by listener. +exports.testQuotaExceededHandle = function (test) { + test.waitUntilDone(); + prefs.set(QUOTA_PREF, 18); + + let loader = Loader(module); + let ss = loader.require("simple-storage"); + ss.on("OverQuota", function () { + test.pass("OverQuota was emitted as expected"); + test.assertEqual(this, ss, "`this` should be simple storage"); + ss.storage = { x: 4, y: 5 }; + + manager(loader).jsonStore.onWrite = function () { + loader = Loader(module); + ss = loader.require("simple-storage"); + let numProps = 0; + for (let prop in ss.storage) + numProps++; + test.assert(numProps, 2, + "Store should contain 2 values: " + ss.storage.toSource()); + test.assertEqual(ss.storage.x, 4, "x value should be correct"); + test.assertEqual(ss.storage.y, 5, "y value should be correct"); + manager(loader).jsonStore.onWrite = function (storage) { + prefs.reset(QUOTA_PREF); + test.done(); + }; + loader.unload(); + }; + loader.unload(); + }); + // This will be JSON.stringify()ed to: {"a":1,"b":2,"c":3} (19 bytes) + ss.storage = { a: 1, b: 2, c: 3 }; + manager(loader).jsonStore.write(); +}; + +// Go over quota but don't handle it. The last good state should still persist. +exports.testQuotaExceededNoHandle = function (test) { + test.waitUntilDone(); + prefs.set(QUOTA_PREF, 5); + + let loader = Loader(module); + let ss = loader.require("simple-storage"); + + manager(loader).jsonStore.onWrite = function (storage) { + loader = Loader(module); + ss = loader.require("simple-storage"); + test.assertEqual(ss.storage, val, + "Value should have persisted: " + ss.storage); + ss.storage = "some very long string that is very long"; + ss.on("OverQuota", function () { + test.pass("OverQuota emitted as expected"); + manager(loader).jsonStore.onWrite = function () { + test.fail("Over-quota value should not have been written"); + }; + loader.unload(); + + loader = Loader(module); + ss = loader.require("simple-storage"); + test.assertEqual(ss.storage, val, + "Over-quota value should not have been written, " + + "old value should have persisted: " + ss.storage); + loader.unload(); + prefs.reset(QUOTA_PREF); + test.done(); + }); + manager(loader).jsonStore.write(); + }; + + let val = "foo"; + ss.storage = val; + loader.unload(); +}; + +exports.testQuotaUsage = function (test) { + test.waitUntilDone(); + + let quota = 21; + prefs.set(QUOTA_PREF, quota); + + let loader = Loader(module); + let ss = loader.require("simple-storage"); + + // {"a":1} (7 bytes) + ss.storage = { a: 1 }; + test.assertEqual(ss.quotaUsage, 7 / quota, "quotaUsage should be correct"); + + // {"a":1,"bb":2} (14 bytes) + ss.storage = { a: 1, bb: 2 }; + test.assertEqual(ss.quotaUsage, 14 / quota, "quotaUsage should be correct"); + + // {"a":1,"bb":2,"cc":3} (21 bytes) + ss.storage = { a: 1, bb: 2, cc: 3 }; + test.assertEqual(ss.quotaUsage, 21 / quota, "quotaUsage should be correct"); + + manager(loader).jsonStore.onWrite = function () { + prefs.reset(QUOTA_PREF); + test.done(); + }; + loader.unload(); +}; + +exports.testUninstall = function (test) { + test.waitUntilDone(); + let loader = Loader(module); + let ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function () { + test.assert(file.exists(storeFilename), "Store file should exist"); + + loader = Loader(module); + ss = loader.require("simple-storage"); + loader.unload("uninstall"); + test.assert(!file.exists(storeFilename), "Store file should be removed"); + test.done(); + }; + ss.storage.foo = "foo"; + loader.unload(); +}; + +exports.testSetNoSetRead = function (test) { + test.waitUntilDone(); + + // Load the module, set a value. + let loader = Loader(module); + let ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function (storage) { + test.assert(file.exists(storeFilename), "Store file should exist"); + + // Load the module again but don't access ss.storage. + loader = Loader(module); + ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function (storage) { + test.fail("Nothing should be written since `storage` was not accessed."); + }; + loader.unload(); + + // Load the module a third time and make sure the value stuck. + loader = Loader(module); + ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function (storage) { + file.remove(storeFilename); + test.done(); + }; + test.assertEqual(ss.storage.foo, val, "Value should persist"); + loader.unload(); + }; + let val = "foo"; + ss.storage.foo = val; + test.assertEqual(ss.storage.foo, val, "Value read should be value set"); + loader.unload(); +}; + + +function setGetRoot(test, val, compare) { + test.waitUntilDone(); + + compare = compare || function (a, b) a === b; + + // Load the module once, set a value. + let loader = Loader(module); + let ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function () { + test.assert(file.exists(storeFilename), "Store file should exist"); + + // Load the module again and make sure the value stuck. + loader = Loader(module); + ss = loader.require("simple-storage"); + manager(loader).jsonStore.onWrite = function () { + file.remove(storeFilename); + test.done(); + }; + test.assert(compare(ss.storage, val), "Value should persist"); + loader.unload(); + }; + ss.storage = val; + test.assert(compare(ss.storage, val), "Value read should be value set"); + loader.unload(); +} + +function setGetRootError(test, val, msg) { + let pred = "storage must be one of the following types: " + + "array, boolean, null, number, object, string"; + let loader = Loader(module); + let ss = loader.require("simple-storage"); + test.assertRaises(function () ss.storage = val, pred, msg); + loader.unload(); +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-tabs.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-tabs.js new file mode 100644 index 0000000..5719ab4 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-tabs.js @@ -0,0 +1,900 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If 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 {Cc,Ci} = require("chrome"); +const { Loader } = require("./helpers"); + +// test tab.activeTab getter +exports.testActiveTab_getter = function(test) { + test.waitUntilDone(); + + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + + let url = "data:text/html,foo"; + require("tab-browser").addTab( + url, + { + onLoad: function(e) { + test.assert(tabs.activeTab); + test.assertEqual(tabs.activeTab.url, url); + test.assertEqual(tabs.activeTab.title, "foo"); + closeBrowserWindow(window, function() test.done()); + } + } + ); + }); +}; + +// test 'BrowserWindow' instance creation on tab 'activate' event +// See bug 648244: there was a infinite loop. +exports.testBrowserWindowCreationOnActivate = function(test) { + test.waitUntilDone(); + + let windows = require("windows").browserWindows; + let tabs = require("tabs"); + + let gotActivate = false; + + tabs.once('activate', function onActivate(eventTab) { + test.assert(windows.activeWindow, "Is able to fetch activeWindow"); + gotActivate = true; + }); + + openBrowserWindow(function(window, browser) { + test.assert(gotActivate, "Received activate event before openBrowserWindow's callback is called"); + closeBrowserWindow(window, function () test.done()); + }); +} + +// test tab.activeTab setter +exports.testActiveTab_setter = function(test) { + test.waitUntilDone(); + + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url = "data:text/html,foo"; + + tabs.on('ready', function onReady(tab) { + tabs.removeListener('ready', onReady); + test.assertEqual(tabs.activeTab.url, "about:blank", "activeTab url has not changed"); + test.assertEqual(tab.url, url, "url of new background tab matches"); + tabs.on('activate', function onActivate(eventTab) { + tabs.removeListener('activate', onActivate); + test.assertEqual(tabs.activeTab.url, url, "url after activeTab setter matches"); + test.assertEqual(eventTab, tab, "event argument is the activated tab"); + test.assertEqual(eventTab, tabs.activeTab, "the tab is the active one"); + closeBrowserWindow(window, function() test.done()); + }); + tab.activate(); + }) + + tabs.open({ + url: url, + inBackground: true + }); + }); +}; + +exports.testAutomaticDestroy = function(test) { + test.waitUntilDone(); + + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + + // Create a second tab instance that we will destroy + let called = false; + + let loader = Loader(module); + let tabs2 = loader.require("tabs"); + tabs2.on('open', function onOpen(tab) { + called = true; + }); + + loader.unload(); + + // Fire a tab event an ensure that this destroyed tab is inactive + tabs.once('open', function () { + require("timer").setTimeout(function () { + test.assert(!called, "Unloaded tab module is destroyed and inactive"); + closeBrowserWindow(window, function() test.done()); + }, 0); + }); + + tabs.open("data:text/html,foo"); + + }); +}; + +// test tab properties +exports.testTabProperties = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs= require("tabs"); + let url = "data:text/html,foofoo"; + tabs.open({ + url: url, + onReady: function(tab) { + test.assertEqual(tab.title, "foo", "title of the new tab matches"); + test.assertEqual(tab.url, url, "URL of the new tab matches"); + test.assert(tab.favicon, "favicon of the new tab is not empty"); + test.assertEqual(tab.style, null, "style of the new tab matches"); + test.assertEqual(tab.index, 1, "index of the new tab matches"); + test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches"); + closeBrowserWindow(window, function() test.done()); + } + }); + }); +}; + +// test tabs iterator and length property +exports.testTabsIteratorAndLength = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let startCount = 0; + for each (let t in tabs) startCount++; + test.assertEqual(startCount, tabs.length, "length property is correct"); + let url = "data:text/html,default"; + tabs.open(url); + tabs.open(url); + tabs.open({ + url: url, + onOpen: function(tab) { + let count = 0; + for each (let t in tabs) count++; + test.assertEqual(count, startCount + 3, "iterated tab count matches"); + test.assertEqual(startCount + 3, tabs.length, "iterated tab count matches length property"); + closeBrowserWindow(window, function() test.done()); + } + }); + }); +}; + +// test tab.url setter +exports.testTabLocation = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url1 = "data:text/html,foo"; + let url2 = "data:text/html,bar"; + + tabs.on('ready', function onReady(tab) { + if (tab.url != url2) + return; + tabs.removeListener('ready', onReady); + test.pass("tab.load() loaded the correct url"); + closeBrowserWindow(window, function() test.done()); + }); + + tabs.open({ + url: url1, + onOpen: function(tab) { + tab.url = url2 + } + }); + }); +}; + +// test tab.close() +exports.testTabClose = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url = "data:text/html,foo"; + + test.assertNotEqual(tabs.activeTab.url, url, "tab is now the active tab"); + tabs.on('ready', function onReady(tab) { + tabs.removeListener('ready', onReady); + test.assertEqual(tabs.activeTab.url, tab.url, "tab is now the active tab"); + tab.close(function() { + closeBrowserWindow(window, function() test.done()); + }); + test.assertNotEqual(tabs.activeTab.url, url, "tab is no longer the active tab"); + }); + + tabs.open(url); + }); +}; + +// test tab.reload() +exports.testTabReload = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url = "data:text/html,"; + + tabs.open({ url: url, onReady: function onReady(tab) { + tab.removeListener("ready", onReady); + + browser.addEventListener( + "load", + function onLoad() { + browser.removeEventListener("load", onLoad, true); + + browser.addEventListener( + "load", + function onReload() { + browser.removeEventListener("load", onReload, true); + test.pass("the tab was loaded again"); + test.assertEqual(tab.url, url, "the tab has the same URL"); + closeBrowserWindow(window, function() test.done()); + }, + true + ); + tab.reload(); + }, + true + ); + }}); + }); +}; + +// test tab.move() +exports.testTabMove = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url = "data:text/html,foo"; + + tabs.open({ + url: url, + onOpen: function(tab) { + test.assertEqual(tab.index, 1, "tab index before move matches"); + tab.index = 0; + test.assertEqual(tab.index, 0, "tab index after move matches"); + closeBrowserWindow(window, function() test.done()); + } + }); + }); +}; + +// open tab with default options +exports.testOpen = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url = "data:text/html,default"; + tabs.open({ + url: url, + onReady: function(tab) { + test.assertEqual(tab.url, url, "URL of the new tab matches"); + test.assertEqual(window.content.location, url, "URL of active tab in the current window matches"); + closeBrowserWindow(window, function() test.done()); + } + }); + }); +}; + +// open pinned tab +exports.testOpenPinned = function(test) { + const xulApp = require("xul-app"); + if (xulApp.versionInRange(xulApp.platformVersion, "2.0b2", "*")) { + // test tab pinning + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url = "data:text/html,default"; + tabs.open({ + url: url, + isPinned: true, + onOpen: function(tab) { + test.assertEqual(tab.isPinned, true, "The new tab is pinned"); + closeBrowserWindow(window, function() test.done()); + } + }); + }); + } + else { + test.pass("Pinned tabs are not supported in this application."); + } +}; + +// pin/unpin opened tab +exports.testPinUnpin = function(test) { + const xulApp = require("xul-app"); + if (xulApp.versionInRange(xulApp.platformVersion, "2.0b2", "*")) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let url = "data:text/html,default"; + tabs.open({ + url: url, + onOpen: function(tab) { + tab.pin(); + test.assertEqual(tab.isPinned, true, "The tab was pinned correctly"); + tab.unpin(); + test.assertEqual(tab.isPinned, false, "The tab was unpinned correctly"); + closeBrowserWindow(window, function() test.done()); + } + }); + }); + } + else { + test.pass("Pinned tabs are not supported in this application."); + } +}; + +// open tab in background +exports.testInBackground = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let activeUrl = tabs.activeTab.url; + let url = "data:text/html,background"; + test.assertEqual(activeWindow, window, "activeWindow matches this window"); + tabs.on('ready', function onReady(tab) { + tabs.removeListener('ready', onReady); + test.assertEqual(tabs.activeTab.url, activeUrl, "URL of active tab has not changed"); + test.assertEqual(tab.url, url, "URL of the new background tab matches"); + test.assertEqual(activeWindow, window, "a new window was not opened"); + test.assertNotEqual(tabs.activeTab.url, url, "URL of active tab is not the new URL"); + closeBrowserWindow(window, function() test.done()); + }); + tabs.open({ + url: url, + inBackground: true + }); + }); +}; + +// open tab in new window +exports.testOpenInNewWindow = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + + let cache = []; + let windowUtils = require("window-utils"); + let wt = new windowUtils.WindowTracker({ + onTrack: function(win) { + cache.push(win); + }, + onUntrack: function(win) { + cache.splice(cache.indexOf(win), 1) + } + }); + let startWindowCount = cache.length; + + let url = "data:text/html,newwindow"; + tabs.open({ + url: url, + inNewWindow: true, + onReady: function(tab) { + let newWindow = cache[cache.length - 1]; + test.assertEqual(cache.length, startWindowCount + 1, "a new window was opened"); + test.assertEqual(activeWindow, newWindow, "new window is active"); + test.assertEqual(tab.url, url, "URL of the new tab matches"); + test.assertEqual(newWindow.content.location, url, "URL of new tab in new window matches"); + test.assertEqual(tabs.activeTab.url, url, "URL of activeTab matches"); + for (var i in cache) cache[i] = null; + wt.unload(); + closeBrowserWindow(newWindow, function() { + closeBrowserWindow(window, function() test.done()); + }); + } + }); + }); +}; + +// onOpen event handler +exports.testTabsEvent_onOpen = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + let url = "data:text/html,1"; + let eventCount = 0; + + // add listener via property assignment + function listener1(tab) { + eventCount++; + }; + tabs.on('open', listener1); + + // add listener via collection add + tabs.on('open', function listener2(tab) { + test.assertEqual(++eventCount, 2, "both listeners notified"); + tabs.removeListener('open', listener1); + tabs.removeListener('open', listener2); + closeBrowserWindow(window, function() test.done()); + }); + + tabs.open(url); + }); +}; + +// onClose event handler +exports.testTabsEvent_onClose = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + let url = "data:text/html,onclose"; + let eventCount = 0; + + // add listener via property assignment + function listener1(tab) { + eventCount++; + } + tabs.on('close', listener1); + + // add listener via collection add + tabs.on('close', function listener2(tab) { + test.assertEqual(++eventCount, 2, "both listeners notified"); + tabs.removeListener('close', listener1); + tabs.removeListener('close', listener2); + closeBrowserWindow(window, function() test.done()); + }); + + tabs.on('ready', function onReady(tab) { + tabs.removeListener('ready', onReady); + tab.close(); + }); + + tabs.open(url); + }); +}; + +// onClose event handler when a window is closed +exports.testTabsEvent_onCloseWindow = function(test) { + test.waitUntilDone(); + + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + + let closeCount = 0, individualCloseCount = 0; + function listener() { + closeCount++; + } + tabs.on('close', listener); + + // One tab is already open with the window + let openTabs = 1; + function testCasePossiblyLoaded() { + if (++openTabs == 4) { + beginCloseWindow(); + } + } + + tabs.open({ + url: "data:text/html,tab2", + onOpen: function() testCasePossiblyLoaded(), + onClose: function() individualCloseCount++ + }); + + tabs.open({ + url: "data:text/html,tab3", + onOpen: function() testCasePossiblyLoaded(), + onClose: function() individualCloseCount++ + }); + + tabs.open({ + url: "data:text/html,tab4", + onOpen: function() testCasePossiblyLoaded(), + onClose: function() individualCloseCount++ + }); + + function beginCloseWindow() { + closeBrowserWindow(window, function testFinished() { + tabs.removeListener("close", listener); + + test.assertEqual(closeCount, 4, "Correct number of close events received"); + test.assertEqual(individualCloseCount, 3, + "Each tab with an attached onClose listener received a close " + + "event when the window was closed"); + + test.done(); + }); + } + + }); +} + +// onReady event handler +exports.testTabsEvent_onReady = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + let url = "data:text/html,onready"; + let eventCount = 0; + + // add listener via property assignment + function listener1(tab) { + eventCount++; + }; + tabs.on('ready', listener1); + + // add listener via collection add + tabs.on('ready', function listener2(tab) { + test.assertEqual(++eventCount, 2, "both listeners notified"); + tabs.removeListener('ready', listener1); + tabs.removeListener('ready', listener2); + closeBrowserWindow(window, function() test.done()); + }); + + tabs.open(url); + }); +}; + +// onActivate event handler +exports.testTabsEvent_onActivate = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + let url = "data:text/html,onactivate"; + let eventCount = 0; + + // add listener via property assignment + function listener1(tab) { + eventCount++; + }; + tabs.on('activate', listener1); + + // add listener via collection add + tabs.on('activate', function listener2(tab) { + test.assertEqual(++eventCount, 2, "both listeners notified"); + tabs.removeListener('activate', listener1); + tabs.removeListener('activate', listener2); + closeBrowserWindow(window, function() test.done()); + }); + + tabs.open(url); + }); +}; + +// onDeactivate event handler +exports.testTabsEvent_onDeactivate = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + let url = "data:text/html,ondeactivate"; + let eventCount = 0; + + // add listener via property assignment + function listener1(tab) { + eventCount++; + }; + tabs.on('deactivate', listener1); + + // add listener via collection add + tabs.on('deactivate', function listener2(tab) { + test.assertEqual(++eventCount, 2, "both listeners notified"); + tabs.removeListener('deactivate', listener1); + tabs.removeListener('deactivate', listener2); + closeBrowserWindow(window, function() test.done()); + }); + + tabs.on('open', function onOpen(tab) { + tabs.removeListener('open', onOpen); + tabs.open("data:text/html,foo"); + }); + + tabs.open(url); + }); +}; + +exports.testTabsEvent_pinning = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + let url = "data:text/html,1"; + + tabs.on('open', function onOpen(tab) { + tabs.removeListener('open', onOpen); + tab.pin(); + }); + + tabs.on('pinned', function onPinned(tab) { + tabs.removeListener('pinned', onPinned); + test.assert(tab.isPinned, "notified tab is pinned"); + tab.unpin(); + }); + + tabs.on('unpinned', function onUnpinned(tab) { + tabs.removeListener('unpinned', onUnpinned); + test.assert(!tab.isPinned, "notified tab is not pinned"); + closeBrowserWindow(window, function() test.done()); + }); + + tabs.open(url); + }); +}; + +// per-tab event handlers +exports.testPerTabEvents = function(test) { + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + var tabs = require("tabs"); + let eventCount = 0; + + tabs.open({ + url: "data:text/html,foo", + onOpen: function(tab) { + // add listener via property assignment + function listener1() { + eventCount++; + }; + tab.on('ready', listener1); + + // add listener via collection add + tab.on('ready', function listener2() { + test.assertEqual(eventCount, 1, "both listeners notified"); + tab.removeListener('ready', listener1); + tab.removeListener('ready', listener2); + closeBrowserWindow(window, function() test.done()); + }); + } + }); + }); +}; + +exports.testAttachOnOpen = function (test) { + // Take care that attach has to be called on tab ready and not on tab open. + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + + tabs.open({ + url: "data:text/html,foobar", + onOpen: function (tab) { + let worker = tab.attach({ + contentScript: 'self.postMessage(document.location.href); ', + onMessage: function (msg) { + test.assertEqual(msg, "about:blank", + "Worker document url is about:blank on open"); + worker.destroy(); + closeBrowserWindow(window, function() test.done()); + } + }); + } + }); + + }); +} + +exports.testAttachOnMultipleDocuments = function (test) { + // Example of attach that process multiple tab documents + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let firstLocation = "data:text/html,foobar"; + let secondLocation = "data:text/html,bar"; + let thirdLocation = "data:text/html,fox"; + let onReadyCount = 0; + let worker1 = null; + let worker2 = null; + let detachEventCount = 0; + tabs.open({ + url: firstLocation, + onReady: function (tab) { + onReadyCount++; + if (onReadyCount == 1) { + worker1 = tab.attach({ + contentScript: 'self.on("message", ' + + ' function () self.postMessage(document.location.href)' + + ');', + onMessage: function (msg) { + test.assertEqual(msg, firstLocation, + "Worker url is equal to the 1st document"); + tab.url = secondLocation; + }, + onDetach: function () { + detachEventCount++; + test.pass("Got worker1 detach event"); + test.assertRaises(function () { + worker1.postMessage("ex-1"); + }, + /The page has been destroyed/, + "postMessage throw because worker1 is destroyed"); + checkEnd(); + } + }); + worker1.postMessage("new-doc-1"); + } + else if (onReadyCount == 2) { + + worker2 = tab.attach({ + contentScript: 'self.on("message", ' + + ' function () self.postMessage(document.location.href)' + + ');', + onMessage: function (msg) { + test.assertEqual(msg, secondLocation, + "Worker url is equal to the 2nd document"); + tab.url = thirdLocation; + }, + onDetach: function () { + detachEventCount++; + test.pass("Got worker2 detach event"); + test.assertRaises(function () { + worker2.postMessage("ex-2"); + }, + /The page has been destroyed/, + "postMessage throw because worker2 is destroyed"); + checkEnd(); + } + }); + worker2.postMessage("new-doc-2"); + } + else if (onReadyCount == 3) { + + tab.close(); + + } + + } + }); + + function checkEnd() { + if (detachEventCount != 2) + return; + + test.pass("Got all detach events"); + + closeBrowserWindow(window, function() test.done()); + } + + }); +} + + +exports.testAttachWrappers = function (test) { + // Check that content script has access to wrapped values by default + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let document = "data:text/html,"; + let count = 0; + + tabs.open({ + url: document, + onReady: function (tab) { + let worker = tab.attach({ + contentScript: 'try {' + + ' self.postMessage(!("globalJSVar" in window));' + + ' self.postMessage(typeof window.globalJSVar == "undefined");' + + '} catch(e) {' + + ' self.postMessage(e.message);' + + '}', + onMessage: function (msg) { + test.assertEqual(msg, true, "Worker has wrapped objects ("+count+")"); + if (count++ == 1) + closeBrowserWindow(window, function() test.done()); + } + }); + } + }); + + }); +} + +/* +// We do not offer unwrapped access to DOM since bug 601295 landed +// See 660780 to track progress of unwrap feature +exports.testAttachUnwrapped = function (test) { + // Check that content script has access to unwrapped values through unsafeWindow + test.waitUntilDone(); + openBrowserWindow(function(window, browser) { + let tabs = require("tabs"); + let document = "data:text/html,"; + let count = 0; + + tabs.open({ + url: document, + onReady: function (tab) { + let worker = tab.attach({ + contentScript: 'try {' + + ' self.postMessage(unsafeWindow.globalJSVar);' + + '} catch(e) {' + + ' self.postMessage(e.message);' + + '}', + onMessage: function (msg) { + test.assertEqual(msg, true, "Worker has access to javascript content globals ("+count+")"); + closeBrowserWindow(window, function() test.done()); + } + }); + } + }); + + }); +} +*/ + +exports['test window focus changes active tab'] = function(test) { + test.waitUntilDone(); + let win1 = openBrowserWindow(function() { + let win2 = openBrowserWindow(function() { + let tabs = require("tabs"); + tabs.on("activate", function onActivate() { + tabs.removeListener("activate", onActivate); + test.pass("activate was called on windows focus change."); + closeBrowserWindow(win1, function() { + closeBrowserWindow(win2, function() { test.done(); }); + }); + }); + win1.focus(); + }, "data:text/html,test window focus changes active tab

Window #2"); + }, "data:text/html,test window focus changes active tab

Window #1"); +}; + +exports['test ready event on new window tab'] = function(test) { + test.waitUntilDone(); + let uri = encodeURI("data:text/html,Waiting for ready event!"); + + require("tabs").on("ready", function onReady(tab) { + if (tab.url === uri) { + require("tabs").removeListener("ready", onReady); + test.pass("ready event was emitted"); + closeBrowserWindow(window, function() { + test.done(); + }); + } + }); + + let window = openBrowserWindow(function(){}, uri); +}; +/******************* helpers *********************/ + +// Helper for getting the active window +this.__defineGetter__("activeWindow", function activeWindow() { + return Cc["@mozilla.org/appshell/window-mediator;1"]. + getService(Ci.nsIWindowMediator). + getMostRecentWindow("navigator:browser"); +}); + +// Utility function to open a new browser window. +function openBrowserWindow(callback, url) { + let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]. + getService(Ci.nsIWindowWatcher); + let urlString = Cc["@mozilla.org/supports-string;1"]. + createInstance(Ci.nsISupportsString); + urlString.data = url; + let window = ww.openWindow(null, "chrome://browser/content/browser.xul", + "_blank", "chrome,all,dialog=no", urlString); + + if (callback) { + window.addEventListener("load", function onLoad(event) { + if (event.target && event.target.defaultView == window) { + window.removeEventListener("load", onLoad, true); + let browsers = window.document.getElementsByTagName("tabbrowser"); + try { + require("timer").setTimeout(function () { + callback(window, browsers[0]); + }, 10); + } catch (e) { console.exception(e); } + } + }, true); + } + + return window; +} + +// Helper for calling code at window close +function closeBrowserWindow(window, callback) { + window.addEventListener("unload", function unload() { + window.removeEventListener("unload", unload, false); + callback(); + }, false); + window.close(); +} + +// If the module doesn't support the app we're being run in, require() will +// throw. In that case, remove all tests above from exports, and add one dummy +// test that passes. +try { + require("tabs"); +} +catch (err) { + // This bug should be mentioned in the error message. + let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=560716"; + if (err.message.indexOf(bug) < 0) + throw err; + for (let [prop, val] in Iterator(exports)) { + if (/^test/.test(prop) && typeof(val) === "function") + delete exports[prop]; + } + exports.testAppNotSupported = function (test) { + test.pass("the tabs module does not support this application."); + }; +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-timers.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-timers.js new file mode 100644 index 0000000..90b26bf --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-timers.js @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const timers = require("timers"); + +exports.testTimeout = function (test) { + test.waitUntilDone(); + timers.setTimeout(function () { + test.pass("timers.setTimeout works"); + test.done(); + }, 0); +} diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-widget.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-widget.js new file mode 100644 index 0000000..5d3475b --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-widget.js @@ -0,0 +1,1010 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If 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 { Loader } = require('./helpers'); +const widgets = require("widget"); +const url = require("url"); +const windowUtils = require("window-utils"); +const tabBrowser = require("tab-browser"); + +exports.testConstructor = function(test) { + test.waitUntilDone(30000); + + let browserWindow = windowUtils.activeBrowserWindow; + let doc = browserWindow.document; + let AddonsMgrListener = browserWindow.AddonsMgrListener; + + function container() doc.getElementById("addon-bar"); + function widgetCount() container() ? container().getElementsByTagName("toolbaritem").length : 0; + let widgetStartCount = widgetCount(); + function widgetNode(index) container() ? container().getElementsByTagName("toolbaritem")[index] : null; + + // Test basic construct/destroy + AddonsMgrListener.onInstalling(); + let w = widgets.Widget({ id: "fooID", label: "foo", content: "bar" }); + AddonsMgrListener.onInstalled(); + test.assertEqual(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction"); + + // test widget height + test.assertEqual(widgetNode(0).firstChild.boxObject.height, 16, "widget has correct default height"); + + AddonsMgrListener.onUninstalling(); + w.destroy(); + AddonsMgrListener.onUninstalled(); + w.destroy(); + test.pass("Multiple destroys do not cause an error"); + test.assertEqual(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy"); + + // Test automatic widget destroy on unload + let loader = Loader(module); + let widgetsFromLoader = loader.require("widget"); + let widgetStartCount = widgetCount(); + let w = widgetsFromLoader.Widget({ id: "fooID", label: "foo", content: "bar" }); + test.assertEqual(widgetCount(), widgetStartCount + 1, "widget has been correctly added"); + loader.unload(); + test.assertEqual(widgetCount(), widgetStartCount, "widget has been destroyed on module unload"); + + // Test nothing + test.assertRaises( + function() widgets.Widget({}), + "The widget must have a non-empty label property.", + "throws on no properties"); + + // Test no label + test.assertRaises( + function() widgets.Widget({content: "foo"}), + "The widget must have a non-empty label property.", + "throws on no label"); + + // Test empty label + test.assertRaises( + function() widgets.Widget({label: "", content: "foo"}), + "The widget must have a non-empty label property.", + "throws on empty label"); + + // Test no content or image + test.assertRaises( + function() widgets.Widget({id: "fooID", label: "foo"}), + "No content or contentURL property found. Widgets must have one or the other.", + "throws on no content"); + + // Test empty content, no image + test.assertRaises( + function() widgets.Widget({id:"fooID", label: "foo", content: ""}), + "No content or contentURL property found. Widgets must have one or the other.", + "throws on empty content"); + + // Test empty image, no content + test.assertRaises( + function() widgets.Widget({id:"fooID", label: "foo", image: ""}), + "No content or contentURL property found. Widgets must have one or the other.", + "throws on empty content"); + + // Test empty content, empty image + test.assertRaises( + function() widgets.Widget({id:"fooID", label: "foo", content: "", image: ""}), + "No content or contentURL property found. Widgets must have one or the other.", + "throws on empty content"); + + // Test duplicated ID + let duplicateID = widgets.Widget({id: "foo", label: "foo", content: "bar"}); + test.assertRaises( + function() widgets.Widget({id: "foo", label: "bar", content: "bar"}), + /This widget ID is already used:/, + "throws on duplicated id"); + duplicateID.destroy(); + + // Test Bug 652527 + test.assertRaises( + function() widgets.Widget({id: "", label: "bar", content: "bar"}), + /You have to specify a unique value for the id property of/, + "throws on falsey id"); + + // Test duplicate label, different ID + let w1 = widgets.Widget({id: "id1", label: "foo", content: "bar"}); + let w2 = widgets.Widget({id: "id2", label: "foo", content: "bar"}); + w1.destroy(); + w2.destroy(); + + // Test position restore on create/destroy/create + // Create 3 ordered widgets + let w1 = widgets.Widget({id: "first", label:"first", content: "bar"}); + let w2 = widgets.Widget({id: "second", label:"second", content: "bar"}); + let w3 = widgets.Widget({id: "third", label:"third", content: "bar"}); + // Remove the middle widget + test.assertEqual(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted"); + w2.destroy(); + test.assertEqual(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one"); + w2 = widgets.Widget({id: "second", label:"second", content: "bar"}); + test.assertEqual(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location"); + // Cleanup this testcase + AddonsMgrListener.onUninstalling(); + w1.destroy(); + w2.destroy(); + w3.destroy(); + AddonsMgrListener.onUninstalled(); + + // Test concurrent widget module instances on addon-bar hiding + let loader = Loader(module); + let anotherWidgetsInstance = loader.require("widget"); + test.assert(container().collapsed, "UI is hidden when no widgets"); + AddonsMgrListener.onInstalling(); + let w1 = widgets.Widget({id: "foo", label: "foo", content: "bar"}); + // Ideally we would let AddonsMgrListener display the addon bar + // But, for now, addon bar is immediatly displayed by sdk code + // https://bugzilla.mozilla.org/show_bug.cgi?id=627484 + test.assert(!container().collapsed, "UI is already visible when we just added the widget"); + AddonsMgrListener.onInstalled(); + test.assert(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation"); + let w2 = anotherWidgetsInstance.Widget({id: "bar", label: "bar", content: "foo"}); + test.assert(!container().collapsed, "UI still visible when we add a second widget"); + AddonsMgrListener.onUninstalling(); + w1.destroy(); + AddonsMgrListener.onUninstalled(); + test.assert(!container().collapsed, "UI still visible when we remove one of two widgets"); + AddonsMgrListener.onUninstalling(); + w2.destroy(); + test.assert(!container().collapsed, "UI is still visible when we have removed all widget but still not called onUninstalled"); + AddonsMgrListener.onUninstalled(); + test.assert(container().collapsed, "UI is hidden when we have removed all widget and called onUninstalled"); + + // Helper for testing a single widget. + // Confirms proper addition and content setup. + function testSingleWidget(widgetOptions) { + // We have to display which test is being run, because here we do not + // use the regular test framework but rather a custom one that iterates + // the `tests` array. + console.info("executing: " + widgetOptions.id); + + let startCount = widgetCount(); + let widget = widgets.Widget(widgetOptions); + let node = widgetNode(startCount); + test.assert(node, "widget node at index"); + test.assertEqual(node.tagName, "toolbaritem", "widget element is correct"); + test.assertEqual(widget.width + "px", node.style.minWidth, "widget width is correct"); + test.assertEqual(widgetCount(), startCount + 1, "container has correct number of child elements"); + let content = node.firstElementChild; + test.assert(content, "found content"); + test.assertMatches(content.tagName, /iframe|image/, "content is iframe or image"); + return widget; + } + + // Array of widgets to test + // and a function to test them. + let tests = []; + function nextTest() { + test.assertEqual(widgetCount(), 0, "widget in last test property cleaned itself up"); + if (!tests.length) + test.done(); + else + require("timer").setTimeout(tests.shift(), 0); + } + function doneTest() nextTest(); + + // text widget + tests.push(function testTextWidget() testSingleWidget({ + id: "text", + label: "text widget", + content: "oh yeah", + contentScript: "self.postMessage(document.body.innerHTML);", + contentScriptWhen: "end", + onMessage: function (message) { + test.assertEqual(this.content, message, "content matches"); + this.destroy(); + doneTest(); + } + })); + + // html widget + tests.push(function testHTMLWidget() testSingleWidget({ + id: "html", + label: "html widget", + content: "
oh yeah
", + contentScript: "self.postMessage(document.body.innerHTML);", + contentScriptWhen: "end", + onMessage: function (message) { + test.assertEqual(this.content, message, "content matches"); + this.destroy(); + doneTest(); + } + })); + + // image url widget + tests.push(function testImageURLWidget() testSingleWidget({ + id: "image", + label: "image url widget", + contentURL: require("self").data.url("test.html"), + contentScript: "self.postMessage({title: document.title, " + + "tag: document.body.firstElementChild.tagName, " + + "content: document.body.firstElementChild.innerHTML});", + contentScriptWhen: "end", + onMessage: function (message) { + test.assertEqual(message.title, "foo", "title matches"); + test.assertEqual(message.tag, "P", "element matches"); + test.assertEqual(message.content, "bar", "element content matches"); + this.destroy(); + doneTest(); + } + })); + + // web uri widget + tests.push(function testWebURIWidget() testSingleWidget({ + id: "web", + label: "web uri widget", + contentURL: require("self").data.url("test.html"), + contentScript: "self.postMessage({title: document.title, " + + "tag: document.body.firstElementChild.tagName, " + + "content: document.body.firstElementChild.innerHTML});", + contentScriptWhen: "end", + onMessage: function (message) { + test.assertEqual(message.title, "foo", "title matches"); + test.assertEqual(message.tag, "P", "element matches"); + test.assertEqual(message.content, "bar", "element content matches"); + this.destroy(); + doneTest(); + } + })); + + // event: onclick + content + tests.push(function testOnclickEventContent() testSingleWidget({ + id: "click", + label: "click test widget - content", + content: "
foo
", + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('click', true, true ); " + + "document.getElementById('me').dispatchEvent(evt);", + contentScriptWhen: "end", + onClick: function() { + test.pass("onClick called"); + this.destroy(); + doneTest(); + } + })); + + // event: onmouseover + content + tests.push(function testOnmouseoverEventContent() testSingleWidget({ + id: "mouseover", + label: "mouseover test widget - content", + content: "
foo
", + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('mouseover', true, true ); " + + "document.getElementById('me').dispatchEvent(evt);", + contentScriptWhen: "end", + onMouseover: function() { + test.pass("onMouseover called"); + this.destroy(); + doneTest(); + } + })); + + // event: onmouseout + content + tests.push(function testOnmouseoutEventContent() testSingleWidget({ + id: "mouseout", + label: "mouseout test widget - content", + content: "
foo
", + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('mouseout', true, true ); " + + "document.getElementById('me').dispatchEvent(evt);", + contentScriptWhen: "end", + onMouseout: function() { + test.pass("onMouseout called"); + this.destroy(); + doneTest(); + } + })); + + // event: onclick + image + tests.push(function testOnclickEventImage() testSingleWidget({ + id: "click", + label: "click test widget - image", + contentURL: require("self").data.url("moz_favicon.ico"), + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('click', true, true ); " + + "document.body.firstElementChild.dispatchEvent(evt);", + contentScriptWhen: "end", + onClick: function() { + test.pass("onClick called"); + this.destroy(); + doneTest(); + } + })); + + // event: onmouseover + image + tests.push(function testOnmouseoverEventImage() testSingleWidget({ + id: "mouseover", + label: "mouseover test widget - image", + contentURL: require("self").data.url("moz_favicon.ico"), + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('mouseover', true, true ); " + + "document.body.firstElementChild.dispatchEvent(evt);", + contentScriptWhen: "end", + onMouseover: function() { + test.pass("onMouseover called"); + this.destroy(); + doneTest(); + } + })); + + // event: onmouseout + image + tests.push(function testOnmouseoutEventImage() testSingleWidget({ + id: "mouseout", + label: "mouseout test widget - image", + contentURL: require("self").data.url("moz_favicon.ico"), + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('mouseout', true, true ); " + + "document.body.firstElementChild.dispatchEvent(evt);", + contentScriptWhen: "end", + onMouseout: function() { + test.pass("onMouseout called"); + this.destroy(); + doneTest(); + } + })); + + // test multiple widgets + tests.push(function testMultipleWidgets() { + let w1 = widgets.Widget({id: "first", label: "first widget", content: "first content"}); + let w2 = widgets.Widget({id: "second", label: "second widget", content: "second content"}); + + w1.destroy(); + w2.destroy(); + + doneTest(); + }); + + // test updating widget content + let loads = 0; + tests.push(function testUpdatingWidgetContent() testSingleWidget({ + id: "content", + label: "content update test widget", + content: "
foo
", + contentScript: "self.postMessage(1)", + contentScriptWhen: "ready", + onMessage: function(message) { + if (!this.flag) { + this.content = "
bar
"; + this.flag = 1; + } + else { + test.assertEqual(this.content, "
bar
"); + this.destroy(); + doneTest(); + } + } + })); + + // test updating widget contentURL + let url1 = "data:text/html,foodle"; + let url2 = "data:text/html,nistel"; + + tests.push(function testUpdatingContentURL() testSingleWidget({ + id: "content", + label: "content update test widget", + contentURL: url1, + contentScript: "self.postMessage(document.location.href);", + contentScriptWhen: "end", + onMessage: function(message) { + if (!this.flag) { + test.assertEqual(this.contentURL.toString(), url1); + test.assertEqual(message, url1); + this.contentURL = url2; + this.flag = 1; + } + else { + test.assertEqual(this.contentURL.toString(), url2); + test.assertEqual(message, url2); + this.destroy(); + doneTest(); + } + } + })); + + // test tooltip + tests.push(function testTooltip() testSingleWidget({ + id: "text", + label: "text widget", + content: "oh yeah", + tooltip: "foo", + contentScript: "self.postMessage(1)", + contentScriptWhen: "ready", + onMessage: function(message) { + test.assertEqual(this.tooltip, "foo", "tooltip matches"); + this.destroy(); + doneTest(); + } + })); + + // test tooltip fallback to label + tests.push(function testTooltipFallback() testSingleWidget({ + id: "fallback", + label: "fallback", + content: "oh yeah", + contentScript: "self.postMessage(1)", + contentScriptWhen: "ready", + onMessage: function(message) { + test.assertEqual(this.tooltip, this.label, "tooltip fallbacks to label"); + this.destroy(); + doneTest(); + } + })); + + // test updating widget tooltip + let updated = false; + tests.push(function testUpdatingTooltip() testSingleWidget({ + id: "tooltip", + label: "tooltip update test widget", + tooltip: "foo", + content: "
foo
", + contentScript: "self.postMessage(1)", + contentScriptWhen: "ready", + onMessage: function(message) { + this.tooltip = "bar"; + test.assertEqual(this.tooltip, "bar", "tooltip gets updated"); + this.destroy(); + doneTest(); + } + })); + + // test allow attribute + tests.push(function testDefaultAllow() testSingleWidget({ + id: "allow", + label: "allow.script attribute", + content: "", + contentScript: "self.postMessage(document.title)", + onMessage: function(message) { + test.assertEqual(message, "ok", "scripts are evaluated by default"); + this.destroy(); + doneTest(); + } + })); + + tests.push(function testExplicitAllow() testSingleWidget({ + id: "allow", + label: "allow.script attribute", + allow: {script: true}, + content: "", + contentScript: "self.postMessage(document.title)", + onMessage: function(message) { + test.assertEqual(message, "ok", "scripts are evaluated when we want to"); + this.destroy(); + doneTest(); + } + })); + + tests.push(function testExplicitDisallow() testSingleWidget({ + id: "allow", + label: "allow.script attribute", + content: "", + allow: {script: false}, + contentScript: "self.postMessage(document.title)", + onMessage: function(message) { + test.assertNotEqual(message, "ok", "scripts aren't evaluated when " + + "explicitly blocked it"); + this.destroy(); + doneTest(); + } + })); + + // test multiple windows + tests.push(function testMultipleWindows() { + tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) { + let browserWindow = e.target.defaultView; + let doc = browserWindow.document; + function container() doc.getElementById("addon-bar"); + function widgetCount2() container() ? container().childNodes.length : 0; + let widgetStartCount2 = widgetCount2(); + + let w1Opts = {id:"first", label: "first widget", content: "first content"}; + let w1 = testSingleWidget(w1Opts); + test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget"); + + let w2Opts = {id:"second", label: "second widget", content: "second content"}; + let w2 = testSingleWidget(w2Opts); + test.assertEqual(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget"); + + w1.destroy(); + test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first destroy"); + w2.destroy(); + test.assertEqual(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after second destroy"); + + closeBrowserWindow(browserWindow, function() { + doneTest(); + }); + }}); + }); + + // test window closing + tests.push(function testWindowClosing() { + // 1/ Create a new widget + let w1Opts = { + id:"first", + label: "first widget", + content: "first content", + contentScript: "self.port.on('event', function () self.port.emit('event'))" + }; + let widget = testSingleWidget(w1Opts); + let windows = require("windows").browserWindows; + + // 2/ Retrieve a WidgetView for the initial browser window + let acceptDetach = false; + let mainView = widget.getView(windows.activeWindow); + test.assert(mainView, "Got first widget view"); + mainView.on("detach", function () { + // 8/ End of our test. Accept detach event only when it occurs after + // widget.destroy() + if (acceptDetach) + doneTest(); + else + test.fail("View on initial window should not be destroyed"); + }); + mainView.port.on("event", function () { + // 7/ Receive event sent during 6/ and cleanup our test + acceptDetach = true; + widget.destroy(); + }); + + // 3/ First: open a new browser window + windows.open({ + url: "about:blank", + onOpen: function(window) { + // 4/ Retrieve a WidgetView for this new window + let view = widget.getView(window); + test.assert(view, "Got second widget view"); + view.port.on("event", function () { + test.fail("We should not receive event on the detach view"); + }); + view.on("detach", function () { + // The related view is destroyed + // 6/ Send a custom event + test.assertRaises(function () { + view.port.emit("event"); + }, + /The widget has been destroyed and can no longer be used./, + "emit on a destroyed view should throw"); + widget.port.emit("event"); + }); + + // 5/ Destroy this window + window.close(); + } + }); + }); + + tests.push(function testAddonBarHide() { + // Hide the addon-bar + browserWindow.setToolbarVisibility(container(), false); + + // Then open a browser window and verify that the addon-bar remains hidden + tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) { + let browserWindow = e.target.defaultView; + let doc = browserWindow.document; + function container2() doc.getElementById("addon-bar"); + function widgetCount2() container2() ? container2().childNodes.length : 0; + let widgetStartCount2 = widgetCount2(); + + let w1Opts = {id:"first", label: "first widget", content: "first content"}; + let w1 = testSingleWidget(w1Opts); + test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after widget creation"); + + w1.destroy(); + test.assertEqual(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after widget destroy"); + + test.assert(container().collapsed, "1st window has an hidden addon-bar"); + test.assert(container2().collapsed, "2nd window has an hidden addon-bar"); + + browserWindow.setToolbarVisibility(container(), true); + + closeBrowserWindow(browserWindow, function() { + doneTest(); + }); + }}); + }); + + // test widget.width + tests.push(function testWidgetWidth() testSingleWidget({ + id: "text", + label: "test widget.width", + content: "test width", + width: 200, + contentScript: "self.postMessage(1)", + contentScriptWhen: "ready", + onMessage: function(message) { + test.assertEqual(this.width, 200); + + let node = widgetNode(0); + test.assertEqual(this.width, node.style.minWidth.replace("px", "")); + test.assertEqual(this.width, node.firstElementChild.style.width.replace("px", "")); + this.width = 300; + test.assertEqual(this.width, node.style.minWidth.replace("px", "")); + test.assertEqual(this.width, node.firstElementChild.style.width.replace("px", "")); + + this.destroy(); + doneTest(); + } + })); + + // test click handler not respond to right-click + let clickCount = 0; + tests.push(function testNoRightClick() testSingleWidget({ + id: "click-content", + label: "click test widget - content", + content: "
foo
", + contentScript: "var evt = document.createEvent('MouseEvents'); " + + "evt.initMouseEvent('click', true, true, window, " + + " 0, 0, 0, 0, 0, false, false, false, false, 2, null); " + + "document.getElementById('me').dispatchEvent(evt); " + + "evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('click', true, true ); " + + "document.getElementById('me').dispatchEvent(evt); " + + "evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('mouseover', true, true ); " + + "document.getElementById('me').dispatchEvent(evt);", + contentScriptWhen: "end", + onClick: function() clickCount++, + onMouseover: function() { + test.assertEqual(clickCount, 1, "right click wasn't sent to click handler"); + this.destroy(); + doneTest(); + } + })); + + // kick off test execution + doneTest(); +}; + +exports.testPanelWidget1 = function testPanelWidget1(test) { + const widgets = require("widget"); + + let widget1 = widgets.Widget({ + id: "panel1", + label: "panel widget 1", + content: "
foo
", + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('click', true, true ); " + + "document.body.dispatchEvent(evt);", + contentScriptWhen: "end", + panel: require("panel").Panel({ + contentURL: "data:text/html,Look ma, a panel!", + onShow: function() { + widget1.destroy(); + test.pass("panel displayed on click"); + test.done(); + } + }) + }); + test.waitUntilDone(); +}; + +exports.testPanelWidget2 = function testPanelWidget2(test) { + const widgets = require("widget"); + test.assertRaises( + function() { + widgets.Widget({ + id: "panel2", + label: "panel widget 2", + panel: {} + }); + }, + "The option \"panel\" must be one of the following types: null, undefined, object", + "widget.panel must be a Panel object" + ); +}; + +exports.testPanelWidget3 = function testPanelWidget3(test) { + const widgets = require("widget"); + let onClickCalled = false; + let widget3 = widgets.Widget({ + id: "panel3", + label: "panel widget 3", + content: "
foo
", + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('click', true, true ); " + + "document.body.firstElementChild.dispatchEvent(evt);", + contentScriptWhen: "end", + onClick: function() { + onClickCalled = true; + this.panel.show(); + }, + panel: require("panel").Panel({ + contentURL: "data:text/html,Look ma, a panel!", + onShow: function() { + test.assert( + onClickCalled, + "onClick called on click for widget with both panel and onClick" + ); + widget3.destroy(); + test.done(); + } + }) + }); + test.waitUntilDone(); +}; + +exports.testWidgetMessaging = function testWidgetMessaging(test) { + test.waitUntilDone(); + let origMessage = "foo"; + const widgets = require("widget"); + let widget = widgets.Widget({ + id: "foo", + label: "foo", + content: "baz", + contentScriptWhen: "end", + contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", + onMessage: function(message) { + if (message == "ready") + widget.postMessage(origMessage); + else { + test.assertEqual(origMessage, message); + widget.destroy(); + test.done(); + } + } + }); +}; + +exports.testWidgetViews = function testWidgetViews(test) { + test.waitUntilDone(); + const widgets = require("widget"); + let widget = widgets.Widget({ + id: "foo", + label: "foo", + content: "baz", + contentScriptWhen: "ready", + contentScript: "self.on('message', function(data) self.postMessage(data)); self.postMessage('ready')", + onAttach: function(view) { + test.pass("WidgetView created"); + view.on("message", function () { + test.pass("Got message in WidgetView"); + widget.destroy(); + }); + view.on("detach", function () { + test.pass("WidgetView destroyed"); + test.done(); + }); + } + }); + +}; + +exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(test) { + test.waitUntilDone(); + const widgets = require("widget"); + let view = null; + let widget = widgets.Widget({ + id: "foo", + label: "foo", + content: "
foo
", + contentScript: "var evt = document.createEvent('HTMLEvents'); " + + "evt.initEvent('click', true, true ); " + + "document.getElementById('me').dispatchEvent(evt);", + contentScriptWhen: "ready", + onAttach: function(attachView) { + view = attachView; + test.pass("Got attach event"); + }, + onClick: function (eventView) { + test.assertEqual(view, eventView, + "event first argument is equal to the WidgetView"); + let view2 = widget.getView(require("windows").browserWindows.activeWindow); + test.assertEqual(view, view2, + "widget.getView return the same WidgetView"); + widget.destroy(); + test.done(); + } + }); +}; + +exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(test) { + test.waitUntilDone(); + const widgets = require("widget"); + let widget = widgets.Widget({ + id: "foo", + label: "foo", + content: "
foo
", + contentScript: "self.port.emit('event', 'ok');", + contentScriptWhen: "ready", + onAttach: function(view) { + view.port.on("event", function (data) { + test.assertEqual(data, "ok", + "event argument is valid on WidgetView"); + }); + }, + }); + widget.port.on("event", function (data) { + test.assertEqual(data, "ok", + "event argument is valid on Widget"); + widget.destroy(); + test.done(); + }); +}; + +exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(test) { + test.waitUntilDone(); + const widgets = require("widget"); + + let widget = new widgets.Widget({ + id: "foo", + label: "foo", + content: "foo" + }); + let view = widget.getView(require("windows").browserWindows.activeWindow); + widget.tooltip = null; + test.assertEqual(view.tooltip, "foo", + "view tooltip defaults to base widget label"); + test.assertEqual(widget.tooltip, "foo", + "tooltip defaults to base widget label"); + widget.destroy(); + test.done(); +}; + +exports.testWidgetMove = function testWidgetMove(test) { + test.waitUntilDone(); + + let windowUtils = require("window-utils"); + let widgets = require("widget"); + + let browserWindow = windowUtils.activeBrowserWindow; + let doc = browserWindow.document; + + let label = "unique-widget-label"; + let origMessage = "message after node move"; + let gotFirstReady = false; + + let widget = widgets.Widget({ + id: "foo", + label: label, + content: "baz", + contentScriptWhen: "ready", + contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", + onMessage: function(message) { + if (message == "ready") { + if (!gotFirstReady) { + test.pass("Got first ready event"); + let widgetNode = doc.querySelector('toolbaritem[label="' + label + '"]'); + let parent = widgetNode.parentNode; + parent.insertBefore(widgetNode, parent.firstChild); + gotFirstReady = true; + } else { + test.pass("Got second ready event"); + widget.postMessage(origMessage); + } + } + else { + test.assertEqual(origMessage, message, "Got message after node move"); + widget.destroy(); + test.done(); + } + } + }); +}; + +/* +The bug is exhibited when a widget with HTML content has it's content +changed to new HTML content with a pound in it. Because the src of HTML +content is converted to a data URI, the underlying iframe doesn't +consider the content change a navigation change, so doesn't load +the new content. +*/ +exports.testWidgetWithPound = function testWidgetWithPound(test) { + test.waitUntilDone(); + + function getWidgetContent(widget) { + let windowUtils = require("window-utils"); + let browserWindow = windowUtils.activeBrowserWindow; + let doc = browserWindow.document; + let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]'); + test.assert(widgetNode, 'found widget node in the front-end'); + return widgetNode.firstChild.contentDocument.body.innerHTML; + } + + let widgets = require("widget"); + let count = 0; + let widget = widgets.Widget({ + id: "1", + label: "foo", + content: "foo", + contentScript: "window.addEventListener('load', self.postMessage, false);", + onMessage: function() { + count++; + if (count == 1) { + widget.content = "foo#"; + } + else { + test.assertEqual(getWidgetContent(widget), "foo#", "content updated to pound?"); + widget.destroy(); + test.done(); + } + } + }); +}; + +exports.testNavigationBarWidgets = function testNavigationBarWidgets(test) { + test.waitUntilDone(); + + let w1 = widgets.Widget({id: "1st", label: "1st widget", content: "1"}); + let w2 = widgets.Widget({id: "2nd", label: "2nd widget", content: "2"}); + let w3 = widgets.Widget({id: "3rd", label: "3rd widget", content: "3"}); + + // Hack to move 2nd and 3rd widgets manually to the navigation bar, in 5th + // position, i.e. after search box. 3rd widget will be in 5th and 2nd in 6th. + function getWidgetNode(toolbar, position) { + return toolbar.getElementsByTagName("toolbaritem")[position]; + } + let browserWindow = windowUtils.activeBrowserWindow; + let doc = browserWindow.document; + let addonBar = doc.getElementById("addon-bar"); + let w2Toolbaritem = getWidgetNode(addonBar, 1); + let w3ToolbarItem = getWidgetNode(addonBar, 2); + let navBar = doc.getElementById("nav-bar"); + navBar.insertItem(w2Toolbaritem.id, navBar.childNodes[6], null, false); + navBar.insertItem(w3ToolbarItem.id, navBar.childNodes[6], null, false); + // Widget and Firefox codes rely on this `currentset` attribute, + // so ensure it is correctly saved + navBar.setAttribute("currentset", navBar.currentSet); + doc.persist(navBar.id, "currentset"); + // Update addonbar too as we removed widget from there. + // Otherwise, widgets may still be added to this toolbar. + addonBar.setAttribute("currentset", addonBar.currentSet); + doc.persist(addonBar.id, "currentset"); + + tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) { + let browserWindow = e.target.defaultView; + let doc = browserWindow.document; + let navBar = doc.getElementById("nav-bar"); + let addonBar = doc.getElementById("addon-bar"); + + // Ensure that 1st is in addon bar + test.assertEqual(getWidgetNode(addonBar, 0).getAttribute("label"), w1.label); + // And that 2nd and 3rd keep their original positions in navigation bar + test.assertEqual(navBar.childNodes[5].getAttribute("label"), w3.label); + test.assertEqual(navBar.childNodes[6].getAttribute("label"), w2.label); + + w1.destroy(); + w2.destroy(); + w3.destroy(); + + closeBrowserWindow(browserWindow, function() { + test.done(); + }); + }}); +}; + +/******************* helpers *********************/ + +// Helper for calling code at window close +function closeBrowserWindow(window, callback) { + require("timer").setTimeout(function() { + window.addEventListener("unload", function onUnload() { + window.removeEventListener("unload", onUnload, false); + callback(); + }, false); + window.close(); + }, 0); +} + +// ADD NO TESTS BELOW THIS LINE! /////////////////////////////////////////////// + +// If the module doesn't support the app we're being run in, require() will +// throw. In that case, remove all tests above from exports, and add one dummy +// test that passes. +try { + require("widget"); +} +catch (err) { + // This bug should be mentioned in the error message. + let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=560716"; + if (err.message.indexOf(bug) < 0) + throw err; + for (let [prop, val] in Iterator(exports)) { + if (/^test/.test(prop) && typeof(val) === "function") + delete exports[prop]; + } + exports.testAppNotSupported = function (test) { + test.pass("widget does not support this application."); + }; +} + diff --git a/tools/addon-sdk-1.7/packages/addon-kit/tests/test-windows.js b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-windows.js new file mode 100644 index 0000000..b85fec7 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/addon-kit/tests/test-windows.js @@ -0,0 +1,309 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const {Cc, Ci} = require("chrome"); +const { setTimeout } = require("timer"); +const { Loader } = require('./helpers'); +const wm = Cc["@mozilla.org/appshell/window-mediator;1"]. + getService(Ci.nsIWindowMediator); +let browserWindows; + +function getTestRunnerWindow() wm.getMostRecentWindow("test:runner") + +exports.testOpenAndCloseWindow = function(test) { + test.waitUntilDone(); + + test.assertEqual(browserWindows.length, 1, "Only one window open"); + + browserWindows.open({ + url: "data:text/html,windows API test", + onOpen: function(window) { + test.assertEqual(this, browserWindows, + "The 'this' object is the windows object."); + test.assertEqual(window.tabs.length, 1, "Only one tab open"); + test.assertEqual(browserWindows.length, 2, "Two windows open"); + window.tabs.activeTab.on('ready', function onReady(tab) { + tab.removeListener('ready', onReady); + test.assert(window.title.indexOf("windows API test") != -1, + "URL correctly loaded"); + window.close(); + }); + }, + onClose: function(window) { + test.assertEqual(window.tabs.length, 0, "Tabs were cleared"); + test.assertEqual(browserWindows.length, 1, "Only one window open"); + test.done(); + } + }); +}; + +exports.testAutomaticDestroy = function(test) { + + test.waitUntilDone(); + let windows = browserWindows; + + // Create a second windows instance that we will unload + let called = false; + let loader = Loader(module); + let windows2 = loader.require("windows").browserWindows; + windows2.on("open", function() { + called = true; + }); + + loader.unload(); + + // Fire a windows event and check that this unloaded instance is inactive + windows.open({ + url: "data:text/html,foo", + onOpen: function(window) { + setTimeout(function () { + test.assert(!called, + "Unloaded windows instance is destroyed and inactive"); + window.close(function () { + test.done(); + }); + }); + } + }); + +}; + +exports.testOnOpenOnCloseListeners = function(test) { + test.waitUntilDone(); + let windows = browserWindows; + + test.assertEqual(browserWindows.length, 1, "Only one window open"); + + let received = { + listener1: false, + listener2: false, + listener3: false, + listener4: false + } + + function listener1() { + test.assertEqual(this, windows, "The 'this' object is the windows object."); + if (received.listener1) + test.fail("Event received twice"); + received.listener1 = true; + } + + function listener2() { + if (received.listener2) + test.fail("Event received twice"); + received.listener2 = true; + } + + function listener3() { + test.assertEqual(this, windows, "The 'this' object is the windows object."); + if (received.listener3) + test.fail("Event received twice"); + received.listener3 = true; + } + + function listener4() { + if (received.listener4) + test.fail("Event received twice"); + received.listener4 = true; + } + + windows.on('open', listener1); + windows.on('open', listener2); + windows.on('close', listener3); + windows.on('close', listener4); + + function verify() { + test.assert(received.listener1, "onOpen handler called"); + test.assert(received.listener2, "onOpen handler called"); + test.assert(received.listener3, "onClose handler called"); + test.assert(received.listener4, "onClose handler called"); + + windows.removeListener('open', listener1); + windows.removeListener('open', listener2); + windows.removeListener('close', listener3); + windows.removeListener('close', listener4); + test.done(); + } + + + windows.open({ + url: "data:text/html,foo", + onOpen: function(window) { + window.close(verify); + } + }); +}; + +exports.testWindowTabsObject = function(test) { + test.waitUntilDone(); + + browserWindows.open({ + url: "data:text/html,tab 1", + onOpen: function onOpen(window) { + test.assertEqual(window.tabs.length, 1, "Only 1 tab open"); + + window.tabs.open({ + url: "data:text/html,tab 2", + inBackground: true, + onReady: function onReady(newTab) { + test.assertEqual(window.tabs.length, 2, "New tab open"); + test.assertEqual(newTab.title, "tab 2", "Correct new tab title"); + test.assertEqual(window.tabs.activeTab.title, "tab 1", "Correct active tab"); + + let i = 1; + for each (let tab in window.tabs) + test.assertEqual(tab.title, "tab " + i++, "Correct title"); + + window.close(); + } + }); + }, + onClose: function onClose(window) { + test.assertEqual(window.tabs.length, 0, "No more tabs on closed window"); + test.done(); + } + }); +}; + +exports.testActiveWindow = function(test) { + const xulApp = require("xul-app"); + if (xulApp.versionInRange(xulApp.platformVersion, "1.9.2", "1.9.2.*")) { + test.pass("This test is disabled on 3.6. For more information, see bug 598525"); + return; + } + + let windows = browserWindows; + + // API window objects + let window2, window3; + + // Raw window objects + let nonBrowserWindow = getTestRunnerWindow(), rawWindow2, rawWindow3; + + test.waitUntilDone(); + + let testSteps = [ + function() { + test.assertEqual(windows.length, 3, "Correct number of browser windows"); + let count = 0; + for (let window in windows) + count++; + test.assertEqual(count, 3, "Correct number of windows returned by iterator"); + + rawWindow2.focus(); + continueAfterFocus(rawWindow2); + }, + function() { + nonBrowserWindow.focus(); + continueAfterFocus(nonBrowserWindow); + }, + function() { + /** + * Bug 614079: This test fails intermittently on some specific linux + * environnements, without being able to reproduce it in same + * distribution with same window manager. + * Disable it until being able to reproduce it easily. + + // On linux, focus is not consistent, so we can't be sure + // what window will be on top. + // Here when we focus "non-browser" window, + // Any Browser window may be selected as "active". + test.assert(windows.activeWindow == window2 || windows.activeWindow == window3, + "Non-browser windows aren't handled by this module"); + */ + window2.activate(); + continueAfterFocus(rawWindow2); + }, + function() { + test.assertEqual(windows.activeWindow.title, window2.title, "Correct active window - 2"); + window3.activate(); + continueAfterFocus(rawWindow3); + }, + function() { + test.assertEqual(windows.activeWindow.title, window3.title, "Correct active window - 3"); + nonBrowserWindow.focus(); + finishTest(); + } + ]; + + windows.open({ + url: "data:text/html,window 2", + onOpen: function(window) { + window2 = window; + rawWindow2 = wm.getMostRecentWindow("navigator:browser"); + + windows.open({ + url: "data:text/html,window 3", + onOpen: function(window) { + window.tabs.activeTab.on('ready', function onReady() { + window3 = window; + rawWindow3 = wm.getMostRecentWindow("navigator:browser"); + nextStep() + }); + } + }); + } + }); + + function nextStep() { + if (testSteps.length > 0) + testSteps.shift()(); + } + + function continueAfterFocus(targetWindow) { + + // Based on SimpleTest.waitForFocus + var fm = Cc["@mozilla.org/focus-manager;1"]. + getService(Ci.nsIFocusManager); + + var childTargetWindow = {}; + fm.getFocusedElementForWindow(targetWindow, true, childTargetWindow); + childTargetWindow = childTargetWindow.value; + + var focusedChildWindow = {}; + if (fm.activeWindow) { + fm.getFocusedElementForWindow(fm.activeWindow, true, focusedChildWindow); + focusedChildWindow = focusedChildWindow.value; + } + + var focused = (focusedChildWindow == childTargetWindow); + if (focused) { + nextStep(); + } else { + childTargetWindow.addEventListener("focus", function focusListener() { + childTargetWindow.removeEventListener("focus", focusListener, true); + nextStep(); + }, true); + } + + } + + function finishTest() { + window3.close(function() { + window2.close(function() { + test.done(); + }); + }); + } +}; + +// If the module doesn't support the app we're being run in, require() will +// throw. In that case, remove all tests above from exports, and add one dummy +// test that passes. +try { + browserWindows = require("windows").browserWindows; +} +catch (err) { + // This bug should be mentioned in the error message. + let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=571449"; + if (err.message.indexOf(bug) < 0) + throw err; + for (let [prop, val] in Iterator(exports)) { + if (/^test/.test(prop) && typeof(val) === "function") + delete exports[prop]; + } + exports.testAppNotSupported = function (test) { + test.pass("the windows module does not support this application."); + }; +} diff --git a/tools/addon-sdk-1.7/packages/api-utils/README.md b/tools/addon-sdk-1.7/packages/api-utils/README.md new file mode 100644 index 0000000..55adb57 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/README.md @@ -0,0 +1,35 @@ + + +API Utils provides a basic CommonJS infrastructure for +developing traditional XULRunner add-ons and applications. It is +the basis for the Add-on SDK. + +To address issues present in traditional add-on development, +API Utils provides mechanisms for: + +* writing and executing test cases, inspired by Python's [nose][] + package, +* tracking JS objects of interest to aid in memory profiling and leak + detection, +* registering callbacks that perform cleanup tasks when modules are + unloaded, +* easily reporting errors with full stack tracebacks. + +API Utils also has the following characteristics: + +* Beautiful, concise documentation. +* A rigorous test suite ensuring that the library doesn't break as the + Mozilla platform evolves. +* Solid developer ergonomics ensuring that developers can easily find + out why something they're doing isn't working. + +API Utils is intended to be very small and only contain the bare +minimum of functionality that all add-ons need. + +Note that the API Utils package has not fully stabilized yet, meaning that +we do still expect to make incompatible changes to its APIs in future releases +of the SDK. + + [nose]: http://code.google.com/p/python-nose/ diff --git a/tools/addon-sdk-1.7/packages/api-utils/data/content-proxy.js b/tools/addon-sdk-1.7/packages/api-utils/data/content-proxy.js new file mode 100644 index 0000000..f0a39d3 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/data/content-proxy.js @@ -0,0 +1,847 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +let Ci = Components.interfaces; + +/** + * Access key that allows privileged code to unwrap proxy wrappers through + * valueOf: + * let xpcWrapper = proxyWrapper.valueOf(UNWRAP_ACCESS_KEY); + * This key should only be used by proxy unit test. + */ + const UNWRAP_ACCESS_KEY = {}; + + + /** + * Returns a closure that wraps arguments before calling the given function, + * which can be given to native functions that accept a function, such that when + * the closure is called, the given function is called with wrapped arguments. + * + * @param fun {Function} + * the function for which to create a closure wrapping its arguments + * @param obj {Object} + * target object from which `fun` comes from + * (optional, for debugging purpose) + * @param name {String} + * name of the attribute from which `fun` is binded on `obj` + * (optional, for debugging purpose) + * + * Example: + * function contentScriptListener(event) {} + * let wrapper = ContentScriptFunctionWrapper(contentScriptListener); + * xray.addEventListener("...", wrapper, false); + * -> Allow to `event` to be wrapped + */ +function ContentScriptFunctionWrapper(fun, obj, name) { + if ("___proxy" in fun && typeof fun.___proxy == "function") + return fun.___proxy; + + let wrappedFun = function () { + let args = []; + for (let i = 0, l = arguments.length; i < l; i++) + args.push(wrap(arguments[i])); + + //console.log("Called from native :"+obj+"."+name); + //console.log(">args "+arguments.length); + //console.log(fun); + + // Native code can execute this callback with `this` being the wrapped + // function. For example, window.mozRequestAnimationFrame. + if (this == wrappedFun) + return fun.apply(fun, args); + + return fun.apply(wrap(this), args); + }; + + Object.defineProperty(fun, "___proxy", {value : wrappedFun, + writable : false, + enumerable : false, + configurable : false}); + + return wrappedFun; +} + +/** + * Returns a closure that unwraps arguments before calling the `fun` function, + * which can be used to build a wrapper for a native function that accepts + * wrapped arguments, since native function only accept unwrapped arguments. + * + * @param fun {Function} + * the function to wrap + * @param originalObject {Object} + * target object from which `fun` comes from + * (optional, for debugging purpose) + * @param name {String} + * name of the attribute from which `fun` is binded on `originalObject` + * (optional, for debugging purpose) + * + * Example: + * wrapper.appendChild = NativeFunctionWrapper(xray.appendChild, xray); + * wrapper.appendChild(anotherWrapper); + * -> Allow to call xray.appendChild with unwrapped version of anotherWrapper + */ +function NativeFunctionWrapper(fun, originalObject, name) { + return function () { + let args = []; + let obj = this && typeof this.valueOf == "function" ? + this.valueOf(UNWRAP_ACCESS_KEY) : this; + + for (let i = 0, l = arguments.length; i < l; i++) + args.push( unwrap(arguments[i], obj, name) ); + + //if (name != "toString") + //console.log(">>calling native ["+(name?name:'#closure#')+"]: \n"+fun.apply+"\n"+obj+"\n("+args.join(', ')+")\nthis :"+obj+"from:"+originalObject+"\n"); + + // Need to use Function.prototype.apply.apply because XMLHttpRequest + // is a function (typeof return 'function') and fun.apply is null :/ + let unwrapResult = Function.prototype.apply.apply(fun, [obj, args]); + let result = wrap(unwrapResult, obj, name); + + //console.log("<< "+rr+" -> "+r); + + return result; + }; +} + +/* + * Unwrap a JS value that comes from the content script. + * Mainly converts proxy wrapper to XPCNativeWrapper. + */ +function unwrap(value, obj, name) { + //console.log("unwrap : "+value+" ("+name+")"); + if (!value) + return value; + let type = typeof value; + + // In case of proxy, unwrap them recursively + // (it should not be recursive, just in case of) + if (["object", "function"].indexOf(type) !== -1 && + "__isWrappedProxy" in value) { + while("__isWrappedProxy" in value) + value = value.valueOf(UNWRAP_ACCESS_KEY); + return value; + } + + // In case of functions we need to return a wrapper that converts native + // arguments applied to this function into proxies. + if (type == "function") + return ContentScriptFunctionWrapper(value, obj, name); + + // We must wrap objects coming from content script too, as they may have + // a function that will be called by a native method. + // For example: + // addEventListener(..., { handleEvent: function(event) {} }, ...); + if (type == "object") + return ContentScriptObjectWrapper(value); + + if (["string", "number", "boolean"].indexOf(type) !== -1) + return value; + //console.log("return non-wrapped to native : "+typeof value+" -- "+value); + return value; +} + +/** + * Returns an XrayWrapper proxy object that allow to wrap any of its function + * though `ContentScriptFunctionWrapper`. These proxies are given to + * XrayWrappers in order to automatically wrap values when they call a method + * of these proxies. So that they are only used internaly and content script, + * nor web page have ever access to them. As a conclusion, we can consider + * this code as being safe regarding web pages overload. + * + * + * @param obj {Object} + * object coming from content script context to wrap + * + * Example: + * let myListener = { handleEvent: function (event) {} }; + * node.addEventListener("click", myListener, false); + * `event` has to be wrapped, so handleEvent has to be wrapped using + * `ContentScriptFunctionWrapper` function. + * In order to do so, we build this new kind of proxies. + */ +function ContentScriptObjectWrapper(obj) { + if ("___proxy" in obj && typeof obj.___proxy == "object") + return obj.___proxy; + + function valueOf(key) { + if (key === UNWRAP_ACCESS_KEY) + return obj; + return this; + } + + let proxy = Proxy.create({ + // Fundamental traps + getPropertyDescriptor: function(name) { + return Object.getOwnPropertyDescriptor(obj, name); + }, + defineProperty: function(name, desc) { + return Object.defineProperty(obj, name, desc); + }, + getOwnPropertyNames: function () { + return Object.getOwnPropertyNames(obj); + }, + delete: function(name) { + return delete obj[name]; + }, + // derived traps + has: function(name) { + return name === "__isXrayWrapperProxy" || + name in obj; + }, + hasOwn: function(name) { + return Object.prototype.hasOwnProperty.call(obj, name); + }, + get: function(receiver, name) { + if (name == "valueOf") + return valueOf; + let value = obj[name]; + if (!value) + return value; + + return unwrap(value); + }, + set: function(receiver, name, val) { + obj[name] = val; + return true; + }, + enumerate: function() { + var result = []; + for each (let name in obj) { + result.push(name); + }; + return result; + }, + keys: function() { + return Object.keys(obj); + } + }); + + Object.defineProperty(obj, "___proxy", {value : proxy, + writable : false, + enumerable : false, + configurable : false}); + + return proxy; +} + +// List of all existing typed arrays. +// Can be found here: +// http://mxr.mozilla.org/mozilla-central/source/js/src/jsapi.cpp#1790 +const typedArraysCtor = [ + ArrayBuffer, + Int8Array, + Uint8Array, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + Uint8ClampedArray +]; + +/* + * Wrap a JS value coming from the document by building a proxy wrapper. + */ +function wrap(value, obj, name, debug) { + if (!value) + return value; + let type = typeof value; + if (type == "object") { + // Bug 671016: Typed arrays don't need to be proxified. + // We avoid checking the whole constructor list on all objects + // by doing this check only on non-extensible objects: + if (!Object.isExtensible(value) && + typedArraysCtor.indexOf(value.constructor) !== -1) + return value; + + // Bug 715755: do not proxify COW wrappers + // These wrappers throw an exception when trying to access + // any attribute that is not in a white list + try { + ("nonExistantAttribute" in value); + } + catch(e) { + if (e.message.indexOf("Permission denied to access property") !== -1) + return value; + } + + // We may have a XrayWrapper proxy. + // For example: + // let myListener = { handleEvent: function () {} }; + // node.addEventListener("click", myListener, false); + // When native code want to call handleEvent, + // we go though ContentScriptFunctionWrapper that calls `wrap(this)` + // `this` is the XrayWrapper proxy of myListener. + // We return this object without building a CS proxy as it is already + // a value coming from the CS. + if ("__isXrayWrapperProxy" in value) + return value.valueOf(UNWRAP_ACCESS_KEY); + + // Unwrap object before wrapping it. + // It should not happen with CS proxy objects. + while("__isWrappedProxy" in value) { + value = value.valueOf(UNWRAP_ACCESS_KEY); + } + + if (XPCNativeWrapper.unwrap(value) !== value) + return getProxyForObject(value); + // In case of Event, HTMLCollection or NodeList or ??? + // XPCNativeWrapper.unwrap(value) === value + // but it's still a XrayWrapper so let's build a proxy + return getProxyForObject(value); + } + if (type == "function") { + if (XPCNativeWrapper.unwrap(value) !== value + || (typeof value.toString === "function" && + value.toString().match(/\[native code\]/))) { + return getProxyForFunction(value, NativeFunctionWrapper(value, obj, name)); + } + return value; + } + if (type == "string") + return value; + if (type == "number") + return value; + if (type == "boolean") + return value; + //console.log("return non-wrapped to wrapped : "+value); + return value; +} + +/* + * Wrap an object from the document to a proxy wrapper + */ +function getProxyForObject(obj) { + if (typeof obj != "object") { + let msg = "tried to proxify something other than an object: " + typeof obj; + console.warn(msg); + throw msg; + } + if ("__isWrappedProxy" in obj) { + return obj; + } + // Check if there is a proxy cached on this wrapper, + // but take care of prototype ___proxy attribute inheritance! + if (obj && obj.___proxy && obj.___proxy.valueOf(UNWRAP_ACCESS_KEY) === obj) { + return obj.___proxy; + } + + let proxy = Proxy.create(handlerMaker(obj)); + + Object.defineProperty(obj, "___proxy", {value : proxy, + writable : false, + enumerable : false, + configurable : false}); + return proxy; +} + +/* + * Wrap a function from the document to a proxy wrapper + */ +function getProxyForFunction(fun, callTrap) { + if (typeof fun != "function") { + let msg = "tried to proxify something other than a function: " + typeof fun; + console.warn(msg); + throw msg; + } + if ("__isWrappedProxy" in fun) + return obj; + if ("___proxy" in fun) + return fun.___proxy; + + let proxy = Proxy.createFunction(handlerMaker(fun), callTrap); + + Object.defineProperty(fun, "___proxy", {value : proxy, + writable : false, + enumerable : false, + configurable : false}); + + return proxy; +} + +/* + * Check if a DOM attribute name is an event name. + */ +function isEventName(id) { + if (id.indexOf("on") != 0 || id.length == 2) + return false; + // Taken from: + // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#7616 + switch (id[2]) { + case 'a' : + return (id == "onabort" || + id == "onafterscriptexecute" || + id == "onafterprint"); + case 'b' : + return (id == "onbeforeunload" || + id == "onbeforescriptexecute" || + id == "onblur" || + id == "onbeforeprint"); + case 'c' : + return (id == "onchange" || + id == "onclick" || + id == "oncontextmenu" || + id == "oncopy" || + id == "oncut" || + id == "oncanplay" || + id == "oncanplaythrough"); + case 'd' : + return (id == "ondblclick" || + id == "ondrag" || + id == "ondragend" || + id == "ondragenter" || + id == "ondragleave" || + id == "ondragover" || + id == "ondragstart" || + id == "ondrop" || + id == "ondurationchange"); + case 'e' : + return (id == "onerror" || + id == "onemptied" || + id == "onended"); + case 'f' : + return id == "onfocus"; + case 'h' : + return id == "onhashchange"; + case 'i' : + return (id == "oninput" || + id == "oninvalid"); + case 'k' : + return (id == "onkeydown" || + id == "onkeypress" || + id == "onkeyup"); + case 'l' : + return (id == "onload" || + id == "onloadeddata" || + id == "onloadedmetadata" || + id == "onloadstart"); + case 'm' : + return (id == "onmousemove" || + id == "onmouseout" || + id == "onmouseover" || + id == "onmouseup" || + id == "onmousedown" || + id == "onmessage"); + case 'p' : + return (id == "onpaint" || + id == "onpageshow" || + id == "onpagehide" || + id == "onpaste" || + id == "onpopstate" || + id == "onpause" || + id == "onplay" || + id == "onplaying" || + id == "onprogress"); + case 'r' : + return (id == "onreadystatechange" || + id == "onreset" || + id == "onresize" || + id == "onratechange"); + case 's' : + return (id == "onscroll" || + id == "onselect" || + id == "onsubmit" || + id == "onseeked" || + id == "onseeking" || + id == "onstalled" || + id == "onsuspend"); + case 't': + return id == "ontimeupdate" + /* + // TODO: Make it work for mobile version + || + (nsDOMTouchEvent::PrefEnabled() && + (id == "ontouchstart" || + id == "ontouchend" || + id == "ontouchmove" || + id == "ontouchenter" || + id == "ontouchleave" || + id == "ontouchcancel"))*/; + + case 'u' : + return id == "onunload"; + case 'v': + return id == "onvolumechange"; + case 'w': + return id == "onwaiting"; + } + + return false; +} + +// XrayWrappers miss some attributes. +// Here is a list of functions that return a value when it detects a miss: +const NODES_INDEXED_BY_NAME = ["IMG", "FORM", "APPLET", "EMBED", "OBJECT"]; +const xRayWrappersMissFixes = [ + + // Fix bug with XPCNativeWrapper on HTMLCollection + // We can only access array item once, then it's undefined :o + function (obj, name) { + let i = parseInt(name); + if (obj.toString().match(/HTMLCollection|NodeList/) && + i >= 0 && i < obj.length) { + return wrap(XPCNativeWrapper(obj.wrappedJSObject[name]), obj, name); + } + return null; + }, + + // Trap access to document["form name"] + // that may refer to an existing form node + // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#9285 + function (obj, name) { + if ("nodeType" in obj && obj.nodeType == 9) { + let node = obj.wrappedJSObject[name]; + // List of supported tag: + // http://mxr.mozilla.org/mozilla-central/source/content/html/content/src/nsGenericHTMLElement.cpp#1267 + if (node && NODES_INDEXED_BY_NAME.indexOf(node.tagName) != -1) + return wrap(XPCNativeWrapper(node)); + } + return null; + }, + + // Trap access to window["frame name"] and window.frames[i] + // that refer to an (i)frame internal window object + // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#6824 + function (obj, name) { + if (typeof obj == "object" && "document" in obj) { + // Ensure that we are on a window object + try { + obj.QueryInterface(Ci.nsIDOMWindow); + } + catch(e) { + return null; + } + + // Integer case: + let i = parseInt(name); + if (i >= 0 && i in obj) { + return wrap(XPCNativeWrapper(obj[i])); + } + + // String name case: + if (name in obj.wrappedJSObject) { + let win = obj.wrappedJSObject[name]; + let nodes = obj.document.getElementsByName(name); + for (let i = 0, l = nodes.length; i < l; i++) { + let node = nodes[i]; + if ("contentWindow" in node && node.contentWindow == win) + return wrap(node.contentWindow); + } + } + } + return null; + }, + + // Trap access to form["node name"] + // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#9477 + function (obj, name) { + if (typeof obj == "object" && obj.tagName == "FORM") { + let match = obj.wrappedJSObject[name]; + let nodes = obj.ownerDocument.getElementsByName(name); + for (let i = 0, l = nodes.length; i < l; i++) { + let node = nodes[i]; + if (node == match) + return wrap(node); + } + } + return null; + }, + + // Fix XPathResult's constants being undefined on XrayWrappers + // these constants are defined here: + // http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/xpath/nsIDOMXPathResult.idl + // and are only numbers. + // The platform bug 665279 was fixed in Gecko 10.0a1. + // FIXME: remove this workaround once the SDK no longer supports Firefox 9. + function (obj, name) { + if (typeof obj == "object" && name in Ci.nsIDOMXPathResult) { + let value = Ci.nsIDOMXPathResult[name]; + if (typeof value == "number" && value === obj.wrappedJSObject[name]) + return value; + } + return null; + } + +]; + +// XrayWrappers have some buggy methods. +// Here is the list of them with functions returning some replacement +// for a given object `obj`: +const xRayWrappersMethodsFixes = { + // postMessage method is checking the Javascript global + // and it expects it to be a window object. + // But in our case, the global object is our sandbox global object. + // See nsGlobalWindow::CallerInnerWindow(): + // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsGlobalWindow.cpp#5893 + // nsCOMPtr win = do_QueryWrappedNative(wrapper); + // win is null + postMessage: function (obj) { + // Ensure that we are on a window object + try { + obj.QueryInterface(Ci.nsIDOMWindow); + } + catch(e) { + return null; + } + // Create a wrapper that is going to call `postMessage` through `eval` + let f = function postMessage(message, targetOrigin) { + message = message.toString().replace(/['\\]/g,"\\$&"); + targetOrigin = targetOrigin.toString().replace(/['\\]/g,"\\$&"); + + let jscode = "this.postMessage('" + message + "', '" + + targetOrigin + "')"; + return this.wrappedJSObject.eval(jscode); + }; + return getProxyForFunction(f, NativeFunctionWrapper(f)); + }, + + // Fix mozMatchesSelector uses that is broken on XrayWrappers + // when we use document.documentElement.mozMatchesSelector.call(node, expr) + // It's only working if we call mozMatchesSelector on the node itself. + // SEE BUG 658909: mozMatchesSelector returns incorrect results with XrayWrappers + mozMatchesSelector: function (obj) { + // Ensure that we are on an object to expose this buggy method + try { + // Bug 707576 removed nsIDOMNSElement. + // Can be simplified as soon as Firefox 11 become the minversion + obj.QueryInterface("nsIDOMElement" in Ci ? Ci.nsIDOMElement : + Ci.nsIDOMNSElement); + } + catch(e) { + return null; + } + // We can't use `wrap` function as `f` is not a native function, + // so wrap it manually: + let f = function mozMatchesSelector(selectors) { + return this.mozMatchesSelector(selectors); + }; + + return getProxyForFunction(f, NativeFunctionWrapper(f)); + }, + + // Bug 679054: History API doesn't work with Proxy objects. We have to pass + // regular JS objects on `pushState` and `replaceState` methods. + // In addition, the first argument has to come from the same compartment. + pushState: function (obj) { + // Ensure that we are on an object that expose History API + try { + obj.QueryInterface(Ci.nsIDOMHistory); + } + catch(e) { + return null; + } + let f = function fix() { + // Call native method with JSON objects + // (need to convert `arguments` to an array via `slice`) + return this.pushState.apply(this, JSON.parse(JSON.stringify(Array.slice(arguments)))); + }; + + return getProxyForFunction(f, NativeFunctionWrapper(f)); + }, + replaceState: function (obj) { + // Ensure that we are on an object that expose History API + try { + obj.QueryInterface(Ci.nsIDOMHistory); + } + catch(e) { + return null; + } + let f = function fix() { + // Call native method with JSON objects + // (need to convert `arguments` to an array via `slice`) + return this.replaceState.apply(this, JSON.parse(JSON.stringify(Array.slice(arguments)))); + }; + + return getProxyForFunction(f, NativeFunctionWrapper(f)); + } +}; + +/* + * Generate handler for proxy wrapper + */ +function handlerMaker(obj) { + // Overloaded attributes dictionary + let overload = {}; + // Expando attributes dictionary (i.e. onclick, onfocus, on* ...) + let expando = {}; + // Cache of methods overloaded to fix XrayWrapper bug + let methodFixes = {}; + return { + // Fundamental traps + getPropertyDescriptor: function(name) { + return Object.getOwnPropertyDescriptor(obj, name); + }, + defineProperty: function(name, desc) { + return Object.defineProperty(obj, name, desc); + }, + getOwnPropertyNames: function () { + return Object.getOwnPropertyNames(obj); + }, + delete: function(name) { + delete expando[name]; + delete overload[name]; + return delete obj[name]; + }, + + // derived traps + has: function(name) { + if (name == "___proxy") return false; + if (isEventName(name)) { + // XrayWrappers throw exception when we try to access expando attributes + // even on "name in wrapper". So avoid doing it! + return name in expando; + } + return name in obj || name in overload || name == "__isWrappedProxy" || + undefined !== this.get(null, name); + }, + hasOwn: function(name) { + return Object.prototype.hasOwnProperty.call(obj, name); + }, + get: function(receiver, name) { + if (name == "___proxy") + return undefined; + + // Overload toString in order to avoid returning "[XrayWrapper [object HTMLElement]]" + // or "[object Function]" for function's Proxy + if (name == "toString") { + // Bug 714778: we should not pass obj.wrappedJSObject.toString + // in order to avoid sharing its proxy between two contents scripts. + // (not that `unwrappedObj` can be equal to `obj` when `obj` isn't + // an xraywrapper) + let unwrappedObj = XPCNativeWrapper.unwrap(obj); + return wrap(function () { + return unwrappedObj.toString.call( + this.valueOf(UNWRAP_ACCESS_KEY), arguments); + }, obj, name); + } + + // Offer a way to retrieve XrayWrapper from a proxified node through `valueOf` + if (name == "valueOf") + return function (key) { + if (key === UNWRAP_ACCESS_KEY) + return obj; + return this; + }; + + // Return overloaded value if there is one. + // It allows to overload native methods like addEventListener that + // are not saved, even on the wrapper itself. + // (And avoid some methods like toSource from being returned here! [__proto__ test]) + if (name in overload && + overload[name] != Object.getPrototypeOf(overload)[name] && + name != "__proto__") { + return overload[name]; + } + + // Catch exceptions thrown by XrayWrappers when we try to access on* + // attributes like onclick, onfocus, ... + if (isEventName(name)) { + //console.log("expando:"+obj+" - "+obj.nodeType); + return name in expando ? expando[name].original : undefined; + } + + // Overload some XrayWrappers method in order to fix its bugs + if (name in methodFixes && + methodFixes[name] != Object.getPrototypeOf(methodFixes)[name] && + name != "__proto__") + return methodFixes[name]; + if (Object.keys(xRayWrappersMethodsFixes).indexOf(name) !== -1) { + let fix = xRayWrappersMethodsFixes[name](obj); + if (fix) + return methodFixes[name] = fix; + } + + let o = obj[name]; + + // XrayWrapper miss some attributes, try to catch these and return a value + if (!o) { + for each(let atttributeFixer in xRayWrappersMissFixes) { + let fix = atttributeFixer(obj, name); + if (fix) + return fix; + } + } + + // Generic case + return wrap(o, obj, name); + + }, + + set: function(receiver, name, val) { + + if (isEventName(name)) { + //console.log("SET on* attribute : " + name + " / " + val + "/" + obj); + let shortName = name.replace(/^on/,""); + + // Unregister previously set listener + if (expando[name]) { + obj.removeEventListener(shortName, expando[name], true); + delete expando[name]; + } + + // Only accept functions + if (typeof val != "function") + return false; + + // Register a new listener + let original = val; + val = ContentScriptFunctionWrapper(val); + expando[name] = val; + val.original = original; + obj.addEventListener(name.replace(/^on/, ""), val, true); + return true; + } + + obj[name] = val; + + // Handle native method not overloaded on XrayWrappers: + // obj.addEventListener = val; -> obj.addEventlistener = native method + // And, XPCNativeWrapper bug where nested values appear to be wrapped: + // obj.customNestedAttribute = val -> obj.customNestedAttribute !== val + // obj.customNestedAttribute = "waive wrapper something" + // SEE BUG 658560: Fix identity problem with CrossOriginWrappers + // TODO: check that DOM can't be updated by the document itself and so overloaded value becomes wrong + // but I think such behavior is limited to primitive type + if ((typeof val == "function" || typeof val == "object") && name) { + overload[name] = val; + } + + return true; + }, + + enumerate: function() { + var result = []; + for each (let name in Object.keys(obj)) { + result.push(name); + }; + return result; + }, + + keys: function() { + return Object.keys(obj); + } + }; +}; + + +/* + * Wrap an object from the document to a proxy wrapper. + */ +function create(object) { + if ("wrappedJSObject" in object) + object = object.wrappedJSObject; + let xpcWrapper = XPCNativeWrapper(object); + // If we can't build an XPCNativeWrapper, it doesn't make sense to build + // a proxy. All proxy code is based on having such wrapper that store + // different JS attributes set. + // (we can't build XPCNativeWrapper when object is from the same + // principal/domain) + if (object === xpcWrapper) { + return object; + } + return getProxyForObject(xpcWrapper); +} diff --git a/tools/addon-sdk-1.7/packages/api-utils/data/test-content-symbiont.js b/tools/addon-sdk-1.7/packages/api-utils/data/test-content-symbiont.js new file mode 100644 index 0000000..65a2a21 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/data/test-content-symbiont.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// test-content-symbiont diff --git a/tools/addon-sdk-1.7/packages/api-utils/data/test-message-manager.js b/tools/addon-sdk-1.7/packages/api-utils/data/test-message-manager.js new file mode 100644 index 0000000..d647bd8 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/data/test-message-manager.js @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const TEST_VALUE = 11; + diff --git a/tools/addon-sdk-1.7/packages/api-utils/data/test-trusted-document.html b/tools/addon-sdk-1.7/packages/api-utils/data/test-trusted-document.html new file mode 100644 index 0000000..5845cf5 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/data/test-trusted-document.html @@ -0,0 +1,17 @@ + + + + + Worker test + + +

Lorem ipsum dolor sit amet.

+ + + diff --git a/tools/addon-sdk-1.7/packages/api-utils/data/worker.js b/tools/addon-sdk-1.7/packages/api-utils/data/worker.js new file mode 100644 index 0000000..aba594d --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/data/worker.js @@ -0,0 +1,247 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const ContentWorker = Object.freeze({ + // TODO: Bug 727854 Use same implementation than common JS modules, + // i.e. EventEmitter module + + /** + * Create an EventEmitter instance. + */ + createEventEmitter: function createEventEmitter(emit) { + let listeners = Object.create(null); + let eventEmitter = Object.freeze({ + emit: emit, + on: function on(name, callback) { + if (typeof callback !== "function") + return this; + if (!(name in listeners)) + listeners[name] = []; + listeners[name].push(callback); + return this; + }, + once: function once(name, callback) { + eventEmitter.on(name, function onceCallback() { + eventEmitter.removeListener(name, onceCallback); + callback.apply(callback, arguments); + }); + }, + removeListener: function removeListener(name, callback) { + if (!(name in listeners)) + return; + let index = listeners[name].indexOf(name); + if (index == -1) + return; + listeners[name].splice(index, 1); + } + }); + function onEvent(name) { + if (!(name in listeners)) + return []; + let args = Array.slice(arguments, 1); + let results = []; + for each (let callback in listeners[name]) { + results.push(callback.apply(null, args)); + } + return results; + } + function hasListenerFor(name) { + if (!(name in listeners)) + return false; + return listeners[name].length > 0; + } + return { + eventEmitter: eventEmitter, + emit: onEvent, + hasListenerFor: hasListenerFor + }; + }, + + /** + * Create an EventEmitter instance to communicate with chrome module + * by passing only strings between compartments. + * This function expects `emitToChrome` function, that allows to send + * events to the chrome module. It returns the EventEmitter as `pipe` + * attribute, and, `onChromeEvent` a function that allows chrome module + * to send event into the EventEmitter. + * + * pipe.emit --> emitToChrome + * onChromeEvent --> callback registered through pipe.on + */ + createPipe: function createPipe(emitToChrome) { + function onEvent() { + // Convert to real array + let args = Array.slice(arguments); + // JSON.stringify is buggy with cross-sandbox values, + // it may return "{}" on functions. Use a replacer to match them correctly. + function replacer(k, v) { + return typeof v === "function" ? undefined : v; + } + let str = JSON.stringify(args, replacer); + emitToChrome(str); + } + + let { eventEmitter, emit, hasListenerFor } = + ContentWorker.createEventEmitter(onEvent); + + return { + pipe: eventEmitter, + onChromeEvent: function onChromeEvent(array) { + // We either receive a stringified array, or a real array. + // We still allow to pass an array of objects, in WorkerSandbox.emitSync + // in order to allow sending DOM node reference between content script + // and modules (only used for context-menu API) + let args = typeof array == "string" ? JSON.parse(array) : array; + return emit.apply(null, args); + }, + hasListenerFor: hasListenerFor + }; + }, + + injectConsole: function injectConsole(exports, pipe) { + exports.console = Object.freeze({ + log: pipe.emit.bind(null, "console", "log"), + info: pipe.emit.bind(null, "console", "info"), + warn: pipe.emit.bind(null, "console", "warn"), + error: pipe.emit.bind(null, "console", "error"), + debug: pipe.emit.bind(null, "console", "debug"), + exception: pipe.emit.bind(null, "console", "exception"), + trace: pipe.emit.bind(null, "console", "trace") + }); + }, + + injectTimers: function injectTimers(exports, chromeAPI, pipe, console) { + // wrapped functions from `'timer'` module. + // Wrapper adds `try catch` blocks to the callbacks in order to + // emit `error` event on a symbiont if exception is thrown in + // the Worker global scope. + // @see http://www.w3.org/TR/workers/#workerutils + + // List of all living timeouts/intervals + let _timers = Object.create(null); + + // Keep a reference to original timeout functions + let { + setTimeout: chromeSetTimeout, + setInterval: chromeSetInterval, + clearTimeout: chromeClearTimeout, + clearInterval: chromeClearInterval + } = chromeAPI.timers; + + exports.setTimeout = function ContentScriptSetTimeout(callback, delay) { + let params = Array.slice(arguments, 2); + let id = chromeSetTimeout(function() { + try { + delete _timers[id]; + callback.apply(null, params); + } catch(e) { + console.exception(e); + } + }, delay); + _timers[id] = "timeout"; + return id; + }; + exports.clearTimeout = function ContentScriptClearTimeout(id) { + delete _timers[id]; + return chromeClearTimeout(id); + }; + + exports.setInterval = function ContentScriptSetInterval(callback, delay) { + let params = Array.slice(arguments, 2); + let id = chromeSetInterval(function() { + try { + callback.apply(null, params); + } catch(e) { + console.exception(e); + } + }, delay); + _timers[id] = "interval"; + return id; + }; + exports.clearInterval = function ContentScriptClearInterval(id) { + delete _timers[id]; + return chromeClearInterval(id); + }; + pipe.on("destroy", function clearTimeouts() { + // Unregister all setTimeout/setInterval on page unload + for (let id in _timers) { + let kind = _timers[id]; + if (kind == "timeout") + chromeClearTimeout(id); + else + chromeClearInterval(id); + } + }); + }, + + injectMessageAPI: function injectMessageAPI(exports, pipe) { + + let { eventEmitter: port, emit : portEmit } = + ContentWorker.createEventEmitter(pipe.emit.bind(null, "event")); + pipe.on("event", portEmit); + + let self = Object.freeze({ + port: port, + postMessage: pipe.emit.bind(null, "message"), + on: pipe.on.bind(null), + once: pipe.once.bind(null), + removeListener: pipe.removeListener.bind(null), + }); + Object.defineProperty(exports, "self", { + value: self + }); + + // Deprecated use of on/postMessage from globals + exports.postMessage = function deprecatedPostMessage() { + console.warn("The global `postMessage()` function in content " + + "scripts is deprecated in favor of the " + + "`self.postMessage()` function, which works the same. " + + "Replace calls to `postMessage()` with calls to " + + "`self.postMessage()`." + + "For more info on `self.on`, see " + + "."); + return self.postMessage.apply(null, arguments); + }; + exports.on = function deprecatedOn() { + console.warn("The global `on()` function in content scripts is " + + "deprecated in favor of the `self.on()` function, " + + "which works the same. Replace calls to `on()` with " + + "calls to `self.on()`" + + "For more info on `self.on`, see " + + "."); + return self.on.apply(null, arguments); + }; + + // Deprecated use of `onMessage` from globals + let onMessage = null; + Object.defineProperty(exports, "onMessage", { + get: function () onMessage, + set: function (v) { + if (onMessage) + self.removeListener("message", onMessage); + console.warn("The global `onMessage` function in content scripts " + + "is deprecated in favor of the `self.on()` function. " + + "Replace `onMessage = function (data){}` definitions " + + "with calls to `self.on('message', function (data){})`. " + + "For more info on `self.on`, see " + + "."); + onMessage = v; + if (typeof onMessage == "function") + self.on("message", onMessage); + } + }); + }, + + inject: function (exports, chromeAPI, emitToChrome) { + let { pipe, onChromeEvent, hasListenerFor } = + ContentWorker.createPipe(emitToChrome); + ContentWorker.injectConsole(exports, pipe); + ContentWorker.injectTimers(exports, chromeAPI, pipe, exports.console); + ContentWorker.injectMessageAPI(exports, pipe); + return { + emitToContent: onChromeEvent, + hasListenerFor: hasListenerFor + }; + } +}); diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/api-utils.md b/tools/addon-sdk-1.7/packages/api-utils/docs/api-utils.md new file mode 100644 index 0000000..aee88da --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/api-utils.md @@ -0,0 +1,157 @@ + + + + + +The `api-utils` module provides some helpers useful to the SDK's high-level API +implementations. + +Introduction +------------ + +The SDK high-level API design guidelines make a number of recommendations. +This module implements some of those patterns so that your own implementations +don't need to reinvent them. + +For example, public constructors should be callable both with and without the +`new` keyword. Your module can implement this recommendation using the +`publicConstructor` function. + +Options objects or "dictionaries" are also common throughout the high-level +APIs. The guidelines recommend that public constructors should generally define +a single `options` parameter rather than defining many parameters. Since one of +the SDK's principles is to be friendly to developers, ideally all properties on +options dictionaries should be checked for correct type, and informative error +messages should be generated when clients make mistakes. With the +`validateOptions` function, your module can easily do so. + +And objects are sometimes iterable over a custom set of key/value pairs. +Such objects should have custom iterators that let consumers iterate keys, +values, or [key, value] pairs. The `addIterator` function makes it easy to do +so in a way that is consistent with the behavior of default iterators during +`for...in`, `for each...in`, and `for...in Iterator()` loops. + + +@function +Returns a function *C* that creates an instance of `privateConstructor`. *C* +may be called with or without the `new` keyword. + +The prototype of each instance returned from *C* is *C*.`prototype`, and +*C*.`prototype` is an object whose prototype is +`privateConstructor.prototype`. Instances returned from *C* are therefore +instances of both *C* and `privateConstructor`. + +Additionally, the constructor of each instance returned from *C* is *C*. + +Instances returned from *C* are automatically memory tracked using +`memory.track` under the bin name `privateConstructor.name`. + +**Example** + + function MyObject() {} + exports.MyObject = apiUtils.publicConstructor(MyObject); + +@returns {function} +A function that makes new instances of `privateConstructor`. + +@param privateConstructor {constructor} + + + +@function +A function to validate an options dictionary according to the specified +constraints. + +`map`, `is`, and `ok` are used in that order. + +The return value is an object whose keys are those keys in `requirements` that +are also in `options` and whose values are the corresponding return values of +`map` or the corresponding values in `options`. Note that any keys not shared +by both `requirements` and `options` are not in the returned object. + +**Examples** + +A typical use: + + var opts = { foo: 1337 }; + var requirements = { + foo: { + map: function (val) val.toString(), + is: ["string"], + ok: function (val) val.length > 0, + msg: "foo must be a non-empty string." + } + }; + var validatedOpts = apiUtils.validateOptions(opts, requirements); + // validatedOpts == { foo: "1337" } + +If the key `foo` is optional and doesn't need to be mapped: + + var opts = { foo: 1337 }; + var validatedOpts = apiUtils.validateOptions(opts, { foo: {} }); + // validatedOpts == { foo: 1337 } + + opts = {}; + validatedOpts = apiUtils.validateOptions(opts, { foo: {} }); + // validatedOpts == {} + +@returns {object} +A validated options dictionary given some requirements. If any of the +requirements are not met, an exception is thrown. + +@param options {object} +The options dictionary to validate. It's not modified. If it's null or +otherwise falsey, an empty object is assumed. + +@param requirements {object} +An object whose keys are the expected keys in `options`. Any key in +`options` that is not present in `requirements` is ignored. Each +value in `requirements` is itself an object describing the requirements +of its key. The keys of that object are the following, and each is optional: + +@prop [map] {function} +A function that's passed the value of the key in the `options`. `map`'s +return value is taken as the key's value in the final validated options, +`is`, and `ok`. If `map` throws an exception it is caught and discarded, +and the key's value is its value in `options`. + +@prop [is] {array} +An array containing the number of `typeof` type names. If the key's value is +none of these types it fails validation. Arrays and nulls are identified by +the special type names "array" and "null"; "object" will not match either. +No type coercion is done. + +@prop [ok] {function} +A function that is passed the key's value. If it returns false, the value +fails validation. + +@prop [msg] {string} +If the key's value fails validation, an exception is thrown. This string +will be used as its message. If undefined, a generic message is used, unless +`is` is defined, in which case the message will state that the value needs to +be one of the given types. + + + +@function +Adds an iterator to the specified object that iterates keys, values, +or [key, value] pairs depending on how it is invoked, i.e.: + + for (var key in obj) { ... } // iterate keys + for each (var val in obj) { ... } // iterate values + for (var [key, val] in Iterator(obj)) { ... } // iterate pairs + +If your object only iterates either keys or values, you don't need this +function. Simply assign a generator function that iterates the keys/values +to your object's `__iterator__` property instead, f.e.: + + obj.__iterator__ = function () { for each (var i in items) yield i; } + +@param obj {object} +the object to which to add the iterator + +@param keysValsGen {function} +a generator function that yields [key, value] pairs + diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/app-strings.md b/tools/addon-sdk-1.7/packages/api-utils/docs/app-strings.md new file mode 100644 index 0000000..c40ddaf --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/app-strings.md @@ -0,0 +1,65 @@ + + +The `app-strings` module gives you access to the host application's localized +string bundles (`.properties` files). + +The module exports the `StringBundle` constructor function. To access a string +bundle, construct an instance of `StringBundle`, passing it the bundle's URL: + + var StringBundle = require("app-strings").StringBundle; + var bundle = StringBundle("chrome://browser/locale/browser.properties"); + +To get the value of a string, call the object's `get` method, passing it +the name of the string: + + var accessKey = bundle.get("contextMenuSearchText.accesskey"); + // "S" in the en-US locale + +To get the formatted value of a string that accepts arguments, call the object's +`get` method, passing it the name of the string and an array of arguments +with which to format the string: + + var searchText = bundle.get("contextMenuSearchText", + ["universe", "signs of intelligent life"]); + // 'Search universe for "signs of intelligent life"' in the en-US locale + +To get all strings in the bundle, iterate the object, which returns arrays +of the form [name, value]: + + for (var [name, value] in Iterator(bundle)) + console.log(name + " = " + value); + +Iteration +--------- + +for (var name in bundle) { ... } + +Iterate the names of strings in the bundle. + +for each (var val in bundle) { ... } + +Iterate the values of strings in the bundle. + +for (var [name, value] in Iterator(bundle)) { ... } + +Iterate the names and values of strings in the bundle. + + + +@class +The `StringBundle` object represents a string bundle. + +@constructor +Creates a StringBundle object that gives you access to a string bundle. +@param url {string} the URL of the string bundle +@returns {StringBundle} the string bundle + + +@method Get the value of the string with the given name. +@param [name] {string} the name of the string to get +@param [args] {array} (optional) strings that replace placeholders in the string +@returns {string} the value of the string + + diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/base.md b/tools/addon-sdk-1.7/packages/api-utils/docs/base.md new file mode 100644 index 0000000..7a694f2 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/base.md @@ -0,0 +1,207 @@ + + +### Inheritance ### + +Doing [inheritance in JavaScript](https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript) +is both verbose and painful. Reading or writing such code requires requires +sharp eye and lot's of discipline, mainly due to code fragmentation and lots of +machinery exposed: + + // Defining a simple Class + function Dog(name) { + // Classes are for creating instances, calling them without `new` changes + // behavior, which in majority cases you need to handle, so you end up + // with additional boilerplate. + if (!(this instanceof Dog)) return new Dog(name); + + this.name = name; + }; + // To define methods you need to make a dance with a special 'prototype' + // property of the constructor function. This is too much machinery exposed. + Dog.prototype.type = 'dog'; + Dog.prototype.bark = function bark() { + return 'Ruff! Ruff!' + }; + + // Subclassing a `Dog` + function Pet(name, breed) { + // Once again we do our little dance + if (!(this instanceof Pet)) return new Pet(name, breed); + + Dog.call(this, name); + this.breed = breed; + } + // To subclass, you need to make another special dance with special + // 'prototype' properties. + Pet.prototype = Object.create(Dog.prototype); + // If you want correct instanceof behavior you need to make a dance with + // another special `constructor` property of the `prototype` object. + Object.defineProperty(Pet.prototype, 'contsructor', { value: Pet }); + // Finally you can define some properties. + Pet.prototype.call = function(name) { + return this.name === name ? this.bark() : ''; + }; + +An "exemplar" is a factory for instances. Usually exemplars are defined as +(constructor) functions as in examples above. But that does not necessary has +to be the case. Prototype (object) can form far more simpler exemplars. After +all what could be more object oriented than objects that inherit from objects. + + var Dog = { + new: function(name) { + var instance = Object.create(this); + this.initialize.apply(instance, arguments); + return instance; + }, + initialize: function initialize(name) { + this.name = name; + }, + type: 'dog', + bark: function bark() { + return 'Ruff! Ruff!' + } + }; + var fluffy = Dog.new('fluffy'); + + + var Pet = Object.create(Dog); + Pet.initialize = function initialize(name, breed) { + Dog.initialize.call(this, name); + this.breed = breed; + }; + Pet.call = function call(name) { + return this.name === name ? this.bark() : ''; + }; + +While this small trick solves some readability issues, there are still more. To +address them this module exports `Base` exemplar with few methods predefined: + + var Dog = Base.extend({ + initialize: function initialize(name) { + this.name = name; + }, + type: 'dog', + bark: function bark() { + return 'Ruff! Ruff!' + } + }); + + var Pet = Dog.extend({ + initialize: function initialize(name, breed) { + Dog.initialize.call(this, name); + this.breed = breed; + }, + function call(name) { + return this.name === name ? this.bark() : ''; + } + }); + + var fluffy = Dog.new('fluffy'); + dog.bark(); // 'Ruff! Ruff!' + Dog.isPrototypeOf(fluffy); // true + Pet.isPrototypeOf(fluffy); // true + +### Composition ### + +Even though (single) inheritance is very powerful it's not always enough. +Sometimes it's more useful suitable to define reusable pieces of functionality +and then compose bigger pieces out of them: + + var HEX = Base.extend({ + hex: function hex() { + return '#' + this.color + } + }) + + var RGB = Base.extend({ + red: function red() { + return parseInt(this.color.substr(0, 2), 16) + }, + green: function green() { + return parseInt(this.color.substr(2, 2), 16) + }, + blue: function blue() { + return parseInt(this.color.substr(4, 2), 16) + } + }) + + var CMYK = Base.extend(RGB, { + black: function black() { + var color = Math.max(Math.max(this.red(), this.green()), this.blue()) + return (1 - color / 255).toFixed(4) + }, + magenta: function magenta() { + var K = this.black(); + return (((1 - this.green() / 255).toFixed(4) - K) / (1 - K)).toFixed(4) + }, + yellow: function yellow() { + var K = this.black(); + return (((1 - this.blue() / 255).toFixed(4) - K) / (1 - K)).toFixed(4) + }, + cyan: function cyan() { + var K = this.black(); + return (((1 - this.red() / 255).toFixed(4) - K) / (1 - K)).toFixed(4) + } + }) + + // Composing `Color` prototype out of reusable components: + var Color = Base.extend(HEX, RGB, CMYK, { + initialize: function initialize(color) { + this.color = color + } + }) + + var pink = Color.new('FFC0CB') + // RGB + pink.red() // 255 + pink.green() // 192 + pink.blue() // 203 + + // CMYK + pink.magenta() // 0.2471 + pink.yellow() // 0.2039 + pink.cyan() // 0.0000 + +### Combining composition & inheritance ### + +Also it's easy to mix composition with inheritance: + + var Pixel = Color.extend({ + initialize: function initialize(x, y, color) { + Color.initialize.call(this, color) + this.x = x + this.y = y + }, + toString: function toString() { + return this.x + ':' + this.y + '@' + this.hex() + } + }); + + var pixel = Pixel.new(11, 23, 'CC3399'); + pixel.toString() // 11:23@#CC3399 + Pixel.isPrototypeOf(pixel) // true + + // Pixel instances inhertis from `Color` + Color.isPrototypeOf(pixel); // true + + // In fact `Pixel` itself inherits from `Color`, remember just simple and + // pure prototypal inheritance where object inherit from objects. + Color.isPrototypeOf(Pixel); // true + +### Classes ### + +Module exports `Class` function. `Class` takes argument of exemplar object +extending `Base` and returns `constructor` function that can be used for +simulating classes defined by given exemplar. + + var CPixel = Class(Pixel); + var pixel = CPixel(11, 12, '000000'); + pixel instanceof CPixel // true + Pixel.prototypeOf(pixel); // true + + // Use of `new` is optional, but possible. + var p2 = CPixel(17, 2, 'cccccc'); + p2 instanceof CPixel // true + p2.prototypeOf(pixel); // true diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/byte-streams.md b/tools/addon-sdk-1.7/packages/api-utils/docs/byte-streams.md new file mode 100644 index 0000000..1238cd8 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/byte-streams.md @@ -0,0 +1,68 @@ + + + + + +The `byte-streams` module provides streams for reading and writing bytes. + + +@class + +@constructor + Creates a binary input stream that reads bytes from a backing stream. +@param inputStream {stream} + The backing stream, an nsIInputStream. + + +@property {boolean} + True if the stream is closed. + + + +@method + Closes both the stream and its backing stream. If the stream is already + closed, an exception is thrown. + + + +@method + Reads a string from the stream. If the stream is closed, an exception is + thrown. +@param [numBytes] {number} + The number of bytes to read. If not given, the remainder of the entire stream + is read. +@returns {string} + A string containing the bytes read. If the stream is at the end, returns the + empty string. + + + + +@class + +@constructor + Creates a binary output stream that writes bytes to a backing stream. +@param outputStream {stream} + The backing stream, an nsIOutputStream. + + +@property {boolean} + True if the stream is closed. + + +@method + Closes both the stream and its backing stream. If the stream is already + closed, an exception is thrown. + + +@method + Writes a string to the stream. If the stream is closed, an exception is + thrown. +@param str {string} + The string to write. + + diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/collection.md b/tools/addon-sdk-1.7/packages/api-utils/docs/collection.md new file mode 100644 index 0000000..1e557c6 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/collection.md @@ -0,0 +1,77 @@ + + + + + +The `collection` module provides a simple list-like class and utilities for +using it. A collection is ordered, like an array, but its items are unique, +like a set. + + +@class +A collection object provides for...in-loop iteration. Items are yielded in the +order they were added. For example, the following code... + + var collection = require("collection"); + var c = new collection.Collection(); + c.add(1); + c.add(2); + c.add(3); + for (item in c) + console.log(item); + +... would print this to the console: + +
+  1
+  2
+  3
+
+ +Iteration proceeds over a copy of the collection made before iteration begins, +so it is safe to mutate the collection during iteration; doing so does not +affect the results of the iteration. + + +@constructor +Creates a new collection. The collection is backed by an array. +@param [array] {array} +If *array* is given, it will be used as the backing array. This way the caller +can fully control the collection. Otherwise a new empty array will be used, and +no one but the collection will have access to it. + + +@property {number} +The number of items in the collection array. + + +@method +Adds a single item or an array of items to the collection. Any items already +contained in the collection are ignored. +@param itemOrItems {object} An item or array of items. +@returns {Collection} The Collection. + + +@method +Removes a single item or an array of items from the collection. Any items not +contained in the collection are ignored. +@param itemOrItems {object} An item or array of items. +@returns {Collection} The Collection. + +
+ + +@function +Adds a collection property to the given object. Setting the property to a +scalar value empties the collection and adds the value. Setting it to an array +empties the collection and adds all the items in the array. +@param object {object} +The property will be defined on this object. +@param propName {string} +The name of the property. +@param [backingArray] {array} +If given, this will be used as the collection's backing array. + + diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/content.md b/tools/addon-sdk-1.7/packages/api-utils/docs/content.md new file mode 100644 index 0000000..1c25eb4 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/content.md @@ -0,0 +1,15 @@ + + + + +The `content` module exports three different traits [Loader][], [Worker][] and +[Symbiont][]. None of this traits is intended to be used directly by programs. +Rather, they are intended to be used by other modules that provide high +level APIs to programs or libraries. + +[Loader]:packages/api-utils/content/loader.html +[Worker]:packages/api-utils/content/worker.html +[Symbiont]:packages/api-utils/content/symbiont.html + diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/content/loader.md b/tools/addon-sdk-1.7/packages/api-utils/docs/content/loader.md new file mode 100644 index 0000000..a460476 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/content/loader.md @@ -0,0 +1,92 @@ + + + + +Loader is base trait and it provides set of core properties and associated +validations. Trait is useful for all the compositions providing high level +APIs for creating JavaScript contexts that can access web content. + +Loader is composed from the +[EventEmitter](packages/api-utils/events.html) trait, therefore +instances of Loader and their descendants expose all the public properties +exposed by EventEmitter along with additional public properties: + +Value changes on all of the above mentioned properties emit `propertyChange` +events on an instances. + +**Example:** + +The following code creates a wrapper on hidden frame that reloads a web page +in frame every time `contentURL` property is changed: + + var hiddenFrames = require("hidden-frame"); + var { Loader } = require("content"); + var PageLoader = Loader.compose({ + constructor: function PageLoader(options) { + options = options || {}; + if (options.contentURL) + this.contentURL = options.contentURL; + this.on('propertyChange', this._onChange = this._onChange.bind(this)); + let self = this; + hiddenFrames.add(hiddenFrames.HiddenFrame({ + onReady: function onReady() { + let frame = self._frame = this.element; + self._emit('propertyChange', { contentURL: self.contentURL }); + } + })); + }, + _onChange: function _onChange(e) { + if ('contentURL' in e) + this._frame.setAttribute('src', this._contentURL); + } + }); + + +@class + +@property {array} +The local file URLs of content scripts to load. Content scripts specified by +this property are loaded *before* those specified by the `contentScript` +property. + + + +@property {array} +The texts of content scripts to load. Content scripts specified by this +property are loaded *after* those specified by the `contentScriptFile` property. + + + +@property {string} +When to load the content scripts. This may take one of the following +values: + +* "start": load content scripts immediately after the document +element for the page is inserted into the DOM, but before the DOM content +itself has been loaded +* "ready": load content scripts once DOM content has been loaded, +corresponding to the +[DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) +event +* "end": load content scripts once all the content (DOM, JS, CSS, +images) for the page has been loaded, at the time the +[window.onload event](https://developer.mozilla.org/en/DOM/window.onload) +fires + + + + +@property {string} +The URL of the content loaded. + + + +@property {object} +Permissions for the content, with the following keys: +@prop script {boolean} + Whether or not to execute script in the content. Defaults to true. + + + diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/content/proxy.md b/tools/addon-sdk-1.7/packages/api-utils/docs/content/proxy.md new file mode 100644 index 0000000..095e8ff --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/content/proxy.md @@ -0,0 +1,241 @@ + + + + +Content scripts need access to the DOM of the pages they are attached to. +However, those pages should be considered to be hostile environments: we +have no control over any other scripts loaded by the web page that may be +executing in the same context. If the content scripts and scripts loaded +by the web page were to access the same DOM objects, there are two possible +security problems: + +First, a malicious page might redefine functions and properties of DOM +objects so they don't do what the add-on expects. For example, if a +content script calls `document.getElementById()` to retrieve a DOM +element, then a malicious page could redefine its behavior to return +something unexpected: + +

+// If the web document contains the following script:
+document.getElementById = function (str) {
+  // Overload indexOf method of all string instances
+  str.__proto__.indexOf = function () {return -1;};
+  // Overload toString method of all object instances
+  str.__proto__.__proto__.toString = function () {return "evil";};
+};
+// After the following line, the content script will be compromised:
+var node = document.getElementById("element");
+// Then your content script is totally out of control.
+
+ +Second, changes the content script made to the DOM objects would be visible +to the page, leaking information to it. + +The general approach to fixing these problems is to wrap DOM objects in +[`XrayWrappers`](https://developer.mozilla.org/en/XPCNativeWrapper) +(also know as `XPCNativeWrapper`). This guarantees that: + +* when the content script accesses DOM properties and functions it gets the +original native version of them, ignoring any modifications made by the web +page +* changes to the DOM made by the content script are not visible to scripts +running in the page. + +However, `XrayWrapper` has some limitations and bugs, which break many +popular web frameworks. In particular, you can't: + +* define attributes like `onclick`: you have to use `addEventListener` syntax +* overload native methods on DOM objects, like this: +

+proxy.addEventListener = function () {};
+
+* access named elements using properties like `window[framename]` or +`document[formname]` +* use some other features that have bugs in the `XrayWrapper` +implementation, like `mozMatchesSelector` + +The `proxy` module uses `XrayWrapper` in combination with the +experimental +[Proxy API](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Proxy) +to address both the security vulnerabilities of content scripts and the +limitations of `XrayWrapper`. + +
+  /--------------------\                           /------------------------\
+  |    Web document    |                           | Content script sandbox |
+  | http://mozilla.org |                           |     data/worker.js     |
+  |                    | require('content-proxy'). |                        |
+  | window >-----------|-     create(window)      -|-> window               |
+  \--------------------/                           \------------------------/
+
+ + +## The Big Picture ## + +The implementation defines two different kinds of proxy: + + 1. Content script proxies that wrap DOM objects that are exposed to + content scripts as described above. + 2. XrayWrapper proxies that wrap objects from content scripts before handing + them over to XrayWrapper functions. These proxies are internal + and are not exposed to content scripts or document content. + +
+  /--------------------\                           /------------------------\
+  |    Web document    |                           | Content script sandbox |
+  | http://mozilla.org |                           |     data/worker.js     |
+  |                    |                   /-------|-> myObject = {}        |
+  |                    |  /----------------v--\    |                        |
+  |                    |  | XrayWrapper Proxy |    | - document             |
+  |                    |  \---------v---------/    \----^-------------------/
+  |                    |            v                   |
+  |                    |  /-------------\  /----------\ |
+  | - document >-------|->| XrayWrapper |<-| CS proxy |-/
+  \--------------------/  \-------------/  \----------/
+
+ +Everything begins with a single call to the `create` function exported by the +content-proxy module: + + // Retrieve the unwrapped reference to the current web page window object + var win = gBrowser.contentDocument.defaultView.wrappedJSObject; + // Or in addon sdk style + var win = require("tab-browser").activeTab.linkedBrowser.contentWindow.wrappedJSObject; + // Now create a content script proxy for the window object + var windowProxy = require("api-utils/content/content-proxy").create(win); + + // We finally use this window object as sandbox prototype, + // so that all web page globals are accessible in CS too: + var contentScriptSandbox = new Cu.Sandbox(win, { + sandboxPrototype: windowProxy + }); + +Then all other proxies are created from this one. Attempts to access DOM +attributes of this proxy are trapped, and the proxy constructs and returns +content script proxies for those attributes: + + // For example, if you simply do this: + var document = window.document; + // accessing the `document` attribute will be trapped by the `window` content script + // proxy, and that proxy will that create another content script proxy for `document` + +So the main responsibility of the content script proxy implementation is to +ensure that we always return content script proxies to the content script. + +## Internal Implementation ## + +Each content script proxy keeps a reference to the `XrayWrapper` that enables +it to be sure of calling native DOM methods. + +There are two internal functions to convert between content script proxy +values and `XrayWrapper` values. + +1. __`wrap`__ takes an XrayWrapper value and wraps it in a content script +proxy if needed. + This method is called when: + * a content script accesses an attribute of a content script proxy. + * XrayWrapper code calls a callback function defined in the content +script, so that arguments passed into the function by the XrayWrapper are +converted into content script proxies. For example, if a content script +calls `addEventListener`, then the listener function will expect any arguments +to be content script proxies. +

+2. __`unwrap`__ takes an object coming from the content script context and: + * if the object is a content script proxy, unwraps it back to an +XrayWrapper reference + * if the object is not a content script proxy, wraps it in an XrayWrapper +proxy. +

+This means we can call a XrayWrapper method either with: + + * a raw XrayWrapper object. + + // The following line doesn't work if child is a content script proxy, + // it has to be a raw XrayWrapper reference + xrayWrapper.appendChild(child) + + * an XrayWrapper proxy when you pass a custom object from the content +script context. + + var myListener = { + handleEvent: function(event) { + // `event` should be a content script proxy + } + }; + // `myListener` has to be another kind of Proxy: XrayWrapper proxy, + // that aims to catch the call to `handleEvent` in order to wrap its + // arguments in a content script proxy. + xrayWrapper.addEventListener("click", myListener, false); + + +## Stack Traces ## + +The following code: + + function listener(event) { + + } + csProxy.addEventListener("message", listener, false); + +generates the following internal calls: + + -> CS Proxy:: get("addEventListener") + -> wrap(xrayWrapper.addEventListener) + -> NativeFunctionWrapper(xrayWrapper.addEventListener) + // NativeFunctionWrapper generates: + function ("message", listener, false) { + return xraywrapper.addEventListener("message", unwrap(listener), false); + } + -> unwrap(listener) + -> ContentScriptFunctionWrapper(listener) + // ContentScriptFunctionWrapper generates: + function (event) { + return listener(wrap(event)); + } + +
+ + // First, create an object from content script context + var myListener = { + handleEvent: function (event) { + + } + }; + // Then, pass this object as an argument to a CS proxy method + window.addEventListener("message", myListener, false); + + // Generates the following internal calls: + -> CS Proxy:: get("addEventListener") + -> wrap(xrayWrapper.addEventListener) + -> NativeFunctionWrapper(xrayWrapper.addEventListener) + // Generate the following function: + function ("message", myListener, false) { + return xraywrapper.addEventListener("message", unwrap(myListener), false); + } + -> unwrap(myListener) + -> ContentScriptObjectWrapper(myListener) + // Generate an XrayWrapper proxy and give it to xrayWrapper method. + // Then when native code fires an event, the proxy will catch it: + -> XrayWrapper Proxy:: get("handleEvent") + -> unwrap(myListener.handleEvent) + -> ContentScriptFunctionWrapper(myListener.handleEvent) + // Generate following function: + function (event) { + return myListener.handleEvent(wrap(event)); + } + + + +@function + Create a content script proxy.
+ Doesn't create a proxy if we are not able to create a XrayWrapper for + this object: for example, if the object comes from system principal. + +@param object {Object} + The object to proxify. + +@returns {Object} + A content script proxy that wraps `object`. +
diff --git a/tools/addon-sdk-1.7/packages/api-utils/docs/content/symbiont.md b/tools/addon-sdk-1.7/packages/api-utils/docs/content/symbiont.md new file mode 100644 index 0000000..1ff7dd1 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/docs/content/symbiont.md @@ -0,0 +1,140 @@ + + + + + + +This module is not intended to be used directly by programs. Rather, it is +intended to be used by other modules that provide APIs to programs. + + +This module exports `Symbiont` trait that can be used for creating JavaScript +contexts that can access web content in host application frames (i.e. XUL +`