mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 15:27:30 +09:00
Add Pale Moon
This commit is contained in:
parent
dcd9973243
commit
fe8028fa2e
1173 changed files with 143053 additions and 934 deletions
491
application/palemoon/components/search/content/engineManager.js
Normal file
491
application/palemoon/components/search/content/engineManager.js
Normal file
|
|
@ -0,0 +1,491 @@
|
|||
/* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
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", false);
|
||||
},
|
||||
|
||||
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.opener.BrowserSearch.loadAddEngines();
|
||||
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();
|
||||
},
|
||||
|
||||
editKeyword: function engineManager_editKeyword() {
|
||||
var selectedEngine = gEngineView.selectedEngine;
|
||||
if (!selectedEngine)
|
||||
return;
|
||||
|
||||
var alias = { value: selectedEngine.alias };
|
||||
var strings = document.getElementById("engineManagerBundle");
|
||||
var title = strings.getString("editTitle");
|
||||
var msg = strings.getFormattedString("editMsg", [selectedEngine.name]);
|
||||
|
||||
while (Services.prompt.prompt(window, title, msg, alias, null, {})) {
|
||||
var bduplicate = false;
|
||||
var eduplicate = false;
|
||||
var dupName = "";
|
||||
|
||||
if (alias.value != "") {
|
||||
try {
|
||||
let bmserv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
if (bmserv.getURIForKeyword(alias.value))
|
||||
bduplicate = true;
|
||||
} catch(ex) {}
|
||||
|
||||
// Check for duplicates in changes we haven't committed yet
|
||||
let engines = gEngineView._engineStore.engines;
|
||||
for each (let engine in engines) {
|
||||
if (engine.alias == alias.value &&
|
||||
engine.name != selectedEngine.name) {
|
||||
eduplicate = true;
|
||||
dupName = engine.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the user if they have chosen an existing engine/bookmark keyword
|
||||
if (eduplicate || bduplicate) {
|
||||
var dtitle = strings.getString("duplicateTitle");
|
||||
var bmsg = strings.getString("duplicateBookmarkMsg");
|
||||
var emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
|
||||
|
||||
Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
|
||||
} else {
|
||||
gEngineView._engineStore.changeEngine(selectedEngine, "alias",
|
||||
alias.value);
|
||||
gEngineView.invalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
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(function (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 each (var engine in 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 "";
|
||||
},
|
||||
|
||||
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 false; },
|
||||
isSelectable: function(index, column) { return false; },
|
||||
setCellValue: function(index, column, value) { },
|
||||
setCellText: function(index, column, value) { },
|
||||
performAction: function(action) { },
|
||||
performActionOnRow: function(action, index) { },
|
||||
performActionOnCell: function(action, index, column) { }
|
||||
};
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?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://browser/skin/engineManager.css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://browser/locale/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 type="application/javascript"
|
||||
src="chrome://browser/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.editKeyword();"
|
||||
disabled="true"/>
|
||||
</commandset>
|
||||
|
||||
<keyset id="engineManagerKeyset">
|
||||
<key id="delete" keycode="VK_DELETE" command="cmd_remove"/>
|
||||
</keyset>
|
||||
|
||||
<stringbundleset id="engineManagerBundleset">
|
||||
<stringbundle id="engineManagerBundle" src="chrome://browser/locale/engineManager.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<description>&engineManager.intro;</description>
|
||||
<separator class="thin"/>
|
||||
<hbox flex="1">
|
||||
<tree id="engineList" flex="1" rows="10" hidecolumnpicker="true"
|
||||
seltype="single" onselect="gEngineManagerDialog.onSelect();">
|
||||
<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>
|
||||
842
application/palemoon/components/search/content/search.xml
Normal file
842
application/palemoon/components/search/content/search.xml
Normal file
|
|
@ -0,0 +1,842 @@
|
|||
<?xml version="1.0"?>
|
||||
# -*- Mode: HTML -*-
|
||||
# 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://browser/locale/searchbar.dtd" >
|
||||
%searchBarDTD;
|
||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
|
||||
%browserDTD;
|
||||
]>
|
||||
|
||||
<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://browser/content/search/searchbarBindings.css"/>
|
||||
<stylesheet src="chrome://browser/skin/searchbar.css"/>
|
||||
</resources>
|
||||
<content>
|
||||
<xul:stringbundle src="chrome://browser/locale/search.properties"
|
||||
anonid="searchbar-stringbundle"/>
|
||||
|
||||
<xul:textbox class="searchbar-textbox"
|
||||
anonid="searchbar-textbox"
|
||||
type="autocomplete"
|
||||
flex="1"
|
||||
autocompletepopup="PopupAutoComplete"
|
||||
autocompletesearch="search-autocomplete"
|
||||
autocompletesearchparam="searchbar-history"
|
||||
timeout="250"
|
||||
maxrows="10"
|
||||
completeselectedindex="true"
|
||||
showcommentcolumn="true"
|
||||
tabscrolling="true"
|
||||
xbl:inherits="disabled,disableautocomplete,searchengine,src,newlines">
|
||||
<xul:box>
|
||||
<xul:button class="searchbar-engine-button"
|
||||
type="menu"
|
||||
anonid="searchbar-engine-button">
|
||||
<xul:image class="searchbar-engine-image" xbl:inherits="src"/>
|
||||
<xul:image class="searchbar-dropmarker-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="openManager(event);"/>
|
||||
</xul:menupopup>
|
||||
</xul:button>
|
||||
</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:textbox>
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIObserver">
|
||||
<constructor><![CDATA[
|
||||
if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
|
||||
return;
|
||||
// Make sure we rebuild the popup in onpopupshowing
|
||||
this._needToBuildPopup = true;
|
||||
|
||||
var os =
|
||||
Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
os.addObserver(this, "browser-search-engine-modified", false);
|
||||
|
||||
this._initialized = true;
|
||||
|
||||
this.searchService.init((function search_init_cb(aStatus) {
|
||||
// Bail out if the binding has been destroyed
|
||||
if (!this._initialized)
|
||||
return;
|
||||
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
// Refresh the display (updating icon, etc)
|
||||
this.updateDisplay();
|
||||
} else {
|
||||
Components.utils.reportError("Cannot initialize search service, bailing out: " + aStatus);
|
||||
}
|
||||
}).bind(this));
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
if (this._initialized) {
|
||||
this._initialized = false;
|
||||
|
||||
var os = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
os.removeObserver(this, "browser-search-engine-modified");
|
||||
}
|
||||
|
||||
// Make sure to break the cycle from _textbox to us. Otherwise we leak
|
||||
// the world. But make sure it's actually pointing to us.
|
||||
if (this._textbox.mController.input == this)
|
||||
this._textbox.mController.input = null;
|
||||
]]></destructor>
|
||||
|
||||
<field name="_stringBundle">document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "searchbar-stringbundle");</field>
|
||||
<field name="_textbox">document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "searchbar-textbox");</field>
|
||||
<field name="_popup">document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "searchbar-popup");</field>
|
||||
<field name="_ss">null</field>
|
||||
<field name="_engines">null</field>
|
||||
<field name="FormHistory" readonly="true">
|
||||
(Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
|
||||
</field>
|
||||
|
||||
<property name="engines" readonly="true">
|
||||
<getter><![CDATA[
|
||||
if (!this._engines)
|
||||
this._engines = this.searchService.getVisibleEngines();
|
||||
return this._engines;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<field name="searchButton">document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "searchbar-engine-button");</field>
|
||||
|
||||
<property name="currentEngine">
|
||||
<setter><![CDATA[
|
||||
let ss = this.searchService;
|
||||
ss.defaultEngine = ss.currentEngine = val;
|
||||
return val;
|
||||
]]></setter>
|
||||
<getter><![CDATA[
|
||||
var currentEngine = this.searchService.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="searchService" readonly="true">
|
||||
<getter><![CDATA[
|
||||
if (!this._ss) {
|
||||
const nsIBSS = Components.interfaces.nsIBrowserSearchService;
|
||||
this._ss =
|
||||
Components.classes["@mozilla.org/browser/search-service;1"]
|
||||
.getService(nsIBSS);
|
||||
}
|
||||
return this._ss;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<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="observe">
|
||||
<parameter name="aEngine"/>
|
||||
<parameter name="aTopic"/>
|
||||
<parameter name="aVerb"/>
|
||||
<body><![CDATA[
|
||||
if (aTopic == "browser-search-engine-modified") {
|
||||
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, browser.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[
|
||||
var allbrowsers = getBrowser().mPanelContainer.childNodes;
|
||||
for (var tab = 0; tab < allbrowsers.length; tab++) {
|
||||
var browser = getBrowser().getBrowserAtIndex(tab);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></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[
|
||||
var allbrowsers = getBrowser().mPanelContainer.childNodes;
|
||||
for (var tab = 0; tab < allbrowsers.length; tab++) {
|
||||
var browser = getBrowser().getBrowserAtIndex(tab);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="setIcon">
|
||||
<parameter name="element"/>
|
||||
<parameter name="uri"/>
|
||||
<body><![CDATA[
|
||||
if (uri) {
|
||||
let size = Math.round(16 * window.devicePixelRatio);
|
||||
if (!uri.includes("#"))
|
||||
uri += "#-moz-resolution=" + size + "," + size;
|
||||
}
|
||||
element.setAttribute("src", uri);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="updateDisplay">
|
||||
<body><![CDATA[
|
||||
var uri = this.currentEngine.iconURI;
|
||||
this.setIcon(this, uri ? uri.spec : "");
|
||||
|
||||
var name = this.currentEngine.name;
|
||||
var text = this._stringBundle.getFormattedString("searchtip", [name]);
|
||||
this._textbox.placeholder = name;
|
||||
this._textbox.label = text;
|
||||
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"))
|
||||
popup.removeChild(items[i]);
|
||||
}
|
||||
|
||||
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 menuitem = document.createElement("menuitem");
|
||||
var engineInfo = addengines[i];
|
||||
var labelStr =
|
||||
this._stringBundle.getFormattedString("cmd_addFoundEngine",
|
||||
[engineInfo.title]);
|
||||
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)
|
||||
this.setIcon(menuitem, 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.removeChild(popup.firstChild);
|
||||
|
||||
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("id", 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)
|
||||
this.setIcon(menuitem, engines[i].iconURI.spec);
|
||||
popup.insertBefore(menuitem, popup.firstChild);
|
||||
menuitem.engine = engines[i];
|
||||
}
|
||||
|
||||
this._needToBuildPopup = false;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="openManager">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
var wm =
|
||||
Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
|
||||
var window = wm.getMostRecentWindow("Browser:SearchManager");
|
||||
if (window)
|
||||
window.focus()
|
||||
else {
|
||||
setTimeout(function () {
|
||||
openDialog("chrome://browser/content/search/engineManager.xul",
|
||||
"_blank", "chrome,dialog,modal,centerscreen,resizable");
|
||||
}, 0);
|
||||
}
|
||||
]]></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 = textBox._prefBranch.getBoolPref("browser.search.openintab");
|
||||
if ((aEvent && aEvent.altKey) ^ newTabPref)
|
||||
where = "tab";
|
||||
}
|
||||
|
||||
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 && !PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
this.FormHistory.update(
|
||||
{ op : "bump",
|
||||
fieldname : textBox.getAttribute("autocompletesearchparam"),
|
||||
value : aData },
|
||||
{ handleError : function(aError) {
|
||||
Components.utils.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")) {
|
||||
var searchService =
|
||||
Components.classes["@mozilla.org/browser/search-service;1"]
|
||||
.getService(Components.interfaces.nsIBrowserSearchService);
|
||||
// We only detect OpenSearch files
|
||||
var type = Components.interfaces.nsISearchEngine.DATA_XML;
|
||||
// Select the installed engine if the installation succeeds
|
||||
var installCallback = {
|
||||
onSuccess: engine => this.currentEngine = engine
|
||||
}
|
||||
searchService.addEngine(target.getAttribute("uri"), type,
|
||||
target.getAttribute("src"), false,
|
||||
installCallback);
|
||||
}
|
||||
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
|
||||
|
||||
const SUGGEST_TYPE = "application/x-suggestions+json";
|
||||
var engine = this.currentEngine;
|
||||
var connector =
|
||||
Services.io.QueryInterface(Components.interfaces.nsISpeculativeConnect);
|
||||
var searchURI = engine.getSubmission("dummy").uri;
|
||||
let callbacks = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsILoadContext);
|
||||
connector.speculativeConnect(searchURI, callbacks);
|
||||
|
||||
if (engine.supportsResponseType(SUGGEST_TYPE)) {
|
||||
var suggestURI = engine.getSubmission("dummy", SUGGEST_TYPE).uri;
|
||||
if (suggestURI.prePath != searchURI.prePath)
|
||||
connector.speculativeConnect(suggestURI, callbacks);
|
||||
}
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="searchbar-textbox"
|
||||
extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
|
||||
<implementation implements="nsIObserver">
|
||||
<constructor><![CDATA[
|
||||
const kXULNS =
|
||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
if (document.getBindingParent(this).parentNode.parentNode.localName ==
|
||||
"toolbarpaletteitem")
|
||||
return;
|
||||
|
||||
// Initialize fields
|
||||
this._stringBundle = document.getBindingParent(this)._stringBundle;
|
||||
this._prefBranch =
|
||||
Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
this._suggestEnabled =
|
||||
this._prefBranch.getBoolPref("browser.search.suggest.enabled");
|
||||
this._clickSelectsAll =
|
||||
this._prefBranch.getBoolPref("browser.urlbar.clickSelectsAll");
|
||||
|
||||
this.setAttribute("clickSelectsAll", this._clickSelectsAll);
|
||||
|
||||
// Add items to context menu and attach controller to handle them
|
||||
var textBox = document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "textbox-input-box");
|
||||
var cxmenu = document.getAnonymousElementByAttribute(textBox,
|
||||
"anonid", "input-box-contextmenu");
|
||||
var pasteAndSearch;
|
||||
cxmenu.addEventListener("popupshowing", function() {
|
||||
if (!pasteAndSearch)
|
||||
return;
|
||||
var controller = document.commandDispatcher.getControllerForCommand("cmd_paste");
|
||||
var enabled = controller.isCommandEnabled("cmd_paste");
|
||||
if (enabled)
|
||||
pasteAndSearch.removeAttribute("disabled");
|
||||
else
|
||||
pasteAndSearch.setAttribute("disabled", "true");
|
||||
}, false);
|
||||
|
||||
var element, label, akey;
|
||||
|
||||
element = document.createElementNS(kXULNS, "menuseparator");
|
||||
cxmenu.appendChild(element);
|
||||
|
||||
var insertLocation = cxmenu.firstChild;
|
||||
while (insertLocation.nextSibling &&
|
||||
insertLocation.getAttribute("cmd") != "cmd_paste")
|
||||
insertLocation = insertLocation.nextSibling;
|
||||
if (insertLocation) {
|
||||
element = document.createElementNS(kXULNS, "menuitem");
|
||||
label = this._stringBundle.getString("cmd_pasteAndSearch");
|
||||
element.setAttribute("label", label);
|
||||
element.setAttribute("anonid", "paste-and-search");
|
||||
element.setAttribute("oncommand",
|
||||
"BrowserSearch.searchBar.select(); goDoCommand('cmd_paste'); BrowserSearch.searchBar.handleSearchCommand();");
|
||||
cxmenu.insertBefore(element, insertLocation.nextSibling);
|
||||
pasteAndSearch = element;
|
||||
}
|
||||
|
||||
element = document.createElementNS(kXULNS, "menuitem");
|
||||
label = this._stringBundle.getString("cmd_clearHistory");
|
||||
akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
|
||||
element.setAttribute("label", label);
|
||||
element.setAttribute("accesskey", akey);
|
||||
element.setAttribute("cmd", "cmd_clearhistory");
|
||||
cxmenu.appendChild(element);
|
||||
|
||||
element = document.createElementNS(kXULNS, "menuitem");
|
||||
label = this._stringBundle.getString("cmd_showSuggestions");
|
||||
akey = this._stringBundle.getString("cmd_showSuggestions_accesskey");
|
||||
element.setAttribute("anonid", "toggle-suggest-item");
|
||||
element.setAttribute("label", label);
|
||||
element.setAttribute("accesskey", akey);
|
||||
element.setAttribute("cmd", "cmd_togglesuggest");
|
||||
element.setAttribute("type", "checkbox");
|
||||
element.setAttribute("checked", this._suggestEnabled);
|
||||
element.setAttribute("autocheck", "false");
|
||||
this._suggestMenuItem = element;
|
||||
cxmenu.appendChild(element);
|
||||
|
||||
this.controllers.appendController(this.searchbarController);
|
||||
|
||||
// Add observer for suggest preference
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
prefs.addObserver("browser.search.suggest.enabled", this, false);
|
||||
prefs.addObserver("browser.urlbar.clickSelectsAll", this, false);
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
prefs.removeObserver("browser.search.suggest.enabled", this);
|
||||
prefs.removeObserver("browser.urlbar.clickSelectsAll", 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="_stringBundle"/>
|
||||
<field name="_prefBranch"/>
|
||||
<field name="_suggestMenuItem"/>
|
||||
<field name="_suggestEnabled"/>
|
||||
<field name="_clickSelectsAll"/>
|
||||
|
||||
<!--
|
||||
This overrides the searchParam property in autocomplete.xml. We're
|
||||
hijacking this property as a vehicle for delivering the privacy
|
||||
information about the window into the guts of nsSearchSuggestions.
|
||||
|
||||
Note that the setter is the same as the parent. We were not sure whether
|
||||
we can override just the getter. If that proves to be the case, the setter
|
||||
can be removed.
|
||||
-->
|
||||
<property name="searchParam"
|
||||
onget="return this.getAttribute('autocompletesearchparam') +
|
||||
(PrivateBrowsingUtils.isWindowPrivate(window) ? '|private' : '');"
|
||||
onset="this.setAttribute('autocompletesearchparam', val); return val;"/>
|
||||
|
||||
<!--
|
||||
This method overrides the autocomplete binding's openPopup (essentially
|
||||
duplicating the logic from the autocomplete popup binding's
|
||||
openAutocompletePopup method), modifying it so that the popup is aligned with
|
||||
the inner textbox, but sized to not extend beyond the search bar border.
|
||||
-->
|
||||
<method name="openPopup">
|
||||
<body><![CDATA[
|
||||
var popup = this.popup;
|
||||
if (!popup.mPopupOpen) {
|
||||
// Initially the panel used for the searchbar (PopupAutoComplete
|
||||
// in browser.xul) is hidden to avoid impacting startup / new
|
||||
// window performance. The base binding's openPopup would normally
|
||||
// call the overriden openAutocompletePopup in urlbarBindings.xml's
|
||||
// browser-autocomplete-result-popup binding to unhide the popup,
|
||||
// but since we're overriding openPopup we need to unhide the panel
|
||||
// ourselves.
|
||||
popup.hidden = false;
|
||||
|
||||
popup.mInput = this;
|
||||
popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
|
||||
popup.invalidate();
|
||||
|
||||
popup.showCommentColumn = this.showCommentColumn;
|
||||
popup.showImageColumn = this.showImageColumn;
|
||||
|
||||
document.popupNode = null;
|
||||
|
||||
const isRTL = getComputedStyle(this, "").direction == "rtl";
|
||||
|
||||
var outerRect = this.getBoundingClientRect();
|
||||
var innerRect = this.inputField.getBoundingClientRect();
|
||||
if (isRTL) {
|
||||
var width = innerRect.right - outerRect.left;
|
||||
} else {
|
||||
var width = outerRect.right - innerRect.left;
|
||||
}
|
||||
popup.setAttribute("width", width > 100 ? width : 100);
|
||||
|
||||
var yOffset = outerRect.bottom - innerRect.bottom;
|
||||
popup.openPopup(this.inputField, "after_start", 0, yOffset, false, false);
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="observe">
|
||||
<parameter name="aSubject"/>
|
||||
<parameter name="aTopic"/>
|
||||
<parameter name="aData"/>
|
||||
<body><![CDATA[
|
||||
if (aTopic == "nsPref:changed") {
|
||||
switch (aData) {
|
||||
case "browser.search.suggest.enabled":
|
||||
this._suggestEnabled = this._prefBranch.getBoolPref(aData);
|
||||
this._suggestMenuItem.setAttribute("checked", this._suggestEnabled);
|
||||
break;
|
||||
case "browser.urlbar.clickSelectsAll":
|
||||
this._clickSelectsAll = this._prefBranch.getBoolPref(aData);
|
||||
this.setAttribute("clickSelectsAll", this._clickSelectsAll);
|
||||
break;
|
||||
}
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<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>
|
||||
|
||||
<!-- nsIController -->
|
||||
<field name="searchbarController" readonly="true"><![CDATA[({
|
||||
_self: this,
|
||||
supportsCommand: function(aCommand) {
|
||||
return aCommand == "cmd_clearhistory" ||
|
||||
aCommand == "cmd_togglesuggest";
|
||||
},
|
||||
|
||||
isCommandEnabled: function(aCommand) {
|
||||
return true;
|
||||
},
|
||||
|
||||
doCommand: function (aCommand) {
|
||||
switch (aCommand) {
|
||||
case "cmd_clearhistory":
|
||||
var param = this._self.getAttribute("autocompletesearchparam");
|
||||
|
||||
let searchBar = this._self.parentNode;
|
||||
|
||||
BrowserSearch.searchBar.FormHistory.update({ op : "remove", fieldname : param }, null);
|
||||
this._self.value = "";
|
||||
break;
|
||||
case "cmd_togglesuggest":
|
||||
// The pref observer will update _suggestEnabled and the menu
|
||||
// checkmark.
|
||||
this._self._prefBranch.setBoolPref("browser.search.suggest.enabled",
|
||||
!this._self._suggestEnabled);
|
||||
break;
|
||||
default:
|
||||
// do nothing with unrecognized command
|
||||
}
|
||||
}
|
||||
})]]></field>
|
||||
</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();"/>
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
<handler event="keypress" keycode="VK_F4"
|
||||
phase="capturing"
|
||||
action="return this.openSearch();"/>
|
||||
#endif
|
||||
|
||||
<handler event="dragover">
|
||||
<![CDATA[
|
||||
var types = event.dataTransfer.types;
|
||||
if (types.contains("text/plain") || types.contains("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(event);
|
||||
}
|
||||
]]>
|
||||
</handler>
|
||||
|
||||
</handlers>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/* 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");
|
||||
|
||||
.searchbar-textbox {
|
||||
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar-textbox");
|
||||
}
|
||||
|
||||
.searchbar-engine-button {
|
||||
-moz-user-focus: none;
|
||||
}
|
||||
9
application/palemoon/components/search/jar.mn
Normal file
9
application/palemoon/components/search/jar.mn
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# 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/.
|
||||
|
||||
browser.jar:
|
||||
* content/browser/search/search.xml (content/search.xml)
|
||||
content/browser/search/searchbarBindings.css (content/searchbarBindings.css)
|
||||
content/browser/search/engineManager.xul (content/engineManager.xul)
|
||||
content/browser/search/engineManager.js (content/engineManager.js)
|
||||
8
application/palemoon/components/search/moz.build
Normal file
8
application/palemoon/components/search/moz.build
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
Loading…
Add table
Add a link
Reference in a new issue