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
This commit is contained in:
commit
b2f7f763c4
@ -1228,7 +1228,7 @@ pref("devtools.toolbox.footer.height", 250);
|
||||
pref("devtools.toolbox.sidebar.width", 500);
|
||||
pref("devtools.toolbox.host", "bottom");
|
||||
pref("devtools.toolbox.selectedTool", "webconsole");
|
||||
pref("devtools.toolbox.toolbarSpec", '["splitconsole", "paintflashing toggle","tilt toggle","scratchpad","resize toggle"]');
|
||||
pref("devtools.toolbox.toolbarSpec", '["splitconsole", "paintflashing toggle","tilt toggle","scratchpad","resize toggle","eyedropper"]');
|
||||
pref("devtools.toolbox.sideEnabled", true);
|
||||
pref("devtools.toolbox.zoomValue", "1");
|
||||
|
||||
@ -1239,6 +1239,7 @@ pref("devtools.command-button-paintflashing.enabled", false);
|
||||
pref("devtools.command-button-tilt.enabled", false);
|
||||
pref("devtools.command-button-scratchpad.enabled", false);
|
||||
pref("devtools.command-button-responsive.enabled", true);
|
||||
pref("devtools.command-button-eyedropper.enabled", false);
|
||||
|
||||
// Inspector preferences
|
||||
// Enable the Inspector
|
||||
|
@ -191,6 +191,60 @@ let AboutHomeListener = {
|
||||
};
|
||||
AboutHomeListener.init(this);
|
||||
|
||||
|
||||
let ContentSearchMediator = {
|
||||
|
||||
whitelist: new Set([
|
||||
"about:newtab",
|
||||
]),
|
||||
|
||||
init: function (chromeGlobal) {
|
||||
chromeGlobal.addEventListener("ContentSearchClient", this, true, true);
|
||||
addMessageListener("ContentSearch", this);
|
||||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
if (this._contentWhitelisted) {
|
||||
this._sendMsg(event.detail.type, event.detail.data);
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function (msg) {
|
||||
if (msg.data.type == "AddToWhitelist") {
|
||||
for (let uri of msg.data.data) {
|
||||
this.whitelist.add(uri);
|
||||
}
|
||||
this._sendMsg("AddToWhitelistAck");
|
||||
return;
|
||||
}
|
||||
if (this._contentWhitelisted) {
|
||||
this._fireEvent(msg.data.type, msg.data.data);
|
||||
}
|
||||
},
|
||||
|
||||
get _contentWhitelisted() {
|
||||
return this.whitelist.has(content.document.documentURI.toLowerCase());
|
||||
},
|
||||
|
||||
_sendMsg: function (type, data=null) {
|
||||
sendAsyncMessage("ContentSearch", {
|
||||
type: type,
|
||||
data: data,
|
||||
});
|
||||
},
|
||||
|
||||
_fireEvent: function (type, data=null) {
|
||||
content.dispatchEvent(new content.CustomEvent("ContentSearchService", {
|
||||
detail: {
|
||||
type: type,
|
||||
data: data,
|
||||
},
|
||||
}));
|
||||
},
|
||||
};
|
||||
ContentSearchMediator.init(this);
|
||||
|
||||
|
||||
var global = this;
|
||||
|
||||
// Lazily load the finder code
|
||||
|
@ -197,12 +197,18 @@ let gGrid = {
|
||||
}
|
||||
|
||||
let availSpace = document.documentElement.clientHeight - this._cellMargin -
|
||||
document.querySelector("#newtab-margin-undo-container").offsetHeight;
|
||||
document.querySelector("#newtab-margin-undo-container").offsetHeight -
|
||||
document.querySelector("#newtab-search-form").offsetHeight;
|
||||
let visibleRows = Math.floor(availSpace / this._cellHeight);
|
||||
this._node.style.height = this._computeHeight() + "px";
|
||||
this._node.style.maxHeight = this._computeHeight(visibleRows) + "px";
|
||||
this._node.style.maxWidth = gGridPrefs.gridColumns * this._cellWidth +
|
||||
GRID_WIDTH_EXTRA + "px";
|
||||
|
||||
// Resize the search bar.
|
||||
let width = parseFloat(window.getComputedStyle(this._node).width);
|
||||
let visibleCols = Math.floor(width / this._cellWidth);
|
||||
gSearch.setWidth(visibleCols * this._cellWidth - this._cellMargin);
|
||||
},
|
||||
|
||||
_shouldRenderGrid : function Grid_shouldRenderGrid() {
|
||||
|
@ -2,6 +2,11 @@
|
||||
* 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/. */
|
||||
|
||||
input {
|
||||
font: message-box !important;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -12,6 +17,7 @@ input[type=button] {
|
||||
position: relative;
|
||||
-moz-box-flex: 1;
|
||||
-moz-user-focus: normal;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
#newtab-scrollbox:not([page-disabled]) {
|
||||
@ -54,6 +60,7 @@ input[type=button] {
|
||||
#newtab-margin-undo-container {
|
||||
display: -moz-box;
|
||||
-moz-box-pack: center;
|
||||
margin-bottom: 26px; /* 32 - 6 search form top "padding" */
|
||||
}
|
||||
|
||||
#newtab-horizontal-margin {
|
||||
@ -64,10 +71,17 @@ input[type=button] {
|
||||
#newtab-margin-top,
|
||||
#newtab-margin-bottom {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#newtab-margin-top {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#newtab-margin-bottom {
|
||||
-moz-box-flex: 2;
|
||||
}
|
||||
|
||||
.newtab-side-margin {
|
||||
min-width: 16px;
|
||||
-moz-box-flex: 1;
|
||||
@ -213,7 +227,7 @@ input[type=button] {
|
||||
opacity: 0.01;
|
||||
}
|
||||
|
||||
/* PANEL */
|
||||
/* SPONSORED PANEL */
|
||||
#sponsored-panel {
|
||||
width: 330px;
|
||||
}
|
||||
@ -225,3 +239,156 @@ input[type=button] {
|
||||
#sponsored-panel .text-link {
|
||||
margin: 12px 0 0;
|
||||
}
|
||||
|
||||
/* SEARCH */
|
||||
#newtab-search-container {
|
||||
display: -moz-box;
|
||||
position: relative;
|
||||
-moz-box-align: center;
|
||||
-moz-box-pack: center;
|
||||
}
|
||||
|
||||
#newtab-search-container[page-disabled] {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#newtab-search-form {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: center;
|
||||
height: 44px; /* 32 + 6 logo top "padding" + 6 logo bottom "padding" */
|
||||
margin-bottom: 10px; /* 32 - 16 tiles top margin - 6 logo bottom "padding" */
|
||||
}
|
||||
|
||||
#newtab-search-logo {
|
||||
display: -moz-box;
|
||||
width: 77px; /* 65 image width + 6 left "padding" + 6 right "padding" */
|
||||
height: 38px; /* 26 image height + 6 top "padding" + 6 bottom "padding" */
|
||||
border: 1px solid transparent;
|
||||
-moz-margin-end: 8px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 65px 26px;
|
||||
}
|
||||
|
||||
#newtab-search-logo[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#newtab-search-logo[active],
|
||||
#newtab-search-logo:hover {
|
||||
background-color: #e9e9e9;
|
||||
border: 1px solid rgb(226, 227, 229);
|
||||
border-radius: 2.5px;
|
||||
}
|
||||
|
||||
#newtab-search-text {
|
||||
height: 32px;
|
||||
-moz-box-flex: 1;
|
||||
|
||||
padding: 0 8px;
|
||||
background: hsla(0,0%,100%,.9) padding-box;
|
||||
border: 1px solid;
|
||||
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
|
||||
box-shadow: 0 1px 0 hsla(210,65%,9%,.02) inset,
|
||||
0 0 2px hsla(210,65%,9%,.1) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.2);
|
||||
border-radius: 2.5px 0 0 2.5px;
|
||||
}
|
||||
|
||||
#newtab-search-text:-moz-dir(rtl) {
|
||||
border-radius: 0 2.5px 2.5px 0;
|
||||
}
|
||||
|
||||
#newtab-search-text:focus,
|
||||
#newtab-search-text[autofocus] {
|
||||
border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
|
||||
}
|
||||
|
||||
#newtab-search-submit {
|
||||
height: 32px;
|
||||
|
||||
-moz-margin-start: -1px;
|
||||
background: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
|
||||
padding: 0 9px;
|
||||
border: 1px solid;
|
||||
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
|
||||
-moz-border-start: 1px solid transparent;
|
||||
border-radius: 0 2.5px 2.5px 0;
|
||||
box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.2);
|
||||
cursor: pointer;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
#newtab-search-submit:-moz-dir(rtl) {
|
||||
border-radius: 2.5px 0 0 2.5px;
|
||||
}
|
||||
|
||||
#newtab-search-text:focus + #newtab-search-submit,
|
||||
#newtab-search-text + #newtab-search-submit:hover,
|
||||
#newtab-search-text[autofocus] + #newtab-search-submit {
|
||||
border-color: #59b5fc #45a3e7 #3294d5;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#newtab-search-text:focus + #newtab-search-submit,
|
||||
#newtab-search-text[autofocus] + #newtab-search-submit {
|
||||
background-image: linear-gradient(#4cb1ff, #1793e5);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.1) inset,
|
||||
0 1px 0 hsla(210,54%,20%,.03);
|
||||
}
|
||||
|
||||
#newtab-search-text + #newtab-search-submit:hover {
|
||||
background-image: linear-gradient(#66bdff, #0d9eff);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.1) inset,
|
||||
0 1px 0 hsla(210,54%,20%,.03),
|
||||
0 0 4px hsla(206,100%,20%,.2);
|
||||
}
|
||||
|
||||
#newtab-search-text + #newtab-search-submit:hover:active {
|
||||
box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
|
||||
0 0 1px hsla(211,79%,6%,.2) inset;
|
||||
transition-duration: 0ms;
|
||||
}
|
||||
|
||||
#newtab-search-panel .panel-arrowcontent {
|
||||
-moz-padding-start: 0;
|
||||
-moz-padding-end: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
background: rgb(248, 250, 251);
|
||||
}
|
||||
|
||||
.newtab-search-panel-engine {
|
||||
-moz-box-align: center;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
-moz-padding-start: 24px;
|
||||
-moz-padding-end: 24px;
|
||||
}
|
||||
|
||||
.newtab-search-panel-engine:not(:last-child) {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.newtab-search-panel-engine > image {
|
||||
-moz-margin-end: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
|
||||
}
|
||||
|
||||
.newtab-search-panel-engine > label {
|
||||
-moz-padding-start: 0;
|
||||
-moz-margin-start: 0;
|
||||
color: rgb(130, 132, 133);
|
||||
}
|
||||
|
||||
.newtab-search-panel-engine[selected] {
|
||||
background: url("chrome://global/skin/menu/shared-menu-check.png") center left 4px no-repeat transparent;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ function inPrivateBrowsingMode() {
|
||||
}
|
||||
|
||||
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
#include transformations.js
|
||||
#include page.js
|
||||
@ -54,6 +55,7 @@ const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||
#include dropPreview.js
|
||||
#include updater.js
|
||||
#include undo.js
|
||||
#include search.js
|
||||
|
||||
// Everything is loaded. Initialize the New Tab Page.
|
||||
gPage.init();
|
||||
|
@ -11,6 +11,8 @@
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % newTabDTD SYSTEM "chrome://browser/locale/newTab.dtd">
|
||||
%newTabDTD;
|
||||
<!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd">
|
||||
%searchBarDTD;
|
||||
]>
|
||||
|
||||
<xul:window id="newtab-window" xmlns="http://www.w3.org/1999/xhtml"
|
||||
@ -24,6 +26,13 @@
|
||||
value="&newtab.panel.link.text;" />
|
||||
</xul:panel>
|
||||
|
||||
<xul:panel id="newtab-search-panel" orient="vertical" type="arrow"
|
||||
noautohide="true">
|
||||
<xul:hbox id="newtab-search-manage" class="newtab-search-panel-engine">
|
||||
<xul:label>&cmd_engineManager.label;</xul:label>
|
||||
</xul:hbox>
|
||||
</xul:panel>
|
||||
|
||||
<div id="newtab-scrollbox">
|
||||
|
||||
<div id="newtab-vertical-margin">
|
||||
@ -46,6 +55,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="newtab-search-container">
|
||||
<form id="newtab-search-form" name="searchForm">
|
||||
<div id="newtab-search-logo"/>
|
||||
<input type="text" name="q" value="" id="newtab-search-text"
|
||||
maxlength="256" dir="auto"/>
|
||||
<input id="newtab-search-submit" type="submit"
|
||||
value="&searchEndCap.label;"/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="newtab-horizontal-margin">
|
||||
<div class="newtab-side-margin"/>
|
||||
|
||||
|
@ -111,6 +111,8 @@ let gPage = {
|
||||
|
||||
this._initialized = true;
|
||||
|
||||
gSearch.init();
|
||||
|
||||
this._mutationObserver = new MutationObserver(() => {
|
||||
if (this.allowBackgroundCaptures) {
|
||||
Services.telemetry.getHistogramById("NEWTAB_PAGE_SHOWN").add(true);
|
||||
@ -138,6 +140,10 @@ let gPage = {
|
||||
let shownCount = Math.min(10, count);
|
||||
Services.telemetry.getHistogramById(shownId).add(shownCount);
|
||||
}
|
||||
|
||||
// content.js isn't loaded for the page while it's in the preloader,
|
||||
// which is why this is necessary.
|
||||
gSearch.setUpInitialState();
|
||||
}
|
||||
});
|
||||
this._mutationObserver.observe(document.documentElement, {
|
||||
@ -164,7 +170,7 @@ let gPage = {
|
||||
*/
|
||||
_updateAttributes: function Page_updateAttributes(aValue) {
|
||||
// Set the nodes' states.
|
||||
let nodeSelector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid";
|
||||
let nodeSelector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid, #newtab-search-container";
|
||||
for (let node of document.querySelectorAll(nodeSelector)) {
|
||||
if (aValue)
|
||||
node.removeAttribute("page-disabled");
|
||||
|
170
browser/base/content/newtab/search.js
Normal file
170
browser/base/content/newtab/search.js
Normal file
@ -0,0 +1,170 @@
|
||||
#ifdef 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/. */
|
||||
#endif
|
||||
|
||||
let gSearch = {
|
||||
|
||||
currentEngineName: null,
|
||||
|
||||
init: function () {
|
||||
for (let idSuffix of this._nodeIDSuffixes) {
|
||||
this._nodes[idSuffix] =
|
||||
document.getElementById("newtab-search-" + idSuffix);
|
||||
}
|
||||
|
||||
window.addEventListener("ContentSearchService", this);
|
||||
this.setUpInitialState();
|
||||
},
|
||||
|
||||
setUpInitialState: function () {
|
||||
this._send("GetState");
|
||||
},
|
||||
|
||||
showPanel: function () {
|
||||
let panel = this._nodes.panel;
|
||||
let logo = this._nodes.logo;
|
||||
panel.openPopup(logo);
|
||||
logo.setAttribute("active", "true");
|
||||
panel.addEventListener("popuphidden", function onHidden() {
|
||||
panel.removeEventListener("popuphidden", onHidden);
|
||||
logo.removeAttribute("active");
|
||||
});
|
||||
},
|
||||
|
||||
search: function (event) {
|
||||
event.preventDefault();
|
||||
let searchStr = this._nodes.text.value;
|
||||
if (this.currentEngineName && searchStr.length) {
|
||||
this._send("Search", {
|
||||
engineName: this.currentEngineName,
|
||||
searchString: searchStr,
|
||||
whence: "newtab",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
manageEngines: function () {
|
||||
this._nodes.panel.hidePopup();
|
||||
this._send("ManageEngines");
|
||||
},
|
||||
|
||||
setWidth: function (width) {
|
||||
this._nodes.form.style.width = width + "px";
|
||||
this._nodes.form.style.maxWidth = width + "px";
|
||||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
this["on" + event.detail.type](event.detail.data);
|
||||
},
|
||||
|
||||
onState: function (data) {
|
||||
this._makePanel(data.engines);
|
||||
this._setCurrentEngine(data.currentEngine);
|
||||
this._initWhenInitalStateReceived();
|
||||
},
|
||||
|
||||
onCurrentEngine: function (engineName) {
|
||||
this._setCurrentEngine(engineName);
|
||||
},
|
||||
|
||||
_nodeIDSuffixes: [
|
||||
"form",
|
||||
"logo",
|
||||
"manage",
|
||||
"panel",
|
||||
"text",
|
||||
],
|
||||
|
||||
_nodes: {},
|
||||
|
||||
_initWhenInitalStateReceived: function () {
|
||||
this._nodes.form.addEventListener("submit", e => this.search(e));
|
||||
this._nodes.logo.addEventListener("click", e => this.showPanel());
|
||||
this._nodes.manage.addEventListener("click", e => this.manageEngines());
|
||||
this._initWhenInitalStateReceived = function () {};
|
||||
},
|
||||
|
||||
_send: function (type, data=null) {
|
||||
window.dispatchEvent(new CustomEvent("ContentSearchClient", {
|
||||
detail: {
|
||||
type: type,
|
||||
data: data,
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
_makePanel: function (engines) {
|
||||
let panel = this._nodes.panel;
|
||||
|
||||
// Empty the panel except for the Manage Engines row.
|
||||
let i = 0;
|
||||
while (i < panel.childNodes.length) {
|
||||
let node = panel.childNodes[i];
|
||||
if (node != this._nodes.manage) {
|
||||
panel.removeChild(node);
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add all the engines.
|
||||
for (let engine of engines) {
|
||||
panel.insertBefore(this._makePanelEngine(panel, engine),
|
||||
this._nodes.manage);
|
||||
}
|
||||
},
|
||||
|
||||
_makePanelEngine: function (panel, engine) {
|
||||
let box = document.createElementNS(XUL_NAMESPACE, "hbox");
|
||||
box.className = "newtab-search-panel-engine";
|
||||
box.setAttribute("engine", engine.name);
|
||||
|
||||
box.addEventListener("click", () => {
|
||||
this._send("SetCurrentEngine", engine.name);
|
||||
panel.hidePopup();
|
||||
this._nodes.text.focus();
|
||||
});
|
||||
|
||||
let image = document.createElementNS(XUL_NAMESPACE, "image");
|
||||
if (engine.iconURI) {
|
||||
image.setAttribute("src", engine.iconURI);
|
||||
}
|
||||
box.appendChild(image);
|
||||
|
||||
let label = document.createElementNS(XUL_NAMESPACE, "label");
|
||||
label.setAttribute("value", engine.name);
|
||||
box.appendChild(label);
|
||||
|
||||
return box;
|
||||
},
|
||||
|
||||
_setCurrentEngine: function (engine) {
|
||||
this.currentEngineName = engine.name;
|
||||
|
||||
// Set the logo.
|
||||
let logoURI = window.devicePixelRatio == 2 ? engine.logo2xURI :
|
||||
engine.logoURI;
|
||||
if (logoURI) {
|
||||
this._nodes.logo.hidden = false;
|
||||
this._nodes.logo.style.backgroundImage = "url(" + logoURI + ")";
|
||||
this._nodes.text.placeholder = "";
|
||||
}
|
||||
else {
|
||||
this._nodes.logo.hidden = true;
|
||||
this._nodes.text.placeholder = engine.name;
|
||||
}
|
||||
|
||||
// Set the selected state of all the engines in the panel.
|
||||
for (let box of this._nodes.panel.childNodes) {
|
||||
if (box.getAttribute("engine") == engine.name) {
|
||||
box.setAttribute("selected", "true");
|
||||
}
|
||||
else {
|
||||
box.removeAttribute("selected");
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
@ -399,7 +399,6 @@ skip-if = e10s # Bug ????? - test calls gBrowser.contentWindow.stop
|
||||
[browser_urlbar_search_healthreport.js]
|
||||
skip-if = e10s # Bug ?????? - FHR tests failing (either with "no data for today" or "2 records for today")
|
||||
[browser_utilityOverlay.js]
|
||||
skip-if = e10s # Bug 921947 - openNewTabWith failed with window.content.document being null
|
||||
[browser_visibleFindSelection.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
[browser_visibleLabel.js]
|
||||
|
@ -1,6 +1,9 @@
|
||||
[DEFAULT]
|
||||
support-files = head.js
|
||||
skip-if = e10s # Bug ?????? - about:newtab tests don't work in e10s
|
||||
support-files =
|
||||
head.js
|
||||
searchEngineLogo.xml
|
||||
searchEngineNoLogo.xml
|
||||
|
||||
[browser_newtab_background_captures.js]
|
||||
[browser_newtab_block.js]
|
||||
@ -25,6 +28,7 @@ skip-if = os == "mac" # Intermittent failures, bug 898317
|
||||
[browser_newtab_focus.js]
|
||||
[browser_newtab_perwindow_private_browsing.js]
|
||||
[browser_newtab_reset.js]
|
||||
[browser_newtab_search.js]
|
||||
[browser_newtab_sponsored_icon_click.js]
|
||||
[browser_newtab_tabsync.js]
|
||||
[browser_newtab_undo.js]
|
||||
|
@ -9,9 +9,9 @@ function runTests() {
|
||||
Services.prefs.setIntPref("accessibility.tabfocus", 7);
|
||||
|
||||
// Focus count in new tab page.
|
||||
// 28 = 9 * 3 + 1 = 9 sites and 1 toggle button, each site has a link, a pin
|
||||
// and a remove button.
|
||||
let FOCUS_COUNT = 28;
|
||||
// 30 = 9 * 3 + 3 = 9 sites, each with link, pin and remove buttons; search
|
||||
// bar; search button; and toggle button.
|
||||
let FOCUS_COUNT = 30;
|
||||
|
||||
// Create a new tab page.
|
||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||
|
295
browser/base/content/test/newtab/browser_newtab_search.js
Normal file
295
browser/base/content/test/newtab/browser_newtab_search.js
Normal file
@ -0,0 +1,295 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// See browser/components/search/test/browser_*_behavior.js for tests of actual
|
||||
// searches.
|
||||
|
||||
const ENGINE_LOGO = "searchEngineLogo.xml";
|
||||
const ENGINE_NO_LOGO = "searchEngineNoLogo.xml";
|
||||
|
||||
const SERVICE_EVENT_NAME = "ContentSearchService";
|
||||
|
||||
const LOGO_LOW_DPI_SIZE = [65, 26];
|
||||
const LOGO_HIGH_DPI_SIZE = [130, 52];
|
||||
|
||||
// The test has an expected search event queue and a search event listener.
|
||||
// Search events that are expected to happen are added to the queue, and the
|
||||
// listener consumes the queue and ensures that each event it receives is at
|
||||
// the head of the queue.
|
||||
//
|
||||
// Each item in the queue is an object { type, deferred }. type is the
|
||||
// expected search event type. deferred is a Promise.defer() value that is
|
||||
// resolved when the event is consumed.
|
||||
var gExpectedSearchEventQueue = [];
|
||||
|
||||
var gNewEngines = [];
|
||||
|
||||
function runTests() {
|
||||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
|
||||
yield addNewTabPageTab();
|
||||
yield whenSearchInitDone();
|
||||
|
||||
// The tab is removed at the end of the test, so there's no need to remove
|
||||
// this listener at the end of the test.
|
||||
info("Adding search event listener");
|
||||
getContentWindow().addEventListener(SERVICE_EVENT_NAME, searchEventListener);
|
||||
|
||||
let panel = searchPanel();
|
||||
is(panel.state, "closed", "Search panel should be closed initially");
|
||||
|
||||
// The panel's animation often is not finished when the test clicks on panel
|
||||
// children, which makes the test click the wrong children, so disable it.
|
||||
panel.setAttribute("animate", "false");
|
||||
|
||||
// Add the two test engines.
|
||||
let logoEngine = null;
|
||||
yield promiseNewSearchEngine(true).then(engine => {
|
||||
logoEngine = engine;
|
||||
TestRunner.next();
|
||||
});
|
||||
ok(!!logoEngine.getIconURLBySize(...LOGO_LOW_DPI_SIZE),
|
||||
"Sanity check: engine should have 1x logo");
|
||||
ok(!!logoEngine.getIconURLBySize(...LOGO_HIGH_DPI_SIZE),
|
||||
"Sanity check: engine should have 2x logo");
|
||||
|
||||
let noLogoEngine = null;
|
||||
yield promiseNewSearchEngine(false).then(engine => {
|
||||
noLogoEngine = engine;
|
||||
TestRunner.next();
|
||||
});
|
||||
ok(!noLogoEngine.getIconURLBySize(...LOGO_LOW_DPI_SIZE),
|
||||
"Sanity check: engine should not have 1x logo");
|
||||
ok(!noLogoEngine.getIconURLBySize(...LOGO_HIGH_DPI_SIZE),
|
||||
"Sanity check: engine should not have 2x logo");
|
||||
|
||||
// Use the search service to change the current engine to the logo engine.
|
||||
Services.search.currentEngine = logoEngine;
|
||||
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
|
||||
checkCurrentEngine(ENGINE_LOGO);
|
||||
|
||||
// Click the logo to open the search panel.
|
||||
yield Promise.all([
|
||||
promisePanelShown(panel),
|
||||
promiseClick(logoImg()),
|
||||
]).then(TestRunner.next);
|
||||
|
||||
// In the search panel, click the no-logo engine. It should become the
|
||||
// current engine.
|
||||
let noLogoBox = null;
|
||||
for (let box of panel.childNodes) {
|
||||
if (box.getAttribute("engine") == noLogoEngine.name) {
|
||||
noLogoBox = box;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(noLogoBox, "Search panel should contain the no-logo engine");
|
||||
yield Promise.all([
|
||||
promiseSearchEvents(["CurrentEngine"]),
|
||||
promiseClick(noLogoBox),
|
||||
]).then(TestRunner.next);
|
||||
|
||||
checkCurrentEngine(ENGINE_NO_LOGO);
|
||||
|
||||
// Switch back to the logo engine.
|
||||
Services.search.currentEngine = logoEngine;
|
||||
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
|
||||
checkCurrentEngine(ENGINE_LOGO);
|
||||
|
||||
// Open the panel again.
|
||||
yield Promise.all([
|
||||
promisePanelShown(panel),
|
||||
promiseClick(logoImg()),
|
||||
]).then(TestRunner.next);
|
||||
|
||||
// In the search panel, click the Manage Engines box.
|
||||
let manageBox = $("manage");
|
||||
ok(!!manageBox, "The Manage Engines box should be present in the document");
|
||||
yield Promise.all([
|
||||
promiseManagerOpen(),
|
||||
promiseClick(manageBox),
|
||||
]).then(TestRunner.next);
|
||||
|
||||
// Done. Revert the current engine and remove the new engines.
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
|
||||
|
||||
let events = [];
|
||||
for (let engine of gNewEngines) {
|
||||
Services.search.removeEngine(engine);
|
||||
events.push("State");
|
||||
}
|
||||
yield promiseSearchEvents(events).then(TestRunner.next);
|
||||
}
|
||||
|
||||
function searchEventListener(event) {
|
||||
info("Got search event " + event.detail.type);
|
||||
let passed = false;
|
||||
let nonempty = gExpectedSearchEventQueue.length > 0;
|
||||
ok(nonempty, "Expected search event queue should be nonempty");
|
||||
if (nonempty) {
|
||||
let { type, deferred } = gExpectedSearchEventQueue.shift();
|
||||
is(event.detail.type, type, "Got expected search event " + type);
|
||||
if (event.detail.type == type) {
|
||||
passed = true;
|
||||
// Let gSearch respond to the event before continuing.
|
||||
executeSoon(() => deferred.resolve());
|
||||
}
|
||||
}
|
||||
if (!passed) {
|
||||
info("Didn't get expected event, stopping the test");
|
||||
getContentWindow().removeEventListener(SERVICE_EVENT_NAME,
|
||||
searchEventListener);
|
||||
// Set next() to a no-op so the test really does stop.
|
||||
TestRunner.next = function () {};
|
||||
TestRunner.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function $(idSuffix) {
|
||||
return getContentDocument().getElementById("newtab-search-" + idSuffix);
|
||||
}
|
||||
|
||||
function promiseSearchEvents(events) {
|
||||
info("Expecting search events: " + events);
|
||||
events = events.map(e => ({ type: e, deferred: Promise.defer() }));
|
||||
gExpectedSearchEventQueue.push(...events);
|
||||
return Promise.all(events.map(e => e.deferred.promise));
|
||||
}
|
||||
|
||||
function promiseNewSearchEngine(withLogo) {
|
||||
let basename = withLogo ? ENGINE_LOGO : ENGINE_NO_LOGO;
|
||||
info("Waiting for engine to be added: " + basename);
|
||||
|
||||
// Wait for the search events triggered by adding the new engine.
|
||||
// engine-added engine-loaded
|
||||
let expectedSearchEvents = ["State", "State"];
|
||||
if (withLogo) {
|
||||
// an engine-changed for each of the two logos
|
||||
expectedSearchEvents.push("State", "State");
|
||||
}
|
||||
let eventPromise = promiseSearchEvents(expectedSearchEvents);
|
||||
|
||||
// Wait for addEngine().
|
||||
let addDeferred = Promise.defer();
|
||||
let url = getRootDirectory(gTestPath) + basename;
|
||||
Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, {
|
||||
onSuccess: function (engine) {
|
||||
info("Search engine added: " + basename);
|
||||
gNewEngines.push(engine);
|
||||
addDeferred.resolve(engine);
|
||||
},
|
||||
onError: function (errCode) {
|
||||
ok(false, "addEngine failed with error code " + errCode);
|
||||
addDeferred.reject();
|
||||
},
|
||||
});
|
||||
|
||||
// Make a new promise that wraps the previous promises. The only point of
|
||||
// this is to pass the new engine to the yielder via deferred.resolve(),
|
||||
// which is a little nicer than passing an array whose first element is the
|
||||
// new engine.
|
||||
let deferred = Promise.defer();
|
||||
Promise.all([addDeferred.promise, eventPromise]).then(values => {
|
||||
let newEngine = values[0];
|
||||
deferred.resolve(newEngine);
|
||||
}, () => deferred.reject());
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkCurrentEngine(basename) {
|
||||
let engine = Services.search.currentEngine;
|
||||
ok(engine.name.contains(basename),
|
||||
"Sanity check: current engine: engine.name=" + engine.name +
|
||||
" basename=" + basename);
|
||||
|
||||
// gSearch.currentEngineName
|
||||
is(gSearch().currentEngineName, engine.name,
|
||||
"currentEngineName: " + engine.name);
|
||||
|
||||
// search bar logo
|
||||
let logoSize = [px * window.devicePixelRatio for (px of LOGO_LOW_DPI_SIZE)];
|
||||
let logoURI = engine.getIconURLBySize(...logoSize);
|
||||
let logo = logoImg();
|
||||
is(logo.hidden, !logoURI,
|
||||
"Logo should be visible iff engine has a logo: " + engine.name);
|
||||
if (logoURI) {
|
||||
is(logo.style.backgroundImage, 'url("' + logoURI + '")', "Logo URI");
|
||||
}
|
||||
|
||||
// "selected" attributes of engines in the panel
|
||||
let panel = searchPanel();
|
||||
for (let engineBox of panel.childNodes) {
|
||||
let engineName = engineBox.getAttribute("engine");
|
||||
if (engineName == engine.name) {
|
||||
is(engineBox.getAttribute("selected"), "true",
|
||||
"Engine box's selected attribute should be true for " +
|
||||
"selected engine: " + engineName);
|
||||
}
|
||||
else {
|
||||
ok(!engineBox.hasAttribute("selected"),
|
||||
"Engine box's selected attribute should be absent for " +
|
||||
"non-selected engine: " + engineName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function promisePanelShown(panel) {
|
||||
let deferred = Promise.defer();
|
||||
info("Waiting for popupshown");
|
||||
panel.addEventListener("popupshown", function onEvent() {
|
||||
panel.removeEventListener("popupshown", onEvent);
|
||||
is(panel.state, "open", "Panel state");
|
||||
executeSoon(() => deferred.resolve());
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseClick(node) {
|
||||
let deferred = Promise.defer();
|
||||
let win = getContentWindow();
|
||||
SimpleTest.waitForFocus(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(node, {}, win);
|
||||
deferred.resolve();
|
||||
}, win);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseManagerOpen() {
|
||||
info("Waiting for the search manager window to open...");
|
||||
let deferred = Promise.defer();
|
||||
let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Ci.nsIWindowWatcher);
|
||||
winWatcher.registerNotification(function onWin(subj, topic, data) {
|
||||
if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
|
||||
subj.addEventListener("load", function onLoad() {
|
||||
subj.removeEventListener("load", onLoad);
|
||||
if (subj.document.documentURI ==
|
||||
"chrome://browser/content/search/engineManager.xul") {
|
||||
winWatcher.unregisterNotification(onWin);
|
||||
ok(true, "Observed search manager window opened");
|
||||
is(subj.opener, gWindow,
|
||||
"Search engine manager opener should be the chrome browser " +
|
||||
"window containing the newtab page");
|
||||
executeSoon(() => {
|
||||
subj.close();
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function searchPanel() {
|
||||
return $("panel");
|
||||
}
|
||||
|
||||
function logoImg() {
|
||||
return $("logo");
|
||||
}
|
||||
|
||||
function gSearch() {
|
||||
return getContentWindow().gSearch;
|
||||
}
|
@ -5,6 +5,10 @@ function runTests() {
|
||||
yield setLinks("0");
|
||||
yield addNewTabPageTab();
|
||||
|
||||
// When gSearch modifies the DOM as it sets itself up, it can prevent the
|
||||
// popup from opening, depending on the timing. Wait until that's done.
|
||||
yield whenSearchInitDone();
|
||||
|
||||
let site = getCell(0).node.querySelector(".newtab-site");
|
||||
site.setAttribute("type", "sponsored");
|
||||
|
||||
|
@ -25,10 +25,41 @@ let isLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc);
|
||||
let isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
|
||||
let gWindow = window;
|
||||
|
||||
// The tests assume all three rows of sites are shown, but the window may be too
|
||||
// short to actually show three rows. Resize it if necessary.
|
||||
let requiredInnerHeight =
|
||||
40 + 32 + // undo container + bottom margin
|
||||
44 + 32 + // search bar + bottom margin
|
||||
(3 * (150 + 32)) + // 3 rows * (tile height + title and bottom margin)
|
||||
100; // breathing room
|
||||
|
||||
let oldInnerHeight = null;
|
||||
if (gBrowser.contentWindow.innerHeight < requiredInnerHeight) {
|
||||
oldInnerHeight = gBrowser.contentWindow.innerHeight;
|
||||
info("Changing browser inner height from " + oldInnerHeight + " to " +
|
||||
requiredInnerHeight);
|
||||
gBrowser.contentWindow.innerHeight = requiredInnerHeight;
|
||||
let screenHeight = {};
|
||||
Cc["@mozilla.org/gfx/screenmanager;1"].
|
||||
getService(Ci.nsIScreenManager).
|
||||
primaryScreen.
|
||||
GetAvailRectDisplayPix({}, {}, {}, screenHeight);
|
||||
screenHeight = screenHeight.value;
|
||||
if (screenHeight < gBrowser.contentWindow.outerHeight) {
|
||||
info("Warning: Browser outer height is now " +
|
||||
gBrowser.contentWindow.outerHeight + ", which is larger than the " +
|
||||
"available screen height, " + screenHeight +
|
||||
". That may cause problems.");
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
while (gWindow.gBrowser.tabs.length > 1)
|
||||
gWindow.gBrowser.removeTab(gWindow.gBrowser.tabs[1]);
|
||||
|
||||
if (oldInnerHeight)
|
||||
gBrowser.contentWindow.innerHeight = oldInnerHeight;
|
||||
|
||||
Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED);
|
||||
Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE);
|
||||
|
||||
@ -549,3 +580,35 @@ function whenPagesUpdated(aCallback, aOnlyIfHidden=false) {
|
||||
NewTabUtils.allPages.unregister(page);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits a small amount of time for search events to stop occurring in the
|
||||
* newtab page.
|
||||
*
|
||||
* newtab pages receive some search events around load time that are difficult
|
||||
* to predict. There are two categories of such events: (1) "State" events
|
||||
* triggered by engine notifications like engine-changed, due to the search
|
||||
* service initializing itself on app startup. This can happen when a test is
|
||||
* the first test to run. (2) "State" events triggered by the newtab page
|
||||
* itself when gSearch first sets itself up. newtab preloading makes these a
|
||||
* pain to predict.
|
||||
*/
|
||||
function whenSearchInitDone() {
|
||||
info("Waiting for initial search events...");
|
||||
let numTicks = 0;
|
||||
function reset(event) {
|
||||
info("Got initial search event " + event.detail.type +
|
||||
", waiting for more...");
|
||||
numTicks = 0;
|
||||
}
|
||||
let eventName = "ContentSearchService";
|
||||
getContentWindow().addEventListener(eventName, reset);
|
||||
let interval = window.setInterval(() => {
|
||||
if (++numTicks >= 100) {
|
||||
info("Done waiting for initial search events");
|
||||
window.clearInterval(interval);
|
||||
getContentWindow().removeEventListener(eventName, reset);
|
||||
TestRunner.next();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
7
browser/base/content/test/newtab/searchEngineLogo.xml
Normal file
7
browser/base/content/test/newtab/searchEngineLogo.xml
Normal file
File diff suppressed because one or more lines are too long
5
browser/base/content/test/newtab/searchEngineNoLogo.xml
Normal file
5
browser/base/content/test/newtab/searchEngineNoLogo.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>browser_newtab_search searchEngineNoLogo.xml</ShortName>
|
||||
<Url type="text/html" method="GET" template="http://browser-newtab-search.com/nologo" rel="searchform"/>
|
||||
</SearchPlugin>
|
@ -599,17 +599,14 @@ function makeURLAbsolute(aBase, aUrl)
|
||||
return makeURI(aUrl, null, makeURI(aBase)).spec;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* openNewTabWith: opens a new tab with the given URL.
|
||||
*
|
||||
* @param aURL
|
||||
* The URL to open (as a string).
|
||||
* @param aDocument
|
||||
* The document from which the URL came, or null. This is used to set the
|
||||
* referrer header and to do a security check of whether the document is
|
||||
* allowed to reference the URL. If null, there will be no referrer
|
||||
* header and no security check.
|
||||
* Note this parameter is now ignored. There is no security check & no
|
||||
* referrer header derived from aDocument (null case).
|
||||
* @param aPostData
|
||||
* Form POST data, or null.
|
||||
* @param aEvent
|
||||
@ -620,46 +617,40 @@ function makeURLAbsolute(aBase, aUrl)
|
||||
* (e.g., Google's I Feel Lucky) for interpretation. This parameter may
|
||||
* be undefined in which case it is treated as false.
|
||||
* @param [optional] aReferrer
|
||||
* If aDocument is null, then this will be used as the referrer.
|
||||
* There will be no security check.
|
||||
* This will be used as the referrer. There will be no security check.
|
||||
*/
|
||||
function openNewTabWith(aURL, aDocument, aPostData, aEvent,
|
||||
aAllowThirdPartyFixup, aReferrer) {
|
||||
if (aDocument)
|
||||
urlSecurityCheck(aURL, aDocument.nodePrincipal);
|
||||
|
||||
// As in openNewWindowWith(), we want to pass the charset of the
|
||||
// current document over to a new tab.
|
||||
var originCharset = aDocument && aDocument.characterSet;
|
||||
if (!originCharset &&
|
||||
document.documentElement.getAttribute("windowtype") == "navigator:browser")
|
||||
originCharset = window.content.document.characterSet;
|
||||
let originCharset = null;
|
||||
if (document.documentElement.getAttribute("windowtype") == "navigator:browser")
|
||||
originCharset = gBrowser.selectedBrowser.characterSet;
|
||||
|
||||
openLinkIn(aURL, aEvent && aEvent.shiftKey ? "tabshifted" : "tab",
|
||||
{ charset: originCharset,
|
||||
postData: aPostData,
|
||||
allowThirdPartyFixup: aAllowThirdPartyFixup,
|
||||
referrerURI: aDocument ? aDocument.documentURIObject : aReferrer });
|
||||
referrerURI: aReferrer });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aDocument
|
||||
* Note this parameter is ignored. See openNewTabWith()
|
||||
*/
|
||||
function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup, aReferrer) {
|
||||
if (aDocument)
|
||||
urlSecurityCheck(aURL, aDocument.nodePrincipal);
|
||||
|
||||
// if and only if the current window is a browser window and it has a
|
||||
// document with a character set, then extract the current charset menu
|
||||
// setting from the current document and use it to initialize the new browser
|
||||
// window...
|
||||
var originCharset = aDocument && aDocument.characterSet;
|
||||
if (!originCharset &&
|
||||
document.documentElement.getAttribute("windowtype") == "navigator:browser")
|
||||
originCharset = window.content.document.characterSet;
|
||||
// Extract the current charset menu setting from the current document and
|
||||
// use it to initialize the new browser window...
|
||||
let originCharset = null;
|
||||
if (document.documentElement.getAttribute("windowtype") == "navigator:browser")
|
||||
originCharset = gBrowser.selectedBrowser.characterSet;
|
||||
|
||||
openLinkIn(aURL, "window",
|
||||
{ charset: originCharset,
|
||||
postData: aPostData,
|
||||
allowThirdPartyFixup: aAllowThirdPartyFixup,
|
||||
referrerURI: aDocument ? aDocument.documentURIObject : aReferrer });
|
||||
referrerURI: aReferrer });
|
||||
}
|
||||
|
||||
// aCalledFromModal is optional
|
||||
|
@ -98,6 +98,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
|
||||
"resource:///modules/SignInToWebsite.jsm");
|
||||
#endif
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
|
||||
"resource:///modules/ContentSearch.jsm");
|
||||
|
||||
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
|
||||
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
|
||||
|
||||
@ -497,6 +500,7 @@ BrowserGlue.prototype = {
|
||||
AboutHome.init();
|
||||
SessionStore.init();
|
||||
BrowserUITelemetry.init();
|
||||
ContentSearch.init();
|
||||
|
||||
if (Services.appinfo.browserTabsRemote) {
|
||||
ContentClick.init();
|
||||
|
@ -65,6 +65,50 @@ function test() {
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "new tab search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
function doSearch(doc) {
|
||||
// Re-add the listener, and perform a search
|
||||
gBrowser.addProgressListener(listener);
|
||||
doc.getElementById("newtab-search-text").value = "foo";
|
||||
doc.getElementById("newtab-search-submit").click();
|
||||
}
|
||||
|
||||
// load about:newtab, but remove the listener first so it doesn't
|
||||
// get in the way
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.loadURI("about:newtab");
|
||||
info("Waiting for about:newtab load");
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
// Observe page setup
|
||||
let win = gBrowser.contentWindow;
|
||||
if (win.gSearch.currentEngineName ==
|
||||
Services.search.currentEngine.name) {
|
||||
doSearch(win.document);
|
||||
}
|
||||
else {
|
||||
info("Waiting for newtab search init");
|
||||
win.addEventListener("ContentSearchService", function done(event) {
|
||||
info("Got newtab search event " + event.detail.type);
|
||||
if (event.detail.type == "State") {
|
||||
win.removeEventListener("ContentSearchService", done);
|
||||
// Let gSearch respond to the event before continuing.
|
||||
executeSoon(() => doSearch(win.document));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "home page search",
|
||||
searchURL: base + "&form=MOZSPG",
|
||||
|
@ -95,6 +95,50 @@ function test() {
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "new tab search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
function doSearch(doc) {
|
||||
// Re-add the listener, and perform a search
|
||||
gBrowser.addProgressListener(listener);
|
||||
doc.getElementById("newtab-search-text").value = "foo";
|
||||
doc.getElementById("newtab-search-submit").click();
|
||||
}
|
||||
|
||||
// load about:newtab, but remove the listener first so it doesn't
|
||||
// get in the way
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.loadURI("about:newtab");
|
||||
info("Waiting for about:newtab load");
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
// Observe page setup
|
||||
let win = gBrowser.contentWindow;
|
||||
if (win.gSearch.currentEngineName ==
|
||||
Services.search.currentEngine.name) {
|
||||
doSearch(win.document);
|
||||
}
|
||||
else {
|
||||
info("Waiting for newtab search init");
|
||||
win.addEventListener("ContentSearchService", function done(event) {
|
||||
info("Got newtab search event " + event.detail.type);
|
||||
if (event.detail.type == "State") {
|
||||
win.removeEventListener("ContentSearchService", done);
|
||||
// Let gSearch respond to the event before continuing.
|
||||
executeSoon(() => doSearch(win.document));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "home page search",
|
||||
searchURL: base + "&channel=np&source=hp",
|
||||
|
@ -9,8 +9,6 @@
|
||||
const TAB_URL = EXAMPLE_URL + "doc_breakpoints-break-on-last-line-of-script-on-reload.html";
|
||||
const CODE_URL = EXAMPLE_URL + "code_breakpoints-break-on-last-line-of-script-on-reload.js";
|
||||
|
||||
const { promiseInvoke } = require("devtools/async-utils");
|
||||
|
||||
function test() {
|
||||
let gPanel, gDebugger, gThreadClient, gEvents;
|
||||
|
||||
@ -59,15 +57,15 @@ function test() {
|
||||
|
||||
// And we should hit the breakpoints as we resume.
|
||||
yield promise.all([
|
||||
doResume(),
|
||||
doResume(gPanel),
|
||||
waitForCaretAndScopes(gPanel, 3)
|
||||
]);
|
||||
yield promise.all([
|
||||
doResume(),
|
||||
doResume(gPanel),
|
||||
waitForCaretAndScopes(gPanel, 4)
|
||||
]);
|
||||
yield promise.all([
|
||||
doResume(),
|
||||
doResume(gPanel),
|
||||
waitForCaretAndScopes(gPanel, 5)
|
||||
]);
|
||||
|
||||
@ -90,23 +88,6 @@ function test() {
|
||||
});
|
||||
});
|
||||
|
||||
function rdpInvoke(obj, method) {
|
||||
return promiseInvoke(obj, method)
|
||||
.then(({error, message }) => {
|
||||
if (error) {
|
||||
throw new Error(error + ": " + message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function doResume() {
|
||||
return rdpInvoke(gThreadClient, gThreadClient.resume);
|
||||
}
|
||||
|
||||
function doInterrupt() {
|
||||
return rdpInvoke(gThreadClient, gThreadClient.interrupt);
|
||||
}
|
||||
|
||||
function setBreakpoint(location) {
|
||||
let deferred = promise.defer();
|
||||
gThreadClient.setBreakpoint(location, ({ error, message }, bpClient) => {
|
||||
|
@ -2,16 +2,15 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that pretty printing when the debugger is paused
|
||||
* does not switch away from the selected source.
|
||||
* Test that pretty printing when the debugger is paused does not switch away
|
||||
* from the selected source.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print-on-paused.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gSources;
|
||||
let gTab, gDebuggee, gPanel, gDebugger, gThreadClient, gSources;
|
||||
|
||||
let gSecondSourceLabel = "code_ugly-2.js";
|
||||
const SECOND_SOURCE_VALUE = EXAMPLE_URL + "code_ugly-2.js";
|
||||
|
||||
function test(){
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
@ -19,63 +18,50 @@ function test(){
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gThreadClient = gDebugger.gThreadClient;
|
||||
gSources = gDebugger.DebuggerView.Sources;
|
||||
|
||||
gPanel.addBreakpoint({ url: gSources.values[0], line: 6 });
|
||||
Task.spawn(function* () {
|
||||
try {
|
||||
yield ensureSourceIs(gPanel, "code_script-switching-02.js", true);
|
||||
|
||||
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6)
|
||||
.then(testPaused)
|
||||
.then(() => {
|
||||
// Switch to the second source.
|
||||
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
|
||||
gSources.selectedIndex = 1;
|
||||
return finished;
|
||||
})
|
||||
.then(testSecondSourceIsSelected)
|
||||
.then(() => {
|
||||
const finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
|
||||
clickPrettyPrintButton();
|
||||
testProgressBarShown();
|
||||
return finished;
|
||||
})
|
||||
.then(testSecondSourceIsStillSelected)
|
||||
.then(() => closeDebuggerAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
|
||||
})
|
||||
yield doInterrupt(gPanel);
|
||||
yield rdpInvoke(gThreadClient, gThreadClient.setBreakpoint, {
|
||||
url: gSources.selectedValue,
|
||||
line: 6
|
||||
});
|
||||
yield doResume(gPanel);
|
||||
|
||||
gDebuggee.secondCall();
|
||||
const bpHit = waitForCaretAndScopes(gPanel, 6);
|
||||
// Get the debuggee call off this tick so that we aren't accidentally
|
||||
// blocking the yielding of bpHit which causes a deadlock.
|
||||
executeSoon(() => gDebuggee.secondCall());
|
||||
yield bpHit;
|
||||
|
||||
info("Switch to the second source.");
|
||||
const sourceShown = waitForSourceShown(gPanel, SECOND_SOURCE_VALUE);
|
||||
gSources.selectedValue = SECOND_SOURCE_VALUE;
|
||||
yield sourceShown;
|
||||
|
||||
info("Pretty print the source.");
|
||||
const prettyPrinted = waitForSourceShown(gPanel, SECOND_SOURCE_VALUE);
|
||||
gDebugger.document.getElementById("pretty-print").click();
|
||||
yield prettyPrinted;
|
||||
|
||||
yield resumeDebuggerThenCloseAndFinish(gPanel);
|
||||
} catch (e) {
|
||||
DevToolsUtils.reportException("browser_dbg_pretty-print-on-paused.js", e);
|
||||
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testPaused() {
|
||||
is(gDebugger.gThreadClient.paused, true,
|
||||
"The thread should be paused");
|
||||
}
|
||||
|
||||
function testSecondSourceIsSelected() {
|
||||
ok(gSources.containsValue(EXAMPLE_URL + gSecondSourceLabel),
|
||||
"The second source should be selected.");
|
||||
}
|
||||
|
||||
function clickPrettyPrintButton() {
|
||||
gDebugger.document.getElementById("pretty-print").click();
|
||||
}
|
||||
|
||||
function testProgressBarShown() {
|
||||
const deck = gDebugger.document.getElementById("editor-deck");
|
||||
is(deck.selectedIndex, 2, "The progress bar should be shown");
|
||||
}
|
||||
|
||||
function testSecondSourceIsStillSelected() {
|
||||
ok(gSources.containsValue(EXAMPLE_URL + gSecondSourceLabel),
|
||||
"The second source should still be selected.");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gThreadClient = null;
|
||||
gSources = null;
|
||||
});
|
||||
|
@ -22,6 +22,7 @@ let { BrowserToolboxProcess } = Cu.import("resource:///modules/devtools/ToolboxP
|
||||
let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||
const { promiseInvoke } = require("devtools/async-utils");
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let Toolbox = devtools.Toolbox;
|
||||
|
||||
@ -856,3 +857,23 @@ function attachAddonActorForUrl(aClient, aUrl) {
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function rdpInvoke(aClient, aMethod, ...args) {
|
||||
return promiseInvoke(aClient, aMethod, ...args)
|
||||
.then(({error, message }) => {
|
||||
if (error) {
|
||||
throw new Error(error + ": " + message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function doResume(aPanel) {
|
||||
const threadClient = aPanel.panelWin.gThreadClient;
|
||||
return rdpInvoke(threadClient, threadClient.resume);
|
||||
}
|
||||
|
||||
function doInterrupt(aPanel) {
|
||||
const threadClient = aPanel.panelWin.gThreadClient;
|
||||
return rdpInvoke(threadClient, threadClient.interrupt);
|
||||
}
|
||||
|
||||
|
50
browser/devtools/eyedropper/commands.js
Normal file
50
browser/devtools/eyedropper/commands.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/. */
|
||||
|
||||
const gcli = require("gcli/index");
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const eventEmitter = new EventEmitter();
|
||||
|
||||
let { Eyedropper, EyedropperManager } = require("devtools/eyedropper/eyedropper");
|
||||
|
||||
/**
|
||||
* 'eyedropper' command
|
||||
*/
|
||||
exports.items = [{
|
||||
name: "eyedropper",
|
||||
description: gcli.lookup("eyedropperDesc"),
|
||||
manual: gcli.lookup("eyedropperManual"),
|
||||
buttonId: "command-button-eyedropper",
|
||||
buttonClass: "command-button command-button-invertable",
|
||||
tooltipText: gcli.lookup("eyedropperTooltip"),
|
||||
state: {
|
||||
isChecked: function(target) {
|
||||
let chromeWindow = target.tab.ownerDocument.defaultView;
|
||||
let dropper = EyedropperManager.getInstance(chromeWindow);
|
||||
if (dropper) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onChange: function(target, changeHandler) {
|
||||
eventEmitter.on("changed", changeHandler);
|
||||
},
|
||||
offChange: function(target, changeHandler) {
|
||||
eventEmitter.off("changed", changeHandler);
|
||||
},
|
||||
},
|
||||
exec: function(args, context) {
|
||||
let chromeWindow = context.environment.chromeWindow;
|
||||
let target = context.environment.target;
|
||||
|
||||
let dropper = EyedropperManager.createInstance(chromeWindow);
|
||||
dropper.open();
|
||||
|
||||
eventEmitter.emit("changed", target.tab);
|
||||
|
||||
dropper.once("destroy", () => {
|
||||
eventEmitter.emit("changed", target.tab);
|
||||
});
|
||||
}
|
||||
}];
|
@ -48,6 +48,40 @@ const CLOSE_DELAY = 750;
|
||||
const HEX_BOX_WIDTH = CANVAS_WIDTH + CANVAS_OFFSET * 2;
|
||||
const HSL_BOX_WIDTH = 158;
|
||||
|
||||
/**
|
||||
* Manage instances of eyedroppers for windows. Registering here isn't
|
||||
* necessary for creating an eyedropper, but can be used for testing.
|
||||
*/
|
||||
let EyedropperManager = {
|
||||
_instances: new WeakMap(),
|
||||
|
||||
getInstance: function(chromeWindow) {
|
||||
return this._instances.get(chromeWindow);
|
||||
},
|
||||
|
||||
createInstance: function(chromeWindow) {
|
||||
let dropper = this.getInstance(chromeWindow);
|
||||
if (dropper) {
|
||||
return dropper;
|
||||
}
|
||||
|
||||
dropper = new Eyedropper(chromeWindow);
|
||||
this._instances.set(chromeWindow, dropper);
|
||||
|
||||
dropper.on("destroy", () => {
|
||||
this.deleteInstance(chromeWindow);
|
||||
});
|
||||
|
||||
return dropper;
|
||||
},
|
||||
|
||||
deleteInstance: function(chromeWindow) {
|
||||
this._instances.delete(chromeWindow);
|
||||
}
|
||||
}
|
||||
|
||||
exports.EyedropperManager = EyedropperManager;
|
||||
|
||||
/**
|
||||
* Eyedropper widget. Once opened, shows zoomed area above current pixel and
|
||||
* displays the color value of the center pixel. Clicking on the window will
|
||||
|
@ -7,6 +7,7 @@
|
||||
JS_MODULES_PATH = 'modules/devtools/eyedropper'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'commands.js',
|
||||
'eyedropper.js'
|
||||
]
|
||||
|
||||
|
@ -7,3 +7,4 @@ support-files =
|
||||
|
||||
[browser_eyedropper_basic.js]
|
||||
skip-if = os == "win" && debug # bug 963492
|
||||
[browser_eyedropper_cmd.js]
|
||||
|
@ -62,14 +62,3 @@ function inspectPage(dropper, click=true) {
|
||||
function pressESC() {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", { });
|
||||
}
|
||||
|
||||
function dropperLoaded(dropper) {
|
||||
if (dropper.loaded) {
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
let deferred = promise.defer();
|
||||
dropper.once("load", deferred.resolve);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
56
browser/devtools/eyedropper/test/browser_eyedropper_cmd.js
Normal file
56
browser/devtools/eyedropper/test/browser_eyedropper_cmd.js
Normal file
@ -0,0 +1,56 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the eyedropper command works
|
||||
|
||||
const TESTCASE_URI = TEST_BASE + "color-block.html";
|
||||
const DIV_COLOR = "#0000FF";
|
||||
|
||||
function test() {
|
||||
return Task.spawn(spawnTest).then(finish, helpers.handleError);
|
||||
}
|
||||
|
||||
function spawnTest() {
|
||||
let options = yield helpers.openTab(TESTCASE_URI);
|
||||
yield helpers.openToolbar(options);
|
||||
|
||||
yield helpers.audit(options, [
|
||||
{
|
||||
setup: "eyedropper",
|
||||
check: {
|
||||
input: "eyedropper"
|
||||
},
|
||||
exec: { output: "" }
|
||||
},
|
||||
]);
|
||||
|
||||
yield inspectAndWaitForCopy();
|
||||
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
}
|
||||
|
||||
function inspectAndWaitForCopy() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
waitForClipboard(DIV_COLOR, () => {
|
||||
inspectPage(); // setup: inspect the page
|
||||
}, deferred.resolve, deferred.reject);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function inspectPage() {
|
||||
let target = content.document.getElementById("test");
|
||||
let win = content.window;
|
||||
|
||||
EventUtils.synthesizeMouse(target, 20, 20, { type: "mousemove" }, win);
|
||||
|
||||
let dropper = EyedropperManager.getInstance(window);
|
||||
|
||||
return dropperLoaded(dropper).then(() => {
|
||||
EventUtils.synthesizeMouse(target, 30, 30, { type: "mousemove" }, win);
|
||||
|
||||
EventUtils.synthesizeMouse(target, 30, 30, {}, win);
|
||||
});
|
||||
}
|
@ -4,10 +4,11 @@
|
||||
const TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/eyedropper/test/";
|
||||
const TEST_HOST = 'mochi.test:8888';
|
||||
|
||||
const promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js").Promise;
|
||||
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
const { Eyedropper } = require("devtools/eyedropper/eyedropper");
|
||||
let { devtools } = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const { Eyedropper, EyedropperManager } = devtools.require("devtools/eyedropper/eyedropper");
|
||||
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
@ -35,3 +36,10 @@ function addTab(uri) {
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function dropperLoaded(dropper) {
|
||||
if (dropper.loaded) {
|
||||
return promise.resolve();
|
||||
}
|
||||
return dropper.once("load");
|
||||
}
|
||||
|
@ -573,7 +573,8 @@ Toolbox.prototype = {
|
||||
"command-button-responsive",
|
||||
"command-button-paintflashing",
|
||||
"command-button-tilt",
|
||||
"command-button-scratchpad"
|
||||
"command-button-scratchpad",
|
||||
"command-button-eyedropper"
|
||||
].map(id => {
|
||||
let button = this.doc.getElementById(id);
|
||||
// Some buttons may not exist inside of Browser Toolbox
|
||||
|
@ -128,6 +128,7 @@ Tools.inspector = {
|
||||
commands: [
|
||||
"devtools/resize-commands",
|
||||
"devtools/inspector/inspector-commands",
|
||||
"devtools/eyedropper/commands.js"
|
||||
],
|
||||
|
||||
preventClosingOnKey: true,
|
||||
|
@ -693,7 +693,7 @@ Tooltip.prototype = {
|
||||
let iframe = this.doc.createElementNS(XHTML_NS, "iframe");
|
||||
iframe.setAttribute("transparent", true);
|
||||
iframe.setAttribute("width", "210");
|
||||
iframe.setAttribute("height", "220");
|
||||
iframe.setAttribute("height", "216");
|
||||
iframe.setAttribute("flex", "1");
|
||||
iframe.setAttribute("class", "devtools-tooltip-iframe");
|
||||
|
||||
|
@ -19,6 +19,6 @@
|
||||
</head>
|
||||
<body role="application">
|
||||
<div id="spectrum"></div>
|
||||
<button id="eyedropper-button"></button>
|
||||
<div id="eyedropper-button"></div>
|
||||
</body>
|
||||
</html>
|
@ -3,17 +3,40 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#eyedropper-button {
|
||||
background: url("chrome://browser/skin/devtools/eyedropper-black.png") no-repeat center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-moz-margin-start: 6px;
|
||||
border: 1px solid #ccc;
|
||||
background-image: url("chrome://browser/skin/devtools/command-eyedropper.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-size: 64px 16px;
|
||||
background-position: 0 center;
|
||||
background-repeat: no-repeat;
|
||||
-moz-margin-start: 5px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.theme-light #eyedropper-button {
|
||||
filter: url(chrome://browser/skin/devtools/filters.svg#invert);
|
||||
border: 1px solid #AAA;
|
||||
}
|
||||
|
||||
.theme-dark #eyedropper-button {
|
||||
filter: url(chrome://browser/skin/devtools/filters.svg#colorpicker-invert);
|
||||
border: 1px solid #444;
|
||||
}
|
||||
|
||||
#eyedropper-button:hover {
|
||||
background-position: -16px center;
|
||||
}
|
||||
#eyedropper-button:hover:active {
|
||||
background-position: -32px center;
|
||||
}
|
||||
#eyedropper-button[checked=true] {
|
||||
background-position: -48px center;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#eyedropper-button {
|
||||
background-image: url("chrome://browser/skin/devtools/command-eyedropper@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
/* Mix-in classes */
|
||||
|
@ -430,6 +430,30 @@ FunctionEnd
|
||||
WriteRegStr SHCTX "$0\.xhtml" "" "FirefoxHTML"
|
||||
${EndIf}
|
||||
|
||||
; Only add .oga if it's not present
|
||||
${CheckIfRegistryKeyExists} "$0" ".oga" $7
|
||||
${If} $7 == "false"
|
||||
WriteRegStr SHCTX "$0\.oga" "" "FirefoxHTML"
|
||||
${EndIf}
|
||||
|
||||
; Only add .ogg if it's not present
|
||||
${CheckIfRegistryKeyExists} "$0" ".ogg" $7
|
||||
${If} $7 == "false"
|
||||
WriteRegStr SHCTX "$0\.ogg" "" "FirefoxHTML"
|
||||
${EndIf}
|
||||
|
||||
; Only add .ogv if it's not present
|
||||
${CheckIfRegistryKeyExists} "$0" ".ogv" $7
|
||||
${If} $7 == "false"
|
||||
WriteRegStr SHCTX "$0\.ogv" "" "FirefoxHTML"
|
||||
${EndIf}
|
||||
|
||||
; Only add .pdf if it's not present
|
||||
${CheckIfRegistryKeyExists} "$0" ".pdf" $7
|
||||
${If} $7 == "false"
|
||||
WriteRegStr SHCTX "$0\.pdf" "" "FirefoxHTML"
|
||||
${EndIf}
|
||||
|
||||
; Only add webm if it's not present
|
||||
${CheckIfRegistryKeyExists} "$0" ".webm" $7
|
||||
${If} $7 == "false"
|
||||
|
@ -324,6 +324,10 @@ Section "Uninstall"
|
||||
${un.RegCleanFileHandler} ".shtml" "FirefoxHTML"
|
||||
${un.RegCleanFileHandler} ".xht" "FirefoxHTML"
|
||||
${un.RegCleanFileHandler} ".xhtml" "FirefoxHTML"
|
||||
${un.RegCleanFileHandler} ".oga" "FirefoxHTML"
|
||||
${un.RegCleanFileHandler} ".ogg" "FirefoxHTML"
|
||||
${un.RegCleanFileHandler} ".ogv" "FirefoxHTML"
|
||||
${un.RegCleanFileHandler} ".pdf" "FirefoxHTML"
|
||||
${un.RegCleanFileHandler} ".webm" "FirefoxHTML"
|
||||
${EndIf}
|
||||
|
||||
|
@ -165,6 +165,20 @@ inspectNodeDesc=CSS selector
|
||||
# on what it does.
|
||||
inspectNodeManual=A CSS selector for use with document.querySelector which identifies a single element
|
||||
|
||||
# LOCALIZATION NOTE (eyedropperDesc) A very short description of the 'eyedropper'
|
||||
# command. See eyedropperManual for a fuller description of what it does. This
|
||||
# string is designed to be shown in a menu alongside the command name, which
|
||||
# is why it should be as short as possible.
|
||||
eyedropperDesc=Grab a color from the page
|
||||
|
||||
# LOCALIZATION NOTE (eyedropperManual) A fuller description of the 'eyedropper'
|
||||
# command, displayed when the user asks for help on what it does.
|
||||
eyedropperManual=Open a panel that magnifies an area of page to inspect pixels and copy color values
|
||||
|
||||
# LOCALIZATION NOTE (eyedropperTooltip) A string displayed as the
|
||||
# tooltip of button in devtools toolbox which toggles the Eyedropper tool.
|
||||
eyedropperTooltip=Grab a color from the page
|
||||
|
||||
# LOCALIZATION NOTE (tiltDesc) A very short description of the 'tilt'
|
||||
# command. See tiltManual for a fuller description of what it does. This
|
||||
# string is designed to be shown in a menu alongside the command name, which
|
||||
|
149
browser/modules/ContentSearch.jsm
Normal file
149
browser/modules/ContentSearch.jsm
Normal file
@ -0,0 +1,149 @@
|
||||
/* 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 = [
|
||||
"ContentSearch",
|
||||
];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const INBOUND_MESSAGE = "ContentSearch";
|
||||
const OUTBOUND_MESSAGE = INBOUND_MESSAGE;
|
||||
|
||||
/**
|
||||
* ContentSearch receives messages named INBOUND_MESSAGE and sends messages
|
||||
* named OUTBOUND_MESSAGE. The data of each message is expected to look like
|
||||
* { type, data }. type is the message's type (or subtype if you consider the
|
||||
* type of the message itself to be INBOUND_MESSAGE), and data is data that is
|
||||
* specific to the type.
|
||||
*
|
||||
* Inbound messages have the following types:
|
||||
*
|
||||
* GetState
|
||||
* Retrieves the current search engine state.
|
||||
* data: null
|
||||
* ManageEngines
|
||||
* Opens the search engine management window.
|
||||
* data: null
|
||||
* Search
|
||||
* Performs a search.
|
||||
* data: an object { engineName, searchString, whence }
|
||||
* SetCurrentEngine
|
||||
* Sets the current engine.
|
||||
* data: the name of the engine
|
||||
*
|
||||
* Outbound messages have the following types:
|
||||
*
|
||||
* CurrentEngine
|
||||
* Sent when the current engine changes.
|
||||
* data: see _currentEngineObj
|
||||
* State
|
||||
* Sent in reply to GetState and when the state changes.
|
||||
* data: see _currentStateObj
|
||||
*/
|
||||
|
||||
this.ContentSearch = {
|
||||
|
||||
init: function () {
|
||||
Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIMessageListenerManager).
|
||||
addMessageListener(INBOUND_MESSAGE, this);
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified", false);
|
||||
},
|
||||
|
||||
receiveMessage: function (msg) {
|
||||
let methodName = "on" + msg.data.type;
|
||||
if (methodName in this) {
|
||||
this[methodName](msg, msg.data.data);
|
||||
}
|
||||
},
|
||||
|
||||
onGetState: function (msg, data) {
|
||||
this._reply(msg, "State", this._currentStateObj());
|
||||
},
|
||||
|
||||
onSearch: function (msg, data) {
|
||||
let expectedDataProps = [
|
||||
"engineName",
|
||||
"searchString",
|
||||
"whence",
|
||||
];
|
||||
for (let prop of expectedDataProps) {
|
||||
if (!(prop in data)) {
|
||||
Cu.reportError("Message data missing required property: " + prop);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let browserWin = msg.target.ownerDocument.defaultView;
|
||||
let engine = Services.search.getEngineByName(data.engineName);
|
||||
browserWin.BrowserSearch.recordSearchInHealthReport(engine, data.whence);
|
||||
let submission = engine.getSubmission(data.searchString, "", data.whence);
|
||||
browserWin.loadURI(submission.uri.spec, null, submission.postData);
|
||||
},
|
||||
|
||||
onSetCurrentEngine: function (msg, data) {
|
||||
Services.search.currentEngine = Services.search.getEngineByName(data);
|
||||
},
|
||||
|
||||
onManageEngines: function (msg, data) {
|
||||
let browserWin = msg.target.ownerDocument.defaultView;
|
||||
browserWin.BrowserSearch.searchBar.openManager(null);
|
||||
},
|
||||
|
||||
observe: function (subj, topic, data) {
|
||||
switch (topic) {
|
||||
case "browser-search-engine-modified":
|
||||
if (data == "engine-current") {
|
||||
this._broadcast("CurrentEngine", this._currentEngineObj());
|
||||
}
|
||||
else if (data != "engine-default") {
|
||||
// engine-default is always sent with engine-current and isn't otherwise
|
||||
// relevant to content searches.
|
||||
this._broadcast("State", this._currentStateObj());
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_reply: function (msg, type, data) {
|
||||
msg.target.messageManager.sendAsyncMessage(...this._msgArgs(type, data));
|
||||
},
|
||||
|
||||
_broadcast: function (type, data) {
|
||||
Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIMessageListenerManager).
|
||||
broadcastAsyncMessage(...this._msgArgs(type, data));
|
||||
},
|
||||
|
||||
_msgArgs: function (type, data) {
|
||||
return [OUTBOUND_MESSAGE, {
|
||||
type: type,
|
||||
data: data,
|
||||
}];
|
||||
},
|
||||
|
||||
_currentStateObj: function () {
|
||||
return {
|
||||
engines: Services.search.getVisibleEngines().map(engine => {
|
||||
return {
|
||||
name: engine.name,
|
||||
iconURI: engine.getIconURLBySize(16, 16),
|
||||
};
|
||||
}),
|
||||
currentEngine: this._currentEngineObj(),
|
||||
};
|
||||
},
|
||||
|
||||
_currentEngineObj: function () {
|
||||
return {
|
||||
name: Services.search.currentEngine.name,
|
||||
logoURI: Services.search.currentEngine.getIconURLBySize(65, 26),
|
||||
logo2xURI: Services.search.currentEngine.getIconURLBySize(130, 52),
|
||||
};
|
||||
},
|
||||
};
|
@ -11,6 +11,7 @@ EXTRA_JS_MODULES += [
|
||||
'BrowserUITelemetry.jsm',
|
||||
'ContentClick.jsm',
|
||||
'ContentLinkHandler.jsm',
|
||||
'ContentSearch.jsm',
|
||||
'CustomizationTabPreloader.jsm',
|
||||
'Feeds.jsm',
|
||||
'NetworkPrioritizer.jsm',
|
||||
|
@ -1,10 +1,12 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
uitour.*
|
||||
contentSearch.js
|
||||
image.png
|
||||
uitour.*
|
||||
|
||||
[browser_BrowserUITelemetry_buckets.js]
|
||||
[browser_ContentSearch.js]
|
||||
[browser_NetworkPrioritizer.js]
|
||||
skip-if = e10s # Bug 666804 - Support NetworkPrioritizer in e10s
|
||||
[browser_SignInToWebsite.js]
|
||||
|
240
browser/modules/test/browser_ContentSearch.js
Normal file
240
browser/modules/test/browser_ContentSearch.js
Normal file
@ -0,0 +1,240 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const TEST_MSG = "ContentSearchTest";
|
||||
const CONTENT_SEARCH_MSG = "ContentSearch";
|
||||
const TEST_CONTENT_SCRIPT_BASENAME = "contentSearch.js";
|
||||
|
||||
function generatorTest() {
|
||||
// nextStep() drives the iterator returned by this function. This function's
|
||||
// iterator in turn drives the iterator of each test below.
|
||||
let currentTestIter = yield startNextTest();
|
||||
let arg = undefined;
|
||||
while (currentTestIter) {
|
||||
try {
|
||||
currentTestIter.send(arg);
|
||||
arg = yield null;
|
||||
}
|
||||
catch (err if err instanceof StopIteration) {
|
||||
currentTestIter = yield startNextTest();
|
||||
arg = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startNextTest() {
|
||||
if (!gTests.length) {
|
||||
setTimeout(() => nextStep(null), 0);
|
||||
return;
|
||||
}
|
||||
let nextTestGen = gTests.shift();
|
||||
let nextTestIter = nextTestGen();
|
||||
addTab(() => {
|
||||
info("Starting test " + nextTestGen.name);
|
||||
nextStep(nextTestIter);
|
||||
});
|
||||
}
|
||||
|
||||
function addTest(testGen) {
|
||||
gTests.push(testGen);
|
||||
}
|
||||
|
||||
var gTests = [];
|
||||
var gMsgMan;
|
||||
|
||||
addTest(function GetState() {
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "GetState",
|
||||
});
|
||||
let msg = yield waitForTestMsg("State");
|
||||
checkMsg(msg, {
|
||||
type: "State",
|
||||
data: currentStateObj(),
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function SetCurrentEngine() {
|
||||
let newCurrentEngine = null;
|
||||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
let engines = Services.search.getVisibleEngines();
|
||||
for (let engine of engines) {
|
||||
if (engine != oldCurrentEngine) {
|
||||
newCurrentEngine = engine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!newCurrentEngine) {
|
||||
info("Couldn't find a non-selected search engine, " +
|
||||
"skipping this part of the test");
|
||||
return;
|
||||
}
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "SetCurrentEngine",
|
||||
data: newCurrentEngine.name,
|
||||
});
|
||||
Services.obs.addObserver(function obs(subj, topic, data) {
|
||||
info("Test observed " + data);
|
||||
if (data == "engine-current") {
|
||||
ok(true, "Test observed engine-current");
|
||||
Services.obs.removeObserver(obs, "browser-search-engine-modified", false);
|
||||
nextStep();
|
||||
}
|
||||
}, "browser-search-engine-modified", false);
|
||||
info("Waiting for test to observe engine-current...");
|
||||
waitForTestMsg("CurrentEngine");
|
||||
let maybeMsg1 = yield null;
|
||||
let maybeMsg2 = yield null;
|
||||
let msg = maybeMsg1 || maybeMsg2;
|
||||
ok(!!msg,
|
||||
"Sanity check: One of the yields is for waitForTestMsg and should have " +
|
||||
"therefore produced a message object");
|
||||
checkMsg(msg, {
|
||||
type: "CurrentEngine",
|
||||
data: currentEngineObj(newCurrentEngine),
|
||||
});
|
||||
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
let msg = yield waitForTestMsg("CurrentEngine");
|
||||
checkMsg(msg, {
|
||||
type: "CurrentEngine",
|
||||
data: currentEngineObj(oldCurrentEngine),
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function ManageEngines() {
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "ManageEngines",
|
||||
});
|
||||
let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Ci.nsIWindowWatcher);
|
||||
winWatcher.registerNotification(function onOpen(subj, topic, data) {
|
||||
if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
|
||||
subj.addEventListener("load", function onLoad() {
|
||||
subj.removeEventListener("load", onLoad);
|
||||
if (subj.document.documentURI ==
|
||||
"chrome://browser/content/search/engineManager.xul") {
|
||||
winWatcher.unregisterNotification(onOpen);
|
||||
ok(true, "Observed search manager window open");
|
||||
is(subj.opener, window,
|
||||
"Search engine manager opener should be this chrome window");
|
||||
subj.close();
|
||||
nextStep();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
info("Waiting for search engine manager window to open...");
|
||||
yield null;
|
||||
});
|
||||
|
||||
addTest(function modifyEngine() {
|
||||
let engine = Services.search.currentEngine;
|
||||
let oldAlias = engine.alias;
|
||||
engine.alias = "ContentSearchTest";
|
||||
let msg = yield waitForTestMsg("State");
|
||||
checkMsg(msg, {
|
||||
type: "State",
|
||||
data: currentStateObj(),
|
||||
});
|
||||
engine.alias = oldAlias;
|
||||
msg = yield waitForTestMsg("State");
|
||||
checkMsg(msg, {
|
||||
type: "State",
|
||||
data: currentStateObj(),
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function search() {
|
||||
let engine = Services.search.currentEngine;
|
||||
let data = {
|
||||
engineName: engine.name,
|
||||
searchString: "ContentSearchTest",
|
||||
whence: "ContentSearchTest",
|
||||
};
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "Search",
|
||||
data: data,
|
||||
});
|
||||
let submissionURL =
|
||||
engine.getSubmission(data.searchString, "", data.whence).uri.spec;
|
||||
let listener = {
|
||||
onStateChange: function (webProg, req, flags, status) {
|
||||
let url = req.originalURI.spec;
|
||||
info("onStateChange " + url);
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if ((flags & docStart) && webProg.isTopLevel && url == submissionURL) {
|
||||
gBrowser.removeProgressListener(listener);
|
||||
ok(true, "Search URL loaded");
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
nextStep();
|
||||
}
|
||||
}
|
||||
};
|
||||
gBrowser.addProgressListener(listener);
|
||||
info("Waiting for search URL to load: " + submissionURL);
|
||||
yield null;
|
||||
});
|
||||
|
||||
function checkMsg(actualMsg, expectedMsgData) {
|
||||
SimpleTest.isDeeply(actualMsg.data, expectedMsgData, "Checking message");
|
||||
}
|
||||
|
||||
function waitForMsg(name, type, callback) {
|
||||
info("Waiting for " + name + " message " + type + "...");
|
||||
gMsgMan.addMessageListener(name, function onMsg(msg) {
|
||||
info("Received " + name + " message " + msg.data.type + "\n");
|
||||
if (msg.data.type == type) {
|
||||
gMsgMan.removeMessageListener(name, onMsg);
|
||||
(callback || nextStep)(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function waitForTestMsg(type, callback) {
|
||||
waitForMsg(TEST_MSG, type, callback);
|
||||
}
|
||||
|
||||
function addTab(onLoad) {
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.linkedBrowser.addEventListener("load", function load() {
|
||||
tab.removeEventListener("load", load, true);
|
||||
let url = getRootDirectory(gTestPath) + TEST_CONTENT_SCRIPT_BASENAME;
|
||||
gMsgMan = tab.linkedBrowser.messageManager;
|
||||
gMsgMan.sendAsyncMessage(CONTENT_SEARCH_MSG, {
|
||||
type: "AddToWhitelist",
|
||||
data: ["about:blank"],
|
||||
});
|
||||
waitForMsg(CONTENT_SEARCH_MSG, "AddToWhitelistAck", () => {
|
||||
gMsgMan.loadFrameScript(url, false);
|
||||
onLoad();
|
||||
});
|
||||
}, true);
|
||||
registerCleanupFunction(() => gBrowser.removeTab(tab));
|
||||
}
|
||||
|
||||
function currentStateObj() {
|
||||
return {
|
||||
engines: Services.search.getVisibleEngines().map(engine => {
|
||||
return {
|
||||
name: engine.name,
|
||||
iconURI: engine.getIconURLBySize(16, 16),
|
||||
};
|
||||
}),
|
||||
currentEngine: currentEngineObj(),
|
||||
};
|
||||
}
|
||||
|
||||
function currentEngineObj(expectedCurrentEngine) {
|
||||
if (expectedCurrentEngine) {
|
||||
is(Services.search.currentEngine.name, expectedCurrentEngine.name,
|
||||
"Sanity check: expected current engine");
|
||||
}
|
||||
return {
|
||||
name: Services.search.currentEngine.name,
|
||||
logoURI: Services.search.currentEngine.getIconURLBySize(65, 26),
|
||||
logo2xURI: Services.search.currentEngine.getIconURLBySize(130, 52),
|
||||
};
|
||||
}
|
21
browser/modules/test/contentSearch.js
Normal file
21
browser/modules/test/contentSearch.js
Normal file
@ -0,0 +1,21 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const TEST_MSG = "ContentSearchTest";
|
||||
const SERVICE_EVENT_TYPE = "ContentSearchService";
|
||||
const CLIENT_EVENT_TYPE = "ContentSearchClient";
|
||||
|
||||
// Forward events from the in-content service to the test.
|
||||
content.addEventListener(SERVICE_EVENT_TYPE, event => {
|
||||
sendAsyncMessage(TEST_MSG, event.detail);
|
||||
});
|
||||
|
||||
// Forward messages from the test to the in-content service.
|
||||
addMessageListener(TEST_MSG, msg => {
|
||||
content.dispatchEvent(
|
||||
new content.CustomEvent(CLIENT_EVENT_TYPE, {
|
||||
detail: msg.data,
|
||||
})
|
||||
);
|
||||
});
|
@ -199,6 +199,8 @@ browser.jar:
|
||||
skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
|
||||
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
|
||||
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
|
||||
skin/classic/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
|
||||
skin/classic/browser/devtools/command-eyedropper@2x.png (../shared/devtools/images/command-eyedropper@2x.png)
|
||||
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
|
||||
* skin/classic/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
|
||||
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
@ -297,7 +299,6 @@ browser.jar:
|
||||
skin/classic/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
|
||||
skin/classic/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
|
||||
skin/classic/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
|
||||
skin/classic/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/sync-16.png
|
||||
skin/classic/browser/sync-32.png
|
||||
|
@ -320,6 +320,8 @@ browser.jar:
|
||||
skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
|
||||
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
|
||||
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
|
||||
skin/classic/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
|
||||
skin/classic/browser/devtools/command-eyedropper@2x.png (../shared/devtools/images/command-eyedropper@2x.png)
|
||||
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
|
||||
* skin/classic/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
|
||||
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
|
||||
@ -418,7 +420,6 @@ browser.jar:
|
||||
skin/classic/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
|
||||
skin/classic/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
|
||||
skin/classic/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
|
||||
skin/classic/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/sync-16.png
|
||||
|
@ -6,11 +6,4 @@
|
||||
<feFuncB type="table" tableValues=".1 0"/>
|
||||
</feComponentTransfer>
|
||||
</filter>
|
||||
<filter id="colorpicker-invert" x="0%" y="0%" width="100%" height="100%" >
|
||||
<feComponentTransfer>
|
||||
<feFuncR type="table" tableValues=".6 0"/>
|
||||
<feFuncG type="table" tableValues=".6 0"/>
|
||||
<feFuncB type="table" tableValues=".6 0"/>
|
||||
</feComponentTransfer>
|
||||
</filter>
|
||||
</svg>
|
Before Width: | Height: | Size: 596 B After Width: | Height: | Size: 321 B |
BIN
browser/themes/shared/devtools/images/command-eyedropper.png
Normal file
BIN
browser/themes/shared/devtools/images/command-eyedropper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
browser/themes/shared/devtools/images/command-eyedropper@2x.png
Normal file
BIN
browser/themes/shared/devtools/images/command-eyedropper@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
@ -580,6 +580,9 @@
|
||||
background-image: url("chrome://browser/skin/devtools/command-console.png");
|
||||
}
|
||||
|
||||
#command-button-eyedropper > image {
|
||||
background-image: url("chrome://browser/skin/devtools/command-eyedropper.png");
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#command-button-paintflashing > image {
|
||||
@ -605,6 +608,10 @@
|
||||
#command-button-splitconsole > image {
|
||||
background-image: url("chrome://browser/skin/devtools/command-console@2x.png");
|
||||
}
|
||||
|
||||
#command-button-eyedropper > image {
|
||||
background-image: url("chrome://browser/skin/devtools/command-eyedropper@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
|
@ -239,6 +239,8 @@ browser.jar:
|
||||
skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
|
||||
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
|
||||
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
|
||||
skin/classic/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
|
||||
skin/classic/browser/devtools/command-eyedropper@2x.png (../shared/devtools/images/command-eyedropper@2x.png)
|
||||
skin/classic/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
|
||||
skin/classic/browser/devtools/editor-error.png (devtools/editor-error.png)
|
||||
skin/classic/browser/devtools/editor-breakpoint.png (devtools/editor-breakpoint.png)
|
||||
@ -333,7 +335,6 @@ browser.jar:
|
||||
skin/classic/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
|
||||
skin/classic/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
|
||||
skin/classic/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
|
||||
skin/classic/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/sync-16.png
|
||||
@ -599,6 +600,8 @@ browser.jar:
|
||||
skin/classic/aero/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png)
|
||||
skin/classic/aero/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
|
||||
skin/classic/aero/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
|
||||
skin/classic/aero/browser/devtools/command-eyedropper.png (../shared/devtools/images/command-eyedropper.png)
|
||||
skin/classic/aero/browser/devtools/command-eyedropper@2x.png (../shared/devtools/images/command-eyedropper@2x.png)
|
||||
skin/classic/aero/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
|
||||
* skin/classic/aero/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
|
||||
skin/classic/aero/browser/devtools/commandline.css (devtools/commandline.css)
|
||||
@ -695,8 +698,6 @@ browser.jar:
|
||||
skin/classic/aero/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
|
||||
skin/classic/aero/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
|
||||
skin/classic/aero/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
|
||||
skin/classic/aero/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/aero/browser/sync-16.png
|
||||
skin/classic/aero/browser/sync-32.png
|
||||
|
@ -2485,8 +2485,6 @@ XULDocument::PrepareToWalk()
|
||||
// Block onload until we've finished building the complete
|
||||
// document content model.
|
||||
BlockOnload();
|
||||
|
||||
nsContentSink::NotifyDocElementCreated(this);
|
||||
}
|
||||
|
||||
// There'd better not be anything on the context stack at this
|
||||
|
@ -5,7 +5,6 @@ support-files =
|
||||
overlay2_bug335375.xul
|
||||
window_bug583948.xul
|
||||
window_bug757137.xul
|
||||
window_documentnotification.xul
|
||||
|
||||
[test_bug199692.xul]
|
||||
[test_bug311681.xul]
|
||||
@ -21,4 +20,3 @@ support-files =
|
||||
[test_bug583948.xul]
|
||||
[test_bug640158_overlay_persist.xul]
|
||||
[test_bug757137.xul]
|
||||
[test_documentnotification.xul]
|
||||
|
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div id="content" style="display: none"/>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var seenNotification = false;
|
||||
function notify(subject, topic, data) {
|
||||
seenNotification = true;
|
||||
is(topic, "document-element-inserted", "Should be the right notification");
|
||||
is(subject, otherWindow.document, "Should have been notified about the right window");
|
||||
ok(subject.documentElement, "documentElement should be defined");
|
||||
}
|
||||
|
||||
var obs = Components.classes["@mozilla.org/observer-service;1"].
|
||||
getService(Components.interfaces.nsIObserverService)
|
||||
obs.addObserver(notify, "document-element-inserted", false);
|
||||
|
||||
var otherWindow = window.open("window_documentnotification.xul", "_new", "chrome");
|
||||
otherWindow.addEventListener("load", function() {
|
||||
ok(seenNotification, "Should have seen the document-element-inserted")
|
||||
obs.removeObserver(notify, "document-element-inserted");
|
||||
window.close();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</window>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<label value="window_documentnotification.xul"/>
|
||||
</window>
|
@ -136,6 +136,7 @@ public class CrashReporter extends Activity
|
||||
SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, true);
|
||||
editor.putBoolean(GeckoApp.PREFS_CRASHED, true);
|
||||
editor.commit();
|
||||
|
||||
final CheckBox allowContactCheckBox = (CheckBox) findViewById(R.id.allow_contact);
|
||||
|
@ -157,6 +157,7 @@ public abstract class GeckoApp
|
||||
public static final String PREFS_OOM_EXCEPTION = "OOMException";
|
||||
public static final String PREFS_VERSION_CODE = "versionCode";
|
||||
public static final String PREFS_WAS_STOPPED = "wasStopped";
|
||||
public static final String PREFS_CRASHED = "crashed";
|
||||
public static final String PREFS_CLEANUP_TEMP_FILES = "cleanupTempFiles";
|
||||
|
||||
public static final String SAVED_STATE_IN_BACKGROUND = "inBackground";
|
||||
@ -1772,10 +1773,17 @@ public abstract class GeckoApp
|
||||
shouldRestore = true;
|
||||
} else if (savedInstanceState != null ||
|
||||
getSessionRestorePreference().equals("always") ||
|
||||
getRestartFromIntent() ||
|
||||
prefs.getBoolean(GeckoApp.PREFS_WAS_STOPPED, false)) {
|
||||
getRestartFromIntent()) {
|
||||
// We're coming back from a background kill by the OS, the user
|
||||
// has chosen to always restore, we restarted, or we crashed.
|
||||
// has chosen to always restore, or we restarted.
|
||||
shouldRestore = true;
|
||||
} else if (prefs.getBoolean(GeckoApp.PREFS_CRASHED, false)) {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
prefs.edit().putBoolean(PREFS_CRASHED, false).commit();
|
||||
}
|
||||
});
|
||||
shouldRestore = true;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import android.util.Log;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class TabsAccessor {
|
||||
private static final String LOGTAG = "GeckoTabsAccessor";
|
||||
@ -49,6 +50,7 @@ public final class TabsAccessor {
|
||||
|
||||
private static final String LOCAL_CLIENT_SELECTION = BrowserContract.Clients.GUID + " IS NULL";
|
||||
private static final String LOCAL_TABS_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS NULL";
|
||||
private static final Pattern FILTERED_URL_PATTERN = Pattern.compile("^(about|chrome|wyciwyg|file):.*$");
|
||||
|
||||
public static class RemoteTab {
|
||||
public String title;
|
||||
@ -149,9 +151,9 @@ public final class TabsAccessor {
|
||||
|
||||
int position = 0;
|
||||
for (Tab tab : tabs) {
|
||||
// Skip this tab if it has a null URL or is in private browsing mode
|
||||
// Skip this tab if it has a null URL or is in private browsing mode, or is a filtered URL.
|
||||
String url = tab.getURL();
|
||||
if (url == null || tab.isPrivate())
|
||||
if (url == null || tab.isPrivate() || isFilteredURL(url))
|
||||
continue;
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
@ -192,4 +194,13 @@ public final class TabsAccessor {
|
||||
insertLocalTabs(cr, tabs);
|
||||
updateLocalClient(cr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the supplied URL string against the set of URLs to filter.
|
||||
*
|
||||
* @return true if the supplied URL should be skipped; false otherwise.
|
||||
*/
|
||||
private static boolean isFilteredURL(String url) {
|
||||
return FILTERED_URL_PATTERN.matcher(url).matches();
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,15 @@ class PanelBackItemView extends LinearLayout {
|
||||
title = (TextView) findViewById(R.id.title);
|
||||
|
||||
final ImageView image = (ImageView) findViewById(R.id.image);
|
||||
Picasso.with(getContext())
|
||||
.load(backImageUrl)
|
||||
.placeholder(R.drawable.folder_up)
|
||||
.into(image);
|
||||
|
||||
if (TextUtils.isEmpty(backImageUrl)) {
|
||||
image.setImageResource(R.drawable.folder_up);
|
||||
} else {
|
||||
Picasso.with(getContext())
|
||||
.load(backImageUrl)
|
||||
.placeholder(R.drawable.folder_up)
|
||||
.into(image);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFromFilter(FilterDetail filter) {
|
||||
|
@ -437,10 +437,8 @@ abstract class PanelLayout extends FrameLayout {
|
||||
final String imageUrl = (emptyViewConfig == null) ? null : emptyViewConfig.getImageUrl();
|
||||
final ImageView imageView = (ImageView) view.findViewById(R.id.home_empty_image);
|
||||
|
||||
if (imageUrl == null) {
|
||||
Picasso.with(getContext())
|
||||
.load(R.drawable.icon_home_empty_firefox)
|
||||
.into(imageView);
|
||||
if (TextUtils.isEmpty(imageUrl)) {
|
||||
imageView.setImageResource(R.drawable.icon_home_empty_firefox);
|
||||
} else {
|
||||
Picasso.with(getContext())
|
||||
.load(imageUrl)
|
||||
|
@ -37,7 +37,8 @@ public class JavascriptTest extends BaseTest {
|
||||
mAsserter.dumpLog("Loading JavaScript test from " + url);
|
||||
loadUrl(url);
|
||||
|
||||
final JavascriptMessageParser testMessageParser = new JavascriptMessageParser(mAsserter);
|
||||
final JavascriptMessageParser testMessageParser =
|
||||
new JavascriptMessageParser(mAsserter, false);
|
||||
try {
|
||||
while (!testMessageParser.isTestFinished()) {
|
||||
if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
|
||||
|
@ -110,8 +110,10 @@ public final class JavascriptBridge {
|
||||
public JavascriptBridge(final Object target) {
|
||||
mTarget = target;
|
||||
mMethods = target.getClass().getMethods();
|
||||
mLogParser = new JavascriptMessageParser(sAsserter);
|
||||
mExpecter = sActions.expectGeckoEvent(EVENT_TYPE);
|
||||
// The JS here is unrelated to a test harness, so we
|
||||
// have our message parser end on assertion failure.
|
||||
mLogParser = new JavascriptMessageParser(sAsserter, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,9 +34,22 @@ public final class JavascriptMessageParser {
|
||||
private String lastTestName = "";
|
||||
// Have we seen a message saying the test is finished?
|
||||
private boolean testFinishedMessageSeen = false;
|
||||
private final boolean endOnAssertionFailure;
|
||||
|
||||
public JavascriptMessageParser(final Assert asserter) {
|
||||
/**
|
||||
* Constructs a message parser for test result messages sent from JavaScript. When seeing an
|
||||
* assertion failure, the message parser can use the given {@link org.mozilla.gecko.Assert}
|
||||
* instance to immediately end the test (typically if the underlying JS framework is not able
|
||||
* to end the test itself) or to swallow the Errors - this functionality is determined by the
|
||||
* <code>endOnAssertionFailure</code> parameter.
|
||||
*
|
||||
* @param asserter The Assert instance to which test results should be passed.
|
||||
* @param endOnAssertionFailure
|
||||
* true if the test should end if we see a JS assertion failure, false otherwise.
|
||||
*/
|
||||
public JavascriptMessageParser(final Assert asserter, final boolean endOnAssertionFailure) {
|
||||
this.asserter = asserter;
|
||||
this.endOnAssertionFailure = endOnAssertionFailure;
|
||||
}
|
||||
|
||||
public boolean isTestFinished() {
|
||||
@ -61,8 +74,15 @@ public final class JavascriptMessageParser {
|
||||
try {
|
||||
asserter.ok(false, name, message);
|
||||
} catch (AssertionFailedError e) {
|
||||
// Swallow this exception. We want to see all the
|
||||
// Javascript failures, not die on the very first one!
|
||||
// Above, we call the assert, allowing it to log.
|
||||
// Now we can end the test, if applicable.
|
||||
if (this.endOnAssertionFailure) {
|
||||
throw e;
|
||||
}
|
||||
// Otherwise, swallow the Error. The JS framework we're
|
||||
// logging messages from is likely capable of ending tests
|
||||
// when it needs to, and we want to see all of its failures,
|
||||
// not just the first one!
|
||||
}
|
||||
} else if ("KNOWN-FAIL".equals(type)) {
|
||||
asserter.todo(false, name, message);
|
||||
|
@ -32,6 +32,7 @@ skip-if = android_version == "10"
|
||||
skip-if = android_version == "10" || processor == "x86"
|
||||
[testDistribution]
|
||||
[testDoorHanger]
|
||||
[testFilterOpenTab]
|
||||
# disabled on 2.3; bug 986172
|
||||
skip-if = android_version == "10"
|
||||
[testFindInPage]
|
||||
|
125
mobile/android/base/tests/testFilterOpenTab.java
Normal file
125
mobile/android/base/tests/testFilterOpenTab.java
Normal file
@ -0,0 +1,125 @@
|
||||
package org.mozilla.gecko.tests;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.mozilla.gecko.PrivateTab;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.TabsAccessor;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.TabsProvider;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
/**
|
||||
* Tests that local tabs are filtered prior to upload.
|
||||
* - create a set of tabs and perists them through TabsAccessor.
|
||||
* - verifies that tabs are filtered by querying.
|
||||
*/
|
||||
public class testFilterOpenTab extends ContentProviderTest {
|
||||
private static final String[] TABS_PROJECTION_COLUMNS = new String[] {
|
||||
BrowserContract.Tabs.TITLE,
|
||||
BrowserContract.Tabs.URL,
|
||||
BrowserContract.Clients.GUID,
|
||||
BrowserContract.Clients.NAME
|
||||
};
|
||||
|
||||
private static final String LOCAL_TABS_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS NULL";
|
||||
|
||||
/**
|
||||
* Factory function that makes new ContentProvider instances.
|
||||
* <p>
|
||||
* We want a fresh provider each test, so this should be invoked in
|
||||
* <code>setUp</code> before each individual test.
|
||||
*/
|
||||
protected static Callable<ContentProvider> sTabProviderCallable = new Callable<ContentProvider>() {
|
||||
@Override
|
||||
public ContentProvider call() {
|
||||
return new TabsProvider();
|
||||
}
|
||||
};
|
||||
|
||||
private Cursor getTabsFromLocalClient() throws Exception {
|
||||
return mProvider.query(BrowserContract.Tabs.CONTENT_URI,
|
||||
TABS_PROJECTION_COLUMNS,
|
||||
LOCAL_TABS_SELECTION,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
private Tab createTab(int id, String url, boolean external, int parentId, String title) {
|
||||
return new Tab((Context) getActivity(), id, url, external, parentId, title);
|
||||
}
|
||||
|
||||
private Tab createPrivateTab(int id, String url, boolean external, int parentId, String title) {
|
||||
return new PrivateTab((Context) getActivity(), id, url, external, parentId, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp(sTabProviderCallable, BrowserContract.TABS_AUTHORITY, "tabs.db");
|
||||
mTests.add(new TestInsertLocalTabs());
|
||||
}
|
||||
|
||||
public void testFilterOpenTab() throws Exception {
|
||||
for (int i = 0; i < mTests.size(); i++) {
|
||||
Runnable test = mTests.get(i);
|
||||
|
||||
setTestName(test.getClass().getSimpleName());
|
||||
test.run();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestInsertLocalTabs extends TestCase {
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
final String TITLE1 = "Google";
|
||||
final String URL1 = "http://www.google.com/";
|
||||
final String TITLE2 = "Mozilla Start Page";
|
||||
final String URL2 = "about:home";
|
||||
final String TITLE3 = "Chrome Weave URL";
|
||||
final String URL3 = "chrome://weave/";
|
||||
final String TITLE4 = "What You Cache Is What You Get";
|
||||
final String URL4 = "wyciwyg://1/test.com";
|
||||
final String TITLE5 = "Root Folder";
|
||||
final String URL5 = "file:///";
|
||||
|
||||
// Create a list of local tabs.
|
||||
List<Tab> tabs = new ArrayList<Tab>(6);
|
||||
Tab tab1 = createTab(1, URL1, false, 0, TITLE1);
|
||||
Tab tab2 = createTab(2, URL2, false, 0, TITLE2);
|
||||
Tab tab3 = createTab(3, URL3, false, 0, TITLE3);
|
||||
Tab tab4 = createTab(4, URL4, false, 0, TITLE4);
|
||||
Tab tab5 = createTab(5, URL5, false, 0, TITLE5);
|
||||
Tab tab6 = createPrivateTab(6, URL1, false, 0, TITLE1);
|
||||
tabs.add(tab1);
|
||||
tabs.add(tab2);
|
||||
tabs.add(tab3);
|
||||
tabs.add(tab4);
|
||||
tabs.add(tab5);
|
||||
tabs.add(tab6);
|
||||
|
||||
// Persist the created tabs.
|
||||
TabsAccessor.persistLocalTabs(mResolver, tabs);
|
||||
|
||||
// Get the persisted tab and check if urls are filtered.
|
||||
Cursor c = getTabsFromLocalClient();
|
||||
assertCountIsAndClose(c, 1, 1 + " tabs entries found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the provided cursor has the expected number of rows,
|
||||
* closing the cursor afterwards.
|
||||
*/
|
||||
private void assertCountIsAndClose(Cursor c, int expectedCount, String message) {
|
||||
try {
|
||||
mAsserter.is(c.getCount(), expectedCount, message);
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
html {
|
||||
background: #f0f0f0;
|
||||
padding: 0 1em;
|
||||
font-family: "Nokia Sans", Tahoma, sans-serif !important;
|
||||
font-family: "Clear Sans", sans-serif !important;
|
||||
font-size: 100% !important;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
%include defines.inc
|
||||
|
||||
html {
|
||||
font-family: Roboto,"Droid Sans",helvetica,arial,clean,sans-serif;
|
||||
font-family: "Clear Sans",sans-serif;
|
||||
font-size: 14px;
|
||||
background-color: @color_about_background@;
|
||||
-moz-text-size-adjust: none;
|
||||
|
@ -126,7 +126,7 @@ section:not([active]) {
|
||||
|
||||
.description,
|
||||
#last-url {
|
||||
font-family: Roboto,"Droid Sans",helvetica,arial,clean,sans-serif;
|
||||
font-family: "Clear Sans",sans-serif;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
body {
|
||||
-moz-text-size-adjust: none;
|
||||
font-family: Roboto,"Droid Sans",helvetica,arial,clean,sans-serif;
|
||||
font-family: "Clear Sans",sans-serif;
|
||||
font-size: 23px;
|
||||
color: #222222;
|
||||
background-color: #ced7de;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
body {
|
||||
font-family: Roboto,"Droid Sans",helvetica,arial,clean,sans-serif;
|
||||
font-family: "Clear Sans",sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
@ -321,7 +321,7 @@ body {
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
font-family: "Droid Sans",helvetica,arial,clean,sans-serif;
|
||||
font-family: "Clear Sans",sans-serif;
|
||||
transition-property: visibility, opacity;
|
||||
transition-duration: 0.7s;
|
||||
visibility: visible;
|
||||
@ -465,7 +465,7 @@ body {
|
||||
.segmented-button > li > a {
|
||||
display: block;
|
||||
padding: 5px 0;
|
||||
font-family: "Roboto",sans-serif;
|
||||
font-family: "Clear Sans",sans-serif;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ body {
|
||||
padding: 0;
|
||||
background-color: #ced7de;
|
||||
-moz-user-select: none;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-family: "Clear Sans",sans-serif;
|
||||
-moz-text-size-adjust: none;
|
||||
}
|
||||
|
||||
|
@ -1222,6 +1222,7 @@ SearchCountMeasurementBase.prototype = Object.freeze({
|
||||
SOURCES: [
|
||||
"abouthome",
|
||||
"contextmenu",
|
||||
"newtab",
|
||||
"searchbar",
|
||||
"urlbar",
|
||||
],
|
||||
|
@ -57,6 +57,7 @@ add_task(function test_record() {
|
||||
}
|
||||
yield provider.recordSearch(engine, "abouthome");
|
||||
yield provider.recordSearch(engine, "contextmenu");
|
||||
yield provider.recordSearch(engine, "newtab");
|
||||
yield provider.recordSearch(engine, "searchbar");
|
||||
yield provider.recordSearch(engine, "urlbar");
|
||||
}
|
||||
|
@ -4781,25 +4781,27 @@ update(AddonThreadActor.prototype, {
|
||||
|
||||
onAttach: function(aRequest) {
|
||||
if (!this.attached) {
|
||||
Services.obs.addObserver(this, "document-element-inserted", false);
|
||||
Services.obs.addObserver(this, "chrome-document-global-created", false);
|
||||
Services.obs.addObserver(this, "content-document-global-created", false);
|
||||
}
|
||||
return ThreadActor.prototype.onAttach.call(this, aRequest);
|
||||
},
|
||||
|
||||
disconnect: function() {
|
||||
if (this.attached) {
|
||||
Services.obs.removeObserver(this, "document-element-inserted");
|
||||
Services.obs.removeObserver(this, "content-document-global-created");
|
||||
Services.obs.removeObserver(this, "chrome-document-global-created");
|
||||
}
|
||||
return ThreadActor.prototype.disconnect.call(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a new DOM document element is created. Check if the DOM was
|
||||
* laoded from an add-on and if so make the window a debuggee.
|
||||
* Called when a new DOM document global is created. Check if the DOM was
|
||||
* loaded from an add-on and if so make the window a debuggee.
|
||||
*/
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
let id = {};
|
||||
if (mapURIToAddonID(aSubject.documentURIObject, id) && id.value === this.addonID) {
|
||||
if (mapURIToAddonID(aSubject.location, id) && id.value === this.addonID) {
|
||||
this.dbg.addDebuggee(aSubject.defaultView);
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user