Revision control

Copy as Markdown

Other Tools

<?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 % textcontextDTD SYSTEM "chrome://communicator/locale/utilityOverlay.dtd">
%textcontextDTD;
<!ENTITY % navigatorDTD SYSTEM "chrome://navigator/locale/navigator.dtd">
%navigatorDTD;
]>
<bindings id="urlbarBindings"
<content sizetopopup="pref">
<xul:hbox class="autocomplete-textbox-container" flex="1">
<xul:hbox class="urlbar-security-level" flex="1" align="center" xbl:inherits="level">
<children includes="image|deck|stack|box">
<xul:image class="autocomplete-icon" allowevents="true"/>
</children>
<xul:hbox class="textbox-input-box paste-and-go" flex="1" tooltip="_child" xbl:inherits="context">
<children/>
<html:input anonid="input" class="autocomplete-textbox textbox-input"
allowevents="true"
xbl:inherits="value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,mozactionhint,userAction"/>
<xul:tooltip anonid="tooltip"
onpopupshowing="document.getBindingParent(this)._showTooltip(event);"/>
</xul:hbox>
<children includes="hbox"/>
</xul:hbox>
</xul:hbox>
<xul:dropmarker class="autocomplete-history-dropmarker" allowevents="true"
xbl:inherits="open" anonid="historydropmarker"/>
<xul:popupset>
<xul:panel type="autocomplete" anonid="popup"
ignorekeys="true" noautofocus="true" level="top"
xbl:inherits="for=id,nomatch"/>
</xul:popupset>
<children includes="menupopup"/>
</content>
<implementation implements="nsIObserver">
<constructor><![CDATA[
this._prefs = Services.prefs.getBranch("browser.urlbar.");
this._prefs.addObserver("", this);
this.updatePref("showPopup");
this.updatePref("autoFill");
this.updatePref("showSearch");
this.updatePref("formatting.enabled");
this.inputField.controllers.insertControllerAt(0, this._editItemsController);
this.inputField.addEventListener("overflow", this);
this.inputField.addEventListener("underflow", this);
]]></constructor>
<destructor><![CDATA[
// Somehow, it's possible for the XBL destructor to fire without the
// constructor ever having fired. Fix:
if (!this._prefs) {
return;
}
this._prefs.removeObserver("", this);
this._prefs = null;
this.inputField.removeEventListener("underflow", this);
this.inputField.removeEventListener("overflow", this);
this.inputField.controllers.removeController(this._editItemsController);
]]></destructor>
<method name="observe">
<parameter name="aSubject"/>
<parameter name="aTopic"/>
<parameter name="aData"/>
<body><![CDATA[
if (aTopic == "nsPref:changed")
this.updatePref(aData);
]]></body>
</method>
<method name="updatePref">
<parameter name="aPref"/>
<body><![CDATA[
if (aPref == "showPopup") {
this.showPopup = this._prefs.getBoolPref(aPref);
} else if (aPref == "autoFill") {
this.autoFill = this._prefs.getBoolPref(aPref);
} else if (aPref == "showSearch") {
this.minResultsForPopup = this._prefs.getBoolPref(aPref) ? 0 : 1;
} else if (aPref == "formatting.enabled") {
this._formattingEnabled = this._prefs.getBoolPref(aPref);
this._formatValue(this._formattingEnabled && !this.focused);
}
]]></body>
</method>
<field name="_overflowing">false</field>
<method name="handleEvent">
<parameter name="aEvent"/>
<body><![CDATA[
switch (aEvent.type) {
case "overflow":
this._overflowing = true;
break;
case "underflow":
this._overflowing = false;
break;
}
]]></body>
</method>
<method name="_showTooltip">
<parameter name="aEvent"/>
<body><![CDATA[
var tooltip = aEvent.target;
if (this._overflowing)
tooltip.label = this.value;
else if (this.value)
tooltip.label = this.placeholder;
else
aEvent.preventDefault();
]]></body>
</method>
<field name="_formattingEnabled">true</field>
<method name="_formatValue">
<parameter name="formattingEnabled"/>
<body><![CDATA[
if (!this.editor)
return;
var controller = this.editor.selectionController;
var selection = controller.getSelection(controller.SELECTION_URLSECONDARY);
selection.removeAllRanges();
if (!formattingEnabled)
return;
var textNode = this.editor.rootElement.firstChild;
var value = textNode.textContent;
var protocol = value.match(/^[a-z\d.+\-]+:(?=[^\d])/);
if (protocol && !/^https?:|ftp:/.test(protocol[0]))
return;
var matchedURL = value.match(/^((?:[a-z]+:\/\/)?(?:[^\/]+@)?)(.+?)(?::\d+)?(?:\/|$)/);
if (!matchedURL)
return;
var [, preDomain, domain] = matchedURL;
var subDomain = "";
// getBaseDomainFromHost doesn't recognize IPv6 literals in brackets as IPs (bug 667159)
if (domain[0] != "[") {
try {
var baseDomain = Services.eTLD.getBaseDomainFromHost(domain);
if (!domain.endsWith(baseDomain)) {
// getBaseDomainFromHost converts its resultant to ACE.
let IDNService = Cc["@mozilla.org/network/idn-service;1"]
.getService(Ci.nsIIDNService);
baseDomain = IDNService.convertACEtoUTF8(baseDomain);
}
if (baseDomain != domain) {
subDomain = domain.slice(0, -baseDomain.length);
}
} catch (e) {}
}
var startLength = preDomain.length + subDomain.length;
if (startLength) {
var startRange = document.createRange();
startRange.setStart(textNode, 0);
startRange.setEnd(textNode, startLength);
selection.addRange(startRange);
}
var endLength = preDomain.length + domain.length;
if (endLength < value.length) {
var endRange = document.createRange();
endRange.setStart(textNode, endLength);
endRange.setEnd(textNode, value.length);
selection.addRange(endRange);
}
]]></body>
</method>
<method name="autoFillInput">
<parameter name="aSessionName"/>
<parameter name="aResults"/>
<parameter name="aUseFirstMatchIfNoDefault"/>
<body><![CDATA[
if (this.mInputElt.selectionEnd < this.currentSearchString.length ||
this.mDefaultMatchFilled)
return;
if (!this.mFinishAfterSearch && this.autoFill &&
this.mLastKeyCode != KeyEvent.DOM_VK_BACK_SPACE &&
this.mLastKeyCode != KeyEvent.DOM_VK_DELETE) {
var indexToUse = aResults.defaultItemIndex;
if (aUseFirstMatchIfNoDefault && indexToUse == -1)
indexToUse = 0;
if (indexToUse != -1) {
var result = this.getSessionValueAt(aSessionName, indexToUse);
var entry = this.value;
var suffix = "";
if (/^ftp:\/\/ftp\b/.test(result) &&
result.lastIndexOf("ftp://" + entry, 0) == 0)
suffix = result.slice(entry.length + 6);
else if (!/^http:\/\/ftp\b/.test(result) &&
result.lastIndexOf("http://" + entry, 0) == 0)
suffix = result.slice(entry.length + 7);
else if (result.lastIndexOf(entry, 0) == 0)
suffix = result.slice(entry.length);
if (suffix) {
this.setTextValue(this.value + suffix);
this.mInputElt.setSelectionRange(entry.length, this.value.length);
this.mDefaultMatchFilled = true;
}
this.mNeedToComplete = true;
}
}
]]></body>
</method>
<method name="_getSelectedValueForClipboard">
<body>
<![CDATA[
var inputVal = this.inputField.value;
var val = inputVal.substring(this.selectionStart, this.selectionEnd);
/* If the entire value is selected and it's a valid non-javascript,
non-data URI, encode it. */
if (val == inputVal &&
gProxyButton.getAttribute("pageproxystate") == "valid") {
var uri;
try {
uri = makeURI(val);
} catch (e) {}
if (uri && !uri.schemeIs("javascript") && !uri.schemeIs("data")) {
val = uri.displaySpec;
// Parentheses are known to confuse third-party applications (bug 458565).
val = val.replace(/[()]/g, c => escape(c));
}
}
return val;
]]>
</body>
</method>
<field name="_editItemsController"><![CDATA[
({
supportsCommand: function(aCommand) {
switch (aCommand) {
case "cmd_copy":
case "cmd_cut":
case "cmd_pasteAndGo":
return true;
}
return false;
},
isCommandEnabled: function(aCommand) {
var hasSelection = this.selectionStart < this.selectionEnd;
switch (aCommand) {
case "cmd_copy":
return hasSelection;
case "cmd_cut":
return !this.readOnly && hasSelection;
case "cmd_pasteAndGo":
return document.commandDispatcher
.getControllerForCommand("cmd_paste")
.isCommandEnabled("cmd_paste");
}
return false;
}.bind(this),
doCommand: function(aCommand) {
switch (aCommand) {
case "cmd_copy":
case "cmd_cut":
var val = this._getSelectedValueForClipboard();
var controller = this._editItemsController;
if (!val || !controller.isCommandEnabled(aCommand))
return;
Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper)
.copyString(val);
if (aCommand == "cmd_cut")
goDoCommand("cmd_delete");
break;
case "cmd_pasteAndGo":
this.select();
goDoCommand("cmd_paste");
this._fireEvent("textentered", "pasting");
break;
}
}.bind(this),
onEvent: function(aEventName) {}
})
]]></field>
</implementation>
<handlers>
<handler event="keypress"
key="&locationBar.accesskey;"
modifiers="access"
action="this.select();"/>
<handler event="ValueChange"><![CDATA[
if (this._formattingEnabled && !this.focused)
this._formatValue(true);
]]></handler>
<handler event="blur"><![CDATA[
if (this._formattingEnabled)
this._formatValue(true);
]]></handler>
<handler event="focus"><![CDATA[
this._formatValue(false);
]]></handler>
</handlers>
</binding>
<binding id="autocomplete-result-popup" extends="chrome://global/content/autocomplete.xml#autocomplete-result-popup">
<content>
<xul:tree anonid="tree" class="autocomplete-tree plain" flex="1">
<xul:treecols anonid="treecols">
<xul:treecol class="autocomplete-treecol" id="treecolAutoCompleteValue" flex="2"/>
<xul:treecol class="autocomplete-treecol" id="treecolAutoCompleteComment" flex="1" hidden="true"/>
</xul:treecols>
<xul:treechildren anonid="treebody" class="autocomplete-treebody" flex="1"/>
</xul:tree>
<xul:box role="search-box" class="autocomplete-search-box"/>
</content>
<implementation implements="nsIObserver, nsIBrowserSearchInitObserver">
<constructor><![CDATA[
// listen for changes to default search engine
Services.prefs.addObserver("browser.search", this);
Services.prefs.addObserver("browser.urlbar", this);
Services.obs.addObserver(this, "browser-search-engine-modified");
this._initialized = true;
Services.search.init(this);
]]></constructor>
<destructor><![CDATA[
Services.prefs.removeObserver("browser.search", this);
Services.prefs.removeObserver("browser.urlbar", this);
if (this._initialized) {
this._initialized = false;
Services.obs.removeObserver(this, "browser-search-engine-modified");
}
]]></destructor>
<property name="showSearch" onget="return this.mShowSearch;">
<setter><![CDATA[
this.mShowSearch = val;
if (val) {
this.updateEngines();
this.mSearchBox.removeAttribute("hidden");
} else {
this.clearEngines();
this.mSearchBox.setAttribute("hidden", "true");
}
]]></setter>
</property>
<property name="defaultSearchEngine"
onget="return this.textbox.getAttribute('defaultSearchEngine') == 'true';"
onset="this.textbox.setAttribute('defaultSearchEngine', val); return val;"/>
<field name="mSearchBox">
document.getAnonymousElementByAttribute(this, "role", "search-box");
</field>
<field name="mInputListener"><![CDATA[
(function(aEvent) {
// "this" is the textbox, not the popup
if (this.mSearchInputTO)
window.clearTimeout(this.mSearchInputTO);
this.mSearchInputTO = window.setTimeout(this.popup.mInputTimeout, this.timeout, this);
});
]]></field>
<field name="mInputTimeout"><![CDATA[
(function(me) {
me.popup.mSearchBox.searchValue = me.value;
me.mSearchInputTO = 0;
});
]]></field>
<field name="_initialized">false</field>
<field name="mEnginesReady">false</field>
<property name="overrideValue" readonly="true">
<getter><![CDATA[
if (this.mSearchBox.selectedIndex != -1) {
return this.mSearchBox.overrideValue;
}
return null;
]]></getter>
</property>
<method name="observe">
<parameter name="aSubject"/>
<parameter name="aTopic"/>
<parameter name="aData"/>
<body><![CDATA[
switch (aTopic) {
case "browser-search-engine-modified":
if (aData == "engine-current") {
this.updateEngines();
}
break;
case "nsPref:changed":
if (/^browser\.search\./.test(aData))
Services.search.init(this);
else if (aData == "browser.urlbar.showSearch")
this.updateShowSearch();
break;
default:
}
]]></body>
</method>
<method name="updateShowSearch">
<body><![CDATA[
this.showSearch = Services.prefs.getBoolPref("browser.urlbar.showSearch");
]]></body>
</method>
<method name="onInitComplete">
<parameter name="aStatus"/>
<body><![CDATA[
if (!this._initialized)
return;
if (Components.isSuccessCode(aStatus)) {
// Refresh the engines.
this.updateEngines();
} else {
Cu.reportError("Cannot initialize search service, bailing out: " + aStatus);
}
]]></body>
</method>
<method name="addEngine">
<parameter name="aName"/>
<parameter name="aIcon"/>
<parameter name="aSearchBarUrl"/>
<body><![CDATA[
var box = document.createElement("box");
box.setAttribute("class", "autocomplete-search-engine");
box.setAttribute("name", aName);
if (aIcon)
box.setAttribute("icon", aIcon.spec);
box.setAttribute("searchBarUrl", aSearchBarUrl);
box.setAttribute("engineIndex", this.childNodes.length);
this.mSearchBox.appendChild(box);
]]></body>
</method>
<method name="clearEngines">
<body><![CDATA[
while (this.mSearchBox.hasChildNodes())
this.mSearchBox.lastChild.remove();
]]></body>
</method>
<method name="updateEngines">
<body><![CDATA[
var defaultEngine = Services.search.defaultEngine;
if (defaultEngine) {
this.clearEngines();
this.addEngine(defaultEngine.name, defaultEngine.iconURI,
defaultEngine.searchForm);
}
this.mEnginesReady = true;
]]></body>
</method>
<method name="clearSelection">
<body>
this.view.selection.clearSelection();
this.mSearchBox.selectedIndex = -1;
</body>
</method>
<method name="selectBy">
<parameter name="aReverse"/>
<parameter name="aPage"/>
<body><![CDATA[
var sel;
if (this.selectedIndex == -1 && aReverse ||
this.mSearchBox.selectedIndex != -1) {
sel = this.mSearchBox.selectBy(aReverse, aPage);
if (sel != -1 || !aReverse)
return -1;
}
sel = this.getNextIndex(aReverse, aPage, this.selectedIndex, this.view.rowCount - 1);
this.selectedIndex = sel;
if (sel == -1 && !aReverse)
this.mSearchBox.selectBy(aReverse, aPage);
else if (this.mSearchBox.selectedIndex != -1)
this.mSearchBox.selectedIndex = -1;
return sel;
]]></body>
</method>
</implementation>
<handlers>
<handler event="popupshowing"><![CDATA[
// sync up with prefs about showing search in the URL bar if
// the URL bar hasn't finished initializing the default engine info
// -or-
// the search sidebar tab was displayed already triggering a change
// notification to the browser.search pref branch listener here which
// calls updateEngines but doesn't cause the ``Search for ...''
// display string to be updated
if ( (!this.mEnginesReady && this.defaultSearchEngine) ||
!("mShowSearch" in this) )
this.updateShowSearch();
if (this.mShowSearch) {
this.textbox.mSearchInputTO = 0;
this.textbox.addEventListener("input", this.mInputListener);
if ("searchValue" in this.mSearchBox)
this.mSearchBox.searchValue = this.textbox.currentSearchString;
else
this.mSearchBox.setAttribute("searchvalue", this.textbox.currentSearchString);
}
]]></handler>
<handler event="popuphiding"><![CDATA[
if (this.mShowSearch)
this.textbox.removeEventListener("input", this.mInputListener);
]]></handler>
</handlers>
</binding>
<binding id="autocomplete-search-box">
<content orient="vertical"/>
<implementation>
<constructor><![CDATA[
this.navigatorBundle = Services.strings
var text = this.getAttribute("searchvalue");
if (text)
this.searchValue = text;
]]></constructor>
<field name="mSelectedIndex">
-1
</field>
<property name="activeChild"
onget="return this.childNodes[this.mSelectedIndex]"/>
<property name="selectedIndex">
<getter>return this.mSelectedIndex;</getter>
<setter><![CDATA[
if (this.mSelectedIndex != -1)
this.activeChild.removeAttribute("menuactive");
this.mSelectedIndex = val;
if (val != -1)
this.activeChild.setAttribute("menuactive", "true");
return val;
]]></setter>
</property>
<property name="searchValue">
<getter><![CDATA[
return this.mSearchValue;
]]></getter>
<setter><![CDATA[
this.mSearchValue = val;
const kids = this.childNodes;
for (var i = 0; i < kids.length; ++i) {
kids[i].setAttribute("label",
this.navigatorBundle.formatStringFromName(
"searchFor", [kids[i].getAttribute("name"), val], 2));
}
]]></setter>
</property>
<method name="selectBy">
<parameter name="aReverse"/>
<parameter name="aPage"/>
<body><![CDATA[
return this.selectedIndex = this.parentNode.getNextIndex(aReverse, aPage, this.selectedIndex, this.childNodes.length - 1);
]]></body>
</method>
<property name="overrideValue" readonly="true">
<getter><![CDATA[
var item = this.activeChild;
if (item) {
// XXXsearch: using default engine for now, this ignores the following values:
// item.getAttribute("searchEngine") and item.getAttribute("searchBarUrl")
var engine = Services.search.defaultEngine;
var submission = engine.getSubmission(this.mSearchValue); // HTML response
// getSubmission can return null if the engine doesn't have a URL
// with a text/html response type. This is unlikely (since
// SearchService._addEngineToStore() should fail for such an engine),
// but let's be on the safe side.
if (!submission)
return null;
// XXXsearch: the submission object may have postData but .overrideValue can't deal with that
// we need to figure out what to do with that case here
return submission.uri.spec;
}
return null;
]]></getter>
</property>
</implementation>
<handlers>
<handler event="mouseup">
this.parentNode.textbox.onResultClick();
</handler>
</handlers>
</binding>
<binding id="autocomplete-search-engine">
<content>
<xul:image class="autocomplete-search-engine-img" xbl:inherits="src=icon"/>
<xul:label class="autocomplete-search-engine-text" xbl:inherits="value=label" crop="right" flex="1"/>
</content>
<handlers>
<handler event="mousemove">
this.parentNode.selectedIndex = Number(this.getAttribute("engineIndex"));
</handler>
<handler event="mouseout">
this.parentNode.selectedIndex = -1;
</handler>
</handlers>
</binding>
<binding id="input-box-paste" 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="&copyCmd.label;" accesskey="&copyCmd.accesskey;" cmd="cmd_copy"/>
<xul:menuitem label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;" cmd="cmd_paste"/>
<xul:menuitem label="&pasteGoCmd.label;" accesskey="&pasteGoCmd.accesskey;" cmd="cmd_pasteAndGo"/>
<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:menupopup>
</content>
</binding>
</bindings>