gecko-dev/toolkit/content/widgets/listbox.xml
Alexander Surkov 7f9931aed9 Bug 512424 - implement IAccessibleTable2, r=marcoz, davidb, sr=neil
--HG--
rename : accessible/src/atk/nsXULTreeAccessibleWrap.h => accessible/src/atk/nsXULTreeGridAccessibleWrap.h
rename : accessible/src/mac/nsXULTreeAccessibleWrap.h => accessible/src/mac/nsXULTreeGridAccessibleWrap.h
rename : accessible/src/msaa/nsXULTreeAccessibleWrap.cpp => accessible/src/msaa/nsXULTreeGridAccessibleWrap.cpp
rename : accessible/src/msaa/nsXULTreeAccessibleWrap.h => accessible/src/msaa/nsXULTreeGridAccessibleWrap.h
rename : accessible/src/other/nsXULTreeAccessibleWrap.h => accessible/src/other/nsXULTreeGridAccessibleWrap.h
rename : accessible/src/xul/nsXULSelectAccessible.cpp => accessible/src/xul/nsXULListboxAccessible.cpp
rename : accessible/src/xul/nsXULSelectAccessible.h => accessible/src/xul/nsXULListboxAccessible.h
rename : accessible/tests/mochitest/test_relations_table.html => accessible/tests/mochitest/test_table_headers.html
rename : accessible/tests/mochitest/test_nsIAccessibleTable_listboxes.xul => accessible/tests/mochitest/test_table_sels_listbox.xul
rename : accessible/tests/mochitest/test_elm_table.html => accessible/tests/mochitest/test_table_struct.html
2009-09-11 09:07:56 +08:00

1233 lines
38 KiB
XML

<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- 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 toolkit code.
-
- The Initial Developer of the Original Code is
- Netscape Communications Corporation.
- Portions created by the Initial Developer are Copyright (C) 2002
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Joe Hewitt <hewitt@netscape.com> (original author)
- Simon Bünzli <zeniko@gmail.com>
- Alexander Surkov <surkov.alexander@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<bindings id="listboxBindings"
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">
<!--
Interface binding that is base for bindings of xul:listbox and
xul:richlistbox elements. This binding assumes that successors bindings
will implement the following properties and methods:
/** Return the number of items */
readonly itemCount
/** Return index of given item
* @param aItem - given item element */
getIndexOfItem(aItem)
/** Return item at given index
* @param aIndex - index of item element */
getItemAtIndex(aIndex)
/** Return count of item elements */
getRowCount()
/** Return count of visible item elements */
getNumberOfVisibleRows()
/** Return index of first visible item element */
getIndexOfFirstVisibleRow()
/** Return true if item of given index is visible
* @param aIndex - index of item element
*
* @note XXX: this method should be removed after bug 364612 is fixed
*/
ensureIndexIsVisible(aIndex)
/** Return true if item element is visible
* @param aElement - given item element */
ensureElementIsVisible(aElement)
/** Scroll list control to make visible item of given index
* @param aIndex - index of item element
*
* @note XXX: this method should be removed after bug 364612 is fixed
*/
scrollToIndex(aIndex)
/** Create item element and append it to the end of listbox
* @param aLabel - label of new item element
* @param aValue - value of new item element */
appendItem(aLabel, aValue)
/** Create item element and insert it to given position
* @param aIndex - insertion position
* @param aLabel - label of new item element
* @param aValue - value of new item element */
insertItemAt(aIndex, aLabel, aValue)
/** Scroll up/down one page
* @param aDirection - specifies scrolling direction, should be either -1 or 1
* @return the number of elements the selection scrolled
*/
scrollOnePage(aDirection)
/** Fire "select" event */
_fireOnSelect()
-->
<binding id="listbox-base"
extends="chrome://global/content/bindings/general.xml#basecontrol">
<implementation implements="nsIDOMXULMultiSelectControlElement, nsIAccessibleProvider">
<field name="_lastKeyTime">0</field>
<field name="_incrementalString">""</field>
<!-- nsIAccessibleProvider -->
<property name="accessibleType" readonly="true">
<getter>
return Components.interfaces.nsIAccessibleProvider.XULListbox;
</getter>
</property>
<!-- nsIDOMXULSelectControlElement -->
<property name="selectedItem"
onset="this.selectItem(val);">
<getter>
<![CDATA[
return this.selectedItems.length > 0 ? this.selectedItems[0] : null;
]]>
</getter>
</property>
<property name="selectedIndex">
<getter>
<![CDATA[
if (this.selectedItems.length > 0)
return this.getIndexOfItem(this.selectedItems[0]);
return -1;
]]>
</getter>
<setter>
<![CDATA[
if (val >= 0)
this.selectItem(this.getItemAtIndex(val));
else
this.clearSelection();
]]>
</setter>
</property>
<property name="value">
<getter>
<![CDATA[
if (this.selectedItems.length > 0)
return this.selectedItem.value;
return null;
]]>
</getter>
<setter>
<![CDATA[
var kids = this.getElementsByAttribute("value", val);
if (kids && kids.item(0))
this.selectItem(kids[0]);
return val;
]]>
</setter>
</property>
<method name="removeItemAt">
<parameter name="index"/>
<body>
<![CDATA[
var remove = this.getItemAtIndex(index);
if (remove)
this.removeChild(remove);
return remove;
]]>
</body>
</method>
<!-- nsIDOMXULMultiSelectControlElement -->
<property name="selType"
onget="return this.getAttribute('seltype');"
onset="this.setAttribute('seltype', val); return val;"/>
<property name="currentItem" onget="return this._currentItem;">
<setter>
if (this._currentItem == val)
return val;
if (this._currentItem)
this._currentItem.current = false;
this._currentItem = val;
if (val)
val.current = true;
return val;
</setter>
</property>
<property name="currentIndex">
<getter>
return this.currentItem ? this.getIndexOfItem(this.currentItem) : -1;
</getter>
<setter>
<![CDATA[
if (val >= 0)
this.currentItem = this.getItemAtIndex(val);
else
this.currentItem = null;
]]>
</setter>
</property>
<field name="selectedItems">[]</field>
<method name="addItemToSelection">
<parameter name="aItem"/>
<body>
<![CDATA[
if (this.selType != "multiple" && this.selectedCount)
return;
if (aItem.selected)
return;
this.selectedItems.push(aItem);
aItem.selected = true;
this._fireOnSelect();
]]>
</body>
</method>
<method name="removeItemFromSelection">
<parameter name="aItem"/>
<body>
<![CDATA[
if (!aItem.selected)
return;
for (var i = 0; i < this.selectedItems.length; ++i) {
if (this.selectedItems[i] == aItem) {
this.selectedItems.splice(i, 1);
aItem.selected = false;
break;
}
}
this._fireOnSelect();
]]>
</body>
</method>
<method name="toggleItemSelection">
<parameter name="aItem"/>
<body>
<![CDATA[
if (aItem.selected)
this.removeItemFromSelection(aItem);
else
this.addItemToSelection(aItem);
]]>
</body>
</method>
<method name="selectItem">
<parameter name="aItem"/>
<body>
<![CDATA[
if (!aItem)
return;
if (this.selectedItems.length == 1 && this.selectedItems[0] == aItem)
return;
this._selectionStart = null;
var suppress = this._suppressOnSelect;
this._suppressOnSelect = true;
this.clearSelection();
this.addItemToSelection(aItem);
this.currentItem = aItem;
this._suppressOnSelect = suppress;
this._fireOnSelect();
]]>
</body>
</method>
<method name="selectItemRange">
<parameter name="aStartItem"/>
<parameter name="aEndItem"/>
<body>
<![CDATA[
if (this.selType != "multiple")
return;
if (!aStartItem)
aStartItem = this._selectionStart ?
this._selectionStart : this.currentItem;
if (!aStartItem)
aStartItem = aEndItem;
var suppressSelect = this._suppressOnSelect;
this._suppressOnSelect = true;
this._selectionStart = aStartItem;
var currentItem;
var startIndex = this.getIndexOfItem(aStartItem);
var endIndex = this.getIndexOfItem(aEndItem);
if (endIndex < startIndex) {
currentItem = aEndItem;
aEndItem = aStartItem;
aStartItem = currentItem;
} else {
currentItem = aStartItem;
}
while (currentItem) {
this.addItemToSelection(currentItem);
if (currentItem == aEndItem) {
currentItem = this.getNextItem(currentItem, 1);
break;
}
currentItem = this.getNextItem(currentItem, 1);
}
// Clear around new selection
// Don't use clearSelection() because it causes a lot of noise
// with respect to selection removed notifications used by the
// accessibility API support.
var userSelecting = this._userSelecting;
this._userSelecting = false; // that's US automatically unselecting
for (; currentItem; currentItem = this.getNextItem(currentItem, 1))
this.removeItemFromSelection(currentItem);
for (currentItem = this.getItemAtIndex(0); currentItem != aStartItem;
currentItem = this.getNextItem(currentItem, 1))
this.removeItemFromSelection(currentItem);
this._userSelecting = userSelecting;
this._suppressOnSelect = suppressSelect;
this._fireOnSelect();
]]>
</body>
</method>
<method name="selectAll">
<body>
this._selectionStart = null;
var suppress = this._suppressOnSelect;
this._suppressOnSelect = true;
var item = this.getItemAtIndex(0);
while (item) {
this.addItemToSelection(item);
item = this.getNextItem(item, 1);
}
this._suppressOnSelect = suppress;
this._fireOnSelect();
</body>
</method>
<method name="invertSelection">
<body>
this._selectionStart = null;
var suppress = this._suppressOnSelect;
this._suppressOnSelect = true;
var item = this.getItemAtIndex(0);
while (item) {
if (item.selected)
this.removeItemFromSelection(item);
else
this.addItemToSelection(item);
item = this.getNextItem(item, 1);
}
this._suppressOnSelect = suppress;
this._fireOnSelect();
</body>
</method>
<method name="clearSelection">
<body>
<![CDATA[
if (this.selectedItems) {
for (var i = this.selectedItems.length - 1; i >= 0; --i)
this.selectedItems[i].selected = false;
this.selectedItems.length = 0;
}
this._selectionStart = null;
this._fireOnSelect();
]]>
</body>
</method>
<property name="selectedCount" readonly="true"
onget="return this.selectedItems.length;"/>
<method name="getSelectedItem">
<parameter name="aIndex"/>
<body>
<![CDATA[
return aIndex < this.selectedItems.length ?
this.selectedItems[aIndex] : null;
]]>
</body>
</method>
<!-- Other public members -->
<property name="disableKeyNavigation"
onget="return this.hasAttribute('disableKeyNavigation');">
<setter>
if (val)
this.setAttribute("disableKeyNavigation", "true");
else
this.removeAttribute("disableKeyNavigation");
return val;
</setter>
</property>
<property name="suppressOnSelect"
onget="return this.getAttribute('suppressonselect') == 'true';"
onset="this.setAttribute('suppressonselect', val);"/>
<property name="_selectDelay"
onset="this.setAttribute('_selectDelay', val);"
onget="return this.getAttribute('_selectDelay') || 50;"/>
<method name="timedSelect">
<parameter name="aItem"/>
<parameter name="aTimeout"/>
<body>
<![CDATA[
var suppress = this._suppressOnSelect;
if (aTimeout != -1)
this._suppressOnSelect = true;
this.selectItem(aItem);
this._suppressOnSelect = suppress;
if (aTimeout != -1) {
if (this._selectTimeout)
window.clearTimeout(this._selectTimeout);
this._selectTimeout =
window.setTimeout(this._selectTimeoutHandler, aTimeout, this);
}
]]>
</body>
</method>
<method name="moveByOffset">
<parameter name="aOffset"/>
<parameter name="aIsSelecting"/>
<parameter name="aIsSelectingRange"/>
<body>
<![CDATA[
if ((aIsSelectingRange || !aIsSelecting) &&
this.selType != "multiple")
return;
var newIndex = this.currentIndex + aOffset;
if (newIndex < 0)
newIndex = 0;
var numItems = this.getRowCount();
if (newIndex > numItems - 1)
newIndex = numItems - 1;
var newItem = this.getItemAtIndex(newIndex);
// make sure that the item is actually visible/selectable
if (this._userSelecting && newItem && !this._canUserSelect(newItem))
newItem =
aOffset > 0 ? this.getNextItem(newItem, 1) || this.getPreviousItem(newItem, 1) :
this.getPreviousItem(newItem, 1) || this.getNextItem(newItem, 1);
if (newItem) {
this.ensureIndexIsVisible(this.getIndexOfItem(newItem));
if (aIsSelectingRange)
this.selectItemRange(null, newItem);
else if (aIsSelecting)
this.selectItem(newItem);
this.currentItem = newItem;
}
]]>
</body>
</method>
<!-- Private -->
<method name="getNextItem">
<parameter name="aStartItem"/>
<parameter name="aDelta"/>
<body>
<![CDATA[
while (aStartItem) {
aStartItem = aStartItem.nextSibling;
if (aStartItem && aStartItem instanceof
Components.interfaces.nsIDOMXULSelectControlItemElement &&
(!this._userSelecting || this._canUserSelect(aStartItem))) {
--aDelta;
if (aDelta == 0)
return aStartItem;
}
}
return null;
]]></body>
</method>
<method name="getPreviousItem">
<parameter name="aStartItem"/>
<parameter name="aDelta"/>
<body>
<![CDATA[
while (aStartItem) {
aStartItem = aStartItem.previousSibling;
if (aStartItem && aStartItem instanceof
Components.interfaces.nsIDOMXULSelectControlItemElement &&
(!this._userSelecting || this._canUserSelect(aStartItem))) {
--aDelta;
if (aDelta == 0)
return aStartItem;
}
}
return null;
]]>
</body>
</method>
<method name="_moveByOffsetFromUserEvent">
<parameter name="aOffset"/>
<parameter name="aEvent"/>
<body>
<![CDATA[
if (!aEvent.getPreventDefault()) {
this._userSelecting = true;
this._mayReverse = true;
this.moveByOffset(aOffset, !aEvent.ctrlKey, aEvent.shiftKey);
this._userSelecting = false;
this._mayReverse = false;
aEvent.preventDefault();
}
]]>
</body>
</method>
<method name="_canUserSelect">
<parameter name="aItem"/>
<body>
<![CDATA[
var style = document.defaultView.getComputedStyle(aItem, "");
return style.display != "none" && style.visibility == "visible";
]]>
</body>
</method>
<method name="_selectTimeoutHandler">
<parameter name="aMe"/>
<body>
aMe._fireOnSelect();
aMe._selectTimeout = null;
</body>
</method>
<field name="_suppressOnSelect">false</field>
<field name="_userSelecting">false</field>
<field name="_mayReverse">false</field>
<field name="_selectTimeout">null</field>
<field name="_currentItem">null</field>
<field name="_selectionStart">null</field>
</implementation>
<handlers>
<handler event="keypress" keycode="VK_UP" modifiers="control shift any"
action="this._moveByOffsetFromUserEvent(-1, event);"
group="system"/>
<handler event="keypress" keycode="VK_DOWN" modifiers="control shift any"
action="this._moveByOffsetFromUserEvent(1, event);"
group="system"/>
<handler event="keypress" keycode="VK_HOME" modifiers="control shift any"
group="system">
<![CDATA[
this._mayReverse = true;
this._moveByOffsetFromUserEvent(-this.currentIndex, event);
this._mayReverse = false;
]]>
</handler>
<handler event="keypress" keycode="VK_END" modifiers="control shift any"
group="system">
<![CDATA[
this._mayReverse = true;
this._moveByOffsetFromUserEvent(this.getRowCount() - this.currentIndex - 1, event);
this._mayReverse = false;
]]>
</handler>
<handler event="keypress" keycode="VK_PAGE_UP" modifiers="control shift any"
group="system">
<![CDATA[
this._mayReverse = true;
this._moveByOffsetFromUserEvent(this.scrollOnePage(-1), event);
this._mayReverse = false;
]]>
</handler>
<handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="control shift any"
group="system">
<![CDATA[
this._mayReverse = true;
this._moveByOffsetFromUserEvent(this.scrollOnePage(1), event);
this._mayReverse = false;
]]>
</handler>
<handler event="keypress" key=" " modifiers="control" phase="target">
<![CDATA[
if (this.currentItem && this.selType == "multiple")
this.toggleItemSelection(this.currentItem);
]]>
</handler>
<handler event="focus">
<![CDATA[
if (this.getRowCount() > 0) {
if (this.currentIndex == -1) {
this.currentIndex = this.getIndexOfFirstVisibleRow();
}
else {
this.currentItem._fireEvent("DOMMenuItemActive");
}
}
this._lastKeyTime = 0;
]]>
</handler>
<handler event="keypress" phase="target">
<![CDATA[
if (this.disableKeyNavigation || !event.charCode ||
event.altKey || event.ctrlKey || event.metaKey)
return;
if (event.timeStamp - this._lastKeyTime > 1000)
this._incrementalString = "";
var key = String.fromCharCode(event.charCode).toLowerCase();
this._incrementalString += key;
this._lastKeyTime = event.timeStamp;
// If all letters in the incremental string are the same, just
// try to match the first one
var incrementalString = /^(.)\1+$/.test(this._incrementalString) ?
RegExp.$1 : this._incrementalString;
var length = incrementalString.length;
var rowCount = this.getRowCount();
var l = this.selectedItems.length;
var start = l > 0 ? this.getIndexOfItem(this.selectedItems[l - 1]) : -1;
// start from the first element if none was selected or from the one
// following the selected one if it's a new or a repeated-letter search
if (start == -1 || length == 1)
start++;
for (var i = 0; i < rowCount; i++) {
var k = (start + i) % rowCount;
var listitem = this.getItemAtIndex(k);
if (!this._canUserSelect(listitem))
continue;
// allow richlistitems to specify the string being searched for
var searchText = "searchLabel" in listitem ? listitem.searchLabel :
listitem.getAttribute("label"); // (see also bug 250123)
searchText = searchText.substring(0, length).toLowerCase();
if (searchText == incrementalString) {
this.ensureIndexIsVisible(k);
this.timedSelect(listitem, this._selectDelay);
break;
}
}
]]>
</handler>
</handlers>
</binding>
<!-- Binding for xul:listbox element.
-->
<binding id="listbox"
extends="#listbox-base">
<resources>
<stylesheet src="chrome://global/skin/listbox.css"/>
</resources>
<content>
<children includes="listcols">
<xul:listcols>
<xul:listcol flex="1"/>
</xul:listcols>
</children>
<xul:listrows>
<children includes="listhead"/>
<xul:listboxbody xbl:inherits="rows,size,minheight">
<children includes="listitem"/>
</xul:listboxbody>
</xul:listrows>
</content>
<implementation>
<!-- ///////////////// public listbox members ///////////////// -->
<property name="listBoxObject"
onget="return this.boxObject.QueryInterface(Components.interfaces.nsIListBoxObject);"
readonly="true"/>
<!-- ///////////////// private listbox members ///////////////// -->
<method name="_fireOnSelect">
<body>
<![CDATA[
if (!this._suppressOnSelect && !this.suppressOnSelect) {
var event = document.createEvent("Events");
event.initEvent("select", true, true);
this.dispatchEvent(event);
}
]]>
</body>
</method>
<constructor>
<![CDATA[
var count = this.itemCount;
for (var index = 0; index < count; index++) {
var item = this.getItemAtIndex(index);
if (item.getAttribute("selected") == "true")
this.selectedItems.push(item);
}
]]>
</constructor>
<!-- ///////////////// nsIDOMXULSelectControlElement ///////////////// -->
<method name="appendItem">
<parameter name="aLabel"/>
<parameter name="aValue"/>
<body>
const XULNS =
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var item = this.ownerDocument.createElementNS(XULNS, "listitem");
item.setAttribute("label", aLabel);
item.setAttribute("value", aValue);
this.appendChild(item);
return item;
</body>
</method>
<method name="insertItemAt">
<parameter name="aIndex"/>
<parameter name="aLabel"/>
<parameter name="aValue"/>
<body>
const XULNS =
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var item = this.ownerDocument.createElementNS(XULNS, "listitem");
item.setAttribute("label", aLabel);
item.setAttribute("value", aValue);
var before = this.getItemAtIndex(aIndex);
if (before)
this.insertBefore(item, before);
else
this.appendChild(item);
return item;
</body>
</method>
<property name="itemCount" readonly="true"
onget="return this.listBoxObject.getRowCount()"/>
<!-- ///////////////// nsIListBoxObject ///////////////// -->
<method name="getIndexOfItem">
<parameter name="item"/>
<body>
return this.listBoxObject.getIndexOfItem(item);
</body>
</method>
<method name="getItemAtIndex">
<parameter name="index"/>
<body>
return this.listBoxObject.getItemAtIndex(index);
</body>
</method>
<method name="ensureIndexIsVisible">
<parameter name="index"/>
<body>
return this.listBoxObject.ensureIndexIsVisible(index);
</body>
</method>
<method name="ensureElementIsVisible">
<parameter name="element"/>
<body>
return this.ensureIndexIsVisible(this.listBoxObject.getIndexOfItem(element));
</body>
</method>
<method name="scrollToIndex">
<parameter name="index"/>
<body>
return this.listBoxObject.scrollToIndex(index);
</body>
</method>
<method name="getNumberOfVisibleRows">
<body>
return this.listBoxObject.getNumberOfVisibleRows();
</body>
</method>
<method name="getIndexOfFirstVisibleRow">
<body>
return this.listBoxObject.getIndexOfFirstVisibleRow();
</body>
</method>
<method name="getRowCount">
<body>
return this.listBoxObject.getRowCount();
</body>
</method>
<method name="scrollOnePage">
<parameter name="direction"/> <!-- Must be -1 or 1 -->
<body>
<![CDATA[
var pageOffset = this.getNumberOfVisibleRows() * direction;
// skip over invisible elements - the user won't care about them
for (var i = 0; i != pageOffset; i += direction) {
var item = this.getItemAtIndex(this.currentIndex + i);
if (item && !this._canUserSelect(item))
pageOffset += direction;
}
var newTop = this.getIndexOfFirstVisibleRow() + pageOffset;
if (direction == 1) {
var maxTop = this.getRowCount() - this.getNumberOfVisibleRows();
for (i = this.getRowCount(); i >= 0 && i > maxTop; i--) {
item = this.getItemAtIndex(i);
if (item && !this._canUserSelect(item))
maxTop--;
}
if (newTop >= maxTop)
newTop = maxTop;
}
if (newTop < 0)
newTop = 0;
this.scrollToIndex(newTop);
return pageOffset;
]]>
</body>
</method>
</implementation>
<handlers>
<handler event="keypress" key=" " phase="target">
<![CDATA[
if (this.currentItem) {
if (this.currentItem.getAttribute("type") != "checkbox")
this.addItemToSelection(this.currentItem);
else if (!this.currentItem.disabled) {
this.currentItem.checked = !this.currentItem.checked;
this.currentItem.doCommand();
}
}
]]>
</handler>
<handler event="MozSwipeGesture">
<![CDATA[
// Figure out which index to show
let targetIndex = 0;
// Only handle swipe gestures up and down
switch (event.direction) {
case event.DIRECTION_DOWN:
targetIndex = this.itemCount - 1;
// Fall through for actual action
case event.DIRECTION_UP:
this.ensureIndexIsVisible(targetIndex);
break;
}
]]>
</handler>
</handlers>
</binding>
<binding id="listrows">
<resources>
<stylesheet src="chrome://global/skin/listbox.css"/>
</resources>
<handlers>
<handler event="DOMMouseScroll" phase="capturing">
<![CDATA[
if (event.axis == event.HORIZONTAL_AXIS)
return;
var listBox = this.parentNode.listBoxObject;
var rows = event.detail;
if (rows == NSUIEvent.SCROLL_PAGE_UP)
rows = -listBox.getNumberOfVisibleRows();
else if (rows == NSUIEvent.SCROLL_PAGE_DOWN)
rows = listBox.getNumberOfVisibleRows();
listBox.scrollByLines(rows);
event.preventDefault();
]]>
</handler>
</handlers>
</binding>
<binding id="listitem"
extends="chrome://global/content/bindings/general.xml#basetext">
<resources>
<stylesheet src="chrome://global/skin/listbox.css"/>
</resources>
<content>
<children>
<xul:listcell xbl:inherits="label,crop,disabled,flexlabel"/>
</children>
</content>
<implementation implements="nsIDOMXULSelectControlItemElement, nsIAccessibleProvider">
<property name="current" onget="return this.getAttribute('current') == 'true';">
<setter><![CDATA[
if (val)
this.setAttribute("current", "true");
else
this.removeAttribute("current");
this._fireEvent(val ? "DOMMenuItemActive" : "DOMMenuItemInactive");
return val;
]]></setter>
</property>
<!-- ///////////////// nsIAccessibleProvider ///////////////// -->
<property name="accessibleType" readonly="true">
<getter>
<![CDATA[
return Components.interfaces.nsIAccessibleProvider.XULListitem;
]]>
</getter>
</property>
<!-- ///////////////// nsIDOMXULSelectControlItemElement ///////////////// -->
<property name="value" onget="return this.getAttribute('value');"
onset="this.setAttribute('value', val); return val;"/>
<property name="label" onget="return this.getAttribute('label');"
onset="this.setAttribute('label', val); return val;"/>
<property name="selected" onget="return this.getAttribute('selected') == 'true';">
<setter><![CDATA[
if (val)
this.setAttribute("selected", "true");
else
this.removeAttribute("selected");
return val;
]]></setter>
</property>
<property name="control">
<getter><![CDATA[
var parent = this.parentNode;
while (parent) {
if (parent instanceof Components.interfaces.nsIDOMXULSelectControlElement)
return parent;
parent = parent.parentNode;
}
return null;
]]></getter>
</property>
<method name="_fireEvent">
<parameter name="name"/>
<body>
<![CDATA[
var event = document.createEvent("Events");
event.initEvent(name, true, true);
this.dispatchEvent(event);
]]>
</body>
</method>
</implementation>
<handlers>
<!-- If there is no modifier key, we select on mousedown, not
click, so that drags work correctly. -->
<handler event="mousedown">
<![CDATA[
var control = this.control;
if (!control || control.disabled)
return;
if ((!event.ctrlKey
#ifdef XP_MACOSX
|| event.button == 2
#endif
) && !event.shiftKey && !event.metaKey) {
if (!this.selected) {
control.selectItem(this);
}
control.currentItem = this;
}
]]>
</handler>
<!-- On a click (up+down on the same item), deselect everything
except this item. -->
<handler event="click" button="0">
<![CDATA[
var control = this.control;
if (!control || control.disabled)
return;
control._userSelecting = true;
if (control.selType != "multiple") {
control.selectItem(this);
}
else if (event.ctrlKey || event.metaKey) {
control.toggleItemSelection(this);
control.currentItem = this;
}
else if (event.shiftKey) {
control.selectItemRange(null, this);
control.currentItem = this;
}
else {
/* We want to deselect all the selected items except what was
clicked, UNLESS it was a right-click. We have to do this
in click rather than mousedown so that you can drag a
selected group of items */
// use selectItemRange instead of selectItem, because this
// doesn't de- and reselect this item if it is selected
control.selectItemRange(this, this);
}
control._userSelecting = false;
]]>
</handler>
</handlers>
</binding>
<binding id="listitem-iconic"
extends="chrome://global/content/bindings/listbox.xml#listitem">
<content>
<children>
<xul:listcell class="listcell-iconic" xbl:inherits="label,image,crop,disabled,flexlabel"/>
</children>
</content>
</binding>
<binding id="listitem-checkbox"
extends="chrome://global/content/bindings/listbox.xml#listitem">
<content>
<children>
<xul:listcell type="checkbox" xbl:inherits="label,crop,checked,disabled,flexlabel"/>
</children>
</content>
<implementation>
<property name="checked"
onget="return this.getAttribute('checked') == 'true';">
<setter><![CDATA[
if (val)
this.setAttribute('checked', 'true');
else
this.removeAttribute('checked');
var event = document.createEvent('Events');
event.initEvent('CheckboxStateChange', true, true);
this.dispatchEvent(event);
return val;
]]></setter>
</property>
</implementation>
<handlers>
<handler event="mousedown" button="0">
<![CDATA[
if (!this.disabled && !this.control.disabled) {
this.checked = !this.checked;
this.doCommand();
}
]]>
</handler>
</handlers>
</binding>
<binding id="listitem-checkbox-iconic"
extends="chrome://global/content/bindings/listbox.xml#listitem-checkbox">
<content>
<children>
<xul:listcell type="checkbox" class="listcell-iconic" xbl:inherits="label,image,crop,checked,disabled,flexlabel"/>
</children>
</content>
</binding>
<binding id="listcell"
extends="chrome://global/content/bindings/general.xml#basecontrol">
<resources>
<stylesheet src="chrome://global/skin/listbox.css"/>
</resources>
<content>
<children>
<xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
</children>
</content>
<implementation implements="nsIAccessibleProvider">
<property name="accessibleType" readonly="true">
<getter>
<![CDATA[
// Don't expose xul:listcell as cell accessible until listbox is
// multicolumn.
const Ci = Components.interfaces;
const kNoAccessible = Ci.nsIAccessibleProvider.NoAccessible;
const kListCellAccessible = Ci.nsIAccessibleProvider.XULListCell;
var listitem = this.parentNode;
if (!(listitem instanceof Ci.nsIDOMXULSelectControlItemElement))
return kNoAccessible;
var list = listitem.control;
if (!list)
return kNoAccessible;
var listcolsElm = list.getElementsByTagName("listcols")[0];
if (!listcolsElm)
return kNoAccessible;
var listcolElms = listcolsElm.getElementsByTagName("listcol");
if (listcolElms.length <= 1)
return kNoAccessible;
return kListCellAccessible;
]]>
</getter>
</property>
</implementation>
</binding>
<binding id="listcell-iconic"
extends="chrome://global/content/bindings/listbox.xml#listcell">
<content>
<children>
<xul:image class="listcell-icon" xbl:inherits="src=image"/>
<xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
</children>
</content>
</binding>
<binding id="listcell-checkbox"
extends="chrome://global/content/bindings/listbox.xml#listcell">
<content>
<children>
<xul:image class="listcell-check" xbl:inherits="checked,disabled"/>
<xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
</children>
</content>
</binding>
<binding id="listcell-checkbox-iconic"
extends="chrome://global/content/bindings/listbox.xml#listcell-checkbox">
<content>
<children>
<xul:image class="listcell-check" xbl:inherits="checked,disabled"/>
<xul:image class="listcell-icon" xbl:inherits="src=image"/>
<xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
</children>
</content>
</binding>
<binding id="listhead">
<resources>
<stylesheet src="chrome://global/skin/listbox.css"/>
</resources>
<content>
<xul:listheaditem>
<children includes="listheader"/>
</xul:listheaditem>
</content>
<implementation implements="nsIAccessibleProvider">
<property name="accessibleType" readonly="true">
<getter>
return Components.interfaces.nsIAccessibleProvider.XULListHead;
</getter>
</property>
</implementation>
</binding>
<binding id="listheader" display="xul:button">
<resources>
<stylesheet src="chrome://global/skin/listbox.css"/>
</resources>
<content>
<xul:image class="listheader-icon"/>
<xul:label class="listheader-label" xbl:inherits="value=label,crop" flex="1" crop="right"/>
<xul:image class="listheader-sortdirection" xbl:inherits="sortDirection"/>
</content>
<implementation implements="nsIAccessibleProvider">
<property name="accessibleType" readonly="true">
<getter>
return Components.interfaces.nsIAccessibleProvider.XULListHeader;
</getter>
</property>
</implementation>
</binding>
</bindings>