mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 13:55:43 +00:00
Bug 1221539 - Add search engine discovery to the page action menu. Part 2: Add the new action. r=Gijs
MozReview-Commit-ID: DEEZBwmV0JD --HG-- extra : rebase_source : 71b68621198d72c069f505d922e92ed357eefe8b
This commit is contained in:
parent
36b7f691ee
commit
e5e43736bc
@ -965,10 +965,29 @@ var BrowserPageActionFeedback = {
|
|||||||
return this.feedbackLabel = document.getElementById("pageActionFeedbackMessage");
|
return this.feedbackLabel = document.getElementById("pageActionFeedbackMessage");
|
||||||
},
|
},
|
||||||
|
|
||||||
show(action, event, textContentOverride) {
|
/**
|
||||||
this.feedbackLabel.textContent = this.panelNode.getAttribute((textContentOverride || action.id) + "Feedback");
|
* Shows the feedback popup for an action.
|
||||||
|
*
|
||||||
|
* @param action (PageActions.Action, required)
|
||||||
|
* The action associated with the feedback.
|
||||||
|
* @param opts (object, optional)
|
||||||
|
* An object with the following optional properties:
|
||||||
|
* - event (DOM event): The event that triggered the feedback.
|
||||||
|
* - textAttributeOverride (string): Normally the feedback text is
|
||||||
|
* taken from an attribute on the feedback panel. The attribute's
|
||||||
|
* name is `${action.id}Feedback`. Use this to override the
|
||||||
|
* action.id part of the name.
|
||||||
|
* - text (string): The text string. If not given, an attribute on
|
||||||
|
* panel is assumed to contain the text, as described above.
|
||||||
|
*/
|
||||||
|
show(action, opts = {}) {
|
||||||
|
this.feedbackLabel.textContent =
|
||||||
|
opts.text ||
|
||||||
|
this.panelNode.getAttribute((opts.textAttributeOverride || action.id) +
|
||||||
|
"Feedback");
|
||||||
this.panelNode.hidden = false;
|
this.panelNode.hidden = false;
|
||||||
|
|
||||||
|
let event = opts.event || null;
|
||||||
let anchor = BrowserPageActions.panelAnchorNodeForAction(action, event);
|
let anchor = BrowserPageActions.panelAnchorNodeForAction(action, event);
|
||||||
PanelMultiView.openPopup(this.panelNode, anchor, {
|
PanelMultiView.openPopup(this.panelNode, anchor, {
|
||||||
position: "bottomcenter topright",
|
position: "bottomcenter topright",
|
||||||
@ -1019,7 +1038,9 @@ BrowserPageActions.copyURL = {
|
|||||||
.getService(Ci.nsIClipboardHelper)
|
.getService(Ci.nsIClipboardHelper)
|
||||||
.copyString(gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec);
|
.copyString(gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec);
|
||||||
let action = PageActions.actionForID("copyURL");
|
let action = PageActions.actionForID("copyURL");
|
||||||
BrowserPageActionFeedback.show(action, event);
|
BrowserPageActionFeedback.show(action, {
|
||||||
|
event,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1096,8 +1117,11 @@ BrowserPageActions.sendToDevice = {
|
|||||||
// in", "Learn about Sync", etc. Device items will be .sendtab-target.
|
// in", "Learn about Sync", etc. Device items will be .sendtab-target.
|
||||||
if (event.target.classList.contains("sendtab-target")) {
|
if (event.target.classList.contains("sendtab-target")) {
|
||||||
let action = PageActions.actionForID("sendToDevice");
|
let action = PageActions.actionForID("sendToDevice");
|
||||||
let textOverride = gSync.offline && "sendToDeviceOffline";
|
let textAttributeOverride = gSync.offline && "sendToDeviceOffline";
|
||||||
BrowserPageActionFeedback.show(action, event, textOverride);
|
BrowserPageActionFeedback.show(action, {
|
||||||
|
event,
|
||||||
|
textAttributeOverride,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return item;
|
return item;
|
||||||
@ -1120,3 +1144,118 @@ BrowserPageActions.sendToDevice = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// add search engine
|
||||||
|
BrowserPageActions.addSearchEngine = {
|
||||||
|
get action() {
|
||||||
|
return PageActions.actionForID("addSearchEngine");
|
||||||
|
},
|
||||||
|
|
||||||
|
get engines() {
|
||||||
|
return gBrowser.selectedBrowser.engines || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
get strings() {
|
||||||
|
delete this.strings;
|
||||||
|
let uri = "chrome://browser/locale/search.properties";
|
||||||
|
return this.strings = Services.strings.createBundle(uri);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateEngines() {
|
||||||
|
// As a slight optimization, if the action isn't in the urlbar, don't do
|
||||||
|
// anything here except disable it. The action's panel nodes are updated
|
||||||
|
// when the panel is shown.
|
||||||
|
this.action.setDisabled(!this.engines.length, window);
|
||||||
|
if (this.action.shouldShowInUrlbar(window)) {
|
||||||
|
this._updateTitleAndIcon();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateTitleAndIcon() {
|
||||||
|
if (!this.engines.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let title =
|
||||||
|
this.engines.length == 1 ?
|
||||||
|
this.strings.formatStringFromName("searchAddFoundEngine",
|
||||||
|
[this.engines[0].title], 1) :
|
||||||
|
this.strings.GetStringFromName("searchAddFoundEngineMenu");
|
||||||
|
this.action.setTitle(title, window);
|
||||||
|
this.action.setIconURL(this.engines[0].icon, window);
|
||||||
|
},
|
||||||
|
|
||||||
|
onShowingInPanel() {
|
||||||
|
this._updateTitleAndIcon();
|
||||||
|
this.action.setWantsSubview(this.engines.length > 1, window);
|
||||||
|
let button = BrowserPageActions.panelButtonNodeForActionID(this.action.id);
|
||||||
|
button.classList.add("badged-button");
|
||||||
|
button.setAttribute("image", this.engines[0].icon);
|
||||||
|
button.setAttribute("uri", this.engines[0].uri);
|
||||||
|
button.setAttribute("crop", "center");
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubviewShowing(panelViewNode) {
|
||||||
|
let body = panelViewNode.querySelector(".panel-subview-body");
|
||||||
|
while (body.firstChild) {
|
||||||
|
body.firstChild.remove();
|
||||||
|
}
|
||||||
|
for (let engine of this.engines) {
|
||||||
|
let button = document.createElement("toolbarbutton");
|
||||||
|
button.classList.add("subviewbutton", "subviewbutton-iconic");
|
||||||
|
button.setAttribute("label", engine.title);
|
||||||
|
button.setAttribute("image", engine.icon);
|
||||||
|
button.setAttribute("uri", engine.uri);
|
||||||
|
button.addEventListener("command", event => {
|
||||||
|
PanelMultiView.hidePopup(BrowserPageActions.panelNode);
|
||||||
|
this._handleClickOnEngineButton(button);
|
||||||
|
});
|
||||||
|
body.appendChild(button);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onCommand(event, buttonNode) {
|
||||||
|
if (!buttonNode.closest("panel")) {
|
||||||
|
// The urlbar button was clicked. It should have a subview if there are
|
||||||
|
// many engines.
|
||||||
|
let manyEngines = this.engines.length > 1;
|
||||||
|
this.action.setWantsSubview(manyEngines, window);
|
||||||
|
if (manyEngines) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._handleClickOnEngineButton(buttonNode);
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleClickOnEngineButton(button) {
|
||||||
|
this._installEngine(button.getAttribute("uri"),
|
||||||
|
button.getAttribute("image"));
|
||||||
|
},
|
||||||
|
|
||||||
|
_installEngine(uri, image) {
|
||||||
|
Services.search.addEngine(uri, null, image, false, {
|
||||||
|
onSuccess: engine => {
|
||||||
|
BrowserPageActionFeedback.show(this.action, {
|
||||||
|
text: this.strings.GetStringFromName("searchAddedFoundEngine"),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError(errorCode) {
|
||||||
|
if (errorCode != Ci.nsISearchInstallCallback.ERROR_DUPLICATE_ENGINE) {
|
||||||
|
// Download error is shown by the search service
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const kSearchBundleURI = "chrome://global/locale/search/search.properties";
|
||||||
|
let searchBundle = Services.strings.createBundle(kSearchBundleURI);
|
||||||
|
let brandBundle = document.getElementById("bundle_brand");
|
||||||
|
let brandName = brandBundle.getString("brandShortName");
|
||||||
|
let title = searchBundle.GetStringFromName("error_invalid_engine_title");
|
||||||
|
let text = searchBundle.formatStringFromName("error_duplicate_engine_msg",
|
||||||
|
[brandName, uri], 2);
|
||||||
|
Services.prompt.QueryInterface(Ci.nsIPromptFactory);
|
||||||
|
let prompt = Services.prompt.getPrompt(gBrowser.contentWindow, Ci.nsIPrompt);
|
||||||
|
prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
|
||||||
|
prompt.setPropertyAsBool("allowTabModal", true);
|
||||||
|
prompt.alert(title, text);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -1346,6 +1346,7 @@ var gBrowserInit = {
|
|||||||
TabletModeUpdater.init();
|
TabletModeUpdater.init();
|
||||||
CombinedStopReload.ensureInitialized();
|
CombinedStopReload.ensureInitialized();
|
||||||
gPrivateBrowsingUI.init();
|
gPrivateBrowsingUI.init();
|
||||||
|
BrowserSearch.init();
|
||||||
BrowserPageActions.init();
|
BrowserPageActions.init();
|
||||||
gAccessibilityServiceIndicator.init();
|
gAccessibilityServiceIndicator.init();
|
||||||
|
|
||||||
@ -1876,6 +1877,8 @@ var gBrowserInit = {
|
|||||||
|
|
||||||
LanguagePrompt.uninit();
|
LanguagePrompt.uninit();
|
||||||
|
|
||||||
|
BrowserSearch.uninit();
|
||||||
|
|
||||||
// Now either cancel delayedStartup, or clean up the services initialized from
|
// Now either cancel delayedStartup, or clean up the services initialized from
|
||||||
// it.
|
// it.
|
||||||
if (this._boundDelayedStartup) {
|
if (this._boundDelayedStartup) {
|
||||||
@ -3747,6 +3750,83 @@ const DOMEventHandler = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const BrowserSearch = {
|
const BrowserSearch = {
|
||||||
|
init() {
|
||||||
|
Services.obs.addObserver(this, "browser-search-engine-modified");
|
||||||
|
},
|
||||||
|
|
||||||
|
uninit() {
|
||||||
|
Services.obs.removeObserver(this, "browser-search-engine-modified");
|
||||||
|
},
|
||||||
|
|
||||||
|
observe(engine, topic, data) {
|
||||||
|
// There are two kinds of search engine objects, nsISearchEngine objects and
|
||||||
|
// plain { uri, title, icon } objects. `engine` in this method is the
|
||||||
|
// former. The browser.engines and browser.hiddenEngines arrays are the
|
||||||
|
// latter, and they're the engines offered by the the page in the browser.
|
||||||
|
//
|
||||||
|
// The two types of engines are currently related by their titles/names,
|
||||||
|
// although that may change; see bug 335102.
|
||||||
|
let engineName = engine.wrappedJSObject.name;
|
||||||
|
switch (data) {
|
||||||
|
case "engine-removed":
|
||||||
|
// An engine was removed from the search service. If a page is offering
|
||||||
|
// the engine, then the engine needs to be added back to the corresponding
|
||||||
|
// browser's offered engines.
|
||||||
|
this._addMaybeOfferedEngine(engineName);
|
||||||
|
break;
|
||||||
|
case "engine-added":
|
||||||
|
// An engine was added to the search service. If a page is offering the
|
||||||
|
// engine, then the engine needs to be removed from the corresponding
|
||||||
|
// browser's offered engines.
|
||||||
|
this._removeMaybeOfferedEngine(engineName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_addMaybeOfferedEngine(engineName) {
|
||||||
|
let selectedBrowserOffersEngine = false;
|
||||||
|
for (let browser of gBrowser.browsers) {
|
||||||
|
for (let i = 0; i < (browser.hiddenEngines || []).length; i++) {
|
||||||
|
if (browser.hiddenEngines[i].title == engineName) {
|
||||||
|
if (!browser.engines) {
|
||||||
|
browser.engines = [];
|
||||||
|
}
|
||||||
|
browser.engines.push(browser.hiddenEngines[i]);
|
||||||
|
browser.hiddenEngines.splice(i, 1);
|
||||||
|
if (browser == gBrowser.selectedBrowser) {
|
||||||
|
selectedBrowserOffersEngine = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedBrowserOffersEngine) {
|
||||||
|
this.updateOpenSearchBadge();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeMaybeOfferedEngine(engineName) {
|
||||||
|
let selectedBrowserOffersEngine = false;
|
||||||
|
for (let browser of gBrowser.browsers) {
|
||||||
|
for (let i = 0; i < (browser.engines || []).length; i++) {
|
||||||
|
if (browser.engines[i].title == engineName) {
|
||||||
|
if (!browser.hiddenEngines) {
|
||||||
|
browser.hiddenEngines = [];
|
||||||
|
}
|
||||||
|
browser.hiddenEngines.push(browser.engines[i]);
|
||||||
|
browser.engines.splice(i, 1);
|
||||||
|
if (browser == gBrowser.selectedBrowser) {
|
||||||
|
selectedBrowserOffersEngine = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedBrowserOffersEngine) {
|
||||||
|
this.updateOpenSearchBadge();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
addEngine(browser, engine, uri) {
|
addEngine(browser, engine, uri) {
|
||||||
// Check to see whether we've already added an engine with this title
|
// Check to see whether we've already added an engine with this title
|
||||||
if (browser.engines) {
|
if (browser.engines) {
|
||||||
@ -3784,6 +3864,8 @@ const BrowserSearch = {
|
|||||||
* has search engines.
|
* has search engines.
|
||||||
*/
|
*/
|
||||||
updateOpenSearchBadge() {
|
updateOpenSearchBadge() {
|
||||||
|
BrowserPageActions.addSearchEngine.updateEngines();
|
||||||
|
|
||||||
var searchBar = this.searchBar;
|
var searchBar = this.searchBar;
|
||||||
if (!searchBar)
|
if (!searchBar)
|
||||||
return;
|
return;
|
||||||
|
@ -42,6 +42,14 @@ skip-if = true # Bug 1315887
|
|||||||
[browser_moz_action_link.js]
|
[browser_moz_action_link.js]
|
||||||
[browser_new_tab_urlbar_reset.js]
|
[browser_new_tab_urlbar_reset.js]
|
||||||
[browser_page_action_menu.js]
|
[browser_page_action_menu.js]
|
||||||
|
[browser_page_action_menu_add_search_engine.js]
|
||||||
|
support-files =
|
||||||
|
page_action_menu_add_search_engine_one.html
|
||||||
|
page_action_menu_add_search_engine_many.html
|
||||||
|
page_action_menu_add_search_engine_same_names.html
|
||||||
|
page_action_menu_add_search_engine_0.xml
|
||||||
|
page_action_menu_add_search_engine_1.xml
|
||||||
|
page_action_menu_add_search_engine_2.xml
|
||||||
[browser_page_action_menu_clipboard.js]
|
[browser_page_action_menu_clipboard.js]
|
||||||
subsuite = clipboard
|
subsuite = clipboard
|
||||||
[browser_pasteAndGo.js]
|
[browser_pasteAndGo.js]
|
||||||
|
@ -0,0 +1,305 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Checks a page that doesn't offer any engines.
|
||||||
|
add_task(async function none() {
|
||||||
|
let url = "http://mochi.test:8888/";
|
||||||
|
await BrowserTestUtils.withNewTab(url, async () => {
|
||||||
|
// Open the panel.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
|
||||||
|
await promisePageActionPanelHidden();
|
||||||
|
|
||||||
|
// The action should not be present.
|
||||||
|
let actions = PageActions.actionsInPanel(window);
|
||||||
|
Assert.ok(!actions.some(a => a.id == "addSearchEngine"),
|
||||||
|
"Action should not be present in panel");
|
||||||
|
let button =
|
||||||
|
BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(!button, "Action button should not be in panel");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Checks a page that offers one engine.
|
||||||
|
add_task(async function one() {
|
||||||
|
let url = getRootDirectory(gTestPath) + "page_action_menu_add_search_engine_one.html";
|
||||||
|
await BrowserTestUtils.withNewTab(url, async () => {
|
||||||
|
// Open the panel.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
|
||||||
|
// The action should be present.
|
||||||
|
let actions = PageActions.actionsInPanel(window);
|
||||||
|
let action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(action, "Action should be present in panel");
|
||||||
|
let expectedTitle =
|
||||||
|
"Add \u{201C}page_action_menu_add_search_engine_0\u{201D} to One-Click Search";
|
||||||
|
Assert.equal(action.getTitle(window), expectedTitle, "Action title");
|
||||||
|
let button =
|
||||||
|
BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(button, "Button should be in panel");
|
||||||
|
Assert.equal(button.label, expectedTitle, "Button label");
|
||||||
|
Assert.equal(button.classList.contains("subviewbutton-nav"), false,
|
||||||
|
"Button should not expand into a subview");
|
||||||
|
|
||||||
|
// Click the action's button.
|
||||||
|
let enginePromise =
|
||||||
|
promiseEngine("engine-added", "page_action_menu_add_search_engine_0");
|
||||||
|
let hiddenPromise = promisePageActionPanelHidden();
|
||||||
|
let feedbackPromise = promiseFeedbackPanelHidden();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||||
|
await hiddenPromise;
|
||||||
|
let engine = await enginePromise;
|
||||||
|
let feedbackText = await feedbackPromise;
|
||||||
|
Assert.equal(feedbackText, "Added to Search Dropdown");
|
||||||
|
|
||||||
|
// Open the panel again.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
|
||||||
|
await promisePageActionPanelHidden();
|
||||||
|
|
||||||
|
// The action should be gone.
|
||||||
|
actions = PageActions.actionsInPanel(window);
|
||||||
|
action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(!action, "Action should not be present in panel");
|
||||||
|
button = BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(!button, "Action button should not be in panel");
|
||||||
|
|
||||||
|
// Remove the engine.
|
||||||
|
enginePromise =
|
||||||
|
promiseEngine("engine-removed", "page_action_menu_add_search_engine_0");
|
||||||
|
Services.search.removeEngine(engine);
|
||||||
|
await enginePromise;
|
||||||
|
|
||||||
|
// Open the panel again.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
|
||||||
|
await promisePageActionPanelHidden();
|
||||||
|
|
||||||
|
// The action should be present again.
|
||||||
|
actions = PageActions.actionsInPanel(window);
|
||||||
|
action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(action, "Action should be present in panel");
|
||||||
|
Assert.equal(action.getTitle(window), expectedTitle, "Action title");
|
||||||
|
button = BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(button, "Action button should be in panel");
|
||||||
|
Assert.equal(button.label, expectedTitle, "Button label");
|
||||||
|
Assert.equal(button.classList.contains("subviewbutton-nav"), false,
|
||||||
|
"Button should not expand into a subview");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Checks a page that offers many engines.
|
||||||
|
add_task(async function many() {
|
||||||
|
let url = getRootDirectory(gTestPath) + "page_action_menu_add_search_engine_many.html";
|
||||||
|
await BrowserTestUtils.withNewTab(url, async () => {
|
||||||
|
// Open the panel.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
|
||||||
|
// The action should be present.
|
||||||
|
let actions = PageActions.actionsInPanel(window);
|
||||||
|
let action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(action, "Action should be present in panel");
|
||||||
|
let expectedTitle = "Add One-Click Search Engine";
|
||||||
|
Assert.equal(action.getTitle(window), expectedTitle, "Action title");
|
||||||
|
let button =
|
||||||
|
BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(button, "Action button should be in panel");
|
||||||
|
Assert.equal(button.label, expectedTitle, "Button label");
|
||||||
|
Assert.equal(button.classList.contains("subviewbutton-nav"), true,
|
||||||
|
"Button should expand into a subview");
|
||||||
|
|
||||||
|
// Click the action's button. The subview should be shown.
|
||||||
|
let viewPromise = promisePageActionViewShown();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||||
|
let view = await viewPromise;
|
||||||
|
let viewID =
|
||||||
|
BrowserPageActions._panelViewNodeIDForActionID("addSearchEngine", false);
|
||||||
|
Assert.equal(view.id, viewID, "View ID");
|
||||||
|
let bodyID = viewID + "-body";
|
||||||
|
let body = document.getElementById(bodyID);
|
||||||
|
Assert.deepEqual(
|
||||||
|
Array.map(body.childNodes, n => n.label),
|
||||||
|
[
|
||||||
|
"page_action_menu_add_search_engine_0",
|
||||||
|
"page_action_menu_add_search_engine_1",
|
||||||
|
"page_action_menu_add_search_engine_2",
|
||||||
|
],
|
||||||
|
"Subview children"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Click the first engine to install it.
|
||||||
|
let enginePromise =
|
||||||
|
promiseEngine("engine-added", "page_action_menu_add_search_engine_0");
|
||||||
|
let hiddenPromise = promisePageActionPanelHidden();
|
||||||
|
let feedbackPromise = promiseFeedbackPanelHidden();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
|
||||||
|
await hiddenPromise;
|
||||||
|
let engines = [];
|
||||||
|
let engine = await enginePromise;
|
||||||
|
engines.push(engine);
|
||||||
|
let feedbackText = await feedbackPromise;
|
||||||
|
Assert.equal(feedbackText, "Added to Search Dropdown", "Feedback text");
|
||||||
|
|
||||||
|
// Open the panel and show the subview again. The installed engine should
|
||||||
|
// be gone.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
viewPromise = promisePageActionViewShown();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||||
|
await viewPromise;
|
||||||
|
Assert.deepEqual(
|
||||||
|
Array.map(body.childNodes, n => n.label),
|
||||||
|
[
|
||||||
|
"page_action_menu_add_search_engine_1",
|
||||||
|
"page_action_menu_add_search_engine_2",
|
||||||
|
],
|
||||||
|
"Subview children"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Click the next engine to install it.
|
||||||
|
enginePromise =
|
||||||
|
promiseEngine("engine-added", "page_action_menu_add_search_engine_1");
|
||||||
|
hiddenPromise = promisePageActionPanelHidden();
|
||||||
|
feedbackPromise = promiseFeedbackPanelHidden();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
|
||||||
|
await hiddenPromise;
|
||||||
|
engine = await enginePromise;
|
||||||
|
engines.push(engine);
|
||||||
|
feedbackText = await feedbackPromise;
|
||||||
|
Assert.equal(feedbackText, "Added to Search Dropdown", "Feedback text");
|
||||||
|
|
||||||
|
// Open the panel again. This time the action button should show the one
|
||||||
|
// remaining engine.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
actions = PageActions.actionsInPanel(window);
|
||||||
|
action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(action, "Action should be present in panel");
|
||||||
|
expectedTitle =
|
||||||
|
"Add \u{201C}page_action_menu_add_search_engine_2\u{201D} to One-Click Search";
|
||||||
|
Assert.equal(action.getTitle(window), expectedTitle, "Action title");
|
||||||
|
button = BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(button, "Button should be present in panel");
|
||||||
|
Assert.equal(button.label, expectedTitle, "Button label");
|
||||||
|
Assert.equal(button.classList.contains("subviewbutton-nav"), false,
|
||||||
|
"Button should not expand into a subview");
|
||||||
|
|
||||||
|
// Click the button.
|
||||||
|
enginePromise =
|
||||||
|
promiseEngine("engine-added", "page_action_menu_add_search_engine_2");
|
||||||
|
hiddenPromise = promisePageActionPanelHidden();
|
||||||
|
feedbackPromise = promiseFeedbackPanelHidden();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||||
|
await hiddenPromise;
|
||||||
|
engine = await enginePromise;
|
||||||
|
engines.push(engine);
|
||||||
|
feedbackText = await feedbackPromise;
|
||||||
|
Assert.equal(feedbackText, "Added to Search Dropdown", "Feedback text");
|
||||||
|
|
||||||
|
// All engines are installed at this point. Open the panel and make sure
|
||||||
|
// the action is gone.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
|
||||||
|
await promisePageActionPanelHidden();
|
||||||
|
actions = PageActions.actionsInPanel(window);
|
||||||
|
action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(!action, "Action should be gone");
|
||||||
|
button = BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(!button, "Button should not be in panel");
|
||||||
|
|
||||||
|
// Remove the first engine.
|
||||||
|
enginePromise =
|
||||||
|
promiseEngine("engine-removed", "page_action_menu_add_search_engine_0");
|
||||||
|
Services.search.removeEngine(engines.shift());
|
||||||
|
await enginePromise;
|
||||||
|
|
||||||
|
// Open the panel again. The action should be present and showing the first
|
||||||
|
// engine.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
|
||||||
|
await promisePageActionPanelHidden();
|
||||||
|
actions = PageActions.actionsInPanel(window);
|
||||||
|
action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(action, "Action should be present in panel");
|
||||||
|
expectedTitle =
|
||||||
|
"Add \u{201C}page_action_menu_add_search_engine_0\u{201D} to One-Click Search";
|
||||||
|
Assert.equal(action.getTitle(window), expectedTitle, "Action title");
|
||||||
|
button = BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(button, "Button should be present in panel");
|
||||||
|
Assert.equal(button.label, expectedTitle, "Button label");
|
||||||
|
Assert.equal(button.classList.contains("subviewbutton-nav"), false,
|
||||||
|
"Button should not expand into a subview");
|
||||||
|
|
||||||
|
// Remove the second engine.
|
||||||
|
enginePromise =
|
||||||
|
promiseEngine("engine-removed", "page_action_menu_add_search_engine_1");
|
||||||
|
Services.search.removeEngine(engines.shift());
|
||||||
|
await enginePromise;
|
||||||
|
|
||||||
|
// Open the panel again and check the subview. The subview should be
|
||||||
|
// present now that there are two offerred engines again.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
actions = PageActions.actionsInPanel(window);
|
||||||
|
action = actions.find(a => a.id == "addSearchEngine");
|
||||||
|
Assert.ok(action, "Action should be present in panel");
|
||||||
|
expectedTitle = "Add One-Click Search Engine";
|
||||||
|
Assert.equal(action.getTitle(window), expectedTitle, "Action title");
|
||||||
|
button = BrowserPageActions.panelButtonNodeForActionID("addSearchEngine");
|
||||||
|
Assert.ok(button, "Button should be in panel");
|
||||||
|
Assert.equal(button.label, expectedTitle, "Button label");
|
||||||
|
Assert.equal(button.classList.contains("subviewbutton-nav"), true,
|
||||||
|
"Button should expand into a subview");
|
||||||
|
viewPromise = promisePageActionViewShown();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||||
|
await viewPromise;
|
||||||
|
body = document.getElementById(bodyID);
|
||||||
|
Assert.deepEqual(
|
||||||
|
Array.map(body.childNodes, n => n.label),
|
||||||
|
[
|
||||||
|
"page_action_menu_add_search_engine_0",
|
||||||
|
"page_action_menu_add_search_engine_1",
|
||||||
|
],
|
||||||
|
"Subview children"
|
||||||
|
);
|
||||||
|
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
|
||||||
|
await promisePageActionPanelHidden();
|
||||||
|
|
||||||
|
// Remove the third engine.
|
||||||
|
enginePromise =
|
||||||
|
promiseEngine("engine-removed", "page_action_menu_add_search_engine_2");
|
||||||
|
Services.search.removeEngine(engines.shift());
|
||||||
|
await enginePromise;
|
||||||
|
|
||||||
|
// Open the panel again and check the subview.
|
||||||
|
await promisePageActionPanelOpen();
|
||||||
|
viewPromise = promisePageActionViewShown();
|
||||||
|
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||||
|
await viewPromise;
|
||||||
|
Assert.deepEqual(
|
||||||
|
Array.map(body.childNodes, n => n.label),
|
||||||
|
[
|
||||||
|
"page_action_menu_add_search_engine_0",
|
||||||
|
"page_action_menu_add_search_engine_1",
|
||||||
|
"page_action_menu_add_search_engine_2",
|
||||||
|
],
|
||||||
|
"Subview children"
|
||||||
|
);
|
||||||
|
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
|
||||||
|
await promisePageActionPanelHidden();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function promiseEngine(expectedData, expectedEngineName) {
|
||||||
|
return TestUtils.topicObserved("browser-search-engine-modified", (engine, data) => {
|
||||||
|
return expectedData == data &&
|
||||||
|
expectedEngineName == engine.wrappedJSObject.name;
|
||||||
|
}).then(([engine, data]) => engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
function promiseFeedbackPanelHidden() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
BrowserPageActionFeedback.panelNode.addEventListener("popuphidden", event => {
|
||||||
|
resolve(BrowserPageActionFeedback.feedbackLabel.textContent);
|
||||||
|
}, {once: true});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||||
|
<ShortName>page_action_menu_add_search_engine_0</ShortName>
|
||||||
|
<Url type="text/html" method="GET" template="http://mochi.test:8888/" rel="searchform">
|
||||||
|
<Param name="terms" value="{searchTerms}"/>
|
||||||
|
</Url>
|
||||||
|
</SearchPlugin>
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||||
|
<ShortName>page_action_menu_add_search_engine_1</ShortName>
|
||||||
|
<Url type="text/html" method="GET" template="http://mochi.test:8888/" rel="searchform">
|
||||||
|
<Param name="terms" value="{searchTerms}"/>
|
||||||
|
</Url>
|
||||||
|
</SearchPlugin>
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||||
|
<ShortName>page_action_menu_add_search_engine_2</ShortName>
|
||||||
|
<Url type="text/html" method="GET" template="http://mochi.test:8888/" rel="searchform">
|
||||||
|
<Param name="terms" value="{searchTerms}"/>
|
||||||
|
</Url>
|
||||||
|
</SearchPlugin>
|
@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="search" type="application/opensearchdescription+xml" title="page_action_menu_add_search_engine_0" href="http://mochi.test:8888/browser/browser/base/content/test/urlbar/page_action_menu_add_search_engine_0.xml">
|
||||||
|
<link rel="search" type="application/opensearchdescription+xml" title="page_action_menu_add_search_engine_1" href="http://mochi.test:8888/browser/browser/base/content/test/urlbar/page_action_menu_add_search_engine_1.xml">
|
||||||
|
<link rel="search" type="application/opensearchdescription+xml" title="page_action_menu_add_search_engine_2" href="http://mochi.test:8888/browser/browser/base/content/test/urlbar/page_action_menu_add_search_engine_2.xml">
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
@ -0,0 +1,8 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="search" type="application/opensearchdescription+xml" title="page_action_menu_add_search_engine_0" href="http://mochi.test:8888/browser/browser/base/content/test/urlbar/page_action_menu_add_search_engine_0.xml">
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="search" type="application/opensearchdescription+xml" title="page_action_menu_add_search_engine_0" href="http://mochi.test:8888/browser/browser/base/content/test/urlbar/page_action_menu_add_search_engine_0.xml">
|
||||||
|
<link rel="search" type="application/opensearchdescription+xml" title="page_action_menu_add_search_engine_1" href="http://mochi.test:8888/browser/browser/base/content/test/urlbar/page_action_menu_add_search_engine_0.xml">
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
@ -188,18 +188,6 @@
|
|||||||
<parameter name="aVerb"/>
|
<parameter name="aVerb"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
if (aTopic == "browser-search-engine-modified") {
|
if (aTopic == "browser-search-engine-modified") {
|
||||||
switch (aVerb) {
|
|
||||||
case "engine-removed":
|
|
||||||
this.offerNewEngine(aEngine);
|
|
||||||
break;
|
|
||||||
case "engine-added":
|
|
||||||
this.hideNewEngine(aEngine);
|
|
||||||
break;
|
|
||||||
case "engine-changed":
|
|
||||||
// An engine was removed (or hidden) or added, or an icon was
|
|
||||||
// changed. Do nothing special.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the engine list is refetched next time it's needed
|
// Make sure the engine list is refetched next time it's needed
|
||||||
this._engines = null;
|
this._engines = null;
|
||||||
|
|
||||||
@ -210,75 +198,6 @@
|
|||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<!-- There are two seaprate lists of search engines, whose uses intersect
|
|
||||||
in this file. The search service (nsIBrowserSearchService and
|
|
||||||
nsSearchService.js) maintains a list of Engine objects which is used to
|
|
||||||
populate the searchbox list of available engines and to perform queries.
|
|
||||||
That list is accessed here via this.SearchService, and it's that sort of
|
|
||||||
Engine that is passed to this binding's observer as aEngine.
|
|
||||||
|
|
||||||
In addition, browser.js fills two lists of autodetected search engines
|
|
||||||
(browser.engines and browser.hiddenEngines) as properties of
|
|
||||||
selectedBrowser. Those lists contain unnamed JS objects of the form
|
|
||||||
{ uri:, title:, icon: }, and that's what the searchbar uses to determine
|
|
||||||
whether to show any "Add <EngineName>" menu items in the drop-down.
|
|
||||||
|
|
||||||
The two types of engines are currently related by their identifying
|
|
||||||
titles (the Engine object's 'name'), although that may change; see bug
|
|
||||||
335102. -->
|
|
||||||
|
|
||||||
<!-- If the engine that was just removed from the searchbox list was
|
|
||||||
autodetected on this page, move it to each browser's active list so it
|
|
||||||
will be offered to be added again. -->
|
|
||||||
<method name="offerNewEngine">
|
|
||||||
<parameter name="aEngine"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
for (let browser of gBrowser.browsers) {
|
|
||||||
if (browser.hiddenEngines) {
|
|
||||||
// XXX This will need to be changed when engines are identified by
|
|
||||||
// URL rather than title; see bug 335102.
|
|
||||||
var removeTitle = aEngine.wrappedJSObject.name;
|
|
||||||
for (var i = 0; i < browser.hiddenEngines.length; i++) {
|
|
||||||
if (browser.hiddenEngines[i].title == removeTitle) {
|
|
||||||
if (!browser.engines)
|
|
||||||
browser.engines = [];
|
|
||||||
browser.engines.push(browser.hiddenEngines[i]);
|
|
||||||
browser.hiddenEngines.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BrowserSearch.updateOpenSearchBadge();
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- If the engine that was just added to the searchbox list was
|
|
||||||
autodetected on this page, move it to each browser's hidden list so it is
|
|
||||||
no longer offered to be added. -->
|
|
||||||
<method name="hideNewEngine">
|
|
||||||
<parameter name="aEngine"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
for (let browser of gBrowser.browsers) {
|
|
||||||
if (browser.engines) {
|
|
||||||
// XXX This will need to be changed when engines are identified by
|
|
||||||
// URL rather than title; see bug 335102.
|
|
||||||
var removeTitle = aEngine.wrappedJSObject.name;
|
|
||||||
for (var i = 0; i < browser.engines.length; i++) {
|
|
||||||
if (browser.engines[i].title == removeTitle) {
|
|
||||||
if (!browser.hiddenEngines)
|
|
||||||
browser.hiddenEngines = [];
|
|
||||||
browser.hiddenEngines.push(browser.engines[i]);
|
|
||||||
browser.engines.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BrowserSearch.updateOpenSearchBadge();
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="setIcon">
|
<method name="setIcon">
|
||||||
<parameter name="element"/>
|
<parameter name="element"/>
|
||||||
<parameter name="uri"/>
|
<parameter name="uri"/>
|
||||||
|
@ -33,6 +33,10 @@ cmd_addFoundEngine=Add “%S”
|
|||||||
# grouped in a submenu using cmd_addFoundEngineMenu as a label.
|
# grouped in a submenu using cmd_addFoundEngineMenu as a label.
|
||||||
cmd_addFoundEngineMenu=Add search engine
|
cmd_addFoundEngineMenu=Add search engine
|
||||||
|
|
||||||
|
searchAddFoundEngine=Add “%S” to One-Click Search
|
||||||
|
searchAddFoundEngineMenu=Add One-Click Search Engine
|
||||||
|
searchAddedFoundEngine=Added to Search Dropdown
|
||||||
|
|
||||||
# LOCALIZATION NOTE (searchForSomethingWith2):
|
# LOCALIZATION NOTE (searchForSomethingWith2):
|
||||||
# This string is used to build the header above the list of one-click
|
# This string is used to build the header above the list of one-click
|
||||||
# search providers: "Search for <user-typed string> with:"
|
# search providers: "Search for <user-typed string> with:"
|
||||||
|
@ -1132,6 +1132,25 @@ var gBuiltInActions = [
|
|||||||
browserPageActions(buttonNode).emailLink.onCommand(event, buttonNode);
|
browserPageActions(buttonNode).emailLink.onCommand(event, buttonNode);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// add search engine
|
||||||
|
{
|
||||||
|
id: "addSearchEngine",
|
||||||
|
// The title is set in browser-pageActions.js.
|
||||||
|
title: "",
|
||||||
|
_transient: true,
|
||||||
|
onShowingInPanel(buttonNode) {
|
||||||
|
browserPageActions(buttonNode).addSearchEngine.onShowingInPanel();
|
||||||
|
},
|
||||||
|
onCommand(event, buttonNode) {
|
||||||
|
browserPageActions(buttonNode).addSearchEngine
|
||||||
|
.onCommand(event, buttonNode);
|
||||||
|
},
|
||||||
|
onSubviewShowing(panelViewNode) {
|
||||||
|
browserPageActions(panelViewNode).addSearchEngine
|
||||||
|
.onSubviewShowing(panelViewNode);
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
||||||
|
@ -164,9 +164,9 @@ add_task(async function simple() {
|
|||||||
initialActionsInUrlbar,
|
initialActionsInUrlbar,
|
||||||
"Actions in urlbar after adding the action");
|
"Actions in urlbar after adding the action");
|
||||||
|
|
||||||
// Check the list of all actions.
|
// Check the set of all actions.
|
||||||
Assert.deepEqual(PageActions.actions,
|
Assert.deepEqual(new Set(PageActions.actions),
|
||||||
initialActions.concat([action]),
|
new Set(initialActions.concat([action])),
|
||||||
"All actions after adding the action");
|
"All actions after adding the action");
|
||||||
|
|
||||||
Assert.deepEqual(PageActions.actionForID(action.id), action,
|
Assert.deepEqual(PageActions.actionForID(action.id), action,
|
||||||
@ -817,15 +817,15 @@ add_task(async function nonBuiltFirst() {
|
|||||||
|
|
||||||
// Check the actions.
|
// Check the actions.
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
PageActions.actions.map(a => a.id),
|
new Set(PageActions.actions.map(a => a.id)),
|
||||||
initialActions.map(a => a.id).concat(
|
new Set(initialActions.map(a => a.id).concat(
|
||||||
[action.id]
|
[action.id]
|
||||||
),
|
)),
|
||||||
"All actions should be in PageActions.actions"
|
"All actions should be in PageActions.actions"
|
||||||
);
|
);
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
PageActions._builtInActions.map(a => a.id),
|
PageActions._builtInActions.map(a => a.id),
|
||||||
initialActions.map(a => a.id),
|
initialActions.filter(a => !a.__transient).map(a => a.id),
|
||||||
"PageActions._builtInActions should be initial actions"
|
"PageActions._builtInActions should be initial actions"
|
||||||
);
|
);
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
@ -866,7 +866,7 @@ add_task(async function nonBuiltFirst() {
|
|||||||
);
|
);
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
PageActions._builtInActions.map(a => a.id),
|
PageActions._builtInActions.map(a => a.id),
|
||||||
initialActions.map(a => a.id),
|
initialActions.filter(a => !a.__transient).map(a => a.id),
|
||||||
"PageActions._builtInActions should be initial actions"
|
"PageActions._builtInActions should be initial actions"
|
||||||
);
|
);
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
|
@ -163,6 +163,23 @@
|
|||||||
list-style-image: url("chrome://browser/skin/sync.svg");
|
list-style-image: url("chrome://browser/skin/sync.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pageAction-panel-addSearchEngine > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
#pageAction-panel-addSearchEngine > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||||
|
display: -moz-box;
|
||||||
|
background: url(chrome://browser/skin/search-indicator-badge-add.svg) no-repeat center;
|
||||||
|
box-shadow: none;
|
||||||
|
/* "!important" is necessary to override the rule in toolbarbutton.css */
|
||||||
|
margin: -4px 0 0 !important;
|
||||||
|
margin-inline-end: -4px !important;
|
||||||
|
width: 11px;
|
||||||
|
height: 11px;
|
||||||
|
min-width: 11px;
|
||||||
|
min-height: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
/* URL bar and page action buttons */
|
/* URL bar and page action buttons */
|
||||||
|
|
||||||
#page-action-buttons {
|
#page-action-buttons {
|
||||||
|
@ -6429,7 +6429,7 @@
|
|||||||
"expires_in_version": "64",
|
"expires_in_version": "64",
|
||||||
"kind": "categorical",
|
"kind": "categorical",
|
||||||
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
||||||
"sendToDevice", "other"],
|
"sendToDevice", "other", "addSearchEngine"],
|
||||||
"description": "Count how many times people add items to the url bar"
|
"description": "Count how many times people add items to the url bar"
|
||||||
},
|
},
|
||||||
"FX_PAGE_ACTION_REMOVED": {
|
"FX_PAGE_ACTION_REMOVED": {
|
||||||
@ -6439,7 +6439,7 @@
|
|||||||
"expires_in_version": "64",
|
"expires_in_version": "64",
|
||||||
"kind": "categorical",
|
"kind": "categorical",
|
||||||
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
||||||
"sendToDevice", "other"],
|
"sendToDevice", "other", "addSearchEngine"],
|
||||||
"description": "Count how many times people remove items from the url bar"
|
"description": "Count how many times people remove items from the url bar"
|
||||||
},
|
},
|
||||||
"FX_PAGE_ACTION_MANAGED": {
|
"FX_PAGE_ACTION_MANAGED": {
|
||||||
@ -6449,7 +6449,7 @@
|
|||||||
"expires_in_version": "64",
|
"expires_in_version": "64",
|
||||||
"kind": "categorical",
|
"kind": "categorical",
|
||||||
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
||||||
"sendToDevice", "other"],
|
"sendToDevice", "other", "addSearchEngine"],
|
||||||
"description": "Count how many times people manage extensions via their actions in the url bar"
|
"description": "Count how many times people manage extensions via their actions in the url bar"
|
||||||
},
|
},
|
||||||
"FX_PAGE_ACTION_URLBAR_USED": {
|
"FX_PAGE_ACTION_URLBAR_USED": {
|
||||||
@ -6459,7 +6459,7 @@
|
|||||||
"expires_in_version": "64",
|
"expires_in_version": "64",
|
||||||
"kind": "categorical",
|
"kind": "categorical",
|
||||||
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
||||||
"sendToDevice", "other"],
|
"sendToDevice", "other", "addSearchEngine"],
|
||||||
"description": "Count how many times people use items in the url bar"
|
"description": "Count how many times people use items in the url bar"
|
||||||
},
|
},
|
||||||
"FX_PAGE_ACTION_PANEL_USED": {
|
"FX_PAGE_ACTION_PANEL_USED": {
|
||||||
@ -6469,7 +6469,7 @@
|
|||||||
"expires_in_version": "64",
|
"expires_in_version": "64",
|
||||||
"kind": "categorical",
|
"kind": "categorical",
|
||||||
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
"labels": ["bookmark", "pocket", "screenshots", "webcompat", "copyURL", "emailLink",
|
||||||
"sendToDevice", "other"],
|
"sendToDevice", "other", "addSearchEngine"],
|
||||||
"description": "Count how many times people use items from the main page action button"
|
"description": "Count how many times people use items from the main page action button"
|
||||||
},
|
},
|
||||||
"INPUT_EVENT_RESPONSE_MS": {
|
"INPUT_EVENT_RESPONSE_MS": {
|
||||||
|
Loading…
Reference in New Issue
Block a user