diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/suite/components/search/content | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/suite/components/search/content')
6 files changed, 1500 insertions, 0 deletions
diff --git a/comm/suite/components/search/content/engineManager.js b/comm/suite/components/search/content/engineManager.js new file mode 100644 index 0000000000..c505bff7fc --- /dev/null +++ b/comm/suite/components/search/content/engineManager.js @@ -0,0 +1,508 @@ +/* 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/. */ + +var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + +ChromeUtils.defineModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); + +const ENGINE_FLAVOR = "text/x-moz-search-engine"; + +const BROWSER_SUGGEST_PREF = "browser.search.suggest.enabled"; + +var gEngineView = null; + +var gEngineManagerDialog = { + init: function engineManager_init() { + gEngineView = new EngineView(new EngineStore()); + + var suggestEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF); + document.getElementById("enableSuggest").checked = suggestEnabled; + + var tree = document.getElementById("engineList"); + tree.view = gEngineView; + + Services.obs.addObserver(this, "browser-search-engine-modified"); + }, + + destroy: function engineManager_destroy() { + // Remove the observer + Services.obs.removeObserver(this, "browser-search-engine-modified"); + }, + + observe: function engineManager_observe(aEngine, aTopic, aVerb) { + if (aTopic == "browser-search-engine-modified") { + aEngine.QueryInterface(Ci.nsISearchEngine); + switch (aVerb) { + case "engine-added": + gEngineView._engineStore.addEngine(aEngine); + gEngineView.rowCountChanged(gEngineView.lastIndex, 1); + break; + case "engine-changed": + gEngineView._engineStore.reloadIcons(); + gEngineView.invalidate(); + break; + case "engine-removed": + case "engine-current": + case "engine-default": + // Not relevant + break; + } + } + }, + + onOK: function engineManager_onOK() { + // Set the preference + var newSuggestEnabled = document.getElementById("enableSuggest").checked; + Services.prefs.setBoolPref(BROWSER_SUGGEST_PREF, newSuggestEnabled); + + // Commit the changes + gEngineView._engineStore.commit(); + }, + + onRestoreDefaults: function engineManager_onRestoreDefaults() { + var num = gEngineView._engineStore.restoreDefaultEngines(); + gEngineView.rowCountChanged(0, num); + gEngineView.invalidate(); + }, + + showRestoreDefaults: function engineManager_showRestoreDefaults(val) { + document.documentElement.getButton("extra2").disabled = !val; + }, + + loadAddEngines: function engineManager_loadAddEngines() { + this.onOK(); + window.arguments[0].value = true; // see OpenSearchEngineManager() + window.close(); + }, + + remove: function engineManager_remove() { + gEngineView._engineStore.removeEngine(gEngineView.selectedEngine); + var index = gEngineView.selectedIndex; + gEngineView.rowCountChanged(index, -1); + gEngineView.invalidate(); + gEngineView.selection.select(Math.min(index, gEngineView.lastIndex)); + gEngineView.ensureRowIsVisible(gEngineView.currentIndex); + document.getElementById("engineList").focus(); + }, + + /** + * Moves the selected engine either up or down in the engine list + * @param aDir + * -1 to move the selected engine down, +1 to move it up. + */ + bump: function engineManager_move(aDir) { + var selectedEngine = gEngineView.selectedEngine; + var newIndex = gEngineView.selectedIndex - aDir; + + gEngineView._engineStore.moveEngine(selectedEngine, newIndex); + + gEngineView.invalidate(); + gEngineView.selection.select(newIndex); + gEngineView.ensureRowIsVisible(newIndex); + this.showRestoreDefaults(true); + document.getElementById("engineList").focus(); + }, + + selectEditKeyword: function engineManager_selectEditKeyword() { + let index = gEngineView.selectedIndex; + // No engine selected. + if (index == -1) + return; + + let tree = document.getElementById("engineList"); + let column = tree.columns.getColumnFor(document.getElementById("engineKeyword")); + tree.startEditing(index, column); + }, + + async editKeyword(aEngine, aNewKeyword) { + let keyword = aNewKeyword.trim(); + if (keyword) { + let eduplicate = false; + let dupName = ""; + + // Check for duplicates in Places keywords. + let bduplicate = !!(await PlacesUtils.keywords.fetch(keyword)); + + // Check for duplicates in changes we haven't committed yet + let engines = gEngineView._engineStore.engines; + for (let engine of engines) { + if (engine.alias == keyword && + engine.name != aEngine.name) { + eduplicate = true; + dupName = engine.name; + break; + } + } + + // Notify the user if they have chosen an existing engine/bookmark keyword + if (eduplicate || bduplicate) { + let strings = document.getElementById("engineManagerBundle"); + let dtitle = strings.getString("duplicateTitle"); + let bmsg = strings.getString("duplicateBookmarkMsg"); + let emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]); + + Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg); + return false; + } + } + + gEngineView._engineStore.changeEngine(aEngine, "alias", keyword); + gEngineView.invalidate(); + return true; + }, + + onSelect: function engineManager_onSelect() { + // Buttons only work if an engine is selected and it's not the last engine, + // the latter is true when the selected is first and last at the same time. + var lastSelected = (gEngineView.selectedIndex == gEngineView.lastIndex); + var firstSelected = (gEngineView.selectedIndex == 0); + var noSelection = (gEngineView.selectedIndex == -1); + + document.getElementById("cmd_remove") + .setAttribute("disabled", noSelection || + (firstSelected && lastSelected)); + + document.getElementById("cmd_moveup") + .setAttribute("disabled", noSelection || firstSelected); + + document.getElementById("cmd_movedown") + .setAttribute("disabled", noSelection || lastSelected); + + document.getElementById("cmd_editkeyword") + .setAttribute("disabled", noSelection); + }, + + onKeydown: function(aEvent) { + var tree = document.getElementById("engineList"); + if (tree.editingColumn) + return; + + if (aEvent.keyCode == (AppConstants.platform == "macosx" ? + KeyEvent.DOM_VK_RETURN : KeyEvent.DOM_VK_F2) && + tree.startEditing(gEngineView.selectedIndex, + tree.columns.engineKeyword)) { + aEvent.preventDefault(); + } + } +}; + +function onDragEngineStart(event) { + var selectedIndex = gEngineView.selectedIndex; + if (selectedIndex >= 0) { + event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString()); + event.dataTransfer.effectAllowed = "move"; + } +} + +// "Operation" objects +function EngineMoveOp(aEngineClone, aNewIndex) { + if (!aEngineClone) + throw new Error("bad args to new EngineMoveOp!"); + this._engine = aEngineClone.originalEngine; + this._newIndex = aNewIndex; +} +EngineMoveOp.prototype = { + _engine: null, + _newIndex: null, + commit: function EMO_commit() { + Services.search.moveEngine(this._engine, this._newIndex); + } +} + +function EngineRemoveOp(aEngineClone) { + if (!aEngineClone) + throw new Error("bad args to new EngineRemoveOp!"); + this._engine = aEngineClone.originalEngine; +} +EngineRemoveOp.prototype = { + _engine: null, + commit: function ERO_commit() { + Services.search.removeEngine(this._engine); + } +} + +function EngineUnhideOp(aEngineClone, aNewIndex) { + if (!aEngineClone) + throw new Error("bad args to new EngineUnhideOp!"); + this._engine = aEngineClone.originalEngine; + this._newIndex = aNewIndex; +} +EngineUnhideOp.prototype = { + _engine: null, + _newIndex: null, + commit: function EUO_commit() { + this._engine.hidden = false; + Services.search.moveEngine(this._engine, this._newIndex); + } +} + +function EngineChangeOp(aEngineClone, aProp, aValue) { + if (!aEngineClone) + throw new Error("bad args to new EngineChangeOp!"); + + this._engine = aEngineClone.originalEngine; + this._prop = aProp; + this._newValue = aValue; +} +EngineChangeOp.prototype = { + _engine: null, + _prop: null, + _newValue: null, + commit: function ECO_commit() { + this._engine[this._prop] = this._newValue; + } +} + +function EngineStore() { + this._engines = Services.search.getVisibleEngines().map(this._cloneEngine); + this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine); + + this._ops = []; + + // check if we need to disable the restore defaults button + var someHidden = this._defaultEngines.some(e => e.hidden); + gEngineManagerDialog.showRestoreDefaults(someHidden); +} +EngineStore.prototype = { + _engines: null, + _defaultEngines: null, + _ops: null, + + get engines() { + return this._engines; + }, + set engines(val) { + this._engines = val; + return val; + }, + + _getIndexForEngine: function ES_getIndexForEngine(aEngine) { + return this._engines.indexOf(aEngine); + }, + + _getEngineByName: function ES_getEngineByName(aName) { + for (var engine of this._engines) + if (engine.name == aName) + return engine; + + return null; + }, + + _cloneEngine: function ES_cloneEngine(aEngine) { + var clonedObj={}; + for (var i in aEngine) + clonedObj[i] = aEngine[i]; + clonedObj.originalEngine = aEngine; + return clonedObj; + }, + + // Callback for Array's some(). A thisObj must be passed to some() + _isSameEngine: function ES_isSameEngine(aEngineClone) { + return aEngineClone.originalEngine == this.originalEngine; + }, + + commit: function ES_commit() { + var currentEngine = this._cloneEngine(Services.search.currentEngine); + for (var i = 0; i < this._ops.length; i++) + this._ops[i].commit(); + + // Restore currentEngine if it is a default engine that is still visible. + // Needed if the user deletes currentEngine and then restores it. + if (this._defaultEngines.some(this._isSameEngine, currentEngine) && + !currentEngine.originalEngine.hidden) + Services.search.currentEngine = currentEngine.originalEngine; + }, + + addEngine: function ES_addEngine(aEngine) { + this._engines.push(this._cloneEngine(aEngine)); + }, + + moveEngine: function ES_moveEngine(aEngine, aNewIndex) { + if (aNewIndex < 0 || aNewIndex > this._engines.length - 1) + throw new Error("ES_moveEngine: invalid aNewIndex!"); + var index = this._getIndexForEngine(aEngine); + if (index == -1) + throw new Error("ES_moveEngine: invalid engine?"); + + if (index == aNewIndex) + return; // nothing to do + + // Move the engine in our internal store + var removedEngine = this._engines.splice(index, 1)[0]; + this._engines.splice(aNewIndex, 0, removedEngine); + + this._ops.push(new EngineMoveOp(aEngine, aNewIndex)); + }, + + removeEngine: function ES_removeEngine(aEngine) { + var index = this._getIndexForEngine(aEngine); + if (index == -1) + throw new Error("invalid engine?"); + + this._engines.splice(index, 1); + this._ops.push(new EngineRemoveOp(aEngine)); + if (this._defaultEngines.some(this._isSameEngine, aEngine)) + gEngineManagerDialog.showRestoreDefaults(true); + }, + + restoreDefaultEngines: function ES_restoreDefaultEngines() { + var added = 0; + + for (var i = 0; i < this._defaultEngines.length; ++i) { + var e = this._defaultEngines[i]; + + // If the engine is already in the list, just move it. + if (this._engines.some(this._isSameEngine, e)) { + this.moveEngine(this._getEngineByName(e.name), i); + } else { + // Otherwise, add it back to our internal store + this._engines.splice(i, 0, e); + this._ops.push(new EngineUnhideOp(e, i)); + added++; + } + } + gEngineManagerDialog.showRestoreDefaults(false); + return added; + }, + + changeEngine: function ES_changeEngine(aEngine, aProp, aNewValue) { + var index = this._getIndexForEngine(aEngine); + if (index == -1) + throw new Error("invalid engine?"); + + this._engines[index][aProp] = aNewValue; + this._ops.push(new EngineChangeOp(aEngine, aProp, aNewValue)); + }, + + reloadIcons: function ES_reloadIcons() { + this._engines.forEach(function (e) { + e.uri = e.originalEngine.uri; + }); + } +} + +function EngineView(aEngineStore) { + this._engineStore = aEngineStore; +} +EngineView.prototype = { + _engineStore: null, + tree: null, + + get lastIndex() { + return this.rowCount - 1; + }, + get selectedIndex() { + var seln = this.selection; + if (seln.getRangeCount() > 0) { + var min = {}; + seln.getRangeAt(0, min, {}); + return min.value; + } + return -1; + }, + get selectedEngine() { + return this._engineStore.engines[this.selectedIndex]; + }, + + // Helpers + rowCountChanged: function (index, count) { + this.tree.rowCountChanged(index, count); + }, + + invalidate: function () { + this.tree.invalidate(); + }, + + ensureRowIsVisible: function (index) { + this.tree.ensureRowIsVisible(index); + }, + + getSourceIndexFromDrag: function (dataTransfer) { + return parseInt(dataTransfer.getData(ENGINE_FLAVOR)); + }, + + // nsITreeView + get rowCount() { + return this._engineStore.engines.length; + }, + + getImageSrc: function(index, column) { + if (column.id == "engineName" && this._engineStore.engines[index].iconURI) + return this._engineStore.engines[index].iconURI.spec; + return ""; + }, + + getCellText: function(index, column) { + if (column.id == "engineName") + return this._engineStore.engines[index].name; + else if (column.id == "engineKeyword") + return this._engineStore.engines[index].alias; + return ""; + }, + + setCellText: function(index, column, value) { + if (column.id == "engineKeyword") { + gEngineManagerDialog.editKeyword(this._engineStore.engines[index], value) + .then(valid => { + if (!valid) + document.getElementById("engineList").startEditing(index, column); + }); + } + }, + + setTree: function(tree) { + this.tree = tree; + }, + + canDrop: function(targetIndex, orientation, dataTransfer) { + var sourceIndex = this.getSourceIndexFromDrag(dataTransfer); + return (sourceIndex != -1 && + sourceIndex != targetIndex && + sourceIndex != targetIndex + orientation); + }, + + drop: function(dropIndex, orientation, dataTransfer) { + var sourceIndex = this.getSourceIndexFromDrag(dataTransfer); + var sourceEngine = this._engineStore.engines[sourceIndex]; + + if (dropIndex > sourceIndex) { + if (orientation == Ci.nsITreeView.DROP_BEFORE) + dropIndex--; + } else { + if (orientation == Ci.nsITreeView.DROP_AFTER) + dropIndex++; + } + + this._engineStore.moveEngine(sourceEngine, dropIndex); + gEngineManagerDialog.showRestoreDefaults(true); + + // Redraw, and adjust selection + this.invalidate(); + this.selection.select(dropIndex); + }, + + selection: null, + getRowProperties: function(index) { return ""; }, + getCellProperties: function(index, column) { return ""; }, + getColumnProperties: function(column) { return ""; }, + isContainer: function(index) { return false; }, + isContainerOpen: function(index) { return false; }, + isContainerEmpty: function(index) { return false; }, + isSeparator: function(index) { return false; }, + isSorted: function(index) { return false; }, + getParentIndex: function(index) { return -1; }, + hasNextSibling: function(parentIndex, index) { return false; }, + getLevel: function(index) { return 0; }, + getProgressMode: function(index, column) { }, + getCellValue: function(index, column) { }, + toggleOpenState: function(index) { }, + cycleHeader: function(column) { }, + selectionChanged: function() { }, + cycleCell: function(row, column) { }, + isEditable: function(index, column) { return column.id == "engineKeyword"; }, + isSelectable: function(index, column) { return false; }, + setCellValue: function(index, column, value) { }, +}; diff --git a/comm/suite/components/search/content/engineManager.xul b/comm/suite/components/search/content/engineManager.xul new file mode 100644 index 0000000000..b160afc4eb --- /dev/null +++ b/comm/suite/components/search/content/engineManager.xul @@ -0,0 +1,98 @@ +<?xml version="1.0"?> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<?xml-stylesheet href="chrome://global/skin/"?> +<?xml-stylesheet href="chrome://communicator/skin/search/engineManager.css"?> + +<!DOCTYPE dialog SYSTEM "chrome://communicator/locale/search/engineManager.dtd"> + +<dialog id="engineManager" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + buttons="accept,cancel,extra2" + buttonlabelextra2="&restoreDefaults.label;" + buttonaccesskeyextra2="&restoreDefaults.accesskey;" + onload="gEngineManagerDialog.init();" + onunload="gEngineManagerDialog.destroy();" + ondialogaccept="gEngineManagerDialog.onOK();" + ondialogextra2="gEngineManagerDialog.onRestoreDefaults();" + title="&engineManager.title;" + style="&engineManager.style;" + persist="screenX screenY width height" + windowtype="Browser:SearchManager"> + + <script src="chrome://communicator/content/search/engineManager.js"/> + + <commandset id="engineManagerCommandSet"> + <command id="cmd_remove" + oncommand="gEngineManagerDialog.remove();" + disabled="true"/> + <command id="cmd_moveup" + oncommand="gEngineManagerDialog.bump(1);" + disabled="true"/> + <command id="cmd_movedown" + oncommand="gEngineManagerDialog.bump(-1);" + disabled="true"/> + <command id="cmd_editkeyword" + oncommand="gEngineManagerDialog.selectEditKeyword();" + disabled="true"/> + </commandset> + + <keyset id="engineManagerKeyset"> + <key id="delete" keycode="VK_DELETE" command="cmd_remove"/> + </keyset> + + <stringbundleset id="engineManagerBundleset"> + <stringbundle id="engineManagerBundle" src="chrome://communicator/locale/search/engineManager.properties"/> + </stringbundleset> + + <description>&engineManager.intro;</description> + <separator class="thin"/> + <hbox flex="1"> + <tree id="engineList" + flex="1" + rows="10" + hidecolumnpicker="true" + editable="true" + seltype="single" + onselect="gEngineManagerDialog.onSelect();" + onkeydown="gEngineManagerDialog.onKeydown(event);"> + <treechildren id="engineChildren" flex="1" + ondragstart="onDragEngineStart(event);"/> + <treecols> + <treecol id="engineName" flex="4" label="&columnLabel.name;"/> + <treecol id="engineKeyword" flex="1" label="&columnLabel.keyword;"/> + </treecols> + </tree> + <vbox> + <spacer flex="1"/> + <button id="edit" + label="&edit.label;" + accesskey="&edit.accesskey;" + command="cmd_editkeyword"/> + <button id="up" + label="&up.label;" + accesskey="&up.accesskey;" + command="cmd_moveup"/> + <button id="down" + label="&dn.label;" + accesskey="&dn.accesskey;" + command="cmd_movedown"/> + <spacer flex="1"/> + <button id="remove" + label="&remove.label;" + accesskey="&remove.accesskey;" + command="cmd_remove"/> + </vbox> + </hbox> + <hbox> + <checkbox id="enableSuggest" + label="&enableSuggest.label;" + accesskey="&enableSuggest.accesskey;"/> + </hbox> + <hbox> + <label id="addEngines" class="text-link" value="&addEngine.label;" + onclick="if (event.button == 0) { gEngineManagerDialog.loadAddEngines(); }"/> + </hbox> +</dialog> diff --git a/comm/suite/components/search/content/search-panel.js b/comm/suite/components/search/content/search-panel.js new file mode 100644 index 0000000000..c6ab43c082 --- /dev/null +++ b/comm/suite/components/search/content/search-panel.js @@ -0,0 +1,86 @@ +/* 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/. */ + +var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); +var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {FormHistory} = ChromeUtils.import("resource://gre/modules/FormHistory.jsm"); + +const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; +const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified"; +var isPB, menulist, textbox; + +function Startup() { + menulist = document.getElementById("sidebar-search-engines"); + textbox = document.getElementById("sidebar-search-text"); + isPB = top.gPrivate; + if (isPB) + textbox.searchParam += "|private"; + + LoadEngineList(); + Services.obs.addObserver(engineObserver, SEARCH_ENGINE_TOPIC, true); +} + +function LoadEngineList() { + var currentEngineName = Services.search.currentEngine.name; + // Make sure the popup is empty. + menulist.removeAllItems(); + + var engines = Services.search.getVisibleEngines(); + for (let engine of engines) { + let name = engine.name; + let menuitem = menulist.appendItem(name, name); + menuitem.setAttribute("class", "menuitem-iconic"); + if (engine.iconURI) + menuitem.setAttribute("image", engine.iconURI.spec); + menuitem.engine = engine; + if (engine.name == currentEngineName) { + // Set selection to the current default engine. + menulist.selectedItem = menuitem; + } + } + // If the current engine isn't in the list any more, select the first item. + if (menulist.selectedIndex < 0) + menulist.selectedIndex = 0; +} + +function SelectEngine() { + if (menulist.selectedItem) + Services.search.currentEngine = menulist.selectedItem.engine; + Services.obs.notifyObservers(null, SEARCH_ENGINE_TOPIC, "engine-current"); +} + +function doSearch() { + var textValue = textbox.value; + + // Save the current value in the form history (shared with the search bar) + // except when in Private Browsing mode. + + if (textValue && !isPB) { + FormHistory.update({ + op: "bump", + fieldname: "searchbar-history", + value: textValue + }, { + handleError: function(aError) { + Cu.reportError("Saving search to form history failed: " + aError.message); + } + }); + } + + var where = Services.prefs.getBoolPref("browser.search.openintab") ? "tab" : "current"; + var submission = Services.search.currentEngine.getSubmission(textValue); + openUILinkIn(submission.uri.spec, where, null, submission.postData); +} + +var engineObserver = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + + observe: function(aEngine, aTopic, aVerb) { + if (aTopic == SEARCH_ENGINE_TOPIC) { + // Right now, always just rebuild the list after any modification. + LoadEngineList(); + } + } +} diff --git a/comm/suite/components/search/content/search-panel.xul b/comm/suite/components/search/content/search-panel.xul new file mode 100644 index 0000000000..8f7c86285e --- /dev/null +++ b/comm/suite/components/search/content/search-panel.xul @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<?xml-stylesheet href="chrome://communicator/content/search/searchbarBindings.css"?> +<?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://communicator/skin/search/search.css" type="text/css"?> + +<!DOCTYPE page SYSTEM "chrome://communicator/locale/search/search-panel.dtd" > +<page id="searchPanel" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="Startup();" + elementtofocus="sidebar-search-text"> + + <script src="chrome://global/content/globalOverlay.js"/> + <script src="chrome://communicator/content/search/search-panel.js"/> + <script src="chrome://communicator/content/utilityOverlay.js"/> + + <popupset id="sidebarPopupset"> + <panel id="PopupAutoComplete" + type="autocomplete" + noautofocus="true"/> + </popupset> + + <menulist id="sidebar-search-engines" + oncommand="SelectEngine(this);"/> + + <hbox align="center"> + <textbox id="sidebar-search-text" flex="1" + class="search-textbox padded" + ontextentered="doSearch();" + placeholder="&search.placeholder;" + type="autocomplete" + inputtype="search" + autocompletepopup="PopupAutoComplete" + autocompletesearch="search-autocomplete" + autocompletesearchparam="searchbar-history" + maxrows="10" + completeselectedindex="true" + tabscrolling="true"/> + <button id="searchButton" label="&search.button.label;" + oncommand="doSearch();"/> + </hbox> + <button id="managerButton" + label="&search.engineManager.label;" + oncommand="window.top.OpenSearchEngineManager();"/> +</page> diff --git a/comm/suite/components/search/content/search.xml b/comm/suite/components/search/content/search.xml new file mode 100644 index 0000000000..8e89824314 --- /dev/null +++ b/comm/suite/components/search/content/search.xml @@ -0,0 +1,739 @@ +<?xml version="1.0"?> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<!DOCTYPE bindings [ + <!ENTITY % searchBarDTD SYSTEM "chrome://communicator/locale/search/searchbar.dtd"> + %searchBarDTD; + <!ENTITY % textcontextDTD SYSTEM "chrome://communicator/locale/utilityOverlay.dtd"> + %textcontextDTD; + <!ENTITY % navigatorDTD SYSTEM "chrome://navigator/locale/navigator.dtd"> + %navigatorDTD; +]> + +<bindings id="SearchBindings" + xmlns="http://www.mozilla.org/xbl" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:xbl="http://www.mozilla.org/xbl"> + + <binding id="searchbar"> + <resources> + <stylesheet src="chrome://communicator/content/search/searchbarBindings.css"/> + <stylesheet src="chrome://communicator/skin/search/searchbar.css"/> + </resources> + <content> + <xul:stringbundle src="chrome://communicator/locale/search/search.properties" + anonid="searchbar-stringbundle"/> + <!-- + There is a dependency between "maxrows" attribute and + "SuggestAutoComplete._historyLimit" (nsSearchSuggestions.js). Changing + one of them requires changing the other one. + --> + <xul:textbox class="searchbar-textbox" + anonid="searchbar-textbox" + type="autocomplete" + inputtype="search" + flex="1" + autocompletepopup="_child" + autocompletesearch="search-autocomplete" + autocompletesearchparam="searchbar-history" + maxrows="10" + completeselectedindex="true" + showcommentcolumn="true" + tabscrolling="true" + xbl:inherits="disabled"> + <xul:box> + <xul:toolbarbutton class="plain searchbar-engine-button" + type="menu" + anonid="searchbar-engine-button" + xbl:inherits="image"> + <xul:menupopup class="searchbar-popup" + anonid="searchbar-popup"> + <xul:menuseparator/> + <xul:menuitem class="open-engine-manager" + anonid="open-engine-manager" + label="&cmd_engineManager.label;" + oncommand="OpenSearchEngineManager();"/> + </xul:menupopup> + </xul:toolbarbutton> + </xul:box> + <xul:hbox class="search-go-container"> + <xul:image class="search-go-button" + anonid="search-go-button" + onclick="handleSearchCommand(event);" + tooltiptext="&searchEndCap.label;"/> + </xul:hbox> + <xul:panel anonid="searchPopupAutoComplete" + type="autocomplete" + noautofocus="true"/> + </xul:textbox> + </content> + + <implementation implements="nsIObserver, nsIBrowserSearchInitObserver, nsISearchInstallCallback"> + <constructor><![CDATA[ + if (this.parentNode.parentNode.localName == "toolbarpaletteitem") + return; + + if (this.usePrivateBrowsing) + this._textbox.searchParam += "|private"; + + Services.obs.addObserver(this, "browser-search-engine-modified"); + Services.obs.addObserver(this, "browser-search-service"); + this._initialized = true; + + Services.search.init(this); + ]]></constructor> + + <destructor><![CDATA[ + if (this._initialized) { + this._initialized = false; + Services.obs.removeObserver(this, "browser-search-engine-modified"); + Services.obs.removeObserver(this, "browser-search-service"); + } + + // Make sure to break the cycle from _textbox to us. Otherwise we leak + // the world. But make sure it's actually pointing to us. + // Also make sure the textbox has ever been constructed, otherwise the + // _textbox getter will cause the textbox constructor to run, add an + // observer, and leak the world too. + if (this._textboxInitialized && this._textbox.mController.input == this) + this._textbox.mController.input = null; + ]]></destructor> + + <field name="_stringBundle">document.getAnonymousElementByAttribute(this, + "anonid", "searchbar-stringbundle");</field> + <field name="_textboxInitialized">false</field> + <field name="_textbox">document.getAnonymousElementByAttribute(this, + "anonid", "searchbar-textbox");</field> + <field name="_popup">document.getAnonymousElementByAttribute(this, + "anonid", "searchbar-popup");</field> + <field name="searchButton">document.getAnonymousElementByAttribute(this, + "anonid", "searchbar-engine-button");</field> + <field name="usePrivateBrowsing" readonly="true"> + window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsILoadContext) + .usePrivateBrowsing + </field> + <field name="_initialized">false</field> + <field name="_engines">null</field> + <field name="_needToBuildPopup">true</field> + <field name="FormHistory" readonly="true"><![CDATA[ + (ChromeUtils.import("resource://gre/modules/FormHistory.jsm", {})) + .FormHistory; + ]]> + </field> + <property name="engines" readonly="true"> + <getter><![CDATA[ + if (!this._engines) + this._engines = Services.search.getVisibleEngines(); + return this._engines; + ]]></getter> + </property> + + <property name="currentEngine"> + <setter><![CDATA[ + Services.search.currentEngine = val; + Services.obs.notifyObservers(null, "browser-search-engine-modified", + "engine-current"); + return val; + ]]></setter> + <getter><![CDATA[ + var currentEngine = Services.search.currentEngine; + // Return a dummy engine if there is no currentEngine + return currentEngine || {name: "", uri: null}; + ]]></getter> + </property> + + <!-- textbox is used by sanitize.js to clear the undo history when + clearing form information. --> + <property name="textbox" readonly="true" + onget="return this._textbox;"/> + + <property name="value" onget="return this._textbox.value;" + onset="return this._textbox.value = val;"/> + + <method name="focus"> + <body><![CDATA[ + this._textbox.focus(); + ]]></body> + </method> + + <method name="select"> + <body><![CDATA[ + this._textbox.select(); + ]]></body> + </method> + + <method name="onInitComplete"> + <parameter name="aStatus"/> + <body><![CDATA[ + if (!this._initialized) + return; + if (Components.isSuccessCode(aStatus)) { + // Refresh the display (updating icon, etc) + this.updateDisplay(); + } else { + Cu.reportError("Cannot initialize search service, bailing out: " + aStatus); + } + ]]></body> + </method> + + <method name="onSuccess"> + <parameter name="aEngine"/> + <body><![CDATA[ + this.currentEngine = aEngine; + ]]></body> + </method> + + <method name="onError"> + <parameter name="aErrorCode"/> + <body><![CDATA[ + ]]></body> + </method> + + <method name="observe"> + <parameter name="aEngine"/> + <parameter name="aTopic"/> + <parameter name="aVerb"/> + <body><![CDATA[ + if (aTopic == "browser-search-engine-modified" || + (aTopic == "browser-search-service" && aVerb == "init-complete")) { + switch (aVerb) { + case "engine-removed": + this.offerNewEngine(aEngine); + break; + case "engine-added": + this.hideNewEngine(aEngine); + break; + case "engine-current": + // The current engine was changed. Rebuilding the menu appears to + // confuse its idea of whether it should be open when it's just + // been clicked, so we force it to close now. + this._popup.hidePopup(); + 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 + this._engines = null; + + // Rebuild the popup and update the display after any modification. + this.rebuildPopup(); + this.updateDisplay(); + } + ]]></body> + </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, navigator.js fills two lists of autodetected search engines + (browser.engines and browser.hiddenEngines) as properties of + mCurrentBrowser. 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 (var browser of getBrowser().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; + } + } + } + } + this.updateSearchButton(); + ]]></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 (var browser of getBrowser().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; + } + } + } + } + this.updateSearchButton(); + ]]></body> + </method> + + <method name="updateSearchButton"> + <body><![CDATA[ + var engines = getBrowser().mCurrentBrowser.engines; + if (engines && engines.length) + this.searchButton.setAttribute("addengines", "true"); + else + this.searchButton.removeAttribute("addengines"); + ]]></body> + </method> + + <method name="updateDisplay"> + <body><![CDATA[ + var uri = this.currentEngine.iconURI; + this.setAttribute("image", uri ? uri.spec : ""); + + var name = this.currentEngine.name; + var text = this._stringBundle.getFormattedString("searchtip", [name]); + this._textbox.placeholder = name; + this._textbox.tooltipText = text; + ]]></body> + </method> + + <!-- Rebuilds the dynamic portion of the popup menu (i.e., the menu items + for new search engines that can be added to the available list). This + is called each time the popup is shown. + --> + <method name="rebuildPopupDynamic"> + <body><![CDATA[ + // We might not have added the main popup items yet, do that first + // if needed. + if (this._needToBuildPopup) + this.rebuildPopup(); + + var popup = this._popup; + // Clear any addengine menuitems, including addengine-item entries and + // the addengine-separator. Work backward to avoid invalidating the + // indexes as items are removed. + var items = popup.childNodes; + for (var i = items.length - 1; i >= 0; i--) { + if (items[i].classList.contains("addengine-item") || + items[i].classList.contains("addengine-separator")) + items[i].remove(); + } + + var addengines = getBrowser().mCurrentBrowser.engines; + if (addengines && addengines.length > 0) { + const kXULNS = + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + + // Find the (first) separator in the remaining menu, or the first item + // if no separators are present. + var insertLocation = popup.firstChild; + while (insertLocation.nextSibling && + insertLocation.localName != "menuseparator") { + insertLocation = insertLocation.nextSibling; + } + if (insertLocation.localName != "menuseparator") + insertLocation = popup.firstChild; + + var separator = document.createElementNS(kXULNS, "menuseparator"); + separator.setAttribute("class", "addengine-separator"); + popup.insertBefore(separator, insertLocation); + + // Insert the "add this engine" items. + for (var i = 0; i < addengines.length; i++) { + var engineInfo = addengines[i]; + var labelStr = + this._stringBundle.getFormattedString("cmd_addFoundEngine", + [engineInfo.title]); + var menuitem = document.createElementNS(kXULNS, "menuitem"); + menuitem.setAttribute("class", "menuitem-iconic addengine-item"); + menuitem.setAttribute("label", labelStr); + menuitem.setAttribute("tooltiptext", engineInfo.uri); + menuitem.setAttribute("uri", engineInfo.uri); + if (engineInfo.icon) + menuitem.setAttribute("image", engineInfo.icon); + menuitem.setAttribute("title", engineInfo.title); + popup.insertBefore(menuitem, insertLocation); + } + } + ]]></body> + </method> + + <!-- Rebuilds the list of visible search engines in the menu. Does not remove + or update any dynamic entries (i.e., "Add this engine" items) nor the + Manage Engines item. This is called by the observer when the list of + visible engines, or the currently selected engine, has changed. + --> + <method name="rebuildPopup"> + <body><![CDATA[ + var popup = this._popup; + + // Clear the popup, down to the first separator + while (popup.firstChild && popup.firstChild.localName != "menuseparator") + popup.firstChild.remove(); + + const kXULNS = + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + + var engines = this.engines; + for (var i = engines.length - 1; i >= 0; --i) { + var menuitem = document.createElementNS(kXULNS, "menuitem"); + var name = engines[i].name; + menuitem.setAttribute("label", name); + menuitem.setAttribute("class", "menuitem-iconic searchbar-engine-menuitem menuitem-with-favicon"); + // Since this menu is rebuilt by the observer method whenever a new + // engine is selected, the "selected" attribute does not need to be + // explicitly cleared anywhere. + if (engines[i] == this.currentEngine) + menuitem.setAttribute("selected", "true"); + var tooltip = this._stringBundle.getFormattedString("searchtip", [name]); + menuitem.setAttribute("tooltiptext", tooltip); + if (engines[i].iconURI) + menuitem.setAttribute("image", engines[i].iconURI.spec); + popup.insertBefore(menuitem, popup.firstChild); + menuitem.engine = engines[i]; + } + + this._needToBuildPopup = false; + ]]></body> + </method> + + <method name="selectEngine"> + <parameter name="aEvent"/> + <parameter name="isNextEngine"/> + <body><![CDATA[ + // Find the new index + var newIndex = this.engines.indexOf(this.currentEngine); + newIndex += isNextEngine ? 1 : -1; + + if (newIndex >= 0 && newIndex < this.engines.length) + this.currentEngine = this.engines[newIndex]; + + aEvent.preventDefault(); + aEvent.stopPropagation(); + ]]></body> + </method> + + <method name="handleSearchCommand"> + <parameter name="aEvent"/> + <body><![CDATA[ + var textBox = this._textbox; + var textValue = textBox.value; + + var where = "current"; + if (aEvent && aEvent.originalTarget.getAttribute("anonid") == "search-go-button") { + if (aEvent.button == 2) + return; + where = whereToOpenLink(aEvent, false, true); + } + else { + var newTabPref = Services.prefs.getBoolPref("browser.search.openintab"); + if ((aEvent && aEvent.altKey) ^ newTabPref) + where = "tabfocused"; + } + + this.doSearch(textValue, where); + ]]></body> + </method> + + <method name="doSearch"> + <parameter name="aData"/> + <parameter name="aWhere"/> + <body><![CDATA[ + var textBox = this._textbox; + + // Save the current value in the form history. + if (aData && !this.usePrivateBrowsing && this.FormHistory.enabled) { + this.FormHistory.update( + { op: "bump", + fieldname: textBox.getAttribute("autocompletesearchparam"), + value: aData }, + { handleError(aError) { + Cu.reportError("Saving search to form history failed: " + aError.message); + }}); + } + + // null parameter below specifies HTML response for search + var submission = this.currentEngine.getSubmission(aData); + openUILinkIn(submission.uri.spec, aWhere, null, submission.postData); + ]]></body> + </method> + </implementation> + + <handlers> + <handler event="command"><![CDATA[ + const target = event.originalTarget; + if (target.engine) { + this.currentEngine = target.engine; + } else if (target.classList.contains("addengine-item")) { + // We only detect OpenSearch files + var type = Ci.nsISearchEngine.DATA_XML; + // Select the installed engine if the installation succeeds + Services.search.addEngine(target.getAttribute("uri"), type, + target.getAttribute("image"), false, + this); + } + else + return; + + this.focus(); + this.select(); + ]]></handler> + + <handler event="popupshowing" action="this.rebuildPopupDynamic();"/> + + <handler event="DOMMouseScroll" + phase="capturing" + modifiers="accel" + action="this.selectEngine(event, (event.detail > 0));"/> + + <handler event="focus"><![CDATA[ + // Speculatively connect to the current engine's search URI (and + // suggest URI, if different) to reduce request latency. + this.currentEngine.speculativeConnect({window: window}); + ]]></handler> + </handlers> + </binding> + + <binding id="search-textbox" + extends="chrome://global/content/bindings/autocomplete.xml#autocomplete"> + <implementation implements="nsIObserver"> + <constructor><![CDATA[ + var bindingParent = document.getBindingParent(this); + if (bindingParent && bindingParent.parentNode.parentNode.localName == + "toolbarpaletteitem") + return; + + if (Services.prefs.getBoolPref("browser.urlbar.clickSelectsAll")) + this.setAttribute("clickSelectsAll", true); + + // Add items to context menu and attach controller to handle them + this.controllers.appendController(this.searchbarController); + // bindingParent is not set in the sidebar because there is no + // searchbar created in it. + if (bindingParent) { + bindingParent._textboxInitialized = true; + } + + // Add observer for suggest preference + Services.prefs.addObserver("browser.search.suggest.enabled", this); + + this._inputBox.setAttribute("suggestchecked", this._suggestEnabled); + ]]></constructor> + + <destructor><![CDATA[ + Services.prefs.removeObserver("browser.search.suggest.enabled", this); + + // Because XBL and the customize toolbar code interacts poorly, + // there may not be anything to remove here + try { + this.controllers.removeController(this.searchbarController); + } catch (ex) { } + ]]></destructor> + <field name="_inputBox"> + document.getAnonymousElementByAttribute(this, "anonid", "textbox-input-box"); + </field> + <field name="_suggestEnabled"> + Services.prefs.getBoolPref("browser.search.suggest.enabled"); + </field> + + <method name="observe"> + <parameter name="aSubject"/> + <parameter name="aTopic"/> + <parameter name="aData"/> + <body><![CDATA[ + if (aTopic == "nsPref:changed") { + this._suggestEnabled = + Services.prefs.getBoolPref("browser.search.suggest.enabled"); + this._inputBox.setAttribute("suggestchecked", this._suggestEnabled); + } + ]]></body> + </method> + + <field name="FormHistory" readonly="true"><![CDATA[ + (ChromeUtils.import("resource://gre/modules/FormHistory.jsm", {})) + .FormHistory; + ]]> + </field> + + <!-- nsIController --> + <field name="searchbarController" readonly="true"><![CDATA[({ + supportsCommand: function(aCommand) { + switch (aCommand) { + case "cmd_pasteAndSearch": + case "cmd_clearhistory": + case "cmd_togglesuggest": + return true; + } + return false; + }, + + isCommandEnabled: function(aCommand) { + switch (aCommand) { + case "cmd_pasteAndSearch": + return document.commandDispatcher + .getControllerForCommand("cmd_paste") + .isCommandEnabled("cmd_paste"); + case "cmd_clearhistory": + case "cmd_togglesuggest": + return true; + } + return false; + }, + + doCommand: function (aCommand) { + switch (aCommand) { + case "cmd_pasteAndSearch": + this.select(); + goDoCommand("cmd_paste"); + this.onTextEntered(); + break; + case "cmd_clearhistory": + this.FormHistory.update( + { op : "remove", fieldname : "searchbar-history" }, + null); + this.value = ""; + break; + case "cmd_togglesuggest": + // The pref observer will update _suggestEnabled and the menu + // checkmark. + Services.prefs.setBoolPref("browser.search.suggest.enabled", + !this._suggestEnabled); + break; + default: + // do nothing with unrecognized command + } + }.bind(this) + })]]></field> + </implementation> + + <handlers> + <handler event="dragover"> + <![CDATA[ + var types = event.dataTransfer.types; + if (types.includes("text/plain") || types.includes("text/x-moz-text-internal")) + event.preventDefault(); + ]]> + </handler> + + <handler event="drop"> + <![CDATA[ + var dataTransfer = event.dataTransfer; + var data = dataTransfer.getData("text/plain"); + if (!data) + data = dataTransfer.getData("text/x-moz-text-internal"); + if (data) { + event.preventDefault(); + this.value = data; + this.onTextEntered(); + } + ]]> + </handler> + </handlers> + </binding> + + <binding id="searchbar-textbox" + extends="chrome://communicator/content/search/search.xml#search-textbox"> + <implementation> + <method name="openSearch"> + <body> + <![CDATA[ + // Don't open search popup if history popup is open + if (!this.popupOpen) { + document.getBindingParent(this).searchButton.open = true; + return false; + } + return true; + ]]> + </body> + </method> + + <!-- override |onTextEntered| in autocomplete.xml --> + <method name="onTextEntered"> + <parameter name="aEvent"/> + <body><![CDATA[ + var evt = aEvent || this.mEnterEvent; + document.getBindingParent(this).handleSearchCommand(evt); + this.mEnterEvent = null; + ]]></body> + </method> + </implementation> + + <handlers> + <handler event="keypress" keycode="VK_UP" modifiers="accel" + phase="capturing" + action="document.getBindingParent(this).selectEngine(event, false);"/> + + <handler event="keypress" keycode="VK_DOWN" modifiers="accel" + phase="capturing" + action="document.getBindingParent(this).selectEngine(event, true);"/> + + <handler event="keypress" keycode="VK_DOWN" modifiers="alt" + phase="capturing" + action="return this.openSearch();"/> + + <handler event="keypress" keycode="VK_UP" modifiers="alt" + phase="capturing" + action="return this.openSearch();"/> + + <handler event="keypress" keycode="VK_F4" phase="capturing"> + <![CDATA[ + return (AppConstants.platform == "macosx") || this.openSearch() + ]]></handler> + </handlers> + </binding> + + <binding id="input-box-search" extends="chrome://global/content/bindings/textbox.xml#input-box"> + <content context="_child"> + <children/> + <xul:menupopup anonid="input-box-contextmenu" + class="textbox-contextmenu" + onpopupshowing="var input = + this.parentNode.getElementsByAttribute('anonid', 'input')[0]; + if (document.commandDispatcher.focusedElement != input) + input.focus(); + this.parentNode._doPopupItemEnabling(this);" + oncommand="var cmd = event.originalTarget.getAttribute('cmd'); if (cmd) { this.parentNode.doCommand(cmd); event.stopPropagation(); }"> + <xul:menuitem label="&undoCmd.label;" accesskey="&undoCmd.accesskey;" cmd="cmd_undo"/> + <xul:menuseparator/> + <xul:menuitem label="&cutCmd.label;" accesskey="&cutCmd.accesskey;" cmd="cmd_cut"/> + <xul:menuitem label="©Cmd.label;" accesskey="©Cmd.accesskey;" cmd="cmd_copy"/> + <xul:menuitem label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;" cmd="cmd_paste"/> + <xul:menuitem label="&pasteSearchCmd.label;" accesskey="&pasteSearchCmd.accesskey;" cmd="cmd_pasteAndSearch"/> + <xul:menuitem label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;" cmd="cmd_delete"/> + <xul:menuseparator/> + <xul:menuitem label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;" cmd="cmd_selectAll"/> + <xul:menuseparator/> + <xul:menuitem label="&clearHistoryCmd.label;" accesskey="&clearHistoryCmd.accesskey;" cmd="cmd_clearhistory"/> + <xul:menuitem label="&showSuggestionsCmd.label;" + accesskey="&showSuggestionsCmd.accesskey;" + anonid="toggle-suggest-item" + type="checkbox" + autocheck="false" + xbl:inherits="checked=suggestchecked" + cmd="cmd_togglesuggest"/> + </xul:menupopup> + </content> + </binding> +</bindings> diff --git a/comm/suite/components/search/content/searchbarBindings.css b/comm/suite/components/search/content/searchbarBindings.css new file mode 100644 index 0000000000..3fefc9365a --- /dev/null +++ b/comm/suite/components/search/content/searchbarBindings.css @@ -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/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +.search-textbox { + -moz-binding: url("chrome://communicator/content/search/search.xml#search-textbox"); +} + +.searchbar-textbox { + -moz-binding: url("chrome://communicator/content/search/search.xml#searchbar-textbox"); +} + +.textbox-input-box { + -moz-binding: url("chrome://communicator/content/search/search.xml#input-box-search"); +} + +.autocomplete-history-dropmarker { + display: none; +} |