mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge fx-team to mozilla-central a=merge
This commit is contained in:
commit
86bbfb82a8
@ -15,6 +15,7 @@ const { loadReason } = require('../self');
|
||||
const { rootURI, metadata } = require("@loader/options");
|
||||
const globals = require('../system/globals');
|
||||
const xulApp = require('../system/xul-app');
|
||||
const { id } = require('sdk/self');
|
||||
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
|
||||
getService(Ci.nsIAppShellService);
|
||||
const { preferences } = metadata;
|
||||
@ -134,7 +135,7 @@ function run(options) {
|
||||
// native-options does stuff directly with preferences key from package.json
|
||||
if (preferences && preferences.length > 0) {
|
||||
try {
|
||||
require('../preferences/native-options').enable(preferences);
|
||||
require('../preferences/native-options').enable({ preferences: preferences, id: id });
|
||||
}
|
||||
catch (error) {
|
||||
console.exception(error);
|
||||
|
@ -12,29 +12,41 @@ const { on } = require('../system/events');
|
||||
const { id, preferencesBranch } = require('../self');
|
||||
const { localizeInlineOptions } = require('../l10n/prefs');
|
||||
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
const { defer } = require("sdk/core/promise");
|
||||
|
||||
const DEFAULT_OPTIONS_URL = 'data:text/xml,<placeholder/>';
|
||||
|
||||
const VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color',
|
||||
const VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color',
|
||||
'file', 'directory', 'control', 'menulist', 'radio'];
|
||||
|
||||
function enable(preferences) {
|
||||
function enable({ preferences, id }) {
|
||||
let enabled = defer();
|
||||
|
||||
validate(preferences);
|
||||
|
||||
setDefaults(preferences, preferencesBranch);
|
||||
|
||||
// allow the use of custom options.xul
|
||||
AddonManager.getAddonByID(id, (addon) => {
|
||||
if (addon.optionsURL === DEFAULT_OPTIONS_URL)
|
||||
on('addon-options-displayed', onAddonOptionsDisplayed, true);
|
||||
})
|
||||
on('addon-options-displayed', onAddonOptionsDisplayed, true);
|
||||
enabled.resolve({ id: id });
|
||||
});
|
||||
|
||||
function onAddonOptionsDisplayed({ subject: doc, data }) {
|
||||
if (data === id) {
|
||||
let parent = doc.getElementById('detail-downloads').parentNode;
|
||||
injectOptions(preferences, preferencesBranch, doc, parent);
|
||||
injectOptions({
|
||||
preferences: preferences,
|
||||
preferencesBranch: preferencesBranch,
|
||||
document: doc,
|
||||
parent: parent,
|
||||
id: id
|
||||
});
|
||||
localizeInlineOptions(doc);
|
||||
}
|
||||
}
|
||||
|
||||
return enabled.promise;
|
||||
}
|
||||
exports.enable = enable;
|
||||
|
||||
@ -75,18 +87,18 @@ function setDefaults(preferences, preferencesBranch) {
|
||||
const branch = Cc['@mozilla.org/preferences-service;1'].
|
||||
getService(Ci.nsIPrefService).
|
||||
getDefaultBranch('extensions.' + preferencesBranch + '.');
|
||||
for (let {name, value} of preferences) {
|
||||
for (let { name, value } of preferences) {
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
branch.setBoolPref(name, value);
|
||||
break;
|
||||
case 'number':
|
||||
case 'number':
|
||||
// must be integer, ignore otherwise
|
||||
if (value % 1 === 0)
|
||||
if (value % 1 === 0) {
|
||||
branch.setIntPref(name, value);
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
// ∵
|
||||
let str = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
str.data = value;
|
||||
@ -98,11 +110,12 @@ function setDefaults(preferences, preferencesBranch) {
|
||||
exports.setDefaults = setDefaults;
|
||||
|
||||
// dynamically injects inline options into about:addons page at runtime
|
||||
function injectOptions(preferences, preferencesBranch, document, parent) {
|
||||
function injectOptions({ preferences, preferencesBranch, document, parent, id }) {
|
||||
for (let { name, type, hidden, title, description, label, options, on, off } of preferences) {
|
||||
|
||||
if (hidden)
|
||||
if (hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let setting = document.createElement('setting');
|
||||
setting.setAttribute('pref-name', name);
|
||||
@ -114,7 +127,7 @@ function injectOptions(preferences, preferencesBranch, document, parent) {
|
||||
|
||||
if (type === 'file' || type === 'directory') {
|
||||
setting.setAttribute('fullpath', 'true');
|
||||
}
|
||||
}
|
||||
else if (type === 'control') {
|
||||
let button = document.createElement('button');
|
||||
button.setAttribute('pref-name', name);
|
||||
@ -123,11 +136,11 @@ function injectOptions(preferences, preferencesBranch, document, parent) {
|
||||
button.setAttribute('oncommand', "Services.obs.notifyObservers(null, '" +
|
||||
id + "-cmdPressed', '" + name + "');");
|
||||
setting.appendChild(button);
|
||||
}
|
||||
}
|
||||
else if (type === 'boolint') {
|
||||
setting.setAttribute('on', on);
|
||||
setting.setAttribute('off', off);
|
||||
}
|
||||
}
|
||||
else if (type === 'menulist') {
|
||||
let menulist = document.createElement('menulist');
|
||||
let menupopup = document.createElement('menupopup');
|
||||
@ -139,7 +152,7 @@ function injectOptions(preferences, preferencesBranch, document, parent) {
|
||||
}
|
||||
menulist.appendChild(menupopup);
|
||||
setting.appendChild(menulist);
|
||||
}
|
||||
}
|
||||
else if (type === 'radio') {
|
||||
let radiogroup = document.createElement('radiogroup');
|
||||
for (let { value, label } of options) {
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
|
50
addon-sdk/source/lib/sdk/preferences/utils.js
Normal file
50
addon-sdk/source/lib/sdk/preferences/utils.js
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/. */
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { openTab, getBrowserForTab, getTabId } = require("sdk/tabs/utils");
|
||||
const { defer, all } = require("sdk/core/promise");
|
||||
const { on, off } = require("sdk/system/events");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
const { getMostRecentBrowserWindow } = require('../window/utils');
|
||||
|
||||
const open = function open({ id }) {
|
||||
let showing = defer();
|
||||
let loaded = defer();
|
||||
let result = { id: id };
|
||||
let tab = openTab(getMostRecentBrowserWindow(), "about:addons", {
|
||||
inBackground: true
|
||||
});
|
||||
let browser = getBrowserForTab(tab);
|
||||
|
||||
browser.addEventListener("load", function onPageLoad() {
|
||||
browser.removeEventListener("load", onPageLoad, true);
|
||||
let window = browser.contentWindow;
|
||||
|
||||
// wait for the add-on's "addon-options-displayed"
|
||||
on("addon-options-displayed", function onPrefDisplayed({ subject: doc, data }) {
|
||||
if (data === id) {
|
||||
off("addon-options-displayed", onPrefDisplayed);
|
||||
result.tabId = getTabId(tab);
|
||||
result.document = doc;
|
||||
loaded.resolve();
|
||||
}
|
||||
}, true);
|
||||
|
||||
// display the add-on inline preferences page
|
||||
window.gViewController.commands.cmd_showItemDetails.doCommand({ id: id }, true);
|
||||
let { node } = window.gViewController.viewObjects.detail;
|
||||
node.addEventListener("ViewChanged", function whenViewChanges() {
|
||||
node.removeEventListener("ViewChanged", whenViewChanges, false);
|
||||
showing.resolve();
|
||||
}, false);
|
||||
}, true);
|
||||
|
||||
return all([ showing.promise, loaded.promise ]).then(_ => result);
|
||||
}
|
||||
exports.open = open;
|
@ -266,7 +266,7 @@ parser_groups = (
|
||||
help="enable remote windows",
|
||||
action="store_true",
|
||||
default=False,
|
||||
cmds=['test', 'run', 'testex', 'testpkgs',
|
||||
cmds=['test', 'run', 'testex', 'testpkgs',
|
||||
'testaddons', 'testcfx', 'testall'])),
|
||||
(("", "--logfile",), dict(dest="logfile",
|
||||
help="log console output to file",
|
||||
@ -421,13 +421,14 @@ def test_all_testaddons(env_root, defaults):
|
||||
addons.sort()
|
||||
fail = False
|
||||
for dirname in addons:
|
||||
# apply the filter
|
||||
if (not defaults['filter'].split(":")[0] in dirname):
|
||||
continue
|
||||
|
||||
print >>sys.stderr, "Testing %s..." % dirname
|
||||
sys.stderr.flush()
|
||||
try:
|
||||
run(arguments=["run",
|
||||
run(arguments=["testrun",
|
||||
"--pkgdir",
|
||||
os.path.join(addons_dir, dirname)],
|
||||
defaults=defaults,
|
||||
@ -619,7 +620,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
return
|
||||
test_cfx(env_root, options.verbose)
|
||||
return
|
||||
elif command not in ["xpi", "test", "run"]:
|
||||
elif command not in ["xpi", "test", "run", "testrun"]:
|
||||
print >>sys.stderr, "Unknown command: %s" % command
|
||||
print >>sys.stderr, "Try using '--help' for assistance."
|
||||
sys.exit(1)
|
||||
@ -663,6 +664,9 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
enforce_timeouts = True
|
||||
elif command == "run":
|
||||
use_main = True
|
||||
elif command == "testrun":
|
||||
use_main = True
|
||||
enforce_timeouts = True
|
||||
else:
|
||||
assert 0, "shouldn't get here"
|
||||
|
||||
@ -681,7 +685,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
# TODO: Consider keeping a cache of dynamic UUIDs, based
|
||||
# on absolute filesystem pathname, in the root directory
|
||||
# or something.
|
||||
if command in ('xpi', 'run'):
|
||||
if command in ('xpi', 'run', 'testrun'):
|
||||
from cuddlefish.preflight import preflight_config
|
||||
if target_cfg_json:
|
||||
config_was_ok, modified = preflight_config(target_cfg,
|
||||
|
@ -37,10 +37,12 @@ import re
|
||||
import os.path
|
||||
|
||||
def get_expanded_variables(versionfile_source):
|
||||
# the code embedded in _version.py can just fetch the value of these
|
||||
# variables. When used from setup.py, we don't want to import
|
||||
# _version.py, so we do it with a regexp instead. This function is not
|
||||
# used from _version.py.
|
||||
"""
|
||||
the code embedded in _version.py can just fetch the value of these
|
||||
variables. When used from setup.py, we don't want to import
|
||||
_version.py, so we do it with a regexp instead. This function is not
|
||||
used from _version.py.
|
||||
"""
|
||||
variables = {}
|
||||
try:
|
||||
for line in open(versionfile_source,"r").readlines():
|
||||
@ -81,15 +83,16 @@ def versions_from_expanded_variables(variables, tag_prefix):
|
||||
"full": variables["full"].strip() }
|
||||
|
||||
def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
|
||||
# this runs 'git' from the root of the source tree. That either means
|
||||
# someone ran a setup.py command (and this code is in versioneer.py, thus
|
||||
# the containing directory is the root of the source tree), or someone
|
||||
# ran a project-specific entry point (and this code is in _version.py,
|
||||
# thus the containing directory is somewhere deeper in the source tree).
|
||||
# This only gets called if the git-archive 'subst' variables were *not*
|
||||
# expanded, and _version.py hasn't already been rewritten with a short
|
||||
# version string, meaning we're inside a checked out source tree.
|
||||
|
||||
"""
|
||||
this runs 'git' from the root of the source tree. That either means
|
||||
someone ran a setup.py command (and this code is in versioneer.py, thus
|
||||
the containing directory is the root of the source tree), or someone
|
||||
ran a project-specific entry point (and this code is in _version.py,
|
||||
thus the containing directory is somewhere deeper in the source tree).
|
||||
This only gets called if the git-archive 'subst' variables were *not*
|
||||
expanded, and _version.py hasn't already been rewritten with a short
|
||||
version string, meaning we're inside a checked out source tree.
|
||||
"""
|
||||
try:
|
||||
here = os.path.abspath(__file__)
|
||||
except NameError:
|
||||
|
@ -120,7 +120,9 @@ def hash_file(fn):
|
||||
return hashlib.sha256(open(fn,"rb").read()).hexdigest()
|
||||
|
||||
def get_datafiles(datadir):
|
||||
# yields pathnames relative to DATADIR, ignoring some files
|
||||
"""
|
||||
yields pathnames relative to DATADIR, ignoring some files
|
||||
"""
|
||||
for dirpath, dirnames, filenames in os.walk(datadir):
|
||||
filenames = list(filter_filenames(filenames))
|
||||
# this tells os.walk to prune the search
|
||||
@ -193,8 +195,9 @@ class ManifestBuilder:
|
||||
self.test_modules = [] # for runtime
|
||||
|
||||
def build(self, scan_tests, test_filter_re):
|
||||
# process the top module, which recurses to process everything it
|
||||
# reaches
|
||||
"""
|
||||
process the top module, which recurses to process everything it reaches
|
||||
"""
|
||||
if "main" in self.target_cfg:
|
||||
top_mi = self.find_top(self.target_cfg)
|
||||
top_me = self.process_module(top_mi)
|
||||
@ -261,9 +264,11 @@ class ManifestBuilder:
|
||||
return sorted(used)
|
||||
|
||||
def get_used_files(self, bundle_sdk_modules):
|
||||
# returns all .js files that we reference, plus data/ files. You will
|
||||
# need to add the loader, off-manifest files that it needs, and
|
||||
# generated metadata.
|
||||
"""
|
||||
returns all .js files that we reference, plus data/ files. You will
|
||||
need to add the loader, off-manifest files that it needs, and
|
||||
generated metadata.
|
||||
"""
|
||||
for datamap in self.datamaps.values():
|
||||
for (zipname, absname) in datamap.files_to_copy:
|
||||
yield absname
|
||||
|
@ -715,7 +715,7 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
|
||||
|
||||
done = False
|
||||
result = None
|
||||
test_name = "unknown"
|
||||
test_name = "Jetpack startup"
|
||||
|
||||
def Timeout(message, test_name, parseable):
|
||||
if parseable:
|
||||
|
@ -25,10 +25,13 @@ UNICODE_ORG_XML_URL = "http://unicode.org/repos/cldr/trunk/common/supplemental/p
|
||||
|
||||
CONDITION_RE = r'n( mod \d+)? (is|in|within|(not in))( not)? ([^\s]+)'
|
||||
|
||||
# For a given regexp.MatchObject `g` for `CONDITION_RE`,
|
||||
# returns the equivalent JS piece of code
|
||||
# i.e. maps pseudo conditional language from unicode.org XML to JS code
|
||||
|
||||
def parseCondition(g):
|
||||
"""
|
||||
For a given regexp.MatchObject `g` for `CONDITION_RE`,
|
||||
returns the equivalent JS piece of code
|
||||
i.e. maps pseudo conditional language from unicode.org XML to JS code
|
||||
"""
|
||||
lvalue = "n"
|
||||
if g.group(1):
|
||||
lvalue = "(n %% %d)" % int(g.group(1).replace("mod ", ""))
|
||||
@ -81,7 +84,9 @@ def parseCondition(g):
|
||||
return "%s(%s)" % (notPrefix, " || ".join(subCondition))
|
||||
|
||||
def computeRules():
|
||||
# Fetch plural rules data directly from unicode.org website:
|
||||
"""
|
||||
Fetch plural rules data directly from unicode.org website:
|
||||
"""
|
||||
url = UNICODE_ORG_XML_URL
|
||||
f = urllib2.urlopen(url)
|
||||
doc = xml.dom.minidom.parse(f)
|
||||
|
@ -28,9 +28,10 @@ INFINITY = float('1e66666')
|
||||
FLOAT_REPR = repr
|
||||
|
||||
def floatstr(o, allow_nan=True):
|
||||
# Check for specials. Note that this type of test is processor- and/or
|
||||
# platform-specific, so do tests which don't depend on the internals.
|
||||
|
||||
"""
|
||||
Check for specials. Note that this type of test is processor- and/or
|
||||
platform-specific, so do tests which don't depend on the internals.
|
||||
"""
|
||||
if o != o:
|
||||
text = 'NaN'
|
||||
elif o == INFINITY:
|
||||
@ -174,9 +175,15 @@ class JSONEncoder(object):
|
||||
self.encoding = encoding
|
||||
|
||||
def _newline_indent(self):
|
||||
"""
|
||||
Indent lines by level
|
||||
"""
|
||||
return '\n' + (' ' * (self.indent * self.current_indent_level))
|
||||
|
||||
def _iterencode_list(self, lst, markers=None):
|
||||
"""
|
||||
Encoding lists, yielding by level
|
||||
"""
|
||||
if not lst:
|
||||
yield '[]'
|
||||
return
|
||||
@ -210,6 +217,9 @@ class JSONEncoder(object):
|
||||
del markers[markerid]
|
||||
|
||||
def _iterencode_dict(self, dct, markers=None):
|
||||
"""
|
||||
Encoding dictionaries, yielding by level
|
||||
"""
|
||||
if not dct:
|
||||
yield '{}'
|
||||
return
|
||||
|
@ -6,9 +6,10 @@
|
||||
const { get: getPref } = require('sdk/preferences/service');
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { openTab, closeTab, getBrowserForTab } = require('sdk/tabs/utils');
|
||||
const tabs = require('sdk/tabs');
|
||||
|
||||
exports.testRemotePrefIsSet = function(assert) {
|
||||
assert.ok(getPref('browser.tabs.remote.autostart'),
|
||||
assert.ok(getPref('browser.tabs.remote.autostart'),
|
||||
"Electrolysis remote tabs pref should be set");
|
||||
}
|
||||
|
||||
@ -19,11 +20,12 @@ exports.testTabIsRemote = function(assert, done) {
|
||||
|
||||
// can't simply close a remote tab before it is loaded, bug 1006043
|
||||
let mm = getBrowserForTab(tab).messageManager;
|
||||
mm.addMessageListener(7, function() {
|
||||
mm.addMessageListener('7', function listener() {
|
||||
mm.removeMessageListener('7', listener);
|
||||
tabs.once('close', done);
|
||||
closeTab(tab);
|
||||
done();
|
||||
})
|
||||
mm.loadFrameScript('data:,sendAsyncMessage(7)', false);
|
||||
mm.loadFrameScript('data:,sendAsyncMessage("7")', true);
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
||||
|
@ -7,8 +7,11 @@ const { Cu } = require('chrome');
|
||||
const sp = require('sdk/simple-prefs');
|
||||
const app = require('sdk/system/xul-app');
|
||||
const self = require('sdk/self');
|
||||
const tabs = require('sdk/tabs');
|
||||
const { preferencesBranch } = require('sdk/self');
|
||||
const { preferencesBranch } = self;
|
||||
const { open } = require('sdk/preferences/utils');
|
||||
const { getTabForId } = require('sdk/tabs/utils');
|
||||
const { Tab } = require('sdk/tabs/tab');
|
||||
require('sdk/tabs');
|
||||
|
||||
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
|
||||
|
||||
@ -26,112 +29,75 @@ exports.testOptionsType = function(assert, done) {
|
||||
}
|
||||
|
||||
exports.testButton = function(assert, done) {
|
||||
tabs.open({
|
||||
url: 'about:addons',
|
||||
onReady: function(tab) {
|
||||
sp.once('sayHello', function() {
|
||||
assert.pass('The button was pressed!');
|
||||
tab.close(done)
|
||||
});
|
||||
open(self).then(({ tabId, document }) => {
|
||||
let tab = Tab({ tab: getTabForId(tabId) });
|
||||
sp.once('sayHello', _ => {
|
||||
assert.pass('The button was pressed!');
|
||||
tab.close(done);
|
||||
});
|
||||
|
||||
tab.attach({
|
||||
contentScriptWhen: 'end',
|
||||
contentScript: 'function onLoad() {\n' +
|
||||
'unsafeWindow.removeEventListener("load", onLoad, false);\n' +
|
||||
'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' +
|
||||
'setTimeout(function() {\n' + // TODO: figure out why this is necessary..
|
||||
'unsafeWindow.document.querySelector("button[label=\'Click me!\']").click()\n' +
|
||||
'}, 250);\n' +
|
||||
'}, false);\n' +
|
||||
'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' +
|
||||
'});\n' +
|
||||
'}\n' +
|
||||
// Wait for the load event ?
|
||||
'if (document.readyState == "complete") {\n' +
|
||||
'onLoad()\n' +
|
||||
'} else {\n' +
|
||||
'unsafeWindow.addEventListener("load", onLoad, false);\n' +
|
||||
'}\n',
|
||||
});
|
||||
}
|
||||
tab.attach({
|
||||
contentScript: 'unsafeWindow.document.querySelector("button[label=\'Click me!\']").click();'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (app.is('Firefox')) {
|
||||
exports.testAOM = function(assert, done) {
|
||||
tabs.open({
|
||||
url: 'about:addons',
|
||||
onReady: function(tab) {
|
||||
tab.attach({
|
||||
contentScriptWhen: 'end',
|
||||
contentScript: 'function onLoad() {\n' +
|
||||
'unsafeWindow.removeEventListener("load", onLoad, false);\n' +
|
||||
'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' +
|
||||
'setTimeout(function() {\n' + // TODO: figure out why this is necessary..
|
||||
'self.postMessage({\n' +
|
||||
'someCount: unsafeWindow.document.querySelectorAll("setting[title=\'some-title\']").length,\n' +
|
||||
'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[title=\'some-title\']")),\n' +
|
||||
'myInteger: getAttributes(unsafeWindow.document.querySelector("setting[title=\'my-int\']")),\n' +
|
||||
'myHiddenInt: getAttributes(unsafeWindow.document.querySelector("setting[title=\'hidden-int\']")),\n' +
|
||||
'sayHello: getAttributes(unsafeWindow.document.querySelector("button[label=\'Click me!\']"))\n' +
|
||||
'});\n' +
|
||||
'}, 250);\n' +
|
||||
'}, false);\n' +
|
||||
'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' +
|
||||
'});\n' +
|
||||
'function getAttributes(ele) {\n' +
|
||||
'if (!ele) return {};\n' +
|
||||
'return {\n' +
|
||||
'pref: ele.getAttribute("pref"),\n' +
|
||||
'type: ele.getAttribute("type"),\n' +
|
||||
'title: ele.getAttribute("title"),\n' +
|
||||
'desc: ele.getAttribute("desc"),\n' +
|
||||
'"data-jetpack-id": ele.getAttribute(\'data-jetpack-id\')\n' +
|
||||
'}\n' +
|
||||
'}\n' +
|
||||
'}\n' +
|
||||
// Wait for the load event ?
|
||||
'if (document.readyState == "complete") {\n' +
|
||||
'onLoad()\n' +
|
||||
'} else {\n' +
|
||||
'unsafeWindow.addEventListener("load", onLoad, false);\n' +
|
||||
'}\n',
|
||||
onMessage: function(msg) {
|
||||
// test against doc caching
|
||||
assert.equal(msg.someCount, 1, 'there is exactly one <setting> node for somePreference');
|
||||
open(self).then(({ tabId }) => {
|
||||
let tab = Tab({ tab: getTabForId(tabId) });
|
||||
assert.pass('the add-on prefs page was opened.');
|
||||
|
||||
// test somePreference
|
||||
assert.equal(msg.somePreference.type, 'string', 'some pref is a string');
|
||||
assert.equal(msg.somePreference.pref, 'extensions.'+self.id+'.somePreference', 'somePreference path is correct');
|
||||
assert.equal(msg.somePreference.title, 'some-title', 'somePreference title is correct');
|
||||
assert.equal(msg.somePreference.desc, 'Some short description for the preference', 'somePreference description is correct');
|
||||
assert.equal(msg.somePreference['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
|
||||
tab.attach({
|
||||
contentScriptWhen: "end",
|
||||
contentScript: 'self.postMessage({\n' +
|
||||
'someCount: unsafeWindow.document.querySelectorAll("setting[title=\'some-title\']").length,\n' +
|
||||
'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[title=\'some-title\']")),\n' +
|
||||
'myInteger: getAttributes(unsafeWindow.document.querySelector("setting[title=\'my-int\']")),\n' +
|
||||
'myHiddenInt: getAttributes(unsafeWindow.document.querySelector("setting[title=\'hidden-int\']")),\n' +
|
||||
'sayHello: getAttributes(unsafeWindow.document.querySelector("button[label=\'Click me!\']"))\n' +
|
||||
'});\n' +
|
||||
'function getAttributes(ele) {\n' +
|
||||
'if (!ele) return {};\n' +
|
||||
'return {\n' +
|
||||
'pref: ele.getAttribute("pref"),\n' +
|
||||
'type: ele.getAttribute("type"),\n' +
|
||||
'title: ele.getAttribute("title"),\n' +
|
||||
'desc: ele.getAttribute("desc"),\n' +
|
||||
'"data-jetpack-id": ele.getAttribute(\'data-jetpack-id\')\n' +
|
||||
'}\n' +
|
||||
'}\n',
|
||||
onMessage: msg => {
|
||||
// test against doc caching
|
||||
assert.equal(msg.someCount, 1, 'there is exactly one <setting> node for somePreference');
|
||||
|
||||
// test myInteger
|
||||
assert.equal(msg.myInteger.type, 'integer', 'myInteger is a int');
|
||||
assert.equal(msg.myInteger.pref, 'extensions.'+self.id+'.myInteger', 'extensions.test-simple-prefs.myInteger');
|
||||
assert.equal(msg.myInteger.title, 'my-int', 'myInteger title is correct');
|
||||
assert.equal(msg.myInteger.desc, 'How many of them we have.', 'myInteger desc is correct');
|
||||
assert.equal(msg.myInteger['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
|
||||
// test somePreference
|
||||
assert.equal(msg.somePreference.type, 'string', 'some pref is a string');
|
||||
assert.equal(msg.somePreference.pref, 'extensions.'+self.id+'.somePreference', 'somePreference path is correct');
|
||||
assert.equal(msg.somePreference.title, 'some-title', 'somePreference title is correct');
|
||||
assert.equal(msg.somePreference.desc, 'Some short description for the preference', 'somePreference description is correct');
|
||||
assert.equal(msg.somePreference['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
|
||||
|
||||
// test myHiddenInt
|
||||
assert.equal(msg.myHiddenInt.type, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.pref, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.title, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.desc, undefined, 'myHiddenInt was not displayed');
|
||||
// test myInteger
|
||||
assert.equal(msg.myInteger.type, 'integer', 'myInteger is a int');
|
||||
assert.equal(msg.myInteger.pref, 'extensions.'+self.id+'.myInteger', 'extensions.test-simple-prefs.myInteger');
|
||||
assert.equal(msg.myInteger.title, 'my-int', 'myInteger title is correct');
|
||||
assert.equal(msg.myInteger.desc, 'How many of them we have.', 'myInteger desc is correct');
|
||||
assert.equal(msg.myInteger['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
|
||||
|
||||
// test sayHello
|
||||
assert.equal(msg.sayHello['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
|
||||
// test myHiddenInt
|
||||
assert.equal(msg.myHiddenInt.type, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.pref, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.title, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.desc, undefined, 'myHiddenInt was not displayed');
|
||||
|
||||
tab.close(done);
|
||||
}
|
||||
});
|
||||
}
|
||||
// test sayHello
|
||||
assert.equal(msg.sayHello['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct');
|
||||
|
||||
tab.close(done);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// run it again, to test against inline options document caching
|
||||
|
10
addon-sdk/source/test/fixtures/bootstrap-addon/bootstrap.js
vendored
Normal file
10
addon-sdk/source/test/fixtures/bootstrap-addon/bootstrap.js
vendored
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';
|
||||
|
||||
function install(data, reason) {}
|
||||
function uninstall(data, reason) {}
|
||||
|
||||
function startup(data, reasonCode) {};
|
||||
function shutdown(data, reasonCode) {};
|
27
addon-sdk/source/test/fixtures/bootstrap-addon/install.rdf
vendored
Normal file
27
addon-sdk/source/test/fixtures/bootstrap-addon/install.rdf
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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>test-bootstrap-addon@mozilla.com</em:id>
|
||||
<em:name>Test Bootstrap Add-on</em:name>
|
||||
<em:creator>Erik Vold</em:creator>
|
||||
<em:optionsType>2</em:optionsType>
|
||||
<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>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
3
addon-sdk/source/test/fixtures/bootstrap-addon/options.xul
vendored
Normal file
3
addon-sdk/source/test/fixtures/bootstrap-addon/options.xul
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE mydialog SYSTEM "chrome://myaddon/locale/mydialog.dtd">
|
||||
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"></vbox>
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"id": "jid1-fZHqN9JfrDBa8A",
|
||||
"id": "no-prefs@jetpack",
|
||||
"title": "No Prefs Test",
|
||||
"author": "Erik Vold",
|
||||
"loader": "lib/main.js"
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"id": "jid1-fZHqN9JfrDBa8A",
|
||||
"id": "simple-prefs@jetpack",
|
||||
"title": "Simple Prefs Test",
|
||||
"author": "Erik Vold",
|
||||
"preferences": [{
|
||||
|
@ -9,7 +9,6 @@ const { on, off } = require("sdk/system/events");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
const tmp = require("sdk/test/tmp-file");
|
||||
const system = require("sdk/system");
|
||||
const fixtures = require("./fixtures");
|
||||
|
||||
const testFolderURL = module.uri.split('test-addon-installer.js')[0];
|
||||
const ADDON_URL = testFolderURL + "fixtures/addon-install-unit-test@mozilla.com.xpi";
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { setDefaults, injectOptions, validate } = require('sdk/preferences/native-options');
|
||||
const { setDefaults, injectOptions: inject, validate } = require('sdk/preferences/native-options');
|
||||
const { activeBrowserWindow: { document } } = require("sdk/deprecated/window-utils");
|
||||
const { preferencesBranch, id } = require('sdk/self');
|
||||
const { get } = require('sdk/preferences/service');
|
||||
@ -12,6 +12,19 @@ const simple = require('sdk/simple-prefs');
|
||||
const fixtures = require('./fixtures');
|
||||
const { Cc, Ci } = require('chrome');
|
||||
|
||||
const prefsrv = Cc['@mozilla.org/preferences-service;1'].
|
||||
getService(Ci.nsIPrefService);
|
||||
|
||||
function injectOptions(preferences, preferencesBranch, document, parent) {
|
||||
inject({
|
||||
id: id,
|
||||
preferences: preferences,
|
||||
preferencesBranch: preferencesBranch,
|
||||
document: document,
|
||||
parent: parent
|
||||
});
|
||||
}
|
||||
|
||||
exports.testValidate = function(assert) {
|
||||
let { preferences } = packageJSON('simple-prefs');
|
||||
|
||||
@ -56,35 +69,45 @@ exports.testNoPrefs = function(assert, done) {
|
||||
|
||||
exports.testCurlyID = function(assert) {
|
||||
let { preferences, id } = packageJSON('curly-id');
|
||||
let branch = prefsrv.getDefaultBranch('extensions.' + id);
|
||||
|
||||
let parent = document.createDocumentFragment();
|
||||
injectOptions(preferences, id, document, parent);
|
||||
assert.equal(parent.children.length, 1, "One setting elements injected");
|
||||
assert.equal(parent.firstElementChild.attributes.pref.value,
|
||||
assert.equal(parent.firstElementChild.attributes.pref.value,
|
||||
"extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13",
|
||||
"Setting pref attribute is set properly");
|
||||
|
||||
setDefaults(preferences, id);
|
||||
assert.equal(get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13'),
|
||||
assert.equal(get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13'),
|
||||
26, "test13 is 26");
|
||||
|
||||
branch.deleteBranch('');
|
||||
assert.equal(get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13'),
|
||||
undefined, "test13 is undefined");
|
||||
}
|
||||
|
||||
exports.testPreferencesBranch = function(assert) {
|
||||
let { preferences, 'preferences-branch': prefsBranch } = packageJSON('preferences-branch');
|
||||
let branch = prefsrv.getDefaultBranch('extensions.' + prefsBranch);
|
||||
|
||||
let parent = document.createDocumentFragment();
|
||||
injectOptions(preferences, prefsBranch, document, parent);
|
||||
assert.equal(parent.children.length, 1, "One setting elements injected");
|
||||
assert.equal(parent.firstElementChild.attributes.pref.value,
|
||||
assert.equal(parent.firstElementChild.attributes.pref.value,
|
||||
"extensions.human-readable.test42",
|
||||
"Setting pref attribute is set properly");
|
||||
|
||||
setDefaults(preferences, prefsBranch);
|
||||
assert.equal(get('extensions.human-readable.test42'), true, "test42 is true");
|
||||
|
||||
branch.deleteBranch('');
|
||||
assert.equal(get('extensions.human-readable.test42'), undefined, "test42 is undefined");
|
||||
}
|
||||
|
||||
exports.testSimplePrefs = function(assert) {
|
||||
let { preferences } = packageJSON('simple-prefs');
|
||||
let branch = prefsrv.getDefaultBranch('extensions.' + preferencesBranch);
|
||||
|
||||
function assertPref(setting, name, type, title) {
|
||||
assert.equal(setting.getAttribute('data-jetpack-id'), id,
|
||||
@ -128,13 +151,15 @@ exports.testSimplePrefs = function(assert) {
|
||||
|
||||
setDefaults(preferences, preferencesBranch);
|
||||
assert.strictEqual(simple.prefs.test, false, "test is false");
|
||||
assert.strictEqual(simple.prefs.test2, "\u00FCnic\u00F8d\u00E9", "test2 is unicode");
|
||||
assert.strictEqual(simple.prefs.test2, "\u00FCnic\u00F8d\u00E9", "test2 is unicode");
|
||||
assert.strictEqual(simple.prefs.test3, "1", "test3 is '1'");
|
||||
assert.strictEqual(simple.prefs.test4, "red", "test4 is 'red'");
|
||||
|
||||
// default pref branch can't be "reset", bug 1012231
|
||||
Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).
|
||||
getDefaultBranch('extensions.' + preferencesBranch).deleteBranch('');
|
||||
branch.deleteBranch('');
|
||||
assert.strictEqual(simple.prefs.test, undefined, "test is undefined");
|
||||
assert.strictEqual(simple.prefs.test2, undefined, "test2 is undefined");
|
||||
assert.strictEqual(simple.prefs.test3, undefined, "test3 is undefined");
|
||||
assert.strictEqual(simple.prefs.test4, undefined, "test4 is undefined");
|
||||
}
|
||||
|
||||
function packageJSON(dir) {
|
||||
|
@ -3,12 +3,29 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci, Cu } = require('chrome');
|
||||
const { Loader } = require("sdk/test/loader");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
const { emit } = require("sdk/system/events");
|
||||
const { id } = require("sdk/self");
|
||||
const simplePrefs = require("sdk/simple-prefs");
|
||||
const { prefs: sp } = simplePrefs;
|
||||
const { defer, resolve, reject, all } = require("sdk/core/promise");
|
||||
const AddonInstaller = require("sdk/addon/installer");
|
||||
const fixtures = require("./fixtures");
|
||||
const { pathFor } = require("sdk/system");
|
||||
const file = require("sdk/io/file");
|
||||
const { install, uninstall } = require("sdk/addon/installer");
|
||||
const { open } = require('sdk/preferences/utils');
|
||||
const { toFilename } = require('sdk/url');
|
||||
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
|
||||
const { ZipWriter } = require('./zip/utils');
|
||||
const { getTabForId } = require('sdk/tabs/utils');
|
||||
const { preferencesBranch, id } = require('sdk/self');
|
||||
const { Tab } = require('sdk/tabs/tab');
|
||||
require('sdk/tabs');
|
||||
|
||||
const prefsrv = Cc['@mozilla.org/preferences-service;1'].
|
||||
getService(Ci.nsIPrefService);
|
||||
|
||||
const specialChars = "!@#$%^&*()_-=+[]{}~`\'\"<>,./?;:";
|
||||
|
||||
@ -230,4 +247,104 @@ exports.testPrefJSONStringification = function(assert) {
|
||||
"JSON stringification should work.");
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
exports.testUnloadOfDynamicPrefGeneration = function(assert, done) {
|
||||
let loader = Loader(module);
|
||||
let branch = prefsrv.getDefaultBranch('extensions.' + preferencesBranch);
|
||||
|
||||
let { enable } = loader.require("sdk/preferences/native-options");
|
||||
|
||||
let addon_id = "test-bootstrap-addon@mozilla.com";
|
||||
let xpi_path = file.join(pathFor("ProfD"), addon_id + ".xpi");
|
||||
|
||||
// zip the add-on
|
||||
let zip = new ZipWriter(xpi_path);
|
||||
assert.pass("start creating the xpi");
|
||||
zip.addFile("", toFilename(fixtures.url("bootstrap-addon/"))).
|
||||
then(zip.close()).
|
||||
then(_ => install(xpi_path)).
|
||||
// get the addon
|
||||
then(id => {
|
||||
let { promise, resolve } = defer();
|
||||
AddonManager.getAddonByID(id, resolve);
|
||||
return promise;
|
||||
}).
|
||||
// insatll the add-on
|
||||
then(addon => {
|
||||
assert.pass('installed');
|
||||
|
||||
assert.pass('addon id: ' + addon.id);
|
||||
addon.userDisabled = false;
|
||||
assert.ok(!addon.userDisabled, 'the add-on is enabled');
|
||||
assert.ok(addon.isActive, 'the add-on is enabled');
|
||||
|
||||
// setup dynamic prefs
|
||||
return enable({
|
||||
id: addon.id,
|
||||
preferences: [{
|
||||
"name": "test",
|
||||
"description": "test",
|
||||
"title": "Test",
|
||||
"type": "string",
|
||||
"value": "default"
|
||||
}, {
|
||||
"name": "test-int",
|
||||
"description": "test",
|
||||
"type": "integer",
|
||||
"value": 5,
|
||||
"title": "How Many?"
|
||||
}]
|
||||
});
|
||||
}).
|
||||
then(args => {
|
||||
assert.pass('enabled');
|
||||
return args;
|
||||
}).
|
||||
// show inline prefs
|
||||
then(open).
|
||||
then(args => {
|
||||
assert.pass('opened');
|
||||
return args;
|
||||
}).
|
||||
// confirm dynamic pref generation did occur
|
||||
then(args => {
|
||||
let results = args.document.querySelectorAll("*[data-jetpack-id=\"" +args.id + "\"]");
|
||||
assert.ok(results.length > 0, "the prefs were setup");
|
||||
return args;
|
||||
}).
|
||||
// unload dynamic prefs
|
||||
then(args => {
|
||||
loader.unload();
|
||||
assert.pass('unload');
|
||||
return args;
|
||||
}).
|
||||
// hide and show the inline prefs
|
||||
then(({ tabId, id, document }) => {
|
||||
let { promise, resolve } = defer();
|
||||
let tab = Tab({ tab: getTabForId(tabId) });
|
||||
|
||||
tab.close(_ => resolve({ id: id }));
|
||||
|
||||
return promise;
|
||||
}).
|
||||
// reopen the add-on prefs page
|
||||
then(open).
|
||||
// confirm dynamic pref generation did not occur
|
||||
then(({ id, tabId, document }) => {
|
||||
let { promise, resolve } = defer();
|
||||
let tab = Tab({ tab: getTabForId(tabId) });
|
||||
|
||||
let results = document.querySelectorAll("*[data-jetpack-id=\"" + id + "\"]");
|
||||
assert.equal(0, results.length, "the prefs were not setup after unload");
|
||||
|
||||
tab.close(_ => resolve({ id: id }));
|
||||
|
||||
return promise;
|
||||
}).
|
||||
// uninstall the add-on
|
||||
then(({ id }) => uninstall(id)).
|
||||
// delete the pref branch
|
||||
then(_ => branch.deleteBranch('')).
|
||||
then(done, assert.fail);
|
||||
}
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
|
@ -1089,41 +1089,39 @@ exports.testSidebarLeakCheckUnloadAfterAttach = function(assert, done) {
|
||||
const loader = Loader(module);
|
||||
const { Sidebar } = loader.require('sdk/ui/sidebar');
|
||||
let testName = 'testSidebarLeakCheckUnloadAfterAttach';
|
||||
let window = getMostRecentBrowserWindow();
|
||||
let sidebar = Sidebar({
|
||||
id: testName,
|
||||
title: testName,
|
||||
url: 'data:text/html;charset=utf-8,'+testName
|
||||
});
|
||||
|
||||
sidebar.on('attach', function() {
|
||||
assert.pass('the sidebar was shown');
|
||||
open().then(focus).then(window => {
|
||||
sidebar.on('attach', function() {
|
||||
assert.pass('the sidebar was shown');
|
||||
|
||||
sidebar.on('show', function() {
|
||||
assert.fail('the sidebar show listener should have been removed');
|
||||
});
|
||||
assert.pass('added a sidebar show listener');
|
||||
sidebar.on('show', function() {
|
||||
assert.fail('the sidebar show listener should have been removed');
|
||||
});
|
||||
assert.pass('added a sidebar show listener');
|
||||
|
||||
sidebar.on('hide', function() {
|
||||
assert.fail('the sidebar hide listener should have been removed');
|
||||
});
|
||||
assert.pass('added a sidebar hide listener');
|
||||
sidebar.on('hide', function() {
|
||||
assert.fail('the sidebar hide listener should have been removed');
|
||||
});
|
||||
assert.pass('added a sidebar hide listener');
|
||||
|
||||
let panelBrowser = window.document.getElementById('sidebar').contentDocument.getElementById('web-panels-browser');
|
||||
panelBrowser.contentWindow.addEventListener('unload', function onUnload() {
|
||||
panelBrowser.contentWindow.removeEventListener('unload', onUnload, false);
|
||||
// wait a tick..
|
||||
setTimeout(function() {
|
||||
let panelBrowser = window.document.getElementById('sidebar').contentDocument.getElementById('web-panels-browser');
|
||||
panelBrowser.contentWindow.addEventListener('unload', function onUnload() {
|
||||
panelBrowser.contentWindow.removeEventListener('unload', onUnload, false);
|
||||
assert.pass('the sidebar web panel was unloaded properly');
|
||||
done();
|
||||
})
|
||||
}, false);
|
||||
close(window).then(done).catch(assert.fail);
|
||||
}, false);
|
||||
|
||||
loader.unload();
|
||||
});
|
||||
loader.unload();
|
||||
});
|
||||
|
||||
assert.pass('showing the sidebar');
|
||||
sidebar.show();
|
||||
assert.pass('showing the sidebar');
|
||||
sidebar.show();
|
||||
}).catch(assert.fail);
|
||||
}
|
||||
|
||||
exports.testTwoSidebarsWithSameTitleAndURL = function(assert) {
|
||||
|
125
addon-sdk/source/test/zip/utils.js
Normal file
125
addon-sdk/source/test/zip/utils.js
Normal file
@ -0,0 +1,125 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { Ci, Cc } = require("chrome");
|
||||
const { defer, all } = require("sdk/core/promise");
|
||||
|
||||
const PR_RDONLY = 0x01;
|
||||
const PR_WRONLY = 0x02;
|
||||
const PR_RDWR = 0x04;
|
||||
const PR_CREATE_FILE = 0x08;
|
||||
const PR_APPEND = 0x10;
|
||||
const PR_TRUNCATE = 0x20;
|
||||
const PR_SYNC = 0x40;
|
||||
const PR_EXCL = 0x80;
|
||||
|
||||
// Default compression level:
|
||||
const { COMPRESSION_DEFAULT } = Ci.nsIZipWriter;
|
||||
|
||||
function createNsFile(path) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
try {
|
||||
file.initWithPath(path);
|
||||
} catch(e) {
|
||||
throw new Error("This zip file path is not valid : " + path + "\n" + e);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
const converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
function streamForData(data) {
|
||||
return converter.convertToInputStream(data);
|
||||
}
|
||||
|
||||
exports.ZipWriter = function (zipPath, mode) {
|
||||
mode = mode ? mode : PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE;
|
||||
|
||||
let zw = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
|
||||
zw.open(createNsFile(zipPath), mode);
|
||||
|
||||
// Create a directory entry.
|
||||
// Returns true if the entry was created, or false if the entry already exists
|
||||
this.mkdir = function mkdir(pathInZip) {
|
||||
try {
|
||||
zw.addEntryDirectory(pathInZip, 0, false);
|
||||
}
|
||||
catch(e) {
|
||||
if (e.name === "NS_ERROR_FILE_ALREADY_EXISTS")
|
||||
return false;
|
||||
throw e
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
this.addFile = function addFile(pathInZip, filePath) {
|
||||
let { promise, reject, resolve } = defer();
|
||||
|
||||
let nsfile = createNsFile(filePath);
|
||||
if (!nsfile.exists()) {
|
||||
reject(new Error("This file doesn't exists : " + nsfile.path));
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Case 1/ Regular file
|
||||
if (!nsfile.isDirectory()) {
|
||||
try {
|
||||
zw.addEntryFile(pathInZip, COMPRESSION_DEFAULT, nsfile, false);
|
||||
resolve();
|
||||
}
|
||||
catch (e) {
|
||||
reject(new Error("Unable to add following file in zip: " + nsfile.path + "\n" + e));
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Case 2/ Directory
|
||||
if (pathInZip.substr(-1) !== '/')
|
||||
pathInZip += "/";
|
||||
let entries = nsfile.directoryEntries;
|
||||
let array = [];
|
||||
|
||||
zw.addEntryDirectory(pathInZip, nsfile.lastModifiedTime, false);
|
||||
|
||||
while(entries.hasMoreElements()) {
|
||||
let file = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
if (file.leafName === "." || file.leafName === "..")
|
||||
continue;
|
||||
let path = pathInZip + file.leafName;
|
||||
if (path.substr(0, 1) == '/') {
|
||||
path = path.substr(1);
|
||||
}
|
||||
this.addFile(path, file.path);
|
||||
}
|
||||
|
||||
resolve();
|
||||
return promise;
|
||||
}
|
||||
|
||||
this.addData = function (pathInZip, data) {
|
||||
let deferred = defer();
|
||||
|
||||
try {
|
||||
let stream = streamForData(data);
|
||||
zw.addEntryStream(pathInZip, 0, COMPRESSION_DEFAULT, stream, false);
|
||||
} catch(e) {
|
||||
throw new Error("Unable to add following data in zip: " +
|
||||
data.substr(0, 20) + "\n" + e);
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
this.close = function close() {
|
||||
let deferred = defer();
|
||||
|
||||
zw.close();
|
||||
|
||||
deferred.resolve();
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
@ -1239,7 +1239,9 @@ var gBrowserInit = {
|
||||
let mpEnabled = slot &&
|
||||
slot.status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED &&
|
||||
slot.status != Ci.nsIPKCS11Slot.SLOT_READY;
|
||||
Services.telemetry.getHistogramById("MASTER_PASSWORD_ENABLED").add(mpEnabled);
|
||||
if (mpEnabled) {
|
||||
Services.telemetry.getHistogramById("MASTER_PASSWORD_ENABLED").add(mpEnabled);
|
||||
}
|
||||
}, 5000);
|
||||
});
|
||||
this.delayedStartupFinished = true;
|
||||
@ -2090,10 +2092,23 @@ function BrowserViewSourceOfDocument(aDocument)
|
||||
// view-source to access the cached copy of the content rather than
|
||||
// refetching it from the network...
|
||||
//
|
||||
try{
|
||||
var PageLoader = webNav.QueryInterface(Components.interfaces.nsIWebPageDescriptor);
|
||||
try {
|
||||
|
||||
pageCookie = PageLoader.currentDescriptor;
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
// Workaround for bug 988133, which causes a crash if we attempt to load
|
||||
// the document from the cache when the document is a CPOW (which occurs
|
||||
// if we're using remote tabs). This causes us to reload the document from
|
||||
// the network in this case, so it's not a permanent solution, hence hiding
|
||||
// it behind the E10S_TESTING_ONLY ifdef. This is just a band-aid fix until
|
||||
// we can find something better - see bug 1025146.
|
||||
if (!Cu.isCrossProcessWrapper(aDocument)) {
|
||||
#endif
|
||||
var PageLoader = webNav.QueryInterface(Components.interfaces.nsIWebPageDescriptor);
|
||||
|
||||
pageCookie = PageLoader.currentDescriptor;
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
}
|
||||
#endif
|
||||
} catch(err) {
|
||||
// If no page descriptor is available, just use the view-source URL...
|
||||
}
|
||||
|
@ -29,6 +29,12 @@ add_task(function() {
|
||||
let newWin = yield openAndLoadWindow({}, true);
|
||||
|
||||
info("Waiting for panel in new window to open");
|
||||
let hideTrace = function() {
|
||||
info(new Error().stack);
|
||||
info("Panel was hidden.");
|
||||
};
|
||||
newWin.PanelUI.panel.addEventListener("popuphidden", hideTrace);
|
||||
|
||||
yield newWin.PanelUI.show();
|
||||
let newWinBookmarksToolbarPlaceholder = newWin.document.getElementById(buttonId);
|
||||
ok(newWinBookmarksToolbarPlaceholder.classList.contains("toolbarbutton-1"),
|
||||
@ -36,6 +42,7 @@ add_task(function() {
|
||||
is(newWinBookmarksToolbarPlaceholder.getAttribute("wrap"), "true",
|
||||
"Button in new window should have 'wrap' attribute");
|
||||
|
||||
newWin.PanelUI.panel.removeEventListener("popuphidden", hideTrace);
|
||||
//XXXgijs on Linux, we're sometimes seeing the panel being hidden early
|
||||
// in the newly created window, probably because something else steals focus.
|
||||
if (newWin.PanelUI.panel.state != "closed") {
|
||||
|
@ -15,6 +15,8 @@ const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const { CallWatcherFront } = require("devtools/server/actors/call-watcher");
|
||||
const { CanvasFront } = require("devtools/server/actors/canvas");
|
||||
const Telemetry = require("devtools/shared/telemetry");
|
||||
const telemetry = new Telemetry();
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
@ -119,6 +121,7 @@ let EventsHandler = {
|
||||
* Listen for events emitted by the current tab target.
|
||||
*/
|
||||
initialize: function() {
|
||||
telemetry.toolOpened("canvasdebugger");
|
||||
this._onTabNavigated = this._onTabNavigated.bind(this);
|
||||
gTarget.on("will-navigate", this._onTabNavigated);
|
||||
gTarget.on("navigate", this._onTabNavigated);
|
||||
@ -128,6 +131,7 @@ let EventsHandler = {
|
||||
* Remove events emitted by the current tab target.
|
||||
*/
|
||||
destroy: function() {
|
||||
telemetry.toolClosed("canvasdebugger");
|
||||
gTarget.off("will-navigate", this._onTabNavigated);
|
||||
gTarget.off("navigate", this._onTabNavigated);
|
||||
},
|
||||
|
@ -20,36 +20,74 @@ let test = asyncTest(function*() {
|
||||
|
||||
let usage = yield csscoverage.getUsage(options.target);
|
||||
|
||||
yield usage.oneshot();
|
||||
yield navigate(usage, options);
|
||||
yield checkPages(usage);
|
||||
yield checkEditorReport(usage);
|
||||
yield checkPageReport(usage);
|
||||
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
});
|
||||
|
||||
/**
|
||||
* Just check current page
|
||||
*/
|
||||
function* navigate(usage, options) {
|
||||
let running = yield usage._testOnly_isRunning();
|
||||
ok(!running, "csscoverage not is running");
|
||||
|
||||
yield usage.oneshot();
|
||||
|
||||
running = yield usage._testOnly_isRunning();
|
||||
ok(!running, "csscoverage not is running");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the expected pages have been visited
|
||||
*/
|
||||
function* checkPages(usage) {
|
||||
let expectedVisited = [ PAGE_3 ];
|
||||
let actualVisited = yield usage._testOnly_visitedPages();
|
||||
isEqualJson(actualVisited, expectedVisited, 'Visited');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that createEditorReport returns the expected JSON
|
||||
*/
|
||||
function* checkEditorReport(usage) {
|
||||
// Page1
|
||||
let expectedPage1 = { reports: [] };
|
||||
let actualPage1 = yield usage.createEditorReport(PAGE_1);
|
||||
let actualPage1 = yield usage.createEditorReport(PAGE_1 + " \u2192 <style> index 0");
|
||||
isEqualJson(actualPage1, expectedPage1, 'Page1');
|
||||
|
||||
// Page2
|
||||
let expectedPage2 = { reports: [] };
|
||||
let actualPage2 = yield usage.createEditorReport(PAGE_2);
|
||||
let actualPage2 = yield usage.createEditorReport(PAGE_2 + " \u2192 <style> index 0");
|
||||
isEqualJson(actualPage2, expectedPage2, 'Page2');
|
||||
|
||||
// Page3
|
||||
let expectedPage3 = {
|
||||
// Page3a
|
||||
let expectedPage3a = {
|
||||
reports: [
|
||||
{
|
||||
selectorText: ".page3-test2",
|
||||
start: { line: 9, column: 5 },
|
||||
},
|
||||
}
|
||||
]
|
||||
};
|
||||
let actualPage3a = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 0");
|
||||
isEqualJson(actualPage3a, expectedPage3a, 'Page3a');
|
||||
|
||||
// Page3b
|
||||
let expectedPage3b = {
|
||||
reports: [
|
||||
{
|
||||
selectorText: ".page3-test3",
|
||||
start: { line: 3, column: 5 },
|
||||
}
|
||||
]
|
||||
};
|
||||
let actualPage3 = yield usage.createEditorReport(PAGE_3);
|
||||
isEqualJson(actualPage3, expectedPage3, 'Page3');
|
||||
let actualPage3b = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 1");
|
||||
isEqualJson(actualPage3b, expectedPage3b, 'Page3b');
|
||||
|
||||
// SheetA
|
||||
let expectedSheetA = {
|
||||
@ -130,11 +168,148 @@ let test = asyncTest(function*() {
|
||||
};
|
||||
let actualSheetD = yield usage.createEditorReport(SHEET_D);
|
||||
isEqualJson(actualSheetD, expectedSheetD, 'SheetD');
|
||||
}
|
||||
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
});
|
||||
/**
|
||||
* Check that checkPageReport returns the expected JSON
|
||||
*/
|
||||
function* checkPageReport(usage) {
|
||||
let actualReport = yield usage.createPageReport();
|
||||
|
||||
// Quick check on trivial things. See doc comment for checkRuleProperties
|
||||
actualReport.preload.forEach(page => page.rules.forEach(checkRuleProperties));
|
||||
actualReport.unused.forEach(page => page.rules.forEach(checkRuleProperties));
|
||||
|
||||
// Check the summary
|
||||
let expectedSummary = { "used": 23, "unused": 9, "preload": 0 };
|
||||
isEqualJson(actualReport.summary, expectedSummary, 'summary');
|
||||
|
||||
// Check the preload header
|
||||
isEqualJson(actualReport.preload.length, 0, 'preload length');
|
||||
|
||||
// Check the unused header
|
||||
isEqualJson(actualReport.unused.length, 6, 'unused length');
|
||||
|
||||
// Check the unused rules
|
||||
isEqualJson(actualReport.unused[0].url, PAGE_3 + " \u2192 <style> index 0", "unused url 0");
|
||||
let expectedUnusedRules0 = [
|
||||
{
|
||||
"url": PAGE_3 + " \u2192 <style> index 0",
|
||||
"start": { "line": 9, "column": 5 },
|
||||
"selectorText": ".page3-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[0].rules, expectedUnusedRules0, 'unused rules 0');
|
||||
|
||||
isEqualJson(actualReport.unused[1].url, PAGE_3 + " \u2192 <style> index 1", "unused url 1");
|
||||
let expectedUnusedRules1 = [
|
||||
{
|
||||
"url": PAGE_3 + " \u2192 <style> index 1",
|
||||
"start": { "line": 3, "column": 5 },
|
||||
"selectorText": ".page3-test3"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[1].rules, expectedUnusedRules1, 'unused rules 1');
|
||||
|
||||
isEqualJson(actualReport.unused[2].url, SHEET_A, "unused url 2");
|
||||
let expectedUnusedRules2 = [
|
||||
{
|
||||
"url": SHEET_A,
|
||||
"start": { "line": 8, "column": 1 },
|
||||
"selectorText": ".sheetA-test2"
|
||||
},
|
||||
{
|
||||
"url": SHEET_A,
|
||||
"start": { "line": 12, "column": 1 },
|
||||
"selectorText": ".sheetA-test3"
|
||||
},
|
||||
{
|
||||
"url": SHEET_A,
|
||||
"start": { "line": 16, "column": 1 },
|
||||
"selectorText": ".sheetA-test4"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[2].rules, expectedUnusedRules2, 'unused rules 2');
|
||||
|
||||
isEqualJson(actualReport.unused[3].url, SHEET_B, "unused url 3");
|
||||
let expectedUnusedRules3 = [
|
||||
{
|
||||
"url": SHEET_B,
|
||||
"start": { "line": 6, "column": 1 },
|
||||
"selectorText": ".sheetB-test2"
|
||||
},
|
||||
{
|
||||
"url": SHEET_B,
|
||||
"start": { "line": 10, "column": 1 },
|
||||
"selectorText": ".sheetB-test3"
|
||||
},
|
||||
{
|
||||
"url": SHEET_B,
|
||||
"start": { "line": 14, "column": 1 },
|
||||
"selectorText": ".sheetB-test4"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[3].rules, expectedUnusedRules3, 'unused rules 3');
|
||||
|
||||
isEqualJson(actualReport.unused[4].url, SHEET_D, "unused url 4");
|
||||
let expectedUnusedRules4 = [
|
||||
{
|
||||
"url": SHEET_D,
|
||||
"start": { "line": 6, "column": 1 },
|
||||
"selectorText": ".sheetD-test2"
|
||||
},
|
||||
{
|
||||
"url": SHEET_D,
|
||||
"start": { "line": 10, "column": 1 },
|
||||
"selectorText": ".sheetD-test3"
|
||||
},
|
||||
{
|
||||
"url": SHEET_D,
|
||||
"start": { "line": 14, "column": 1 },
|
||||
"selectorText": ".sheetD-test4"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[4].rules, expectedUnusedRules4, 'unused rules 4');
|
||||
|
||||
isEqualJson(actualReport.unused[5].url, SHEET_C, "unused url 5");
|
||||
let expectedUnusedRules5 = [
|
||||
{
|
||||
"url": SHEET_C,
|
||||
"start": { "line": 6, "column": 1 },
|
||||
"selectorText": ".sheetC-test2"
|
||||
},
|
||||
{
|
||||
"url": SHEET_C,
|
||||
"start": { "line": 10, "column": 1 },
|
||||
"selectorText": ".sheetC-test3"
|
||||
},
|
||||
{
|
||||
"url": SHEET_C,
|
||||
"start": { "line": 14, "column": 1 },
|
||||
"selectorText": ".sheetC-test4"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[5].rules, expectedUnusedRules5, 'unused rules 5');
|
||||
}
|
||||
|
||||
/**
|
||||
* We do basic tests on the shortUrl and formattedCssText because they are
|
||||
* very derivative, and so make for fragile tests, and having done those quick
|
||||
* existence checks we remove them so the JSON check later can ignore them
|
||||
*/
|
||||
function checkRuleProperties(rule, index) {
|
||||
is(typeof rule.shortUrl, "string", "typeof rule.shortUrl for " + index);
|
||||
is(rule.shortUrl.indexOf("http://"), -1, "http not in rule.shortUrl for" + index);
|
||||
delete rule.shortUrl;
|
||||
|
||||
is(typeof rule.formattedCssText, "string", "typeof rule.formattedCssText for " + index);
|
||||
ok(rule.formattedCssText.indexOf("{") > 0, "{ in rule.formattedCssText for " + index);
|
||||
delete rule.formattedCssText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to compare JSON structures
|
||||
*/
|
||||
function isEqualJson(o1, o2, msg) {
|
||||
is(JSON.stringify(o1), JSON.stringify(o2), msg);
|
||||
}
|
||||
|
@ -42,11 +42,13 @@
|
||||
/* How quickly do we rush through this? */
|
||||
let delay = 500;
|
||||
window.addEventListener("load", () => {
|
||||
dump('TEST-INFO | load from browser_cmd_csscoverage_page1.html\n');
|
||||
setTimeout(() => {
|
||||
dump('TEST-INFO | timeout from browser_cmd_csscoverage_page1.html\n');
|
||||
/* This adds <div class=page1-test5></div> */
|
||||
let parent = document.querySelector("#page1-test5-holder");
|
||||
let child = document.createElement("div");
|
||||
child.classList.add("class=page1-test5");
|
||||
child.classList.add("page1-test5");
|
||||
parent.appendChild(child);
|
||||
|
||||
/* Then navigate to the next step */
|
||||
|
@ -26,11 +26,13 @@
|
||||
/* How quickly do we rush through this? */
|
||||
let delay = 500;
|
||||
window.addEventListener("load", () => {
|
||||
dump('TEST-INFO | load from browser_cmd_csscoverage_page2.html\n');
|
||||
setTimeout(() => {
|
||||
dump('TEST-INFO | timeout from browser_cmd_csscoverage_page2.html\n');
|
||||
/* This adds <div class=page2-test3></div> */
|
||||
let parent = document.querySelector("#page2-test3-holder");
|
||||
let child = document.createElement("div");
|
||||
child.classList.add("class=page2-test3");
|
||||
child.classList.add("page2-test3");
|
||||
parent.appendChild(child);
|
||||
}, delay);
|
||||
});
|
||||
@ -41,7 +43,6 @@
|
||||
<h2>Page 2</h2>
|
||||
|
||||
<div class=page2-test1>.page2-test1</div>
|
||||
<div class=page2-test3>.page2-test3</div>
|
||||
|
||||
<div id=page2-test3-holder></div>
|
||||
|
||||
|
@ -23,6 +23,11 @@
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetA.css">
|
||||
<link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetB.css">
|
||||
<script type="application/javascript;version=1.8">
|
||||
window.addEventListener("load", () => {
|
||||
dump('TEST-INFO | load from browser_cmd_csscoverage_page3.html\n');
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
@ -20,43 +20,100 @@ let test = asyncTest(function*() {
|
||||
|
||||
let usage = yield csscoverage.getUsage(options.target);
|
||||
|
||||
yield navigate(usage, options);
|
||||
yield checkPages(usage);
|
||||
yield checkEditorReport(usage);
|
||||
yield checkPageReport(usage);
|
||||
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
});
|
||||
|
||||
/**
|
||||
* Visit all the pages in the test
|
||||
*/
|
||||
function* navigate(usage, options) {
|
||||
yield usage.start();
|
||||
|
||||
let running = yield usage._testOnly_isRunning();
|
||||
ok(running, "csscoverage is running");
|
||||
|
||||
yield helpers.navigate(PAGE_3, options);
|
||||
yield helpers.navigate(PAGE_1, options);
|
||||
|
||||
// Wait for the test pages to auto-cycle
|
||||
let ev = yield helpers.listenOnce(options.browser, "load", true);
|
||||
is(ev.target.location.href, PAGE_1, "page 1 loaded");
|
||||
|
||||
ev = yield helpers.listenOnce(options.browser, "load", true);
|
||||
is(ev.target.location.href, PAGE_3, "page 3 loaded");
|
||||
|
||||
yield usage.stop();
|
||||
|
||||
running = yield usage._testOnly_isRunning();
|
||||
ok(!running, "csscoverage not is running");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the expected pages have been visited
|
||||
*/
|
||||
function* checkPages(usage) {
|
||||
// 'load' event order. '' is for the initial location
|
||||
let expectedVisited = [ '', PAGE_2, PAGE_1, PAGE_3 ];
|
||||
let actualVisited = yield usage._testOnly_visitedPages();
|
||||
isEqualJson(actualVisited, expectedVisited, 'Visited');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that createEditorReport returns the expected JSON
|
||||
*/
|
||||
function* checkEditorReport(usage) {
|
||||
// Page1
|
||||
let expectedPage1 = { reports: [] };
|
||||
let actualPage1 = yield usage.createEditorReport(PAGE_1);
|
||||
let expectedPage1 = {
|
||||
reports: [
|
||||
{
|
||||
selectorText: ".page1-test2",
|
||||
start: { line: 8, column: 5 },
|
||||
}
|
||||
]
|
||||
};
|
||||
let actualPage1 = yield usage.createEditorReport(PAGE_1 + " \u2192 <style> index 0");
|
||||
isEqualJson(actualPage1, expectedPage1, 'Page1');
|
||||
|
||||
// Page2
|
||||
let expectedPage2 = { reports: [] };
|
||||
let actualPage2 = yield usage.createEditorReport(PAGE_2);
|
||||
let expectedPage2 = {
|
||||
reports: [
|
||||
{
|
||||
selectorText: ".page2-test2",
|
||||
start: { line: 9, column: 5 },
|
||||
},
|
||||
]
|
||||
};
|
||||
let actualPage2 = yield usage.createEditorReport(PAGE_2 + " \u2192 <style> index 0");
|
||||
isEqualJson(actualPage2, expectedPage2, 'Page2');
|
||||
|
||||
// Page3
|
||||
let expectedPage3 = {
|
||||
// Page3a
|
||||
let expectedPage3a = {
|
||||
reports: [
|
||||
{
|
||||
selectorText: ".page3-test2",
|
||||
start: { line: 9, column: 5 },
|
||||
},
|
||||
}
|
||||
]
|
||||
};
|
||||
let actualPage3a = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 0");
|
||||
isEqualJson(actualPage3a, expectedPage3a, 'Page3a');
|
||||
|
||||
// Page3b
|
||||
let expectedPage3b = {
|
||||
reports: [
|
||||
{
|
||||
selectorText: ".page3-test3",
|
||||
start: { line: 3, column: 5 },
|
||||
}
|
||||
]
|
||||
};
|
||||
let actualPage3 = yield usage.createEditorReport(PAGE_3);
|
||||
isEqualJson(actualPage3, expectedPage3, 'Page3');
|
||||
let actualPage3b = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 1");
|
||||
isEqualJson(actualPage3b, expectedPage3b, 'Page3b');
|
||||
|
||||
// SheetA
|
||||
let expectedSheetA = {
|
||||
@ -64,14 +121,6 @@ let test = asyncTest(function*() {
|
||||
{
|
||||
selectorText: ".sheetA-test2",
|
||||
start: { line: 8, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetA-test3",
|
||||
start: { line: 12, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetA-test4",
|
||||
start: { line: 16, column: 1 },
|
||||
}
|
||||
]
|
||||
};
|
||||
@ -84,14 +133,6 @@ let test = asyncTest(function*() {
|
||||
{
|
||||
selectorText: ".sheetB-test2",
|
||||
start: { line: 6, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetB-test3",
|
||||
start: { line: 10, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetB-test4",
|
||||
start: { line: 14, column: 1 },
|
||||
}
|
||||
]
|
||||
};
|
||||
@ -104,14 +145,6 @@ let test = asyncTest(function*() {
|
||||
{
|
||||
selectorText: ".sheetC-test2",
|
||||
start: { line: 6, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetC-test3",
|
||||
start: { line: 10, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetC-test4",
|
||||
start: { line: 14, column: 1 },
|
||||
}
|
||||
]
|
||||
};
|
||||
@ -124,24 +157,303 @@ let test = asyncTest(function*() {
|
||||
{
|
||||
selectorText: ".sheetD-test2",
|
||||
start: { line: 6, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetD-test3",
|
||||
start: { line: 10, column: 1 },
|
||||
},
|
||||
{
|
||||
selectorText: ".sheetD-test4",
|
||||
start: { line: 14, column: 1 },
|
||||
}
|
||||
]
|
||||
};
|
||||
let actualSheetD = yield usage.createEditorReport(SHEET_D);
|
||||
isEqualJson(actualSheetD, expectedSheetD, 'SheetD');
|
||||
}
|
||||
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
});
|
||||
/**
|
||||
* Check that checkPageReport returns the expected JSON
|
||||
*/
|
||||
function* checkPageReport(usage) {
|
||||
let actualReport = yield usage.createPageReport();
|
||||
|
||||
// Quick check on trivial things. See doc comment for checkRuleProperties
|
||||
actualReport.preload.forEach(page => page.rules.forEach(checkRuleProperties));
|
||||
actualReport.unused.forEach(page => page.rules.forEach(checkRuleProperties));
|
||||
|
||||
// Check the summary
|
||||
let expectedSummary = { "used": 92, "unused": 22, "preload": 28 };
|
||||
isEqualJson(actualReport.summary, expectedSummary, 'summary');
|
||||
|
||||
checkPageReportPreload(actualReport);
|
||||
checkPageReportUnused(actualReport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that checkPageReport returns the expected preload JSON
|
||||
*/
|
||||
function checkPageReportPreload(actualReport) {
|
||||
// Check the preload header
|
||||
isEqualJson(actualReport.preload.length, 3, 'preload length');
|
||||
|
||||
// Check the preload rules
|
||||
isEqualJson(actualReport.preload[0].url, PAGE_2, 'preload url 0');
|
||||
let expectedPreloadRules0 = [
|
||||
// TODO: This is already pre-loaded, we should note this
|
||||
{
|
||||
url: PAGE_2 + " \u2192 <style> index 0",
|
||||
start: { line: 5, column: 5 },
|
||||
selectorText: ".page2-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_A,
|
||||
start: { line: 4, column: 1 },
|
||||
selectorText: ".sheetA-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_A,
|
||||
start: { line: 16, column: 1 },
|
||||
selectorText: ".sheetA-test4"
|
||||
},
|
||||
{
|
||||
url: SHEET_B,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetB-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_B,
|
||||
start: { line: 14, column: 1 },
|
||||
selectorText: ".sheetB-test4"
|
||||
},
|
||||
{
|
||||
url: SHEET_D,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetD-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_D,
|
||||
start: { line: 14, column: 1 },
|
||||
selectorText: ".sheetD-test4"
|
||||
},
|
||||
{
|
||||
url: SHEET_C,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetC-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_C,
|
||||
start: { line: 14, column: 1 },
|
||||
selectorText: ".sheetC-test4"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.preload[0].rules, expectedPreloadRules0, 'preload rules 0');
|
||||
|
||||
isEqualJson(actualReport.preload[1].url, PAGE_1, 'preload url 1');
|
||||
let expectedPreloadRules1 = [
|
||||
{
|
||||
url: SHEET_A,
|
||||
start: { line: 4, column: 1 },
|
||||
selectorText: ".sheetA-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_A,
|
||||
start: { line: 12, column: 1 },
|
||||
selectorText: ".sheetA-test3"
|
||||
},
|
||||
{
|
||||
url: SHEET_B,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetB-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_B,
|
||||
start: { line: 10, column: 1 },
|
||||
selectorText: ".sheetB-test3"
|
||||
},
|
||||
{
|
||||
url: SHEET_D,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetD-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_D,
|
||||
start: { line: 10, column: 1 },
|
||||
selectorText: ".sheetD-test3"
|
||||
},
|
||||
{
|
||||
url: SHEET_C,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetC-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_C,
|
||||
start: { line: 10, column: 1 },
|
||||
selectorText: ".sheetC-test3"
|
||||
},
|
||||
{
|
||||
url: PAGE_1 + " \u2192 <style> index 0",
|
||||
start: { line: 4, column: 5 },
|
||||
selectorText: ".page1-test1"
|
||||
},
|
||||
{
|
||||
url: PAGE_1 + " \u2192 <style> index 0",
|
||||
start: { line: 12, column: 5 },
|
||||
selectorText: ".page1-test3:hover"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.preload[1].rules, expectedPreloadRules1, 'preload rules 1');
|
||||
|
||||
isEqualJson(actualReport.preload[2].url, PAGE_3, 'preload url 2');
|
||||
let expectedPreloadRules2 = [
|
||||
{
|
||||
url: SHEET_A,
|
||||
start: { line: 4, column: 1 },
|
||||
selectorText: ".sheetA-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_A,
|
||||
start: { line: 20, column: 1 },
|
||||
selectorText: ".sheetA-test5"
|
||||
},
|
||||
{
|
||||
url: SHEET_B,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetB-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_B,
|
||||
start: { line: 18, column: 1 },
|
||||
selectorText: ".sheetB-test5"
|
||||
},
|
||||
{
|
||||
url: SHEET_D,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetD-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_D,
|
||||
start: { line: 18, column: 1 },
|
||||
selectorText: ".sheetD-test5"
|
||||
},
|
||||
{
|
||||
url: SHEET_C,
|
||||
start: { line: 2, column: 1 },
|
||||
selectorText: ".sheetC-test1"
|
||||
},
|
||||
{
|
||||
url: SHEET_C,
|
||||
start: { line: 18, column: 1 },
|
||||
selectorText: ".sheetC-test5"
|
||||
},
|
||||
{
|
||||
url: PAGE_3 + " \u2192 <style> index 0",
|
||||
start: { line: 5, column: 5 },
|
||||
selectorText: ".page3-test1"
|
||||
},
|
||||
];
|
||||
isEqualJson(actualReport.preload[2].rules, expectedPreloadRules2, 'preload rules 2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that checkPageReport returns the expected unused JSON
|
||||
*/
|
||||
function checkPageReportUnused(actualReport) {
|
||||
// Check the unused header
|
||||
isEqualJson(actualReport.unused.length, 8, 'unused length');
|
||||
|
||||
// Check the unused rules
|
||||
isEqualJson(actualReport.unused[0].url, PAGE_2 + " \u2192 <style> index 0", "unused url 0");
|
||||
let expectedUnusedRules0 = [
|
||||
{
|
||||
url: PAGE_2 + " \u2192 <style> index 0",
|
||||
start: { line: 9, column: 5 },
|
||||
selectorText: ".page2-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[0].rules, expectedUnusedRules0, 'unused rules 0');
|
||||
|
||||
isEqualJson(actualReport.unused[1].url, SHEET_A, "unused url 1");
|
||||
let expectedUnusedRules1 = [
|
||||
{
|
||||
url: SHEET_A,
|
||||
start: { line: 8, column: 1 },
|
||||
selectorText: ".sheetA-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[1].rules, expectedUnusedRules1, 'unused rules 1');
|
||||
|
||||
isEqualJson(actualReport.unused[2].url, SHEET_B, "unused url 2");
|
||||
let expectedUnusedRules2 = [
|
||||
{
|
||||
url: SHEET_B,
|
||||
start: { line: 6, column: 1 },
|
||||
selectorText: ".sheetB-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[2].rules, expectedUnusedRules2, 'unused rules 2');
|
||||
|
||||
isEqualJson(actualReport.unused[3].url, SHEET_D, "unused url 3");
|
||||
let expectedUnusedRules3 = [
|
||||
{
|
||||
url: SHEET_D,
|
||||
start: { line: 6, column: 1 },
|
||||
selectorText: ".sheetD-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[3].rules, expectedUnusedRules3, 'unused rules 3');
|
||||
|
||||
isEqualJson(actualReport.unused[4].url, SHEET_C, "unused url 4");
|
||||
let expectedUnusedRules4 = [
|
||||
{
|
||||
url: SHEET_C,
|
||||
start: { line: 6, column: 1 },
|
||||
selectorText: ".sheetC-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[4].rules, expectedUnusedRules4, 'unused rules 4');
|
||||
|
||||
isEqualJson(actualReport.unused[5].url, PAGE_1 + " \u2192 <style> index 0", "unused url 5");
|
||||
let expectedUnusedRules5 = [
|
||||
{
|
||||
url: PAGE_1 + " \u2192 <style> index 0",
|
||||
start: { line: 8, column: 5 },
|
||||
selectorText: ".page1-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[5].rules, expectedUnusedRules5, 'unused rules 5');
|
||||
|
||||
isEqualJson(actualReport.unused[6].url, PAGE_3 + " \u2192 <style> index 0", "unused url 6");
|
||||
let expectedUnusedRules6 = [
|
||||
{
|
||||
url: PAGE_3 + " \u2192 <style> index 0",
|
||||
start: { line: 9, column: 5 },
|
||||
selectorText: ".page3-test2"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[6].rules, expectedUnusedRules6, 'unused rules 6');
|
||||
|
||||
isEqualJson(actualReport.unused[7].url, PAGE_3 + " \u2192 <style> index 1", "unused url 7");
|
||||
let expectedUnusedRules7 = [
|
||||
{
|
||||
url: PAGE_3 + " \u2192 <style> index 1",
|
||||
start: { line: 3, column: 5 },
|
||||
selectorText: ".page3-test3"
|
||||
}
|
||||
];
|
||||
isEqualJson(actualReport.unused[7].rules, expectedUnusedRules7, 'unused rules 7');
|
||||
}
|
||||
|
||||
/**
|
||||
* We do basic tests on the shortUrl and formattedCssText because they are
|
||||
* very derivative, and so make for fragile tests, and having done those quick
|
||||
* existence checks we remove them so the JSON check later can ignore them
|
||||
*/
|
||||
function checkRuleProperties(rule, index) {
|
||||
is(typeof rule.shortUrl, "string", "typeof rule.shortUrl for " + index);
|
||||
is(rule.shortUrl.indexOf("http://"), -1, "http not in rule.shortUrl for" + index);
|
||||
delete rule.shortUrl;
|
||||
|
||||
is(typeof rule.formattedCssText, "string", "typeof rule.formattedCssText for " + index);
|
||||
ok(rule.formattedCssText.indexOf("{") > 0, "{ in rule.formattedCssText for " + index);
|
||||
delete rule.formattedCssText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to compare JSON structures
|
||||
*/
|
||||
function isEqualJson(o1, o2, msg) {
|
||||
is(JSON.stringify(o1), JSON.stringify(o2), msg);
|
||||
}
|
||||
|
@ -489,9 +489,9 @@ helpers._actual = {
|
||||
},
|
||||
|
||||
unassigned: function(options) {
|
||||
return options.requisition._unassigned.map(function(assignment) {
|
||||
return options.requisition._unassigned.map(assignment => {
|
||||
return assignment.arg.toString();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
outputState: function(options) {
|
||||
@ -540,7 +540,7 @@ helpers._createDebugCheck = function(options) {
|
||||
var hintsPromise = helpers._actual.hints(options);
|
||||
var predictionsPromise = helpers._actual.predictions(options);
|
||||
|
||||
return Promise.all(hintsPromise, predictionsPromise).then(function(values) {
|
||||
return Promise.all(hintsPromise, predictionsPromise).then((values) => {
|
||||
var hints = values[0];
|
||||
var predictions = values[1];
|
||||
var output = '';
|
||||
@ -610,7 +610,7 @@ helpers._createDebugCheck = function(options) {
|
||||
output += ']);';
|
||||
|
||||
return output;
|
||||
}.bind(this), util.errorHandler);
|
||||
}, util.errorHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -933,7 +933,7 @@ helpers._exec = function(options, name, expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
return requisition.exec({ hidden: true }).then(function(output) {
|
||||
return requisition.exec({ hidden: true }).then((output) => {
|
||||
if ('type' in expected) {
|
||||
assert.is(output.type,
|
||||
expected.type,
|
||||
@ -993,7 +993,7 @@ helpers._exec = function(options, name, expected) {
|
||||
}
|
||||
return { output: output, text: textOutput };
|
||||
});
|
||||
}.bind(this)).then(function(data) {
|
||||
}).then(function(data) {
|
||||
if (expected.error) {
|
||||
cli.logErrors = origLogErrors;
|
||||
}
|
||||
|
@ -273,25 +273,25 @@ DevTools.prototype = {
|
||||
|
||||
this._toolboxes.set(target, toolbox);
|
||||
|
||||
toolbox.once("destroyed", function() {
|
||||
toolbox.once("destroyed", () => {
|
||||
this._toolboxes.delete(target);
|
||||
this.emit("toolbox-destroyed", target);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
// If we were asked for a specific tool then we need to wait for the
|
||||
// tool to be ready, otherwise we can just wait for toolbox open
|
||||
if (toolId != null) {
|
||||
toolbox.once(toolId + "-ready", function(event, panel) {
|
||||
toolbox.once(toolId + "-ready", (event, panel) => {
|
||||
this.emit("toolbox-ready", toolbox);
|
||||
deferred.resolve(toolbox);
|
||||
}.bind(this));
|
||||
});
|
||||
toolbox.open();
|
||||
}
|
||||
else {
|
||||
toolbox.open().then(function() {
|
||||
toolbox.open().then(() => {
|
||||
deferred.resolve(toolbox);
|
||||
this.emit("toolbox-ready", toolbox);
|
||||
}.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,14 +71,14 @@ ToolSidebar.prototype = {
|
||||
let tab = this._tabbox.tabs.appendItem();
|
||||
tab.setAttribute("label", ""); // Avoid showing "undefined" while the tab is loading
|
||||
|
||||
let onIFrameLoaded = function() {
|
||||
let onIFrameLoaded = () => {
|
||||
tab.setAttribute("label", iframe.contentDocument.title);
|
||||
iframe.removeEventListener("load", onIFrameLoaded, true);
|
||||
if ("setPanel" in iframe.contentWindow) {
|
||||
iframe.contentWindow.setPanel(this._toolPanel, iframe);
|
||||
}
|
||||
this.emit(id + "-ready");
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
iframe.addEventListener("load", onIFrameLoaded, true);
|
||||
|
||||
@ -101,9 +101,9 @@ ToolSidebar.prototype = {
|
||||
// For some reason I don't understand, if we call this.select in this
|
||||
// event loop (after inserting the tab), the tab will never get the
|
||||
// the "selected" attribute set to true.
|
||||
this._panelDoc.defaultView.setTimeout(function() {
|
||||
this._panelDoc.defaultView.setTimeout(() => {
|
||||
this.select(id);
|
||||
}.bind(this), 10);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
this.emit("new-tab-registered", id);
|
||||
|
@ -365,7 +365,7 @@ TabTarget.prototype = {
|
||||
};
|
||||
this.client.addListener("tabDetached", this._onTabDetached);
|
||||
|
||||
this._onTabNavigated = function onRemoteTabNavigated(aType, aPacket) {
|
||||
this._onTabNavigated = (aType, aPacket) => {
|
||||
let event = Object.create(null);
|
||||
event.url = aPacket.url;
|
||||
event.title = aPacket.title;
|
||||
@ -381,7 +381,7 @@ TabTarget.prototype = {
|
||||
this.emit("navigate", event);
|
||||
this._navWindow = null;
|
||||
}
|
||||
}.bind(this);
|
||||
};
|
||||
this.client.addListener("tabNavigated", this._onTabNavigated);
|
||||
},
|
||||
|
||||
|
@ -122,11 +122,11 @@ DevToolPanel.prototype = {
|
||||
open: function() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
executeSoon(function() {
|
||||
executeSoon(() => {
|
||||
this._isReady = true;
|
||||
this.emit("ready");
|
||||
deferred.resolve(this);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
@ -48,7 +48,7 @@ function selectAndCheckById(id) {
|
||||
}
|
||||
|
||||
function testToggle() {
|
||||
toolbox.once("destroyed", function() {
|
||||
toolbox.once("destroyed", () => {
|
||||
// Cannot reuse a target after it's destroyed.
|
||||
target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, "styleeditor").then(function(aToolbox) {
|
||||
@ -58,7 +58,7 @@ function testToggle() {
|
||||
finishUp();
|
||||
});
|
||||
});
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
toolbox.destroy();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ function test() {
|
||||
isTargetSupported: function() true,
|
||||
build: function(iframeWindow, toolbox) {
|
||||
let deferred = promise.defer();
|
||||
executeSoon(function() {
|
||||
executeSoon(() => {
|
||||
deferred.resolve({
|
||||
target: toolbox.target,
|
||||
toolbox: toolbox,
|
||||
@ -38,7 +38,7 @@ function test() {
|
||||
destroy: function(){},
|
||||
panelDoc: iframeWindow.document,
|
||||
});
|
||||
}.bind(this));
|
||||
});
|
||||
return deferred.promise;
|
||||
},
|
||||
};
|
||||
|
@ -60,10 +60,10 @@ BottomHost.prototype = {
|
||||
this._nbox.appendChild(this._splitter);
|
||||
this._nbox.appendChild(this.frame);
|
||||
|
||||
let frameLoad = function() {
|
||||
let frameLoad = () => {
|
||||
this.emit("ready", this.frame);
|
||||
deferred.resolve(this.frame);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
this.frame.tooltip = "aHTMLTooltip";
|
||||
|
||||
@ -143,10 +143,10 @@ SidebarHost.prototype = {
|
||||
this._sidebar.appendChild(this._splitter);
|
||||
this._sidebar.appendChild(this.frame);
|
||||
|
||||
let frameLoad = function() {
|
||||
let frameLoad = () => {
|
||||
this.emit("ready", this.frame);
|
||||
deferred.resolve(this.frame);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
this.frame.tooltip = "aHTMLTooltip";
|
||||
this.frame.setAttribute("src", "about:blank");
|
||||
@ -213,14 +213,14 @@ WindowHost.prototype = {
|
||||
let win = Services.ww.openWindow(null, this.WINDOW_URL, "_blank",
|
||||
flags, null);
|
||||
|
||||
let frameLoad = function(event) {
|
||||
let frameLoad = (event) => {
|
||||
win.removeEventListener("load", frameLoad, true);
|
||||
win.focus();
|
||||
this.frame = win.document.getElementById("toolbox-iframe");
|
||||
this.emit("ready", this.frame);
|
||||
|
||||
deferred.resolve(this.frame);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
win.addEventListener("load", frameLoad, true);
|
||||
win.addEventListener("unload", this._boundUnload);
|
||||
|
@ -101,12 +101,12 @@ HTMLBreadcrumbs.prototype = {
|
||||
this.container._scrollButtonUp.collapsed = true;
|
||||
this.container._scrollButtonDown.collapsed = true;
|
||||
|
||||
this.onscrollboxreflow = function() {
|
||||
this.onscrollboxreflow = () => {
|
||||
if (this.container._scrollButtonDown.collapsed)
|
||||
this.container.removeAttribute("overflows");
|
||||
else
|
||||
this.container.setAttribute("overflows", true);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
this.container.addEventListener("underflow", this.onscrollboxreflow, false);
|
||||
this.container.addEventListener("overflow", this.onscrollboxreflow, false);
|
||||
@ -480,9 +480,9 @@ HTMLBreadcrumbs.prototype = {
|
||||
button.click();
|
||||
}
|
||||
|
||||
button.onBreadcrumbsClick = function onBreadcrumbsClick() {
|
||||
button.onBreadcrumbsClick = () => {
|
||||
this.selection.setNodeFront(aNode, "breadcrumbs");
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
button.onclick = (function _onBreadcrumbsRightClick(event) {
|
||||
button.focus();
|
||||
|
@ -136,7 +136,7 @@ InspectorPanel.prototype = {
|
||||
// Show a warning when the debugger is paused.
|
||||
// We show the warning only when the inspector
|
||||
// is selected.
|
||||
this.updateDebuggerPausedWarning = function() {
|
||||
this.updateDebuggerPausedWarning = () => {
|
||||
let notificationBox = this._toolbox.getNotificationBox();
|
||||
let notification = notificationBox.getNotificationWithValue("inspector-script-paused");
|
||||
if (!notification && this._toolbox.currentToolId == "inspector" &&
|
||||
@ -154,7 +154,7 @@ InspectorPanel.prototype = {
|
||||
notificationBox.removeNotification(notification);
|
||||
}
|
||||
|
||||
}.bind(this);
|
||||
};
|
||||
this.target.on("thread-paused", this.updateDebuggerPausedWarning);
|
||||
this.target.on("thread-resumed", this.updateDebuggerPausedWarning);
|
||||
this._toolbox.on("select", this.updateDebuggerPausedWarning);
|
||||
@ -164,7 +164,7 @@ InspectorPanel.prototype = {
|
||||
this._initMarkup();
|
||||
this.isReady = false;
|
||||
|
||||
this.once("markuploaded", function() {
|
||||
this.once("markuploaded", () => {
|
||||
this.isReady = true;
|
||||
|
||||
// All the components are initialized. Let's select a node.
|
||||
@ -174,7 +174,7 @@ InspectorPanel.prototype = {
|
||||
|
||||
this.emit("ready");
|
||||
deferred.resolve(this);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
this.setupSearchBox();
|
||||
this.setupSidebar();
|
||||
@ -281,9 +281,9 @@ InspectorPanel.prototype = {
|
||||
|
||||
let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
|
||||
|
||||
this._setDefaultSidebar = function(event, toolId) {
|
||||
this._setDefaultSidebar = (event, toolId) => {
|
||||
Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
this.sidebar.on("select", this._setDefaultSidebar);
|
||||
|
||||
@ -850,10 +850,10 @@ InspectorPanel.prototype = {
|
||||
if (this._timer) {
|
||||
return null;
|
||||
}
|
||||
this._timer = this.panelWin.setTimeout(function() {
|
||||
this._timer = this.panelWin.setTimeout(() => {
|
||||
this.emit("layout-change");
|
||||
this._timer = null;
|
||||
}.bind(this), LAYOUT_CHANGE_TIMER);
|
||||
}, LAYOUT_CHANGE_TIMER);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -231,12 +231,12 @@ MarkupView.prototype = {
|
||||
},
|
||||
|
||||
update: function() {
|
||||
let updateChildren = function(node) {
|
||||
let updateChildren = (node) => {
|
||||
this.getContainer(node).update();
|
||||
for (let child of node.treeChildren()) {
|
||||
updateChildren(child);
|
||||
}
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
// Start with the documentElement
|
||||
let documentElement;
|
||||
@ -361,11 +361,15 @@ MarkupView.prototype = {
|
||||
|
||||
switch(aEvent.keyCode) {
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_H:
|
||||
let node = this._selectedContainer.node;
|
||||
if (node.hidden) {
|
||||
this.walker.unhideNode(node).then(() => this.nodeChanged(node));
|
||||
if (aEvent.metaKey || aEvent.shiftKey) {
|
||||
handled = false;
|
||||
} else {
|
||||
this.walker.hideNode(node).then(() => this.nodeChanged(node));
|
||||
let node = this._selectedContainer.node;
|
||||
if (node.hidden) {
|
||||
this.walker.unhideNode(node).then(() => this.nodeChanged(node));
|
||||
} else {
|
||||
this.walker.hideNode(node).then(() => this.nodeChanged(node));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_DELETE:
|
||||
@ -1240,10 +1244,10 @@ MarkupView.prototype = {
|
||||
this._previewBar.classList.add("hide");
|
||||
win.clearTimeout(this._resizePreviewTimeout);
|
||||
|
||||
win.setTimeout(function() {
|
||||
win.setTimeout(() => {
|
||||
this._updatePreview();
|
||||
this._previewBar.classList.remove("hide");
|
||||
}.bind(this), 1000);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -52,7 +52,7 @@ function Cleopatra(panel, opts) {
|
||||
// or when user clicks on start/stop buttons.
|
||||
|
||||
doc.getElementById("profiler-report").appendChild(this.iframe);
|
||||
win.addEventListener("message", function (event) {
|
||||
win.addEventListener("message", (event) => {
|
||||
if (parseInt(event.data.uid, 10) !== parseInt(this.uid, 10)) {
|
||||
return;
|
||||
}
|
||||
@ -65,7 +65,7 @@ function Cleopatra(panel, opts) {
|
||||
case "displaysource":
|
||||
this.panel.displaySource(event.data.data);
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
Cleopatra.prototype = {
|
||||
@ -163,4 +163,5 @@ Cleopatra.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Cleopatra;
|
||||
module.exports = Cleopatra;
|
||||
|
||||
|
@ -18,6 +18,35 @@ var AppManagerRenderer = Class({
|
||||
return AppProjectEditor;
|
||||
}
|
||||
},
|
||||
getUI: function(parent) {
|
||||
let doc = parent.ownerDocument;
|
||||
if (parent.childElementCount == 0) {
|
||||
let image = doc.createElement("image");
|
||||
let optionImage = doc.createElement("image");
|
||||
let flexElement = doc.createElement("div");
|
||||
let nameLabel = doc.createElement("span");
|
||||
let statusElement = doc.createElement("div");
|
||||
|
||||
image.className = "project-image";
|
||||
optionImage.className = "project-options";
|
||||
optionImage.setAttribute("src", OPTION_URL);
|
||||
nameLabel.className = "project-name-label";
|
||||
statusElement.className = "project-status";
|
||||
flexElement.className = "project-flex";
|
||||
|
||||
parent.appendChild(image);
|
||||
parent.appendChild(nameLabel);
|
||||
parent.appendChild(flexElement);
|
||||
parent.appendChild(statusElement);
|
||||
parent.appendChild(optionImage);
|
||||
}
|
||||
|
||||
return {
|
||||
image: parent.querySelector(".project-image"),
|
||||
nameLabel: parent.querySelector(".project-name-label"),
|
||||
statusElement: parent.querySelector(".project-status")
|
||||
};
|
||||
},
|
||||
onAnnotate: function(resource, editor, elt) {
|
||||
if (resource.parent || !this.isAppManagerProject()) {
|
||||
return;
|
||||
@ -25,33 +54,16 @@ var AppManagerRenderer = Class({
|
||||
|
||||
let {appManagerOpts} = this.host.project;
|
||||
let doc = elt.ownerDocument;
|
||||
let image = doc.createElement("image");
|
||||
let optionImage = doc.createElement("image");
|
||||
let flexElement = doc.createElement("div");
|
||||
let nameLabel = doc.createElement("span");
|
||||
let statusElement = doc.createElement("div");
|
||||
|
||||
image.className = "project-image";
|
||||
optionImage.className = "project-options";
|
||||
nameLabel.className = "project-name-label";
|
||||
statusElement.className = "project-status";
|
||||
flexElement.className = "project-flex";
|
||||
|
||||
let {image,nameLabel,statusElement} = this.getUI(elt);
|
||||
let name = appManagerOpts.name || resource.basename;
|
||||
let url = appManagerOpts.iconUrl || "icon-sample.png";
|
||||
let status = appManagerOpts.validationStatus || "unknown";
|
||||
|
||||
nameLabel.textContent = name;
|
||||
image.setAttribute("src", url);
|
||||
optionImage.setAttribute("src", OPTION_URL);
|
||||
statusElement.setAttribute("status", status)
|
||||
statusElement.setAttribute("status", status);
|
||||
|
||||
elt.innerHTML = "";
|
||||
elt.appendChild(image);
|
||||
elt.appendChild(nameLabel);
|
||||
elt.appendChild(flexElement);
|
||||
elt.appendChild(statusElement);
|
||||
elt.appendChild(optionImage);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -47,12 +47,7 @@ let test = asyncTest(function*() {
|
||||
validationStatus: "error"
|
||||
});
|
||||
|
||||
ok (!nameLabel.parentNode, "The old elements have been removed");
|
||||
|
||||
info ("Getting ahold of and validating the project header DOM");
|
||||
let image = header.querySelector(".project-image");
|
||||
let nameLabel = header.querySelector(".project-name-label");
|
||||
let statusElement = header.querySelector(".project-status");
|
||||
is (statusElement.getAttribute("status"), "error", "The status has been set correctly.");
|
||||
is (nameLabel.textContent, "Test2", "The name label has been set correctly");
|
||||
is (image.getAttribute("src"), "chrome://browser/skin/devtools/tool-inspector.svg", "The icon has been set correctly");
|
||||
@ -65,12 +60,7 @@ let test = asyncTest(function*() {
|
||||
validationStatus: "warning"
|
||||
});
|
||||
|
||||
ok (!nameLabel.parentNode, "The old elements have been removed");
|
||||
|
||||
info ("Getting ahold of and validating the project header DOM");
|
||||
let image = header.querySelector(".project-image");
|
||||
let nameLabel = header.querySelector(".project-name-label");
|
||||
let statusElement = header.querySelector(".project-status");
|
||||
is (statusElement.getAttribute("status"), "warning", "The status has been set correctly.");
|
||||
is (nameLabel.textContent, "Test3", "The name label has been set correctly");
|
||||
is (image.getAttribute("src"), "chrome://browser/skin/devtools/tool-webconsole.svg", "The icon has been set correctly");
|
||||
@ -83,12 +73,7 @@ let test = asyncTest(function*() {
|
||||
validationStatus: "valid"
|
||||
});
|
||||
|
||||
ok (!nameLabel.parentNode, "The old elements have been removed");
|
||||
|
||||
info ("Getting ahold of and validating the project header DOM");
|
||||
let image = header.querySelector(".project-image");
|
||||
let nameLabel = header.querySelector(".project-name-label");
|
||||
let statusElement = header.querySelector(".project-status");
|
||||
is (statusElement.getAttribute("status"), "valid", "The status has been set correctly.");
|
||||
is (nameLabel.textContent, "Test4", "The name label has been set correctly");
|
||||
is (image.getAttribute("src"), "chrome://browser/skin/devtools/tool-debugger.svg", "The icon has been set correctly");
|
||||
|
@ -36,7 +36,7 @@ this.SplitView = function SplitView(aRoot)
|
||||
this._mql = aRoot.ownerDocument.defaultView.matchMedia(LANDSCAPE_MEDIA_QUERY);
|
||||
|
||||
// items list focus and search-on-type handling
|
||||
this._nav.addEventListener("keydown", function onKeyCatchAll(aEvent) {
|
||||
this._nav.addEventListener("keydown", (aEvent) => {
|
||||
function getFocusedItemWithin(nav) {
|
||||
let node = nav.ownerDocument.activeElement;
|
||||
while (node && node.parentNode != nav) {
|
||||
@ -77,7 +77,7 @@ this.SplitView = function SplitView(aRoot)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}.bind(this), false);
|
||||
}, false);
|
||||
}
|
||||
|
||||
SplitView.prototype = {
|
||||
@ -196,10 +196,10 @@ SplitView.prototype = {
|
||||
|
||||
this._nav.appendChild(aSummary);
|
||||
|
||||
aSummary.addEventListener("click", function onSummaryClick(aEvent) {
|
||||
aSummary.addEventListener("click", (aEvent) => {
|
||||
aEvent.stopPropagation();
|
||||
this.activeSummary = aSummary;
|
||||
}.bind(this), false);
|
||||
}, false);
|
||||
|
||||
this._side.appendChild(aDetails);
|
||||
|
||||
|
@ -125,6 +125,16 @@ Telemetry.prototype = {
|
||||
userHistogram: "DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webaudioeditor: {
|
||||
histogram: "DEVTOOLS_WEBAUDIOEDITOR_OPENED_BOOLEAN",
|
||||
userHistogram: "DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
canvasdebugger: {
|
||||
histogram: "DEVTOOLS_CANVASDEBUGGER_OPENED_BOOLEAN",
|
||||
userHistogram: "DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
jsprofiler: {
|
||||
histogram: "DEVTOOLS_JSPROFILER_OPENED_BOOLEAN",
|
||||
userHistogram: "DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG",
|
||||
|
@ -38,6 +38,8 @@ support-files =
|
||||
[browser_telemetry_sidebar.js]
|
||||
[browser_telemetry_toolbox.js]
|
||||
[browser_telemetry_toolboxtabs_inspector.js]
|
||||
[browser_telemetry_toolboxtabs_webaudioeditor.js]
|
||||
[browser_telemetry_toolboxtabs_canvasdebugger.js]
|
||||
[browser_telemetry_toolboxtabs_jsdebugger.js]
|
||||
[browser_telemetry_toolboxtabs_jsprofiler.js]
|
||||
[browser_telemetry_toolboxtabs_netmonitor.js]
|
||||
|
@ -0,0 +1,117 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_canvasdebugger.js</p>";
|
||||
|
||||
// Because we need to gather stats for the period of time that a tool has been
|
||||
// opened we make use of setTimeout() to create tool active times.
|
||||
const TOOL_DELAY = 200;
|
||||
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
|
||||
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
let originalPref = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled");
|
||||
Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true);
|
||||
|
||||
function init() {
|
||||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
}
|
||||
|
||||
this.telemetryInfo[histogramId].push(value);
|
||||
}
|
||||
}
|
||||
|
||||
openToolboxTabTwice("canvasdebugger", false);
|
||||
}
|
||||
|
||||
function openToolboxTabTwice(id, secondPass) {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, id).then(function(toolbox) {
|
||||
info("Toolbox tab " + id + " opened");
|
||||
|
||||
toolbox.once("destroyed", function() {
|
||||
if (secondPass) {
|
||||
checkResults();
|
||||
} else {
|
||||
openToolboxTabTwice(id, true);
|
||||
}
|
||||
});
|
||||
// We use a timeout to check the tools active time
|
||||
setTimeout(function() {
|
||||
gDevTools.closeToolbox(target);
|
||||
}, TOOL_DELAY);
|
||||
}).then(null, reportError);
|
||||
}
|
||||
|
||||
function checkResults() {
|
||||
let result = Telemetry.prototype.telemetryInfo;
|
||||
|
||||
for (let [histId, value] of Iterator(result)) {
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element === true;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries are === true");
|
||||
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element > 0;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries have time > 0");
|
||||
}
|
||||
}
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function reportError(error) {
|
||||
let stack = " " + error.stack.replace(/\n?.*?@/g, "\n JS frame :: ");
|
||||
|
||||
ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
|
||||
error.lineNumber + "\n\nStack trace:" + stack);
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
Telemetry.prototype.log = Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype.telemetryInfo;
|
||||
Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", originalPref);
|
||||
|
||||
TargetFactory = Services = promise = require = null;
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
waitForFocus(init, content);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_webaudioeditor.js</p>";
|
||||
|
||||
// Because we need to gather stats for the period of time that a tool has been
|
||||
// opened we make use of setTimeout() to create tool active times.
|
||||
const TOOL_DELAY = 200;
|
||||
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
|
||||
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
|
||||
let originalPref = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
|
||||
Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true);
|
||||
|
||||
function init() {
|
||||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (!this.telemetryInfo) {
|
||||
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||
return;
|
||||
}
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
}
|
||||
|
||||
this.telemetryInfo[histogramId].push(value);
|
||||
}
|
||||
}
|
||||
|
||||
openToolboxTabTwice("webaudioeditor", false);
|
||||
}
|
||||
|
||||
function openToolboxTabTwice(id, secondPass) {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, id).then(function(toolbox) {
|
||||
info("Toolbox tab " + id + " opened");
|
||||
|
||||
toolbox.once("destroyed", function() {
|
||||
if (secondPass) {
|
||||
checkResults();
|
||||
} else {
|
||||
openToolboxTabTwice(id, true);
|
||||
}
|
||||
});
|
||||
// We use a timeout to check the tools active time
|
||||
setTimeout(function() {
|
||||
gDevTools.closeToolbox(target);
|
||||
}, TOOL_DELAY);
|
||||
}).then(null, reportError);
|
||||
}
|
||||
|
||||
function checkResults() {
|
||||
let result = Telemetry.prototype.telemetryInfo;
|
||||
|
||||
for (let [histId, value] of Iterator(result)) {
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element === true;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries are === true");
|
||||
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element > 0;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries have time > 0");
|
||||
}
|
||||
}
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function reportError(error) {
|
||||
let stack = " " + error.stack.replace(/\n?.*?@/g, "\n JS frame :: ");
|
||||
|
||||
ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
|
||||
error.lineNumber + "\n\nStack trace:" + stack);
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
Telemetry.prototype.log = Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype.telemetryInfo;
|
||||
|
||||
Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", originalPref);
|
||||
TargetFactory = Services = promise = require = null;
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
waitForFocus(init, content);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
}
|
@ -58,10 +58,10 @@ function runTest(index) {
|
||||
var ais = is.bind(this);
|
||||
|
||||
function createTester(holder, options) {
|
||||
return function() {
|
||||
return () => {
|
||||
ais(holder.innerHTML, options.later, options.name + ' later');
|
||||
runNextTest();
|
||||
}.bind(this);
|
||||
};
|
||||
}
|
||||
|
||||
executeSoon(createTester(holder, options));
|
||||
|
@ -134,13 +134,13 @@ StyleEditorUI.prototype = {
|
||||
|
||||
this._view = new SplitView(viewRoot);
|
||||
|
||||
wire(this._view.rootElement, ".style-editor-newButton", function onNew() {
|
||||
wire(this._view.rootElement, ".style-editor-newButton", () =>{
|
||||
this._debuggee.addStyleSheet(null).then(this._onStyleSheetCreated);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
wire(this._view.rootElement, ".style-editor-importButton", function onImport() {
|
||||
wire(this._view.rootElement, ".style-editor-importButton", ()=> {
|
||||
this._importFromFile(this._mockImportFile || null, this._window);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
this._optionsMenu = this._panelDoc.getElementById("style-editor-options-popup");
|
||||
this._optionsMenu.addEventListener("popupshowing",
|
||||
@ -300,7 +300,7 @@ StyleEditorUI.prototype = {
|
||||
* Optional parent window for the file picker.
|
||||
*/
|
||||
_importFromFile: function(file, parentWindow) {
|
||||
let onFileSelected = function(file) {
|
||||
let onFileSelected = (file) => {
|
||||
if (!file) {
|
||||
// nothing selected
|
||||
return;
|
||||
@ -318,7 +318,7 @@ StyleEditorUI.prototype = {
|
||||
});
|
||||
});
|
||||
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
showFilePicker(file, false, parentWindow, onFileSelected);
|
||||
},
|
||||
@ -430,11 +430,11 @@ StyleEditorUI.prototype = {
|
||||
|
||||
wire(summary, ".stylesheet-name", {
|
||||
events: {
|
||||
"keypress": function onStylesheetNameActivate(aEvent) {
|
||||
"keypress": (aEvent) => {
|
||||
if (aEvent.keyCode == aEvent.DOM_VK_RETURN) {
|
||||
this._view.activeSummary = summary;
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -494,7 +494,7 @@ StyleEditorUI.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let href = editor.styleSheet.href || editor.styleSheet.nodeHref;
|
||||
let href = csscoverage.sheetToUrl(editor.styleSheet);
|
||||
usage.createEditorReport(href).then(data => {
|
||||
editor.removeAllUnusedRegions();
|
||||
|
||||
|
@ -500,7 +500,7 @@ StyleSheetEditor.prototype = {
|
||||
converter.charset = "UTF-8";
|
||||
let istream = converter.convertToInputStream(this._state.text);
|
||||
|
||||
NetUtil.asyncCopy(istream, ostream, function onStreamCopied(status) {
|
||||
NetUtil.asyncCopy(istream, ostream, (status) => {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
if (callback) {
|
||||
callback(null);
|
||||
@ -515,7 +515,7 @@ StyleSheetEditor.prototype = {
|
||||
if (callback) {
|
||||
callback(returnFile);
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
};
|
||||
|
||||
let defaultName;
|
||||
|
@ -429,10 +429,10 @@ CssHtmlTree.prototype = {
|
||||
win.clearTimeout(this._filterChangedTimeout);
|
||||
}
|
||||
|
||||
this._filterChangedTimeout = win.setTimeout(function() {
|
||||
this._filterChangedTimeout = win.setTimeout(() => {
|
||||
this.refreshPanel();
|
||||
this._filterChangeTimeout = null;
|
||||
}.bind(this), FILTER_CHANGED_TIMEOUT);
|
||||
}, FILTER_CHANGED_TIMEOUT);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,8 @@ const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devt
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
const Telemetry = require("devtools/shared/telemetry");
|
||||
const telemetry = new Telemetry();
|
||||
|
||||
let { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
|
||||
@ -144,6 +146,7 @@ let WebAudioEditorController = {
|
||||
* Listen for events emitted by the current tab target.
|
||||
*/
|
||||
initialize: function() {
|
||||
telemetry.toolOpened("webaudioeditor");
|
||||
this._onTabNavigated = this._onTabNavigated.bind(this);
|
||||
this._onThemeChange = this._onThemeChange.bind(this);
|
||||
gTarget.on("will-navigate", this._onTabNavigated);
|
||||
@ -169,6 +172,7 @@ let WebAudioEditorController = {
|
||||
* Remove events emitted by the current tab target.
|
||||
*/
|
||||
destroy: function() {
|
||||
telemetry.toolClosed("webaudioeditor");
|
||||
gTarget.off("will-navigate", this._onTabNavigated);
|
||||
gTarget.off("navigate", this._onTabNavigated);
|
||||
gFront.off("start-context", this._onStartContext);
|
||||
|
@ -286,7 +286,7 @@ NetworkPanel.prototype =
|
||||
return a.name.toLowerCase() < b.name.toLowerCase();
|
||||
});
|
||||
|
||||
aList.forEach(function(aItem) {
|
||||
aList.forEach((aItem) => {
|
||||
let name = aItem.name;
|
||||
if (aIgnoreCookie && (name == "Cookie" || name == "Set-Cookie")) {
|
||||
return;
|
||||
@ -332,7 +332,7 @@ NetworkPanel.prototype =
|
||||
row.appendChild(td);
|
||||
|
||||
parent.appendChild(row);
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -612,7 +612,7 @@ NetworkPanel.prototype =
|
||||
let content = this.httpActivity.response.content;
|
||||
let longString = this.webconsole.webConsoleClient.longString(content.text);
|
||||
longString.substring(longString.initial.length, longString.length,
|
||||
function NP__onLongStringSubstring(aResponse)
|
||||
(aResponse) =>
|
||||
{
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
|
||||
@ -632,7 +632,7 @@ NetworkPanel.prototype =
|
||||
this._appendTextNode("responseBody" + cached + "Content",
|
||||
aResponse.substring);
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -779,7 +779,7 @@ NetworkPanel.prototype =
|
||||
let postData = this.httpActivity.request.postData;
|
||||
let longString = this.webconsole.webConsoleClient.longString(postData.text);
|
||||
longString.substring(longString.initial.length, longString.length,
|
||||
function NP__onLongStringSubstring(aResponse)
|
||||
(aResponse) =>
|
||||
{
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
|
||||
@ -788,7 +788,7 @@ NetworkPanel.prototype =
|
||||
|
||||
postData.text = postData.text.initial + aResponse.substring;
|
||||
this._updateRequestBody();
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1850,7 +1850,7 @@ WebConsoleFrame.prototype = {
|
||||
let actor = aHttpActivity.actor;
|
||||
|
||||
if (actor) {
|
||||
this.webConsoleClient.getRequestHeaders(actor, function(aResponse) {
|
||||
this.webConsoleClient.getRequestHeaders(actor, (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF_openNetworkPanel getRequestHeaders:" +
|
||||
aResponse.error);
|
||||
@ -1860,10 +1860,10 @@ WebConsoleFrame.prototype = {
|
||||
aHttpActivity.request.headers = aResponse.headers;
|
||||
|
||||
this.webConsoleClient.getRequestCookies(actor, onRequestCookies);
|
||||
}.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
let onRequestCookies = function(aResponse) {
|
||||
let onRequestCookies = (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF_openNetworkPanel getRequestCookies:" +
|
||||
aResponse.error);
|
||||
@ -1873,9 +1873,9 @@ WebConsoleFrame.prototype = {
|
||||
aHttpActivity.request.cookies = aResponse.cookies;
|
||||
|
||||
this.webConsoleClient.getResponseHeaders(actor, onResponseHeaders);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
let onResponseHeaders = function(aResponse) {
|
||||
let onResponseHeaders = (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF_openNetworkPanel getResponseHeaders:" +
|
||||
aResponse.error);
|
||||
@ -1885,9 +1885,9 @@ WebConsoleFrame.prototype = {
|
||||
aHttpActivity.response.headers = aResponse.headers;
|
||||
|
||||
this.webConsoleClient.getResponseCookies(actor, onResponseCookies);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
let onResponseCookies = function(aResponse) {
|
||||
let onResponseCookies = (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF_openNetworkPanel getResponseCookies:" +
|
||||
aResponse.error);
|
||||
@ -1897,9 +1897,9 @@ WebConsoleFrame.prototype = {
|
||||
aHttpActivity.response.cookies = aResponse.cookies;
|
||||
|
||||
this.webConsoleClient.getRequestPostData(actor, onRequestPostData);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
let onRequestPostData = function(aResponse) {
|
||||
let onRequestPostData = (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF_openNetworkPanel getRequestPostData:" +
|
||||
aResponse.error);
|
||||
@ -1910,9 +1910,9 @@ WebConsoleFrame.prototype = {
|
||||
aHttpActivity.discardRequestBody = aResponse.postDataDiscarded;
|
||||
|
||||
this.webConsoleClient.getResponseContent(actor, onResponseContent);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
let onResponseContent = function(aResponse) {
|
||||
let onResponseContent = (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF_openNetworkPanel getResponseContent:" +
|
||||
aResponse.error);
|
||||
@ -1923,9 +1923,9 @@ WebConsoleFrame.prototype = {
|
||||
aHttpActivity.discardResponseBody = aResponse.contentDiscarded;
|
||||
|
||||
this.webConsoleClient.getEventTimings(actor, onEventTimings);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
let onEventTimings = function(aResponse) {
|
||||
let onEventTimings = (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF_openNetworkPanel getEventTimings:" +
|
||||
aResponse.error);
|
||||
@ -1935,9 +1935,9 @@ WebConsoleFrame.prototype = {
|
||||
aHttpActivity.timings = aResponse.timings;
|
||||
|
||||
openPanel();
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
let openPanel = function() {
|
||||
let openPanel = () => {
|
||||
aNode._netPanel = netPanel;
|
||||
|
||||
let panel = netPanel.panel;
|
||||
@ -1953,7 +1953,7 @@ WebConsoleFrame.prototype = {
|
||||
});
|
||||
|
||||
aNode._panelOpen = true;
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
let netPanel = new NetworkPanel(this.popupset, aHttpActivity, this);
|
||||
netPanel.linkNode = aNode;
|
||||
@ -2911,9 +2911,9 @@ WebConsoleFrame.prototype = {
|
||||
|
||||
this._commandController = null;
|
||||
|
||||
let onDestroy = function() {
|
||||
let onDestroy = () => {
|
||||
this._destroyer.resolve(null);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
if (this.proxy) {
|
||||
this.proxy.disconnect().then(onDestroy);
|
||||
@ -4850,12 +4850,12 @@ WebConsoleConnectionProxy.prototype = {
|
||||
timeout, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
let connPromise = this._connectDefer.promise;
|
||||
connPromise.then(function _onSucess() {
|
||||
connPromise.then(() => {
|
||||
this._connectTimer.cancel();
|
||||
this._connectTimer = null;
|
||||
}.bind(this), function _onFailure() {
|
||||
}, () => {
|
||||
this._connectTimer = null;
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
let client = this.client = this.target.client;
|
||||
|
||||
|
@ -116,6 +116,7 @@ let UI = {
|
||||
this.updateTitle();
|
||||
this.updateCommands();
|
||||
this.updateProjectButton();
|
||||
this.updateProjectEditorHeader();
|
||||
break;
|
||||
};
|
||||
},
|
||||
@ -290,6 +291,25 @@ let UI = {
|
||||
return this.projecteditor.loaded;
|
||||
},
|
||||
|
||||
updateProjectEditorHeader: function() {
|
||||
let project = AppManager.selectedProject;
|
||||
if (!project || !this.projecteditor) {
|
||||
return;
|
||||
}
|
||||
let status = project.validationStatus || "unknown";
|
||||
if (status == "error warning") {
|
||||
status = "error";
|
||||
}
|
||||
this.getProjectEditor().then((projecteditor) => {
|
||||
projecteditor.setProjectToAppPath(project.location, {
|
||||
name: project.name,
|
||||
iconUrl: project.icon,
|
||||
projectOverviewURL: "chrome://webide/content/details.xhtml",
|
||||
validationStatus: status
|
||||
});
|
||||
}, console.error);
|
||||
},
|
||||
|
||||
isProjectEditorEnabled: function() {
|
||||
return Services.prefs.getBoolPref("devtools.webide.showProjectEditor");
|
||||
},
|
||||
@ -333,12 +353,8 @@ let UI = {
|
||||
detailsIframe.setAttribute("hidden", "true");
|
||||
projecteditorIframe.removeAttribute("hidden");
|
||||
|
||||
this.getProjectEditor().then((projecteditor) => {
|
||||
projecteditor.setProjectToAppPath(project.location, {
|
||||
name: project.name,
|
||||
iconUrl: project.icon,
|
||||
projectOverviewURL: "chrome://webide/content/details.xhtml"
|
||||
});
|
||||
this.getProjectEditor().then(() => {
|
||||
this.updateProjectEditorHeader();
|
||||
}, console.error);
|
||||
|
||||
if (project.location) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 1.0.277
|
||||
Current extension version is: 1.0.370
|
||||
|
||||
|
@ -66,7 +66,12 @@ var DEFAULT_PREFERENCES = {
|
||||
defaultZoomValue: '',
|
||||
sidebarViewOnLoad: 0,
|
||||
enableHandToolOnLoad: false,
|
||||
enableWebGL: false
|
||||
enableWebGL: false,
|
||||
disableRange: false,
|
||||
disableAutoFetch: false,
|
||||
disableFontFace: false,
|
||||
disableTextLayer: false,
|
||||
useOnlyCssZoom: false
|
||||
};
|
||||
|
||||
|
||||
|
@ -21,8 +21,8 @@ if (typeof PDFJS === 'undefined') {
|
||||
(typeof window !== 'undefined' ? window : this).PDFJS = {};
|
||||
}
|
||||
|
||||
PDFJS.version = '1.0.277';
|
||||
PDFJS.build = '250d394';
|
||||
PDFJS.version = '1.0.370';
|
||||
PDFJS.build = '13efe84';
|
||||
|
||||
(function pdfjsWrapper() {
|
||||
// Use strict in our context only - users might not want it
|
||||
@ -883,15 +883,15 @@ function isBool(v) {
|
||||
}
|
||||
|
||||
function isInt(v) {
|
||||
return typeof v == 'number' && ((v | 0) == v);
|
||||
return typeof v === 'number' && ((v | 0) === v);
|
||||
}
|
||||
|
||||
function isNum(v) {
|
||||
return typeof v == 'number';
|
||||
return typeof v === 'number';
|
||||
}
|
||||
|
||||
function isString(v) {
|
||||
return typeof v == 'string';
|
||||
return typeof v === 'string';
|
||||
}
|
||||
|
||||
function isNull(v) {
|
||||
@ -903,7 +903,7 @@ function isName(v) {
|
||||
}
|
||||
|
||||
function isCmd(v, cmd) {
|
||||
return v instanceof Cmd && (!cmd || v.cmd == cmd);
|
||||
return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
|
||||
}
|
||||
|
||||
function isDict(v, type) {
|
||||
@ -914,7 +914,7 @@ function isDict(v, type) {
|
||||
return true;
|
||||
}
|
||||
var dictType = v.get('Type');
|
||||
return isName(dictType) && dictType.name == type;
|
||||
return isName(dictType) && dictType.name === type;
|
||||
}
|
||||
|
||||
function isArray(v) {
|
||||
@ -922,13 +922,11 @@ function isArray(v) {
|
||||
}
|
||||
|
||||
function isStream(v) {
|
||||
return typeof v == 'object' && v !== null && v !== undefined &&
|
||||
('getBytes' in v);
|
||||
return typeof v === 'object' && v !== null && v.getBytes !== undefined;
|
||||
}
|
||||
|
||||
function isArrayBuffer(v) {
|
||||
return typeof v == 'object' && v !== null && v !== undefined &&
|
||||
('byteLength' in v);
|
||||
return typeof v === 'object' && v !== null && v.byteLength !== undefined;
|
||||
}
|
||||
|
||||
function isRef(v) {
|
||||
@ -1414,7 +1412,7 @@ var Annotation = (function AnnotationClosure() {
|
||||
data &&
|
||||
(!data.annotationFlags ||
|
||||
!(data.annotationFlags & 0x22)) && // Hidden or NoView
|
||||
data.rect); // rectangle is nessessary
|
||||
data.rect); // rectangle is necessary
|
||||
},
|
||||
|
||||
isPrintable: function Annotation_isPrintable() {
|
||||
@ -1423,7 +1421,8 @@ var Annotation = (function AnnotationClosure() {
|
||||
data &&
|
||||
data.annotationFlags && // Default: not printable
|
||||
data.annotationFlags & 0x4 && // Print
|
||||
data.rect); // rectangle is nessessary
|
||||
!(data.annotationFlags & 0x2) && // Hidden
|
||||
data.rect); // rectangle is necessary
|
||||
},
|
||||
|
||||
loadResources: function Annotation_loadResources(keys) {
|
||||
@ -1548,7 +1547,9 @@ var Annotation = (function AnnotationClosure() {
|
||||
if (annotation.isViewable() || annotation.isPrintable()) {
|
||||
return annotation;
|
||||
} else {
|
||||
warn('unimplemented annotation type: ' + subtype);
|
||||
if (SUPPORTED_TYPES.indexOf(subtype) === -1) {
|
||||
warn('unimplemented annotation type: ' + subtype);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -2150,6 +2151,13 @@ PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
|
||||
PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
|
||||
true : PDFJS.disableWebGL);
|
||||
|
||||
/**
|
||||
* Enables CSS only zooming.
|
||||
* @var {boolean}
|
||||
*/
|
||||
PDFJS.useOnlyCssZoom = (PDFJS.useOnlyCssZoom === undefined ?
|
||||
false : PDFJS.useOnlyCssZoom);
|
||||
|
||||
/**
|
||||
* Controls the logging level.
|
||||
* The constants from PDFJS.VERBOSITY_LEVELS should be used:
|
||||
@ -2161,6 +2169,14 @@ PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
|
||||
PDFJS.verbosity = (PDFJS.verbosity === undefined ?
|
||||
PDFJS.VERBOSITY_LEVELS.warnings : PDFJS.verbosity);
|
||||
|
||||
/**
|
||||
* The maximum supported canvas size in total pixels e.g. width * height.
|
||||
* The default value is 4096 * 4096. Use -1 for no limit.
|
||||
* @var {number}
|
||||
*/
|
||||
PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ?
|
||||
16777216 : PDFJS.maxCanvasPixels);
|
||||
|
||||
/**
|
||||
* Document initialization / loading parameters object.
|
||||
*
|
||||
@ -3793,6 +3809,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
// Defines the time the executeOperatorList is going to be executing
|
||||
// before it stops and shedules a continue of execution.
|
||||
var EXECUTION_TIME = 15;
|
||||
// Defines the number of steps before checking the execution time
|
||||
var EXECUTION_STEPS = 10;
|
||||
|
||||
function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) {
|
||||
this.ctx = canvasCtx;
|
||||
@ -3998,49 +4016,54 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
function composeSMaskBackdrop(bytes, r0, g0, b0) {
|
||||
var length = bytes.length;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
var alpha = bytes[i];
|
||||
if (alpha === 0) {
|
||||
bytes[i - 3] = r0;
|
||||
bytes[i - 2] = g0;
|
||||
bytes[i - 1] = b0;
|
||||
} else if (alpha < 255) {
|
||||
var alpha_ = 255 - alpha;
|
||||
bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) >> 8;
|
||||
bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) >> 8;
|
||||
bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function composeSMaskAlpha(maskData, layerData) {
|
||||
var length = maskData.length;
|
||||
var scale = 1 / 255;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
var alpha = maskData[i];
|
||||
layerData[i] = (layerData[i] * alpha * scale) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
function composeSMaskLuminosity(maskData, layerData) {
|
||||
var length = maskData.length;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
var y = ((maskData[i - 3] * 77) + // * 0.3 / 255 * 0x10000
|
||||
(maskData[i - 2] * 152) + // * 0.59 ....
|
||||
(maskData[i - 1] * 28)) | 0; // * 0.11 ....
|
||||
layerData[i] = (layerData[i] * y) >> 16;
|
||||
}
|
||||
}
|
||||
|
||||
function genericComposeSMask(maskCtx, layerCtx, width, height,
|
||||
subtype, backdrop) {
|
||||
var addBackdropFn;
|
||||
if (backdrop) {
|
||||
addBackdropFn = function (r0, g0, b0, bytes) {
|
||||
var length = bytes.length;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
var alpha = bytes[i] / 255;
|
||||
if (alpha === 0) {
|
||||
bytes[i - 3] = r0;
|
||||
bytes[i - 2] = g0;
|
||||
bytes[i - 1] = b0;
|
||||
} else if (alpha < 1) {
|
||||
var alpha_ = 1 - alpha;
|
||||
bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) | 0;
|
||||
bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) | 0;
|
||||
bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) | 0;
|
||||
}
|
||||
}
|
||||
}.bind(null, backdrop[0], backdrop[1], backdrop[2]);
|
||||
} else {
|
||||
addBackdropFn = function () {};
|
||||
}
|
||||
var hasBackdrop = !!backdrop;
|
||||
var r0 = hasBackdrop ? backdrop[0] : 0;
|
||||
var g0 = hasBackdrop ? backdrop[1] : 0;
|
||||
var b0 = hasBackdrop ? backdrop[2] : 0;
|
||||
|
||||
var composeFn;
|
||||
if (subtype === 'Luminosity') {
|
||||
composeFn = function (maskDataBytes, layerDataBytes) {
|
||||
var length = maskDataBytes.length;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
var y = ((maskDataBytes[i - 3] * 77) + // * 0.3 / 255 * 0x10000
|
||||
(maskDataBytes[i - 2] * 152) + // * 0.59 ....
|
||||
(maskDataBytes[i - 1] * 28)) | 0; // * 0.11 ....
|
||||
layerDataBytes[i] = (layerDataBytes[i] * y) >> 16;
|
||||
}
|
||||
};
|
||||
composeFn = composeSMaskLuminosity;
|
||||
} else {
|
||||
composeFn = function (maskDataBytes, layerDataBytes) {
|
||||
var length = maskDataBytes.length;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
var alpha = maskDataBytes[i];
|
||||
layerDataBytes[i] = (layerDataBytes[i] * alpha / 255) | 0;
|
||||
}
|
||||
};
|
||||
composeFn = composeSMaskAlpha;
|
||||
}
|
||||
|
||||
// processing image in chunks to save memory
|
||||
@ -4051,7 +4074,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var maskData = maskCtx.getImageData(0, row, width, chunkHeight);
|
||||
var layerData = layerCtx.getImageData(0, row, width, chunkHeight);
|
||||
|
||||
addBackdropFn(maskData.data);
|
||||
if (hasBackdrop) {
|
||||
composeSMaskBackdrop(maskData.data, r0, g0, b0);
|
||||
}
|
||||
composeFn(maskData.data, layerData.data);
|
||||
|
||||
maskCtx.putImageData(layerData, 0, row);
|
||||
@ -4125,18 +4150,21 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var argsArrayLen = argsArray.length;
|
||||
|
||||
// Sometimes the OperatorList to execute is empty.
|
||||
if (argsArrayLen == i) {
|
||||
if (argsArrayLen === i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
var endTime = Date.now() + EXECUTION_TIME;
|
||||
var chunkOperations = (argsArrayLen - i > EXECUTION_STEPS &&
|
||||
typeof continueCallback === 'function');
|
||||
var endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
|
||||
var steps = 0;
|
||||
|
||||
var commonObjs = this.commonObjs;
|
||||
var objs = this.objs;
|
||||
var fnId;
|
||||
|
||||
while (true) {
|
||||
if (stepper && i === stepper.nextBreakPoint) {
|
||||
if (stepper !== undefined && i === stepper.nextBreakPoint) {
|
||||
stepper.breakIt(i, continueCallback);
|
||||
return i;
|
||||
}
|
||||
@ -4149,16 +4177,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var deps = argsArray[i];
|
||||
for (var n = 0, nn = deps.length; n < nn; n++) {
|
||||
var depObjId = deps[n];
|
||||
var common = depObjId.substring(0, 2) == 'g_';
|
||||
var common = depObjId[0] === 'g' && depObjId[1] === '_';
|
||||
var objsPool = common ? commonObjs : objs;
|
||||
|
||||
// If the promise isn't resolved yet, add the continueCallback
|
||||
// to the promise and bail out.
|
||||
if (!common && !objs.isResolved(depObjId)) {
|
||||
objs.get(depObjId, continueCallback);
|
||||
return i;
|
||||
}
|
||||
if (common && !commonObjs.isResolved(depObjId)) {
|
||||
commonObjs.get(depObjId, continueCallback);
|
||||
if (!objsPool.isResolved(depObjId)) {
|
||||
objsPool.get(depObjId, continueCallback);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -4167,15 +4192,18 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
i++;
|
||||
|
||||
// If the entire operatorList was executed, stop as were done.
|
||||
if (i == argsArrayLen) {
|
||||
if (i === argsArrayLen) {
|
||||
return i;
|
||||
}
|
||||
|
||||
// If the execution took longer then a certain amount of time and
|
||||
// `continueCallback` is specified, interrupt the execution.
|
||||
if (continueCallback && Date.now() > endTime) {
|
||||
continueCallback();
|
||||
return i;
|
||||
if (chunkOperations && ++steps > EXECUTION_STEPS) {
|
||||
if (Date.now() > endTime) {
|
||||
continueCallback();
|
||||
return i;
|
||||
}
|
||||
steps = 0;
|
||||
}
|
||||
|
||||
// If the operatorList isn't executed completely yet OR the execution
|
||||
@ -4334,18 +4362,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var old = this.current;
|
||||
this.stateStack.push(old);
|
||||
this.current = old.clone();
|
||||
if (this.current.activeSMask) {
|
||||
this.current.activeSMask = null;
|
||||
}
|
||||
this.current.activeSMask = null;
|
||||
},
|
||||
restore: function CanvasGraphics_restore() {
|
||||
var prev = this.stateStack.pop();
|
||||
if (prev) {
|
||||
if (this.current.activeSMask) {
|
||||
if (this.stateStack.length !== 0) {
|
||||
if (this.current.activeSMask !== null) {
|
||||
this.endSMaskGroup();
|
||||
}
|
||||
|
||||
this.current = prev;
|
||||
this.current = this.stateStack.pop();
|
||||
this.ctx.restore();
|
||||
}
|
||||
},
|
||||
@ -4901,7 +4926,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
// Color
|
||||
getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) {
|
||||
var pattern;
|
||||
if (IR[0] == 'TilingPattern') {
|
||||
if (IR[0] === 'TilingPattern') {
|
||||
var color = IR[1];
|
||||
pattern = new TilingPattern(IR, color, this.ctx, this.objs,
|
||||
this.commonObjs, this.baseTransform);
|
||||
@ -4977,13 +5002,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.save();
|
||||
this.baseTransformStack.push(this.baseTransform);
|
||||
|
||||
if (matrix && isArray(matrix) && 6 == matrix.length) {
|
||||
if (isArray(matrix) && 6 === matrix.length) {
|
||||
this.transform.apply(this, matrix);
|
||||
}
|
||||
|
||||
this.baseTransform = this.ctx.mozCurrentTransform;
|
||||
|
||||
if (bbox && isArray(bbox) && 4 == bbox.length) {
|
||||
if (isArray(bbox) && 4 === bbox.length) {
|
||||
var width = bbox[2] - bbox[0];
|
||||
var height = bbox[3] - bbox[1];
|
||||
this.rectangle(bbox[0], bbox[1], width, height);
|
||||
@ -5135,7 +5160,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
matrix) {
|
||||
this.save();
|
||||
|
||||
if (rect && isArray(rect) && 4 == rect.length) {
|
||||
if (isArray(rect) && 4 === rect.length) {
|
||||
var width = rect[2] - rect[0];
|
||||
var height = rect[3] - rect[1];
|
||||
this.rectangle(rect[0], rect[1], width, height);
|
||||
@ -5453,7 +5478,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
consumePath: function CanvasGraphics_consumePath() {
|
||||
var ctx = this.ctx;
|
||||
if (this.pendingClip) {
|
||||
if (this.pendingClip == EO_CLIP) {
|
||||
if (this.pendingClip === EO_CLIP) {
|
||||
if (ctx.mozFillRule !== undefined) {
|
||||
ctx.mozFillRule = 'evenodd';
|
||||
ctx.clip();
|
||||
|
1799
browser/extensions/pdfjs/content/build/pdf.worker.js
vendored
1799
browser/extensions/pdfjs/content/build/pdf.worker.js
vendored
File diff suppressed because it is too large
Load Diff
@ -57,8 +57,7 @@ var NetworkManager = (function NetworkManagerClosure() {
|
||||
}
|
||||
|
||||
function getArrayBuffer(xhr) {
|
||||
var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
|
||||
xhr.responseArrayBuffer || xhr.response);
|
||||
var data = xhr.response;
|
||||
if (typeof data !== 'string') {
|
||||
return data;
|
||||
}
|
||||
@ -110,7 +109,7 @@ var NetworkManager = (function NetworkManagerClosure() {
|
||||
pendingRequest.expectedStatus = 200;
|
||||
}
|
||||
|
||||
xhr.mozResponseType = xhr.responseType = 'arraybuffer';
|
||||
xhr.responseType = 'arraybuffer';
|
||||
|
||||
if (args.onProgress) {
|
||||
xhr.onprogress = args.onProgress;
|
||||
|
@ -217,6 +217,8 @@ http://sourceforge.net/adobe/cmap/wiki/License/
|
||||
<option title="" value="1.25">125%</option>
|
||||
<option title="" value="1.5">150%</option>
|
||||
<option title="" value="2">200%</option>
|
||||
<option title="" value="3">300%</option>
|
||||
<option title="" value="4">400%</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -28,18 +28,17 @@ var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
|
||||
var DEFAULT_SCALE = 'auto';
|
||||
var DEFAULT_SCALE_DELTA = 1.1;
|
||||
var UNKNOWN_SCALE = 0;
|
||||
var CACHE_SIZE = 20;
|
||||
var CACHE_SIZE = 10;
|
||||
var CSS_UNITS = 96.0 / 72.0;
|
||||
var SCROLLBAR_PADDING = 40;
|
||||
var VERTICAL_PADDING = 5;
|
||||
var MAX_AUTO_SCALE = 1.25;
|
||||
var MIN_SCALE = 0.25;
|
||||
var MAX_SCALE = 4.0;
|
||||
var MAX_SCALE = 10.0;
|
||||
var VIEW_HISTORY_MEMORY = 20;
|
||||
var SCALE_SELECT_CONTAINER_PADDING = 8;
|
||||
var SCALE_SELECT_PADDING = 22;
|
||||
var THUMBNAIL_SCROLL_MARGIN = -19;
|
||||
var USE_ONLY_CSS_ZOOM = false;
|
||||
var CLEANUP_TIMEOUT = 30000;
|
||||
var IGNORE_CURRENT_POSITION_ON_ZOOM = false;
|
||||
var RenderingStates = {
|
||||
@ -295,7 +294,7 @@ var Cache = function cacheCache(size) {
|
||||
this.push = function cachePush(view) {
|
||||
var i = data.indexOf(view);
|
||||
if (i >= 0) {
|
||||
data.splice(i);
|
||||
data.splice(i, 1);
|
||||
}
|
||||
data.push(view);
|
||||
if (data.length > size) {
|
||||
@ -312,7 +311,12 @@ var DEFAULT_PREFERENCES = {
|
||||
defaultZoomValue: '',
|
||||
sidebarViewOnLoad: 0,
|
||||
enableHandToolOnLoad: false,
|
||||
enableWebGL: false
|
||||
enableWebGL: false,
|
||||
disableRange: false,
|
||||
disableAutoFetch: false,
|
||||
disableFontFace: false,
|
||||
disableTextLayer: false,
|
||||
useOnlyCssZoom: false
|
||||
};
|
||||
|
||||
|
||||
@ -2635,12 +2639,36 @@ var PDFView = {
|
||||
var initializedPromise = Promise.all([
|
||||
Preferences.get('enableWebGL').then(function resolved(value) {
|
||||
PDFJS.disableWebGL = !value;
|
||||
}, function rejected(reason) {}),
|
||||
}),
|
||||
Preferences.get('sidebarViewOnLoad').then(function resolved(value) {
|
||||
self.preferenceSidebarViewOnLoad = value;
|
||||
}, function rejected(reason) {})
|
||||
}),
|
||||
Preferences.get('disableTextLayer').then(function resolved(value) {
|
||||
if (PDFJS.disableTextLayer === true) {
|
||||
return;
|
||||
}
|
||||
PDFJS.disableTextLayer = value;
|
||||
}),
|
||||
Preferences.get('disableRange').then(function resolved(value) {
|
||||
if (PDFJS.disableRange === true) {
|
||||
return;
|
||||
}
|
||||
PDFJS.disableRange = value;
|
||||
}),
|
||||
Preferences.get('disableAutoFetch').then(function resolved(value) {
|
||||
PDFJS.disableAutoFetch = value;
|
||||
}),
|
||||
Preferences.get('disableFontFace').then(function resolved(value) {
|
||||
if (PDFJS.disableFontFace === true) {
|
||||
return;
|
||||
}
|
||||
PDFJS.disableFontFace = value;
|
||||
}),
|
||||
Preferences.get('useOnlyCssZoom').then(function resolved(value) {
|
||||
PDFJS.useOnlyCssZoom = value;
|
||||
})
|
||||
// TODO move more preferences and other async stuff here
|
||||
]);
|
||||
]).catch(function (reason) { });
|
||||
|
||||
return initializedPromise.then(function () {
|
||||
PDFView.initialized = true;
|
||||
@ -3584,6 +3612,8 @@ var PDFView = {
|
||||
}
|
||||
}
|
||||
this.pdfDocument.cleanup();
|
||||
|
||||
ThumbnailView.tempImageCache = null;
|
||||
},
|
||||
|
||||
getHighestPriority: function pdfViewGetHighestPriority(visible, views,
|
||||
@ -3652,6 +3682,9 @@ var PDFView = {
|
||||
},
|
||||
|
||||
setHash: function pdfViewSetHash(hash) {
|
||||
var validFitZoomValues = ['Fit','FitB','FitH','FitBH',
|
||||
'FitV','FitBV','FitR'];
|
||||
|
||||
if (!hash) {
|
||||
return;
|
||||
}
|
||||
@ -3676,10 +3709,13 @@ var PDFView = {
|
||||
// it should stay as it is.
|
||||
var zoomArg = zoomArgs[0];
|
||||
var zoomArgNumber = parseFloat(zoomArg);
|
||||
var destName = 'XYZ';
|
||||
if (zoomArgNumber) {
|
||||
zoomArg = zoomArgNumber / 100;
|
||||
} else if (validFitZoomValues.indexOf(zoomArg) >= 0) {
|
||||
destName = zoomArg;
|
||||
}
|
||||
dest = [null, {name: 'XYZ'},
|
||||
dest = [null, { name: destName },
|
||||
zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
|
||||
zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
|
||||
zoomArg];
|
||||
@ -3988,6 +4024,7 @@ var PageView = function pageView(container, id, scale,
|
||||
this.scale = scale || 1.0;
|
||||
this.viewport = defaultViewport;
|
||||
this.pdfPageRotate = defaultViewport.rotation;
|
||||
this.hasRestrictedScaling = false;
|
||||
|
||||
this.renderingState = RenderingStates.INITIAL;
|
||||
this.resume = null;
|
||||
@ -4058,7 +4095,13 @@ var PageView = function pageView(container, id, scale,
|
||||
this.annotationLayer = null;
|
||||
}
|
||||
|
||||
delete this.canvas;
|
||||
if (this.canvas) {
|
||||
// Zeroing the width and height causes Firefox to release graphics
|
||||
// resources immediately, which can greatly reduce memory consumption.
|
||||
this.canvas.width = 0;
|
||||
this.canvas.height = 0;
|
||||
delete this.canvas;
|
||||
}
|
||||
|
||||
this.loadingIconDiv = document.createElement('div');
|
||||
this.loadingIconDiv.className = 'loadingIcon';
|
||||
@ -4078,8 +4121,23 @@ var PageView = function pageView(container, id, scale,
|
||||
rotation: totalRotation
|
||||
});
|
||||
|
||||
if (USE_ONLY_CSS_ZOOM && this.canvas) {
|
||||
this.cssTransform(this.canvas);
|
||||
var isScalingRestricted = false;
|
||||
if (this.canvas && PDFJS.maxCanvasPixels > 0) {
|
||||
var ctx = this.canvas.getContext('2d');
|
||||
var outputScale = getOutputScale(ctx);
|
||||
var pixelsInViewport = this.viewport.width * this.viewport.height;
|
||||
var maxScale = Math.sqrt(PDFJS.maxCanvasPixels / pixelsInViewport);
|
||||
if (((Math.floor(this.viewport.width) * outputScale.sx) | 0) *
|
||||
((Math.floor(this.viewport.height) * outputScale.sy) | 0) >
|
||||
PDFJS.maxCanvasPixels) {
|
||||
isScalingRestricted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.canvas &&
|
||||
(PDFJS.useOnlyCssZoom ||
|
||||
(this.hasRestrictedScaling && isScalingRestricted))) {
|
||||
this.cssTransform(this.canvas, true);
|
||||
return;
|
||||
} else if (this.canvas && !this.zoomLayer) {
|
||||
this.zoomLayer = this.canvas.parentNode;
|
||||
@ -4091,7 +4149,7 @@ var PageView = function pageView(container, id, scale,
|
||||
this.reset(true);
|
||||
};
|
||||
|
||||
this.cssTransform = function pageCssTransform(canvas) {
|
||||
this.cssTransform = function pageCssTransform(canvas, redrawAnnotations) {
|
||||
// Scale canvas, canvas wrapper, and page container.
|
||||
var width = this.viewport.width;
|
||||
var height = this.viewport.height;
|
||||
@ -4154,7 +4212,7 @@ var PageView = function pageView(container, id, scale,
|
||||
CustomStyle.setProp('transformOrigin', textLayerDiv, '0% 0%');
|
||||
}
|
||||
|
||||
if (USE_ONLY_CSS_ZOOM && this.annotationLayer) {
|
||||
if (redrawAnnotations && this.annotationLayer) {
|
||||
setupAnnotations(div, this.pdfPage, this.viewport);
|
||||
}
|
||||
};
|
||||
@ -4451,7 +4509,7 @@ var PageView = function pageView(container, id, scale,
|
||||
var ctx = canvas.getContext('2d');
|
||||
var outputScale = getOutputScale(ctx);
|
||||
|
||||
if (USE_ONLY_CSS_ZOOM) {
|
||||
if (PDFJS.useOnlyCssZoom) {
|
||||
var actualSizeViewport = viewport.clone({ scale: CSS_UNITS });
|
||||
// Use a scale that will make the canvas be the original intended size
|
||||
// of the page.
|
||||
@ -4460,6 +4518,19 @@ var PageView = function pageView(container, id, scale,
|
||||
outputScale.scaled = true;
|
||||
}
|
||||
|
||||
if (PDFJS.maxCanvasPixels > 0) {
|
||||
var pixelsInViewport = viewport.width * viewport.height;
|
||||
var maxScale = Math.sqrt(PDFJS.maxCanvasPixels / pixelsInViewport);
|
||||
if (outputScale.sx > maxScale || outputScale.sy > maxScale) {
|
||||
outputScale.sx = maxScale;
|
||||
outputScale.sy = maxScale;
|
||||
outputScale.scaled = true;
|
||||
this.hasRestrictedScaling = true;
|
||||
} else {
|
||||
this.hasRestrictedScaling = false;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = (Math.floor(viewport.width) * outputScale.sx) | 0;
|
||||
canvas.height = (Math.floor(viewport.height) * outputScale.sy) | 0;
|
||||
canvas.style.width = Math.floor(viewport.width) + 'px';
|
||||
@ -4542,8 +4613,6 @@ var PageView = function pageView(container, id, scale,
|
||||
self.onAfterDraw();
|
||||
}
|
||||
|
||||
cache.push(self);
|
||||
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('pagerender', true, true, {
|
||||
pageNumber: pdfPage.pageNumber
|
||||
@ -4594,6 +4663,10 @@ var PageView = function pageView(container, id, scale,
|
||||
|
||||
setupAnnotations(div, pdfPage, this.viewport);
|
||||
div.setAttribute('data-loaded', true);
|
||||
|
||||
// Add the page to the cache at the start of drawing. That way it can be
|
||||
// evicted from the cache and destroyed even if we pause its rendering.
|
||||
cache.push(this);
|
||||
};
|
||||
|
||||
this.beforePrint = function pageViewBeforePrint() {
|
||||
@ -4820,6 +4893,17 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
this.hasImage = true;
|
||||
};
|
||||
|
||||
function getTempCanvas(width, height) {
|
||||
var tempCanvas = ThumbnailView.tempImageCache;
|
||||
if (!tempCanvas) {
|
||||
tempCanvas = document.createElement('canvas');
|
||||
ThumbnailView.tempImageCache = tempCanvas;
|
||||
}
|
||||
tempCanvas.width = width;
|
||||
tempCanvas.height = height;
|
||||
return tempCanvas;
|
||||
}
|
||||
|
||||
this.setImage = function thumbnailViewSetImage(img) {
|
||||
if (!this.pdfPage) {
|
||||
var promise = PDFView.getPage(this.id);
|
||||
@ -4834,13 +4918,40 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
}
|
||||
this.renderingState = RenderingStates.FINISHED;
|
||||
var ctx = this.getPageDrawContext();
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height,
|
||||
|
||||
var reducedImage = img;
|
||||
var reducedWidth = img.width;
|
||||
var reducedHeight = img.height;
|
||||
|
||||
// drawImage does an awful job of rescaling the image, doing it gradually
|
||||
var MAX_SCALE_FACTOR = 2.0;
|
||||
if (Math.max(img.width / ctx.canvas.width,
|
||||
img.height / ctx.canvas.height) > MAX_SCALE_FACTOR) {
|
||||
reducedWidth >>= 1;
|
||||
reducedHeight >>= 1;
|
||||
reducedImage = getTempCanvas(reducedWidth, reducedHeight);
|
||||
var reducedImageCtx = reducedImage.getContext('2d');
|
||||
reducedImageCtx.drawImage(img, 0, 0, img.width, img.height,
|
||||
0, 0, reducedWidth, reducedHeight);
|
||||
while (Math.max(reducedWidth / ctx.canvas.width,
|
||||
reducedHeight / ctx.canvas.height) > MAX_SCALE_FACTOR) {
|
||||
reducedImageCtx.drawImage(reducedImage,
|
||||
0, 0, reducedWidth, reducedHeight,
|
||||
0, 0, reducedWidth >> 1, reducedHeight >> 1);
|
||||
reducedWidth >>= 1;
|
||||
reducedHeight >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,
|
||||
0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
|
||||
this.hasImage = true;
|
||||
};
|
||||
};
|
||||
|
||||
ThumbnailView.tempImageCache = null;
|
||||
|
||||
|
||||
var FIND_SCROLL_OFFSET_TOP = -50;
|
||||
var FIND_SCROLL_OFFSET_LEFT = -400;
|
||||
@ -5301,7 +5412,7 @@ function webViewerInitialized() {
|
||||
}
|
||||
|
||||
if ('useOnlyCssZoom' in hashParams) {
|
||||
USE_ONLY_CSS_ZOOM = (hashParams['useOnlyCssZoom'] === 'true');
|
||||
PDFJS.useOnlyCssZoom = (hashParams['useOnlyCssZoom'] === 'true');
|
||||
}
|
||||
|
||||
if ('verbosity' in hashParams) {
|
||||
@ -5819,13 +5930,14 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
break;
|
||||
|
||||
case 36: // home
|
||||
if (PresentationMode.active) {
|
||||
if (PresentationMode.active || PDFView.page > 1) {
|
||||
PDFView.page = 1;
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
case 35: // end
|
||||
if (PresentationMode.active) {
|
||||
if (PresentationMode.active ||
|
||||
PDFView.page < PDFView.pdfDocument.numPages) {
|
||||
PDFView.page = PDFView.pdfDocument.numPages;
|
||||
handled = true;
|
||||
}
|
||||
|
@ -168,8 +168,8 @@ helpManRequired=required
|
||||
helpManOptional=optional
|
||||
helpManDefault=optional, default=%S
|
||||
|
||||
# LOCALIZATION NOTE (helpIntro): This forms part of the output from the 'help'
|
||||
# command. 'GCLI' is a project name and should be left untranslated.
|
||||
# LOCALIZATION NOTE: This forms part of the output from the 'help' command.
|
||||
# 'GCLI' is a project name and should be left untranslated.
|
||||
helpIntro=GCLI is an experiment to create a highly usable command line for web developers.
|
||||
|
||||
# LOCALIZATION NOTE: Text shown as part of the output of the 'help' command
|
||||
|
@ -68,8 +68,8 @@
|
||||
<!-- LOCALIZATION NOTE (options.enableChrome.label4): This is the label for the
|
||||
- checkbox that toggles chrome debugging, i.e. devtools.chrome.enabled
|
||||
- boolean preference in about:config, in the options panel. -->
|
||||
<!ENTITY options.enableChrome.label4 "Enable chrome and addon debugging">
|
||||
<!ENTITY options.enableChrome.tooltip2 "Turning this option on will allow you to use various developer tools in browser context and debug addons from the Add-On Manager">
|
||||
<!ENTITY options.enableChrome.label4 "Enable chrome and add-on debugging">
|
||||
<!ENTITY options.enableChrome.tooltip2 "Turning this option on will allow you to use various developer tools in browser context and debug add-ons from the Add-ons Manager">
|
||||
|
||||
<!-- LOCALIZATION NOTE (options.enableRemote.label3): This is the label for the
|
||||
- checkbox that toggles remote debugging, i.e. devtools.debugger.remote-enabled
|
||||
|
@ -687,6 +687,7 @@ filefield {
|
||||
border-radius: 2px;
|
||||
background-color: #FBFBFB;
|
||||
overflow-y: auto;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
#typeColumn,
|
||||
|
@ -488,6 +488,26 @@ public:
|
||||
mStatsShowing = aShow;
|
||||
}
|
||||
|
||||
bool MozAllowCasting() const
|
||||
{
|
||||
return mAllowCasting;
|
||||
}
|
||||
|
||||
void SetMozAllowCasting(bool aShow)
|
||||
{
|
||||
mAllowCasting = aShow;
|
||||
}
|
||||
|
||||
bool MozIsCasting() const
|
||||
{
|
||||
return mIsCasting;
|
||||
}
|
||||
|
||||
void SetMozIsCasting(bool aShow)
|
||||
{
|
||||
mIsCasting = aShow;
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream> GetMozSrcObject() const;
|
||||
|
||||
void SetMozSrcObject(DOMMediaStream& aValue);
|
||||
@ -1093,6 +1113,14 @@ protected:
|
||||
// video controls
|
||||
bool mStatsShowing;
|
||||
|
||||
// The following two fields are here for the private storage of the builtin
|
||||
// video controls, and control 'casting' of the video to external devices
|
||||
// (TVs, projectors etc.)
|
||||
// True if casting is currently allowed
|
||||
bool mAllowCasting;
|
||||
// True if currently casting this video
|
||||
bool mIsCasting;
|
||||
|
||||
// True if the sound is being captured.
|
||||
bool mAudioCaptured;
|
||||
|
||||
|
@ -1992,6 +1992,8 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<nsINodeInfo>& aNodeInfo)
|
||||
mPaused(true),
|
||||
mMuted(0),
|
||||
mStatsShowing(false),
|
||||
mAllowCasting(false),
|
||||
mIsCasting(false),
|
||||
mAudioCaptured(false),
|
||||
mPlayingBeforeSeek(false),
|
||||
mPausedForInactiveDocumentOrChannel(false),
|
||||
|
@ -104,6 +104,8 @@ partial interface HTMLMediaElement {
|
||||
|
||||
// NB: for internal use with the video controls:
|
||||
[Func="IsChromeOrXBL"] attribute boolean mozMediaStatisticsShowing;
|
||||
[Func="IsChromeOrXBL"] attribute boolean mozAllowCasting;
|
||||
[Func="IsChromeOrXBL"] attribute boolean mozIsCasting;
|
||||
|
||||
// Mozilla extension: stream capture
|
||||
[Throws]
|
||||
|
@ -487,7 +487,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT);
|
||||
}
|
||||
|
||||
((GeckoApp.MainLayout) mMainLayout).setTouchEventInterceptor(new HideTabsTouchListener());
|
||||
((GeckoApp.MainLayout) mMainLayout).setTouchEventInterceptor(new HideOnTouchListener());
|
||||
((GeckoApp.MainLayout) mMainLayout).setMotionEventInterceptor(new MotionEventInterceptor() {
|
||||
@Override
|
||||
public boolean onInterceptMotionEvent(View view, MotionEvent event) {
|
||||
@ -1985,11 +1985,20 @@ abstract public class BrowserApp extends GeckoApp
|
||||
mBrowserSearch.setUserVisibleHint(false);
|
||||
}
|
||||
|
||||
private class HideTabsTouchListener implements TouchEventInterceptor {
|
||||
/**
|
||||
* Hides certain UI elements (e.g. button toast, tabs tray) when the
|
||||
* user touches the main layout.
|
||||
*/
|
||||
private class HideOnTouchListener implements TouchEventInterceptor {
|
||||
private boolean mIsHidingTabs = false;
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(View view, MotionEvent event) {
|
||||
// Only try to hide the button toast if it's already inflated.
|
||||
if (mToast != null) {
|
||||
mToast.hide(false, ButtonToast.ReasonHidden.TOUCH_OUTSIDE);
|
||||
}
|
||||
|
||||
// We need to account for scroll state for the touched view otherwise
|
||||
// tapping on an "empty" part of the view will still be considered a
|
||||
// valid touch event.
|
||||
@ -2627,10 +2636,25 @@ abstract public class BrowserApp extends GeckoApp
|
||||
*/
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
String action = intent.getAction();
|
||||
|
||||
final boolean isViewAction = Intent.ACTION_VIEW.equals(action);
|
||||
final boolean isBookmarkAction = GeckoApp.ACTION_BOOKMARK.equals(action);
|
||||
|
||||
if (mInitialized && (isViewAction || isBookmarkAction)) {
|
||||
// Dismiss editing mode if the user is loading a URL from an external app.
|
||||
mBrowserToolbar.cancelEdit();
|
||||
|
||||
// GeckoApp.ACTION_BOOKMARK means we're opening a bookmark that
|
||||
// was added to Android's homescreen.
|
||||
final TelemetryContract.Method method =
|
||||
(isViewAction ? TelemetryContract.Method.INTENT : TelemetryContract.Method.HOMESCREEN);
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, method);
|
||||
}
|
||||
|
||||
super.onNewIntent(intent);
|
||||
|
||||
if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 10 && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
|
||||
String uri = intent.getDataString();
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(uri));
|
||||
@ -2640,14 +2664,6 @@ abstract public class BrowserApp extends GeckoApp
|
||||
return;
|
||||
}
|
||||
|
||||
if (Intent.ACTION_VIEW.equals(action)) {
|
||||
// Dismiss editing mode if the user is loading a URL from an external app.
|
||||
mBrowserToolbar.cancelEdit();
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only solicit feedback when the app has been launched from the icon shortcut.
|
||||
if (!Intent.ACTION_MAIN.equals(action)) {
|
||||
return;
|
||||
|
@ -126,6 +126,9 @@ public interface TelemetryContract {
|
||||
// Action occurred via an intent.
|
||||
INTENT("intent"),
|
||||
|
||||
// Action occurred via a homescreen launcher.
|
||||
HOMESCREEN("homescreen"),
|
||||
|
||||
// Action triggered from a list.
|
||||
LIST("list"),
|
||||
|
||||
|
@ -119,6 +119,12 @@ public class AnnouncementsBroadcastService extends BackgroundService {
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
Logger.setThreadLogTag(AnnouncementsConstants.GLOBAL_LOG_TAG);
|
||||
|
||||
// Intent can be null. Bug 1025937.
|
||||
if (intent == null) {
|
||||
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
|
||||
}
|
||||
|
||||
final String action = intent.getAction();
|
||||
Logger.debug(LOG_TAG, "Broadcast onReceive. Intent is " + action);
|
||||
|
||||
@ -143,8 +149,10 @@ public class AnnouncementsBroadcastService extends BackgroundService {
|
||||
* Handle the intent sent by the browser when it wishes to notify us
|
||||
* of the value of the user preference. Look at the value and toggle the
|
||||
* alarm service accordingly.
|
||||
*
|
||||
* @param intent must be non-null.
|
||||
*/
|
||||
protected void handlePrefIntent(Intent intent) {
|
||||
private void handlePrefIntent(Intent intent) {
|
||||
if (!intent.hasExtra("enabled")) {
|
||||
Logger.warn(LOG_TAG, "Got ANNOUNCEMENTS_PREF intent without enabled. Ignoring.");
|
||||
return;
|
||||
|
@ -117,6 +117,12 @@ public class AnnouncementsService extends BackgroundService implements Announcem
|
||||
@Override
|
||||
public void onHandleIntent(Intent intent) {
|
||||
Logger.setThreadLogTag(AnnouncementsConstants.GLOBAL_LOG_TAG);
|
||||
|
||||
// Intent can be null. Bug 1025937.
|
||||
if (intent == null) {
|
||||
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
|
||||
}
|
||||
|
||||
Logger.debug(LOG_TAG, "Running AnnouncementsService.");
|
||||
|
||||
if (AnnouncementsConstants.DISABLED) {
|
||||
|
@ -100,6 +100,11 @@ public class HealthReportBroadcastService extends BackgroundService {
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
Logger.setThreadLogTag(HealthReportConstants.GLOBAL_LOG_TAG);
|
||||
|
||||
// Intent can be null. Bug 1025937.
|
||||
if (intent == null) {
|
||||
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
|
||||
}
|
||||
|
||||
// The same intent can be handled by multiple methods so do not short-circuit evaluate.
|
||||
boolean handled = attemptHandleIntentForUpload(intent);
|
||||
handled = attemptHandleIntentForPrune(intent) ? true : handled;
|
||||
@ -111,8 +116,10 @@ public class HealthReportBroadcastService extends BackgroundService {
|
||||
|
||||
/**
|
||||
* Attempts to handle the given intent for FHR document upload. If it cannot, false is returned.
|
||||
*
|
||||
* @param intent must be non-null.
|
||||
*/
|
||||
protected boolean attemptHandleIntentForUpload(final Intent intent) {
|
||||
private boolean attemptHandleIntentForUpload(final Intent intent) {
|
||||
if (HealthReportConstants.UPLOAD_FEATURE_DISABLED) {
|
||||
Logger.debug(LOG_TAG, "Health report upload feature is compile-time disabled; not handling intent.");
|
||||
return false;
|
||||
@ -142,8 +149,10 @@ public class HealthReportBroadcastService extends BackgroundService {
|
||||
* Handle the intent sent by the browser when it wishes to notify us
|
||||
* of the value of the user preference. Look at the value and toggle the
|
||||
* alarm service accordingly.
|
||||
*
|
||||
* @param intent must be non-null.
|
||||
*/
|
||||
protected void handleUploadPrefIntent(Intent intent) {
|
||||
private void handleUploadPrefIntent(Intent intent) {
|
||||
if (!intent.hasExtra("enabled")) {
|
||||
Logger.warn(LOG_TAG, "Got " + HealthReportConstants.ACTION_HEALTHREPORT_UPLOAD_PREF + " intent without enabled. Ignoring.");
|
||||
return;
|
||||
@ -194,8 +203,10 @@ public class HealthReportBroadcastService extends BackgroundService {
|
||||
|
||||
/**
|
||||
* Attempts to handle the given intent for FHR data pruning. If it cannot, false is returned.
|
||||
*
|
||||
* @param intent must be non-null.
|
||||
*/
|
||||
protected boolean attemptHandleIntentForPrune(final Intent intent) {
|
||||
private boolean attemptHandleIntentForPrune(final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
Logger.debug(LOG_TAG, "Prune: Attempting to handle intent with action, " + action + ".");
|
||||
|
||||
@ -215,7 +226,10 @@ public class HealthReportBroadcastService extends BackgroundService {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void handlePruneIntent(final Intent intent) {
|
||||
/**
|
||||
* @param intent must be non-null.
|
||||
*/
|
||||
private void handlePruneIntent(final Intent intent) {
|
||||
final String profileName = intent.getStringExtra("profileName");
|
||||
final String profilePath = intent.getStringExtra("profilePath");
|
||||
|
||||
|
@ -39,6 +39,12 @@ public class HealthReportPruneService extends BackgroundService {
|
||||
@Override
|
||||
public void onHandleIntent(Intent intent) {
|
||||
Logger.setThreadLogTag(HealthReportConstants.GLOBAL_LOG_TAG);
|
||||
|
||||
// Intent can be null. Bug 1025937.
|
||||
if (intent == null) {
|
||||
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
|
||||
}
|
||||
|
||||
Logger.debug(LOG_TAG, "Handling prune intent.");
|
||||
|
||||
if (!isIntentValid(intent)) {
|
||||
@ -59,7 +65,11 @@ public class HealthReportPruneService extends BackgroundService {
|
||||
return new PrunePolicy(storage, getSharedPreferences());
|
||||
}
|
||||
|
||||
protected boolean isIntentValid(final Intent intent) {
|
||||
/**
|
||||
* @param intent must be non-null.
|
||||
* @return true if the supplied intent contains both profileName and profilePath.
|
||||
*/
|
||||
private static boolean isIntentValid(final Intent intent) {
|
||||
boolean isValid = true;
|
||||
|
||||
final String profileName = intent.getStringExtra("profileName");
|
||||
|
@ -43,6 +43,11 @@ public class HealthReportUploadService extends BackgroundService {
|
||||
public void onHandleIntent(Intent intent) {
|
||||
Logger.setThreadLogTag(HealthReportConstants.GLOBAL_LOG_TAG);
|
||||
|
||||
// Intent can be null. Bug 1025937.
|
||||
if (intent == null) {
|
||||
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
|
||||
}
|
||||
|
||||
if (HealthReportConstants.UPLOAD_FEATURE_DISABLED) {
|
||||
Logger.debug(LOG_TAG, "Health report upload feature is compile-time disabled; not handling upload intent.");
|
||||
return;
|
||||
|
@ -29,6 +29,11 @@ public class FxAccountDeletedService extends IntentService {
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(final Intent intent) {
|
||||
// Intent can, in theory, be null. Bug 1025937.
|
||||
if (intent == null) {
|
||||
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
|
||||
}
|
||||
|
||||
final Context context = this;
|
||||
|
||||
long intentVersion = intent.getLongExtra(
|
||||
|
@ -371,6 +371,10 @@ size. -->
|
||||
previous location in the navigation, such as the previous folder -->
|
||||
<!ENTITY home_move_up_to_filter "Up to &formatS;">
|
||||
|
||||
<!ENTITY private_browsing_title "Private Browsing">
|
||||
<!ENTITY private_tabs_panel_description "Your private tabs will show up here. While we don\'t keep any form of your browsing history or cookies, files that you download will still be saved on your device.">
|
||||
<!ENTITY private_tabs_panel_learn_more "Want to learn more?">
|
||||
|
||||
<!ENTITY pin_site_dialog_hint "Enter a search keyword">
|
||||
|
||||
<!ENTITY filepicker_title "Choose File">
|
||||
|
@ -372,6 +372,7 @@ gbjar.sources += [
|
||||
'Tab.java',
|
||||
'Tabs.java',
|
||||
'TabsAccessor.java',
|
||||
'tabspanel/PrivateTabsPanel.java',
|
||||
'tabspanel/RemoteTabsContainerPanel.java',
|
||||
'tabspanel/RemoteTabsList.java',
|
||||
'tabspanel/RemoteTabsPanel.java',
|
||||
|
@ -40,13 +40,11 @@
|
||||
android:visibility="gone"
|
||||
gecko:tabs="tabs_normal"/>
|
||||
|
||||
<org.mozilla.gecko.tabspanel.TabsTray android:id="@+id/private_tabs"
|
||||
style="@style/TabsList"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:choiceMode="singleChoice"
|
||||
android:visibility="gone"
|
||||
gecko:tabs="tabs_private"/>
|
||||
<org.mozilla.gecko.tabspanel.PrivateTabsPanel
|
||||
android:id="@+id/private_tabs_panel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<org.mozilla.gecko.tabspanel.RemoteTabsPanel
|
||||
android:id="@+id/remote_tabs"
|
||||
|
50
mobile/android/base/resources/layout/private_tabs_panel.xml
Normal file
50
mobile/android/base/resources/layout/private_tabs_panel.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<org.mozilla.gecko.tabspanel.TabsTray android:id="@+id/private_tabs_tray"
|
||||
style="@style/TabsList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:choiceMode="singleChoice"
|
||||
gecko:tabs="tabs_private"/>
|
||||
|
||||
<LinearLayout android:id="@+id/private_tabs_empty"
|
||||
style="@style/TabsPanelFrame.PrivateTabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout style="@style/TabsPanelSection.PrivateTabs.Header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView style="@style/TabsPanelItem.TextAppearance.Header.PrivateTabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/private_browsing_title"/>
|
||||
|
||||
<TextView style="@style/TabsPanelItem.TextAppearance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/private_tabs_panel_description"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/TabsPanelSection.PrivateTabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView android:id="@+id/private_tabs_learn_more"
|
||||
style="@style/TabsPanelItem.TextAppearance.Linkified.LearnMore"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/private_tabs_panel_learn_more"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
@ -10,27 +10,27 @@
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout android:id="@+id/remote_tabs_setup_containing_layout"
|
||||
style="@style/RemoteTabsPanelChild"
|
||||
style="@style/TabsPanelFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout style="@style/RemoteTabsSection"
|
||||
<LinearLayout style="@style/TabsPanelSection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView style="@style/RemoteTabsItem.TextAppearance.Header"
|
||||
<TextView style="@style/TabsPanelItem.TextAppearance.Header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fxaccount_getting_started_welcome_to_sync"/>
|
||||
|
||||
<TextView style="@style/RemoteTabsItem.TextAppearance"
|
||||
<TextView style="@style/TabsPanelItem.TextAppearance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fxaccount_getting_started_description"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/RemoteTabsSection"
|
||||
<LinearLayout style="@style/TabsPanelSection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/RemoteTabsItem.Button"
|
||||
style="@style/TabsPanelItem.Button"
|
||||
android:text="@string/fxaccount_getting_started_get_started"
|
||||
android:layout_marginBottom="15dp"/>
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/RemoteTabsItem.TextAppearance.Linkified"
|
||||
style="@style/TabsPanelItem.TextAppearance.Linkified"
|
||||
android:text="@string/fxaccount_getting_started_old_firefox"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -10,40 +10,40 @@
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout android:id="@+id/remote_tabs_verification_containing_layout"
|
||||
style="@style/RemoteTabsPanelChild"
|
||||
style="@style/TabsPanelFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout style="@style/RemoteTabsSection"
|
||||
<LinearLayout style="@style/TabsPanelSection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView style="@style/RemoteTabsItem.TextAppearance.Header.FXAccounts"
|
||||
<TextView style="@style/TabsPanelItem.TextAppearance.Header.FXAccounts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fxaccount_full_label"
|
||||
android:layout_marginBottom="0dp"/>
|
||||
|
||||
<TextView style="@style/RemoteTabsItem.TextAppearance.Header"
|
||||
<TextView style="@style/TabsPanelItem.TextAppearance.Header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fxaccount_confirm_account_header"
|
||||
android:layout_marginTop="0dp"/>
|
||||
|
||||
<TextView android:id="@+id/remote_tabs_confirm_verification"
|
||||
style="@style/RemoteTabsItem.TextAppearance"
|
||||
style="@style/TabsPanelItem.TextAppearance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fxaccount_confirm_account_verification_link"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/RemoteTabsSection"
|
||||
<LinearLayout style="@style/TabsPanelSection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView android:id="@+id/remote_tabs_confirm_resend"
|
||||
style="@style/RemoteTabsItem.TextAppearance.Linkified.Resend"
|
||||
style="@style/TabsPanelItem.TextAppearance.Linkified.Resend"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/fxaccount_confirm_account_resend_email"/>
|
||||
|
||||
|
@ -39,13 +39,11 @@
|
||||
android:visibility="gone"
|
||||
gecko:tabs="tabs_normal"/>
|
||||
|
||||
<org.mozilla.gecko.tabspanel.TabsTray android:id="@+id/private_tabs"
|
||||
style="@style/TabsList"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:choiceMode="singleChoice"
|
||||
android:visibility="gone"
|
||||
gecko:tabs="tabs_private"/>
|
||||
<org.mozilla.gecko.tabspanel.PrivateTabsPanel
|
||||
android:id="@+id/private_tabs_panel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<org.mozilla.gecko.tabspanel.RemoteTabsPanel
|
||||
android:id="@+id/remote_tabs"
|
||||
|
@ -17,23 +17,31 @@
|
||||
<item name="android:nextFocusUp">@+id/info</item>
|
||||
</style>
|
||||
|
||||
<!-- Remote tabs panel -->
|
||||
<style name="RemoteTabsPanelChild" parent="RemoteTabsPanelChildBase">
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelFrame" parent="TabsPanelFrameBase">
|
||||
<item name="android:orientation">horizontal</item>
|
||||
<item name="android:paddingTop">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsSection" parent="RemoteTabsSectionBase">
|
||||
<style name="TabsPanelFrame.PrivateTabs">
|
||||
<item name="android:paddingTop">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
|
||||
<item name="android:layout_weight">1</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem">
|
||||
<style name="TabsPanelSection.PrivateTabs.Header">
|
||||
<item name="android:paddingTop">18dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem">
|
||||
<item name="android:layout_marginBottom">20dp</item>
|
||||
<item name="android:layout_gravity">left</item>
|
||||
<item name="android:gravity">left</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.Button" parent="RemoteTabsItem.ButtonBase">
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
<item name="android:paddingLeft">6dp</item>
|
||||
@ -42,11 +50,21 @@
|
||||
<item name="android:layout_marginRight">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Header.FXAccounts">
|
||||
<style name="TabsPanelItem.TextAppearance.Header.FXAccounts">
|
||||
<item name="android:visibility">gone</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Linkified.Resend">
|
||||
<style name="TabsPanelItem.TextAppearance.Header.PrivateTabs">
|
||||
<item name="android:visibility">gone</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified.Resend">
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
|
@ -51,23 +51,36 @@
|
||||
<item name="android:paddingTop">30dp</item>
|
||||
</style>
|
||||
|
||||
<!-- Remote tabs panel -->
|
||||
<style name="RemoteTabsPanelChild" parent="RemoteTabsPanelChildBase">
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelFrame" parent="TabsPanelFrameBase">
|
||||
<item name="android:paddingTop">32dp</item>
|
||||
<!-- Additional spacing set via margins on RemoteTabsSection. -->
|
||||
<!-- Additional spacing set via margins on TabsPanelSection. -->
|
||||
<item name="android:paddingLeft">0dp</item>
|
||||
<item name="android:paddingRight">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsSection" parent="RemoteTabsSectionBase">
|
||||
<style name="TabsPanelFrame.PrivateTabs">
|
||||
<!-- We set values in tablet portrait. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
|
||||
<!-- To override the values-land style. -->
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem" parent="RemoteTabsItemBase">
|
||||
<style name="TabsPanelSection.PrivateTabs">
|
||||
<!-- We set values in tablet portrait. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection.PrivateTabs.Header">
|
||||
<!-- We set values in tablet portrait. -->
|
||||
</style>
|
||||
|
||||
|
||||
<style name="TabsPanelItem" parent="TabsPanelItemBase">
|
||||
<!-- To override the values-land style. -->
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.Button" parent="RemoteTabsItem.ButtonBase">
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
<item name="android:paddingLeft">6dp</item>
|
||||
@ -77,11 +90,19 @@
|
||||
<item name="android:textSize">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Header.FXAccounts">
|
||||
<style name="TabsPanelItem.TextAppearance.Header.FXAccounts">
|
||||
<item name="android:visibility">gone</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Linkified.Resend">
|
||||
<style name="TabsPanelItem.TextAppearance.Header.PrivateTabs">
|
||||
<item name="android:visibility">visible</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified.Resend">
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
</style>
|
||||
|
||||
|
@ -94,12 +94,36 @@
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="RemoteTabsPanelChild" parent="RemoteTabsPanelChildBase">
|
||||
<style name="TabsPanelFrame.PrivateTabs">
|
||||
<item name="android:orientation">horizontal</item>
|
||||
<item name="android:paddingTop">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection.PrivateTabs">
|
||||
<item name="android:layout_weight">1</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection.PrivateTabs.Header">
|
||||
<item name="android:paddingTop">32dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Header.PrivateTabs">
|
||||
<item name="android:visibility">gone</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelFrame" parent="TabsPanelFrameBase">
|
||||
<item name="android:paddingLeft">84dp</item>
|
||||
<item name="android:paddingRight">84dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.Button" parent="RemoteTabsItem.ButtonBase">
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">18dp</item>
|
||||
<item name="android:paddingBottom">18dp</item>
|
||||
<item name="android:paddingLeft">9dp</item>
|
||||
|
@ -29,7 +29,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="RemoteTabsItem.Button" parent="RemoteTabsItem.ButtonBase">
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
<item name="android:paddingLeft">6dp</item>
|
||||
|
@ -31,7 +31,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="RemoteTabsItem.Button" parent="RemoteTabsItem.ButtonBase">
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">18dp</item>
|
||||
<item name="android:paddingBottom">18dp</item>
|
||||
<item name="android:paddingLeft">9dp</item>
|
||||
|
@ -448,46 +448,58 @@
|
||||
<item name="android:groupIndicator">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<!-- Remote tabs panel -->
|
||||
<style name="RemoteTabsPanelChildBase">
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelFrameBase">
|
||||
<item name="android:paddingLeft">16dp</item>
|
||||
<item name="android:paddingRight">16dp</item>
|
||||
<item name="android:paddingTop">32dp</item>
|
||||
<item name="android:orientation">vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsPanelChild" parent="RemoteTabsPanelChildBase">
|
||||
<style name="TabsPanelFrame" parent="TabsPanelFrameBase">
|
||||
<!-- We set values in landscape. -->
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsSectionBase">
|
||||
<style name="TabsPanelFrame.PrivateTabs">
|
||||
<!-- We set values on tablet. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSectionBase">
|
||||
<item name="android:orientation">vertical</item>
|
||||
<item name="android:layout_marginLeft">16dp</item>
|
||||
<item name="android:layout_marginRight">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsSection" parent="RemoteTabsSectionBase">
|
||||
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
|
||||
<!-- We set values in landscape. -->
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItemBase">
|
||||
<style name="TabsPanelSection.PrivateTabs">
|
||||
<!-- We set values on tablet. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection.PrivateTabs.Header">
|
||||
<!-- We set values on landscape and tablet. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItemBase">
|
||||
<item name="android:layout_marginBottom">28dp</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
<item name="android:gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem" parent="RemoteTabsItemBase">
|
||||
<style name="TabsPanelItem" parent="TabsPanelItemBase">
|
||||
<!-- We set values in landscape. -->
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.ButtonBase">
|
||||
<style name="TabsPanelItem.ButtonBase">
|
||||
<item name="android:background">@drawable/remote_tabs_setup_button_background</item>
|
||||
<item name="android:textColor">#FFFEFF</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
<item name="android:gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.Button" parent="RemoteTabsItem.ButtonBase">
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">18dp</item>
|
||||
<item name="android:paddingBottom">18dp</item>
|
||||
<item name="android:paddingLeft">9dp</item>
|
||||
@ -496,26 +508,34 @@
|
||||
<item name="android:layout_marginRight">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance">
|
||||
<style name="TabsPanelItem.TextAppearance">
|
||||
<item name="android:textColor">#C0C9D0</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Header">
|
||||
<style name="TabsPanelItem.TextAppearance.Header">
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Header.FXAccounts">
|
||||
<style name="TabsPanelItem.TextAppearance.Header.FXAccounts">
|
||||
<!-- We change these values on landscape. -->
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Linkified">
|
||||
<style name="TabsPanelItem.TextAppearance.Header.PrivateTabs">
|
||||
<!-- We change these values on landscape and tablet. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified">
|
||||
<item name="android:clickable">true</item>
|
||||
<item name="android:focusable">true</item>
|
||||
<item name="android:textColor">#0292D6</item>
|
||||
</style>
|
||||
|
||||
<style name="RemoteTabsItem.TextAppearance.Linkified.Resend">
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified.Resend">
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
</style>
|
||||
|
||||
|
@ -322,6 +322,11 @@
|
||||
<string name="home_reading_list_hint_accessible">&home_reading_list_hint_accessible;</string>
|
||||
<string name="home_default_empty">&home_default_empty;</string>
|
||||
<string name="home_move_up_to_filter">&home_move_up_to_filter;</string>
|
||||
<string name="private_browsing_title">&private_browsing_title;</string>
|
||||
<string name="private_tabs_panel_description">&private_tabs_panel_description;</string>
|
||||
<string name="private_tabs_panel_learn_more">&private_tabs_panel_learn_more;</string>
|
||||
<!-- https://support.mozilla.org/%LOCALE%/kb/mobile-private-browsing-browse-web-without-saving-syncing-info -->
|
||||
<string name="private_tabs_panel_learn_more_link">https://support.mozilla.org/&formatS1;/kb/mobile-private-browsing-browse-web-without-saving-syncing-info</string>
|
||||
<string name="pin_site_dialog_hint">&pin_site_dialog_hint;</string>
|
||||
|
||||
<string name="filepicker_title">&filepicker_title;</string>
|
||||
|
@ -32,6 +32,11 @@ public class SyncAccountDeletedService extends IntentService {
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
// Intent can, in theory, be null. Bug 1025937.
|
||||
if (intent == null) {
|
||||
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
|
||||
}
|
||||
|
||||
final Context context = this;
|
||||
|
||||
long intentVersion = intent.getLongExtra(Constants.JSON_KEY_VERSION, 0);
|
||||
|
77
mobile/android/base/tabspanel/PrivateTabsPanel.java
Normal file
77
mobile/android/base/tabspanel/PrivateTabsPanel.java
Normal file
@ -0,0 +1,77 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.tabspanel;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.mozilla.gecko.BrowserLocaleManager;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.tabspanel.TabsPanel.PanelView;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* A container that wraps the private tabs {@link android.widget.AdapterView} and empty
|
||||
* {@link android.view.View} to manage both of their visibility states by changing the visibility of
|
||||
* this container as calling {@link android.widget.AdapterView#setVisibility} does not affect the
|
||||
* empty View's visibility.
|
||||
*/
|
||||
class PrivateTabsPanel extends FrameLayout implements PanelView {
|
||||
private TabsPanel tabsPanel;
|
||||
private TabsTray tabsTray;
|
||||
|
||||
public PrivateTabsPanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.private_tabs_panel, this);
|
||||
tabsTray = (TabsTray) findViewById(R.id.private_tabs_tray);
|
||||
|
||||
final View emptyView = findViewById(R.id.private_tabs_empty);
|
||||
tabsTray.setEmptyView(emptyView);
|
||||
|
||||
final View learnMore = findViewById(R.id.private_tabs_learn_more);
|
||||
learnMore.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final String locale = BrowserLocaleManager.getLanguageTag(Locale.getDefault());
|
||||
final String url =
|
||||
getResources().getString(R.string.private_tabs_panel_learn_more_link, locale);
|
||||
Tabs.getInstance().loadUrlInTab(url);
|
||||
if (tabsPanel != null) {
|
||||
tabsPanel.autoHidePanel();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTabsPanel(TabsPanel panel) {
|
||||
tabsPanel = panel;
|
||||
tabsTray.setTabsPanel(panel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
tabsTray.show();
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
setVisibility(View.GONE);
|
||||
tabsTray.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExpand() {
|
||||
return tabsTray.shouldExpand();
|
||||
}
|
||||
}
|
@ -120,7 +120,7 @@ public class TabsPanel extends LinearLayout
|
||||
mPanelNormal = (PanelView) findViewById(R.id.normal_tabs);
|
||||
mPanelNormal.setTabsPanel(this);
|
||||
|
||||
mPanelPrivate = (PanelView) findViewById(R.id.private_tabs);
|
||||
mPanelPrivate = (PanelView) findViewById(R.id.private_tabs_panel);
|
||||
mPanelPrivate.setTabsPanel(this);
|
||||
|
||||
mPanelRemote = (PanelView) findViewById(R.id.remote_tabs);
|
||||
|
@ -42,6 +42,7 @@ public class ButtonToast {
|
||||
|
||||
public enum ReasonHidden {
|
||||
CLICKED,
|
||||
TOUCH_OUTSIDE,
|
||||
TIMEOUT,
|
||||
REPLACED,
|
||||
STARTUP
|
||||
@ -129,6 +130,11 @@ public class ButtonToast {
|
||||
}
|
||||
|
||||
public void hide(boolean immediate, ReasonHidden reason) {
|
||||
// There's nothing to do if the view is already hidden.
|
||||
if (mView.getVisibility() == View.GONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentToast != null && mCurrentToast.listener != null) {
|
||||
mCurrentToast.listener.onToastHidden(reason);
|
||||
}
|
||||
|
@ -13,6 +13,18 @@ var rokuTarget = {
|
||||
}
|
||||
};
|
||||
|
||||
var fireflyTarget = {
|
||||
target: "urn:dial-multiscreen-org:service:dial:1",
|
||||
filters: {
|
||||
server: null,
|
||||
modelName: "Eureka Dongle"
|
||||
},
|
||||
factory: function(aService) {
|
||||
Cu.import("resource://gre/modules/FireflyApp.jsm");
|
||||
return new FireflyApp(aService);
|
||||
}
|
||||
};
|
||||
|
||||
var CastingApps = {
|
||||
_castMenuId: -1,
|
||||
|
||||
@ -23,6 +35,7 @@ var CastingApps = {
|
||||
|
||||
// Register targets
|
||||
SimpleServiceDiscovery.registerTarget(rokuTarget);
|
||||
SimpleServiceDiscovery.registerTarget(fireflyTarget);
|
||||
|
||||
// Search for devices continuously every 120 seconds
|
||||
SimpleServiceDiscovery.search(120 * 1000);
|
||||
@ -250,8 +263,7 @@ var CastingApps = {
|
||||
// Look for a castable <video> that is playing, and start casting it
|
||||
let videos = browser.contentDocument.querySelectorAll("video");
|
||||
for (let video of videos) {
|
||||
let unwrappedVideo = XPCNativeWrapper.unwrap(video);
|
||||
if (!video.paused && unwrappedVideo.mozAllowCasting) {
|
||||
if (!video.paused && video.mozAllowCasting) {
|
||||
UITelemetry.addEvent("cast.1", "pageaction", null);
|
||||
CastingApps.openExternal(video, 0, 0);
|
||||
return;
|
||||
@ -270,13 +282,12 @@ var CastingApps = {
|
||||
let castableVideo = null;
|
||||
let videos = aBrowser.contentDocument.querySelectorAll("video");
|
||||
for (let video of videos) {
|
||||
let unwrappedVideo = XPCNativeWrapper.unwrap(video);
|
||||
if (unwrappedVideo.mozIsCasting) {
|
||||
if (video.mozIsCasting) {
|
||||
// This <video> is cast-active. Break out of loop.
|
||||
return video;
|
||||
}
|
||||
|
||||
if (!video.paused && unwrappedVideo.mozAllowCasting) {
|
||||
if (!video.paused && video.mozAllowCasting) {
|
||||
// This <video> is cast-ready. Keep looking so cast-active could be found.
|
||||
castableVideo = video;
|
||||
}
|
||||
@ -324,15 +335,14 @@ var CastingApps = {
|
||||
// 1. The video is actively being cast
|
||||
// 2. The video is allowed to be cast and is currently playing
|
||||
// Both states have the same action: Show the cast page action
|
||||
let unwrappedVideo = XPCNativeWrapper.unwrap(aVideo);
|
||||
if (unwrappedVideo.mozIsCasting) {
|
||||
if (aVideo.mozIsCasting) {
|
||||
this.pageAction.id = NativeWindow.pageactions.add({
|
||||
title: Strings.browser.GetStringFromName("contextmenu.castToScreen"),
|
||||
icon: "drawable://casting_active",
|
||||
clickCallback: this.pageAction.click,
|
||||
important: true
|
||||
});
|
||||
} else if (unwrappedVideo.mozAllowCasting) {
|
||||
} else if (aVideo.mozAllowCasting) {
|
||||
this.pageAction.id = NativeWindow.pageactions.add({
|
||||
title: Strings.browser.GetStringFromName("contextmenu.castToScreen"),
|
||||
icon: "drawable://casting",
|
||||
@ -363,6 +373,7 @@ var CastingApps = {
|
||||
},
|
||||
|
||||
handleContextMenu: function(aElement, aX, aY) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_cast");
|
||||
UITelemetry.addEvent("cast.1", "contextmenu", null);
|
||||
this.openExternal(aElement, aX, aY);
|
||||
},
|
||||
|
@ -482,6 +482,9 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.openInNewTab"),
|
||||
NativeWindow.contextmenus.linkOpenableNonPrivateContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_open_new_tab");
|
||||
UITelemetry.addEvent("loadurl.1", "contextmenu", null);
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
ContentAreaUtils.urlSecurityCheck(url, aTarget.ownerDocument.nodePrincipal);
|
||||
let tab = BrowserApp.addTab(url, { selected: false, parentId: BrowserApp.selectedTab.id });
|
||||
@ -501,6 +504,9 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.openInPrivateTab"),
|
||||
NativeWindow.contextmenus.linkOpenableContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_open_private_tab");
|
||||
UITelemetry.addEvent("loadurl.1", "contextmenu", null);
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
ContentAreaUtils.urlSecurityCheck(url, aTarget.ownerDocument.nodePrincipal);
|
||||
let tab = BrowserApp.addTab(url, { selected: false, parentId: BrowserApp.selectedTab.id, isPrivate: true });
|
||||
@ -520,6 +526,8 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.copyLink"),
|
||||
NativeWindow.contextmenus.linkCopyableContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_copy_link");
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
NativeWindow.contextmenus._copyStringToDefaultClipboard(url);
|
||||
});
|
||||
@ -527,6 +535,8 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.copyEmailAddress"),
|
||||
NativeWindow.contextmenus.emailLinkContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_copy_email");
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let emailAddr = NativeWindow.contextmenus._stripScheme(url);
|
||||
NativeWindow.contextmenus._copyStringToDefaultClipboard(emailAddr);
|
||||
@ -535,6 +545,8 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.copyPhoneNumber"),
|
||||
NativeWindow.contextmenus.phoneNumberLinkContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_copy_phone");
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let phoneNumber = NativeWindow.contextmenus._stripScheme(url);
|
||||
NativeWindow.contextmenus._copyStringToDefaultClipboard(phoneNumber);
|
||||
@ -551,7 +563,9 @@ var BrowserApp = {
|
||||
};
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) { }
|
||||
callback: function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_share_link");
|
||||
}
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add({
|
||||
@ -568,7 +582,9 @@ var BrowserApp = {
|
||||
};
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) { }
|
||||
callback: function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_share_email");
|
||||
}
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add({
|
||||
@ -585,12 +601,16 @@ var BrowserApp = {
|
||||
};
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) { }
|
||||
callback: function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_share_phone");
|
||||
}
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.addToContacts"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.emailLinkContext),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_contact_email");
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
sendMessageToJava({
|
||||
type: "Contact:Add",
|
||||
@ -601,6 +621,8 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.addToContacts"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.phoneNumberLinkContext),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_contact_phone");
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
sendMessageToJava({
|
||||
type: "Contact:Add",
|
||||
@ -611,6 +633,8 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.bookmarkLink"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.linkBookmarkableContext),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_bookmark");
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let title = aTarget.textContent || aTarget.title || url;
|
||||
sendMessageToJava({
|
||||
@ -623,18 +647,21 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.playMedia"),
|
||||
NativeWindow.contextmenus.mediaContext("media-paused"),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_play");
|
||||
aTarget.play();
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.pauseMedia"),
|
||||
NativeWindow.contextmenus.mediaContext("media-playing"),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_pause");
|
||||
aTarget.pause();
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.showControls2"),
|
||||
NativeWindow.contextmenus.mediaContext("media-hidingcontrols"),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_controls_media");
|
||||
aTarget.setAttribute("controls", true);
|
||||
});
|
||||
|
||||
@ -653,30 +680,36 @@ var BrowserApp = {
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_share_media");
|
||||
}
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.fullScreen"),
|
||||
NativeWindow.contextmenus.SelectorContext("video:not(:-moz-full-screen)"),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_fullscreen");
|
||||
aTarget.mozRequestFullScreen();
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.mute"),
|
||||
NativeWindow.contextmenus.mediaContext("media-unmuted"),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_mute");
|
||||
aTarget.muted = true;
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.unmute"),
|
||||
NativeWindow.contextmenus.mediaContext("media-muted"),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_unmute");
|
||||
aTarget.muted = false;
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.copyImageLocation"),
|
||||
NativeWindow.contextmenus.imageLocationCopyableContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_copy_image");
|
||||
|
||||
let url = aTarget.src;
|
||||
NativeWindow.contextmenus._copyStringToDefaultClipboard(url);
|
||||
});
|
||||
@ -699,12 +732,16 @@ var BrowserApp = {
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
menu: true,
|
||||
callback: function(aTarget) { }
|
||||
callback: function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_share_image");
|
||||
}
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.saveImage"),
|
||||
NativeWindow.contextmenus.imageSaveableContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_save_image");
|
||||
|
||||
ContentAreaUtils.saveImageURL(aTarget.currentURI.spec, null, "SaveImageTitle",
|
||||
false, true, aTarget.ownerDocument.documentURIObject,
|
||||
aTarget.ownerDocument);
|
||||
@ -713,6 +750,8 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.setImageAs"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.imageSaveableContext),
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_background_image");
|
||||
|
||||
let src = aTarget.src;
|
||||
sendMessageToJava({
|
||||
type: "Image:SetAs",
|
||||
@ -734,6 +773,8 @@ var BrowserApp = {
|
||||
return Strings.browser.GetStringFromName("contextmenu.saveVideo");
|
||||
}, NativeWindow.contextmenus.mediaSaveableContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_save_media");
|
||||
|
||||
let url = aTarget.currentSrc || aTarget.src;
|
||||
let filePickerTitleKey = (aTarget instanceof HTMLVideoElement &&
|
||||
(aTarget.videoWidth != 0 && aTarget.videoHeight != 0))
|
||||
|
318
mobile/android/modules/FireflyApp.jsm
Normal file
318
mobile/android/modules/FireflyApp.jsm
Normal file
@ -0,0 +1,318 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["FireflyApp"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// meta constants
|
||||
const HEADER_META = ".meta";
|
||||
const PROTO_CMD_KEY = "cmd";
|
||||
const PROTO_CMD_VALUE_CREATE_SESSION = "create-session";
|
||||
const PROTO_CMD_VALUE_END_SESSION = "end-session";
|
||||
const PROTO_CMD_VALUE_ATTACH_APP = "attach-app";
|
||||
const PROTO_CMD_VALUE_SET_WIFI = "set-wifi";
|
||||
const PROTO_CMD_RESPONSE_PREFIX = "~";
|
||||
const PROTO_CMD_VALUE_START_APP = "start-app";
|
||||
const PROTO_CMD_VALUE_CANCEL_START_APP = "cancel-start-app";
|
||||
const PROTO_CMD_VALUE_DOWNLODING_APP = "downloading-app";
|
||||
const PROTO_CMD_VALUE_ATTACH_APP_MANAGER = "attach-app-manager";
|
||||
const PROTO_CMD_VALUE_EXCEPTION = "exception";
|
||||
const PROTO_EXCEPTION_KEY = "exception";
|
||||
const PROTO_EXCEPTION_NO_KEY = "errno";
|
||||
const PROTO_STATUS_VALUE_APP_CLOSED = "app-closed";
|
||||
const PROTO_STATUS_VALUE_TRY_LATER = "try-later";
|
||||
const PROTO_STATUS_VALUE_CANCELLED = "cancelled";
|
||||
const PROTO_STATUS_VALUE_REFUSED = "refused";
|
||||
const PROTO_STATUS_VALUE_TIMEOUT = "time-out";
|
||||
const PROTO_STATUS_VALUE_INVALID_APP = "app_not_exist";
|
||||
const PROTO_STATUS_VALUE_APP_CHECK_FAIL = "app_check_fail";
|
||||
const PROTO_STATUS_VALUE_APP_INSTALL_FAIL = "app_install_fail";
|
||||
const PROTO_STATUS_VALUE_APP_DOWNLOAD_FAIL = "app_download_fail";
|
||||
const PROTO_STATUS_VALUE_APP_LAUNCH_FAIL = "app_launch_fail";
|
||||
const PROTO_STATUS_KEY = "status";
|
||||
const PROTO_STATUS_VALUE_OK = "OK";
|
||||
const PROTO_STATUS_VALUE_FAILED = "FAILED_REASON";
|
||||
const PROTO_EXCEPTION_NO_APP_NAME_NULL = 10;
|
||||
const PROTO_EXCEPTION_NO_MESSAGE_NULL = 11;
|
||||
const PROTO_EXCEPTION_NO_NEW_GROUP_START = 12;
|
||||
const PROTO_EXCEPTION_NO_UNKNOW_CMD = 13;
|
||||
const PROTO_EXCEPTION_NO_JSON_DATA_ERROR = 14;
|
||||
const PARAM_APP_NAME = "app-name";
|
||||
const PROTO_HOME_APP = "home";
|
||||
const PARAM_DOWNLOADING_PERCENT = "download-percent";
|
||||
const PARAM_KEEP_SESSION = "keep-session";
|
||||
const PROTO_SENDER_HOST_NAME_KEY = "sender-host-name";
|
||||
const PROTO_SENDER_PORT_KEY = "sender-port";
|
||||
const PROTO_APP_META_KEY = "app-meta";
|
||||
const PROTO_APP_META_NAME = "name";
|
||||
const PROTO_APP_META_TITLE = "title";
|
||||
const PROTO_APP_META_IMG_URI = "img-uri";
|
||||
const PROTO_MIME_DATA_KEY = "mime-data";
|
||||
const PROTO_APP_NAME_KEY = "app-name";
|
||||
const PARAM_WIFI_NAME = "wifi-name";
|
||||
const PARAM_WIFI_PASSWORD = "wifi-password";
|
||||
const PARAM_WIFI_TYPE = "wifi-type";
|
||||
const PARAM_WIFI_KEY = "key";
|
||||
const PROTO_MIME_DATA_KEY_TYPE = "type";
|
||||
const PROTO_MIME_DATA_KEY_DATA = "data";
|
||||
|
||||
// RAMP constants
|
||||
const RAMP_CMD_KEY_ID = "cmd_id";
|
||||
const RAMP_CMD_KEY_TYPE = "type";
|
||||
const RAMP_CMD_KEY_STATUS = "status";
|
||||
const RAMP_CMD_KEY_URL = "url";
|
||||
const RAMP_CMD_KEY_VALUE = "value";
|
||||
const RAMP_CMD_KEY_VIDEO_NAME = "videoname";
|
||||
const RAMP_CMD_KEY_EVENT_SEQ = "event_sequence";
|
||||
const NAMESPACE_RAMP = "ramp";
|
||||
const RAMP_CMD_ID_START = 0;
|
||||
const RAMP_CMD_ID_INFO = 1;
|
||||
const RAMP_CMD_ID_PLAY = 2;
|
||||
const RAMP_CMD_ID_PAUSE = 3;
|
||||
const RAMP_CMD_ID_STOP = 4;
|
||||
const RAMP_CMD_ID_SEEKTO = 5;
|
||||
const RAMP_CMD_ID_SETVOLUME = 6;
|
||||
const RAMP_CMD_ID_MUTE = 7;
|
||||
const RAMP_CMD_ID_DECONSTE = 8;
|
||||
const RAMP_CMD_START = "START";
|
||||
const RAMP_CMD_INFO = "INFO";
|
||||
const RAMP_CMD_PLAY = "PLAY";
|
||||
const RAMP_CMD_PAUSE = "PAUSE";
|
||||
const RAMP_CMD_STOP = "STOP";
|
||||
const RAMP_CMD_SEEKTO = "SEEKTO";
|
||||
const RAMP_CMD_SETVOLUME = "SETVOLUME";
|
||||
const RAMP_CMD_MUTE = "MUTE";
|
||||
const RAMP_CMD_DECONSTE = "DECONSTE";
|
||||
const RAMP_CAST_STATUS_EVENT_SEQUENCE = "event_sequence";
|
||||
const RAMP_CAST_STATUS_STATE = "state";
|
||||
const RAMP_CAST_STATUS_CONTENT_ID = "content_id";
|
||||
const RAMP_CAST_STATUS_CURRENT_TIME = "current_time";
|
||||
const RAMP_CAST_STATUS_DURATION = "duration";
|
||||
const RAMP_CAST_STATUS_MUTED = "muted";
|
||||
const RAMP_CAST_STATUS_TIME_PROGRESS = "time_progress";
|
||||
const RAMP_CAST_STATUS_TITLE = "title";
|
||||
const RAMP_CAST_STATUS_VOLUME = "volume";
|
||||
const PLAYER_STATUS_PREPARING = 1;
|
||||
const PLAYER_STATUS_PLAYING = 2;
|
||||
const PLAYER_STATUS_PAUSE = 3;
|
||||
const PLAYER_STATUS_STOP = 4;
|
||||
const PLAYER_STATUS_IDLE = 5;
|
||||
const PLAYER_STATUS_BUFFERING = 6;
|
||||
|
||||
function FireflyApp(service) {
|
||||
let uri = Services.io.newURI(service.location, null, null);
|
||||
this._ip = uri.host;
|
||||
};
|
||||
|
||||
FireflyApp.prototype = {
|
||||
_ip: null,
|
||||
_port: 8888,
|
||||
_cmd_socket: null,
|
||||
_meta_callback: null,
|
||||
_ramp_callbacks: {},
|
||||
_mediaListener: null,
|
||||
_event_sequence: 0,
|
||||
status: "unloaded",
|
||||
_have_session: false,
|
||||
_info_timer: null,
|
||||
|
||||
_send_meta_cmd: function(cmd, callback, extras) {
|
||||
this._meta_callback = callback;
|
||||
let msg = extras ? extras : {};
|
||||
msg.cmd = cmd;
|
||||
this._send_cmd(JSON.stringify([HEADER_META, msg]), 0);
|
||||
},
|
||||
|
||||
_send_ramp_cmd: function(type, cmd_id, callback, extras) {
|
||||
let msg = extras ? extras : {};
|
||||
msg.cmd_id = cmd_id;
|
||||
msg.type = type;
|
||||
msg.event_sequence = this._event_sequence++;
|
||||
this._send_cmd(JSON.stringify([NAMESPACE_RAMP, msg]), 0);
|
||||
},
|
||||
|
||||
_send_cmd: function(str, recursionDepth) {
|
||||
if (!this._cmd_socket) {
|
||||
let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
|
||||
this._cmd_socket = baseSocket.open(this._ip, 8888, { useSecureTransport: false, binaryType: "string" });
|
||||
if (!(this._cmd_socket)) {
|
||||
dump("socket is null");
|
||||
return;
|
||||
}
|
||||
|
||||
this._cmd_socket.ondata = function(response) {
|
||||
try {
|
||||
let data = JSON.parse(response.data);
|
||||
let res = data[1];
|
||||
switch (data[0]) {
|
||||
case ".meta":
|
||||
this._handle_meta_response(data[1]);
|
||||
return;
|
||||
case "ramp":
|
||||
this._handle_ramp_response(data[1]);
|
||||
return;
|
||||
default:
|
||||
dump("unknown response");
|
||||
}
|
||||
} catch(ex) {
|
||||
dump("error handling response: " + ex);
|
||||
if (!this._info_timer) {
|
||||
this._info_timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._info_timer.init(this, 200, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this._cmd_socket.onerror = function(err) {
|
||||
this.shutdown();
|
||||
Cu.reportError("error: " + err.data.name);
|
||||
this._cmd_socket = null;
|
||||
}.bind(this);
|
||||
|
||||
this._cmd_socket.onclose = function() {
|
||||
this.shutdown();
|
||||
this._cmd_socket = null;
|
||||
Cu.reportError("closed tcp socket")
|
||||
}.bind(this);
|
||||
|
||||
this._cmd_socket.onopen = function() {
|
||||
if (recursionDepth <= 2) {
|
||||
this._send_cmd(str, ++recursionDepth);
|
||||
}
|
||||
}.bind(this);
|
||||
} else {
|
||||
try {
|
||||
this._cmd_socket.send(str, str.length);
|
||||
let data = JSON.parse(str);
|
||||
if (data[1][PARAM_APP_NAME] == PROTO_HOME_APP) {
|
||||
// assuming we got home OK
|
||||
if (this._meta_callback) {
|
||||
this._handle_meta_callback({ status: "OK" });
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
this._cmd_socket = null;
|
||||
this._send_cmd(str);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(subject, data, topic) {
|
||||
if (data === "timer-callback") {
|
||||
this._info_timer = null;
|
||||
this._send_ramp_cmd(RAMP_CMD_INFO, RAMP_CMD_ID_INFO, null)
|
||||
}
|
||||
},
|
||||
|
||||
start: function(func) {
|
||||
let cmd = this._have_session ? PROTO_CMD_VALUE_START_APP : PROTO_CMD_VALUE_CREATE_SESSION ;
|
||||
this._send_meta_cmd(cmd, func, { "app-name": "Remote Player" });
|
||||
},
|
||||
|
||||
stop: function(func) {
|
||||
if (func) {
|
||||
func(true);
|
||||
}
|
||||
},
|
||||
|
||||
remoteMedia: function(func, listener) {
|
||||
this._mediaListener = listener;
|
||||
func(this);
|
||||
if (listener) {
|
||||
listener.onRemoteMediaStart(this);
|
||||
}
|
||||
},
|
||||
|
||||
_handle_meta_response: function(data) {
|
||||
switch(data.cmd) {
|
||||
case "create-session":
|
||||
case "~create-session":
|
||||
// if we get a response form start-app, assume we have a connection already
|
||||
case "start-app":
|
||||
case "~start-app":
|
||||
this._have_session = (data.status == "OK");
|
||||
break;
|
||||
case "end-session":
|
||||
case "~end-session":
|
||||
this._have_session = (data.status != "OK");
|
||||
break;
|
||||
}
|
||||
|
||||
if (this._meta_callback) {
|
||||
let callback = this._meta_callback;
|
||||
this._meta_callback = null;
|
||||
callback(data.status == "OK");
|
||||
}
|
||||
},
|
||||
|
||||
_handle_ramp_response: function(data) {
|
||||
switch (data.status.state) {
|
||||
case PLAYER_STATUS_PREPARING:
|
||||
this.status = "preparing";
|
||||
break;
|
||||
case PLAYER_STATUS_PLAYING:
|
||||
this.status = "started";
|
||||
break;
|
||||
case PLAYER_STATUS_PAUSE:
|
||||
this.status = "paused";
|
||||
break;
|
||||
case PLAYER_STATUS_STOP:
|
||||
this.status = "stopped";
|
||||
break;
|
||||
case PLAYER_STATUS_IDLE:
|
||||
this.status = "idle";
|
||||
break;
|
||||
case PLAYER_STATUS_BUFFERING:
|
||||
this.status = "buffering";
|
||||
break;
|
||||
}
|
||||
|
||||
if (data.status.state == PLAYER_STATUS_STOP && data.status.current_time > 0 && data.status.current_time == data.status.duration) {
|
||||
this.status = "completed";
|
||||
} else if (!this._info_timer) {
|
||||
this._info_timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._info_timer.init(this, 200, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
if (this._mediaListener) {
|
||||
this._mediaListener.onRemoteMediaStatus(this);
|
||||
}
|
||||
},
|
||||
|
||||
load: function(data) {
|
||||
let meta = {
|
||||
url: data.source,
|
||||
videoname: data.title
|
||||
};
|
||||
this._send_ramp_cmd(RAMP_CMD_START, RAMP_CMD_ID_START, null, meta);
|
||||
},
|
||||
|
||||
play: function() {
|
||||
this._send_ramp_cmd(RAMP_CMD_PLAY, RAMP_CMD_ID_PLAY, null);
|
||||
},
|
||||
|
||||
pause: function() {
|
||||
this._send_ramp_cmd(RAMP_CMD_PAUSE, RAMP_CMD_ID_PAUSE, null);
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
if (this._info_timer) {
|
||||
this._info_timer.clear();
|
||||
this._info_timer = null;
|
||||
}
|
||||
|
||||
this.stop(function() {
|
||||
this._send_meta_cmd(PROTO_CMD_VALUE_END_SESSION);
|
||||
if (this._mediaListener) {
|
||||
this._mediaListener.onRemoteMediaStop(this);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
@ -9,6 +9,7 @@ EXTRA_JS_MODULES += [
|
||||
'AndroidLog.jsm',
|
||||
'ContactService.jsm',
|
||||
'dbg-browser-actors.js',
|
||||
'FireflyApp.jsm',
|
||||
'HelperApps.jsm',
|
||||
'Home.jsm',
|
||||
'HomeProvider.jsm',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user