зеркало из https://github.com/mozilla/gecko-dev.git
merge fx-team to mozilla-central a=merge
This commit is contained in:
Коммит
a449c7eac9
|
@ -6,6 +6,8 @@
|
|||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
||||
DIRS += ["source/modules/system"]
|
||||
|
||||
JS_MODULES_PATH = 'modules/sdk'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
|
|
|
@ -7,178 +7,7 @@ module.metadata = {
|
|||
"stability": "experimental"
|
||||
};
|
||||
|
||||
var { Cc, Ci } = require("chrome");
|
||||
var { Cu } = require("chrome");
|
||||
var { XulApp } = Cu.import("resource://gre/modules/sdk/system/XulApp.js", {});
|
||||
|
||||
var appInfo = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULAppInfo);
|
||||
var vc = Cc["@mozilla.org/xpcom/version-comparator;1"]
|
||||
.getService(Ci.nsIVersionComparator);
|
||||
|
||||
var ID = exports.ID = appInfo.ID;
|
||||
var name = exports.name = appInfo.name;
|
||||
var version = exports.version = appInfo.version;
|
||||
var platformVersion = exports.platformVersion = appInfo.platformVersion;
|
||||
|
||||
// The following mapping of application names to GUIDs was taken from:
|
||||
//
|
||||
// https://addons.mozilla.org/en-US/firefox/pages/appversions
|
||||
//
|
||||
// Using the GUID instead of the app's name is preferable because sometimes
|
||||
// re-branded versions of a product have different names: for instance,
|
||||
// Firefox, Minefield, Iceweasel, and Shiretoko all have the same
|
||||
// GUID.
|
||||
// This mapping is duplicated in `app-extensions/bootstrap.js`. They should keep
|
||||
// in sync, so if you change one, change the other too!
|
||||
|
||||
var ids = exports.ids = {
|
||||
Firefox: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
|
||||
Mozilla: "{86c18b42-e466-45a9-ae7a-9b95ba6f5640}",
|
||||
Sunbird: "{718e30fb-e89b-41dd-9da7-e25a45638b28}",
|
||||
SeaMonkey: "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}",
|
||||
Fennec: "{aa3c5121-dab2-40e2-81ca-7ea25febc110}",
|
||||
Thunderbird: "{3550f703-e582-4d05-9a08-453d09bdfdc6}"
|
||||
};
|
||||
|
||||
function is(name) {
|
||||
if (!(name in ids))
|
||||
throw new Error("Unkown Mozilla Application: " + name);
|
||||
return ID == ids[name];
|
||||
};
|
||||
exports.is = is;
|
||||
|
||||
function isOneOf(names) {
|
||||
for (var i = 0; i < names.length; i++)
|
||||
if (is(names[i]))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
exports.isOneOf = isOneOf;
|
||||
|
||||
/**
|
||||
* Use this to check whether the given version (e.g. xulApp.platformVersion)
|
||||
* is in the given range. Versions must be in version comparator-compatible
|
||||
* format. See MDC for details:
|
||||
* https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIVersionComparator
|
||||
*/
|
||||
var versionInRange = exports.versionInRange =
|
||||
function versionInRange(version, lowInclusive, highExclusive) {
|
||||
return (vc.compare(version, lowInclusive) >= 0) &&
|
||||
(vc.compare(version, highExclusive) < 0);
|
||||
}
|
||||
|
||||
const reVersionRange = /^((?:<|>)?=?)?\s*((?:\d+[\S]*)|\*)(?:\s+((?:<|>)=?)?(\d+[\S]+))?$/;
|
||||
const reOnlyInifinity = /^[<>]?=?\s*[*x]$/;
|
||||
const reSubInfinity = /\.[*x]/g;
|
||||
const reHyphenRange = /^(\d+.*?)\s*-\s*(\d+.*?)$/;
|
||||
const reRangeSeparator = /\s*\|\|\s*/;
|
||||
|
||||
const compares = {
|
||||
"=": function (c) { return c === 0 },
|
||||
">=": function (c) { return c >= 0 },
|
||||
"<=": function (c) { return c <= 0},
|
||||
"<": function (c) { return c < 0 },
|
||||
">": function (c) { return c > 0 }
|
||||
}
|
||||
|
||||
function normalizeRange(range) {
|
||||
return range
|
||||
.replace(reOnlyInifinity, "")
|
||||
.replace(reSubInfinity, ".*")
|
||||
.replace(reHyphenRange, ">=$1 <=$2")
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the versions given, using the comparison operator provided.
|
||||
* Internal use only.
|
||||
*
|
||||
* @example
|
||||
* compareVersion("1.2", "<=", "1.*") // true
|
||||
*
|
||||
* @param {String} version
|
||||
* A version to compare
|
||||
*
|
||||
* @param {String} comparison
|
||||
* The comparison operator
|
||||
*
|
||||
* @param {String} compareVersion
|
||||
* A version to compare
|
||||
*/
|
||||
function compareVersion(version, comparison, compareVersion) {
|
||||
let hasWildcard = compareVersion.indexOf("*") !== -1;
|
||||
|
||||
comparison = comparison || "=";
|
||||
|
||||
if (hasWildcard) {
|
||||
switch (comparison) {
|
||||
case "=":
|
||||
let zeroVersion = compareVersion.replace(reSubInfinity, ".0");
|
||||
return versionInRange(version, zeroVersion, compareVersion);
|
||||
case ">=":
|
||||
compareVersion = compareVersion.replace(reSubInfinity, ".0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let compare = compares[comparison];
|
||||
|
||||
return typeof compare === "function" && compare(vc.compare(version, compareVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if `version` satisfies the `versionRange` given.
|
||||
* If only an argument is passed, is used as `versionRange` and compared against
|
||||
* `xulApp.platformVersion`.
|
||||
*
|
||||
* `versionRange` is either a string which has one or more space-separated
|
||||
* descriptors, or a range like "fromVersion - toVersion".
|
||||
* Version range descriptors may be any of the following styles:
|
||||
*
|
||||
* - "version" Must match `version` exactly
|
||||
* - "=version" Same as just `version`
|
||||
* - ">version" Must be greater than `version`
|
||||
* - ">=version" Must be greater or equal than `version`
|
||||
* - "<version" Must be less than `version`
|
||||
* - "<=version" Must be less or equal than `version`
|
||||
* - "1.2.x" or "1.2.*" See 'X version ranges' below
|
||||
* - "*" or "" (just an empty string) Matches any version
|
||||
* - "version1 - version2" Same as ">=version1 <=version2"
|
||||
* - "range1 || range2" Passes if either `range1` or `range2` are satisfied
|
||||
*
|
||||
* For example, these are all valid:
|
||||
* - "1.0.0 - 2.9999.9999"
|
||||
* - ">=1.0.2 <2.1.2"
|
||||
* - ">1.0.2 <=2.3.4"
|
||||
* - "2.0.1"
|
||||
* - "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
|
||||
* - "2.x" (equivalent to "2.*")
|
||||
* - "1.2.x" (equivalent to "1.2.*" and ">=1.2.0 <1.3.0")
|
||||
*/
|
||||
function satisfiesVersion(version, versionRange) {
|
||||
if (arguments.length === 1) {
|
||||
versionRange = version;
|
||||
version = appInfo.version;
|
||||
}
|
||||
|
||||
let ranges = versionRange.trim().split(reRangeSeparator);
|
||||
|
||||
return ranges.some(function(range) {
|
||||
range = normalizeRange(range);
|
||||
|
||||
// No versions' range specified means that any version satisfies the
|
||||
// requirements.
|
||||
if (range === "")
|
||||
return true;
|
||||
|
||||
let matches = range.match(reVersionRange);
|
||||
|
||||
if (!matches)
|
||||
return false;
|
||||
|
||||
let [, lowMod, lowVer, highMod, highVer] = matches;
|
||||
|
||||
return compareVersion(version, lowMod, lowVer) && (highVer !== undefined
|
||||
? compareVersion(version, highMod, highVer)
|
||||
: true);
|
||||
});
|
||||
}
|
||||
exports.satisfiesVersion = satisfiesVersion;
|
||||
Object.keys(XulApp).forEach(k => exports[k] = XulApp[k]);
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["XulApp"];
|
||||
|
||||
var { classes: Cc, interfaces: Ci } = Components;
|
||||
|
||||
var exports = {};
|
||||
var XulApp = exports;
|
||||
|
||||
var appInfo = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULAppInfo);
|
||||
var vc = Cc["@mozilla.org/xpcom/version-comparator;1"]
|
||||
.getService(Ci.nsIVersionComparator);
|
||||
|
||||
var ID = exports.ID = appInfo.ID;
|
||||
var name = exports.name = appInfo.name;
|
||||
var version = exports.version = appInfo.version;
|
||||
var platformVersion = exports.platformVersion = appInfo.platformVersion;
|
||||
|
||||
// The following mapping of application names to GUIDs was taken from:
|
||||
//
|
||||
// https://addons.mozilla.org/en-US/firefox/pages/appversions
|
||||
//
|
||||
// Using the GUID instead of the app's name is preferable because sometimes
|
||||
// re-branded versions of a product have different names: for instance,
|
||||
// Firefox, Minefield, Iceweasel, and Shiretoko all have the same
|
||||
// GUID.
|
||||
// This mapping is duplicated in `app-extensions/bootstrap.js`. They should keep
|
||||
// in sync, so if you change one, change the other too!
|
||||
|
||||
var ids = exports.ids = {
|
||||
Firefox: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
|
||||
Mozilla: "{86c18b42-e466-45a9-ae7a-9b95ba6f5640}",
|
||||
Sunbird: "{718e30fb-e89b-41dd-9da7-e25a45638b28}",
|
||||
SeaMonkey: "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}",
|
||||
Fennec: "{aa3c5121-dab2-40e2-81ca-7ea25febc110}",
|
||||
Thunderbird: "{3550f703-e582-4d05-9a08-453d09bdfdc6}"
|
||||
};
|
||||
|
||||
function is(name) {
|
||||
if (!(name in ids))
|
||||
throw new Error("Unkown Mozilla Application: " + name);
|
||||
return ID == ids[name];
|
||||
};
|
||||
exports.is = is;
|
||||
|
||||
function isOneOf(names) {
|
||||
for (var i = 0; i < names.length; i++)
|
||||
if (is(names[i]))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
exports.isOneOf = isOneOf;
|
||||
|
||||
/**
|
||||
* Use this to check whether the given version (e.g. xulApp.platformVersion)
|
||||
* is in the given range. Versions must be in version comparator-compatible
|
||||
* format. See MDC for details:
|
||||
* https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIVersionComparator
|
||||
*/
|
||||
var versionInRange = exports.versionInRange =
|
||||
function versionInRange(version, lowInclusive, highExclusive) {
|
||||
return (vc.compare(version, lowInclusive) >= 0) &&
|
||||
(vc.compare(version, highExclusive) < 0);
|
||||
}
|
||||
|
||||
const reVersionRange = /^((?:<|>)?=?)?\s*((?:\d+[\S]*)|\*)(?:\s+((?:<|>)=?)?(\d+[\S]+))?$/;
|
||||
const reOnlyInifinity = /^[<>]?=?\s*[*x]$/;
|
||||
const reSubInfinity = /\.[*x]/g;
|
||||
const reHyphenRange = /^(\d+.*?)\s*-\s*(\d+.*?)$/;
|
||||
const reRangeSeparator = /\s*\|\|\s*/;
|
||||
|
||||
const compares = {
|
||||
"=": function (c) { return c === 0 },
|
||||
">=": function (c) { return c >= 0 },
|
||||
"<=": function (c) { return c <= 0},
|
||||
"<": function (c) { return c < 0 },
|
||||
">": function (c) { return c > 0 }
|
||||
}
|
||||
|
||||
function normalizeRange(range) {
|
||||
return range
|
||||
.replace(reOnlyInifinity, "")
|
||||
.replace(reSubInfinity, ".*")
|
||||
.replace(reHyphenRange, ">=$1 <=$2")
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the versions given, using the comparison operator provided.
|
||||
* Internal use only.
|
||||
*
|
||||
* @example
|
||||
* compareVersion("1.2", "<=", "1.*") // true
|
||||
*
|
||||
* @param {String} version
|
||||
* A version to compare
|
||||
*
|
||||
* @param {String} comparison
|
||||
* The comparison operator
|
||||
*
|
||||
* @param {String} compareVersion
|
||||
* A version to compare
|
||||
*/
|
||||
function compareVersion(version, comparison, compareVersion) {
|
||||
let hasWildcard = compareVersion.indexOf("*") !== -1;
|
||||
|
||||
comparison = comparison || "=";
|
||||
|
||||
if (hasWildcard) {
|
||||
switch (comparison) {
|
||||
case "=":
|
||||
let zeroVersion = compareVersion.replace(reSubInfinity, ".0");
|
||||
return versionInRange(version, zeroVersion, compareVersion);
|
||||
case ">=":
|
||||
compareVersion = compareVersion.replace(reSubInfinity, ".0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let compare = compares[comparison];
|
||||
|
||||
return typeof compare === "function" && compare(vc.compare(version, compareVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if `version` satisfies the `versionRange` given.
|
||||
* If only an argument is passed, is used as `versionRange` and compared against
|
||||
* `xulApp.platformVersion`.
|
||||
*
|
||||
* `versionRange` is either a string which has one or more space-separated
|
||||
* descriptors, or a range like "fromVersion - toVersion".
|
||||
* Version range descriptors may be any of the following styles:
|
||||
*
|
||||
* - "version" Must match `version` exactly
|
||||
* - "=version" Same as just `version`
|
||||
* - ">version" Must be greater than `version`
|
||||
* - ">=version" Must be greater or equal than `version`
|
||||
* - "<version" Must be less than `version`
|
||||
* - "<=version" Must be less or equal than `version`
|
||||
* - "1.2.x" or "1.2.*" See 'X version ranges' below
|
||||
* - "*" or "" (just an empty string) Matches any version
|
||||
* - "version1 - version2" Same as ">=version1 <=version2"
|
||||
* - "range1 || range2" Passes if either `range1` or `range2` are satisfied
|
||||
*
|
||||
* For example, these are all valid:
|
||||
* - "1.0.0 - 2.9999.9999"
|
||||
* - ">=1.0.2 <2.1.2"
|
||||
* - ">1.0.2 <=2.3.4"
|
||||
* - "2.0.1"
|
||||
* - "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
|
||||
* - "2.x" (equivalent to "2.*")
|
||||
* - "1.2.x" (equivalent to "1.2.*" and ">=1.2.0 <1.3.0")
|
||||
*/
|
||||
function satisfiesVersion(version, versionRange) {
|
||||
if (arguments.length === 1) {
|
||||
versionRange = version;
|
||||
version = appInfo.version;
|
||||
}
|
||||
|
||||
let ranges = versionRange.trim().split(reRangeSeparator);
|
||||
|
||||
return ranges.some(function(range) {
|
||||
range = normalizeRange(range);
|
||||
|
||||
// No versions' range specified means that any version satisfies the
|
||||
// requirements.
|
||||
if (range === "")
|
||||
return true;
|
||||
|
||||
let matches = range.match(reVersionRange);
|
||||
|
||||
if (!matches)
|
||||
return false;
|
||||
|
||||
let [, lowMod, lowVer, highMod, highVer] = matches;
|
||||
|
||||
return compareVersion(version, lowMod, lowVer) && (highVer !== undefined
|
||||
? compareVersion(version, highMod, highVer)
|
||||
: true);
|
||||
});
|
||||
}
|
||||
exports.satisfiesVersion = satisfiesVersion;
|
|
@ -0,0 +1,11 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
JS_MODULES_PATH = 'modules/sdk/system'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'XulApp.js',
|
||||
]
|
|
@ -17,15 +17,7 @@
|
|||
title="&fontsDialog.title;"
|
||||
dlgbuttons="accept,cancel,help"
|
||||
ondialoghelp="openPrefsHelp()"
|
||||
#ifdef XP_UNIX
|
||||
#ifdef XP_MACOSX
|
||||
style="width: &window.macWidth; !important;">
|
||||
#else
|
||||
style="width: &window.unixWidth; !important;">
|
||||
#endif
|
||||
#else
|
||||
style="width: &window.width; !important;">
|
||||
#endif
|
||||
style="">
|
||||
|
||||
<script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
|
||||
|
||||
|
|
|
@ -153,8 +153,7 @@ var gContentPane = {
|
|||
*/
|
||||
configureFonts: function ()
|
||||
{
|
||||
openDialog("chrome://browser/content/preferences/fonts.xul",
|
||||
"Browser:FontPreferences", null);
|
||||
gSubDialog.open("chrome://browser/content/preferences/fonts.xul");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -182,8 +181,7 @@ var gContentPane = {
|
|||
*/
|
||||
showTranslationExceptions: function ()
|
||||
{
|
||||
openDialog("chrome://browser/content/preferences/translation.xul",
|
||||
"Browser:TranslationExceptions", null);
|
||||
gSubDialog.open("chrome://browser/content/preferences/translation.xul");
|
||||
},
|
||||
|
||||
openTranslationProviderAttribution: function ()
|
||||
|
|
|
@ -9,7 +9,7 @@ function test() {
|
|||
waitForExplicitFinish();
|
||||
|
||||
// open a new window and setup the window state.
|
||||
newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
|
||||
newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", "about:blank");
|
||||
whenWindowLoaded(newWin, function () {
|
||||
let newState = {
|
||||
windows: [{
|
||||
|
|
|
@ -29,6 +29,6 @@ function test() {
|
|||
|
||||
function newWindow(callback) {
|
||||
let opts = "chrome,all,dialog=no,height=800,width=800";
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", opts);
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", opts, "about:blank");
|
||||
whenDelayedStartupFinished(win, () => callback(win));
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ function newWindowWithTabView(shownCallback, loadCallback, width, height) {
|
|||
let winHeight = height || 800;
|
||||
let win = window.openDialog(getBrowserURL(), "_blank",
|
||||
"chrome,all,dialog=no,height=" + winHeight +
|
||||
",width=" + winWidth);
|
||||
",width=" + winWidth, "about:blank");
|
||||
|
||||
whenWindowLoaded(win, function () {
|
||||
if (loadCallback)
|
||||
|
@ -333,7 +333,7 @@ function newWindowWithState(state, callback) {
|
|||
.getService(Ci.nsISessionStore);
|
||||
|
||||
let opts = "chrome,all,dialog=no,height=800,width=800";
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", opts);
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", opts, "about:blank");
|
||||
|
||||
let numConditions = 2;
|
||||
let check = function () {
|
||||
|
@ -433,3 +433,19 @@ function waitForOnBeforeUnloadDialog(browser, callback) {
|
|||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides browser.js' OpenBrowserWindow() function to enforce an initial
|
||||
* tab different from about:home to not hit the network.
|
||||
*/
|
||||
function OpenBrowserWindow(aOptions) {
|
||||
let features = "";
|
||||
let url = "about:blank";
|
||||
|
||||
if (aOptions && aOptions.private || false) {
|
||||
features = ",private";
|
||||
url = "about:privatebrowsing";
|
||||
}
|
||||
|
||||
return openDialog(getBrowserURL(), "", "chrome,all,dialog=no" + features, url);
|
||||
}
|
||||
|
|
|
@ -3643,9 +3643,14 @@ VariablesView.stringifiers.byObjectKind = {
|
|||
|
||||
switch (preview.nodeType) {
|
||||
case Ci.nsIDOMNode.DOCUMENT_NODE: {
|
||||
let location = WebConsoleUtils.abbreviateSourceURL(preview.location,
|
||||
{ onlyCropQuery: !concise });
|
||||
return aGrip.class + " \u2192 " + location;
|
||||
let result = aGrip.class;
|
||||
if (preview.location) {
|
||||
let location = WebConsoleUtils.abbreviateSourceURL(preview.location,
|
||||
{ onlyCropQuery: !concise });
|
||||
result += " \u2192 " + location;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case Ci.nsIDOMNode.ATTRIBUTE_NODE: {
|
||||
|
|
|
@ -250,6 +250,7 @@ run-if = os == "mac"
|
|||
[browser_webconsole_for_of.js]
|
||||
[browser_webconsole_history.js]
|
||||
[browser_webconsole_input_field_focus_on_panel_select.js]
|
||||
[browser_webconsole_inspect-parsed-documents.js]
|
||||
[browser_webconsole_js_input_expansion.js]
|
||||
[browser_webconsole_jsterm.js]
|
||||
[browser_webconsole_live_filtering_of_message_types.js]
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that dynamically created (HTML|XML|SVG)Documents can be inspected by
|
||||
// clicking on the object in console (bug 1035198).
|
||||
|
||||
const TEST_CASES = [
|
||||
{
|
||||
input: '(new DOMParser()).parseFromString("<a />", "text/html")',
|
||||
output: "HTMLDocument",
|
||||
inspectable: true,
|
||||
},
|
||||
{
|
||||
input: '(new DOMParser()).parseFromString("<a />", "application/xml")',
|
||||
output: "XMLDocument",
|
||||
inspectable: true,
|
||||
},
|
||||
{
|
||||
input: '(new DOMParser()).parseFromString("<svg></svg>", "image/svg+xml")',
|
||||
output: "SVGDocument",
|
||||
inspectable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8," +
|
||||
"browser_webconsole_inspect-parsed-documents.js";
|
||||
let test = asyncTest(function* () {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
yield checkOutputForInputs(hud, TEST_CASES);
|
||||
});
|
|
@ -69,9 +69,11 @@ let inputTests = [
|
|||
|
||||
// 8
|
||||
{
|
||||
input: "new String('hello world')",
|
||||
output: '"hello world"',
|
||||
input: "new String('hello')",
|
||||
output: 'String [ "h", "e", "l", "l", "o" ]',
|
||||
printOutput: "hello",
|
||||
inspectable: true,
|
||||
variablesViewLabel: "String[5]"
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -44,6 +44,13 @@ SimpleTest.registerCleanupFunction(() => {
|
|||
gDevTools.testing = false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Define an async test based on a generator function
|
||||
*/
|
||||
function asyncTest(generator) {
|
||||
return () => Task.spawn(generator).then(null, ok.bind(null, false)).then(finishTest);
|
||||
}
|
||||
|
||||
function log(aMsg)
|
||||
{
|
||||
dump("*** WebConsoleTest: " + aMsg + "\n");
|
||||
|
|
|
@ -533,7 +533,10 @@ exports.AppManager = AppManager = {
|
|||
_updateUSBRuntimes: function() {
|
||||
this.runtimeList.usb = [];
|
||||
for (let id of Devices.available()) {
|
||||
this.runtimeList.usb.push(new USBRuntime(id));
|
||||
let r = new USBRuntime(id);
|
||||
this.runtimeList.usb.push(r);
|
||||
r.updateNameFromADB().then(
|
||||
() => this.update("runtimelist"), () => {});
|
||||
}
|
||||
this.update("runtimelist");
|
||||
},
|
||||
|
|
|
@ -33,7 +33,24 @@ USBRuntime.prototype = {
|
|||
return this.id;
|
||||
},
|
||||
getName: function() {
|
||||
return this.id;
|
||||
return this._productModel || this.id;
|
||||
},
|
||||
updateNameFromADB: function() {
|
||||
if (this._productModel) {
|
||||
return promise.resolve();
|
||||
}
|
||||
let device = Devices.getByName(this.id);
|
||||
let deferred = promise.defer();
|
||||
if (device && device.shell) {
|
||||
device.shell("getprop ro.product.model").then(stdout => {
|
||||
this._productModel = stdout;
|
||||
deferred.resolve();
|
||||
}, () => {});
|
||||
} else {
|
||||
this._productModel = null;
|
||||
deferred.reject();
|
||||
}
|
||||
return deferred.promise;
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY fontsDialog.title "Fonts">
|
||||
<!ENTITY window.width "39em">
|
||||
<!ENTITY window.macWidth "43em">
|
||||
<!ENTITY window.unixWidth "41em">
|
||||
|
||||
<!ENTITY language.label "Fonts for:">
|
||||
<!ENTITY language.accesskey "F">
|
||||
|
|
|
@ -126,6 +126,7 @@ tab[selected] {
|
|||
/* buttons and menulists */
|
||||
|
||||
button,
|
||||
colorpicker[type="button"],
|
||||
menulist {
|
||||
-moz-appearance: none;
|
||||
height: 30px;
|
||||
|
@ -142,20 +143,28 @@ menulist {
|
|||
}
|
||||
|
||||
button:not([disabled="true"]):hover,
|
||||
colorpicker[type="button"]:not([disabled="true"]):hover,
|
||||
menulist:not([disabled="true"]):hover {
|
||||
background-color: #EBEBEB;
|
||||
}
|
||||
|
||||
button:not([disabled="true"]):hover:active,
|
||||
colorpicker[type="button"]:not([disabled="true"]):hover:active,
|
||||
menulist[open="true"]:not([disabled="true"]) {
|
||||
background-color: #DADADA;
|
||||
}
|
||||
|
||||
button[disabled="true"],
|
||||
colorpicker[type="button"][disabled="true"],
|
||||
menulist[disabled="true"] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
colorpicker[type="button"] {
|
||||
padding: 6px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
button > .button-box,
|
||||
menulist > .menulist-label-box {
|
||||
padding-right: 10px !important;
|
||||
|
@ -893,6 +902,11 @@ tree:not(#rejectsTree) {
|
|||
min-height: 15em;
|
||||
}
|
||||
|
||||
:-moz-any(dialog, window, prefwindow) groupbox {
|
||||
-moz-margin-start: 8px;
|
||||
-moz-margin-end: 8px;
|
||||
}
|
||||
|
||||
/**
|
||||
* End sub-dialog
|
||||
*/
|
||||
|
|
|
@ -112,9 +112,10 @@ public class SearchHistoryProvider extends SharedBrowserDatabaseProvider {
|
|||
String[] selectionArgs, String sortOrder) {
|
||||
String groupBy = null;
|
||||
String having = null;
|
||||
return getReadableDatabase(uri).query(SearchHistory.TABLE_NAME, projection,
|
||||
selection, selectionArgs,
|
||||
groupBy, having, sortOrder);
|
||||
final Cursor cursor = getReadableDatabase(uri).query(SearchHistory.TABLE_NAME, projection,
|
||||
selection, selectionArgs, groupBy, having, sortOrder);
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,4 +22,7 @@ public class Constants {
|
|||
|
||||
public static final String YAHOO_WEB_SEARCH_BASE_URL = "https://search.yahoo.com/search?p=";
|
||||
public static final String YAHOO_WEB_SEARCH_RESULTS_FILTER = "//search.yahoo.com";
|
||||
|
||||
public static final String INTENT_START_SEARCH = "org.mozilla.search.intent.START_SEARCH";
|
||||
public static final String INTENT_START_SEARCH_QUERY_EXTRA = "org.mozilla.search.intent.START_SEARCH_QUERY_EXTRA";
|
||||
}
|
||||
|
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
package org.mozilla.search;
|
||||
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentValues;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.View;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
|
||||
import org.mozilla.search.autocomplete.AcceptsSearchQuery;
|
||||
|
||||
/**
|
||||
|
@ -27,18 +31,20 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
|
|||
}
|
||||
|
||||
private State state = State.START;
|
||||
private AsyncQueryHandler queryHandler;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle stateBundle) {
|
||||
super.onCreate(stateBundle);
|
||||
setContentView(R.layout.search_activity_main);
|
||||
|
||||
queryHandler = new AsyncQueryHandler(getContentResolver()) {};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSearch(String s) {
|
||||
startPostsearch();
|
||||
((PostSearchFragment) getSupportFragmentManager().findFragmentById(R.id.postsearch))
|
||||
.startSearch(s);
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
queryHandler = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,6 +54,14 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
|
|||
startPresearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSearch(String query) {
|
||||
startPostsearch();
|
||||
storeQuery(query);
|
||||
((PostSearchFragment) getSupportFragmentManager().findFragmentById(R.id.postsearch))
|
||||
.setUrl("https://search.yahoo.com/search?p=" + Uri.encode(query));
|
||||
}
|
||||
|
||||
private void startPresearch() {
|
||||
if (state != State.PRESEARCH) {
|
||||
state = State.PRESEARCH;
|
||||
|
@ -72,4 +86,15 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
|
|||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the search query in Fennec's search history database.
|
||||
*/
|
||||
private void storeQuery(String query) {
|
||||
final ContentValues cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, query);
|
||||
// Setting 0 for the token, since we only have one type of insert.
|
||||
// Setting null for the cookie, since we don't handle the result of the insert.
|
||||
queryHandler.startInsert(0, null, SearchHistory.CONTENT_URI, cv);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,24 +21,24 @@ public class PostSearchFragment extends Fragment {
|
|||
private static final String LOGTAG = "PostSearchFragment";
|
||||
private WebView webview;
|
||||
|
||||
private static String HIDE_BANNER_SCRIPT = "javascript:(function(){var tag=document.createElement('style');" +
|
||||
private static final String HIDE_BANNER_SCRIPT = "javascript:(function(){var tag=document.createElement('style');" +
|
||||
"tag.type='text/css';document.getElementsByTagName('head')[0].appendChild(tag);tag.innerText='#nav,#header{display:none}'})();";
|
||||
|
||||
public PostSearchFragment() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
final View mainView = inflater.inflate(R.layout.search_activity_detail, container, false);
|
||||
webview = (WebView) inflater.inflate(R.layout.search_fragment_post_search, container, false);
|
||||
|
||||
webview = (WebView) mainView.findViewById(R.id.webview);
|
||||
webview.setWebViewClient(new LinkInterceptingClient());
|
||||
webview.setWebChromeClient(new StyleInjectingClient());
|
||||
|
||||
// This is required for our greasemonkey terror script.
|
||||
webview.getSettings().setJavaScriptEnabled(true);
|
||||
|
||||
return mainView;
|
||||
return webview;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,55 +4,122 @@
|
|||
|
||||
package org.mozilla.search;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.widget.SimpleCursorAdapter;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.mozilla.search.stream.PreloadAgent;
|
||||
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
|
||||
import org.mozilla.search.autocomplete.AcceptsSearchQuery;
|
||||
|
||||
|
||||
/**
|
||||
* This fragment is responsible for managing the card stream. Right now
|
||||
* we only use this during pre-search, but we could also use it
|
||||
* during post-search at some point.
|
||||
* This fragment is responsible for managing the card stream.
|
||||
*/
|
||||
public class PreSearchFragment extends ListFragment {
|
||||
public class PreSearchFragment extends Fragment {
|
||||
|
||||
private ArrayAdapter<PreloadAgent.TmpItem> adapter;
|
||||
private AcceptsSearchQuery searchListener;
|
||||
private SimpleCursorAdapter cursorAdapter;
|
||||
|
||||
private ListView listView;
|
||||
|
||||
private final String[] PROJECTION = new String[]{SearchHistory.QUERY, SearchHistory._ID};
|
||||
|
||||
private static final int LOADER_ID_SEARCH_HISTORY = 1;
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public PreSearchFragment() {
|
||||
// Mandatory empty constructor for Android's Fragment.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
getListView().setDivider(null);
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
if (activity instanceof AcceptsSearchQuery) {
|
||||
searchListener = (AcceptsSearchQuery) activity;
|
||||
} else {
|
||||
throw new ClassCastException(activity.toString() + " must implement AcceptsSearchQuery.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
if (null == adapter) {
|
||||
adapter = new ArrayAdapter<PreloadAgent.TmpItem>(getActivity(), R.layout.search_card,
|
||||
R.id.card_title, PreloadAgent.ITEMS) {
|
||||
/**
|
||||
* Return false here disables the ListView from highlighting the click events
|
||||
* for each of the items. Each card should handle its own click events.
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
return false;
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
searchListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getLoaderManager().initLoader(LOADER_ID_SEARCH_HISTORY, null, new SearchHistoryLoaderCallbacks());
|
||||
cursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.search_card_history, null,
|
||||
PROJECTION, new int[]{R.id.site_name}, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
getLoaderManager().destroyLoader(LOADER_ID_SEARCH_HISTORY);
|
||||
cursorAdapter.swapCursor(null);
|
||||
cursorAdapter = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
|
||||
listView = (ListView) inflater.inflate(R.layout.search_fragment_pre_search, container, false);
|
||||
listView.setAdapter(cursorAdapter);
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final Cursor c = cursorAdapter.getCursor();
|
||||
if (c == null || !c.moveToPosition(position)) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
final String query = c.getString(c.getColumnIndexOrThrow(SearchHistory.QUERY));
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
searchListener.onSearch(query);
|
||||
}
|
||||
}
|
||||
});
|
||||
return listView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
listView.setAdapter(null);
|
||||
listView = null;
|
||||
}
|
||||
|
||||
private class SearchHistoryLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return new CursorLoader(getActivity(), SearchHistory.CONTENT_URI,
|
||||
PROJECTION, null, null, SearchHistory.DATE_LAST_VISITED + " DESC");
|
||||
}
|
||||
|
||||
setListAdapter(adapter);
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
if (cursorAdapter != null) {
|
||||
cursorAdapter.swapCursor(data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
if (cursorAdapter != null) {
|
||||
cursorAdapter.swapCursor(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,19 +5,27 @@
|
|||
package org.mozilla.search.autocomplete;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.SpannableString;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mozilla.search.R;
|
||||
import org.mozilla.search.autocomplete.SearchFragment.Suggestion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The adapter that is used to populate the autocomplete rows.
|
||||
*/
|
||||
class AutoCompleteAdapter extends ArrayAdapter<String> {
|
||||
class AutoCompleteAdapter extends ArrayAdapter<Suggestion> {
|
||||
|
||||
private final AcceptsJumpTaps acceptsJumpTaps;
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
public AutoCompleteAdapter(Context context, AcceptsJumpTaps acceptsJumpTaps) {
|
||||
// Uses '0' for the template id since we are overriding getView
|
||||
// and supplying our own view.
|
||||
|
@ -26,22 +34,30 @@ class AutoCompleteAdapter extends ArrayAdapter<String> {
|
|||
|
||||
// Disable notifying on change. We will notify ourselves in update.
|
||||
setNotifyOnChange(false);
|
||||
|
||||
inflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
AutoCompleteRowView view;
|
||||
|
||||
if (convertView == null) {
|
||||
view = new AutoCompleteRowView(getContext());
|
||||
} else {
|
||||
view = (AutoCompleteRowView) convertView;
|
||||
convertView = inflater.inflate(R.layout.search_auto_complete_row, null);
|
||||
}
|
||||
|
||||
view.setOnJumpListener(acceptsJumpTaps);
|
||||
view.setMainText(getItem(position));
|
||||
final Suggestion suggestion = getItem(position);
|
||||
|
||||
return view;
|
||||
final TextView textView = (TextView) convertView.findViewById(R.id.auto_complete_row_text);
|
||||
textView.setText(suggestion.display);
|
||||
|
||||
final View jumpButton = convertView.findViewById(R.id.auto_complete_row_jump_button);
|
||||
jumpButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
acceptsJumpTaps.onJumpTap(suggestion.value);
|
||||
}
|
||||
});
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,10 +65,10 @@ class AutoCompleteAdapter extends ArrayAdapter<String> {
|
|||
*
|
||||
* @param suggestions List of search suggestions.
|
||||
*/
|
||||
public void update(List<String> suggestions) {
|
||||
public void update(List<Suggestion> suggestions) {
|
||||
clear();
|
||||
if (suggestions != null) {
|
||||
for (String s : suggestions) {
|
||||
for (Suggestion s : suggestions) {
|
||||
add(s);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.search.autocomplete;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mozilla.search.R;
|
||||
|
||||
/**
|
||||
* One row withing the autocomplete suggestion list.
|
||||
*/
|
||||
class AutoCompleteRowView extends LinearLayout {
|
||||
|
||||
private TextView textView;
|
||||
private AcceptsJumpTaps onJumpListener;
|
||||
|
||||
public AutoCompleteRowView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOrientation(LinearLayout.HORIZONTAL);
|
||||
setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.search_auto_complete_row, this, true);
|
||||
|
||||
textView = (TextView) findViewById(R.id.auto_complete_row_text);
|
||||
|
||||
findViewById(R.id.auto_complete_row_jump_button).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (null == onJumpListener) {
|
||||
Log.e("SuggestionRow.onJump", "jump listener is null");
|
||||
return;
|
||||
}
|
||||
|
||||
onJumpListener.onJumpTap(textView.getText().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setMainText(String s) {
|
||||
textView.setText(s);
|
||||
}
|
||||
|
||||
public void setOnJumpListener(AcceptsJumpTaps onJumpListener) {
|
||||
this.onJumpListener = onJumpListener;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,9 @@ import android.support.v4.app.LoaderManager;
|
|||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.text.Editable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -28,6 +30,7 @@ import android.widget.TextView;
|
|||
|
||||
import org.mozilla.search.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -48,6 +51,9 @@ public class SearchFragment extends Fragment
|
|||
// Maximum number of results returned by the suggestion client
|
||||
private static final int SUGGESTION_MAX = 5;
|
||||
|
||||
// Color of search term match in search suggestion
|
||||
private static final int SUGGESTION_HIGHLIGHT_COLOR = 0xFF999999;
|
||||
|
||||
private SuggestClient suggestClient;
|
||||
private SuggestionLoaderCallbacks suggestionLoaderCallbacks;
|
||||
|
||||
|
@ -155,8 +161,8 @@ public class SearchFragment extends Fragment
|
|||
suggestionDropdown.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final String query = (String) suggestionDropdown.getItemAtPosition(position);
|
||||
startSearch(query);
|
||||
final Suggestion suggestion = (Suggestion) suggestionDropdown.getItemAtPosition(position);
|
||||
startSearch(suggestion.value);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -252,32 +258,48 @@ public class SearchFragment extends Fragment
|
|||
editText.setSelection(suggestion.length());
|
||||
}
|
||||
|
||||
private class SuggestionLoaderCallbacks implements LoaderManager.LoaderCallbacks<List<String>> {
|
||||
@Override
|
||||
public Loader<List<String>> onCreateLoader(int id, Bundle args) {
|
||||
// suggestClient is set to null in onDestroyView(), so using it
|
||||
// safely here relies on the fact that onCreateLoader() is called
|
||||
// synchronously in restartLoader().
|
||||
return new SuggestionAsyncLoader(getActivity(), suggestClient, args.getString(KEY_SEARCH_TERM));
|
||||
}
|
||||
public static class Suggestion {
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<List<String>> loader, List<String> suggestions) {
|
||||
autoCompleteAdapter.update(suggestions);
|
||||
}
|
||||
private static final ForegroundColorSpan COLOR_SPAN =
|
||||
new ForegroundColorSpan(SUGGESTION_HIGHLIGHT_COLOR);
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<List<String>> loader) {
|
||||
if (autoCompleteAdapter != null) {
|
||||
autoCompleteAdapter.update(null);
|
||||
public final String value;
|
||||
public final SpannableString display;
|
||||
|
||||
public Suggestion(String value, String searchTerm) {
|
||||
this.value = value;
|
||||
|
||||
display = new SpannableString(value);
|
||||
|
||||
// Highlight mixed-case matches.
|
||||
final int start = value.toLowerCase().indexOf(searchTerm.toLowerCase());
|
||||
if (start >= 0) {
|
||||
display.setSpan(COLOR_SPAN, start, searchTerm.length(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SuggestionAsyncLoader extends AsyncTaskLoader<List<String>> {
|
||||
private class SuggestionLoaderCallbacks implements LoaderManager.LoaderCallbacks<List<Suggestion>> {
|
||||
@Override
|
||||
public Loader<List<Suggestion>> onCreateLoader(int id, Bundle args) {
|
||||
return new SuggestionAsyncLoader(getActivity(), suggestClient, args.getString(KEY_SEARCH_TERM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<List<Suggestion>> loader, List<Suggestion> suggestions) {
|
||||
autoCompleteAdapter.update(suggestions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<List<Suggestion>> loader) {
|
||||
autoCompleteAdapter.update(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SuggestionAsyncLoader extends AsyncTaskLoader<List<Suggestion>> {
|
||||
private final SuggestClient suggestClient;
|
||||
private final String searchTerm;
|
||||
private List<String> suggestions;
|
||||
private List<Suggestion> suggestions;
|
||||
|
||||
public SuggestionAsyncLoader(Context context, SuggestClient suggestClient, String searchTerm) {
|
||||
super(context);
|
||||
|
@ -287,12 +309,19 @@ public class SearchFragment extends Fragment
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<String> loadInBackground() {
|
||||
return suggestClient.query(searchTerm);
|
||||
public List<Suggestion> loadInBackground() {
|
||||
final List<String> values = suggestClient.query(searchTerm);
|
||||
|
||||
final List<Suggestion> result = new ArrayList<Suggestion>(values.size());
|
||||
for (String value : values) {
|
||||
result.add(new Suggestion(value, searchTerm));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(List<String> suggestions) {
|
||||
public void deliverResult(List<Suggestion> suggestions) {
|
||||
this.suggestions = suggestions;
|
||||
|
||||
if (isStarted()) {
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.search.stream;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A temporary agent for loading cards into the pre-load card stream.
|
||||
* <p/>
|
||||
* When we have more agents, we'll want to put an agent manager between the PreSearchFragment
|
||||
* and the set of all agents. See autocomplete.AutoCompleteFragmentManager.
|
||||
*/
|
||||
public class PreloadAgent {
|
||||
|
||||
public static final List<TmpItem> ITEMS = new ArrayList<TmpItem>();
|
||||
|
||||
private static final Map<String, TmpItem> ITEM_MAP = new HashMap<String, TmpItem>();
|
||||
|
||||
static {
|
||||
addItem(new TmpItem("1", "Pre-load item1"));
|
||||
addItem(new TmpItem("2", "Pre-load item2"));
|
||||
}
|
||||
|
||||
private static void addItem(TmpItem item) {
|
||||
ITEMS.add(item);
|
||||
ITEM_MAP.put(item.id, item);
|
||||
}
|
||||
|
||||
public static class TmpItem {
|
||||
public final String id;
|
||||
public final String content;
|
||||
|
||||
public TmpItem(String id, String content) {
|
||||
this.id = id;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
|
Двоичные данные
mobile/android/search/res/drawable-hdpi/search_header.png
Двоичные данные
mobile/android/search/res/drawable-hdpi/search_header.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 4.0 KiB |
Двоичные данные
mobile/android/search/res/drawable-mdpi/search_header.png
Двоичные данные
mobile/android/search/res/drawable-mdpi/search_header.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
mobile/android/search/res/drawable-xhdpi/search_header.png
Двоичные данные
mobile/android/search/res/drawable-xhdpi/search_header.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 4.6 KiB |
|
@ -1,16 +0,0 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="org.mozilla.search.PostSearchFragment">
|
||||
|
||||
|
||||
<WebView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/webview"/>
|
||||
</RelativeLayout>
|
|
@ -11,25 +11,22 @@
|
|||
tools:context=".MainActivity">
|
||||
|
||||
<fragment
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:name="org.mozilla.search.PostSearchFragment"
|
||||
android:layout_marginTop="@dimen/search_bar_height"
|
||||
android:id="@+id/postsearch"
|
||||
/>
|
||||
|
||||
<fragment
|
||||
android:name="org.mozilla.search.PostSearchFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:name="org.mozilla.search.PreSearchFragment"
|
||||
android:layout_marginTop="@dimen/search_bar_height"
|
||||
android:layout_marginTop="@dimen/search_bar_height"/>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/presearch"
|
||||
/>
|
||||
|
||||
<fragment
|
||||
android:name="org.mozilla.search.PreSearchFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:name="org.mozilla.search.autocomplete.SearchFragment"
|
||||
android:id="@+id/search_fragment"/>
|
||||
android:layout_marginTop="@dimen/search_bar_height"/>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/search_fragment"
|
||||
android:name="org.mozilla.search.autocomplete.SearchFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</merge>
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:background="@drawable/search_card_background"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/card_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,17 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/site_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:padding="25dp"
|
||||
android:background="@drawable/search_card_background"
|
||||
android:fontFamily="sans-serif-thin"
|
||||
android:textSize="16sp"/>
|
|
@ -0,0 +1,8 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<WebView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
|
@ -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/. -->
|
||||
|
||||
<ListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"/>
|
|
@ -12,4 +12,6 @@
|
|||
<color name="card_background">#ffffff</color>
|
||||
<color name="card_shadow_1">#d4d4d4</color>
|
||||
<color name="card_shadow_2">#dddddd</color>
|
||||
|
||||
<!-- Search suggestion highlight color is defined in SearchFragment.java -->
|
||||
</resources>
|
|
@ -8,12 +8,10 @@ search_activity_sources = [
|
|||
'java/org/mozilla/search/autocomplete/AcceptsJumpTaps.java',
|
||||
'java/org/mozilla/search/autocomplete/AcceptsSearchQuery.java',
|
||||
'java/org/mozilla/search/autocomplete/AutoCompleteAdapter.java',
|
||||
'java/org/mozilla/search/autocomplete/AutoCompleteRowView.java',
|
||||
'java/org/mozilla/search/autocomplete/SearchFragment.java',
|
||||
'java/org/mozilla/search/autocomplete/SuggestClient.java',
|
||||
'java/org/mozilla/search/Constants.java',
|
||||
'java/org/mozilla/search/MainActivity.java',
|
||||
'java/org/mozilla/search/PostSearchFragment.java',
|
||||
'java/org/mozilla/search/PreSearchFragment.java',
|
||||
'java/org/mozilla/search/stream/PreloadAgent.java',
|
||||
]
|
||||
|
|
|
@ -1757,14 +1757,17 @@ ThreadClient.prototype = {
|
|||
this.client.request(packet, (aResponse) => {
|
||||
// Ignoring errors, since the user may be setting a breakpoint in a
|
||||
// dead script that will reappear on a page reload.
|
||||
if (aOnResponse) {
|
||||
let bpClient;
|
||||
if (aResponse.actor) {
|
||||
let root = this.client.mainRoot;
|
||||
let bpClient = new BreakpointClient(
|
||||
bpClient = new BreakpointClient(
|
||||
this.client,
|
||||
aResponse.actor,
|
||||
location,
|
||||
root.traits.conditionalBreakpoints ? condition : undefined
|
||||
);
|
||||
}
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse, bpClient);
|
||||
}
|
||||
if (aCallback) {
|
||||
|
|
|
@ -98,7 +98,7 @@ BreakpointStore.prototype = {
|
|||
get size() { return this._size; },
|
||||
|
||||
/**
|
||||
* Add a breakpoint to the breakpoint store.
|
||||
* Add a breakpoint to the breakpoint store if it doesn't already exist.
|
||||
*
|
||||
* @param Object aBreakpoint
|
||||
* The breakpoint to be added (not copied). It is an object with the
|
||||
|
@ -109,10 +109,11 @@ BreakpointStore.prototype = {
|
|||
* the whole line)
|
||||
* - condition (optional)
|
||||
* - actor (optional)
|
||||
* @returns Object aBreakpoint
|
||||
* The new or existing breakpoint.
|
||||
*/
|
||||
addBreakpoint: function (aBreakpoint) {
|
||||
let { url, line, column } = aBreakpoint;
|
||||
let updating = false;
|
||||
|
||||
if (column != null) {
|
||||
if (!this._breakpoints[url]) {
|
||||
|
@ -121,16 +122,22 @@ BreakpointStore.prototype = {
|
|||
if (!this._breakpoints[url][line]) {
|
||||
this._breakpoints[url][line] = [];
|
||||
}
|
||||
this._breakpoints[url][line][column] = aBreakpoint;
|
||||
if (!this._breakpoints[url][line][column]) {
|
||||
this._breakpoints[url][line][column] = aBreakpoint;
|
||||
this._size++;
|
||||
}
|
||||
return this._breakpoints[url][line][column];
|
||||
} else {
|
||||
// Add a breakpoint that breaks on the whole line.
|
||||
if (!this._wholeLineBreakpoints[url]) {
|
||||
this._wholeLineBreakpoints[url] = [];
|
||||
}
|
||||
this._wholeLineBreakpoints[url][line] = aBreakpoint;
|
||||
if (!this._wholeLineBreakpoints[url][line]) {
|
||||
this._wholeLineBreakpoints[url][line] = aBreakpoint;
|
||||
this._size++;
|
||||
}
|
||||
return this._wholeLineBreakpoints[url][line];
|
||||
}
|
||||
|
||||
this._size++;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1439,9 +1446,7 @@ ThreadActor.prototype = {
|
|||
|
||||
let locationPromise = this.sources.getGeneratedLocation(aRequest.location);
|
||||
return locationPromise.then(({url, line, column}) => {
|
||||
if (line == null ||
|
||||
line < 0 ||
|
||||
this.dbg.findScripts({ url: url }).length == 0) {
|
||||
if (line == null || line < 0) {
|
||||
return {
|
||||
error: "noScript",
|
||||
message: "Requested setting a breakpoint on "
|
||||
|
@ -1537,12 +1542,11 @@ ThreadActor.prototype = {
|
|||
// Find all scripts matching the given location
|
||||
let scripts = this.dbg.findScripts(aLocation);
|
||||
if (scripts.length == 0) {
|
||||
// Since we did not find any scripts to set the breakpoint on now, return
|
||||
// early. When a new script that matches this breakpoint location is
|
||||
// introduced, the breakpoint actor will already be in the breakpoint store
|
||||
// and will be set at that time.
|
||||
return {
|
||||
error: "noScript",
|
||||
message: "Requested setting a breakpoint on "
|
||||
+ aLocation.url + ":" + aLocation.line
|
||||
+ (aLocation.column != null ? ":" + aLocation.column : "")
|
||||
+ " but there is no Debugger.Script at that location",
|
||||
actor: actor.actorID
|
||||
};
|
||||
}
|
||||
|
@ -3561,16 +3565,29 @@ exports.ObjectActor = ObjectActor;
|
|||
DebuggerServer.ObjectActorPreviewers = {
|
||||
String: [function({obj, threadActor}, aGrip) {
|
||||
let result = genericObjectPreviewer("String", String, obj, threadActor);
|
||||
if (result) {
|
||||
let length = DevToolsUtils.getProperty(obj, "length");
|
||||
if (typeof length != "number") {
|
||||
return false;
|
||||
}
|
||||
let length = DevToolsUtils.getProperty(obj, "length");
|
||||
|
||||
aGrip.displayString = result.value;
|
||||
if (!result || typeof length != "number") {
|
||||
return false;
|
||||
}
|
||||
|
||||
aGrip.preview = {
|
||||
kind: "ArrayLike",
|
||||
length: length
|
||||
};
|
||||
|
||||
if (threadActor._gripDepth > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let items = aGrip.preview.items = [];
|
||||
|
||||
const max = Math.min(result.value.length, OBJECT_PREVIEW_MAX_ITEMS);
|
||||
for (let i = 0; i < max; i++) {
|
||||
let value = threadActor.createValueGrip(result.value[i]);
|
||||
items.push(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}],
|
||||
|
||||
|
|
|
@ -510,6 +510,17 @@ function resume(threadClient) {
|
|||
return rdpRequest(threadClient, threadClient.resume);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt JS execution for the specified thread.
|
||||
*
|
||||
* @param ThreadClient threadClient
|
||||
* @returns Promise
|
||||
*/
|
||||
function interrupt(threadClient) {
|
||||
dumpn("Interrupting.");
|
||||
return rdpRequest(threadClient, threadClient.interrupt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume JS execution for the specified thread and then wait for the next pause
|
||||
* event.
|
||||
|
|
|
@ -8,62 +8,65 @@
|
|||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
var gCallback;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
run_test_with_server(DebuggerServer, function () {
|
||||
run_test_with_server(WorkerDebuggerServer, do_test_finished);
|
||||
});
|
||||
do_test_pending();
|
||||
};
|
||||
|
||||
function run_test_with_server(aServer, aCallback)
|
||||
{
|
||||
gCallback = aCallback;
|
||||
initTestDebuggerServer(aServer);
|
||||
gDebuggee = addTestGlobal("test-stack", aServer);
|
||||
gClient = new DebuggerClient(aServer.connectPipe());
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function () {
|
||||
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_same_breakpoint();
|
||||
testSameBreakpoint();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_same_breakpoint()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
let path = getFilePath('test_breakpoint-01.js');
|
||||
let location = {
|
||||
url: path,
|
||||
line: gDebuggee.line0 + 3
|
||||
};
|
||||
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
|
||||
gThreadClient.setBreakpoint(location, function (aResponse, secondBpClient) {
|
||||
do_check_eq(bpClient.actor, secondBpClient.actor,
|
||||
"Should get the same actor w/ whole line breakpoints");
|
||||
let location = {
|
||||
url: path,
|
||||
line: gDebuggee.line0 + 2,
|
||||
column: 6
|
||||
};
|
||||
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
|
||||
gThreadClient.setBreakpoint(location, function (aResponse, secondBpClient) {
|
||||
do_check_eq(bpClient.actor, secondBpClient.actor,
|
||||
"Should get the same actor column breakpoints");
|
||||
gClient.close(gCallback);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
const SOURCE_URL = "http://example.com/source.js";
|
||||
|
||||
Components.utils.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"var b = 2;\n", // line0 + 3
|
||||
gDebuggee);
|
||||
}
|
||||
const testSameBreakpoint = Task.async(function* () {
|
||||
yield executeOnNextTickAndWaitForPause(evalCode, gClient);
|
||||
|
||||
// Whole line
|
||||
|
||||
let wholeLineLocation = {
|
||||
url: SOURCE_URL,
|
||||
line: 2
|
||||
};
|
||||
|
||||
let [firstResponse, firstBpClient] = yield setBreakpoint(gThreadClient, wholeLineLocation);
|
||||
let [secondResponse, secondBpClient] = yield setBreakpoint(gThreadClient, wholeLineLocation);
|
||||
|
||||
do_check_eq(firstBpClient.actor, secondBpClient.actor, "Should get the same actor w/ whole line breakpoints");
|
||||
|
||||
// Specific column
|
||||
|
||||
let columnLocation = {
|
||||
url: SOURCE_URL,
|
||||
line: 2,
|
||||
column: 6
|
||||
};
|
||||
|
||||
let [firstResponse, firstBpClient] = yield setBreakpoint(gThreadClient, columnLocation);
|
||||
let [secondResponse, secondBpClient] = yield setBreakpoint(gThreadClient, columnLocation);
|
||||
|
||||
do_check_eq(secondBpClient.actor, secondBpClient.actor, "Should get the same actor column breakpoints");
|
||||
|
||||
finishClient(gClient);
|
||||
});
|
||||
|
||||
function evalCode() {
|
||||
Components.utils.evalInSandbox(
|
||||
"" + function doStuff(k) { // line 1
|
||||
let arg = 15; // line 2 - Step in here
|
||||
k(arg); // line 3
|
||||
} + "\n" // line 4
|
||||
+ "debugger;", // line 5
|
||||
gDebuggee,
|
||||
"1.8",
|
||||
SOURCE_URL,
|
||||
1
|
||||
);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that setting a breakpoint in a not-yet-existing script doesn't throw
|
||||
* an error (see bug 897567). Also make sure that this breakpoint works.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
var gCallback;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
run_test_with_server(DebuggerServer, function () {
|
||||
run_test_with_server(WorkerDebuggerServer, do_test_finished);
|
||||
});
|
||||
do_test_pending();
|
||||
};
|
||||
|
||||
function run_test_with_server(aServer, aCallback)
|
||||
{
|
||||
gCallback = aCallback;
|
||||
initTestDebuggerServer(aServer);
|
||||
gDebuggee = addTestGlobal("test-breakpoints", aServer);
|
||||
gDebuggee.console = { log: x => void x };
|
||||
gClient = new DebuggerClient(aServer.connectPipe());
|
||||
gClient.connect(function () {
|
||||
attachTestTabAndResume(gClient,
|
||||
"test-breakpoints",
|
||||
function (aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
testBreakpoint();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const URL = "test.js";
|
||||
|
||||
function setUpCode() {
|
||||
Cu.evalInSandbox(
|
||||
"" + function test() { // 1
|
||||
var a = 1; // 2
|
||||
debugger; // 3
|
||||
} + // 4
|
||||
"\ndebugger;", // 5
|
||||
gDebuggee,
|
||||
"1.8",
|
||||
URL
|
||||
);
|
||||
}
|
||||
|
||||
const testBreakpoint = Task.async(function* () {
|
||||
const [response, bpClient] = yield setBreakpoint(gThreadClient, {url: URL, line: 2});
|
||||
ok(!response.error);
|
||||
|
||||
const actor = response.actor;
|
||||
ok(actor);
|
||||
|
||||
yield executeOnNextTickAndWaitForPause(setUpCode, gClient);
|
||||
yield resume(gThreadClient);
|
||||
|
||||
const packet = yield executeOnNextTickAndWaitForPause(gDebuggee.test, gClient);
|
||||
equal(packet.why.type, "breakpoint")
|
||||
notEqual(packet.why.actors.indexOf(actor), -1);
|
||||
|
||||
finishClient(gClient);
|
||||
});
|
|
@ -16,6 +16,7 @@ function run_test()
|
|||
test_add_breakpoint();
|
||||
test_remove_breakpoint();
|
||||
test_find_breakpoints();
|
||||
test_duplicate_breakpoints();
|
||||
}
|
||||
|
||||
function test_has_breakpoint() {
|
||||
|
@ -165,3 +166,28 @@ function test_find_breakpoints() {
|
|||
do_check_eq(bpSet.size, 0,
|
||||
"Should be able to filter the iteration by url and line");
|
||||
}
|
||||
|
||||
function test_duplicate_breakpoints() {
|
||||
let bpStore = new BreakpointStore();
|
||||
|
||||
// Breakpoint with column
|
||||
let location = {
|
||||
url: "http://example.com/foo.js",
|
||||
line: 10,
|
||||
column: 9
|
||||
};
|
||||
bpStore.addBreakpoint(location);
|
||||
bpStore.addBreakpoint(location);
|
||||
do_check_eq(bpStore.size, 1, "We should have only 1 column breakpoint");
|
||||
bpStore.removeBreakpoint(location);
|
||||
|
||||
// Breakpoint without column (whole line breakpoint)
|
||||
location = {
|
||||
url: "http://example.com/foo.js",
|
||||
line: 15
|
||||
};
|
||||
bpStore.addBreakpoint(location);
|
||||
bpStore.addBreakpoint(location);
|
||||
do_check_eq(bpStore.size, 1, "We should have only 1 whole line breakpoint");
|
||||
bpStore.removeBreakpoint(location);
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ reason = bug 820380
|
|||
[test_breakpoint-16.js]
|
||||
[test_breakpoint-17.js]
|
||||
[test_breakpoint-18.js]
|
||||
[test_breakpoint-19.js]
|
||||
[test_conditional_breakpoint-01.js]
|
||||
[test_conditional_breakpoint-02.js]
|
||||
[test_conditional_breakpoint-03.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче