mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
779 lines
27 KiB
XML
779 lines
27 KiB
XML
<?xml version="1.0"?>
|
|
|
|
# -*- Mode: HTML -*-
|
|
# ***** BEGIN LICENSE BLOCK *****
|
|
# The contents of this file are subject to the Mozilla Public
|
|
# License Version 1.1 (the "License"); you may not use this file
|
|
# except in compliance with the License. You may obtain a copy of
|
|
# the License at http://www.mozilla.org/MPL/
|
|
#
|
|
# Software distributed under the License is distributed on an "AS
|
|
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
# implied. See the License for the specific language governing
|
|
# rights and limitations under the License.
|
|
#
|
|
# The Original Code is mozilla.org browser.
|
|
#
|
|
# The Initial Developer of the Original Code is Joe Hewitt.
|
|
# Portions created by the Initial Developer are
|
|
# Copyright (C) 2003 the Initial Developer. All
|
|
# Rights Reserved.
|
|
#
|
|
# Contributor(s):
|
|
# Pierre Chanial (p_ch@verizon.net)
|
|
# Dean Tessman (dean_tessman@hotmail.com)
|
|
#
|
|
# Alternatively, the contents of this file may be used under the
|
|
# terms of the GNU General Public License Version 2 or later (the
|
|
# "GPL"), in which case the provisions of the GPL are applicable
|
|
# instead of those above. If you wish to allow use of your
|
|
# version of this file only under the terms of the GPL and not to
|
|
# allow others to use your version of this file under the MPL,
|
|
# indicate your decision by deleting the provisions above and
|
|
# replace them with the notice and other provisions required by
|
|
# the GPL. If you do not delete the provisions above, a recipient
|
|
# may use your version of this file under either the MPL or the
|
|
# GPL.
|
|
#
|
|
# ***** END LICENSE BLOCK *****
|
|
|
|
<bindings id="autocompleteBindings"
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
|
|
|
<binding id="autocomplete"
|
|
extends="chrome://global/content/bindings/textbox.xml#textbox">
|
|
<resources>
|
|
<stylesheet src="chrome://global/skin/autocomplete.css"/>
|
|
</resources>
|
|
|
|
<content sizetopopup="pref">
|
|
<xul:hbox class="autocomplete-textbox-container" flex="1">
|
|
<children includes="image|deck">
|
|
<xul:image class="autocomplete-icon" allowevents="true"/>
|
|
</children>
|
|
|
|
<xul:hbox class="textbox-input-box" flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
|
|
<children/>
|
|
<html:input anonid="input" class="autocomplete-textbox textbox-input"
|
|
flex="1" allowevents="true"
|
|
xbl:inherits="tooltiptext=inputtooltiptext,onfocus,onblur,value,type,maxlength,disabled,size,readonly,userAction"/>
|
|
</xul:hbox>
|
|
<xul:image class="info-icon" xbl:inherits="src=infoicon,tooltiptext=infotext"/>
|
|
</xul:hbox>
|
|
|
|
<xul:dropmarker anonid="historydropmarker" class="autocomplete-history-dropmarker"
|
|
allowevents="true"
|
|
xbl:inherits="open,enablehistory"/>
|
|
|
|
<xul:popupset anonid="popupset" class="autocomplete-result-popupset"/>
|
|
</content>
|
|
|
|
<implementation implements="nsIAccessibleProvider, nsIAutoCompleteInput, nsIDOMXULMenuListElement">
|
|
<field name="mController">null</field>
|
|
<field name="mSearchNames">null</field>
|
|
<field name="mIgnoreInput">false</field>
|
|
<field name="mEnterEvent">null</field>
|
|
|
|
<field name="mInputElt">
|
|
document.getAnonymousElementByAttribute(this, "anonid", "input");
|
|
</field>
|
|
|
|
<constructor><![CDATA[
|
|
// set default property values
|
|
this.ifSetAttribute("disablehistory", true);
|
|
|
|
mController = Components.classes["@mozilla.org/autocomplete/controller;1"].
|
|
createInstance(Components.interfaces.nsIAutoCompleteController);
|
|
]]></constructor>
|
|
|
|
<!-- =================== nsIAccessibleProvider =================== -->
|
|
|
|
<property name="accessible">
|
|
<getter>
|
|
<![CDATA[
|
|
var accService = Components.classes["@mozilla.org/accessibilityService;1"].
|
|
getService(Components.interfaces.nsIAccessibilityService);
|
|
return accService.createXULComboboxAccessible(this);
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- =================== nsIAutoCompleteInput =================== -->
|
|
|
|
<field name="popup"><![CDATA[
|
|
var popup = null;
|
|
var popupId = this.getAttribute("autocompletepopup");
|
|
if (popupId)
|
|
popup = document.getElementById(popupId);
|
|
if (!popup) {
|
|
popup = document.createElement("popup");
|
|
popup.setAttribute("type", "autocomplete");
|
|
popup.setAttribute("hidden", "true");
|
|
|
|
var popupset = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
|
|
popupset.appendChild(popup);
|
|
}
|
|
popup.mInput = this;
|
|
popup;
|
|
]]></field>
|
|
|
|
<property name="controller" onget="return this.mController;" readonly="true"/>
|
|
|
|
<property name="popupOpen"
|
|
onget="return this.popup.popupOpen;"
|
|
onset="if (val) this.openPopup(); else this.closePopup();"/>
|
|
|
|
<property name="disableAutoComplete"
|
|
onset="this.setAttribute('disableautocomplete', val); return val;"
|
|
onget="return this.getAttribute('disableautocomplete') == 'true';"/>
|
|
|
|
<property name="completeDefaultIndex"
|
|
onset="this.setAttribute('completedefaultindex', val); return val;"
|
|
onget="return this.getAttribute('completedefaultindex') == 'true';"/>
|
|
|
|
<property name="forceComplete"
|
|
onset="this.setAttribute('forcecomplete', val); return val;"
|
|
onget="return this.getAttribute('forcecomplete') == 'true';"/>
|
|
|
|
<property name="minResultsForPopup"
|
|
onset="this.setAttribute('minresultsforpopup', val); return val;"
|
|
onget="return parseInt(this.getAttribute('minresultsforpopup')) || 0;"/>
|
|
|
|
<property name="showCommentColumn"
|
|
onset="this.setAttribute('showcommentcolumn', val); return val;"
|
|
onget="return this.getAttribute('showcommentcolumn') == 'true';"/>
|
|
|
|
<property name="timeout"
|
|
onset="this.setAttribute('timeout', val); return val;"
|
|
onget="return parseInt(this.getAttribute('timeout')) || 50;"/>
|
|
|
|
<property name="searchParam"
|
|
onget="return this.getAttribute('autocompletesearchparam');"
|
|
onset="this.setAttribute('autocompletesearchparam', val); return val;"/>
|
|
|
|
<property name="searchCount" readonly="true"
|
|
onget="this.initSearchNames(); return this.mSearchNames.length;"/>
|
|
|
|
<method name="getSearchAt">
|
|
<parameter name="aIndex"/>
|
|
<body><![CDATA[
|
|
this.initSearchNames();
|
|
return this.mSearchNames[aIndex];
|
|
]]></body>
|
|
</method>
|
|
|
|
<property name="textValue"
|
|
onget="return this.value;"
|
|
onset="return this.value = val;"/>
|
|
|
|
<property name="selectionStart"
|
|
onget="return this.mInputElt.selectionStart;"/>
|
|
|
|
<property name="selectionEnd"
|
|
onget="return this.mInputElt.selectionEnd;"/>
|
|
|
|
<method name="selectTextRange">
|
|
<parameter name="aStartIndex"/>
|
|
<parameter name="aEndIndex"/>
|
|
<body><![CDATA[
|
|
this.mInputElt.setSelectionRange(aStartIndex, aEndIndex);
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="onSearchComplete">
|
|
<body><![CDATA[
|
|
if (this.mController.matchCount == 0)
|
|
this.popup.setAttribute("nomatch", "true");
|
|
else
|
|
this.popup.removeAttribute("nomatch");
|
|
|
|
this.fireEvent("searchcomplete");
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="onTextEntered">
|
|
<body><![CDATA[
|
|
var rv = this.fireEvent("textentered", this.mEnterEvent);
|
|
this.mEnterEvent = null;
|
|
return rv;
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="onTextReverted">
|
|
<body><![CDATA[
|
|
return this.fireEvent("textreverted");
|
|
]]></body>
|
|
</method>
|
|
|
|
<!-- =================== nsIDOMXULMenuListElement =================== -->
|
|
|
|
<property name="editable" readonly="true"
|
|
onget="return true;" />
|
|
|
|
<property name="crop"
|
|
onset="this.setAttribute('crop',val); return val;"
|
|
onget="return this.getAttribute('crop');"/>
|
|
|
|
<property name="label"
|
|
onset="this.setAttribute('label',val); return val;"
|
|
onget="return this.getAttribute('label');"/>
|
|
|
|
<property name="open"
|
|
onget="return this.getAttribute('open') == 'true';">
|
|
<setter><![CDATA[
|
|
if (val) {
|
|
this.setAttribute("open", "true");
|
|
this.showHistoryPopup();
|
|
}
|
|
else {
|
|
this.removeAttribute("open");
|
|
this.closePopup();
|
|
}
|
|
]]></setter>
|
|
</property>
|
|
|
|
<!-- =================== PUBLIC MEMBERS =================== -->
|
|
|
|
<property name="value"
|
|
onget="return this.mInputElt.value;">
|
|
<setter><![CDATA[
|
|
this.mIgnoreInput = true;
|
|
this.mInputElt.value = val;
|
|
this.mIgnoreInput = false;
|
|
var event = document.createEvent('Events');
|
|
event.initEvent('ValueChange', true, true);
|
|
this.mInputElt.dispatchEvent(event);
|
|
return val;
|
|
]]></setter>
|
|
</property>
|
|
|
|
<property name="focused" readonly="true"
|
|
onget="return this.getAttribute('focused') == 'true';"/>
|
|
|
|
<!-- maximum number of rows to display at a time -->
|
|
<property name="maxRows"
|
|
onset="this.setAttribute('maxrows', val); return val;"
|
|
onget="return parseInt(this.getAttribute('maxrows')) || 0;"/>
|
|
|
|
<!-- option to allow scrolling through the list via the tab key, rather than
|
|
tab moving focus out of the textbox -->
|
|
<property name="tabScrolling"
|
|
onset="return this.setAttribute('tabscrolling', val); return val;"
|
|
onget="return this.getAttribute('tabscrolling') == 'true';"/>
|
|
|
|
<!-- disable key navigation handling in the popup results -->
|
|
<property name="disableKeyNavigation"
|
|
onset="this.setAttribute('disablekeynavigation', val); return val;"
|
|
onget="return this.getAttribute('disablekeynavigation') == 'true';"/>
|
|
|
|
<!-- option to completely ignore any blur events while
|
|
searches are still going on. This is useful so that nothing
|
|
gets autopicked if the window is required to lose focus for
|
|
some reason (eg in LDAP autocomplete, another window may be
|
|
brought up so that the user can enter a password to authenticate
|
|
to an LDAP server). -->
|
|
<property name="ignoreBlurWhileSearching"
|
|
onset="this.setAttribute('ignoreblurwhilesearching', val); return val;"
|
|
onget="return this.getAttribute('ignoreblurwhilesearching') == 'true';"/>
|
|
|
|
<!-- =================== PRIVATE MEMBERS =================== -->
|
|
|
|
<!-- ::::::::::::: autocomplete controller ::::::::::::: -->
|
|
|
|
<method name="attachController">
|
|
<body><![CDATA[
|
|
if (this.mController.input != this)
|
|
this.mController.input = this;
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="detachController">
|
|
<body><![CDATA[
|
|
if (this.mController.input == this)
|
|
this.mController.input = null;
|
|
]]></body>
|
|
</method>
|
|
|
|
<!-- ::::::::::::: popup opening ::::::::::::: -->
|
|
|
|
<method name="openPopup">
|
|
<body><![CDATA[
|
|
this.popup.openPopup(this, this.boxObject.screenX, this.boxObject.screenY+this.boxObject.height, this.boxObject.width);
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="closePopup">
|
|
<body><![CDATA[
|
|
this.popup.closePopup();
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="showHistoryPopup">
|
|
<body><![CDATA[
|
|
this.maxRows = 14;
|
|
this.attachController();
|
|
this.mController.startSearch("");
|
|
]]></body>
|
|
</method>
|
|
|
|
<!-- ::::::::::::: event dispatching ::::::::::::: -->
|
|
|
|
<method name="fireEvent">
|
|
<parameter name="aEventType"/>
|
|
<body><![CDATA[
|
|
var cancel = false;
|
|
// handle any xml attribute event handlers
|
|
var handler = this.getAttribute("on"+aEventType);
|
|
if (handler) {
|
|
var fn = new Function("eventType", "param", handler);
|
|
cancel = fn.apply(this, arguments);
|
|
}
|
|
|
|
return cancel;
|
|
]]></body>
|
|
</method>
|
|
|
|
<!-- ::::::::::::: key handling ::::::::::::: -->
|
|
|
|
<method name="onKeyPress">
|
|
<parameter name="aEvent"/>
|
|
<body><![CDATA[
|
|
//XXXpch this is so bogus...
|
|
if (aEvent.getPreventDefault())
|
|
return false;
|
|
|
|
var cancel = false;
|
|
const IController = Components.interfaces.nsIAutoCompleteController;
|
|
|
|
if (!this.disableKeyNavigation && !aEvent.ctrlKey && !aEvent.altKey) {
|
|
switch (aEvent.keyCode) {
|
|
case KeyEvent.DOM_VK_TAB:
|
|
if (this.tabScrolling && this.popup.mPopupOpen)
|
|
cancel = this.mController.handleKeyNavigation(aEvent.shiftKey ? IController.KEY_UP : IController.KEY_DOWN);
|
|
break;
|
|
case KeyEvent.DOM_VK_UP:
|
|
cancel = this.mController.handleKeyNavigation(IController.KEY_UP);
|
|
break;
|
|
case KeyEvent.DOM_VK_DOWN:
|
|
cancel = this.mController.handleKeyNavigation(IController.KEY_DOWN);
|
|
break;
|
|
case KeyEvent.DOM_VK_LEFT:
|
|
cancel = this.mController.handleKeyNavigation(IController.KEY_LEFT);
|
|
break;
|
|
case KeyEvent.DOM_VK_RIGHT:
|
|
cancel = this.mController.handleKeyNavigation(IController.KEY_RIGHT);
|
|
break;
|
|
case KeyEvent.DOM_VK_PAGE_UP:
|
|
cancel = this.mController.handleKeyNavigation(IController.KEY_PAGE_UP);
|
|
break;
|
|
case KeyEvent.DOM_VK_PAGE_DOWN:
|
|
cancel = this.mController.handleKeyNavigation(IController.KEY_PAGE_DOWN);
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (aEvent.keyCode) {
|
|
case KeyEvent.DOM_VK_ESCAPE:
|
|
cancel = this.mController.handleEscape();
|
|
break;
|
|
case KeyEvent.DOM_VK_RETURN:
|
|
this.mEnterEvent = aEvent;
|
|
cancel = this.mController.handleEnter();
|
|
break;
|
|
case KeyEvent.DOM_VK_DELETE:
|
|
if (aEvent.shiftKey)
|
|
cancel = this.mController.handleDelete();
|
|
break;
|
|
}
|
|
|
|
if (cancel) {
|
|
aEvent.stopPropagation();
|
|
aEvent.preventDefault();
|
|
}
|
|
|
|
return true;
|
|
]]></body>
|
|
</method>
|
|
|
|
<!-- ::::::::::::: miscellaneous ::::::::::::: -->
|
|
|
|
<method name="initSearchNames">
|
|
<body><![CDATA[
|
|
if (!this.mSearchNames) {
|
|
var names = this.getAttribute("autocompletesearch");
|
|
if (!names)
|
|
this.mSearchNames = [];
|
|
else
|
|
this.mSearchNames = names.split(" ");
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="ifSetAttribute">
|
|
<parameter name="aAttr"/>
|
|
<parameter name="aVal"/>
|
|
<body><![CDATA[
|
|
if (!this.hasAttribute(aAttr))
|
|
this.setAttribute(aAttr, aVal);
|
|
]]></body>
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="input"
|
|
action="if (!this.mIgnoreInput) this.mController.handleText(false);"/>
|
|
|
|
<handler event="keypress" phase="capturing"
|
|
action="return this.onKeyPress(event);"/>
|
|
|
|
<handler event="focus" phase="capturing"
|
|
action="this.attachController();"/>
|
|
|
|
<handler event="blur" phase="capturing"
|
|
action="this.detachController();"/>
|
|
|
|
<handler event="dblclick">
|
|
<![CDATA[
|
|
if (event.originalTarget.className == "info-icon" && event.button == 0)
|
|
return this.fireEvent("infoclick");
|
|
return true;
|
|
]]>
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="autocomplete-result-popup" extends="chrome://global/content/bindings/popup.xml#popup">
|
|
<resources>
|
|
<stylesheet src="chrome://global/skin/tree.css"/>
|
|
<stylesheet src="chrome://global/skin/autocomplete.css"/>
|
|
</resources>
|
|
|
|
<content>
|
|
<xul:tree anonid="tree" class="autocomplete-tree plain" hidecolumnpicker="true" flex="1">
|
|
<xul:treecols anonid="treecols">
|
|
<xul:treecol id="treecolAutoCompleteValue" class="autocomplete-treecol" flex="1"/>
|
|
</xul:treecols>
|
|
<xul:treechildren class="autocomplete-treebody"/>
|
|
</xul:tree>
|
|
</content>
|
|
|
|
<implementation implements="nsIAutoCompletePopup">
|
|
<field name="mInput">null</field>
|
|
<field name="mPopupOpen">false</field>
|
|
<field name="mShowCommentCol">false</field>
|
|
|
|
<constructor><![CDATA[
|
|
this.setAttribute("ignorekeys", "true");
|
|
]]></constructor>
|
|
|
|
<!-- =================== nsIAutoCompletePopup =================== -->
|
|
|
|
<property name="input"
|
|
onget="return this.mInput"/>
|
|
|
|
<property name="overrideValue" readonly="true"
|
|
onget="return null;"/>
|
|
|
|
<property name="selectedIndex"
|
|
onget="return this.tree.currentIndex;">
|
|
<setter><![CDATA[
|
|
this.tree.view.selection.select(val);
|
|
if (this.tree.treeBoxObject.height > 0)
|
|
this.tree.treeBoxObject.ensureRowIsVisible(val < 0 ? 0 : val);
|
|
// Fire select event on xul:tree so that accessibility API
|
|
// support layer can fire appropriate accessibility events.
|
|
var event = document.createEvent('Events');
|
|
event.initEvent("select", true, true);
|
|
this.tree.dispatchEvent(event);
|
|
return val;
|
|
]]></setter>
|
|
</property>
|
|
|
|
<property name="popupOpen" readonly="true"
|
|
onget="return this.mPopupOpen;"/>
|
|
|
|
<method name="openPopup">
|
|
<parameter name="aInput"/>
|
|
<parameter name="aX"/>
|
|
<parameter name="aY"/>
|
|
<parameter name="aWidth"/>
|
|
<body><![CDATA[
|
|
if (!this.mPopupOpen) {
|
|
this.mInput = aInput;
|
|
this.view = aInput.controller.QueryInterface(Components.interfaces.nsITreeView);
|
|
this.invalidate();
|
|
|
|
this.showCommentColumn = this.mInput.showCommentColumn;
|
|
|
|
this.removeAttribute("hidden");
|
|
this.setAttribute("width", aWidth < 100 ? 100 : aWidth);
|
|
|
|
document.popupNode = null;
|
|
this.showPopup(document.documentElement, aX, aY, "popup", null, null);
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="closePopup">
|
|
<body><![CDATA[
|
|
if (this.mPopupOpen) {
|
|
this.hidePopup();
|
|
document.popupNode = null;
|
|
|
|
this.setAttribute("hidden", "true");
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="invalidate">
|
|
<body><![CDATA[
|
|
this.adjustHeight();
|
|
this.tree.treeBoxObject.invalidate();
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="selectBy">
|
|
<parameter name="aReverse"/>
|
|
<parameter name="aPage"/>
|
|
<body><![CDATA[
|
|
try {
|
|
var amount = aPage ? 5 : 1;
|
|
this.selectedIndex = this.getNextIndex(aReverse, amount, this.selectedIndex, this.tree.view.rowCount-1);
|
|
} catch (ex) {
|
|
// do nothing - occasionally timer-related js errors happen here
|
|
// e.g. "this.selectedIndex has no properties", when you type fast and hit a
|
|
// navigation key before this popup has opened
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<!-- =================== PUBLIC MEMBERS =================== -->
|
|
|
|
<field name="tree">
|
|
document.getAnonymousElementByAttribute(this, "anonid", "tree");
|
|
</field>
|
|
|
|
<field name="treecols">
|
|
document.getAnonymousElementByAttribute(this, "anonid", "treecols");
|
|
</field>
|
|
|
|
<property name="view"
|
|
onget="return this.mView;">
|
|
<setter><![CDATA[
|
|
// We must do this by hand because the tree binding may not be ready yet
|
|
this.mView = val;
|
|
var bx = this.tree.boxObject;
|
|
bx = bx.QueryInterface(Components.interfaces.nsITreeBoxObject);
|
|
bx.view = val;
|
|
]]></setter>
|
|
</property>
|
|
|
|
<property name="maxRows" readonly="true">
|
|
<getter><![CDATA[
|
|
return (this.mInput && this.mInput.maxRows) || 6;
|
|
]]></getter>
|
|
</property>
|
|
|
|
<property name="showCommentColumn"
|
|
onget="return this.mShowCommentColumn;">
|
|
<setter><![CDATA[
|
|
if (!val && this.mShowCommentColumn) {
|
|
// reset the flex on the value column and add the comment column
|
|
document.getElementById("treecolAutoCompleteValue").setAttribute("flex", 1);
|
|
this.removeColumn("treecolAutoCompleteComment");
|
|
} else if (val && !this.mShowCommentColumn) {
|
|
// reset the flex on the value column and add the comment column
|
|
document.getElementById("treecolAutoCompleteValue").setAttribute("flex", 2);
|
|
this.addColumn({id: "treecolAutoCompleteComment", flex: 1});
|
|
}
|
|
this.mShowCommentColumn = val;
|
|
return val;
|
|
]]></setter>
|
|
</property>
|
|
|
|
<method name="addColumn">
|
|
<parameter name="aAttrs"/>
|
|
<body><![CDATA[
|
|
var col = document.createElement("treecol");
|
|
col.setAttribute("class", "autocomplete-treecol");
|
|
for (var name in aAttrs)
|
|
col.setAttribute(name, aAttrs[name]);
|
|
this.treecols.appendChild(col);
|
|
return col;
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="removeColumn">
|
|
<parameter name="aColId"/>
|
|
<body><![CDATA[
|
|
return this.treecols.removeChild(document.getElementById(aColId));
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="adjustHeight">
|
|
<body><![CDATA[
|
|
// detect the desired height of the tree
|
|
var bx = this.tree.treeBoxObject;
|
|
var view = this.tree.view;
|
|
var rows = this.maxRows;
|
|
if (!view.rowCount || (rows && view.rowCount < rows))
|
|
rows = view.rowCount;
|
|
|
|
var height = rows * bx.rowHeight;
|
|
|
|
if (height == 0)
|
|
this.tree.setAttribute("collapsed", "true");
|
|
else {
|
|
if (this.tree.hasAttribute("collapsed"))
|
|
this.tree.removeAttribute("collapsed");
|
|
|
|
this.tree.setAttribute("height", height);
|
|
}
|
|
this.tree.setAttribute("hidescrollbar", view.rowCount <= rows);
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="getNextIndex">
|
|
<parameter name="aReverse"/>
|
|
<parameter name="aAmount"/>
|
|
<parameter name="aIndex"/>
|
|
<parameter name="aMaxRow"/>
|
|
<body><![CDATA[
|
|
if (aMaxRow < 0)
|
|
return -1;
|
|
|
|
var newIdx = aIndex + (aReverse?-1:1)*aAmount;
|
|
if (aReverse && aIndex == -1 || newIdx > aMaxRow && aIndex != aMaxRow)
|
|
newIdx = aMaxRow;
|
|
else if (!aReverse && aIndex == -1 || newIdx < 0 && aIndex != 0)
|
|
newIdx = 0;
|
|
|
|
if (newIdx < 0 && aIndex == 0 || newIdx > aMaxRow && aIndex == aMaxRow)
|
|
aIndex = -1;
|
|
else
|
|
aIndex = newIdx;
|
|
|
|
return aIndex;
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="onPopupClick">
|
|
<parameter name="aEvent"/>
|
|
<body><![CDATA[
|
|
var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
|
|
controller.handleEnter();
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="clearOpenProperty">
|
|
<parameter name="aPopupNode"/>
|
|
<body><![CDATA[
|
|
aPopupNode.mPopupOpen = false;
|
|
]]></body>
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="popupshowing">
|
|
this.mPopupOpen = true;
|
|
</handler>
|
|
|
|
<handler event="popuphiding">
|
|
setTimeout(this.clearOpenProperty, 0, this);
|
|
this.mInput.maxRows = 6;
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="autocomplete-tree" extends="chrome://global/content/bindings/tree.xml#tree">
|
|
<content>
|
|
<children includes="treecols"/>
|
|
<xul:treerows class="autocomplete-treerows tree-rows" xbl:inherits="hidescrollbar" flex="1">
|
|
<children/>
|
|
</xul:treerows>
|
|
</content>
|
|
</binding>
|
|
|
|
<binding id="autocomplete-treebody">
|
|
<implementation>
|
|
<field name="mLastMoveTime">new Date()</field>
|
|
|
|
<method name="getHoverCell">
|
|
<parameter name="aEvent"/>
|
|
<body><![CDATA[
|
|
var row = {}; var col = {}; var obj = {};
|
|
var x = aEvent.screenX - this.boxObject.screenX + this.boxObject.x;
|
|
var y = aEvent.screenY - this.boxObject.screenY + this.boxObject.y;
|
|
this.parentNode.treeBoxObject.getCellAt(x, y, row, col, obj);
|
|
if (row.value >= 0)
|
|
return {row: row.value, column: col.value.id};
|
|
else
|
|
return null;
|
|
]]></body>
|
|
</method>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="mouseout" action="this.parentNode.currentIndex = -1;"/>
|
|
<handler event="mouseup" action="this.parentNode.parentNode.onPopupClick(event);"/>
|
|
|
|
<handler event="mousemove"><![CDATA[
|
|
if (new Date() - this.mLastMoveTime > 30) {
|
|
var rc = this.getHoverCell(event);
|
|
if (rc && rc.row != this.parentNode.currentIndex)
|
|
this.parentNode.view.selection.select(rc.row);
|
|
this.mLastMoveTime = new Date();
|
|
}
|
|
]]></handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="autocomplete-treerows">
|
|
<content onmousedown="event.preventDefault()">
|
|
<xul:hbox flex="1" class="tree-bodybox">
|
|
<children/>
|
|
</xul:hbox>
|
|
<xul:scrollbar xbl:inherits="collapsed=hidescrollbar" orient="vertical" class="tree-scrollbar"/>
|
|
</content>
|
|
</binding>
|
|
|
|
<binding id="history-dropmarker" extends="xul:button">
|
|
<content>
|
|
<xul:image class="dropmarker-image"/>
|
|
</content>
|
|
|
|
<implementation implements="nsIAccessibleProvider">
|
|
<property name="accessible">
|
|
<getter>
|
|
<![CDATA[
|
|
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
|
|
return accService.createXULDropmarkerAccessible(this);
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
|
|
<method name="showPopup">
|
|
<body><![CDATA[
|
|
var textbox = document.getBindingParent(this);
|
|
if (!textbox.popup.mPopupOpen) {
|
|
textbox.showHistoryPopup();
|
|
}
|
|
]]></body>
|
|
</method>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="mousedown" button="0"><![CDATA[
|
|
this.showPopup();
|
|
]]></handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
</bindings>
|
|
|