Files
Mozilla/mozilla/toolkit/content/widgets/menulist.xml
bzbarsky%mit.edu 16f1f02320 Make getElementsByAttribute be an nsContentList so that it's got that live
DOMNodeList goodness that all nodelists should have.  Change some JS to not
break, and some other JS to be a little more efficient with the new world of
lazy listness.  Bug 240186, r=neil on the JS changes, r=jst on the content
changes, sr=jst


git-svn-id: svn://10.0.0.236/trunk@154907 18797224-902f-48f8-a5cc-f745e15eee43
2004-04-15 01:51:32 +00:00

454 lines
15 KiB
XML

<?xml version="1.0"?>
<bindings id="menulistBindings"
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="menulist-base">
<resources>
<stylesheet src="chrome://global/skin/menulist.css"/>
</resources>
</binding>
<binding id="menulist" display="xul:menu"
extends="chrome://global/content/bindings/menulist.xml#menulist-base">
<content sizetopopup="pref">
<xul:hbox class="menulist-label-box" flex="1">
<xul:image class="menulist-icon" xbl:inherits="src"/>
<xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
</xul:hbox>
<xul:dropmarker class="menulist-dropmarker" type="menu"/>
<children includes="menupopup"/>
</content>
<handlers>
<handler event="command" phase="capturing">
<![CDATA[
// XXX see bug #196755
// originalTarget is workaround for arrowscrollbox retargeting bug
if (event.originalTarget.parentNode.parentNode == this)
this.selectedItem = event.originalTarget;
]]>
</handler>
<handler event="popupshowing">
<![CDATA[
// XXX see bug #196755
// originalTarget is workaround for arrowscrollbox retargeting bug
if (event.originalTarget.parentNode == this && this.selectedItem)
// Not ready for auto-setting the active child in hierarchies yet.
// For now, only do this when the outermost menupopup opens.
this.menuBoxObject.activeChild = this.selectedInternal;
]]>
</handler>
</handlers>
<implementation implements="nsIDOMXULMenuListElement, nsIAccessibleProvider">
<constructor>
this.setInitialSelection()
</constructor>
<method name="setInitialSelection">
<body>
<![CDATA[
var popup = this.menupopup;
if (popup) {
var arr = popup.getElementsByAttribute('selected', 'true');
if (!arr.item(0) && this.value)
arr = popup.getElementsByAttribute('value', this.value);
if (arr.item(0))
this.selectedItem = arr[0];
else
this.selectedIndex = 0;
}
]]>
</body>
</method>
<property name="value" onget="return this.getAttribute('value');">
<setter>
<![CDATA[
var arr = null;
var popup = this.menupopup;
if (popup)
arr = popup.getElementsByAttribute('value', val);
if (arr && arr.item(0))
this.selectedItem = arr[0];
else
this.setAttribute('value', val);
return val;
]]>
</setter>
</property>
<property name="crop" onset="this.setAttribute('crop',val); return val;"
onget="return this.getAttribute('crop');"/>
<property name="src" onset="this.setAttribute('src',val); return val;"
onget="return this.getAttribute('src');"/>
<property name="label" onset="this.setAttribute('label',val); return val;"
onget="return this.getAttribute('label');"/>
<property name="disabled" onset="if (val) this.setAttribute('disabled',true);
else this.removeAttribute('disabled');
return val;"
onget="return this.hasAttribute('disabled');"/>
<property name="open" onset="this.menuBoxObject.openMenu(val);
return val;"
onget="return this.hasAttribute('open');"/>
<property name="menupopup" readonly="true">
<getter>
<![CDATA[
var popup = this.firstChild;
while (popup && popup.localName != "menupopup")
popup = popup.nextSibling;
return popup;
]]>
</getter>
</property>
<field name="menuBoxObject" readonly="true">
this.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject)
</field>
<field name="selectedInternal">
null
</field>
<property name="selectedIndex">
<getter>
<![CDATA[
// Quick and dirty. We won't deal with hierarchical menulists yet.
if (!this.selectedItem ||
!this.selectedInternal.parentNode ||
this.selectedInternal.parentNode.parentNode != this)
return -1;
var children = this.selectedInternal.parentNode.childNodes;
var i = children.length;
while (i--)
if (children[i] == this.selectedInternal)
break;
return i;
]]>
</getter>
<setter>
<![CDATA[
var popup = this.menupopup;
if (popup && 0 <= val && val < popup.childNodes.length)
this.selectedItem = popup.childNodes[val];
else
this.selectedItem = null;
return val;
]]>
</setter>
</property>
<property name="selectedItem">
<getter>
<![CDATA[
return this.selectedInternal;
]]>
</getter>
<setter>
<![CDATA[
if (this.selectedInternal == val)
return val;
if (this.selectedInternal)
this.selectedInternal.removeAttribute('selected');
this.selectedInternal = val;
if (!this.selectedInternal) {
this.removeAttribute('value');
this.removeAttribute('src');
this.removeAttribute('label');
return val;
}
val.setAttribute('selected', 'true');
this.setAttribute('value', val.getAttribute('value'));
this.setAttribute('src', val.getAttribute('src'));
this.setAttribute('label', val.getAttribute('label'));
return val;
]]>
</setter>
</property>
<method name="appendItem">
<parameter name="label"/>
<parameter name="value"/>
<body>
<![CDATA[
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var popup = this.menupopup ||
this.appendChild(document.createElementNS(XULNS, "menupopup"));
var item = document.createElementNS(XULNS, "menuitem");
item.setAttribute("label", label);
item.setAttribute("value", value);
popup.appendChild(item);
return item;
]]>
</body>
</method>
<method name="insertItemAt">
<parameter name="index"/>
<parameter name="label"/>
<parameter name="value"/>
<body>
<![CDATA[
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var popup = this.menupopup ||
this.appendChild(document.createElementNS(XULNS, "menupopup"));
var item = document.createElementNS(XULNS, "menuitem");
item.setAttribute("label", label);
item.setAttribute("value", value);
if (index < popup.childNodes.length)
popup.insertBefore(item, popup.childNodes[index]);
else
popup.appendChild(item);
return item;
]]>
</body>
</method>
<method name="removeItemAt">
<parameter name="index"/>
<body>
<![CDATA[
var popup = this.menupopup;
if (popup && 0 <= index && index < popup.childNodes.length) {
var remove = popup.childNodes[index];
popup.removeChild(remove);
return remove;
}
return null;
]]>
</body>
</method>
<method name="removeAllItems">
<body>
<![CDATA[
this.selectedInternal = null;
var popup = this.menupopup;
if (popup)
this.removeChild(popup);
]]>
</body>
</method>
<property name="accessible">
<getter>
<![CDATA[
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
return accService.createXULComboboxAccessible(this);
]]>
</getter>
</property>
</implementation>
</binding>
<binding id="menulist-editable" extends="chrome://global/content/bindings/menulist.xml#menulist">
<content sizetopopup="pref">
<xul:hbox class="menulist-editable-box textbox-input-box" xbl:inherits="context" flex="1">
<html:input class="menulist-editable-input" flex="1" anonid="input" allowevents="true"
xbl:inherits="value=label,disabled"/>
</xul:hbox>
<xul:dropmarker class="menulist-dropmarker" type="menu"/>
<children includes="menupopup"/>
</content>
<implementation>
<constructor><![CDATA[
this.setInitialSelection();
]]></constructor>
<method name="_selectInputFieldValueInList">
<body>
<![CDATA[
if (this.hasAttribute("disableautoselect"))
return "";
// Find and select the menuitem that matches inputField's "value"
var arr = null;
var popup = this.menupopup;
if (popup)
arr = popup.getElementsByAttribute('label', this.inputField.value);
if (arr && arr.item(0))
this.setSelectionInternal(arr[0]);
else
this.setSelectionInternal(null);
]]>
</body>
</method>
<method name="setSelectionInternal">
<parameter name="val"/>
<body>
<![CDATA[
// This is called internally to set selected item
// without triggering infinite loop
// when using selectedItem's setter
if (this.selectedInternal == val)
return val;
if (this.selectedInternal)
this.selectedInternal.removeAttribute('selected');
this.selectedInternal = val;
if (val)
val.setAttribute('selected', 'true');
//Do NOT change the "value", which is owned by inputField
return val;
]]>
</body>
</method>
<field name="mInputField">null</field>
<property name="inputField" readonly="true">
<getter><![CDATA[
if (!this.mInputField)
this.mInputField = document.getAnonymousElementByAttribute(this, "anonid", "input");
return this.mInputField;
]]></getter>
</property>
<property name="label" onset="this.inputField.value = val; return val;"
onget="return this.inputField.value;"/>
<property name="value" onget="return this.inputField.value;">
<setter>
<![CDATA[
// Override menulist's value setter to refer to the inputField's value
// (Allows using "menulist.value" instead of "menulist.inputField.value")
this.inputField.value = val;
this.setAttribute('value', val);
this.setAttribute('label', val);
this._selectInputFieldValueInList();
return val;
]]>
</setter>
</property>
<property name="selectedItem">
<getter>
<![CDATA[
// Make sure internally-selected item
// is in sync with inputField.value
this._selectInputFieldValueInList();
return this.selectedInternal;
]]>
</getter>
<setter>
<![CDATA[
// This doesn't touch inputField.value or "value" and "label" attributes
this.setSelectionInternal(val);
if (!this.selectedInternal) {
this.inputField.value = "";
this.removeAttribute('value');
this.removeAttribute('label');
return val;
}
// Editable menulist uses "label" as its "value"
var label = val.getAttribute('label');
this.inputField.value = label;
this.setAttribute('value', label);
this.setAttribute('label', label);
return val;
]]>
</setter>
</property>
<property name="disableautoselect"
onset="if (val) this.setAttribute('disableautoselect','true');
else this.removeAttribute('disableautoselect'); return val;"
onget="return this.hasAttribute('disableautoselect');"/>
<method name="select">
<body>
this.inputField.select();
</body>
</method>
</implementation>
<handlers>
<handler event="focus" phase="capturing">
<![CDATA[
if (!this.hasAttribute('focused')) {
if (document.commandDispatcher.focusedElement != this.inputField)
this.inputField.focus();
this.setAttribute('focused','true');
}
]]>
</handler>
<handler event="blur" phase="capturing">
<![CDATA[
this.removeAttribute('focused');
]]>
</handler>
<handler event="popupshowing">
<![CDATA[
// editable menulists elements aren't in the focus order,
// so when the popup opens we need to force the focus to the inputField
// XXX see bug #196755
// originalTarget is workaround for arrowscrollbox retargeting bug
if (event.originalTarget.parentNode == this) {
if (document.commandDispatcher.focusedElement != this.inputField)
this.inputField.focus();
if (this.selectedItem)
// Not ready for auto-setting the active child in hierarchies yet.
// For now, only do this when the outermost menupopup opens.
this.menuBoxObject.activeChild = this.selectedInternal;
}
]]>
</handler>
<handler event="keypress">
<![CDATA[
// open popup if key is up arrow, down arrow, or F4
if (!event.ctrlKey && !event.shiftKey) {
if (event.keyCode == KeyEvent.DOM_VK_UP ||
event.keyCode == KeyEvent.DOM_VK_DOWN ||
(event.keyCode == KeyEvent.DOM_VK_F4 && !event.altKey)) {
event.preventDefault();
this.open = true;
}
}
]]>
</handler>
</handlers>
</binding>
<binding id="menulist-compact" display="xul:menu"
extends="chrome://global/content/bindings/menulist.xml#menulist">
<content sizetopopup="false">
<xul:dropmarker class="menulist-dropmarker" type="menu"/>
<xul:image class="menulist-icon" xbl:inherits="src"/>
<xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
<children includes="menupopup"/>
</content>
</binding>
</bindings>