зеркало из https://github.com/mozilla/gecko-dev.git
Bug 962490 - Add a search field to the new tab page (part 2: about:newtab changes). r=ttaubert
This commit is contained in:
Родитель
53bd0fe01b
Коммит
0e5c640329
|
@ -197,12 +197,18 @@ let gGrid = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let availSpace = document.documentElement.clientHeight - this._cellMargin -
|
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);
|
let visibleRows = Math.floor(availSpace / this._cellHeight);
|
||||||
this._node.style.height = this._computeHeight() + "px";
|
this._node.style.height = this._computeHeight() + "px";
|
||||||
this._node.style.maxHeight = this._computeHeight(visibleRows) + "px";
|
this._node.style.maxHeight = this._computeHeight(visibleRows) + "px";
|
||||||
this._node.style.maxWidth = gGridPrefs.gridColumns * this._cellWidth +
|
this._node.style.maxWidth = gGridPrefs.gridColumns * this._cellWidth +
|
||||||
GRID_WIDTH_EXTRA + "px";
|
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() {
|
_shouldRenderGrid : function Grid_shouldRenderGrid() {
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
input {
|
||||||
|
font: message-box !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
input[type=button] {
|
input[type=button] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +17,7 @@ input[type=button] {
|
||||||
position: relative;
|
position: relative;
|
||||||
-moz-box-flex: 1;
|
-moz-box-flex: 1;
|
||||||
-moz-user-focus: normal;
|
-moz-user-focus: normal;
|
||||||
|
-moz-box-orient: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
#newtab-scrollbox:not([page-disabled]) {
|
#newtab-scrollbox:not([page-disabled]) {
|
||||||
|
@ -54,6 +60,7 @@ input[type=button] {
|
||||||
#newtab-margin-undo-container {
|
#newtab-margin-undo-container {
|
||||||
display: -moz-box;
|
display: -moz-box;
|
||||||
-moz-box-pack: center;
|
-moz-box-pack: center;
|
||||||
|
margin-bottom: 26px; /* 32 - 6 search form top "padding" */
|
||||||
}
|
}
|
||||||
|
|
||||||
#newtab-horizontal-margin {
|
#newtab-horizontal-margin {
|
||||||
|
@ -64,10 +71,17 @@ input[type=button] {
|
||||||
#newtab-margin-top,
|
#newtab-margin-top,
|
||||||
#newtab-margin-bottom {
|
#newtab-margin-bottom {
|
||||||
display: -moz-box;
|
display: -moz-box;
|
||||||
-moz-box-flex: 1;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#newtab-margin-top {
|
||||||
|
-moz-box-flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#newtab-margin-bottom {
|
||||||
|
-moz-box-flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.newtab-side-margin {
|
.newtab-side-margin {
|
||||||
min-width: 16px;
|
min-width: 16px;
|
||||||
-moz-box-flex: 1;
|
-moz-box-flex: 1;
|
||||||
|
@ -213,7 +227,7 @@ input[type=button] {
|
||||||
opacity: 0.01;
|
opacity: 0.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PANEL */
|
/* SPONSORED PANEL */
|
||||||
#sponsored-panel {
|
#sponsored-panel {
|
||||||
width: 330px;
|
width: 330px;
|
||||||
}
|
}
|
||||||
|
@ -225,3 +239,156 @@ input[type=button] {
|
||||||
#sponsored-panel .text-link {
|
#sponsored-panel .text-link {
|
||||||
margin: 12px 0 0;
|
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 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 transformations.js
|
||||||
#include page.js
|
#include page.js
|
||||||
|
@ -54,6 +55,7 @@ const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||||
#include dropPreview.js
|
#include dropPreview.js
|
||||||
#include updater.js
|
#include updater.js
|
||||||
#include undo.js
|
#include undo.js
|
||||||
|
#include search.js
|
||||||
|
|
||||||
// Everything is loaded. Initialize the New Tab Page.
|
// Everything is loaded. Initialize the New Tab Page.
|
||||||
gPage.init();
|
gPage.init();
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
<!DOCTYPE window [
|
<!DOCTYPE window [
|
||||||
<!ENTITY % newTabDTD SYSTEM "chrome://browser/locale/newTab.dtd">
|
<!ENTITY % newTabDTD SYSTEM "chrome://browser/locale/newTab.dtd">
|
||||||
%newTabDTD;
|
%newTabDTD;
|
||||||
|
<!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd">
|
||||||
|
%searchBarDTD;
|
||||||
]>
|
]>
|
||||||
|
|
||||||
<xul:window id="newtab-window" xmlns="http://www.w3.org/1999/xhtml"
|
<xul:window id="newtab-window" xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
@ -24,6 +26,13 @@
|
||||||
value="&newtab.panel.link.text;" />
|
value="&newtab.panel.link.text;" />
|
||||||
</xul:panel>
|
</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-scrollbox">
|
||||||
|
|
||||||
<div id="newtab-vertical-margin">
|
<div id="newtab-vertical-margin">
|
||||||
|
@ -46,6 +55,16 @@
|
||||||
</div>
|
</div>
|
||||||
</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 id="newtab-horizontal-margin">
|
||||||
<div class="newtab-side-margin"/>
|
<div class="newtab-side-margin"/>
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,8 @@ let gPage = {
|
||||||
|
|
||||||
this._initialized = true;
|
this._initialized = true;
|
||||||
|
|
||||||
|
gSearch.init();
|
||||||
|
|
||||||
this._mutationObserver = new MutationObserver(() => {
|
this._mutationObserver = new MutationObserver(() => {
|
||||||
if (this.allowBackgroundCaptures) {
|
if (this.allowBackgroundCaptures) {
|
||||||
Services.telemetry.getHistogramById("NEWTAB_PAGE_SHOWN").add(true);
|
Services.telemetry.getHistogramById("NEWTAB_PAGE_SHOWN").add(true);
|
||||||
|
@ -138,6 +140,10 @@ let gPage = {
|
||||||
let shownCount = Math.min(10, count);
|
let shownCount = Math.min(10, count);
|
||||||
Services.telemetry.getHistogramById(shownId).add(shownCount);
|
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, {
|
this._mutationObserver.observe(document.documentElement, {
|
||||||
|
@ -164,7 +170,7 @@ let gPage = {
|
||||||
*/
|
*/
|
||||||
_updateAttributes: function Page_updateAttributes(aValue) {
|
_updateAttributes: function Page_updateAttributes(aValue) {
|
||||||
// Set the nodes' states.
|
// 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)) {
|
for (let node of document.querySelectorAll(nodeSelector)) {
|
||||||
if (aValue)
|
if (aValue)
|
||||||
node.removeAttribute("page-disabled");
|
node.removeAttribute("page-disabled");
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,6 +1,9 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files = head.js
|
|
||||||
skip-if = e10s # Bug ?????? - about:newtab tests don't work in e10s
|
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_background_captures.js]
|
||||||
[browser_newtab_block.js]
|
[browser_newtab_block.js]
|
||||||
|
@ -25,6 +28,7 @@ skip-if = os == "mac" # Intermittent failures, bug 898317
|
||||||
[browser_newtab_focus.js]
|
[browser_newtab_focus.js]
|
||||||
[browser_newtab_perwindow_private_browsing.js]
|
[browser_newtab_perwindow_private_browsing.js]
|
||||||
[browser_newtab_reset.js]
|
[browser_newtab_reset.js]
|
||||||
|
[browser_newtab_search.js]
|
||||||
[browser_newtab_sponsored_icon_click.js]
|
[browser_newtab_sponsored_icon_click.js]
|
||||||
[browser_newtab_tabsync.js]
|
[browser_newtab_tabsync.js]
|
||||||
[browser_newtab_undo.js]
|
[browser_newtab_undo.js]
|
||||||
|
|
|
@ -9,9 +9,9 @@ function runTests() {
|
||||||
Services.prefs.setIntPref("accessibility.tabfocus", 7);
|
Services.prefs.setIntPref("accessibility.tabfocus", 7);
|
||||||
|
|
||||||
// Focus count in new tab page.
|
// Focus count in new tab page.
|
||||||
// 28 = 9 * 3 + 1 = 9 sites and 1 toggle button, each site has a link, a pin
|
// 30 = 9 * 3 + 3 = 9 sites, each with link, pin and remove buttons; search
|
||||||
// and a remove button.
|
// bar; search button; and toggle button.
|
||||||
let FOCUS_COUNT = 28;
|
let FOCUS_COUNT = 30;
|
||||||
|
|
||||||
// Create a new tab page.
|
// Create a new tab page.
|
||||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||||
|
|
|
@ -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 setLinks("0");
|
||||||
yield addNewTabPageTab();
|
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");
|
let site = getCell(0).node.querySelector(".newtab-site");
|
||||||
site.setAttribute("type", "sponsored");
|
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 isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
|
||||||
let gWindow = window;
|
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 () {
|
registerCleanupFunction(function () {
|
||||||
while (gWindow.gBrowser.tabs.length > 1)
|
while (gWindow.gBrowser.tabs.length > 1)
|
||||||
gWindow.gBrowser.removeTab(gWindow.gBrowser.tabs[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_ENABLED);
|
||||||
Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE);
|
Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE);
|
||||||
|
|
||||||
|
@ -549,3 +580,35 @@ function whenPagesUpdated(aCallback, aOnlyIfHidden=false) {
|
||||||
NewTabUtils.allPages.unregister(page);
|
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);
|
||||||
|
}
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -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>
|
Загрузка…
Ссылка в новой задаче