From 107a29219572bad3c3a61281bd892af6239e1279 Mon Sep 17 00:00:00 2001 From: "Olli.Pettay%helsinki.fi" Date: Tue, 16 Jan 2007 17:09:58 +0000 Subject: [PATCH] Bug 298371, make richlistbox multi-selectable p=surkov, r=mano+enndeakin --- toolkit/content/widgets/listbox.xml | 1114 ++++++++++------- toolkit/content/widgets/richlistbox.xml | 731 ++++++----- .../themes/pinstripe/global/richlistbox.css | 16 + .../themes/winstripe/global/richlistbox.css | 16 + 4 files changed, 1023 insertions(+), 854 deletions(-) diff --git a/toolkit/content/widgets/listbox.xml b/toolkit/content/widgets/listbox.xml index 9955814f08d..7f572d20ce7 100644 --- a/toolkit/content/widgets/listbox.xml +++ b/toolkit/content/widgets/listbox.xml @@ -1,18 +1,562 @@ + + - - + 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"> + + + + + + + + + + return Components.interfaces.nsIAccessibleProvider.XULListbox; + + + + + + + 0 ? this.selectedItems[0] : null; + ]]> + + + + + + 0) + return this.getIndexOfItem(this.selectedItems[0]); + return -1; + ]]> + + + = 0) + this.selectItem(this.getItemAtIndex(val)); + else + this.clearSelection(); + ]]> + + + + + + 0) + return this.selectedItem.value; + return null; + ]]> + + + + + + + + + + + + + + + + + + + if (this._currentItem == val) + return val; + + if (this._currentItem) + this._currentItem.current = false; + this._currentItem = val; + + if (val) + val.current = true; + + return val; + + + + + + return this.currentItem ? this.getIndexOfItem(this.currentItem) : -1; + + + = 0) + this.currentItem = this.getItemAtIndex(val); + else + this.currentItem = null; + ]]> + + + + [] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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(); + + + + + + 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(); + + + + + + = 0; --i) + this.selectedItems[i].selected = false; + + this.selectedItems.splice(0, this.selectedItems.length); + } + + this._selectionStart = null; + this._fireOnSelect(); + ]]> + + + + + + + + + + + + + + + + if (val) + this.setAttribute("disableKeyNavigation", "true"); + else + this.removeAttribute("disableKeyNavigation"); + return val; + + + + + + + + + + + + + + + + + + + + + numItems - 1) + newIndex = numItems - 1; + + var newItem = this.getItemAtIndex(newIndex); + if (newItem) { + this.ensureIndexIsVisible(newIndex); + if (aIsSelectingRange) + this.selectItemRange(null, newItem); + else if (aIsSelecting) + this.selectItem(newItem); + + this.currentItem = newItem; + } + ]]> + + + + + + + + + + + + + + + + + + + + + + + aMe._fireOnSelect(); + aMe._selectTimeout = null; + + + + + + + + false + null + null + null + + + + + + + - - - + @@ -26,77 +570,23 @@ - - - false - null - null - null + + 0 "" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 ? this.getIndexOfItem(this.selectedItems[0]) : -1; - ]]> - = 0) - this.selectItem(this.getItemAtIndex(val)); - else - this.clearSelection(); - ]]> - - - [] - - 0 ? this.selectedItems[0] : null; - ]]> - - - - - - 0) - return this.selectedItem.value; - else - return null; - ]]> - - - - - - - - + + - - + - - - + + + - - - - - - - - - - - - - - - - - - = 0) - this.currentItem = this.getItemAtIndex(val); - else - this.currentItem = null; - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - = 0; --i) - this.selectedItems[i].selected = false; - - this.selectedItems.splice(0, this.selectedItems.length); - } - this._selectionStart = null; - this._fireOnSelect(); - ]]> - - - - - - - - - - - - - - return this.listBoxObject.getIndexOfItem(item); + @@ -513,34 +679,7 @@ return this.listBoxObject.getRowCount(); - - - - - - numItems - 1) - newIndex = numItems - 1; - var newItem = this.getItemAtIndex(newIndex); - if (newItem) { - this.ensureIndexIsVisible(newIndex); - if (isSelectingRange) { - this.selectItemRange(null, newItem); - } - else if (isSelecting) { - this.selectItem(newItem); - } - this.currentItem = newItem; - } - ]]> - - + @@ -590,6 +729,7 @@ if (this.currentIndex == -1 && this.getRowCount() > 0) { this.currentIndex = this.getIndexOfFirstVisibleRow(); } + this._lastKeyTime = 0; ]]> @@ -651,8 +791,12 @@ - + + + + + + @@ -717,10 +864,6 @@ else this.removeAttribute("selected"); - var event = document.createEvent("Events"); - event.initEvent("DOMMenuItemActive", true, true); - this.dispatchEvent(event); - return val; ]]> @@ -729,25 +872,38 @@ + + + + + + + @@ -756,17 +912,19 @@ except this item. --> @@ -834,7 +977,7 @@ @@ -851,7 +994,12 @@ + extends="chrome://global/content/bindings/general.xml#basecontrol"> + + + + + @@ -890,8 +1038,12 @@ - + + + + + + @@ -899,8 +1051,12 @@ - + + + + + + diff --git a/toolkit/content/widgets/richlistbox.xml b/toolkit/content/widgets/richlistbox.xml index c0c72046064..0496913dbb1 100644 --- a/toolkit/content/widgets/richlistbox.xml +++ b/toolkit/content/widgets/richlistbox.xml @@ -22,6 +22,7 @@ - - Contributor(s): - Doron Rosenberg (Original Author) + - Simon Bünzli - - 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 @@ -42,7 +43,12 @@ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl"> - + + + + + @@ -50,11 +56,7 @@ - - - - - + null - - - - - - - - - - - - - - - - - + + = this.getRowCount()) - this.selectedIndex = this.getRowCount() - 1; - else - this.selectedIndex = selectedIndex; - - // XXX: downloadmanager needs the following line, else we scroll to - // the middle on inital load. - this.ensureSelectedElementIsVisible(); - } - ]]> - - - - - - - - - - 0 - - - - - - = 0) { - // only set if we get an item returned - var item = this.getItemAtIndex(val); - if (item) - this.selectedItem = item; - } - ]]> - - - - null - - - return this._selectedItem; - - - -1) + this._currentIndex = this.currentIndex + 1; - this._fireOnSelect(); + var event = document.createEvent("Events"); + event.initEvent("select", true, true); + this.dispatchEvent(event); + + // always call this (allows a commandupdater without controller) + document.commandDispatcher.updateCommands("richlistbox-select"); ]]> - - + + - - + + + + + return this.insertItemAt(-1, aLabel, aValue); + + + + + + + + + const XULNS = + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + + var item = + this.ownerDocument.createElementNS(XULNS, "richlistitem"); + item.setAttribute("value", aValue); + + var label = this.ownerDocument.createElementNS(XULNS, "label"); + label.setAttribute("value", aLabel); + label.setAttribute("flex", "1"); + label.setAttribute("crop", "end"); + item.appendChild(label); + + var before = this.getItemAtIndex(aIndex); + if (!before) + this.appendChild(item); + else + this.insertBefore(item, before); + + return item; + + + + - + + + + return this.children[aIndex] || null; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -267,34 +237,154 @@ - + + height) + break; + index += aDirection; } - return false; + index -= aDirection; + + return index != this.currentIndex ? index - this.currentIndex : aDirection; ]]> - + + + + + + + + + + + + = 0; i--) { + if (this.selectedItems[i] && this.selectedItems[i].id) + this.selectedItems[i] = document.getElementById(this.selectedItems[i].id); + else + this.selectedItems[i] = null; + if (!this.selectedItems[i]) + this.selectedItems.splice(i, 1); } } - return false; + if (this.currentItem && this.currentItem.id) + this.currentItem = document.getElementById(this.currentItem.id); + else + this.currentItem = null; + + // if we have no previously current item or if the above check fails to + // find the previous nodes (which causes it to clear selection) + if (!this.currentItem && this.selectedCount == 0) { + this.currentIndex = this._currentIndex ? this._currentIndex - 1 : 0; + + // cf. listbox constructor: + // select items according to their attributes + var els = this.getElementsByAttribute("selected", "true"); + for (i = 0; i < els.length; i++) + this.selectedItems.push(els[i]); + } + + if (this.selType != "multiple" && this.selectedCount == 0) + this.selectedItem = this.currentItem; + + // XXX hack for the Downloads manager (better to focus the list than + // the individual items - these usually aren't tabbable anyway, and + // we need the keyboard focus for navigation), see bug 363271: + this.focus(); ]]> @@ -317,148 +407,88 @@ - - - - = 0 && index < children.length) { - var border2 = children[index].boxObject.y; - if (aDirection == -1) - border2 += children[index].boxObject.height; - if ((border2 - border) * aDirection > height) - break; - index += aDirection; - } - index -= aDirection; - - if (this.selectedItem != children[index]) { - this.selectedItem = children[index]; - return true; - } - - // Move by at least one item if the view port is too small - if (aDirection == -1) - return this.goUp(); - - return this.goDown(); - ]]> - - - - - - - - - + null + - - - - - - - + - - - - - - - + + 0) - document.commandDispatcher.updateCommands("richlistbox-select"); - } + var index = this.currentIndex; + this.moveByOffset(-1, true, false); + return index != this.currentIndex; ]]> + + + + + + + + - - - - - - + + + + + + + @@ -468,119 +498,70 @@ if (event.button != 2) { var popup = document.getElementById(this.getAttribute("context")); if (popup) - popup.showPopup(this.selectedItem, -1, -1, "context", "bottomleft", "topleft"); + popup.showPopup(this.currentItem, -1, -1, "context", "bottomleft", "topleft"); } ]]> - - - + extends="chrome://global/content/bindings/listbox.xml#listitem"> - + - + - - - - - - - - - - - + + concatentation of label text to expose via accessibility APIs --> - - - - - - - - - - - diff --git a/toolkit/themes/pinstripe/global/richlistbox.css b/toolkit/themes/pinstripe/global/richlistbox.css index 2db665d1cc2..468b56de953 100644 --- a/toolkit/themes/pinstripe/global/richlistbox.css +++ b/toolkit/themes/pinstripe/global/richlistbox.css @@ -20,6 +20,7 @@ * * Contributor(s): * Doron Rosenberg (original author) + * Simon Bünzli * * 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 @@ -38,6 +39,7 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); richlistbox { + margin: 2px 4px; background-color: -moz-Field; color: -moz-FieldText; } @@ -47,7 +49,21 @@ richlistbox[disabled="true"] { } richlistitem[selected="true"] { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +richlistbox:focus > richlistitem[selected="true"] { background-color: Highlight; color: HighlightText; } +richlistbox[seltype="multiple"]:focus > richlistitem[current="true"] { + outline: 1px dotted Highlight; + -moz-outline-offset: -1px; +} + +richlistbox[seltype="multiple"]:focus > richlistitem[current="true"][selected="true"] { + outline: 1px dotted #F3D982; /* TODO: find a suitable system color */ +} + diff --git a/toolkit/themes/winstripe/global/richlistbox.css b/toolkit/themes/winstripe/global/richlistbox.css index 2db665d1cc2..468b56de953 100644 --- a/toolkit/themes/winstripe/global/richlistbox.css +++ b/toolkit/themes/winstripe/global/richlistbox.css @@ -20,6 +20,7 @@ * * Contributor(s): * Doron Rosenberg (original author) + * Simon Bünzli * * 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 @@ -38,6 +39,7 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); richlistbox { + margin: 2px 4px; background-color: -moz-Field; color: -moz-FieldText; } @@ -47,7 +49,21 @@ richlistbox[disabled="true"] { } richlistitem[selected="true"] { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +richlistbox:focus > richlistitem[selected="true"] { background-color: Highlight; color: HighlightText; } +richlistbox[seltype="multiple"]:focus > richlistitem[current="true"] { + outline: 1px dotted Highlight; + -moz-outline-offset: -1px; +} + +richlistbox[seltype="multiple"]:focus > richlistitem[current="true"][selected="true"] { + outline: 1px dotted #F3D982; /* TODO: find a suitable system color */ +} +