mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-02 05:17:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
29
addon-sdk/Makefile.in
Normal file
29
addon-sdk/Makefile.in
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TESTADDONS = source/test/addons
|
||||
ADDONSRC = $(srcdir)/$(TESTADDONS)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# This can switch to just zipping the files when native jetpacks land
|
||||
%.xpi: FORCE
|
||||
$(PYTHON) $(srcdir)/source/bin/cfx xpi --no-strip-xpi --pkgdir=$(ADDONSRC)/$* --output-file=$@
|
||||
|
||||
TEST_FILES = \
|
||||
$(srcdir)/source/app-extension \
|
||||
$(srcdir)/source/bin \
|
||||
$(srcdir)/source/python-lib \
|
||||
$(srcdir)/source/test \
|
||||
$(srcdir)/source/package.json \
|
||||
$(srcdir)/source/mapping.json \
|
||||
$(NULL)
|
||||
|
||||
# Remove this once the test harness uses the APIs built into Firefox
|
||||
TEST_FILES += $(srcdir)/source/lib
|
||||
|
||||
PKG_STAGE = $(DIST)/test-stage
|
||||
|
||||
stage-tests-package:: $(TEST_FILES)
|
||||
$(INSTALL) $^ $(PKG_STAGE)/jetpack
|
||||
107
addon-sdk/mach_commands.py
Normal file
107
addon-sdk/mach_commands.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Integrates the xpcshell test runner with mach.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
|
||||
import mozpack.path as mozpath
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
)
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command('generate-addon-sdk-moz-build', category='misc',
|
||||
description='Generates the moz.build file for the addon-sdk/ directory.')
|
||||
def run_addon_sdk_moz_build(self, **params):
|
||||
addon_sdk_dir = mozpath.join(self.topsrcdir, 'addon-sdk')
|
||||
js_src_dir = mozpath.join(addon_sdk_dir, 'source/lib')
|
||||
dirs_to_files = {}
|
||||
|
||||
for path, dirs, files in os.walk(js_src_dir):
|
||||
js_files = [f for f in files if f.endswith(('.js', '.jsm', '.html'))]
|
||||
if not js_files:
|
||||
continue
|
||||
|
||||
relative = mozpath.relpath(path, js_src_dir)
|
||||
dirs_to_files[relative] = js_files
|
||||
|
||||
moz_build = """# AUTOMATICALLY GENERATED FROM mozbuild.template AND mach. DO NOT EDIT.
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
%(moz-build-template)s
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
|
||||
%(non-b2g-modules)s
|
||||
%(always-on-modules)s"""
|
||||
|
||||
non_b2g_paths = [
|
||||
'method/test',
|
||||
'sdk/ui',
|
||||
'sdk/ui/button',
|
||||
'sdk/ui/sidebar',
|
||||
'sdk/places',
|
||||
'sdk/places/host',
|
||||
'sdk/tabs',
|
||||
'sdk/panel',
|
||||
'sdk/frame',
|
||||
'sdk/test',
|
||||
'sdk/window',
|
||||
'sdk/windows',
|
||||
'sdk/deprecated',
|
||||
]
|
||||
|
||||
non_b2g_modules = []
|
||||
always_on_modules = []
|
||||
|
||||
for d, files in sorted(dirs_to_files.items()):
|
||||
if d in non_b2g_paths:
|
||||
non_b2g_modules.append((d, files))
|
||||
else:
|
||||
always_on_modules.append((d, files))
|
||||
|
||||
def list_to_js_modules(l, indent=''):
|
||||
js_modules = []
|
||||
for d, files in l:
|
||||
if d == '':
|
||||
module_path = ''
|
||||
dir_path = ''
|
||||
else:
|
||||
# Ensure that we don't have things like:
|
||||
# EXTRA_JS_MODULES.commonjs.sdk.private-browsing
|
||||
# which would be a Python syntax error.
|
||||
path = d.split('/')
|
||||
module_path = ''.join('.' + p if p.find('-') == -1 else "['%s']" % p for p in path)
|
||||
dir_path = d + '/'
|
||||
filelist = ["'source/lib/%s%s'" % (dir_path, f)
|
||||
for f in sorted(files, key=lambda x: x.lower())]
|
||||
js_modules.append("EXTRA_JS_MODULES.commonjs%s += [\n %s,\n]\n"
|
||||
% (module_path, ',\n '.join(filelist)))
|
||||
stringified = '\n'.join(js_modules)
|
||||
# This isn't the same thing as |js_modules|, since |js_modules| had
|
||||
# embedded newlines.
|
||||
lines = stringified.split('\n')
|
||||
# Indent lines while avoiding trailing whitespace.
|
||||
lines = [indent + line if line else line for line in lines]
|
||||
return '\n'.join(lines)
|
||||
|
||||
moz_build_output = mozpath.join(addon_sdk_dir, 'moz.build')
|
||||
moz_build_template = mozpath.join(addon_sdk_dir, 'mozbuild.template')
|
||||
with open(moz_build_output, 'w') as f, open(moz_build_template, 'r') as t:
|
||||
substs = { 'moz-build-template': t.read(),
|
||||
'non-b2g-modules': list_to_js_modules(non_b2g_modules,
|
||||
indent=' '),
|
||||
'always-on-modules': list_to_js_modules(always_on_modules) }
|
||||
f.write(moz_build % substs)
|
||||
542
addon-sdk/moz.build
Normal file
542
addon-sdk/moz.build
Normal file
|
|
@ -0,0 +1,542 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=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/.
|
||||
|
||||
# Makefile.in uses a misc target through test_addons_TARGET.
|
||||
HAS_MISC_RULE = True
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
JETPACK_PACKAGE_MANIFESTS += ['source/test/jetpack-package.ini',
|
||||
'source/test/leak/jetpack-package.ini']
|
||||
JETPACK_ADDON_MANIFESTS += ['source/test/addons/jetpack-addon.ini']
|
||||
|
||||
DIRS += ['source/test/fixtures']
|
||||
|
||||
addons = [
|
||||
'addon-manager',
|
||||
'author-email',
|
||||
'child_process',
|
||||
'chrome',
|
||||
'content-permissions',
|
||||
'content-script-messages-latency',
|
||||
'contributors',
|
||||
'curly-id',
|
||||
'developers',
|
||||
'e10s-content',
|
||||
'e10s-l10n',
|
||||
'e10s-remote',
|
||||
'e10s-tabs',
|
||||
'e10s',
|
||||
'embedded-webextension',
|
||||
'l10n-properties',
|
||||
'l10n',
|
||||
'layout-change',
|
||||
'main',
|
||||
'name-in-numbers-plus',
|
||||
'name-in-numbers',
|
||||
'packaging',
|
||||
'packed',
|
||||
'page-mod-debugger-post',
|
||||
'page-mod-debugger-pre',
|
||||
'page-worker',
|
||||
'places',
|
||||
'predefined-id-with-at',
|
||||
'preferences-branch',
|
||||
'private-browsing-supported',
|
||||
'remote',
|
||||
'require',
|
||||
'self',
|
||||
'simple-prefs-l10n',
|
||||
'simple-prefs-regression',
|
||||
'simple-prefs',
|
||||
'standard-id',
|
||||
'tab-close-on-startup',
|
||||
'toolkit-require-reload',
|
||||
'translators',
|
||||
'unsafe-content-script',
|
||||
]
|
||||
|
||||
addons = ['%s.xpi' % f for f in addons]
|
||||
GENERATED_FILES += addons
|
||||
|
||||
TEST_HARNESS_FILES.testing.mochitest['jetpack-addon']['addon-sdk'].source.test.addons += [
|
||||
'!%s' % f for f in addons
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.sdk += [
|
||||
'source/app-extension/bootstrap.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.sdk.system += [
|
||||
'source/modules/system/Startup.js',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
|
||||
EXTRA_JS_MODULES.commonjs.method.test += [
|
||||
'source/lib/method/test/browser.js',
|
||||
'source/lib/method/test/common.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.deprecated += [
|
||||
'source/lib/sdk/deprecated/api-utils.js',
|
||||
'source/lib/sdk/deprecated/sync-worker.js',
|
||||
'source/lib/sdk/deprecated/unit-test-finder.js',
|
||||
'source/lib/sdk/deprecated/unit-test.js',
|
||||
'source/lib/sdk/deprecated/window-utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.frame += [
|
||||
'source/lib/sdk/frame/hidden-frame.js',
|
||||
'source/lib/sdk/frame/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.panel += [
|
||||
'source/lib/sdk/panel/events.js',
|
||||
'source/lib/sdk/panel/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.places += [
|
||||
'source/lib/sdk/places/bookmarks.js',
|
||||
'source/lib/sdk/places/contract.js',
|
||||
'source/lib/sdk/places/events.js',
|
||||
'source/lib/sdk/places/favicon.js',
|
||||
'source/lib/sdk/places/history.js',
|
||||
'source/lib/sdk/places/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.places.host += [
|
||||
'source/lib/sdk/places/host/host-bookmarks.js',
|
||||
'source/lib/sdk/places/host/host-query.js',
|
||||
'source/lib/sdk/places/host/host-tags.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.tabs += [
|
||||
'source/lib/sdk/tabs/common.js',
|
||||
'source/lib/sdk/tabs/events.js',
|
||||
'source/lib/sdk/tabs/helpers.js',
|
||||
'source/lib/sdk/tabs/namespace.js',
|
||||
'source/lib/sdk/tabs/observer.js',
|
||||
'source/lib/sdk/tabs/tab-fennec.js',
|
||||
'source/lib/sdk/tabs/tab-firefox.js',
|
||||
'source/lib/sdk/tabs/tab.js',
|
||||
'source/lib/sdk/tabs/tabs-firefox.js',
|
||||
'source/lib/sdk/tabs/utils.js',
|
||||
'source/lib/sdk/tabs/worker.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.test += [
|
||||
'source/lib/sdk/test/assert.js',
|
||||
'source/lib/sdk/test/harness.js',
|
||||
'source/lib/sdk/test/httpd.js',
|
||||
'source/lib/sdk/test/loader.js',
|
||||
'source/lib/sdk/test/memory.js',
|
||||
'source/lib/sdk/test/options.js',
|
||||
'source/lib/sdk/test/runner.js',
|
||||
'source/lib/sdk/test/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui += [
|
||||
'source/lib/sdk/ui/component.js',
|
||||
'source/lib/sdk/ui/frame.js',
|
||||
'source/lib/sdk/ui/id.js',
|
||||
'source/lib/sdk/ui/sidebar.js',
|
||||
'source/lib/sdk/ui/state.js',
|
||||
'source/lib/sdk/ui/toolbar.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui.button += [
|
||||
'source/lib/sdk/ui/button/action.js',
|
||||
'source/lib/sdk/ui/button/contract.js',
|
||||
'source/lib/sdk/ui/button/toggle.js',
|
||||
'source/lib/sdk/ui/button/view.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui.sidebar += [
|
||||
'source/lib/sdk/ui/sidebar/actions.js',
|
||||
'source/lib/sdk/ui/sidebar/contract.js',
|
||||
'source/lib/sdk/ui/sidebar/namespace.js',
|
||||
'source/lib/sdk/ui/sidebar/utils.js',
|
||||
'source/lib/sdk/ui/sidebar/view.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.window += [
|
||||
'source/lib/sdk/window/browser.js',
|
||||
'source/lib/sdk/window/events.js',
|
||||
'source/lib/sdk/window/helpers.js',
|
||||
'source/lib/sdk/window/namespace.js',
|
||||
'source/lib/sdk/window/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.windows += [
|
||||
'source/lib/sdk/windows/fennec.js',
|
||||
'source/lib/sdk/windows/firefox.js',
|
||||
'source/lib/sdk/windows/observer.js',
|
||||
'source/lib/sdk/windows/tabs-fennec.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs += [
|
||||
'source/lib/index.js',
|
||||
'source/lib/test.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk += [
|
||||
'source/lib/sdk/webextension.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.dev += [
|
||||
'source/lib/dev/debuggee.js',
|
||||
'source/lib/dev/frame-script.js',
|
||||
'source/lib/dev/panel.js',
|
||||
'source/lib/dev/ports.js',
|
||||
'source/lib/dev/theme.js',
|
||||
'source/lib/dev/toolbox.js',
|
||||
'source/lib/dev/utils.js',
|
||||
'source/lib/dev/volcan.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.dev.panel += [
|
||||
'source/lib/dev/panel/view.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.dev.theme += [
|
||||
'source/lib/dev/theme/hooks.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.diffpatcher += [
|
||||
'source/lib/diffpatcher/diff.js',
|
||||
'source/lib/diffpatcher/index.js',
|
||||
'source/lib/diffpatcher/patch.js',
|
||||
'source/lib/diffpatcher/rebase.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.diffpatcher.test += [
|
||||
'source/lib/diffpatcher/test/common.js',
|
||||
'source/lib/diffpatcher/test/diff.js',
|
||||
'source/lib/diffpatcher/test/index.js',
|
||||
'source/lib/diffpatcher/test/patch.js',
|
||||
'source/lib/diffpatcher/test/tap.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.framescript += [
|
||||
'source/lib/framescript/content.jsm',
|
||||
'source/lib/framescript/context-menu.js',
|
||||
'source/lib/framescript/FrameScriptManager.jsm',
|
||||
'source/lib/framescript/manager.js',
|
||||
'source/lib/framescript/util.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs['jetpack-id'] += [
|
||||
'source/lib/jetpack-id/index.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.method += [
|
||||
'source/lib/method/core.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs['mozilla-toolkit-versioning'] += [
|
||||
'source/lib/mozilla-toolkit-versioning/index.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs['mozilla-toolkit-versioning'].lib += [
|
||||
'source/lib/mozilla-toolkit-versioning/lib/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.node += [
|
||||
'source/lib/node/os.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk += [
|
||||
'source/lib/sdk/base64.js',
|
||||
'source/lib/sdk/clipboard.js',
|
||||
'source/lib/sdk/context-menu.js',
|
||||
'source/lib/sdk/context-menu@2.js',
|
||||
'source/lib/sdk/hotkeys.js',
|
||||
'source/lib/sdk/indexed-db.js',
|
||||
'source/lib/sdk/l10n.js',
|
||||
'source/lib/sdk/messaging.js',
|
||||
'source/lib/sdk/notifications.js',
|
||||
'source/lib/sdk/page-mod.js',
|
||||
'source/lib/sdk/page-worker.js',
|
||||
'source/lib/sdk/panel.js',
|
||||
'source/lib/sdk/passwords.js',
|
||||
'source/lib/sdk/private-browsing.js',
|
||||
'source/lib/sdk/querystring.js',
|
||||
'source/lib/sdk/request.js',
|
||||
'source/lib/sdk/selection.js',
|
||||
'source/lib/sdk/self.js',
|
||||
'source/lib/sdk/simple-prefs.js',
|
||||
'source/lib/sdk/simple-storage.js',
|
||||
'source/lib/sdk/system.js',
|
||||
'source/lib/sdk/tabs.js',
|
||||
'source/lib/sdk/test.js',
|
||||
'source/lib/sdk/timers.js',
|
||||
'source/lib/sdk/ui.js',
|
||||
'source/lib/sdk/url.js',
|
||||
'source/lib/sdk/windows.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.addon += [
|
||||
'source/lib/sdk/addon/bootstrap.js',
|
||||
'source/lib/sdk/addon/events.js',
|
||||
'source/lib/sdk/addon/host.js',
|
||||
'source/lib/sdk/addon/installer.js',
|
||||
'source/lib/sdk/addon/manager.js',
|
||||
'source/lib/sdk/addon/runner.js',
|
||||
'source/lib/sdk/addon/window.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.browser += [
|
||||
'source/lib/sdk/browser/events.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.console += [
|
||||
'source/lib/sdk/console/plain-text.js',
|
||||
'source/lib/sdk/console/traceback.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.content += [
|
||||
'source/lib/sdk/content/content-worker.js',
|
||||
'source/lib/sdk/content/content.js',
|
||||
'source/lib/sdk/content/context-menu.js',
|
||||
'source/lib/sdk/content/events.js',
|
||||
'source/lib/sdk/content/l10n-html.js',
|
||||
'source/lib/sdk/content/loader.js',
|
||||
'source/lib/sdk/content/mod.js',
|
||||
'source/lib/sdk/content/page-mod.js',
|
||||
'source/lib/sdk/content/page-worker.js',
|
||||
'source/lib/sdk/content/sandbox.js',
|
||||
'source/lib/sdk/content/tab-events.js',
|
||||
'source/lib/sdk/content/thumbnail.js',
|
||||
'source/lib/sdk/content/utils.js',
|
||||
'source/lib/sdk/content/worker-child.js',
|
||||
'source/lib/sdk/content/worker.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.content.sandbox += [
|
||||
'source/lib/sdk/content/sandbox/events.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk['context-menu'] += [
|
||||
'source/lib/sdk/context-menu/context.js',
|
||||
'source/lib/sdk/context-menu/core.js',
|
||||
'source/lib/sdk/context-menu/readers.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.core += [
|
||||
'source/lib/sdk/core/disposable.js',
|
||||
'source/lib/sdk/core/heritage.js',
|
||||
'source/lib/sdk/core/namespace.js',
|
||||
'source/lib/sdk/core/observer.js',
|
||||
'source/lib/sdk/core/promise.js',
|
||||
'source/lib/sdk/core/reference.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.deprecated.events += [
|
||||
'source/lib/sdk/deprecated/events/assembler.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.dom += [
|
||||
'source/lib/sdk/dom/events-shimmed.js',
|
||||
'source/lib/sdk/dom/events.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.dom.events += [
|
||||
'source/lib/sdk/dom/events/keys.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.event += [
|
||||
'source/lib/sdk/event/chrome.js',
|
||||
'source/lib/sdk/event/core.js',
|
||||
'source/lib/sdk/event/dom.js',
|
||||
'source/lib/sdk/event/target.js',
|
||||
'source/lib/sdk/event/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.fs += [
|
||||
'source/lib/sdk/fs/path.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.input += [
|
||||
'source/lib/sdk/input/browser.js',
|
||||
'source/lib/sdk/input/customizable-ui.js',
|
||||
'source/lib/sdk/input/frame.js',
|
||||
'source/lib/sdk/input/system.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.io += [
|
||||
'source/lib/sdk/io/buffer.js',
|
||||
'source/lib/sdk/io/byte-streams.js',
|
||||
'source/lib/sdk/io/file.js',
|
||||
'source/lib/sdk/io/fs.js',
|
||||
'source/lib/sdk/io/stream.js',
|
||||
'source/lib/sdk/io/text-streams.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.keyboard += [
|
||||
'source/lib/sdk/keyboard/hotkeys.js',
|
||||
'source/lib/sdk/keyboard/observer.js',
|
||||
'source/lib/sdk/keyboard/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.l10n += [
|
||||
'source/lib/sdk/l10n/core.js',
|
||||
'source/lib/sdk/l10n/html.js',
|
||||
'source/lib/sdk/l10n/loader.js',
|
||||
'source/lib/sdk/l10n/locale.js',
|
||||
'source/lib/sdk/l10n/plural-rules.js',
|
||||
'source/lib/sdk/l10n/prefs.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.l10n.json += [
|
||||
'source/lib/sdk/l10n/json/core.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.l10n.properties += [
|
||||
'source/lib/sdk/l10n/properties/core.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.lang += [
|
||||
'source/lib/sdk/lang/functional.js',
|
||||
'source/lib/sdk/lang/type.js',
|
||||
'source/lib/sdk/lang/weak-set.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.lang.functional += [
|
||||
'source/lib/sdk/lang/functional/concurrent.js',
|
||||
'source/lib/sdk/lang/functional/core.js',
|
||||
'source/lib/sdk/lang/functional/helpers.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.loader += [
|
||||
'source/lib/sdk/loader/cuddlefish.js',
|
||||
'source/lib/sdk/loader/sandbox.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.model += [
|
||||
'source/lib/sdk/model/core.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.net += [
|
||||
'source/lib/sdk/net/url.js',
|
||||
'source/lib/sdk/net/xhr.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.output += [
|
||||
'source/lib/sdk/output/system.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk['page-mod'] += [
|
||||
'source/lib/sdk/page-mod/match-pattern.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.passwords += [
|
||||
'source/lib/sdk/passwords/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.platform += [
|
||||
'source/lib/sdk/platform/xpcom.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.preferences += [
|
||||
'source/lib/sdk/preferences/event-target.js',
|
||||
'source/lib/sdk/preferences/native-options.js',
|
||||
'source/lib/sdk/preferences/service.js',
|
||||
'source/lib/sdk/preferences/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk['private-browsing'] += [
|
||||
'source/lib/sdk/private-browsing/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.remote += [
|
||||
'source/lib/sdk/remote/child.js',
|
||||
'source/lib/sdk/remote/core.js',
|
||||
'source/lib/sdk/remote/parent.js',
|
||||
'source/lib/sdk/remote/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.stylesheet += [
|
||||
'source/lib/sdk/stylesheet/style.js',
|
||||
'source/lib/sdk/stylesheet/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.system += [
|
||||
'source/lib/sdk/system/child_process.js',
|
||||
'source/lib/sdk/system/environment.js',
|
||||
'source/lib/sdk/system/events-shimmed.js',
|
||||
'source/lib/sdk/system/events.js',
|
||||
'source/lib/sdk/system/globals.js',
|
||||
'source/lib/sdk/system/process.js',
|
||||
'source/lib/sdk/system/runtime.js',
|
||||
'source/lib/sdk/system/unload.js',
|
||||
'source/lib/sdk/system/xul-app.js',
|
||||
'source/lib/sdk/system/xul-app.jsm',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.system.child_process += [
|
||||
'source/lib/sdk/system/child_process/subprocess.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.tab += [
|
||||
'source/lib/sdk/tab/events.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui.button.view += [
|
||||
'source/lib/sdk/ui/button/view/events.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui.frame += [
|
||||
'source/lib/sdk/ui/frame/model.js',
|
||||
'source/lib/sdk/ui/frame/view.html',
|
||||
'source/lib/sdk/ui/frame/view.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui.state += [
|
||||
'source/lib/sdk/ui/state/events.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui.toolbar += [
|
||||
'source/lib/sdk/ui/toolbar/model.js',
|
||||
'source/lib/sdk/ui/toolbar/view.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.uri += [
|
||||
'source/lib/sdk/uri/resource.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.url += [
|
||||
'source/lib/sdk/url/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.util += [
|
||||
'source/lib/sdk/util/array.js',
|
||||
'source/lib/sdk/util/collection.js',
|
||||
'source/lib/sdk/util/contract.js',
|
||||
'source/lib/sdk/util/deprecate.js',
|
||||
'source/lib/sdk/util/dispatcher.js',
|
||||
'source/lib/sdk/util/list.js',
|
||||
'source/lib/sdk/util/match-pattern.js',
|
||||
'source/lib/sdk/util/object.js',
|
||||
'source/lib/sdk/util/rules.js',
|
||||
'source/lib/sdk/util/sequence.js',
|
||||
'source/lib/sdk/util/uuid.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.view += [
|
||||
'source/lib/sdk/view/core.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.worker += [
|
||||
'source/lib/sdk/worker/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.zip += [
|
||||
'source/lib/sdk/zip/utils.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.toolkit += [
|
||||
'source/lib/toolkit/loader.js',
|
||||
'source/lib/toolkit/require.js',
|
||||
]
|
||||
20
addon-sdk/mozbuild.template
Normal file
20
addon-sdk/mozbuild.template
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=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/.
|
||||
|
||||
# Makefile.in uses a misc target through test_addons_TARGET.
|
||||
HAS_MISC_RULE = True
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
JETPACK_PACKAGE_MANIFESTS += ['source/test/jetpack-package.ini']
|
||||
JETPACK_ADDON_MANIFESTS += ['source/test/addons/jetpack-addon.ini']
|
||||
|
||||
EXTRA_JS_MODULES.sdk += [
|
||||
'source/app-extension/bootstrap.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.sdk.system += [
|
||||
'source/modules/system/Startup.js',
|
||||
]
|
||||
5
addon-sdk/source/.gitattributes
vendored
Normal file
5
addon-sdk/source/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.gitignore export-ignore
|
||||
.hgignore export-ignore
|
||||
.hgtags export-ignore
|
||||
.gitattributes export-ignore
|
||||
python-lib/cuddlefish/_version.py export-subst
|
||||
36
addon-sdk/source/.gitignore
vendored
Normal file
36
addon-sdk/source/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
local.json
|
||||
python-lib/cuddlefish/app-extension/components/jetpack.xpt
|
||||
testdocs.tgz
|
||||
jetpack-sdk-docs.tgz
|
||||
.test_tmp/
|
||||
doc/dev-guide/
|
||||
doc/index.html
|
||||
doc/modules/
|
||||
doc/status.md5
|
||||
packages/*
|
||||
node_modules
|
||||
cache
|
||||
|
||||
# Python
|
||||
*.pyc
|
||||
|
||||
# OSX
|
||||
*.DS_Store
|
||||
|
||||
# Windows
|
||||
*Thumbs.db
|
||||
|
||||
# Ignore subtrees
|
||||
|
||||
# git@github.com:jsantell/jetpack-id.git
|
||||
lib/jetpack-id/*
|
||||
!lib/jetpack-id/index.js
|
||||
!lib/jetpack-id/package.json
|
||||
|
||||
# git@github.com:jsantell/mozilla-toolkit-versioning.git
|
||||
lib/mozilla-toolkit-versioning/*
|
||||
!lib/mozilla-toolkit-versioning/index.js
|
||||
!lib/mozilla-toolkit-versioning/lib
|
||||
lib/mozilla-toolkit-versioning/lib/*
|
||||
!lib/mozilla-toolkit-versioning/lib/*.js
|
||||
!lib/mozilla-toolkit-versioning/package.json
|
||||
15
addon-sdk/source/.hgignore
Normal file
15
addon-sdk/source/.hgignore
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
syntax: glob
|
||||
local.json
|
||||
python-lib/cuddlefish/app-extension/components/jetpack.xpt
|
||||
testdocs.tgz
|
||||
jetpack-sdk-docs.tgz
|
||||
.test_tmp
|
||||
jetpack-sdk-docs
|
||||
node_modules
|
||||
|
||||
# These should really be in a global .hgignore, but such a thing
|
||||
# seems ridiculously confusing to set up, so we'll include some
|
||||
# common intermediate files here.
|
||||
*.pyc
|
||||
*~
|
||||
*.DS_Store
|
||||
64
addon-sdk/source/.hgtags
Normal file
64
addon-sdk/source/.hgtags
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
39c45211aa250d43f6e54b776a60ef07a7a4cbb6 jep-31-examples
|
||||
0120642297b217680e75e68c4005a93b16466001 0.1rc1
|
||||
1fd7993ff2cec39c5948a1b2535b78c2d4c65858 0.1rc2
|
||||
530e51d02922ad05fd43e8cf113618068216b0cf 0.1
|
||||
ed11a9e3ae23aefd56ac88042b9816887d10a04f 0.2rc1
|
||||
f70ab8998abdce809bda93408435f83648909cdd 0.2rc2
|
||||
f70ab8998abdce809bda93408435f83648909cdd 0.2
|
||||
436968c6ec833d9c18a15426be26595a44b79283 0.3rc1
|
||||
a3b091d29607f0bcecf77fe27801ba901142f1c9 0.3
|
||||
06031b56312ad7f1880a9620b4d26ce253a23b23 0.3rc2
|
||||
a3b091d29607f0bcecf77fe27801ba901142f1c9 0.3
|
||||
4b08c8a8c1eef71ac3aa54e004b68e87049ca56b 0.3
|
||||
6884e54fd6a1cfa9ec63910c46d2cbf51495b584 0.3rc3
|
||||
4b08c8a8c1eef71ac3aa54e004b68e87049ca56b 0.3
|
||||
cd70b7140ec20689255f1248512a1e5b9cf90a32 0.3
|
||||
d9d733666ca8738e9665ba816d5d12f41fc0d216 0.4rc1
|
||||
8d2871fc10df16740273f53ef05815310da4b210 0.4
|
||||
201e60065b1aef23259a71756f93207cffa2abd5 0.4rc2
|
||||
8d2871fc10df16740273f53ef05815310da4b210 0.4
|
||||
c0e5bbdcafad4572a5de22e533543bf3330a869e 0.4
|
||||
201e60065b1aef23259a71756f93207cffa2abd5 0.4rc2
|
||||
a8dceaefd6f3376b7bc1619cccd854591b76ecc0 0.4rc2
|
||||
c0e5bbdcafad4572a5de22e533543bf3330a869e 0.4
|
||||
dfa3bdfedb12d743b5e0ac19d0ecf116b567a0b3 0.4
|
||||
b519a0848585e2a665a14aac2fb6f15c0a839e6c 0.4rc3
|
||||
dfa3bdfedb12d743b5e0ac19d0ecf116b567a0b3 0.4
|
||||
05acdf4987c28d8cc1d5a12d87e71b1445fdd6b7 0.4
|
||||
04b5afe48d1cee819d9f0af72ed16556a075b67d 0.5rc1
|
||||
1968150561097bcfeeb28a75801ef881d2fcbbf5 0.5
|
||||
3236e68e6f2e36353e47f01a9b8acfce56686263 0.5rc2
|
||||
1968150561097bcfeeb28a75801ef881d2fcbbf5 0.5
|
||||
0097da78aa23be8b7a5a811c4be0e3e35395af43 0.5
|
||||
be7016807a69c910ac31ff068a6c2bde0a25c9d4 0.5rc3
|
||||
0097da78aa23be8b7a5a811c4be0e3e35395af43 0.5
|
||||
83e97107e4a381b898c780b32e30e48b0e4d37f3 0.5
|
||||
182a405aa393dbd412e671e8516d2decd8e8d80c 0.6rc1
|
||||
96799a3d96abfdb1408f9b8e30479668f1feed70 0.6
|
||||
c5f6cdfa36b2ad33d8017e6844992de0b0a6c0e0 0.6rc2
|
||||
96799a3d96abfdb1408f9b8e30479668f1feed70 0.6
|
||||
65c393fbc6af7db79a4a2e903d06b17e90d254bf 0.6
|
||||
3e747e3e307a4e853d468b03357f96b2172bad37 0.7rc1
|
||||
b0e97e12eb9115f08127cc447d459f871c5046ed 0.7
|
||||
37288479d249168668abd60a907620fa7f593128 0.7rc2
|
||||
b0e97e12eb9115f08127cc447d459f871c5046ed 0.7
|
||||
db0eabc310619d00ce47372ecaafba7d2539b601 0.7
|
||||
37288479d249168668abd60a907620fa7f593128 0.7rc2
|
||||
b90bedb83525d8f32ebb4d3833e8d91efa991b6d 0.7rc2
|
||||
db0eabc310619d00ce47372ecaafba7d2539b601 0.7
|
||||
e6ea2e5c5274cbbb0278dc976844dbf51818a95e 0.7
|
||||
b90bedb83525d8f32ebb4d3833e8d91efa991b6d 0.7rc2
|
||||
9b978d823509de5d52ca222b9907f72591c68c5a 0.7rc2
|
||||
e6ea2e5c5274cbbb0278dc976844dbf51818a95e 0.7
|
||||
cd71e1e77c93adf169b9f38184b1f95d423876ba 0.7
|
||||
67e3fd285fa955898a2641226c86725365d68b95 0.8rc1
|
||||
b2f9405db6d74c21601ca9c250887411c837396a 0.8
|
||||
67e3fd285fa955898a2641226c86725365d68b95 0.8rc1
|
||||
56e8179ff5b467959ddf33978558d7eb5346ee53 0.8rc1
|
||||
b2f9405db6d74c21601ca9c250887411c837396a 0.8
|
||||
51a22a186b1c7d8e7292a5ec9670752dad223ca1 0.8
|
||||
d150cca77cfef60dee2f2fe7c892fd7fc5ce83c4 0.9rc1
|
||||
1e106beb57f65fabc32682f277de51a8101c919b 0.9
|
||||
173d56fa8cc1c5622eae70f1ae88ef789de4722b 0.9rc2
|
||||
1e106beb57f65fabc32682f277de51a8101c919b 0.9
|
||||
cde12eefd178d7a0ee7d5e9ae77f3089bcbdc6ec 0.9
|
||||
18
addon-sdk/source/.jpmignore
Normal file
18
addon-sdk/source/.jpmignore
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
local.json
|
||||
mapping.json
|
||||
CONTRIBUTING.md
|
||||
@addon-sdk.xpi
|
||||
.*
|
||||
app-extension/
|
||||
bin/
|
||||
modules/
|
||||
node_modules/
|
||||
examples/
|
||||
cache/
|
||||
|
||||
# Python
|
||||
python-lib/
|
||||
*.pyc
|
||||
|
||||
# Windows
|
||||
*Thumbs.db
|
||||
26
addon-sdk/source/.travis.yml
Normal file
26
addon-sdk/source/.travis.yml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.12"
|
||||
|
||||
env:
|
||||
- JPM_FX_DEBUG=0
|
||||
- JPM_FX_DEBUG=1
|
||||
|
||||
notifications:
|
||||
irc: "irc.mozilla.org#jetpack"
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- cache
|
||||
|
||||
before_install:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 -extension RANDR"
|
||||
|
||||
before_script:
|
||||
- npm install fx-download -g
|
||||
- npm install gulp -g
|
||||
- bash bin/fx-download.sh
|
||||
- export JPM_FIREFOX_BINARY=$TRAVIS_BUILD_DIR/../firefox/firefox
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
54
addon-sdk/source/CONTRIBUTING.md
Normal file
54
addon-sdk/source/CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
## Overview
|
||||
|
||||
- Changes should follow the [design guidelines], as well as the [coding style guide]
|
||||
- All changes need tests
|
||||
- In order to land, changes need a review by one of the Jetpack reviewers
|
||||
- Changes may need an API review
|
||||
- Changes may need a review from a Mozilla platform domain-expert
|
||||
|
||||
If you have questions, ask in [#jetpack on IRC][jetpack irc channel] or on the [Jetpack mailing list].
|
||||
|
||||
## How to Make Code Contributions
|
||||
|
||||
Follow the [standard mozilla contribution guidelines](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Introduction). All contributions and patches should be through Bugzilla.
|
||||
|
||||
Pull requests on github are not accepted and new pull requests on github will be rejected.
|
||||
|
||||
## Good First Bugs
|
||||
|
||||
There is a list of [good first bugs here][good first bugs].
|
||||
|
||||
## Reviewers
|
||||
|
||||
Changes should be reviewed by someone on the [add-on sdk review team](https://bugzilla.mozilla.org/page.cgi?id=review_suggestions.html#Add-on%20SDK) within Bugzilla.
|
||||
|
||||
Others who might be able to help include:
|
||||
|
||||
- [@mossop]
|
||||
- [@gozala]
|
||||
- [@ZER0]
|
||||
- [@jsantell]
|
||||
- [@zombie]
|
||||
|
||||
For review of Mozilla platform usage and best practices, ask [@autonome],
|
||||
[@0c0w3], or [@mossop] to find the domain expert.
|
||||
|
||||
For API and developer ergonomics review, ask [@gozala].
|
||||
|
||||
[design guidelines]:https://wiki.mozilla.org/Labs/Jetpack/Design_Guidelines
|
||||
[jetpack irc channel]:irc://irc.mozilla.org/#jetpack
|
||||
[Jetpack mailing list]:http://groups.google.com/group/mozilla-labs-jetpack
|
||||
[open bugs]:https://bugzilla.mozilla.org/buglist.cgi?quicksearch=product%3ASDK
|
||||
[make bug]:https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK&component=general
|
||||
[test intro]:https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Unit_testing
|
||||
[test API]:https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/test_assert
|
||||
[coding style guide]:https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide
|
||||
[Add-on SDK repo]:https://github.com/mozilla/addon-sdk
|
||||
[GitHub]:https://github.com/
|
||||
[good first bugs]:https://bugzilla.mozilla.org/buglist.cgi?list_id=7345714&columnlist=bug_severity%2Cpriority%2Cassigned_to%2Cbug_status%2Ctarget_milestone%2Cresolution%2Cshort_desc%2Cchangeddate&query_based_on=jetpack-good-1st-bugs&status_whiteboard_type=allwordssubstr&query_format=advanced&status_whiteboard=[good%20first%20bug]&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=VERIFIED&product=Add-on%20SDK&known_name=jetpack-good-1st-bugs
|
||||
|
||||
[@mossop]:https://github.com/mossop/
|
||||
[@gozala]:https://github.com/Gozala/
|
||||
[@ZER0]:https://github.com/ZER0/
|
||||
[@jsantell]:https://github.com/jsantell
|
||||
[@zombie]:https://github.com/zombie
|
||||
30
addon-sdk/source/LICENSE
Normal file
30
addon-sdk/source/LICENSE
Normal file
|
|
@ -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.
|
||||
34
addon-sdk/source/README.md
Normal file
34
addon-sdk/source/README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Mozilla Add-on SDK [](https://travis-ci.org/mozilla/addon-sdk)
|
||||
|
||||
We suggest that developers of new add-ons [should look at using WebExtensions](https://developer.mozilla.org/en-US/Add-ons/WebExtensions).
|
||||
|
||||
Using the Add-on SDK you can create Firefox add-ons using standard Web technologies: JavaScript, HTML, and CSS. The SDK includes JavaScript APIs which you can use to create add-ons, and tools for creating, running, testing, and packaging add-ons.
|
||||
|
||||
If you find a problem, please [report the bug here](https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK).
|
||||
|
||||
## Developing Add-ons
|
||||
|
||||
These resources offer some help:
|
||||
|
||||
* [Add-on SDK Documentation](https://developer.mozilla.org/en-US/Add-ons/SDK)
|
||||
* [Community Developed Modules](https://github.com/mozilla/addon-sdk/wiki/Community-developed-modules)
|
||||
* [Jetpack FAQ](https://wiki.mozilla.org/Jetpack/FAQ)
|
||||
* [StackOverflow Questions](http://stackoverflow.com/questions/tagged/firefox-addon-sdk)
|
||||
* [Mailing List](https://wiki.mozilla.org/Jetpack#Mailing_list)
|
||||
* #jetpack on irc.mozilla.org
|
||||
|
||||
## Contributing Code
|
||||
|
||||
Please read these two guides if you wish to make some patches to the addon-sdk:
|
||||
|
||||
* [Contribute Guide](https://github.com/mozilla/addon-sdk/blob/master/CONTRIBUTING.md)
|
||||
* [Style Guide](https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide)
|
||||
|
||||
## Issues
|
||||
|
||||
We use [bugzilla](https://bugzilla.mozilla.org/) as our issue tracker, here are some useful links:
|
||||
|
||||
* [File a bug](https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK)
|
||||
* [Open bugs](https://bugzilla.mozilla.org/buglist.cgi?bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&columnlist=bug_severity%2Cpriority%2Cassigned_to%2Cbug_status%2Ctarget_milestone%2Cresolution%2Cshort_desc%2Cchangeddate&product=Add-on%20SDK&query_format=advanced&order=priority)
|
||||
* [Good first bugs](https://bugzilla.mozilla.org/buglist.cgi?status_whiteboard=[good+first+bug]&&resolution=---&product=Add-on+SDK)
|
||||
* [Good next bugs](https://bugzilla.mozilla.org/buglist.cgi?status_whiteboard=[good+next+bug]&&resolution=---&product=Add-on+SDK)
|
||||
11
addon-sdk/source/app-extension/application.ini
Normal file
11
addon-sdk/source/app-extension/application.ini
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[App]
|
||||
Vendor=Varma
|
||||
Name=Test App
|
||||
Version=1.0
|
||||
BuildID=20060101
|
||||
Copyright=Copyright (c) 2009 Atul Varma
|
||||
ID=xulapp@toolness.com
|
||||
|
||||
[Gecko]
|
||||
MinVersion=1.9.2.0
|
||||
MaxVersion=2.0.*
|
||||
362
addon-sdk/source/app-extension/bootstrap.js
vendored
Normal file
362
addon-sdk/source/app-extension/bootstrap.js
vendored
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// @see http://dxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
|
||||
|
||||
'use strict';
|
||||
|
||||
// IMPORTANT: Avoid adding any initialization tasks here, if you need to do
|
||||
// something before add-on is loaded consider addon/runner module instead!
|
||||
|
||||
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu,
|
||||
results: Cr, manager: Cm } = Components;
|
||||
const ioService = Cc['@mozilla.org/network/io-service;1'].
|
||||
getService(Ci.nsIIOService);
|
||||
const resourceHandler = ioService.getProtocolHandler('resource').
|
||||
QueryInterface(Ci.nsIResProtocolHandler);
|
||||
const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
|
||||
const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
const prefService = Cc['@mozilla.org/preferences-service;1'].
|
||||
getService(Ci.nsIPrefService).
|
||||
QueryInterface(Ci.nsIPrefBranch);
|
||||
const appInfo = Cc["@mozilla.org/xre/app-info;1"].
|
||||
getService(Ci.nsIXULAppInfo);
|
||||
const vc = Cc["@mozilla.org/xpcom/version-comparator;1"].
|
||||
getService(Ci.nsIVersionComparator);
|
||||
|
||||
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
|
||||
const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
|
||||
|
||||
|
||||
const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable',
|
||||
'install', 'uninstall', 'upgrade', 'downgrade' ];
|
||||
|
||||
const bind = Function.call.bind(Function.bind);
|
||||
|
||||
var loader = null;
|
||||
var unload = null;
|
||||
var cuddlefishSandbox = null;
|
||||
var nukeTimer = null;
|
||||
|
||||
var resourceDomains = [];
|
||||
function setResourceSubstitution(domain, uri) {
|
||||
resourceDomains.push(domain);
|
||||
resourceHandler.setSubstitution(domain, uri);
|
||||
}
|
||||
|
||||
// Utility function that synchronously reads local resource from the given
|
||||
// `uri` and returns content string.
|
||||
function readURI(uri) {
|
||||
let channel = NetUtil.newChannel({
|
||||
uri: NetUtil.newURI(uri, 'UTF-8'),
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
|
||||
let stream = channel.open2();
|
||||
|
||||
let cstream = Cc['@mozilla.org/intl/converter-input-stream;1'].
|
||||
createInstance(Ci.nsIConverterInputStream);
|
||||
cstream.init(stream, 'UTF-8', 0, 0);
|
||||
|
||||
let str = {};
|
||||
let data = '';
|
||||
let read = 0;
|
||||
do {
|
||||
read = cstream.readString(0xffffffff, str);
|
||||
data += str.value;
|
||||
} while (read != 0);
|
||||
|
||||
cstream.close();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// We don't do anything on install & uninstall yet, but in a future
|
||||
// we should allow add-ons to cleanup after uninstall.
|
||||
function install(data, reason) {}
|
||||
function uninstall(data, reason) {}
|
||||
|
||||
function startup(data, reasonCode) {
|
||||
try {
|
||||
let reason = REASON[reasonCode];
|
||||
// URI for the root of the XPI file.
|
||||
// 'jar:' URI if the addon is packed, 'file:' URI otherwise.
|
||||
// (Used by l10n module in order to fetch `locale` folder)
|
||||
let rootURI = data.resourceURI.spec;
|
||||
|
||||
// TODO: Maybe we should perform read harness-options.json asynchronously,
|
||||
// since we can't do anything until 'sessionstore-windows-restored' anyway.
|
||||
let options = JSON.parse(readURI(rootURI + './harness-options.json'));
|
||||
|
||||
let id = options.jetpackID;
|
||||
let name = options.name;
|
||||
|
||||
// Clean the metadata
|
||||
options.metadata[name]['permissions'] = options.metadata[name]['permissions'] || {};
|
||||
|
||||
// freeze the permissionss
|
||||
Object.freeze(options.metadata[name]['permissions']);
|
||||
// freeze the metadata
|
||||
Object.freeze(options.metadata[name]);
|
||||
|
||||
// Register a new resource 'domain' for this addon which is mapping to
|
||||
// XPI's `resources` folder.
|
||||
// Generate the domain name by using jetpack ID, which is the extension ID
|
||||
// by stripping common characters that doesn't work as a domain name:
|
||||
let uuidRe =
|
||||
/^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/;
|
||||
|
||||
let domain = id.
|
||||
toLowerCase().
|
||||
replace(/@/g, '-at-').
|
||||
replace(/\./g, '-dot-').
|
||||
replace(uuidRe, '$1');
|
||||
|
||||
let prefixURI = 'resource://' + domain + '/';
|
||||
let resourcesURI = ioService.newURI(rootURI + '/resources/', null, null);
|
||||
setResourceSubstitution(domain, resourcesURI);
|
||||
|
||||
// Create path to URLs mapping supported by loader.
|
||||
let paths = {
|
||||
// Relative modules resolve to add-on package lib
|
||||
'./': prefixURI + name + '/lib/',
|
||||
'./tests/': prefixURI + name + '/tests/',
|
||||
'': 'resource://gre/modules/commonjs/'
|
||||
};
|
||||
|
||||
// Maps addon lib and tests ressource folders for each package
|
||||
paths = Object.keys(options.metadata).reduce(function(result, name) {
|
||||
result[name + '/'] = prefixURI + name + '/lib/'
|
||||
result[name + '/tests/'] = prefixURI + name + '/tests/'
|
||||
return result;
|
||||
}, paths);
|
||||
|
||||
// We need to map tests folder when we run sdk tests whose package name
|
||||
// is stripped
|
||||
if (name == 'addon-sdk')
|
||||
paths['tests/'] = prefixURI + name + '/tests/';
|
||||
|
||||
let useBundledSDK = options['force-use-bundled-sdk'];
|
||||
if (!useBundledSDK) {
|
||||
try {
|
||||
useBundledSDK = prefService.getBoolPref("extensions.addon-sdk.useBundledSDK");
|
||||
}
|
||||
catch (e) {
|
||||
// Pref doesn't exist, allow using Firefox shipped SDK
|
||||
}
|
||||
}
|
||||
|
||||
// Starting with Firefox 21.0a1, we start using modules shipped into firefox
|
||||
// Still allow using modules from the xpi if the manifest tell us to do so.
|
||||
// And only try to look for sdk modules in xpi if the xpi actually ship them
|
||||
if (options['is-sdk-bundled'] &&
|
||||
(vc.compare(appInfo.version, '21.0a1') < 0 || useBundledSDK)) {
|
||||
// Maps sdk module folders to their resource folder
|
||||
paths[''] = prefixURI + 'addon-sdk/lib/';
|
||||
// test.js is usually found in root commonjs or SDK_ROOT/lib/ folder,
|
||||
// so that it isn't shipped in the xpi. Keep a copy of it in sdk/ folder
|
||||
// until we no longer support SDK modules in XPI:
|
||||
paths['test'] = prefixURI + 'addon-sdk/lib/sdk/test.js';
|
||||
}
|
||||
|
||||
// Retrieve list of module folder overloads based on preferences in order to
|
||||
// eventually used a local modules instead of files shipped into Firefox.
|
||||
let branch = prefService.getBranch('extensions.modules.' + id + '.path');
|
||||
paths = branch.getChildList('', {}).reduce(function (result, name) {
|
||||
// Allows overloading of any sub folder by replacing . by / in pref name
|
||||
let path = name.substr(1).split('.').join('/');
|
||||
// Only accept overloading folder by ensuring always ending with `/`
|
||||
if (path) path += '/';
|
||||
let fileURI = branch.getCharPref(name);
|
||||
|
||||
// On mobile, file URI has to end with a `/` otherwise, setSubstitution
|
||||
// takes the parent folder instead.
|
||||
if (fileURI[fileURI.length-1] !== '/')
|
||||
fileURI += '/';
|
||||
|
||||
// Maps the given file:// URI to a resource:// in order to avoid various
|
||||
// failure that happens with file:// URI and be close to production env
|
||||
let resourcesURI = ioService.newURI(fileURI, null, null);
|
||||
let resName = 'extensions.modules.' + domain + '.commonjs.path' + name;
|
||||
setResourceSubstitution(resName, resourcesURI);
|
||||
|
||||
result[path] = 'resource://' + resName + '/';
|
||||
return result;
|
||||
}, paths);
|
||||
|
||||
// Make version 2 of the manifest
|
||||
let manifest = options.manifest;
|
||||
|
||||
// Import `cuddlefish.js` module using a Sandbox and bootstrap loader.
|
||||
let cuddlefishPath = 'loader/cuddlefish.js';
|
||||
let cuddlefishURI = 'resource://gre/modules/commonjs/sdk/' + cuddlefishPath;
|
||||
if (paths['sdk/']) { // sdk folder has been overloaded
|
||||
// (from pref, or cuddlefish is still in the xpi)
|
||||
cuddlefishURI = paths['sdk/'] + cuddlefishPath;
|
||||
}
|
||||
else if (paths['']) { // root modules folder has been overloaded
|
||||
cuddlefishURI = paths[''] + 'sdk/' + cuddlefishPath;
|
||||
}
|
||||
|
||||
cuddlefishSandbox = loadSandbox(cuddlefishURI);
|
||||
let cuddlefish = cuddlefishSandbox.exports;
|
||||
|
||||
// Normalize `options.mainPath` so that it looks like one that will come
|
||||
// in a new version of linker.
|
||||
let main = options.mainPath;
|
||||
|
||||
unload = cuddlefish.unload;
|
||||
loader = cuddlefish.Loader({
|
||||
paths: paths,
|
||||
// modules manifest.
|
||||
manifest: manifest,
|
||||
|
||||
// Add-on ID used by different APIs as a unique identifier.
|
||||
id: id,
|
||||
// Add-on name.
|
||||
name: name,
|
||||
// Add-on version.
|
||||
version: options.metadata[name].version,
|
||||
// Add-on package descriptor.
|
||||
metadata: options.metadata[name],
|
||||
// Add-on load reason.
|
||||
loadReason: reason,
|
||||
|
||||
prefixURI: prefixURI,
|
||||
// Add-on URI.
|
||||
rootURI: rootURI,
|
||||
// options used by system module.
|
||||
// File to write 'OK' or 'FAIL' (exit code emulation).
|
||||
resultFile: options.resultFile,
|
||||
// Arguments passed as --static-args
|
||||
staticArgs: options.staticArgs,
|
||||
|
||||
// Option to prevent automatic kill of firefox during tests
|
||||
noQuit: options.no_quit,
|
||||
|
||||
// Add-on preferences branch name
|
||||
preferencesBranch: options.preferencesBranch,
|
||||
|
||||
// Arguments related to test runner.
|
||||
modules: {
|
||||
'@test/options': {
|
||||
iterations: options.iterations,
|
||||
filter: options.filter,
|
||||
profileMemory: options.profileMemory,
|
||||
stopOnError: options.stopOnError,
|
||||
verbose: options.verbose,
|
||||
parseable: options.parseable,
|
||||
checkMemory: options.check_memory,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let module = cuddlefish.Module('sdk/loader/cuddlefish', cuddlefishURI);
|
||||
let require = cuddlefish.Require(loader, module);
|
||||
|
||||
// Init the 'sdk/webextension' module from the bootstrap addon parameter.
|
||||
require("sdk/webextension").initFromBootstrapAddonParam(data);
|
||||
|
||||
require('sdk/addon/runner').startup(reason, {
|
||||
loader: loader,
|
||||
main: main,
|
||||
prefsURI: rootURI + 'defaults/preferences/prefs.js'
|
||||
});
|
||||
} catch (error) {
|
||||
dump('Bootstrap error: ' +
|
||||
(error.message ? error.message : String(error)) + '\n' +
|
||||
(error.stack || error.fileName + ': ' + error.lineNumber) + '\n');
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
function loadSandbox(uri) {
|
||||
let proto = {
|
||||
sandboxPrototype: {
|
||||
loadSandbox: loadSandbox,
|
||||
ChromeWorker: ChromeWorker
|
||||
}
|
||||
};
|
||||
let sandbox = Cu.Sandbox(systemPrincipal, proto);
|
||||
// Create a fake commonjs environnement just to enable loading loader.js
|
||||
// correctly
|
||||
sandbox.exports = {};
|
||||
sandbox.module = { uri: uri, exports: sandbox.exports };
|
||||
sandbox.require = function (id) {
|
||||
if (id !== "chrome")
|
||||
throw new Error("Bootstrap sandbox `require` method isn't implemented.");
|
||||
|
||||
return Object.freeze({ Cc: Cc, Ci: Ci, Cu: Cu, Cr: Cr, Cm: Cm,
|
||||
CC: bind(CC, Components), components: Components,
|
||||
ChromeWorker: ChromeWorker });
|
||||
};
|
||||
scriptLoader.loadSubScript(uri, sandbox, 'UTF-8');
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
function unloadSandbox(sandbox) {
|
||||
if (Cu.getClassName(sandbox, true) == "Sandbox")
|
||||
Cu.nukeSandbox(sandbox);
|
||||
}
|
||||
|
||||
function setTimeout(callback, delay) {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback({ notify: callback }, delay,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return timer;
|
||||
}
|
||||
|
||||
function shutdown(data, reasonCode) {
|
||||
let reason = REASON[reasonCode];
|
||||
if (loader) {
|
||||
unload(loader, reason);
|
||||
unload = null;
|
||||
|
||||
// Don't waste time cleaning up if the application is shutting down
|
||||
if (reason != "shutdown") {
|
||||
// Avoid leaking all modules when something goes wrong with one particular
|
||||
// module. Do not clean it up immediatly in order to allow executing some
|
||||
// actions on addon disabling.
|
||||
// We need to keep a reference to the timer, otherwise it is collected
|
||||
// and won't ever fire.
|
||||
nukeTimer = setTimeout(nukeModules, 1000);
|
||||
|
||||
// Bug 944951 - bootstrap.js must remove the added resource: URIs on unload
|
||||
resourceDomains.forEach(domain => {
|
||||
resourceHandler.setSubstitution(domain, null);
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function nukeModules() {
|
||||
nukeTimer = null;
|
||||
// module objects store `exports` which comes from sandboxes
|
||||
// We should avoid keeping link to these object to avoid leaking sandboxes
|
||||
for (let key in loader.modules) {
|
||||
delete loader.modules[key];
|
||||
}
|
||||
// Direct links to sandboxes should be removed too
|
||||
for (let key in loader.sandboxes) {
|
||||
let sandbox = loader.sandboxes[key];
|
||||
delete loader.sandboxes[key];
|
||||
// Bug 775067: From FF17 we can kill all CCW from a given sandbox
|
||||
unloadSandbox(sandbox);
|
||||
}
|
||||
unloadSandbox(loader.sharedGlobalSandbox);
|
||||
loader = null;
|
||||
|
||||
// both `toolkit/loader` and `system/xul-app` are loaded as JSM's via
|
||||
// `cuddlefish.js`, and needs to be unloaded to avoid memory leaks, when
|
||||
// the addon is unload.
|
||||
|
||||
unloadSandbox(cuddlefishSandbox.loaderSandbox);
|
||||
|
||||
// Bug 764840: We need to unload cuddlefish otherwise it will stay alive
|
||||
// and keep a reference to this compartment.
|
||||
unloadSandbox(cuddlefishSandbox);
|
||||
cuddlefishSandbox = null;
|
||||
}
|
||||
33
addon-sdk/source/app-extension/install.rdf
Normal file
33
addon-sdk/source/app-extension/install.rdf
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>xulapp@toolness.com</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:unpack>false</em:unpack>
|
||||
|
||||
<!-- Firefox -->
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>26.0</em:minVersion>
|
||||
<em:maxVersion>30.0</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Test App</em:name>
|
||||
<em:description>Harness for tests.</em:description>
|
||||
<em:creator>Mozilla Corporation</em:creator>
|
||||
<em:homepageURL></em:homepageURL>
|
||||
<em:optionsType></em:optionsType>
|
||||
<em:optionsURL></em:optionsURL>
|
||||
<em:updateURL></em:updateURL>
|
||||
</Description>
|
||||
</RDF>
|
||||
84
addon-sdk/source/bin/activate
Normal file
84
addon-sdk/source/bin/activate
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# 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
|
||||
|
||||
PYTHONPATH="$_OLD_PYTHONPATH"
|
||||
export PYTHONPATH
|
||||
unset _OLD_PYTHONPATH
|
||||
|
||||
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()"
|
||||
134
addon-sdk/source/bin/activate.bat
Normal file
134
addon-sdk/source/bin/activate.bat
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
@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=
|
||||
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 <NO NAME>\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
|
||||
66
addon-sdk/source/bin/activate.fish
Normal file
66
addon-sdk/source/bin/activate.fish
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.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.fish" *from fish*
|
||||
# you cannot run it directly
|
||||
|
||||
# Much of this code is based off of the activate.fish file for the
|
||||
# virtualenv project. http://ur1.ca/ehmd6
|
||||
|
||||
function deactivate -d "Exit addon-sdk and return to normal shell environment"
|
||||
if test -n "$_OLD_VIRTUAL_PATH"
|
||||
set -gx PATH $_OLD_VIRTUAL_PATH
|
||||
set -e _OLD_VIRTUAL_PATH
|
||||
end
|
||||
|
||||
if test -n "$_OLD_PYTHONPATH"
|
||||
set -gx PYTHONPATH $_OLD_PYTHONPATH
|
||||
set -e _OLD_PYTHONPATH
|
||||
end
|
||||
|
||||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
|
||||
functions -e fish_prompt
|
||||
set -e _OLD_FISH_PROMPT_OVERRIDE
|
||||
. ( begin
|
||||
printf "function fish_prompt\n\t#"
|
||||
functions _old_fish_prompt
|
||||
end | psub )
|
||||
|
||||
functions -e _old_fish_prompt
|
||||
end
|
||||
|
||||
set -e CUDDLEFISH_ROOT
|
||||
set -e VIRTUAL_ENV
|
||||
|
||||
if test "$argv[1]" != "nondestructive"
|
||||
functions -e deactivate
|
||||
end
|
||||
end
|
||||
|
||||
# unset irrelavent variables
|
||||
deactivate nondestructive
|
||||
|
||||
set -gx _OLD_PYTHONPATH $PYTHONPATH
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
set -gx _OLD_FISH_PROMPT_OVERRIDE "true"
|
||||
|
||||
set VIRTUAL_ENV (pwd)
|
||||
|
||||
set -gx CUDDLEFISH_ROOT $VIRTUAL_ENV
|
||||
set -gx PYTHONPATH "$VIRTUAL_ENV/python-lib" $PYTHONPATH
|
||||
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
|
||||
|
||||
# save the current fish_prompt function as the function _old_fish_prompt
|
||||
. ( begin
|
||||
printf "function _old_fish_prompt\n\t#"
|
||||
functions fish_prompt
|
||||
end | psub )
|
||||
|
||||
# with the original prompt function renamed, we can override with our own.
|
||||
function fish_prompt
|
||||
printf "(%s)%s%s" (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt)
|
||||
return
|
||||
end
|
||||
|
||||
python -c "from jetpack_sdk_env import welcome; welcome()"
|
||||
99
addon-sdk/source/bin/activate.ps1
Normal file
99
addon-sdk/source/bin/activate.ps1
Normal file
|
|
@ -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()"
|
||||
|
||||
33
addon-sdk/source/bin/cfx
Normal file
33
addon-sdk/source/bin/cfx
Normal file
|
|
@ -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.insert(0, 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()
|
||||
6
addon-sdk/source/bin/cfx.bat
Normal file
6
addon-sdk/source/bin/cfx.bat
Normal file
|
|
@ -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" %*
|
||||
23
addon-sdk/source/bin/deactivate.bat
Normal file
23
addon-sdk/source/bin/deactivate.bat
Normal file
|
|
@ -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
|
||||
7
addon-sdk/source/bin/fx-download.sh
Normal file
7
addon-sdk/source/bin/fx-download.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ "$JPM_FX_DEBUG" = "1" ]; then
|
||||
fx-download --branch nightly -c prerelease --host ftp.mozilla.org ../firefox --debug
|
||||
else
|
||||
fx-download --branch nightly -c prerelease --host ftp.mozilla.org ../firefox
|
||||
fi
|
||||
|
|
@ -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
|
||||
364
addon-sdk/source/bin/integration-scripts/integration-check
Normal file
364
addon-sdk/source/bin/integration-scripts/integration-check
Normal file
|
|
@ -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)
|
||||
34
addon-sdk/source/bin/jpm-test.js
Normal file
34
addon-sdk/source/bin/jpm-test.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If 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 Promise = require("promise");
|
||||
var Mocha = require("mocha");
|
||||
var mocha = new Mocha({
|
||||
ui: "bdd",
|
||||
reporter: "spec",
|
||||
timeout: 900000
|
||||
});
|
||||
|
||||
var isDebug = require("./node-scripts/utils").isDebug;
|
||||
|
||||
exports.run = function(type) {
|
||||
return new Promise(function(resolve) {
|
||||
type = type || "";
|
||||
[
|
||||
(!isDebug && /^(firefox-bin)?$/.test(type)) && require.resolve("../bin/node-scripts/test.firefox-bin"),
|
||||
(!isDebug && /^(docs)?$/.test(type)) && require.resolve("../bin/node-scripts/test.docs"),
|
||||
(!isDebug && /^(ini)?$/.test(type)) && require.resolve("../bin/node-scripts/test.ini"),
|
||||
(/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"),
|
||||
(!isDebug && /^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
|
||||
(!isDebug && /^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
|
||||
].forEach(function(filepath) {
|
||||
filepath && mocha.addFile(filepath);
|
||||
})
|
||||
|
||||
mocha.run(function(failures) {
|
||||
resolve(failures);
|
||||
});
|
||||
});
|
||||
}
|
||||
64
addon-sdk/source/bin/node-scripts/apply-patch.js
Normal file
64
addon-sdk/source/bin/node-scripts/apply-patch.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var path = require("path");
|
||||
var cp = require("child_process");
|
||||
var fs = require("fs");
|
||||
var Promise = require("promise");
|
||||
var patcher = require("patch-editor");
|
||||
var readParam = require("./utils").readParam;
|
||||
|
||||
var isKeeper = /\/addon-sdk\/source/;
|
||||
|
||||
function apply(options) {
|
||||
return clean(options).then(function() {
|
||||
return new Promise(function(resolve) {
|
||||
var patch = path.resolve(readParam("patch"));
|
||||
var proc = cp.spawn("git", ["apply", patch]);
|
||||
proc.stdout.pipe(process.stdout);
|
||||
proc.stderr.pipe(process.stderr);
|
||||
proc.on("close", resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.apply = apply;
|
||||
|
||||
function clean(options) {
|
||||
return new Promise(function(resolve) {
|
||||
var patch = path.resolve(readParam("patch"));
|
||||
if (!patch) {
|
||||
throw new Error("no --patch was provided.");
|
||||
}
|
||||
console.log("Cleaning patch " + patch);
|
||||
|
||||
patcher.getChunks({ patch: patch }).then(function(chunks) {
|
||||
var keepers = [];
|
||||
|
||||
for (var i = chunks.length - 1; i >= 0; i--) {
|
||||
var chunk = chunks[i];
|
||||
var files = chunk.getFilesChanged();
|
||||
|
||||
// check if the file changed is related to the addon-sdk/source directory
|
||||
var keepIt = files.map(function(file) {
|
||||
return (isKeeper.test(file));
|
||||
}).reduce(function(prev, curr) {
|
||||
return prev || curr;
|
||||
}, false);
|
||||
|
||||
if (keepIt) {
|
||||
keepers.push(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
var contents = "\n" + keepers.join("\n") + "\n";
|
||||
contents = contents.replace(/\/addon-sdk\/source/g, "");
|
||||
|
||||
fs.writeFileSync(patch, contents, { encoding: "utf8" });
|
||||
|
||||
console.log("Done cleaning patch.");
|
||||
}).then(resolve).catch(console.error);
|
||||
});
|
||||
}
|
||||
exports.clean = clean;
|
||||
57
addon-sdk/source/bin/node-scripts/test.addons.js
Normal file
57
addon-sdk/source/bin/node-scripts/test.addons.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var jpm = utils.run;
|
||||
var readParam = utils.readParam;
|
||||
var isDebug = utils.isDebug;
|
||||
|
||||
var addonsPath = path.join(__dirname, "..", "..", "test", "addons");
|
||||
|
||||
var binary = process.env.JPM_FIREFOX_BINARY || "nightly";
|
||||
var filterPattern = readParam("filter");
|
||||
|
||||
describe("jpm test sdk addons", function () {
|
||||
fs.readdirSync(addonsPath)
|
||||
.filter(fileFilter.bind(null, addonsPath))
|
||||
.forEach(function (file) {
|
||||
it(file, function (done) {
|
||||
var addonPath = path.join(addonsPath, file);
|
||||
process.chdir(addonPath);
|
||||
|
||||
var options = { cwd: addonPath, env: { JPM_FIREFOX_BINARY: binary }};
|
||||
if (process.env.DISPLAY) {
|
||||
options.env.DISPLAY = process.env.DISPLAY;
|
||||
}
|
||||
if (/^e10s/.test(file)) {
|
||||
options.e10s = true;
|
||||
}
|
||||
|
||||
jpm("run", options).then(done).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function fileFilter(root, file) {
|
||||
var matcher = filterPattern && new RegExp(filterPattern);
|
||||
if (/^(l10n-properties|simple-prefs|page-mod-debugger)/.test(file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// filter additional add-ons when using debug builds
|
||||
if (isDebug) {
|
||||
if (/^(chrome|e10s)/.test(file)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (matcher && !matcher.test(file)) {
|
||||
return false;
|
||||
}
|
||||
var stat = fs.statSync(path.join(root, file))
|
||||
return (stat && stat.isDirectory());
|
||||
}
|
||||
145
addon-sdk/source/bin/node-scripts/test.docs.js
Normal file
145
addon-sdk/source/bin/node-scripts/test.docs.js
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var createHash = require('crypto').createHash;
|
||||
var fs = require("fs");
|
||||
var fsExtra = require("fs-extra")
|
||||
var path = require("path");
|
||||
var Promise = require("promise");
|
||||
var chai = require("chai");
|
||||
var expect = chai.expect;
|
||||
var teacher = require("teacher");
|
||||
|
||||
var rootURI = path.join(__dirname, "..", "..");
|
||||
|
||||
// get a list of words that fail spell check but are still acceptable
|
||||
var NEW_WORDS = fs.readFileSync(path.join(__dirname, "words.txt")).toString().trim().split("\n");
|
||||
|
||||
var CACHE_PATH = path.join(__dirname, "..", "..", "cache", "spellchecks.json");
|
||||
|
||||
var CACHE = {};
|
||||
|
||||
try {
|
||||
CACHE = JSON.parse(fs.readFileSync(CACHE_PATH).toString());
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
function md5(str) {
|
||||
return createHash("md5").update(str).digest("utf8");
|
||||
}
|
||||
|
||||
function addCacheHash(hash) {
|
||||
CACHE[hash] = true;
|
||||
fsExtra.ensureFileSync(CACHE_PATH);
|
||||
fsExtra.writeJSONSync(CACHE_PATH, CACHE);
|
||||
}
|
||||
|
||||
describe("Spell Checking", function () {
|
||||
it("Spellcheck CONTRIBUTING.md", function (done) {
|
||||
var readme = path.join(rootURI, "CONTRIBUTING.md");
|
||||
|
||||
fs.readFile(readme, function (err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
var text = data.toString();
|
||||
var hash = md5(text);
|
||||
|
||||
// skip this test if we know we have done the
|
||||
// exact same test with positive results before
|
||||
if (CACHE[hash]) {
|
||||
expect(CACHE[hash]).to.be.equal(true);
|
||||
return done();
|
||||
}
|
||||
|
||||
teacher.check(text, function(err, data) {
|
||||
expect(err).to.be.equal(null);
|
||||
|
||||
var results = data || [];
|
||||
results = results.filter(function(result) {
|
||||
if (NEW_WORDS.indexOf(result.string.toLowerCase()) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore anything that starts with a dash
|
||||
if (result.string[0] == "-") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(new RegExp(result.string)).test(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
|
||||
if (results.length > 0) {
|
||||
console.log(results);
|
||||
}
|
||||
else {
|
||||
addCacheHash(hash);
|
||||
}
|
||||
|
||||
expect(results.length).to.be.equal(0);
|
||||
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("Spellcheck README.md", function (done) {
|
||||
var readme = path.join(rootURI, "README.md");
|
||||
|
||||
fs.readFile(readme, function (err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
var text = data.toString();
|
||||
var hash = md5(text);
|
||||
|
||||
// skip this test if we know we have done the
|
||||
// exact same test with positive results before
|
||||
if (CACHE[hash]) {
|
||||
expect(CACHE[hash]).to.be.equal(true);
|
||||
return done();
|
||||
}
|
||||
|
||||
teacher.check(text, function(err, data) {
|
||||
expect(err).to.be.equal(null);
|
||||
|
||||
var results = data || [];
|
||||
results = results.filter(function(result) {
|
||||
if (NEW_WORDS.indexOf(result.string.toLowerCase()) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore anything that starts with a dash
|
||||
if (result.string[0] == "-") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore anything that we don't find in the original text,
|
||||
// for some reason "bootstrap.js" becomes "bootstrapjs".
|
||||
if (!(new RegExp(result.string)).test(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
|
||||
if (results.length > 0) {
|
||||
console.log(results);
|
||||
}
|
||||
else {
|
||||
addCacheHash(hash);
|
||||
}
|
||||
|
||||
expect(results.length).to.be.equal(0);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
45
addon-sdk/source/bin/node-scripts/test.examples.js
Normal file
45
addon-sdk/source/bin/node-scripts/test.examples.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var jpm = utils.run;
|
||||
var readParam = utils.readParam;
|
||||
|
||||
var examplesPath = path.join(__dirname, "..", "..", "examples");
|
||||
|
||||
var binary = process.env.JPM_FIREFOX_BINARY || "nightly";
|
||||
var filterPattern = readParam("filter");
|
||||
|
||||
describe("jpm test sdk examples", function () {
|
||||
fs.readdirSync(examplesPath)
|
||||
.filter(fileFilter.bind(null, examplesPath))
|
||||
.forEach(function (file) {
|
||||
it(file, function (done) {
|
||||
var addonPath = path.join(examplesPath, file);
|
||||
process.chdir(addonPath);
|
||||
|
||||
var options = { cwd: addonPath, env: { JPM_FIREFOX_BINARY: binary }};
|
||||
if (process.env.DISPLAY) {
|
||||
options.env.DISPLAY = process.env.DISPLAY;
|
||||
}
|
||||
|
||||
jpm("test", options).then(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function fileFilter(root, file) {
|
||||
var matcher = filterPattern && new RegExp(filterPattern);
|
||||
if (/^(reading-data)/.test(file)) {
|
||||
return false;
|
||||
}
|
||||
if (matcher && !matcher.test(file)) {
|
||||
return false;
|
||||
}
|
||||
var stat = fs.statSync(path.join(root, file))
|
||||
return (stat && stat.isDirectory());
|
||||
}
|
||||
37
addon-sdk/source/bin/node-scripts/test.firefox-bin.js
Normal file
37
addon-sdk/source/bin/node-scripts/test.firefox-bin.js
Normal file
|
|
@ -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";
|
||||
|
||||
var fs = require("fs");
|
||||
var Promise = require("promise");
|
||||
var chai = require("chai");
|
||||
var expect = chai.expect;
|
||||
var normalizeBinary = require("fx-runner/lib/utils").normalizeBinary;
|
||||
|
||||
//var firefox_binary = process.env["JPM_FIREFOX_BINARY"] || normalizeBinary("nightly");
|
||||
|
||||
describe("Checking Firefox binary", function () {
|
||||
|
||||
it("using matching fx-runner version with jpm", function () {
|
||||
var sdkPackageJSON = require("../../package.json");
|
||||
var jpmPackageINI = require("jpm/package.json");
|
||||
expect(sdkPackageJSON.devDependencies["fx-runner"]).to.be.equal(jpmPackageINI.dependencies["fx-runner"]);
|
||||
});
|
||||
|
||||
it("exists", function (done) {
|
||||
var useEnvVar = new Promise(function(resolve) {
|
||||
resolve(process.env["JPM_FIREFOX_BINARY"]);
|
||||
});
|
||||
|
||||
var firefox_binary = process.env["JPM_FIREFOX_BINARY"] ? useEnvVar : normalizeBinary("nightly");
|
||||
firefox_binary.then(function(path) {
|
||||
expect(path).to.be.ok;
|
||||
fs.exists(path, function (exists) {
|
||||
expect(exists).to.be.ok;
|
||||
done();
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
68
addon-sdk/source/bin/node-scripts/test.ini.js
Normal file
68
addon-sdk/source/bin/node-scripts/test.ini.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var Promise = require("promise");
|
||||
var chai = require("chai");
|
||||
var expect = chai.expect;
|
||||
var ini = require("./update-ini");
|
||||
|
||||
var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
|
||||
var packageINI = path.resolve("./test/jetpack-package.ini");
|
||||
|
||||
describe("Checking ini files", function () {
|
||||
|
||||
it("Check test/addons/jetpack-addon.ini", function (done) {
|
||||
|
||||
fs.readFile(addonINI, function (err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// filter comments
|
||||
var text = data.toString().split("\n").filter(function(line) {
|
||||
return !/^\s*#/.test(line);
|
||||
}).join("\n");
|
||||
var expected = "";
|
||||
|
||||
ini.makeAddonIniContent()
|
||||
.then(function(contents) {
|
||||
expected = contents;
|
||||
|
||||
setTimeout(function end() {
|
||||
expect(text.trim()).to.be.equal(expected.trim());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("Check test/jetpack-package.ini", function (done) {
|
||||
|
||||
fs.readFile(packageINI, function (err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// filter comments
|
||||
var text = data.toString().split("\n").filter(function(line) {
|
||||
return !/^\s*#/.test(line);
|
||||
}).join("\n");
|
||||
var expected = "";
|
||||
|
||||
ini.makePackageIniContent()
|
||||
.then(function(contents) {
|
||||
expected = contents;
|
||||
|
||||
setTimeout(function end() {
|
||||
expect(text.trim()).to.be.equal(expected.trim());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
28
addon-sdk/source/bin/node-scripts/test.modules.js
Normal file
28
addon-sdk/source/bin/node-scripts/test.modules.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If 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 utils = require("./utils");
|
||||
var readParam = utils.readParam;
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var jpm = utils.run;
|
||||
var sdk = path.join(__dirname, "..", "..");
|
||||
var binary = process.env.JPM_FIREFOX_BINARY || "nightly";
|
||||
|
||||
var filterPattern = readParam("filter");
|
||||
|
||||
describe("jpm test sdk modules", function () {
|
||||
it("SDK Modules", function (done) {
|
||||
process.chdir(sdk);
|
||||
|
||||
var options = { cwd: sdk, env: { JPM_FIREFOX_BINARY: binary } };
|
||||
if (process.env.DISPLAY) {
|
||||
options.env.DISPLAY = process.env.DISPLAY;
|
||||
}
|
||||
options.filter = filterPattern;
|
||||
|
||||
jpm("test", options, process).then(done);
|
||||
});
|
||||
});
|
||||
141
addon-sdk/source/bin/node-scripts/update-ini.js
Normal file
141
addon-sdk/source/bin/node-scripts/update-ini.js
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var path = require("path");
|
||||
var cp = require("child_process");
|
||||
var fs = require("fs");
|
||||
var Promise = require("promise");
|
||||
var parser = require("ini-parser");
|
||||
|
||||
var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
|
||||
var addonsDir = path.resolve("./test/addons/");
|
||||
var packageINI = path.resolve("./test/jetpack-package.ini");
|
||||
var packageDir = path.resolve("./test/");
|
||||
var packageIgnorables = [ "addons", "preferences" ];
|
||||
var packageSupportFiles = [
|
||||
"fixtures.js",
|
||||
"test-context-menu.html",
|
||||
"util.js"
|
||||
]
|
||||
|
||||
function updateAddonINI() {
|
||||
return new Promise(function(resolve) {
|
||||
console.log("Start updating " + addonINI);
|
||||
|
||||
makeAddonIniContent().
|
||||
then(function(contents) {
|
||||
fs.writeFileSync(addonINI, contents, { encoding: "utf8" });
|
||||
console.log("Done updating " + addonINI);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
}
|
||||
exports.updateAddonINI = updateAddonINI;
|
||||
|
||||
function makeAddonIniContent() {
|
||||
return new Promise(function(resolve) {
|
||||
var data = parser.parse(fs.readFileSync(addonINI, { encoding: "utf8" }).toString());
|
||||
var result = {};
|
||||
|
||||
fs.readdir(addonsDir, function(err, files) {
|
||||
// get a list of folders
|
||||
var folders = files.filter(function(file) {
|
||||
return fs.statSync(path.resolve(addonsDir, file)).isDirectory();
|
||||
}).sort();
|
||||
|
||||
// copy any related data from the existing ini
|
||||
folders.forEach(function(folder) {
|
||||
var oldData = data[folder + ".xpi"];
|
||||
result[folder] = oldData ? oldData : {};
|
||||
});
|
||||
|
||||
// build a new ini file
|
||||
var contents = [];
|
||||
Object.keys(result).sort().forEach(function(key) {
|
||||
contents.push("[" + key + ".xpi]");
|
||||
Object.keys(result[key]).forEach(function(dataKey) {
|
||||
contents.push(dataKey + " = " + result[key][dataKey]);
|
||||
});
|
||||
});
|
||||
contents = contents.join("\n") + "\n";
|
||||
|
||||
return resolve(contents);
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.makeAddonIniContent = makeAddonIniContent;
|
||||
|
||||
function makePackageIniContent() {
|
||||
return new Promise(function(resolve) {
|
||||
var data = parser.parse(fs.readFileSync(packageINI, { encoding: "utf8" }).toString());
|
||||
var result = {};
|
||||
|
||||
fs.readdir(packageDir, function(err, files) {
|
||||
// get a list of folders
|
||||
var folders = files.filter(function(file) {
|
||||
var ignore = (packageIgnorables.indexOf(file) >= 0);
|
||||
var isDir = fs.statSync(path.resolve(packageDir, file)).isDirectory();
|
||||
return (isDir && !ignore);
|
||||
}).sort();
|
||||
|
||||
// get a list of "test-"" files
|
||||
var files = files.filter(function(file) {
|
||||
var ignore = !/^test\-.*\.js$/i.test(file);
|
||||
var isDir = fs.statSync(path.resolve(packageDir, file)).isDirectory();
|
||||
return (!isDir && !ignore);
|
||||
}).sort();
|
||||
|
||||
// get a list of the support files
|
||||
var support_files = packageSupportFiles.map(function(file) {
|
||||
return " " + file;
|
||||
});
|
||||
folders.forEach(function(folder) {
|
||||
support_files.push(" " + folder + "/**");
|
||||
});
|
||||
support_files = support_files.sort();
|
||||
|
||||
// copy any related data from the existing ini
|
||||
files.forEach(function(file) {
|
||||
var oldData = data[file];
|
||||
result[file] = oldData ? oldData : {};
|
||||
});
|
||||
|
||||
// build a new ini file
|
||||
var contents = [
|
||||
"[DEFAULT]",
|
||||
"support-files ="
|
||||
];
|
||||
support_files.forEach(function(support_file) {
|
||||
contents.push(support_file);
|
||||
});
|
||||
contents.push("");
|
||||
|
||||
Object.keys(result).sort().forEach(function(key) {
|
||||
contents.push("[" + key + "]");
|
||||
Object.keys(result[key]).forEach(function(dataKey) {
|
||||
contents.push(dataKey + " = " + result[key][dataKey]);
|
||||
});
|
||||
});
|
||||
contents = contents.join("\n") + "\n";
|
||||
|
||||
return resolve(contents);
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.makePackageIniContent = makePackageIniContent;
|
||||
|
||||
function updatePackageINI() {
|
||||
return new Promise(function(resolve) {
|
||||
console.log("Start updating " + packageINI);
|
||||
|
||||
makeAddonIniContent().
|
||||
then(function(contents) {
|
||||
fs.writeFileSync(packageINI, contents, { encoding: "utf8" });
|
||||
console.log("Done updating " + packageINI);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
}
|
||||
exports.updatePackageINI = updatePackageINI;
|
||||
104
addon-sdk/source/bin/node-scripts/utils.js
Normal file
104
addon-sdk/source/bin/node-scripts/utils.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If 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 _ = require("lodash");
|
||||
var path = require("path");
|
||||
var child_process = require("child_process");
|
||||
var jpm = require.resolve("../../node_modules/jpm/bin/jpm");
|
||||
var Promise = require("promise");
|
||||
var chai = require("chai");
|
||||
var expect = chai.expect;
|
||||
var assert = chai.assert;
|
||||
var DEFAULT_PROCESS = process;
|
||||
|
||||
var sdk = path.join(__dirname, "..", "..");
|
||||
var prefsPath = path.join(sdk, "test", "preferences", "test-preferences.js");
|
||||
var e10sPrefsPath = path.join(sdk, "test", "preferences", "test-e10s-preferences.js");
|
||||
|
||||
var OUTPUT_FILTERS = [
|
||||
/[^\n\r]+WARNING\: NS_ENSURE_SUCCESS\(rv, rv\) failed[^\n]+\n\r?/
|
||||
];
|
||||
|
||||
var isDebug = (process.env["JPM_FX_DEBUG"] == "1");
|
||||
exports.isDebug = isDebug;
|
||||
|
||||
function spawn (cmd, options) {
|
||||
options = options || {};
|
||||
var env = _.extend({}, options.env, process.env);
|
||||
|
||||
if (isDebug) {
|
||||
env["MOZ_QUIET"] = 1;
|
||||
}
|
||||
|
||||
var e10s = options.e10s || false;
|
||||
|
||||
return child_process.spawn("node", [
|
||||
jpm, cmd, "-v", "--tbpl",
|
||||
"--prefs", e10s ? e10sPrefsPath : prefsPath,
|
||||
"-o", sdk,
|
||||
"-f", options.filter || ""
|
||||
], {
|
||||
cwd: options.cwd || tmpOutputDir,
|
||||
env: env
|
||||
});
|
||||
}
|
||||
exports.spawn = spawn;
|
||||
|
||||
function run (cmd, options, p) {
|
||||
return new Promise(function(resolve) {
|
||||
var output = [];
|
||||
|
||||
var proc = spawn(cmd, options);
|
||||
proc.stderr.pipe(process.stderr);
|
||||
proc.stdout.on("data", function (data) {
|
||||
for (var i = OUTPUT_FILTERS.length - 1; i >= 0; i--) {
|
||||
if (OUTPUT_FILTERS[i].test(data)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
output.push(data);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (p) {
|
||||
proc.stdout.pipe(p.stdout);
|
||||
}
|
||||
else if (!isDebug) {
|
||||
proc.stdout.pipe(DEFAULT_PROCESS.stdout);
|
||||
}
|
||||
else {
|
||||
proc.stdout.on("data", function (data) {
|
||||
data = (data || "") + "";
|
||||
if (/TEST-/.test(data)) {
|
||||
DEFAULT_PROCESS.stdout.write(data.replace(/[\s\n]+$/, "") + "\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
proc.on("close", function(code) {
|
||||
var out = output.join("");
|
||||
var buildDisplayed = /Build \d+/.test(out);
|
||||
var noTests = /No tests were run/.test(out);
|
||||
var hasSuccess = /All tests passed!/.test(out);
|
||||
var hasFailure = /There were test failures\.\.\./.test(out);
|
||||
if (noTests || hasFailure || !hasSuccess || code != 0) {
|
||||
DEFAULT_PROCESS.stdout.write(out);
|
||||
}
|
||||
expect(code).to.equal(hasFailure ? 1 : 0);
|
||||
expect(buildDisplayed).to.equal(true);
|
||||
expect(hasFailure).to.equal(false);
|
||||
expect(hasSuccess).to.equal(true);
|
||||
expect(noTests).to.equal(false);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.run = run;
|
||||
|
||||
function readParam(name) {
|
||||
var index = process.argv.indexOf("--" + name)
|
||||
return index >= 0 && process.argv[index + 1]
|
||||
}
|
||||
exports.readParam = readParam;
|
||||
11
addon-sdk/source/bin/node-scripts/words.txt
Normal file
11
addon-sdk/source/bin/node-scripts/words.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
addon-sdk
|
||||
github
|
||||
stackoverflow
|
||||
bugzilla
|
||||
irc
|
||||
jsantell
|
||||
mossop
|
||||
gozala
|
||||
zer0
|
||||
autonome
|
||||
0c0w3
|
||||
3
addon-sdk/source/examples/actor-repl/README.md
Normal file
3
addon-sdk/source/examples/actor-repl/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Actor REPL
|
||||
|
||||
Simple REPL for a Firefox debugging protocol.
|
||||
File diff suppressed because one or more lines are too long
264
addon-sdk/source/examples/actor-repl/data/codemirror.css
Normal file
264
addon-sdk/source/examples/actor-repl/data/codemirror.css
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
/* Set scrolling behaviour here */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
z-index: 3;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
background: #7e7;
|
||||
z-index: 1;
|
||||
}
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
|
||||
|
||||
.cm-tab { display: inline-block; }
|
||||
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable {color: black;}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3 {color: #085;}
|
||||
.cm-s-default .cm-property {color: black;}
|
||||
.cm-s-default .cm-operator {color: black;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actuall scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
padding-bottom: 30px;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
padding-bottom: 30px;
|
||||
margin-bottom: -32px;
|
||||
display: inline-block;
|
||||
/* Hack to make IE7 behave */
|
||||
*zoom:1;
|
||||
*display:inline;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
}
|
||||
.CodeMirror pre {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
.CodeMirror-wrap pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-wrap .CodeMirror-scroll {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
.CodeMirror-focused div.CodeMirror-cursor {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
|
||||
.CodeMirror span { *vertical-align: text-bottom; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
147
addon-sdk/source/examples/actor-repl/data/index.html
Normal file
147
addon-sdk/source/examples/actor-repl/data/index.html
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="./codemirror.css">
|
||||
<link rel="stylesheet" href="./main.css">
|
||||
<script src="./codemirror-compressed.js"></script>
|
||||
<views>
|
||||
<section class="task cm-s-default">
|
||||
<pre class="request "></pre>
|
||||
<pre class="response"><span class="one"></span><span class="two"></span><span class="three"></span></pre>
|
||||
</section>
|
||||
</views>
|
||||
</head>
|
||||
<body>
|
||||
<pre class="input"></pre>
|
||||
</body>
|
||||
<script>
|
||||
function debounce(fn, ms) {
|
||||
var id;
|
||||
return function(...args) {
|
||||
clearTimeout(id);
|
||||
id = setTimeout(fn, ms, ...args);
|
||||
};
|
||||
}
|
||||
|
||||
function Try(fn) {
|
||||
return function(...args) {
|
||||
try { return fn(...args); }
|
||||
catch (error) { return null; }
|
||||
};
|
||||
}
|
||||
|
||||
var parse = Try(JSON.parse);
|
||||
|
||||
var CommandHistory = {
|
||||
init: function() {
|
||||
this._state = {};
|
||||
this._state.els = document.querySelectorAll("body > section.task > .request");
|
||||
this._state.idx = this._state.els.length;
|
||||
},
|
||||
get prev() {
|
||||
if (!!this._state.els && this._state.idx > 0) {
|
||||
this._state.idx--;
|
||||
return this._state.els[this._state.idx].textContent;
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
get next() {
|
||||
if (!!this._state.els && this._state.idx < this._state.els.length-1) {
|
||||
this._state.idx++;
|
||||
return this._state.els[this._state.idx].textContent;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function cmdHistory(fn, editor) {
|
||||
editor.setValue(fn());
|
||||
document.querySelector(".input").scrollIntoView();
|
||||
}
|
||||
|
||||
var cmdHistoryNext = cmdHistory.bind(null, () => CommandHistory.next);
|
||||
var cmdHistoryBack = cmdHistory.bind(null, () => CommandHistory.prev);
|
||||
|
||||
function send(editor) {
|
||||
var input = editor.getWrapperElement().parentNode;
|
||||
var code = editor.getValue().trim();
|
||||
var packet = parse(code);
|
||||
if (packet) {
|
||||
var task = document.querySelector("views .task").cloneNode(true);
|
||||
var request = task.querySelector(".request");
|
||||
var response = task.querySelector(".response");
|
||||
|
||||
input.parentNode.insertBefore(task, input);
|
||||
|
||||
CodeMirror.runMode(JSON.stringify(packet, 2, 2),
|
||||
"application/json",
|
||||
request);
|
||||
response.classList.add("pending");
|
||||
|
||||
editor.setValue("");
|
||||
|
||||
document.querySelector(".input").scrollIntoView();
|
||||
|
||||
port.postMessage(packet);
|
||||
}
|
||||
}
|
||||
|
||||
var editor = CodeMirror(document.querySelector(".input"), {
|
||||
autofocus: true,
|
||||
mode: "application/json",
|
||||
matchBrackets: true,
|
||||
value: '{"to": "root", "type": "requestTypes"}',
|
||||
extraKeys: {"Cmd-Enter": send,
|
||||
"Ctrl-Enter": send,
|
||||
"Cmd-Down": cmdHistoryNext,
|
||||
"Ctrl-Down": cmdHistoryNext,
|
||||
"Cmd-Up": cmdHistoryBack,
|
||||
"Ctrl-Up": cmdHistoryBack}
|
||||
});
|
||||
editor.on("change", debounce(function(editor) {
|
||||
var input = editor.getWrapperElement().parentNode;
|
||||
if (parse(editor.getValue().trim())) {
|
||||
input.classList.remove("invalid");
|
||||
} else {
|
||||
input.classList.add("invalid");
|
||||
}
|
||||
}, 800));
|
||||
</script>
|
||||
<script>
|
||||
window.addEventListener("message", event => {
|
||||
window.port = event.ports[0];
|
||||
port.onmessage = onMessage;
|
||||
});
|
||||
|
||||
var onMessage = (event) => {
|
||||
var packet = event.data;
|
||||
var code = JSON.stringify(packet, 2, 2);
|
||||
|
||||
var input = document.querySelector(".input");
|
||||
var response = document.querySelector(".task .response.pending");
|
||||
|
||||
if (!response) {
|
||||
message = document.querySelector("views .task").cloneNode(true);
|
||||
response = message.querySelector(".response");
|
||||
response.classList.add("message");
|
||||
|
||||
input.parentNode.insertBefore(message, input);
|
||||
}
|
||||
|
||||
if (packet.error) {
|
||||
response.classList.add("error");
|
||||
}
|
||||
|
||||
CodeMirror.runMode(code, "application/json", response);
|
||||
response.classList.remove("pending");
|
||||
|
||||
document.querySelector(".input").scrollIntoView();
|
||||
|
||||
CommandHistory.init();
|
||||
};
|
||||
</script>
|
||||
</html>
|
||||
117
addon-sdk/source/examples/actor-repl/data/main.css
Normal file
117
addon-sdk/source/examples/actor-repl/data/main.css
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
body
|
||||
{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: white;
|
||||
}
|
||||
|
||||
|
||||
pre
|
||||
{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
section
|
||||
{
|
||||
border-top: 1px solid rgba(150, 150, 150, 0.5);
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
height: auto;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
overflow-y: hidden;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.request,
|
||||
.response,
|
||||
.input
|
||||
{
|
||||
border-left: 5px solid;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.request:not(:empty),
|
||||
.response.pending
|
||||
{
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.input
|
||||
{
|
||||
padding-left: 6px;
|
||||
border-color: lightgreen;
|
||||
}
|
||||
.input.invalid
|
||||
{
|
||||
border-color: orange;
|
||||
}
|
||||
|
||||
.request
|
||||
{
|
||||
border-color: lightgrey;
|
||||
}
|
||||
|
||||
.response
|
||||
{
|
||||
border-color: grey;
|
||||
}
|
||||
.response.error
|
||||
{
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.response.message
|
||||
{
|
||||
border-color: lightblue;
|
||||
}
|
||||
|
||||
.response .one,
|
||||
.response .two,
|
||||
.response .three
|
||||
{
|
||||
width: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.response.pending .one,
|
||||
.response.pending .two,
|
||||
.response.pending .three
|
||||
{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: rgba(150, 150, 150, 0.5);
|
||||
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
animation: bouncedelay 1.4s infinite ease-in-out;
|
||||
/* Prevent first frame from flickering when animation starts */
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.response.pending .one
|
||||
{
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.response.pending .two
|
||||
{
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@keyframes bouncedelay {
|
||||
0%, 80%, 100% {
|
||||
transform: scale(0.0);
|
||||
} 40% {
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
BIN
addon-sdk/source/examples/actor-repl/data/robot.png
Normal file
BIN
addon-sdk/source/examples/actor-repl/data/robot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
37
addon-sdk/source/examples/actor-repl/index.js
Normal file
37
addon-sdk/source/examples/actor-repl/index.js
Normal file
|
|
@ -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";
|
||||
|
||||
const { Panel } = require("dev/panel");
|
||||
const { Tool } = require("dev/toolbox");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
|
||||
|
||||
const REPLPanel = Class({
|
||||
extends: Panel,
|
||||
label: "Actor REPL",
|
||||
tooltip: "Firefox debugging protocol REPL",
|
||||
icon: "./robot.png",
|
||||
url: "./index.html",
|
||||
setup: function({debuggee}) {
|
||||
this.debuggee = debuggee;
|
||||
},
|
||||
dispose: function() {
|
||||
this.debuggee = null;
|
||||
},
|
||||
onReady: function() {
|
||||
console.log("repl panel document is interactive");
|
||||
this.debuggee.start();
|
||||
this.postMessage("RDP", [this.debuggee]);
|
||||
},
|
||||
onLoad: function() {
|
||||
console.log("repl panel document is fully loaded");
|
||||
}
|
||||
});
|
||||
exports.REPLPanel = REPLPanel;
|
||||
|
||||
|
||||
const replTool = new Tool({
|
||||
panels: { repl: REPLPanel }
|
||||
});
|
||||
10
addon-sdk/source/examples/actor-repl/package.json
Normal file
10
addon-sdk/source/examples/actor-repl/package.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "actor-repl",
|
||||
"id": "@actor-repl",
|
||||
"title": "Actor REPL",
|
||||
"description": "Actor REPL",
|
||||
"version": "0.0.1",
|
||||
"author": "Irakli Gozalishvili",
|
||||
"main": "./index.js",
|
||||
"license": "MPL-2.0"
|
||||
}
|
||||
10
addon-sdk/source/examples/actor-repl/test/test-main.js
Normal file
10
addon-sdk/source/examples/actor-repl/test/test-main.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
exports.testMain = function(assert) {
|
||||
assert.pass("TODO: Write some tests.");
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
816
addon-sdk/source/examples/debug-client/data/client.js
Normal file
816
addon-sdk/source/examples/debug-client/data/client.js
Normal file
|
|
@ -0,0 +1,816 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
|
||||
|
||||
var describe = Object.getOwnPropertyDescriptor;
|
||||
var Class = fields => {
|
||||
var constructor = fields.constructor || function() {};
|
||||
var ancestor = fields.extends || Object;
|
||||
|
||||
|
||||
|
||||
var descriptor = {};
|
||||
for (var key of Object.keys(fields))
|
||||
descriptor[key] = describe(fields, key);
|
||||
|
||||
var prototype = Object.create(ancestor.prototype, descriptor);
|
||||
|
||||
constructor.prototype = prototype;
|
||||
prototype.constructor = constructor;
|
||||
|
||||
return constructor;
|
||||
};
|
||||
|
||||
|
||||
var bus = function Bus() {
|
||||
var parser = new DOMParser();
|
||||
return parser.parseFromString("<EventTarget/>", "application/xml").documentElement;
|
||||
}();
|
||||
|
||||
var GUID = new WeakMap();
|
||||
GUID.id = 0;
|
||||
var guid = x => GUID.get(x);
|
||||
var setGUID = x => {
|
||||
GUID.set(x, ++ GUID.id);
|
||||
};
|
||||
|
||||
var Emitter = Class({
|
||||
extends: EventTarget,
|
||||
constructor: function() {
|
||||
this.setupEmitter();
|
||||
},
|
||||
setupEmitter: function() {
|
||||
setGUID(this);
|
||||
},
|
||||
addEventListener: function(type, listener, capture) {
|
||||
bus.addEventListener(type + "@" + guid(this),
|
||||
listener, capture);
|
||||
},
|
||||
removeEventListener: function(type, listener, capture) {
|
||||
bus.removeEventListener(type + "@" + guid(this),
|
||||
listener, capture);
|
||||
}
|
||||
});
|
||||
|
||||
function dispatch(target, type, data) {
|
||||
var event = new MessageEvent(type + "@" + guid(target), {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
data: data
|
||||
});
|
||||
bus.dispatchEvent(event);
|
||||
}
|
||||
|
||||
var supervisedWorkers = new WeakMap();
|
||||
var supervised = supervisor => {
|
||||
if (!supervisedWorkers.has(supervisor)) {
|
||||
supervisedWorkers.set(supervisor, new Map());
|
||||
supervisor.connection.addActorPool(supervisor);
|
||||
}
|
||||
return supervisedWorkers.get(supervisor);
|
||||
};
|
||||
|
||||
var Supervisor = Class({
|
||||
extends: Emitter,
|
||||
constructor: function(...params) {
|
||||
this.setupEmitter(...params);
|
||||
this.setupSupervisor(...params);
|
||||
},
|
||||
Supervisor: function(connection) {
|
||||
this.connection = connection;
|
||||
},
|
||||
/**
|
||||
* Return the parent pool for this client.
|
||||
*/
|
||||
supervisor: function() {
|
||||
return this.connection.poolFor(this.actorID);
|
||||
},
|
||||
/**
|
||||
* Override this if you want actors returned by this actor
|
||||
* to belong to a different actor by default.
|
||||
*/
|
||||
marshallPool: function() { return this; },
|
||||
/**
|
||||
* Add an actor as a child of this pool.
|
||||
*/
|
||||
supervise: function(actor) {
|
||||
if (!actor.actorID)
|
||||
actor.actorID = this.connection.allocID(actor.actorPrefix ||
|
||||
actor.typeName);
|
||||
|
||||
supervised(this).set(actor.actorID, actor);
|
||||
return actor;
|
||||
},
|
||||
/**
|
||||
* Remove an actor as a child of this pool.
|
||||
*/
|
||||
abandon: function(actor) {
|
||||
supervised(this).delete(actor.actorID);
|
||||
},
|
||||
// true if the given actor ID exists in the pool.
|
||||
has: function(actorID) {
|
||||
return supervised(this).has(actorID);
|
||||
},
|
||||
// Same as actor, should update debugger connection to use 'actor'
|
||||
// and then remove this.
|
||||
get: function(actorID) {
|
||||
return supervised(this).get(actorID);
|
||||
},
|
||||
actor: function(actorID) {
|
||||
return supervised(this).get(actorID);
|
||||
},
|
||||
isEmpty: function() {
|
||||
return supervised(this).size === 0;
|
||||
},
|
||||
/**
|
||||
* For getting along with the debugger server pools, should be removable
|
||||
* eventually.
|
||||
*/
|
||||
cleanup: function() {
|
||||
this.destroy();
|
||||
},
|
||||
destroy: function() {
|
||||
var supervisor = this.supervisor();
|
||||
if (supervisor)
|
||||
supervisor.abandon(this);
|
||||
|
||||
for (var actor of supervised(this).values()) {
|
||||
if (actor !== this) {
|
||||
var destroy = actor.destroy;
|
||||
// Disconnect destroy while we're destroying in case of (misbehaving)
|
||||
// circular ownership.
|
||||
if (destroy) {
|
||||
actor.destroy = null;
|
||||
destroy.call(actor);
|
||||
actor.destroy = destroy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.connection.removeActorPool(this);
|
||||
supervised(this).clear();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
var mailbox = new WeakMap();
|
||||
var clientRequests = new WeakMap();
|
||||
|
||||
var inbox = client => mailbox.get(client).inbox;
|
||||
var outbox = client => mailbox.get(client).outbox;
|
||||
var requests = client => clientRequests.get(client);
|
||||
|
||||
|
||||
var Receiver = Class({
|
||||
receive: function(packet) {
|
||||
if (packet.error)
|
||||
this.reject(packet.error);
|
||||
else
|
||||
this.resolve(this.read(packet));
|
||||
}
|
||||
});
|
||||
|
||||
var Connection = Class({
|
||||
constructor: function() {
|
||||
// Queue of the outgoing messages.
|
||||
this.outbox = [];
|
||||
// Map of pending requests.
|
||||
this.pending = new Map();
|
||||
this.pools = new Set();
|
||||
},
|
||||
isConnected: function() {
|
||||
return !!this.port
|
||||
},
|
||||
connect: function(port) {
|
||||
this.port = port;
|
||||
port.addEventListener("message", this);
|
||||
port.start();
|
||||
|
||||
this.flush();
|
||||
},
|
||||
addPool: function(pool) {
|
||||
this.pools.add(pool);
|
||||
},
|
||||
removePool: function(pool) {
|
||||
this.pools.delete(pool);
|
||||
},
|
||||
poolFor: function(id) {
|
||||
for (let pool of this.pools.values()) {
|
||||
if (pool.has(id))
|
||||
return pool;
|
||||
}
|
||||
},
|
||||
get: function(id) {
|
||||
var pool = this.poolFor(id);
|
||||
return pool && pool.get(id);
|
||||
},
|
||||
disconnect: function() {
|
||||
this.port.stop();
|
||||
this.port = null;
|
||||
for (var request of this.pending.values()) {
|
||||
request.catch(new Error("Connection closed"));
|
||||
}
|
||||
this.pending.clear();
|
||||
|
||||
var requests = this.outbox.splice(0);
|
||||
for (var request of request) {
|
||||
requests.catch(new Error("Connection closed"));
|
||||
}
|
||||
},
|
||||
handleEvent: function(event) {
|
||||
this.receive(event.data);
|
||||
},
|
||||
flush: function() {
|
||||
if (this.isConnected()) {
|
||||
for (var request of this.outbox) {
|
||||
if (!this.pending.has(request.to)) {
|
||||
this.outbox.splice(this.outbox.indexOf(request), 1);
|
||||
this.pending.set(request.to, request);
|
||||
this.send(request.packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
send: function(packet) {
|
||||
this.port.postMessage(packet);
|
||||
},
|
||||
request: function(packet) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
this.outbox.push({
|
||||
to: packet.to,
|
||||
packet: packet,
|
||||
receive: resolve,
|
||||
catch: reject
|
||||
});
|
||||
this.flush();
|
||||
});
|
||||
},
|
||||
receive: function(packet) {
|
||||
var { from, type, why } = packet;
|
||||
var receiver = this.pending.get(from);
|
||||
if (!receiver) {
|
||||
console.warn("Unable to handle received packet", data);
|
||||
} else {
|
||||
this.pending.delete(from);
|
||||
if (packet.error)
|
||||
receiver.catch(packet.error);
|
||||
else
|
||||
receiver.receive(packet);
|
||||
}
|
||||
this.flush();
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Base class for client-side actor fronts.
|
||||
*/
|
||||
var Client = Class({
|
||||
extends: Supervisor,
|
||||
constructor: function(from=null, detail=null, connection=null) {
|
||||
this.Client(from, detail, connection);
|
||||
},
|
||||
Client: function(form, detail, connection) {
|
||||
this.Supervisor(connection);
|
||||
|
||||
if (form) {
|
||||
this.actorID = form.actor;
|
||||
this.from(form, detail);
|
||||
}
|
||||
},
|
||||
connect: function(port) {
|
||||
this.connection = new Connection(port);
|
||||
},
|
||||
actorID: null,
|
||||
actor: function() {
|
||||
return this.actorID;
|
||||
},
|
||||
/**
|
||||
* Update the actor from its representation.
|
||||
* Subclasses should override this.
|
||||
*/
|
||||
form: function(form) {
|
||||
},
|
||||
/**
|
||||
* Method is invokeid when packet received constitutes an
|
||||
* event. By default such packets are demarshalled and
|
||||
* dispatched on the client instance.
|
||||
*/
|
||||
dispatch: function(packet) {
|
||||
},
|
||||
/**
|
||||
* Method is invoked when packet is returned in response to
|
||||
* a request. By default respond delivers response to a first
|
||||
* request in a queue.
|
||||
*/
|
||||
read: function(input) {
|
||||
throw new TypeError("Subclass must implement read method");
|
||||
},
|
||||
write: function(input) {
|
||||
throw new TypeError("Subclass must implement write method");
|
||||
},
|
||||
respond: function(packet) {
|
||||
var [resolve, reject] = requests(this).shift();
|
||||
if (packet.error)
|
||||
reject(packet.error);
|
||||
else
|
||||
resolve(this.read(packet));
|
||||
},
|
||||
receive: function(packet) {
|
||||
if (this.isEventPacket(packet)) {
|
||||
this.dispatch(packet);
|
||||
}
|
||||
else if (requests(this).length) {
|
||||
this.respond(packet);
|
||||
}
|
||||
else {
|
||||
this.catch(packet);
|
||||
}
|
||||
},
|
||||
send: function(packet) {
|
||||
Promise.cast(packet.to || this.actor()).then(id => {
|
||||
packet.to = id;
|
||||
this.connection.send(packet);
|
||||
})
|
||||
},
|
||||
request: function(packet) {
|
||||
return this.connection.request(packet);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var Destructor = method => {
|
||||
return function(...args) {
|
||||
return method.apply(this, args).then(result => {
|
||||
this.destroy();
|
||||
return result;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
var Profiled = (method, id) => {
|
||||
return function(...args) {
|
||||
var start = new Date();
|
||||
return method.apply(this, args).then(result => {
|
||||
var end = new Date();
|
||||
this.telemetry.add(id, +end - start);
|
||||
return result;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
var Method = (request, response) => {
|
||||
return response ? new BidirectionalMethod(request, response) :
|
||||
new UnidirecationalMethod(request);
|
||||
};
|
||||
|
||||
var UnidirecationalMethod = request => {
|
||||
return function(...args) {
|
||||
var packet = request.write(args, this);
|
||||
this.connection.send(packet);
|
||||
return Promise.resolve(void(0));
|
||||
};
|
||||
};
|
||||
|
||||
var BidirectionalMethod = (request, response) => {
|
||||
return function(...args) {
|
||||
var packet = request.write(args, this);
|
||||
return this.connection.request(packet).then(packet => {
|
||||
return response.read(packet, this);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Client.from = ({category, typeName, methods, events}) => {
|
||||
var proto = {
|
||||
constructor: function(...args) {
|
||||
this.Client(...args);
|
||||
},
|
||||
extends: Client,
|
||||
name: typeName
|
||||
};
|
||||
|
||||
methods.forEach(({telemetry, request, response, name, oneway, release}) => {
|
||||
var [reader, writer] = oneway ? [, new Request(request)] :
|
||||
[new Request(request), new Response(response)];
|
||||
var method = new Method(request, response);
|
||||
var profiler = telemetry ? new Profiler(method) : method;
|
||||
var destructor = release ? new Destructor(profiler) : profiler;
|
||||
proto[name] = destructor;
|
||||
});
|
||||
|
||||
return Class(proto);
|
||||
};
|
||||
|
||||
|
||||
var defineType = (client, descriptor) => {
|
||||
var type = void(0)
|
||||
if (typeof(descriptor) === "string") {
|
||||
if (name.indexOf(":") > 0)
|
||||
type = makeCompoundType(descriptor);
|
||||
else if (name.indexOf("#") > 0)
|
||||
type = new ActorDetail(descriptor);
|
||||
else if (client.specification[descriptor])
|
||||
type = makeCategoryType(client.specification[descriptor]);
|
||||
} else {
|
||||
type = makeCategoryType(descriptor);
|
||||
}
|
||||
|
||||
if (type)
|
||||
client.types.set(type.name, type);
|
||||
else
|
||||
throw TypeError("Invalid type: " + descriptor);
|
||||
};
|
||||
|
||||
|
||||
var makeCompoundType = name => {
|
||||
var index = name.indexOf(":");
|
||||
var [baseType, subType] = [name.slice(0, index), parts.slice(1)];
|
||||
return baseType === "array" ? new ArrayOf(subType) :
|
||||
baseType === "nullable" ? new Maybe(subType) :
|
||||
null;
|
||||
};
|
||||
|
||||
var makeCategoryType = (descriptor) => {
|
||||
var { category } = descriptor;
|
||||
return category === "dict" ? new Dictionary(descriptor) :
|
||||
category === "actor" ? new Actor(descriptor) :
|
||||
null;
|
||||
};
|
||||
|
||||
|
||||
var typeFor = (client, type="primitive") => {
|
||||
if (!client.types.has(type))
|
||||
defineType(client, type);
|
||||
|
||||
return client.types.get(type);
|
||||
};
|
||||
|
||||
|
||||
var Client = Class({
|
||||
constructor: function() {
|
||||
},
|
||||
setupTypes: function(specification) {
|
||||
this.specification = specification;
|
||||
this.types = new Map();
|
||||
},
|
||||
read: function(input, type) {
|
||||
return typeFor(this, type).read(input, this);
|
||||
},
|
||||
write: function(input, type) {
|
||||
return typeFor(this, type).write(input, this);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var Type = Class({
|
||||
get name() {
|
||||
return this.category ? this.category + ":" + this.type :
|
||||
this.type;
|
||||
},
|
||||
read: function(input, client) {
|
||||
throw new TypeError("`Type` subclass must implement `read`");
|
||||
},
|
||||
write: function(input, client) {
|
||||
throw new TypeError("`Type` subclass must implement `write`");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var Primitve = Class({
|
||||
extends: Type,
|
||||
constuctor: function(type) {
|
||||
this.type = type;
|
||||
},
|
||||
read: function(input, client) {
|
||||
return input;
|
||||
},
|
||||
write: function(input, client) {
|
||||
return input;
|
||||
}
|
||||
});
|
||||
|
||||
var Maybe = Class({
|
||||
extends: Type,
|
||||
category: "nullable",
|
||||
constructor: function(type) {
|
||||
this.type = type;
|
||||
},
|
||||
read: function(input, client) {
|
||||
return input === null ? null :
|
||||
input === void(0) ? void(0) :
|
||||
client.read(input, this.type);
|
||||
},
|
||||
write: function(input, client) {
|
||||
return input === null ? null :
|
||||
input === void(0) ? void(0) :
|
||||
client.write(input, this.type);
|
||||
}
|
||||
});
|
||||
|
||||
var ArrayOf = Class({
|
||||
extends: Type,
|
||||
category: "array",
|
||||
constructor: function(type) {
|
||||
this.type = type;
|
||||
},
|
||||
read: function(input, client) {
|
||||
return input.map($ => client.read($, this.type));
|
||||
},
|
||||
write: function(input, client) {
|
||||
return input.map($ => client.write($, this.type));
|
||||
}
|
||||
});
|
||||
|
||||
var Dictionary = Class({
|
||||
exteds: Type,
|
||||
category: "dict",
|
||||
get name() { return this.type; },
|
||||
constructor: function({typeName, specializations}) {
|
||||
this.type = typeName;
|
||||
this.types = specifications;
|
||||
},
|
||||
read: function(input, client) {
|
||||
var output = {};
|
||||
for (var key in input) {
|
||||
output[key] = client.read(input[key], this.types[key]);
|
||||
}
|
||||
return output;
|
||||
},
|
||||
write: function(input, client) {
|
||||
var output = {};
|
||||
for (var key in input) {
|
||||
output[key] = client.write(value, this.types[key]);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
});
|
||||
|
||||
var Actor = Class({
|
||||
exteds: Type,
|
||||
category: "actor",
|
||||
get name() { return this.type; },
|
||||
constructor: function({typeName}) {
|
||||
this.type = typeName;
|
||||
},
|
||||
read: function(input, client, detail) {
|
||||
var id = value.actor;
|
||||
var actor = void(0);
|
||||
if (client.connection.has(id)) {
|
||||
return client.connection.get(id).form(input, detail, client);
|
||||
} else {
|
||||
actor = Client.from(detail, client);
|
||||
actor.actorID = id;
|
||||
client.supervise(actor);
|
||||
}
|
||||
},
|
||||
write: function(input, client, detail) {
|
||||
if (input instanceof Actor) {
|
||||
if (!input.actorID) {
|
||||
client.supervise(input);
|
||||
}
|
||||
return input.from(detail);
|
||||
}
|
||||
return input.actorID;
|
||||
}
|
||||
});
|
||||
|
||||
var Root = Client.from({
|
||||
"category": "actor",
|
||||
"typeName": "root",
|
||||
"methods": [
|
||||
{"name": "listTabs",
|
||||
"request": {},
|
||||
"response": {
|
||||
}
|
||||
},
|
||||
{"name": "listAddons"
|
||||
},
|
||||
{"name": "echo",
|
||||
|
||||
},
|
||||
{"name": "protocolDescription",
|
||||
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
var ActorDetail = Class({
|
||||
extends: Actor,
|
||||
constructor: function(name, actor, detail) {
|
||||
this.detail = detail;
|
||||
this.actor = actor;
|
||||
},
|
||||
read: function(input, client) {
|
||||
this.actor.read(input, client, this.detail);
|
||||
},
|
||||
write: function(input, client) {
|
||||
this.actor.write(input, client, this.detail);
|
||||
}
|
||||
});
|
||||
|
||||
var registeredLifetimes = new Map();
|
||||
var LifeTime = Class({
|
||||
extends: Type,
|
||||
category: "lifetime",
|
||||
constructor: function(lifetime, type) {
|
||||
this.name = lifetime + ":" + type.name;
|
||||
this.field = registeredLifetimes.get(lifetime);
|
||||
},
|
||||
read: function(input, client) {
|
||||
return this.type.read(input, client[this.field]);
|
||||
},
|
||||
write: function(input, client) {
|
||||
return this.type.write(input, client[this.field]);
|
||||
}
|
||||
});
|
||||
|
||||
var primitive = new Primitve("primitive");
|
||||
var string = new Primitve("string");
|
||||
var number = new Primitve("number");
|
||||
var boolean = new Primitve("boolean");
|
||||
var json = new Primitve("json");
|
||||
var array = new Primitve("array");
|
||||
|
||||
|
||||
var TypedValue = Class({
|
||||
extends: Type,
|
||||
constructor: function(name, type) {
|
||||
this.TypedValue(name, type);
|
||||
},
|
||||
TypedValue: function(name, type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
},
|
||||
read: function(input, client) {
|
||||
return this.client.read(input, this.type);
|
||||
},
|
||||
write: function(input, client) {
|
||||
return this.client.write(input, this.type);
|
||||
}
|
||||
});
|
||||
|
||||
var Return = Class({
|
||||
extends: TypedValue,
|
||||
constructor: function(type) {
|
||||
this.type = type
|
||||
}
|
||||
});
|
||||
|
||||
var Argument = Class({
|
||||
extends: TypedValue,
|
||||
constructor: function(...args) {
|
||||
this.Argument(...args);
|
||||
},
|
||||
Argument: function(index, type) {
|
||||
this.index = index;
|
||||
this.TypedValue("argument[" + index + "]", type);
|
||||
},
|
||||
read: function(input, client, target) {
|
||||
return target[this.index] = client.read(input, this.type);
|
||||
}
|
||||
});
|
||||
|
||||
var Option = Class({
|
||||
extends: Argument,
|
||||
constructor: function(...args) {
|
||||
return this.Argument(...args);
|
||||
},
|
||||
read: function(input, client, target, name) {
|
||||
var param = target[this.index] || (target[this.index] = {});
|
||||
param[name] = input === void(0) ? input : client.read(input, this.type);
|
||||
},
|
||||
write: function(input, client, name) {
|
||||
var value = input && input[name];
|
||||
return value === void(0) ? value : client.write(value, this.type);
|
||||
}
|
||||
});
|
||||
|
||||
var Request = Class({
|
||||
extends: Type,
|
||||
constructor: function(template={}) {
|
||||
this.type = template.type;
|
||||
this.template = template;
|
||||
this.params = findPlaceholders(template, Argument);
|
||||
},
|
||||
read: function(packet, client) {
|
||||
var args = [];
|
||||
for (var param of this.params) {
|
||||
var {placeholder, path} = param;
|
||||
var name = path[path.length - 1];
|
||||
placeholder.read(getPath(packet, path), client, args, name);
|
||||
// TODO:
|
||||
// args[placeholder.index] = placeholder.read(query(packet, path), client);
|
||||
}
|
||||
return args;
|
||||
},
|
||||
write: function(input, client) {
|
||||
return JSON.parse(JSON.stringify(this.template, (key, value) => {
|
||||
return value instanceof Argument ? value.write(input[value.index],
|
||||
client, key) :
|
||||
value;
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
var Response = Class({
|
||||
extends: Type,
|
||||
constructor: function(template={}) {
|
||||
this.template = template;
|
||||
var [x] = findPlaceholders(template, Return);
|
||||
var {placeholder, path} = x;
|
||||
this.return = placeholder;
|
||||
this.path = path;
|
||||
},
|
||||
read: function(packet, client) {
|
||||
var value = query(packet, this.path);
|
||||
return this.return.read(value, client);
|
||||
},
|
||||
write: function(input, client) {
|
||||
return JSON.parse(JSON.stringify(this.template, (key, value) => {
|
||||
return value instanceof Return ? value.write(input) :
|
||||
input
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// Returns array of values for the given object.
|
||||
var values = object => Object.keys(object).map(key => object[key]);
|
||||
// Returns [key, value] pairs for the given object.
|
||||
var pairs = object => Object.keys(object).map(key => [key, object[key]]);
|
||||
// Queries an object for the field nested with in it.
|
||||
var query = (object, path) => path.reduce((object, entry) => object && object[entry],
|
||||
object);
|
||||
|
||||
|
||||
var Root = Client.from({
|
||||
"category": "actor",
|
||||
"typeName": "root",
|
||||
"methods": [
|
||||
{
|
||||
"name": "echo",
|
||||
"request": {
|
||||
"string": { "_arg": 0, "type": "string" }
|
||||
},
|
||||
"response": {
|
||||
"string": { "_retval": "string" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "listTabs",
|
||||
"request": {},
|
||||
"response": { "_retval": "tablist" }
|
||||
},
|
||||
{
|
||||
"name": "actorDescriptions",
|
||||
"request": {},
|
||||
"response": { "_retval": "json" }
|
||||
}
|
||||
],
|
||||
"events": {
|
||||
"tabListChanged": {}
|
||||
}
|
||||
});
|
||||
|
||||
var Tab = Client.from({
|
||||
"category": "dict",
|
||||
"typeName": "tab",
|
||||
"specifications": {
|
||||
"title": "string",
|
||||
"url": "string",
|
||||
"outerWindowID": "number",
|
||||
"console": "console",
|
||||
"inspectorActor": "inspector",
|
||||
"callWatcherActor": "call-watcher",
|
||||
"canvasActor": "canvas",
|
||||
"webglActor": "webgl",
|
||||
"webaudioActor": "webaudio",
|
||||
"styleSheetsActor": "stylesheets",
|
||||
"styleEditorActor": "styleeditor",
|
||||
"storageActor": "storage",
|
||||
"gcliActor": "gcli",
|
||||
"memoryActor": "memory",
|
||||
"eventLoopLag": "eventLoopLag",
|
||||
|
||||
"trace": "trace", // missing
|
||||
}
|
||||
});
|
||||
|
||||
var tablist = Client.from({
|
||||
"category": "dict",
|
||||
"typeName": "tablist",
|
||||
"specializations": {
|
||||
"selected": "number",
|
||||
"tabs": "array:tab"
|
||||
}
|
||||
});
|
||||
|
||||
})(this);
|
||||
|
||||
50
addon-sdk/source/examples/debug-client/data/index.html
Normal file
50
addon-sdk/source/examples/debug-client/data/index.html
Normal file
|
|
@ -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/. -->
|
||||
<html>
|
||||
<head>
|
||||
<script src="resource://sdk/dev/volcan.js"></script>
|
||||
<script src="./task.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
<script>
|
||||
const wait = (target, type, capture) => new Promise((resolve, reject) => {
|
||||
const listener = event => {
|
||||
target.removeEventListener(type, listener, capture);
|
||||
resolve(event);
|
||||
};
|
||||
target.addEventListener(type, listener, capture);
|
||||
});
|
||||
|
||||
const display = message =>
|
||||
document.body.innerHTML += message + "<br/>";
|
||||
|
||||
Task.spawn(function*() {
|
||||
var event = yield wait(window, "message");
|
||||
var port = event.ports[0];
|
||||
|
||||
display("Port received");
|
||||
var root = yield volcan.connect(port);
|
||||
|
||||
display("Connected to a debugger");
|
||||
|
||||
var message = yield root.echo("hello")
|
||||
|
||||
display("Received echo for: " + message);
|
||||
|
||||
var list = yield root.listTabs();
|
||||
|
||||
display("You have " + list.tabs.length + " open tabs");
|
||||
|
||||
var activeTab = list.tabs[list.selected];
|
||||
|
||||
display("Your active tab url is: " + activeTab.url);
|
||||
|
||||
var sheets = yield activeTab.styleSheetsActor.getStyleSheets();
|
||||
|
||||
display("Page in active tab has " + sheets.length + " stylesheets");
|
||||
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
BIN
addon-sdk/source/examples/debug-client/data/plugin.png
Normal file
BIN
addon-sdk/source/examples/debug-client/data/plugin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
28
addon-sdk/source/examples/debug-client/data/task.js
Normal file
28
addon-sdk/source/examples/debug-client/data/task.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
|
||||
const spawn = (task, ...args) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const routine = task(...args);
|
||||
const raise = error => routine.throw(error);
|
||||
const step = data => {
|
||||
const { done, value } = routine.next(data);
|
||||
if (done)
|
||||
resolve(value);
|
||||
else
|
||||
Promise.resolve(value).then(step, raise);
|
||||
}
|
||||
step();
|
||||
} catch(error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.spawn = spawn;
|
||||
|
||||
})(Task = {});
|
||||
33
addon-sdk/source/examples/debug-client/index.js
Normal file
33
addon-sdk/source/examples/debug-client/index.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If 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 { Panel } = require("dev/panel");
|
||||
const { Tool } = require("dev/toolbox");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
|
||||
|
||||
const LadybugPanel = Class({
|
||||
extends: Panel,
|
||||
label: "Ladybug",
|
||||
tooltip: "Debug client example",
|
||||
icon: "./plugin.png",
|
||||
url: "./index.html",
|
||||
setup: function({debuggee}) {
|
||||
this.debuggee = debuggee;
|
||||
},
|
||||
dispose: function() {
|
||||
delete this.debuggee;
|
||||
},
|
||||
onReady: function() {
|
||||
this.debuggee.start();
|
||||
this.postMessage("RDP", [this.debuggee]);
|
||||
},
|
||||
});
|
||||
exports.LadybugPanel = LadybugPanel;
|
||||
|
||||
|
||||
const ladybug = new Tool({
|
||||
panels: { ladybug: LadybugPanel }
|
||||
});
|
||||
10
addon-sdk/source/examples/debug-client/package.json
Normal file
10
addon-sdk/source/examples/debug-client/package.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "debug-client",
|
||||
"id": "@debug-client",
|
||||
"title": "Debug client",
|
||||
"description": "Example debug client",
|
||||
"version": "0.0.1",
|
||||
"author": "Irakli Gozalishvili",
|
||||
"main": "./index.js",
|
||||
"license": "MPL-2.0"
|
||||
}
|
||||
10
addon-sdk/source/examples/debug-client/test/test-main.js
Normal file
10
addon-sdk/source/examples/debug-client/test/test-main.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
exports.testMain = function(assert) {
|
||||
assert.pass("TODO: Write some tests.");
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
BIN
addon-sdk/source/examples/reading-data/data/mom.png
Normal file
BIN
addon-sdk/source/examples/reading-data/data/mom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
7
addon-sdk/source/examples/reading-data/data/sample.html
Normal file
7
addon-sdk/source/examples/reading-data/data/sample.html
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<html><body>
|
||||
<h1>Hello World</h1>
|
||||
</body></html>
|
||||
53
addon-sdk/source/examples/reading-data/lib/main.js
Normal file
53
addon-sdk/source/examples/reading-data/lib/main.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var self = require("sdk/self");
|
||||
var { Panel } = require("sdk/panel");
|
||||
var { ToggleButton } = require("sdk/ui");
|
||||
|
||||
function replaceMom(html) {
|
||||
return html.replace("World", "Mom");
|
||||
}
|
||||
exports.replaceMom = replaceMom;
|
||||
|
||||
exports.main = function(options, callbacks) {
|
||||
console.log("My ID is " + self.id);
|
||||
|
||||
// Load the sample HTML into a string.
|
||||
var helloHTML = self.data.load("sample.html");
|
||||
|
||||
// Let's now modify it...
|
||||
helloHTML = replaceMom(helloHTML);
|
||||
|
||||
// ... and then create a panel that displays it.
|
||||
var myPanel = Panel({
|
||||
contentURL: "data:text/html," + helloHTML,
|
||||
onHide: handleHide
|
||||
});
|
||||
|
||||
// Create a widget that displays the image. We'll attach the panel to it.
|
||||
// When you click the widget, the panel will pop up.
|
||||
var button = ToggleButton({
|
||||
id: "test-widget",
|
||||
label: "Mom",
|
||||
icon: './mom.png',
|
||||
onChange: handleChange
|
||||
});
|
||||
|
||||
// If you run cfx with --static-args='{"quitWhenDone":true}' this program
|
||||
// will automatically quit Firefox when it's done.
|
||||
if (options.staticArgs.quitWhenDone)
|
||||
callbacks.quit();
|
||||
}
|
||||
|
||||
function handleChange(state) {
|
||||
if (state.checked) {
|
||||
myPanel.show({ position: button });
|
||||
}
|
||||
}
|
||||
|
||||
function handleHide() {
|
||||
button.state('window', { checked: false });
|
||||
}
|
||||
9
addon-sdk/source/examples/reading-data/package.json
Normal file
9
addon-sdk/source/examples/reading-data/package.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "reading-data",
|
||||
"description": "A demonstration of reading bundled data.",
|
||||
"keywords": [],
|
||||
"author": "Brian Warner",
|
||||
"contributors": [],
|
||||
"license": "MPL-2.0",
|
||||
"id": "reading-data-example@jetpack.mozillalabs.com"
|
||||
}
|
||||
25
addon-sdk/source/examples/reading-data/tests/test-main.js
Normal file
25
addon-sdk/source/examples/reading-data/tests/test-main.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If 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 m = require("main");
|
||||
var self = require("sdk/self");
|
||||
|
||||
exports.testReplace = function(test) {
|
||||
var input = "Hello World";
|
||||
var output = m.replaceMom(input);
|
||||
test.assertEqual(output, "Hello Mom");
|
||||
var callbacks = { quit: function() {} };
|
||||
|
||||
// Make sure it doesn't crash...
|
||||
m.main({ staticArgs: {} }, callbacks);
|
||||
};
|
||||
|
||||
exports.testID = function(test) {
|
||||
// The ID is randomly generated during tests, so we cannot compare it against
|
||||
// anything in particular. Just assert that it is not empty.
|
||||
test.assert(self.id.length > 0);
|
||||
test.assertEqual(self.data.url("sample.html"),
|
||||
"resource://reading-data-example-at-jetpack-dot-mozillalabs-dot-com/reading-data/data/sample.html");
|
||||
};
|
||||
BIN
addon-sdk/source/examples/theme/data/icon-16.png
Normal file
BIN
addon-sdk/source/examples/theme/data/icon-16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
9
addon-sdk/source/examples/theme/data/index.html
Normal file
9
addon-sdk/source/examples/theme/data/index.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
7
addon-sdk/source/examples/theme/data/theme.css
Normal file
7
addon-sdk/source/examples/theme/data/theme.css
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#devtools-theme-box {
|
||||
background-color: red !important;
|
||||
}
|
||||
37
addon-sdk/source/examples/theme/lib/main.js
Normal file
37
addon-sdk/source/examples/theme/lib/main.js
Normal file
|
|
@ -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";
|
||||
|
||||
const { Tool } = require("dev/toolbox");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
const { onEnable, onDisable } = require("dev/theme/hooks");
|
||||
const { Theme, LightTheme } = require("dev/theme");
|
||||
|
||||
/**
|
||||
* This object represents a new theme registered within the Toolbox.
|
||||
* You can activate it by clicking on "My Light Theme" theme option
|
||||
* in the Options panel.
|
||||
* Note that the new theme derives styles from built-in Light theme.
|
||||
*/
|
||||
const MyTheme = Theme({
|
||||
name: "mytheme",
|
||||
label: "My Light Theme",
|
||||
styles: [LightTheme, "./theme.css"],
|
||||
|
||||
onEnable: function(window, oldTheme) {
|
||||
console.log("myTheme.onEnable; method override " +
|
||||
window.location.href);
|
||||
},
|
||||
onDisable: function(window, newTheme) {
|
||||
console.log("myTheme.onDisable; method override " +
|
||||
window.location.href);
|
||||
},
|
||||
});
|
||||
|
||||
// Registration
|
||||
|
||||
const mytheme = new Tool({
|
||||
name: "My Tool",
|
||||
themes: { mytheme: MyTheme }
|
||||
});
|
||||
10
addon-sdk/source/examples/theme/package.json
Normal file
10
addon-sdk/source/examples/theme/package.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "theme",
|
||||
"title": "theme",
|
||||
"id": "theme@jetpack",
|
||||
"description": "How to create new theme for devtools",
|
||||
"author": "Jan Odvarko",
|
||||
"license": "MPL-2.0",
|
||||
"version": "0.1.0",
|
||||
"main": "lib/main"
|
||||
}
|
||||
10
addon-sdk/source/examples/theme/test/test-main.js
Normal file
10
addon-sdk/source/examples/theme/test/test-main.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
exports.testMain = function(assert) {
|
||||
assert.pass("TODO: Write some tests.");
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
BIN
addon-sdk/source/examples/toolbar-api/data/favicon.ico
Normal file
BIN
addon-sdk/source/examples/toolbar-api/data/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
21
addon-sdk/source/examples/toolbar-api/data/index.html
Normal file
21
addon-sdk/source/examples/toolbar-api/data/index.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<button id=post>post!</button>
|
||||
</body>
|
||||
<script>
|
||||
window.addEventListener("message", event => {
|
||||
console.log("Document message", event, event.data, event.source !== window && event.source === window.parent);
|
||||
});
|
||||
window.addEventListener("click", event => {
|
||||
if (event.target.id === "post") {
|
||||
console.log("click!")
|
||||
window.parent.postMessage("ping!", "*");
|
||||
}
|
||||
});
|
||||
console.log(window.parent === window)
|
||||
</script>
|
||||
</html>
|
||||
48
addon-sdk/source/examples/toolbar-api/lib/main.js
Normal file
48
addon-sdk/source/examples/toolbar-api/lib/main.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If 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 { Toolbar } = require("sdk/ui/toolbar");
|
||||
const { Frame } = require("sdk/ui/frame");
|
||||
const { ActionButton } = require("sdk/ui/button/action");
|
||||
|
||||
var button = new ActionButton({
|
||||
id: "button",
|
||||
label: "send!",
|
||||
icon: "./favicon.ico",
|
||||
onClick: () => {
|
||||
frame.postMessage({
|
||||
hello: "content"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var frame = new Frame({
|
||||
url: "./index.html",
|
||||
onAttach: () => {
|
||||
console.log("frame was attached");
|
||||
},
|
||||
onReady: () => {
|
||||
console.log("frame document was loaded");
|
||||
},
|
||||
onLoad: () => {
|
||||
console.log("frame load complete");
|
||||
},
|
||||
onMessage: (event) => {
|
||||
console.log("got message from frame content", event);
|
||||
if (event.data === "ping!")
|
||||
event.source.postMessage("pong!", event.source.origin);
|
||||
}
|
||||
});
|
||||
var toolbar = new Toolbar({
|
||||
items: [frame],
|
||||
title: "Addon Demo",
|
||||
hidden: false,
|
||||
onShow: () => {
|
||||
console.log("toolbar was shown");
|
||||
},
|
||||
onHide: () => {
|
||||
console.log("toolbar was hidden");
|
||||
}
|
||||
});
|
||||
12
addon-sdk/source/examples/toolbar-api/package.json
Normal file
12
addon-sdk/source/examples/toolbar-api/package.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "toolbar-api",
|
||||
"title": "Toolbar API",
|
||||
"main": "./lib/main.js",
|
||||
"description": "a toolbar api example",
|
||||
"author": "",
|
||||
"license": "MPL-2.0",
|
||||
"version": "0.1.1",
|
||||
"engines": {
|
||||
"firefox": ">=27.0 <=30.0"
|
||||
}
|
||||
}
|
||||
10
addon-sdk/source/examples/toolbar-api/test/test-main.js
Normal file
10
addon-sdk/source/examples/toolbar-api/test/test-main.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
exports.testMain = function(assert) {
|
||||
assert.pass("TODO: Write some tests.");
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
39
addon-sdk/source/examples/ui-button-apis/lib/main.js
Normal file
39
addon-sdk/source/examples/ui-button-apis/lib/main.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var data = require('sdk/self').data;
|
||||
var tabs = require('sdk/tabs');
|
||||
var { notify } = require('sdk/notifications');
|
||||
var { ActionButton, ToggleButton } = require('sdk/ui');
|
||||
|
||||
var icon = 'chrome://mozapps/skin/extensions/extensionGeneric.svg';
|
||||
exports.icon = icon;
|
||||
|
||||
// your basic action button
|
||||
var action = ActionButton({
|
||||
id: 'test-action-button',
|
||||
label: 'Action Button',
|
||||
icon: icon,
|
||||
onClick: function (state) {
|
||||
notify({
|
||||
title: "Action!",
|
||||
text: "This notification was triggered from an action button!",
|
||||
});
|
||||
}
|
||||
});
|
||||
exports.actionButton = action;
|
||||
|
||||
var toggle = ToggleButton({
|
||||
id: 'test-toggle-button',
|
||||
label: 'Toggle Button',
|
||||
icon: icon,
|
||||
onClick: function (state) {
|
||||
notify({
|
||||
title: "Toggled!",
|
||||
text: "The current state of the button is " + state.checked,
|
||||
});
|
||||
}
|
||||
});
|
||||
exports.toggleButton = toggle;
|
||||
10
addon-sdk/source/examples/ui-button-apis/package.json
Normal file
10
addon-sdk/source/examples/ui-button-apis/package.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "ui-button-apis",
|
||||
"title": "Australis Button API Examples",
|
||||
"id": "ui-button-apis@mozilla.org",
|
||||
"description": "A Button API example",
|
||||
"author": "jeff@canuckistani.ca (Jeff Griffiths | @canuckistani)",
|
||||
"license": "MPL-2.0",
|
||||
"version": "0.1.1",
|
||||
"main": "./lib/main.js"
|
||||
}
|
||||
29
addon-sdk/source/examples/ui-button-apis/tests/test-main.js
Normal file
29
addon-sdk/source/examples/ui-button-apis/tests/test-main.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
try {
|
||||
// CFX use case..
|
||||
var { actionButton, toggleButton, icon } = require("main");
|
||||
}
|
||||
catch (e) {
|
||||
// JPM use case..
|
||||
let mainURI = "../lib/main";
|
||||
var { actionButton, toggleButton, icon } = require(mainURI);
|
||||
}
|
||||
var self = require("sdk/self");
|
||||
|
||||
exports.testActionButton = function(assert) {
|
||||
assert.equal(actionButton.id, "test-action-button", "action button id is correct");
|
||||
assert.equal(actionButton.label, "Action Button", "action button label is correct");
|
||||
assert.equal(actionButton.icon, icon, "action button icon is correct");
|
||||
}
|
||||
|
||||
exports.testToggleButton = function(assert) {
|
||||
assert.equal(toggleButton.id, "test-toggle-button", "toggle button id is correct");
|
||||
assert.equal(toggleButton.label, "Toggle Button", "toggle button label is correct");
|
||||
assert.equal(toggleButton.icon, icon, "toggle button icon is correct");
|
||||
}
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
44
addon-sdk/source/gulpfile.js
Normal file
44
addon-sdk/source/gulpfile.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var gulp = require('gulp');
|
||||
var patch = require("./bin/node-scripts/apply-patch");
|
||||
var ini = require("./bin/node-scripts/update-ini");
|
||||
|
||||
gulp.task('test', function(done) {
|
||||
require("./bin/jpm-test").run().then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:addons', function(done) {
|
||||
require("./bin/jpm-test").run("addons").catch(console.error).then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:docs', function(done) {
|
||||
require("./bin/jpm-test").run("docs").catch(console.error).then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:examples', function(done) {
|
||||
require("./bin/jpm-test").run("examples").catch(console.error).then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:modules', function(done) {
|
||||
require("./bin/jpm-test").run("modules").catch(console.error).then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:ini', function(done) {
|
||||
require("./bin/jpm-test").run("ini").catch(console.error).then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:firefox-bin', function(done) {
|
||||
require("./bin/jpm-test").run("firefox-bin").catch(console.error).then(done);
|
||||
});
|
||||
|
||||
gulp.task('patch:clean', function(done) {
|
||||
patch.clean().catch(console.error).then(done);
|
||||
});
|
||||
|
||||
gulp.task('patch:apply', function(done) {
|
||||
patch.apply().catch(console.error).then(done);
|
||||
});
|
||||
95
addon-sdk/source/lib/dev/debuggee.js
Normal file
95
addon-sdk/source/lib/dev/debuggee.js
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { Cu } = require("chrome");
|
||||
const { Class } = require("../sdk/core/heritage");
|
||||
const { MessagePort, MessageChannel } = require("../sdk/messaging");
|
||||
const { require: devtoolsRequire } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { DebuggerServer } = devtoolsRequire("devtools/server/main");
|
||||
|
||||
const outputs = new WeakMap();
|
||||
const inputs = new WeakMap();
|
||||
const targets = new WeakMap();
|
||||
const transports = new WeakMap();
|
||||
|
||||
const inputFor = port => inputs.get(port);
|
||||
const outputFor = port => outputs.get(port);
|
||||
const transportFor = port => transports.get(port);
|
||||
|
||||
const fromTarget = target => {
|
||||
const debuggee = new Debuggee();
|
||||
const { port1, port2 } = new MessageChannel();
|
||||
inputs.set(debuggee, port1);
|
||||
outputs.set(debuggee, port2);
|
||||
targets.set(debuggee, target);
|
||||
|
||||
return debuggee;
|
||||
};
|
||||
exports.fromTarget = fromTarget;
|
||||
|
||||
const Debuggee = Class({
|
||||
extends: MessagePort.prototype,
|
||||
close: function() {
|
||||
const server = transportFor(this);
|
||||
if (server) {
|
||||
transports.delete(this);
|
||||
server.close();
|
||||
}
|
||||
outputFor(this).close();
|
||||
},
|
||||
start: function() {
|
||||
const target = targets.get(this);
|
||||
if (target.isLocalTab) {
|
||||
// Since a remote protocol connection will be made, let's start the
|
||||
// DebuggerServer here, once and for all tools.
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
transports.set(this, DebuggerServer.connectPipe());
|
||||
}
|
||||
// TODO: Implement support for remote connections (See Bug 980421)
|
||||
else {
|
||||
throw Error("Remote targets are not yet supported");
|
||||
}
|
||||
|
||||
// pipe messages send to the debuggee to an actual
|
||||
// server via remote debugging protocol transport.
|
||||
inputFor(this).addEventListener("message", ({data}) =>
|
||||
transportFor(this).send(data));
|
||||
|
||||
// pipe messages received from the remote debugging
|
||||
// server transport onto the this debuggee.
|
||||
transportFor(this).hooks = {
|
||||
onPacket: packet => inputFor(this).postMessage(packet),
|
||||
onClosed: () => inputFor(this).close()
|
||||
};
|
||||
|
||||
inputFor(this).start();
|
||||
outputFor(this).start();
|
||||
},
|
||||
postMessage: function(data) {
|
||||
return outputFor(this).postMessage(data);
|
||||
},
|
||||
get onmessage() {
|
||||
return outputFor(this).onmessage;
|
||||
},
|
||||
set onmessage(onmessage) {
|
||||
outputFor(this).onmessage = onmessage;
|
||||
},
|
||||
addEventListener: function(...args) {
|
||||
return outputFor(this).addEventListener(...args);
|
||||
},
|
||||
removeEventListener: function(...args) {
|
||||
return outputFor(this).removeEventListener(...args);
|
||||
}
|
||||
});
|
||||
exports.Debuggee = Debuggee;
|
||||
120
addon-sdk/source/lib/dev/frame-script.js
Normal file
120
addon-sdk/source/lib/dev/frame-script.js
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
(function({content, sendSyncMessage, addMessageListener, sendAsyncMessage}) {
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const observerService = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
|
||||
const channels = new Map();
|
||||
const handles = new WeakMap();
|
||||
|
||||
// Takes remote port handle and creates a local one.
|
||||
// also set's up a messaging channel between them.
|
||||
// This is temporary workaround until Bug 914974 is fixed
|
||||
// and port can be transfered through message manager.
|
||||
const demarshal = (handle) => {
|
||||
if (handle.type === "MessagePort") {
|
||||
if (!channels.has(handle.id)) {
|
||||
const channel = new content.MessageChannel();
|
||||
channels.set(handle.id, channel);
|
||||
handles.set(channel.port1, handle);
|
||||
channel.port1.onmessage = onOutPort;
|
||||
}
|
||||
return channels.get(handle.id).port2;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const onOutPort = event => {
|
||||
const handle = handles.get(event.target);
|
||||
sendAsyncMessage("sdk/port/message", {
|
||||
port: handle,
|
||||
message: event.data
|
||||
});
|
||||
};
|
||||
|
||||
const onInPort = ({data}) => {
|
||||
const channel = channels.get(data.port.id);
|
||||
if (channel)
|
||||
channel.port1.postMessage(data.message);
|
||||
};
|
||||
|
||||
const onOutEvent = event =>
|
||||
sendSyncMessage("sdk/event/" + event.type,
|
||||
{ type: event.type,
|
||||
data: event.data });
|
||||
|
||||
const onInMessage = (message) => {
|
||||
const {type, data, origin, bubbles, cancelable, ports} = message.data;
|
||||
|
||||
const event = new content.MessageEvent(type, {
|
||||
bubbles: bubbles,
|
||||
cancelable: cancelable,
|
||||
data: data,
|
||||
origin: origin,
|
||||
target: content,
|
||||
source: content,
|
||||
ports: ports.map(demarshal)
|
||||
});
|
||||
content.dispatchEvent(event);
|
||||
};
|
||||
|
||||
const onReady = event => {
|
||||
channels.clear();
|
||||
};
|
||||
|
||||
addMessageListener("sdk/event/message", onInMessage);
|
||||
addMessageListener("sdk/port/message", onInPort);
|
||||
|
||||
const observer = {
|
||||
handleEvent: ({target, type}) => {
|
||||
observer.observe(target, type);
|
||||
},
|
||||
observe: (document, topic, data) => {
|
||||
// When frame associated with message manager is removed from document `docShell`
|
||||
// is set to `null` but observer is still kept alive. At this point accesing
|
||||
// `content.document` throws "can't access dead object" exceptions. In order to
|
||||
// avoid leaking observer and logged errors observer is going to be removed when
|
||||
// `docShell` is set to `null`.
|
||||
if (!docShell) {
|
||||
observerService.removeObserver(observer, topic);
|
||||
}
|
||||
else if (document === content.document) {
|
||||
if (topic.endsWith("-document-interactive")) {
|
||||
sendAsyncMessage("sdk/event/ready", {
|
||||
type: "ready",
|
||||
readyState: document.readyState,
|
||||
uri: document.documentURI
|
||||
});
|
||||
}
|
||||
if (topic.endsWith("-document-loaded")) {
|
||||
sendAsyncMessage("sdk/event/load", {
|
||||
type: "load",
|
||||
readyState: document.readyState,
|
||||
uri: document.documentURI
|
||||
});
|
||||
}
|
||||
if (topic === "unload") {
|
||||
channels.clear();
|
||||
sendAsyncMessage("sdk/event/unload", {
|
||||
type: "unload",
|
||||
readyState: "uninitialized",
|
||||
uri: document.documentURI
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
observerService.addObserver(observer, "content-document-interactive", false);
|
||||
observerService.addObserver(observer, "content-document-loaded", false);
|
||||
observerService.addObserver(observer, "chrome-document-interactive", false);
|
||||
observerService.addObserver(observer, "chrome-document-loaded", false);
|
||||
addEventListener("unload", observer, false);
|
||||
|
||||
})(this);
|
||||
259
addon-sdk/source/lib/dev/panel.js
Normal file
259
addon-sdk/source/lib/dev/panel.js
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { Cu } = require("chrome");
|
||||
const { Class } = require("../sdk/core/heritage");
|
||||
const { curry } = require("../sdk/lang/functional");
|
||||
const { EventTarget } = require("../sdk/event/target");
|
||||
const { Disposable, setup, dispose } = require("../sdk/core/disposable");
|
||||
const { emit, off, setListeners } = require("../sdk/event/core");
|
||||
const { when } = require("../sdk/event/utils");
|
||||
const { getFrameElement } = require("../sdk/window/utils");
|
||||
const { contract, validate } = require("../sdk/util/contract");
|
||||
const { data: { url: resolve }} = require("../sdk/self");
|
||||
const { identify } = require("../sdk/ui/id");
|
||||
const { isLocalURL, URL } = require("../sdk/url");
|
||||
const { encode } = require("../sdk/base64");
|
||||
const { marshal, demarshal } = require("./ports");
|
||||
const { fromTarget } = require("./debuggee");
|
||||
const { removed } = require("../sdk/dom/events");
|
||||
const { id: addonID } = require("../sdk/self");
|
||||
const { viewFor } = require("../sdk/view/core");
|
||||
const { createView } = require("./panel/view");
|
||||
|
||||
const OUTER_FRAME_URI = module.uri.replace(/\.js$/, ".html");
|
||||
const FRAME_SCRIPT = module.uri.replace("/panel.js", "/frame-script.js");
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
const makeID = name =>
|
||||
("dev-panel-" + addonID + "-" + name).
|
||||
split("/").join("-").
|
||||
split(".").join("-").
|
||||
split(" ").join("-").
|
||||
replace(/[^A-Za-z0-9_\-]/g, "");
|
||||
|
||||
|
||||
// Weak mapping between `Panel` instances and their frame's
|
||||
// `nsIMessageManager`.
|
||||
const managers = new WeakMap();
|
||||
// Return `nsIMessageManager` for the given `Panel` instance.
|
||||
const managerFor = x => managers.get(x);
|
||||
|
||||
// Weak mappinging between iframe's and their owner
|
||||
// `Panel` instances.
|
||||
const panels = new WeakMap();
|
||||
const panelFor = frame => panels.get(frame);
|
||||
|
||||
// Weak mapping between panels and debugees they're targeting.
|
||||
const debuggees = new WeakMap();
|
||||
const debuggeeFor = panel => debuggees.get(panel);
|
||||
|
||||
const frames = new WeakMap();
|
||||
const frameFor = panel => frames.get(panel);
|
||||
|
||||
const setAttributes = (node, attributes) => {
|
||||
for (var key in attributes)
|
||||
node.setAttribute(key, attributes[key]);
|
||||
};
|
||||
|
||||
const onStateChange = ({target, data}) => {
|
||||
const panel = panelFor(target);
|
||||
panel.readyState = data.readyState;
|
||||
emit(panel, data.type, { target: panel, type: data.type });
|
||||
};
|
||||
|
||||
// port event listener on the message manager that demarshalls
|
||||
// and forwards to the actual receiver. This is a workaround
|
||||
// until Bug 914974 is fixed.
|
||||
const onPortMessage = ({data, target}) => {
|
||||
const port = demarshal(target, data.port);
|
||||
if (port)
|
||||
port.postMessage(data.message);
|
||||
};
|
||||
|
||||
// When frame is removed from the toolbox destroy panel
|
||||
// associated with it to release all the resources.
|
||||
const onFrameRemove = frame => {
|
||||
panelFor(frame).destroy();
|
||||
};
|
||||
|
||||
const onFrameInited = frame => {
|
||||
frame.style.visibility = "visible";
|
||||
}
|
||||
|
||||
const inited = frame => new Promise(resolve => {
|
||||
const { messageManager } = frame.frameLoader;
|
||||
const listener = message => {
|
||||
messageManager.removeMessageListener("sdk/event/ready", listener);
|
||||
resolve(frame);
|
||||
};
|
||||
messageManager.addMessageListener("sdk/event/ready", listener);
|
||||
});
|
||||
|
||||
const getTarget = ({target}) => target;
|
||||
|
||||
const Panel = Class({
|
||||
extends: Disposable,
|
||||
implements: [EventTarget],
|
||||
get id() {
|
||||
return makeID(this.name || this.label);
|
||||
},
|
||||
readyState: "uninitialized",
|
||||
ready: function() {
|
||||
const { readyState } = this;
|
||||
const isReady = readyState === "complete" ||
|
||||
readyState === "interactive";
|
||||
return isReady ? Promise.resolve(this) :
|
||||
when(this, "ready").then(getTarget);
|
||||
},
|
||||
loaded: function() {
|
||||
const { readyState } = this;
|
||||
const isLoaded = readyState === "complete";
|
||||
return isLoaded ? Promise.resolve(this) :
|
||||
when(this, "load").then(getTarget);
|
||||
},
|
||||
unloaded: function() {
|
||||
const { readyState } = this;
|
||||
const isUninitialized = readyState === "uninitialized";
|
||||
return isUninitialized ? Promise.resolve(this) :
|
||||
when(this, "unload").then(getTarget);
|
||||
},
|
||||
postMessage: function(data, ports=[]) {
|
||||
const manager = managerFor(this);
|
||||
manager.sendAsyncMessage("sdk/event/message", {
|
||||
type: "message",
|
||||
bubbles: false,
|
||||
cancelable: false,
|
||||
data: data,
|
||||
origin: this.url,
|
||||
ports: ports.map(marshal(manager))
|
||||
});
|
||||
}
|
||||
});
|
||||
exports.Panel = Panel;
|
||||
|
||||
validate.define(Panel, contract({
|
||||
label: {
|
||||
is: ["string"],
|
||||
msg: "The `option.label` must be a provided"
|
||||
},
|
||||
tooltip: {
|
||||
is: ["string", "undefined"],
|
||||
msg: "The `option.tooltip` must be a string"
|
||||
},
|
||||
icon: {
|
||||
is: ["string"],
|
||||
map: x => x && resolve(x),
|
||||
ok: x => isLocalURL(x),
|
||||
msg: "The `options.icon` must be a valid local URI."
|
||||
},
|
||||
url: {
|
||||
map: x => resolve(x.toString()),
|
||||
is: ["string"],
|
||||
ok: x => isLocalURL(x),
|
||||
msg: "The `options.url` must be a valid local URI."
|
||||
},
|
||||
invertIconForLightTheme: {
|
||||
is: ["boolean", "undefined"],
|
||||
msg: "The `options.invertIconForLightTheme` must be a boolean."
|
||||
},
|
||||
invertIconForDarkTheme: {
|
||||
is: ["boolean", "undefined"],
|
||||
msg: "The `options.invertIconForDarkTheme` must be a boolean."
|
||||
}
|
||||
}));
|
||||
|
||||
setup.define(Panel, (panel, {window, toolbox, url}) => {
|
||||
// Hack: Given that iframe created by devtools API is no good for us,
|
||||
// we obtain original iframe and replace it with the one that has
|
||||
// desired configuration.
|
||||
const original = getFrameElement(window);
|
||||
const container = original.parentNode;
|
||||
original.remove();
|
||||
const frame = createView(panel, container.ownerDocument);
|
||||
|
||||
// Following modifications are a temporary workaround until Bug 1049188
|
||||
// is fixed.
|
||||
// Enforce certain iframe customizations regardless of users request.
|
||||
setAttributes(frame, {
|
||||
"id": original.id,
|
||||
"src": url,
|
||||
"flex": 1,
|
||||
"forceOwnRefreshDriver": "",
|
||||
"tooltip": "aHTMLTooltip"
|
||||
});
|
||||
frame.style.visibility = "hidden";
|
||||
frame.classList.add("toolbox-panel-iframe");
|
||||
// Inject iframe into designated node until add-on author decides
|
||||
// to inject it elsewhere instead.
|
||||
if (!frame.parentNode)
|
||||
container.appendChild(frame);
|
||||
|
||||
// associate view with a panel
|
||||
frames.set(panel, frame);
|
||||
|
||||
// associate panel model with a frame view.
|
||||
panels.set(frame, panel);
|
||||
|
||||
const debuggee = fromTarget(toolbox.target);
|
||||
// associate debuggee with a panel.
|
||||
debuggees.set(panel, debuggee);
|
||||
|
||||
|
||||
// Setup listeners for the frame message manager.
|
||||
const { messageManager } = frame.frameLoader;
|
||||
messageManager.addMessageListener("sdk/event/ready", onStateChange);
|
||||
messageManager.addMessageListener("sdk/event/load", onStateChange);
|
||||
messageManager.addMessageListener("sdk/event/unload", onStateChange);
|
||||
messageManager.addMessageListener("sdk/port/message", onPortMessage);
|
||||
messageManager.loadFrameScript(FRAME_SCRIPT, false);
|
||||
|
||||
managers.set(panel, messageManager);
|
||||
|
||||
// destroy panel if frame is removed.
|
||||
removed(frame).then(onFrameRemove);
|
||||
// show frame when it is initialized.
|
||||
inited(frame).then(onFrameInited);
|
||||
|
||||
|
||||
// set listeners if there are ones defined on the prototype.
|
||||
setListeners(panel, Object.getPrototypeOf(panel));
|
||||
|
||||
|
||||
panel.setup({ debuggee: debuggee });
|
||||
});
|
||||
|
||||
createView.define(Panel, (panel, document) => {
|
||||
const frame = document.createElement("iframe");
|
||||
setAttributes(frame, {
|
||||
"sandbox": "allow-scripts",
|
||||
// We end up using chrome iframe with forced message manager
|
||||
// as fixing a swapFrameLoader seemed like a giant task (see
|
||||
// Bug 1075490).
|
||||
"type": "chrome",
|
||||
"forcemessagemanager": true,
|
||||
"transparent": true,
|
||||
"seamless": "seamless",
|
||||
});
|
||||
return frame;
|
||||
});
|
||||
|
||||
dispose.define(Panel, function(panel) {
|
||||
debuggeeFor(panel).close();
|
||||
|
||||
debuggees.delete(panel);
|
||||
managers.delete(panel);
|
||||
frames.delete(panel);
|
||||
panel.readyState = "destroyed";
|
||||
panel.dispose();
|
||||
});
|
||||
|
||||
viewFor.define(Panel, frameFor);
|
||||
14
addon-sdk/source/lib/dev/panel/view.js
Normal file
14
addon-sdk/source/lib/dev/panel/view.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { method } = require("method/core");
|
||||
|
||||
const createView = method("dev/panel/view#createView");
|
||||
exports.createView = createView;
|
||||
64
addon-sdk/source/lib/dev/ports.js
Normal file
64
addon-sdk/source/lib/dev/ports.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
// This module provides `marshal` and `demarshal` functions
|
||||
// that can be used to send MessagePort's over `nsIFrameMessageManager`
|
||||
// until Bug 914974 is fixed.
|
||||
|
||||
const { add, iterator } = require("../sdk/lang/weak-set");
|
||||
const { curry } = require("../sdk/lang/functional");
|
||||
|
||||
var id = 0;
|
||||
const ports = new WeakMap();
|
||||
|
||||
// Takes `nsIFrameMessageManager` and `MessagePort` instances
|
||||
// and returns a handle representing given `port`. Messages
|
||||
// received on given `port` will be forwarded to a message
|
||||
// manager under `sdk/port/message` and messages like:
|
||||
// { port: { type: "MessagePort", id: 2}, data: data }
|
||||
// Where id is an identifier associated with a given `port`
|
||||
// and `data` is an `event.data` received on port.
|
||||
const marshal = curry((manager, port) => {
|
||||
if (!ports.has(port)) {
|
||||
id = id + 1;
|
||||
const handle = {type: "MessagePort", id: id};
|
||||
// Bind id to the given port
|
||||
ports.set(port, handle);
|
||||
|
||||
// Obtain a weak reference to a port.
|
||||
add(exports, port);
|
||||
|
||||
port.onmessage = event => {
|
||||
manager.sendAsyncMessage("sdk/port/message", {
|
||||
port: handle,
|
||||
message: event.data
|
||||
});
|
||||
};
|
||||
|
||||
return handle;
|
||||
}
|
||||
return ports.get(port);
|
||||
});
|
||||
exports.marshal = marshal;
|
||||
|
||||
// Takes `nsIFrameMessageManager` instance and a handle returned
|
||||
// `marshal(manager, port)` returning a `port` that was passed
|
||||
// to it. Note that `port` may be GC-ed in which case returned
|
||||
// value will be `null`.
|
||||
const demarshal = curry((manager, {type, id}) => {
|
||||
if (type === "MessagePort") {
|
||||
for (let port of iterator(exports)) {
|
||||
if (id === ports.get(port).id)
|
||||
return port;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
exports.demarshal = demarshal;
|
||||
135
addon-sdk/source/lib/dev/theme.js
Normal file
135
addon-sdk/source/lib/dev/theme.js
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { Class } = require("../sdk/core/heritage");
|
||||
const { EventTarget } = require("../sdk/event/target");
|
||||
const { Disposable, setup, dispose } = require("../sdk/core/disposable");
|
||||
const { contract, validate } = require("../sdk/util/contract");
|
||||
const { id: addonID } = require("../sdk/self");
|
||||
const { onEnable, onDisable } = require("dev/theme/hooks");
|
||||
const { isString, instanceOf, isFunction } = require("sdk/lang/type");
|
||||
const { add } = require("sdk/util/array");
|
||||
const { data } = require("../sdk/self");
|
||||
const { isLocalURL } = require("../sdk/url");
|
||||
|
||||
const makeID = name =>
|
||||
("dev-theme-" + addonID + (name ? "-" + name : "")).
|
||||
split(/[ . /]/).join("-").
|
||||
replace(/[^A-Za-z0-9_\-]/g, "");
|
||||
|
||||
const Theme = Class({
|
||||
extends: Disposable,
|
||||
implements: [EventTarget],
|
||||
|
||||
initialize: function(options) {
|
||||
this.name = options.name;
|
||||
this.label = options.label;
|
||||
this.styles = options.styles;
|
||||
|
||||
// Event handlers
|
||||
this.onEnable = options.onEnable;
|
||||
this.onDisable = options.onDisable;
|
||||
},
|
||||
get id() {
|
||||
return makeID(this.name || this.label);
|
||||
},
|
||||
setup: function() {
|
||||
// Any initialization steps done at the registration time.
|
||||
},
|
||||
getStyles: function() {
|
||||
if (!this.styles) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (isString(this.styles)) {
|
||||
if (isLocalURL(this.styles)) {
|
||||
return [data.url(this.styles)];
|
||||
}
|
||||
}
|
||||
|
||||
let result = [];
|
||||
for (let style of this.styles) {
|
||||
if (isString(style)) {
|
||||
if (isLocalURL(style)) {
|
||||
style = data.url(style);
|
||||
}
|
||||
add(result, style);
|
||||
} else if (instanceOf(style, Theme)) {
|
||||
result = result.concat(style.getStyles());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getClassList: function() {
|
||||
let result = [];
|
||||
for (let style of this.styles) {
|
||||
if (instanceOf(style, Theme)) {
|
||||
result = result.concat(style.getClassList());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.name) {
|
||||
add(result, this.name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
exports.Theme = Theme;
|
||||
|
||||
// Initialization & dispose
|
||||
|
||||
setup.define(Theme, (theme) => {
|
||||
theme.classList = [];
|
||||
theme.setup();
|
||||
});
|
||||
|
||||
dispose.define(Theme, function(theme) {
|
||||
theme.dispose();
|
||||
});
|
||||
|
||||
// Validation
|
||||
|
||||
validate.define(Theme, contract({
|
||||
label: {
|
||||
is: ["string"],
|
||||
msg: "The `option.label` must be a provided"
|
||||
},
|
||||
}));
|
||||
|
||||
// Support theme events: apply and unapply the theme.
|
||||
|
||||
onEnable.define(Theme, (theme, {window, oldTheme}) => {
|
||||
if (isFunction(theme.onEnable)) {
|
||||
theme.onEnable(window, oldTheme);
|
||||
}
|
||||
});
|
||||
|
||||
onDisable.define(Theme, (theme, {window, newTheme}) => {
|
||||
if (isFunction(theme.onDisable)) {
|
||||
theme.onDisable(window, newTheme);
|
||||
}
|
||||
});
|
||||
|
||||
// Support for built-in themes
|
||||
|
||||
const LightTheme = Theme({
|
||||
name: "theme-light",
|
||||
styles: "chrome://devtools/skin/light-theme.css",
|
||||
});
|
||||
|
||||
const DarkTheme = Theme({
|
||||
name: "theme-dark",
|
||||
styles: "chrome://devtools/skin/dark-theme.css",
|
||||
});
|
||||
|
||||
exports.LightTheme = LightTheme;
|
||||
exports.DarkTheme = DarkTheme;
|
||||
17
addon-sdk/source/lib/dev/theme/hooks.js
Normal file
17
addon-sdk/source/lib/dev/theme/hooks.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { method } = require("method/core");
|
||||
|
||||
const onEnable = method("dev/theme/hooks#onEnable");
|
||||
const onDisable = method("dev/theme/hooks#onDisable");
|
||||
|
||||
exports.onEnable = onEnable;
|
||||
exports.onDisable = onDisable;
|
||||
107
addon-sdk/source/lib/dev/toolbox.js
Normal file
107
addon-sdk/source/lib/dev/toolbox.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { Cu, Cc, Ci } = require("chrome");
|
||||
const { Class } = require("../sdk/core/heritage");
|
||||
const { Disposable, setup } = require("../sdk/core/disposable");
|
||||
const { contract, validate } = require("../sdk/util/contract");
|
||||
const { each, pairs, values } = require("../sdk/util/sequence");
|
||||
const { onEnable, onDisable } = require("../dev/theme/hooks");
|
||||
|
||||
const { gDevTools } = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
|
||||
|
||||
// This is temporary workaround to allow loading of the developer tools client - volcan
|
||||
// into a toolbox panel, this hack won't be necessary as soon as devtools patch will be
|
||||
// shipped in nightly, after which it can be removed. Bug 1038517
|
||||
const registerSDKURI = () => {
|
||||
const ioService = Cc['@mozilla.org/network/io-service;1']
|
||||
.getService(Ci.nsIIOService);
|
||||
const resourceHandler = ioService.getProtocolHandler("resource")
|
||||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
|
||||
const uri = module.uri.replace("dev/toolbox.js", "");
|
||||
resourceHandler.setSubstitution("sdk", ioService.newURI(uri, null, null));
|
||||
};
|
||||
|
||||
registerSDKURI();
|
||||
|
||||
const Tool = Class({
|
||||
extends: Disposable,
|
||||
setup: function(params={}) {
|
||||
const { panels } = validate(this, params);
|
||||
const { themes } = validate(this, params);
|
||||
|
||||
this.panels = panels;
|
||||
this.themes = themes;
|
||||
|
||||
each(([key, Panel]) => {
|
||||
const { url, label, tooltip, icon, invertIconForLightTheme,
|
||||
invertIconForDarkTheme } = validate(Panel.prototype);
|
||||
const { id } = Panel.prototype;
|
||||
|
||||
gDevTools.registerTool({
|
||||
id: id,
|
||||
url: "about:blank",
|
||||
label: label,
|
||||
tooltip: tooltip,
|
||||
icon: icon,
|
||||
invertIconForLightTheme: invertIconForLightTheme,
|
||||
invertIconForDarkTheme: invertIconForDarkTheme,
|
||||
isTargetSupported: target => target.isLocalTab,
|
||||
build: (window, toolbox) => {
|
||||
const panel = new Panel();
|
||||
setup(panel, { window: window,
|
||||
toolbox: toolbox,
|
||||
url: url });
|
||||
|
||||
return panel.ready();
|
||||
}
|
||||
});
|
||||
}, pairs(panels));
|
||||
|
||||
each(([key, theme]) => {
|
||||
validate(theme);
|
||||
setup(theme);
|
||||
|
||||
gDevTools.registerTheme({
|
||||
id: theme.id,
|
||||
label: theme.label,
|
||||
stylesheets: theme.getStyles(),
|
||||
classList: theme.getClassList(),
|
||||
onApply: (window, oldTheme) => {
|
||||
onEnable(theme, { window: window,
|
||||
oldTheme: oldTheme });
|
||||
},
|
||||
onUnapply: (window, newTheme) => {
|
||||
onDisable(theme, { window: window,
|
||||
newTheme: newTheme });
|
||||
}
|
||||
});
|
||||
}, pairs(themes));
|
||||
},
|
||||
dispose: function() {
|
||||
each(Panel => gDevTools.unregisterTool(Panel.prototype.id),
|
||||
values(this.panels));
|
||||
|
||||
each(Theme => gDevTools.unregisterTheme(Theme.prototype.id),
|
||||
values(this.themes));
|
||||
}
|
||||
});
|
||||
|
||||
validate.define(Tool, contract({
|
||||
panels: {
|
||||
is: ["object", "undefined"]
|
||||
},
|
||||
themes: {
|
||||
is: ["object", "undefined"]
|
||||
}
|
||||
}));
|
||||
|
||||
exports.Tool = Tool;
|
||||
40
addon-sdk/source/lib/dev/utils.js
Normal file
40
addon-sdk/source/lib/dev/utils.js
Normal file
|
|
@ -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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Cu } = require("chrome");
|
||||
const { gDevTools } = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
|
||||
const { devtools } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
|
||||
const { getActiveTab } = require("../sdk/tabs/utils");
|
||||
const { getMostRecentBrowserWindow } = require("../sdk/window/utils");
|
||||
|
||||
const targetFor = target => {
|
||||
target = target || getActiveTab(getMostRecentBrowserWindow());
|
||||
return devtools.TargetFactory.forTab(target);
|
||||
};
|
||||
|
||||
const getId = id => ((id.prototype && id.prototype.id) || id.id || id);
|
||||
|
||||
const getCurrentPanel = toolbox => toolbox.getCurrentPanel();
|
||||
exports.getCurrentPanel = getCurrentPanel;
|
||||
|
||||
const openToolbox = (id, tab) => {
|
||||
id = getId(id);
|
||||
return gDevTools.showToolbox(targetFor(tab), id);
|
||||
};
|
||||
exports.openToolbox = openToolbox;
|
||||
|
||||
const closeToolbox = tab => gDevTools.closeToolbox(targetFor(tab));
|
||||
exports.closeToolbox = closeToolbox;
|
||||
|
||||
const getToolbox = tab => gDevTools.getToolbox(targetFor(tab));
|
||||
exports.getToolbox = getToolbox;
|
||||
|
||||
const openToolboxPanel = (id, tab) => {
|
||||
id = getId(id);
|
||||
return gDevTools.showToolbox(targetFor(tab), id).then(getCurrentPanel);
|
||||
};
|
||||
exports.openToolboxPanel = openToolboxPanel;
|
||||
3848
addon-sdk/source/lib/dev/volcan.js
Normal file
3848
addon-sdk/source/lib/dev/volcan.js
Normal file
File diff suppressed because one or more lines are too long
5
addon-sdk/source/lib/diffpatcher/.travis.yml
Normal file
5
addon-sdk/source/lib/diffpatcher/.travis.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.4
|
||||
- 0.5
|
||||
- 0.6
|
||||
14
addon-sdk/source/lib/diffpatcher/History.md
Normal file
14
addon-sdk/source/lib/diffpatcher/History.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Changes
|
||||
|
||||
## 1.0.1 / 2013-05-01
|
||||
|
||||
- Update method library version.
|
||||
|
||||
## 1.0.0 / 2012-11-09
|
||||
|
||||
- Test integration for browsers.
|
||||
- New method library.
|
||||
|
||||
## 0.0.1 / 2012-10-22
|
||||
|
||||
- Initial release
|
||||
18
addon-sdk/source/lib/diffpatcher/License.md
Normal file
18
addon-sdk/source/lib/diffpatcher/License.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
Copyright 2012 Irakli Gozalishvili. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
70
addon-sdk/source/lib/diffpatcher/Readme.md
Normal file
70
addon-sdk/source/lib/diffpatcher/Readme.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# diffpatcher
|
||||
|
||||
[](http://travis-ci.org/Gozala/diffpatcher)
|
||||
|
||||
[](http://ci.testling.com/Gozala/diffpatcher)
|
||||
|
||||
Diffpatcher is a small library that lets you treat hashes as if they were
|
||||
git repositories.
|
||||
|
||||
## diff
|
||||
|
||||
Diff function that takes two hashes and returns delta hash.
|
||||
|
||||
```js
|
||||
var diff = require("diffpatcher/diff")
|
||||
|
||||
diff({ a: { b: 1 }, c: { d: 2 } }, // hash#1
|
||||
{ a: { e: 3 }, c: { d: 4 } }) // hash#2
|
||||
|
||||
// => { // delta
|
||||
// a: {
|
||||
// b: null, // -
|
||||
// e: 3 // +
|
||||
// },
|
||||
// c: {
|
||||
// d: 4 // ±
|
||||
// }
|
||||
// }
|
||||
```
|
||||
|
||||
As you can see from the example above `delta` makes no real distinction between
|
||||
proprety upadate and property addition. Try to think of additions as an update
|
||||
from `undefined` to whatever it's being updated to.
|
||||
|
||||
## patch
|
||||
|
||||
Patch fuction takes a `hash` and a `delta` and returns a new `hash` which is
|
||||
just like orginial but with delta applied to it. Let's apply delta from the
|
||||
previous example to the first hash from the same example
|
||||
|
||||
|
||||
```js
|
||||
var patch = require("diffpatcher/patch")
|
||||
|
||||
patch({ a: { b: 1 }, c: { d: 2 } }, // hash#1
|
||||
{ // delta
|
||||
a: {
|
||||
b: null, // -
|
||||
e: 3 // +
|
||||
},
|
||||
c: {
|
||||
d: 4 // ±
|
||||
}
|
||||
})
|
||||
|
||||
// => { a: { e: 3 }, c: { d: 4 } } // hash#2
|
||||
```
|
||||
|
||||
That's about it really, just diffing hashes and applying thes diffs on them.
|
||||
|
||||
|
||||
### rebase
|
||||
|
||||
And as Linus mentioned everything in git can be expressed with `rebase`, that
|
||||
also pretty much the case for `diffpatcher`. `rebase` takes `target` hash,
|
||||
and rebases `parent` onto it with `diff` applied.
|
||||
|
||||
## Install
|
||||
|
||||
npm install diffpatcher
|
||||
45
addon-sdk/source/lib/diffpatcher/diff.js
Normal file
45
addon-sdk/source/lib/diffpatcher/diff.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
"use strict";
|
||||
|
||||
var method = require("../method/core")
|
||||
|
||||
// Method is designed to work with data structures representing application
|
||||
// state. Calling it with a state should return object representing `delta`
|
||||
// that has being applied to a previous state to get to a current state.
|
||||
//
|
||||
// Example
|
||||
//
|
||||
// diff(state) // => { "item-id-1": { title: "some title" } "item-id-2": null }
|
||||
var diff = method("diff@diffpatcher")
|
||||
|
||||
// diff between `null` / `undefined` to any hash is a hash itself.
|
||||
diff.define(null, function(from, to) { return to })
|
||||
diff.define(undefined, function(from, to) { return to })
|
||||
diff.define(Object, function(from, to) {
|
||||
return calculate(from, to || {}) || {}
|
||||
})
|
||||
|
||||
function calculate(from, to) {
|
||||
var diff = {}
|
||||
var changes = 0
|
||||
Object.keys(from).forEach(function(key) {
|
||||
changes = changes + 1
|
||||
if (!(key in to) && from[key] != null) diff[key] = null
|
||||
else changes = changes - 1
|
||||
})
|
||||
Object.keys(to).forEach(function(key) {
|
||||
changes = changes + 1
|
||||
var previous = from[key]
|
||||
var current = to[key]
|
||||
if (previous === current) return (changes = changes - 1)
|
||||
if (typeof(current) !== "object") return diff[key] = current
|
||||
if (typeof(previous) !== "object") return diff[key] = current
|
||||
var delta = calculate(previous, current)
|
||||
if (delta) diff[key] = delta
|
||||
else changes = changes - 1
|
||||
})
|
||||
return changes ? diff : null
|
||||
}
|
||||
|
||||
diff.calculate = calculate
|
||||
|
||||
module.exports = diff
|
||||
5
addon-sdk/source/lib/diffpatcher/index.js
Normal file
5
addon-sdk/source/lib/diffpatcher/index.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
exports.diff = require("./diff")
|
||||
exports.patch = require("./patch")
|
||||
exports.rebase = require("./rebase")
|
||||
54
addon-sdk/source/lib/diffpatcher/package.json
Normal file
54
addon-sdk/source/lib/diffpatcher/package.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"name": "diffpatcher",
|
||||
"id": "diffpatcher",
|
||||
"version": "1.2.0",
|
||||
"description": "Utilities for diff-ing & patch-ing hashes",
|
||||
"keywords": [
|
||||
"diff", "patch", "rebase", "hash", "changes", "versions"
|
||||
],
|
||||
"author": "Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)",
|
||||
"homepage": "https://github.com/Gozala/diffpatcher",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Gozala/diffpatcher.git",
|
||||
"web": "https://github.com/Gozala/diffpatcher"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://github.com/Gozala/diffpatcher/issues/"
|
||||
},
|
||||
"dependencies": {
|
||||
"method": "~2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"test": "~0.x.0",
|
||||
"phantomify": "~0.x.0",
|
||||
"retape": "~0.x.0",
|
||||
"tape": "~0.1.5"
|
||||
},
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"test": "npm run test-node && npm run test-browser",
|
||||
"test-browser": "node ./node_modules/phantomify/bin/cmd.js ./test/common.js",
|
||||
"test-node": "node ./test/common.js",
|
||||
"test-tap": "node ./test/tap.js"
|
||||
},
|
||||
"testling": {
|
||||
"files": "test/tap.js",
|
||||
"browsers": [
|
||||
"ie/9..latest",
|
||||
"chrome/25..latest",
|
||||
"firefox/20..latest",
|
||||
"safari/6..latest",
|
||||
"opera/11.0..latest",
|
||||
"iphone/6..latest",
|
||||
"ipad/6..latest",
|
||||
"android-browser/4.2..latest"
|
||||
]
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/Gozala/diffpatcher/License.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
21
addon-sdk/source/lib/diffpatcher/patch.js
Normal file
21
addon-sdk/source/lib/diffpatcher/patch.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
"use strict";
|
||||
|
||||
var method = require("../method/core")
|
||||
var rebase = require("./rebase")
|
||||
|
||||
// Method is designed to work with data structures representing application
|
||||
// state. Calling it with a state and delta should return object representing
|
||||
// new state, with changes in `delta` being applied to previous.
|
||||
//
|
||||
// ## Example
|
||||
//
|
||||
// patch(state, {
|
||||
// "item-id-1": { completed: false }, // update
|
||||
// "item-id-2": null // delete
|
||||
// })
|
||||
var patch = method("patch@diffpatcher")
|
||||
patch.define(Object, function patch(hash, delta) {
|
||||
return rebase({}, hash, delta)
|
||||
})
|
||||
|
||||
module.exports = patch
|
||||
36
addon-sdk/source/lib/diffpatcher/rebase.js
Normal file
36
addon-sdk/source/lib/diffpatcher/rebase.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"use strict";
|
||||
|
||||
var nil = {}
|
||||
var owns = ({}).hasOwnProperty
|
||||
|
||||
function rebase(result, parent, delta) {
|
||||
var key, current, previous, update
|
||||
for (key in parent) {
|
||||
if (owns.call(parent, key)) {
|
||||
previous = parent[key]
|
||||
update = owns.call(delta, key) ? delta[key] : nil
|
||||
if (previous === null) continue
|
||||
else if (previous === void(0)) continue
|
||||
else if (update === null) continue
|
||||
else if (update === void(0)) continue
|
||||
else result[key] = previous
|
||||
}
|
||||
}
|
||||
for (key in delta) {
|
||||
if (owns.call(delta, key)) {
|
||||
update = delta[key]
|
||||
current = owns.call(result, key) ? result[key] : nil
|
||||
if (current === update) continue
|
||||
else if (update === null) continue
|
||||
else if (update === void(0)) continue
|
||||
else if (current === nil) result[key] = update
|
||||
else if (typeof(update) !== "object") result[key] = update
|
||||
else if (typeof(current) !== "object") result[key] = update
|
||||
else result[key]= rebase({}, current, update)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = rebase
|
||||
3
addon-sdk/source/lib/diffpatcher/test/common.js
Normal file
3
addon-sdk/source/lib/diffpatcher/test/common.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
require("test").run(require("./index"))
|
||||
59
addon-sdk/source/lib/diffpatcher/test/diff.js
Normal file
59
addon-sdk/source/lib/diffpatcher/test/diff.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
"use strict";
|
||||
|
||||
var diff = require("../diff")
|
||||
|
||||
exports["test diff from null"] = function(assert) {
|
||||
var to = { a: 1, b: 2 }
|
||||
assert.equal(diff(null, to), to, "diff null to x returns x")
|
||||
assert.equal(diff(void(0), to), to, "diff undefined to x returns x")
|
||||
|
||||
}
|
||||
|
||||
exports["test diff to null"] = function(assert) {
|
||||
var from = { a: 1, b: 2 }
|
||||
assert.deepEqual(diff({ a: 1, b: 2 }, null),
|
||||
{ a: null, b: null },
|
||||
"diff x null returns x with all properties nullified")
|
||||
}
|
||||
|
||||
exports["test diff identical"] = function(assert) {
|
||||
assert.deepEqual(diff({}, {}), {}, "diff on empty objects is {}")
|
||||
|
||||
assert.deepEqual(diff({ a: 1, b: 2 }, { a: 1, b: 2 }), {},
|
||||
"if properties match diff is {}")
|
||||
|
||||
assert.deepEqual(diff({ a: 1, b: { c: { d: 3, e: 4 } } },
|
||||
{ a: 1, b: { c: { d: 3, e: 4 } } }), {},
|
||||
"diff between identical nested hashes is {}")
|
||||
|
||||
}
|
||||
|
||||
exports["test diff delete"] = function(assert) {
|
||||
assert.deepEqual(diff({ a: 1, b: 2 }, { b: 2 }), { a: null },
|
||||
"missing property is deleted")
|
||||
assert.deepEqual(diff({ a: 1, b: 2 }, { a: 2 }), { a: 2, b: null },
|
||||
"missing property is deleted another updated")
|
||||
assert.deepEqual(diff({ a: 1, b: 2 }, {}), { a: null, b: null },
|
||||
"missing propertes are deleted")
|
||||
assert.deepEqual(diff({ a: 1, b: { c: { d: 2 } } }, {}),
|
||||
{ a: null, b: null },
|
||||
"missing deep propertes are deleted")
|
||||
assert.deepEqual(diff({ a: 1, b: { c: { d: 2 } } }, { b: { c: {} } }),
|
||||
{ a: null, b: { c: { d: null } } },
|
||||
"missing nested propertes are deleted")
|
||||
}
|
||||
|
||||
exports["test add update"] = function(assert) {
|
||||
assert.deepEqual(diff({ a: 1, b: 2 }, { b: 2, c: 3 }), { a: null, c: 3 },
|
||||
"delete and add")
|
||||
assert.deepEqual(diff({ a: 1, b: 2 }, { a: 2, c: 3 }), { a: 2, b: null, c: 3 },
|
||||
"delete and adds")
|
||||
assert.deepEqual(diff({}, { a: 1, b: 2 }), { a: 1, b: 2 },
|
||||
"diff on empty objcet returns equivalen of to")
|
||||
assert.deepEqual(diff({ a: 1, b: { c: { d: 2 } } }, { d: 3 }),
|
||||
{ a: null, b: null, d: 3 },
|
||||
"missing deep propertes are deleted")
|
||||
assert.deepEqual(diff({ b: { c: {} }, d: null }, { a: 1, b: { c: { d: 2 } } }),
|
||||
{ a: 1, b: { c: { d: 2 } } },
|
||||
"missing nested propertes are deleted")
|
||||
}
|
||||
14
addon-sdk/source/lib/diffpatcher/test/index.js
Normal file
14
addon-sdk/source/lib/diffpatcher/test/index.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
"use strict";
|
||||
|
||||
var diff = require("../diff")
|
||||
var patch = require("../patch")
|
||||
|
||||
exports["test diff"] = require("./diff")
|
||||
exports["test patch"] = require("./patch")
|
||||
|
||||
exports["test patch(a, diff(a, b)) => b"] = function(assert) {
|
||||
var a = { a: { b: 1 }, c: { d: 2 } }
|
||||
var b = { a: { e: 3 }, c: { d: 4 } }
|
||||
|
||||
assert.deepEqual(patch(a, diff(a, b)), b, "patch(a, diff(a, b)) => b")
|
||||
}
|
||||
83
addon-sdk/source/lib/diffpatcher/test/patch.js
Normal file
83
addon-sdk/source/lib/diffpatcher/test/patch.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
"use strict";
|
||||
|
||||
var patch = require("../patch")
|
||||
|
||||
exports["test patch delete"] = function(assert) {
|
||||
var hash = { a: 1, b: 2 }
|
||||
|
||||
assert.deepEqual(patch(hash, { a: null }), { b: 2 }, "null removes property")
|
||||
}
|
||||
|
||||
exports["test patch delete with void"] = function(assert) {
|
||||
var hash = { a: 1, b: 2 }
|
||||
|
||||
assert.deepEqual(patch(hash, { a: void(0) }), { b: 2 },
|
||||
"void(0) removes property")
|
||||
}
|
||||
|
||||
exports["test patch delete missing"] = function(assert) {
|
||||
assert.deepEqual(patch({ a: 1, b: 2 }, { c: null }),
|
||||
{ a: 1, b: 2 },
|
||||
"null removes property if exists");
|
||||
|
||||
assert.deepEqual(patch({ a: 1, b: 2 }, { c: void(0) }),
|
||||
{ a: 1, b: 2 },
|
||||
"void removes property if exists");
|
||||
}
|
||||
|
||||
exports["test delete deleted"] = function(assert) {
|
||||
assert.deepEqual(patch({ a: null, b: 2, c: 3, d: void(0)},
|
||||
{ a: void(0), b: null, d: null }),
|
||||
{c: 3},
|
||||
"removed all existing and non existing");
|
||||
}
|
||||
|
||||
exports["test update deleted"] = function(assert) {
|
||||
assert.deepEqual(patch({ a: null, b: void(0), c: 3},
|
||||
{ a: { b: 2 } }),
|
||||
{ a: { b: 2 }, c: 3 },
|
||||
"replace deleted");
|
||||
}
|
||||
|
||||
exports["test patch delete with void"] = function(assert) {
|
||||
var hash = { a: 1, b: 2 }
|
||||
|
||||
assert.deepEqual(patch(hash, { a: void(0) }), { b: 2 },
|
||||
"void(0) removes property")
|
||||
}
|
||||
|
||||
|
||||
exports["test patch addition"] = function(assert) {
|
||||
var hash = { a: 1, b: 2 }
|
||||
|
||||
assert.deepEqual(patch(hash, { c: 3 }), { a: 1, b: 2, c: 3 },
|
||||
"new properties are added")
|
||||
}
|
||||
|
||||
exports["test patch addition"] = function(assert) {
|
||||
var hash = { a: 1, b: 2 }
|
||||
|
||||
assert.deepEqual(patch(hash, { c: 3 }), { a: 1, b: 2, c: 3 },
|
||||
"new properties are added")
|
||||
}
|
||||
|
||||
exports["test hash on itself"] = function(assert) {
|
||||
var hash = { a: 1, b: 2 }
|
||||
|
||||
assert.deepEqual(patch(hash, hash), hash,
|
||||
"applying hash to itself returns hash itself")
|
||||
}
|
||||
|
||||
exports["test patch with empty delta"] = function(assert) {
|
||||
var hash = { a: 1, b: 2 }
|
||||
|
||||
assert.deepEqual(patch(hash, {}), hash,
|
||||
"applying empty delta results in no changes")
|
||||
}
|
||||
|
||||
exports["test patch nested data"] = function(assert) {
|
||||
assert.deepEqual(patch({ a: { b: 1 }, c: { d: 2 } },
|
||||
{ a: { b: null, e: 3 }, c: { d: 4 } }),
|
||||
{ a: { e: 3 }, c: { d: 4 } },
|
||||
"nested structures can also be patched")
|
||||
}
|
||||
3
addon-sdk/source/lib/diffpatcher/test/tap.js
Normal file
3
addon-sdk/source/lib/diffpatcher/test/tap.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
require("retape")(require("./index"))
|
||||
27
addon-sdk/source/lib/framescript/FrameScriptManager.jsm
Normal file
27
addon-sdk/source/lib/framescript/FrameScriptManager.jsm
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const globalMM = Components.classes["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Components.interfaces.nsIMessageListenerManager);
|
||||
|
||||
// Load frame scripts from the same dir as this module.
|
||||
// Since this JSM will be loaded using require(), PATH will be
|
||||
// overridden while running tests, just like any other module.
|
||||
const PATH = __URI__.replace('framescript/FrameScriptManager.jsm', '');
|
||||
|
||||
// Builds a unique loader ID for this runtime. We prefix with the SDK path so
|
||||
// overriden versions of the SDK don't conflict
|
||||
var LOADER_ID = 0;
|
||||
this.getNewLoaderID = () => {
|
||||
return PATH + ":" + LOADER_ID++;
|
||||
}
|
||||
|
||||
const frame_script = function(contentFrame, PATH) {
|
||||
let { registerContentFrame } = Components.utils.import(PATH + 'framescript/content.jsm', {});
|
||||
registerContentFrame(contentFrame);
|
||||
}
|
||||
globalMM.loadFrameScript("data:,(" + frame_script.toString() + ")(this, " + JSON.stringify(PATH) + ");", true);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['getNewLoaderID'];
|
||||
94
addon-sdk/source/lib/framescript/content.jsm
Normal file
94
addon-sdk/source/lib/framescript/content.jsm
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
||||
const { Services } = Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
const cpmm = Cc['@mozilla.org/childprocessmessagemanager;1'].
|
||||
getService(Ci.nsISyncMessageSender);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["registerContentFrame"];
|
||||
|
||||
// This may be an overriden version of the SDK so use the PATH as a key for the
|
||||
// initial messages before we have a loaderID.
|
||||
const PATH = __URI__.replace('framescript/content.jsm', '');
|
||||
|
||||
const { Loader } = Cu.import(PATH + 'toolkit/loader.js', {});
|
||||
|
||||
// one Loader instance per addon (per @loader/options to be precise)
|
||||
var addons = new Map();
|
||||
|
||||
// Tell the parent that a new process is ready
|
||||
cpmm.sendAsyncMessage('sdk/remote/process/start', {
|
||||
modulePath: PATH
|
||||
});
|
||||
|
||||
// Load a child process module loader with the given loader options
|
||||
cpmm.addMessageListener('sdk/remote/process/load', ({ data: { modulePath, loaderID, options, reason } }) => {
|
||||
if (modulePath != PATH)
|
||||
return;
|
||||
|
||||
// During startup races can mean we get a second load message
|
||||
if (addons.has(loaderID))
|
||||
return;
|
||||
|
||||
options.waiveInterposition = true;
|
||||
|
||||
let loader = Loader.Loader(options);
|
||||
let addon = {
|
||||
loader,
|
||||
require: Loader.Require(loader, { id: 'LoaderHelper' }),
|
||||
}
|
||||
addons.set(loaderID, addon);
|
||||
|
||||
cpmm.sendAsyncMessage('sdk/remote/process/attach', {
|
||||
loaderID,
|
||||
processID: Services.appinfo.processID,
|
||||
isRemote: Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT
|
||||
});
|
||||
|
||||
addon.child = addon.require('sdk/remote/child');
|
||||
|
||||
for (let contentFrame of frames.values())
|
||||
addon.child.registerContentFrame(contentFrame);
|
||||
});
|
||||
|
||||
// Unload a child process loader
|
||||
cpmm.addMessageListener('sdk/remote/process/unload', ({ data: { loaderID, reason } }) => {
|
||||
if (!addons.has(loaderID))
|
||||
return;
|
||||
|
||||
let addon = addons.get(loaderID);
|
||||
Loader.unload(addon.loader, reason);
|
||||
|
||||
// We want to drop the reference to the loader but never allow creating a new
|
||||
// loader with the same ID
|
||||
addons.set(loaderID, {});
|
||||
})
|
||||
|
||||
|
||||
var frames = new Set();
|
||||
|
||||
this.registerContentFrame = contentFrame => {
|
||||
contentFrame.addEventListener("unload", () => {
|
||||
unregisterContentFrame(contentFrame);
|
||||
}, false);
|
||||
|
||||
frames.add(contentFrame);
|
||||
|
||||
for (let addon of addons.values()) {
|
||||
if ("child" in addon)
|
||||
addon.child.registerContentFrame(contentFrame);
|
||||
}
|
||||
};
|
||||
|
||||
function unregisterContentFrame(contentFrame) {
|
||||
frames.delete(contentFrame);
|
||||
|
||||
for (let addon of addons.values()) {
|
||||
if ("child" in addon)
|
||||
addon.child.unregisterContentFrame(contentFrame);
|
||||
}
|
||||
}
|
||||
215
addon-sdk/source/lib/framescript/context-menu.js
Normal file
215
addon-sdk/source/lib/framescript/context-menu.js
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If 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 { query, constant, cache } = require("sdk/lang/functional");
|
||||
const { pairs, each, map, object } = require("sdk/util/sequence");
|
||||
const { nodeToMessageManager } = require("./util");
|
||||
|
||||
// Decorator function that takes `f` function and returns one that attempts
|
||||
// to run `f` with given arguments. In case of exception error is logged
|
||||
// and `fallback` is returned instead.
|
||||
const Try = (fn, fallback=null) => (...args) => {
|
||||
try {
|
||||
return fn(...args);
|
||||
} catch(error) {
|
||||
console.error(error);
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
|
||||
// Decorator funciton that takes `f` function and returns one that returns
|
||||
// JSON cloned result of whatever `f` returns for given arguments.
|
||||
const JSONReturn = f => (...args) => JSON.parse(JSON.stringify(f(...args)));
|
||||
|
||||
const Null = constant(null);
|
||||
|
||||
// Table of readers mapped to field names they're going to be reading.
|
||||
const readers = Object.create(null);
|
||||
// Read function takes "contextmenu" event target `node` and returns table of
|
||||
// read field names mapped to appropriate values. Read uses above defined read
|
||||
// table to read data for all registered readers.
|
||||
const read = node =>
|
||||
object(...map(([id, read]) => [id, read(node, id)], pairs(readers)));
|
||||
|
||||
// Table of built-in readers, each takes a descriptor and returns a reader:
|
||||
// descriptor -> node -> JSON
|
||||
const parsers = Object.create(null)
|
||||
// Function takes a descriptor of the remotely defined reader and parsese it
|
||||
// to construct a local reader that's going to read out data from context menu
|
||||
// target.
|
||||
const parse = descriptor => {
|
||||
const parser = parsers[descriptor.category];
|
||||
if (!parser) {
|
||||
console.error("Unknown reader descriptor was received", descriptor, `"${descriptor.category}"`);
|
||||
return Null
|
||||
}
|
||||
return Try(parser(descriptor));
|
||||
}
|
||||
|
||||
// TODO: Test how chrome's mediaType behaves to try and match it's behavior.
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
// Firefox always creates a HTMLVideoElement when loading an ogg file
|
||||
// directly. If the media is actually audio, be smarter and provide a
|
||||
// context menu with audio operations.
|
||||
// Source: https://github.com/mozilla/gecko-dev/blob/28c2fca3753c5371643843fc2f2f205146b083b7/browser/base/content/nsContextMenu.js#L632-L637
|
||||
const isVideoLoadingAudio = node =>
|
||||
node.readyState >= node.HAVE_METADATA &&
|
||||
(node.videoWidth == 0 || node.videoHeight == 0)
|
||||
|
||||
const isVideo = node =>
|
||||
node instanceof node.ownerDocument.defaultView.HTMLVideoElement &&
|
||||
!isVideoLoadingAudio(node);
|
||||
|
||||
const isAudio = node => {
|
||||
const {HTMLVideoElement, HTMLAudioElement} = node.ownerDocument.defaultView;
|
||||
return node instanceof HTMLAudioElement ? true :
|
||||
node instanceof HTMLVideoElement ? isVideoLoadingAudio(node) :
|
||||
false;
|
||||
};
|
||||
|
||||
const isImage = ({namespaceURI, localName}) =>
|
||||
namespaceURI === HTML_NS && localName === "img" ? true :
|
||||
namespaceURI === XUL_NS && localName === "image" ? true :
|
||||
namespaceURI === SVG_NS && localName === "image" ? true :
|
||||
false;
|
||||
|
||||
parsers["reader/MediaType()"] = constant(node =>
|
||||
isImage(node) ? "image" :
|
||||
isAudio(node) ? "audio" :
|
||||
isVideo(node) ? "video" :
|
||||
null);
|
||||
|
||||
|
||||
const readLink = node =>
|
||||
node.namespaceURI === HTML_NS && node.localName === "a" ? node.href :
|
||||
readLink(node.parentNode);
|
||||
|
||||
parsers["reader/LinkURL()"] = constant(node =>
|
||||
node.matches("a, a *") ? readLink(node) : null);
|
||||
|
||||
// Reader that reads out `true` if "contextmenu" `event.target` matches
|
||||
// `descriptor.selector` and `false` if it does not.
|
||||
parsers["reader/SelectorMatch()"] = ({selector}) =>
|
||||
node => node.matches(selector);
|
||||
|
||||
// Accessing `selectionStart` and `selectionEnd` properties on non
|
||||
// editable input nodes throw exceptions, there for we need this util
|
||||
// function to guard us against them.
|
||||
const getInputSelection = node => {
|
||||
try {
|
||||
if ("selectionStart" in node && "selectionEnd" in node) {
|
||||
const {selectionStart, selectionEnd} = node;
|
||||
return {selectionStart, selectionEnd}
|
||||
}
|
||||
}
|
||||
catch(_) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Selection reader does not really cares about descriptor so it is
|
||||
// a constant function returning selection reader. Selection reader
|
||||
// returns string of the selected text or `null` if there is no selection.
|
||||
parsers["reader/Selection()"] = constant(node => {
|
||||
const selection = node.ownerDocument.getSelection();
|
||||
if (!selection.isCollapsed) {
|
||||
return selection.toString();
|
||||
}
|
||||
// If target node is editable (text, input, textarea, etc..) document does
|
||||
// not really handles selections there. There for we fallback to checking
|
||||
// `selectionStart` `selectionEnd` properties and if they are present we
|
||||
// extract selections manually from the `node.value`.
|
||||
else {
|
||||
const selection = getInputSelection(node);
|
||||
const isSelected = selection &&
|
||||
Number.isInteger(selection.selectionStart) &&
|
||||
Number.isInteger(selection.selectionEnd) &&
|
||||
selection.selectionStart !== selection.selectionEnd;
|
||||
return isSelected ? node.value.substring(selection.selectionStart,
|
||||
selection.selectionEnd) :
|
||||
null;
|
||||
}
|
||||
});
|
||||
|
||||
// Query reader just reads out properties from the node, so we just use `query`
|
||||
// utility function.
|
||||
parsers["reader/Query()"] = ({path}) => JSONReturn(query(path));
|
||||
// Attribute reader just reads attribute of the event target node.
|
||||
parsers["reader/Attribute()"] = ({name}) => node => node.getAttribute(name);
|
||||
|
||||
// Extractor reader defines generates a reader out of serialized function, who's
|
||||
// return value is JSON cloned. Note: We do know source will evaluate to function
|
||||
// as that's what we serialized on the other end, it's also ok if generated function
|
||||
// is going to throw as registered readers are wrapped in try catch to avoid breakting
|
||||
// unrelated readers.
|
||||
parsers["reader/Extractor()"] = ({source}) =>
|
||||
JSONReturn(new Function("return (" + source + ")")());
|
||||
|
||||
// If the context-menu target node or any of its ancestors is one of these,
|
||||
// Firefox uses a tailored context menu, and so the page context doesn't apply.
|
||||
// There for `reader/isPage()` will read `false` in that case otherwise it's going
|
||||
// to read `true`.
|
||||
const nonPageElements = ["a", "applet", "area", "button", "canvas", "object",
|
||||
"embed", "img", "input", "map", "video", "audio", "menu",
|
||||
"option", "select", "textarea", "[contenteditable=true]"];
|
||||
const nonPageSelector = nonPageElements.
|
||||
concat(nonPageElements.map(tag => `${tag} *`)).
|
||||
join(", ");
|
||||
|
||||
// Note: isPageContext implementation could have actually used SelectorMatch reader,
|
||||
// but old implementation was also checked for collapsed selection there for to keep
|
||||
// the behavior same we end up implementing a new reader.
|
||||
parsers["reader/isPage()"] = constant(node =>
|
||||
node.ownerDocument.defaultView.getSelection().isCollapsed &&
|
||||
!node.matches(nonPageSelector));
|
||||
|
||||
// Reads `true` if node is in an iframe otherwise returns true.
|
||||
parsers["reader/isFrame()"] = constant(node =>
|
||||
!!node.ownerDocument.defaultView.frameElement);
|
||||
|
||||
parsers["reader/isEditable()"] = constant(node => {
|
||||
const selection = getInputSelection(node);
|
||||
return selection ? !node.readOnly && !node.disabled : node.isContentEditable;
|
||||
});
|
||||
|
||||
|
||||
// TODO: Add some reader to read out tab id.
|
||||
|
||||
const onReadersUpdate = message => {
|
||||
each(([id, descriptor]) => {
|
||||
if (descriptor) {
|
||||
readers[id] = parse(descriptor);
|
||||
}
|
||||
else {
|
||||
delete readers[id];
|
||||
}
|
||||
}, pairs(message.data));
|
||||
};
|
||||
exports.onReadersUpdate = onReadersUpdate;
|
||||
|
||||
|
||||
const onContextMenu = event => {
|
||||
if (!event.defaultPrevented) {
|
||||
const manager = nodeToMessageManager(event.target);
|
||||
manager.sendSyncMessage("sdk/context-menu/read", read(event.target), readers);
|
||||
}
|
||||
};
|
||||
exports.onContextMenu = onContextMenu;
|
||||
|
||||
|
||||
const onContentFrame = (frame) => {
|
||||
// Listen for contextmenu events in on this frame.
|
||||
frame.addEventListener("contextmenu", onContextMenu);
|
||||
// Listen to registered reader changes and update registry.
|
||||
frame.addMessageListener("sdk/context-menu/readers", onReadersUpdate);
|
||||
|
||||
// Request table of readers (if this is loaded in a new process some table
|
||||
// changes may be missed, this is way to sync up).
|
||||
frame.sendAsyncMessage("sdk/context-menu/readers?");
|
||||
};
|
||||
exports.onContentFrame = onContentFrame;
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue