1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/modules/SelectContentHelper.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,110 @@ 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 +const Cc = Components.classes; 1.11 +const Ci = Components.interfaces; 1.12 +const Cu = Components.utils; 1.13 + 1.14 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.15 + 1.16 +XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", 1.17 + "resource://gre/modules/BrowserUtils.jsm"); 1.18 + 1.19 +this.EXPORTED_SYMBOLS = [ 1.20 + "SelectContentHelper" 1.21 +]; 1.22 + 1.23 +this.SelectContentHelper = function (aElement, aGlobal) { 1.24 + this.element = aElement; 1.25 + this.global = aGlobal; 1.26 + this.init(); 1.27 + this.showDropDown(); 1.28 +} 1.29 + 1.30 +this.SelectContentHelper.prototype = { 1.31 + init: function() { 1.32 + this.global.addMessageListener("Forms:SelectDropDownItem", this); 1.33 + this.global.addMessageListener("Forms:DismissedDropDown", this); 1.34 + this.global.addEventListener("pagehide", this); 1.35 + }, 1.36 + 1.37 + uninit: function() { 1.38 + this.global.removeMessageListener("Forms:SelectDropDownItem", this); 1.39 + this.global.removeMessageListener("Forms:DismissedDropDown", this); 1.40 + this.global.removeEventListener("pagehide", this); 1.41 + this.element = null; 1.42 + this.global = null; 1.43 + }, 1.44 + 1.45 + showDropDown: function() { 1.46 + let rect = this._getBoundingContentRect(); 1.47 + 1.48 + this.global.sendAsyncMessage("Forms:ShowDropDown", { 1.49 + rect: rect, 1.50 + options: this._buildOptionList(), 1.51 + selectedIndex: this.element.selectedIndex, 1.52 + }); 1.53 + }, 1.54 + 1.55 + _getBoundingContentRect: function() { 1.56 + return BrowserUtils.getElementBoundingScreenRect(this.element); 1.57 + }, 1.58 + 1.59 + _buildOptionList: function() { 1.60 + return buildOptionListForChildren(this.element); 1.61 + }, 1.62 + 1.63 + receiveMessage: function(message) { 1.64 + switch (message.name) { 1.65 + case "Forms:SelectDropDownItem": 1.66 + if (this.element.selectedIndex != message.data.value) { 1.67 + this.element.selectedIndex = message.data.value; 1.68 + 1.69 + let event = this.element.ownerDocument.createEvent("Events"); 1.70 + event.initEvent("change", true, true); 1.71 + this.element.dispatchEvent(event); 1.72 + } 1.73 + 1.74 + //intentional fall-through 1.75 + case "Forms:DismissedDropDown": 1.76 + this.uninit(); 1.77 + break; 1.78 + } 1.79 + }, 1.80 + 1.81 + handleEvent: function(event) { 1.82 + switch (event.type) { 1.83 + case "pagehide": 1.84 + this.global.sendAsyncMessage("Forms:HideDropDown", {}); 1.85 + this.uninit(); 1.86 + break; 1.87 + } 1.88 + } 1.89 + 1.90 +} 1.91 + 1.92 +function buildOptionListForChildren(node) { 1.93 + let result = []; 1.94 + for (let child = node.firstChild; child; child = child.nextSibling) { 1.95 + if (child.tagName == 'OPTION' || child.tagName == 'OPTGROUP') { 1.96 + let info = { 1.97 + tagName: child.tagName, 1.98 + textContent: child.tagName == 'OPTGROUP' ? child.getAttribute("label") 1.99 + : child.textContent, 1.100 + // XXX this uses a highlight color when this is the selected element. 1.101 + // We need to suppress such highlighting in the content process to get 1.102 + // the option's correct unhighlighted color here. 1.103 + // We also need to detect default color vs. custom so that a standard 1.104 + // color does not override color: menutext in the parent. 1.105 + // backgroundColor: computedStyle.backgroundColor, 1.106 + // color: computedStyle.color, 1.107 + children: child.tagName == 'OPTGROUP' ? buildOptionListForChildren(child) : [] 1.108 + }; 1.109 + result.push(info); 1.110 + } 1.111 + } 1.112 + return result; 1.113 +}