1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/metro/base/content/helperui/SelectHelperUI.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,169 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +/** 1.11 + * SelectHelperUI: Provides an interface for making a choice in a list. 1.12 + * Supports simultaneous selection of choices and group headers. 1.13 + */ 1.14 +var SelectHelperUI = { 1.15 + _list: null, 1.16 + 1.17 + get _container() { 1.18 + delete this._container; 1.19 + return this._container = document.getElementById("select-container"); 1.20 + }, 1.21 + 1.22 + get _listbox() { 1.23 + delete this._listbox; 1.24 + return this._listbox = document.getElementById("select-commands"); 1.25 + }, 1.26 + 1.27 + get _menuPopup() { 1.28 + let popup = document.getElementById("select-popup"); 1.29 + delete this._menuPopup; 1.30 + return this._menuPopup = new MenuPopup(this._container, popup); 1.31 + }, 1.32 + 1.33 + show: function selectHelperShow(aList, aTitle, aRect) { 1.34 + if (this._list) { 1.35 + this.reset(); 1.36 + } 1.37 + 1.38 + this._list = aList; 1.39 + 1.40 + this._listbox.setAttribute("seltype", aList.multiple ? "multiple" : "single"); 1.41 + 1.42 + let firstSelected = null; 1.43 + 1.44 + // Using a fragment prevent us to hang on huge list 1.45 + let fragment = document.createDocumentFragment(); 1.46 + let choices = aList.choices; 1.47 + let selectedItems = []; 1.48 + for (let i = 0; i < choices.length; i++) { 1.49 + let choice = choices[i]; 1.50 + let item = document.createElement("richlistitem"); 1.51 + let label = document.createElement("label"); 1.52 + 1.53 + item.setAttribute("class", "option-command listitem-iconic"); 1.54 + item.setAttribute("flex", "1"); 1.55 + item.setAttribute("crop", "center"); 1.56 + label.setAttribute("value", choice.text); 1.57 + item.appendChild(label); 1.58 + item.setAttribute("oldstate", "false"); 1.59 + choice.disabled ? item.setAttribute("disabled", "true") 1.60 + : item.removeAttribute("disabled"); 1.61 + 1.62 + fragment.appendChild(item); 1.63 + 1.64 + if (choice.group) { 1.65 + item.classList.add("optgroup"); 1.66 + continue; 1.67 + } 1.68 + 1.69 + item.optionIndex = choice.optionIndex; 1.70 + item.choiceIndex = i; 1.71 + 1.72 + if (choice.inGroup) { 1.73 + item.classList.add("in-optgroup"); 1.74 + } 1.75 + 1.76 + if (choice.selected) { 1.77 + firstSelected = firstSelected || item; 1.78 + selectedItems.push(item); 1.79 + } 1.80 + } 1.81 + this._listbox.appendChild(fragment); 1.82 + 1.83 + this._container.addEventListener("click", this, false); 1.84 + window.addEventListener("MozPrecisePointer", this, false); 1.85 + this._menuPopup.show(this._positionOptions(aRect)); 1.86 + 1.87 + // Setup pre-selected items. Note, this has to happen after show. 1.88 + this._listbox.clearSelection(); 1.89 + for (let item of selectedItems) { 1.90 + this._listbox.addItemToSelection(item); 1.91 + item.setAttribute("oldstate", "true"); 1.92 + } 1.93 + this._listbox.ensureElementIsVisible(firstSelected); 1.94 + }, 1.95 + 1.96 + reset: function selectHelperReset() { 1.97 + this._updateControl(); 1.98 + while (this._listbox.hasChildNodes()) 1.99 + this._listbox.removeChild(this._listbox.lastChild); 1.100 + this._list = null; 1.101 + }, 1.102 + 1.103 + hide: function selectHelperHide() { 1.104 + if (!this._list) 1.105 + return; 1.106 + 1.107 + this._container.removeEventListener("click", this, false); 1.108 + window.removeEventListener("MozPrecisePointer", this, false); 1.109 + this._menuPopup.hide(); 1.110 + this.reset(); 1.111 + }, 1.112 + 1.113 + _positionOptions: function _positionOptions(aRect) { 1.114 + let browser = Browser.selectedBrowser; 1.115 + let p0 = browser.ptBrowserToClient(aRect.left, aRect.top); 1.116 + let p1 = browser.ptBrowserToClient(aRect.right, aRect.bottom); 1.117 + 1.118 + return { 1.119 + xPos: p0.x, 1.120 + yPos: p1.y, 1.121 + bottomAligned: false, 1.122 + leftAligned: true 1.123 + }; 1.124 + }, 1.125 + 1.126 + _updateControl: function _selectHelperUpdateControl() { 1.127 + Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceChange", { }); 1.128 + }, 1.129 + 1.130 + handleEvent: function selectHelperHandleEvent(aEvent) { 1.131 + switch (aEvent.type) { 1.132 + case "MozPrecisePointer": 1.133 + this.hide(); 1.134 + break; 1.135 + case "click": 1.136 + let item = aEvent.target; 1.137 + if (item && item.hasOwnProperty("optionIndex")) { 1.138 + if (this._list.multiple) { 1.139 + // item.selected is always true here since that's how richlistbox handles 1.140 + // mouse click events. We track our own state so that we can toggle here 1.141 + // on click events. Iniial 'oldstate' values are setup in show above. 1.142 + if (item.getAttribute("oldstate") == "true") { 1.143 + item.setAttribute("oldstate", "false"); 1.144 + } else { 1.145 + item.setAttribute("oldstate", "true"); 1.146 + } 1.147 + // Fix up selected items - richlistbox will clear selection on click events 1.148 + // so we need to set selection on the items the user has previously chosen. 1.149 + this._listbox.clearSelection(); 1.150 + for (let node of this._listbox.childNodes) { 1.151 + if (node.getAttribute("oldstate") == "true") { 1.152 + this._listbox.addItemToSelection(node); 1.153 + } 1.154 + } 1.155 + } 1.156 + // Let the form element know we've added or removed a selected item. 1.157 + this.onSelect(item.optionIndex, item.selected); 1.158 + } 1.159 + break; 1.160 + } 1.161 + }, 1.162 + 1.163 + onSelect: function selectHelperOnSelect(aIndex, aSelected) { 1.164 + Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceSelect", { 1.165 + index: aIndex, 1.166 + selected: aSelected 1.167 + }); 1.168 + if (!this._list.multiple) { 1.169 + this.hide(); 1.170 + } 1.171 + } 1.172 +};