--- a/toolkit/modules/SelectParentHelper.jsm
+++ b/toolkit/modules/SelectParentHelper.jsm
@@ -3,37 +3,52 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = [
"SelectParentHelper"
];
+const {utils: Cu} = Components;
+const { AppConstants } = Cu.import("resource://gre/modules/AppConstants.jsm");
+
// Maximum number of rows to display in the select dropdown.
const MAX_ROWS = 20;
var currentBrowser = null;
var currentMenulist = null;
var currentZoom = 1;
var closedWithEnter = false;
+//CPST
+var lastColor = "";
+var lastBackground = "";
+//END CPST
+
this.SelectParentHelper = {
+
populate: function(menulist, items, selectedIndex, zoom) {
// Clear the current contents of the popup
menulist.menupopup.textContent = "";
currentZoom = zoom;
currentMenulist = menulist;
+
populateChildren(menulist, items, selectedIndex, zoom);
},
open: function(browser, menulist, rect, isOpenedViaTouch) {
menulist.hidden = false;
currentBrowser = browser;
closedWithEnter = false;
+ //let selectedItem = menulist.selectedItem;
+ //if(selectedItem){
+ // selectedItem.style.color = lastColor;
+ // selectedItem.style.backgroundColor = lastBackground;
+ //}
this._registerListeners(browser, menulist.menupopup);
let win = browser.ownerDocument.defaultView;
// Set the maximum height to show exactly MAX_ROWS items.
let menupopup = menulist.menupopup;
let firstItem = menupopup.firstChild;
while (firstItem && firstItem.hidden) {
@@ -52,43 +67,46 @@ this.SelectParentHelper = {
menupopup.classList.toggle("isOpenedViaTouch", isOpenedViaTouch);
let constraintRect = browser.getBoundingClientRect();
constraintRect = new win.DOMRect(constraintRect.left + win.mozInnerScreenX,
constraintRect.top + win.mozInnerScreenY,
constraintRect.width, constraintRect.height);
menupopup.setConstraintRect(constraintRect);
- menupopup.openPopupAtScreenRect("after_start", rect.left, rect.top, rect.width, rect.height, false, false);
+ menupopup.openPopupAtScreenRect(AppConstants.platform == "macosx" ? "selection" : "after_start", rect.left, rect.top, rect.width, rect.height, false, false);
},
hide: function(menulist, browser) {
if (currentBrowser == browser) {
menulist.menupopup.hidePopup();
}
},
handleEvent: function(event) {
switch (event.type) {
case "mouseover":
currentBrowser.messageManager.sendAsyncMessage("Forms:MouseOver", {});
+
break;
case "mouseout":
currentBrowser.messageManager.sendAsyncMessage("Forms:MouseOut", {});
break;
case "keydown":
if (event.keyCode == event.DOM_VK_RETURN) {
closedWithEnter = true;
}
break;
case "command":
if (event.target.hasAttribute("value")) {
+ //event.target.style.color = "";
+ //event.target.style.backgroundColor = "";
let win = currentBrowser.ownerDocument.defaultView;
currentBrowser.messageManager.sendAsyncMessage("Forms:SelectDropDownItem", {
value: event.target.value,
closedWithEnter: closedWithEnter
});
}
break;
@@ -142,71 +160,62 @@ this.SelectParentHelper = {
popup.removeEventListener("mouseout", this);
browser.ownerDocument.defaultView.removeEventListener("keydown", this, true);
browser.ownerDocument.defaultView.removeEventListener("fullscreen", this, true);
browser.messageManager.removeMessageListener("Forms:UpdateDropDown", this);
},
};
-// code for working on the scaling of the padding to text size
-
function populateChildren(menulist, options, selectedIndex, zoom,
- parentElement = null, isGroupDisabled = false, adjustedTextSize = -1) {
-
+ parentElement = null, isGroupDisabled = false, adjustedTextSize = -1, addSearch = true) {
let element = menulist.menupopup;
- let adjustedTextRatio;
- let win = element.ownerDocument.defaultView;
// -1 just means we haven't calculated it yet. When we recurse through this function
// we will pass in adjustedTextSize to save on recalculations.
if (adjustedTextSize == -1) {
+ let win = element.ownerDocument.defaultView;
// Grab the computed text size and multiply it by the remote browser's fullZoom to ensure
// the popup's text size is matched with the content's. We can't just apply a CSS transform
// here as the popup's preferred size is calculated pre-transform.
let textSize = win.getComputedStyle(element).getPropertyValue("font-size");
- adjustedTextRatio = (zoom * parseFloat(textSize, 10));
- adjustedTextSize = adjustedTextRatio + "px";
+ adjustedTextSize = (zoom * parseFloat(textSize, 10)) + "px";
+
}
for (let option of options) {
let isOptGroup = (option.tagName == 'OPTGROUP');
let item = element.ownerDocument.createElement(isOptGroup ? "menucaption" : "menuitem");
item.setAttribute("label", option.textContent);
item.style.direction = option.textDirection;
item.style.fontSize = adjustedTextSize;
+
+ if(!isOptGroup && option.color != ""){
+ item.style.color = option.color;
+ }
+ if(!isOptGroup && option.backgroundColor != ""){
+ item.style.backgroundColor = option.backgroundColor;
+ }
+
item.hidden = option.display == "none" || (parentElement && parentElement.hidden);
item.setAttribute("tooltiptext", option.tooltip);
element.appendChild(item);
-
- // element.ownerDocument.getAnonymousElementByAttribute(element, attribute, value);
-
- //let menuCaption = element.ownerDocument.getAnonymousElementByAttribute(item, "class", "menu-iconic-text");
-
- //let shadowChildren = element.ownerDocument.getAnonymousNodes(element);
-
- //let textSizeValue = parseFloat(win.getComputedStyle(item).getPropertyValue("font-size"),10);
- //let padding = parseFloat(win.getComputedStyle(item).getPropertyValue("padding-top"),10);
- //let paddingRatio = parseFloat((padding / adjustedTextRatio),10);
-
- //item.style.paddingTop = (textSizeValue * paddingRatio) + "px";
- //item.style.paddingBottom = (textSizeValue * paddingRatio) + "px";
// A disabled optgroup disables all of its child options.
let isDisabled = isGroupDisabled || option.disabled;
if (isDisabled) {
item.setAttribute("disabled", "true");
}
if (isOptGroup) {
populateChildren(menulist, option.children, selectedIndex, zoom,
- item, isDisabled, adjustedTextSize);
+ item, isDisabled, adjustedTextSize, false);
} else {
if (option.index == selectedIndex) {
// We expect the parent element of the popup to be a <xul:menulist> that
// has the popuponly attribute set to "true". This is necessary in order
// for a <xul:menupopup> to act like a proper <html:select> dropdown, as
// the <xul:menulist> does things like remember state and set the
// _moz-menuactive attribute on the selected <xul:menuitem>.
menulist.selectedItem = item;
@@ -221,9 +230,82 @@ function populateChildren(menulist, opti
item.setAttribute("value", option.index);
if (parentElement) {
item.classList.add("contentSelectDropdown-ingroup")
}
}
}
+
+ // Check if this is the first time iterating through the dropdown and if list is
+ // long enough for a search element to be added.
+ if(addSearch && element.childElementCount > 40){
+
+ // Add a search text field as the first element of the dropdown
+ let searchbox = element.ownerDocument.createElement("textbox");
+ searchbox.setAttribute("type", "search");
+ searchbox.addEventListener("input", onSearchInput);
+ element.insertBefore(searchbox, element.childNodes[0]);
+ }
+
}
+
+function onSearchInput(){
+
+ let searchObj = this;
+
+ // Get input from search field, set to all lower case for comparison
+ let input = searchObj.value.toLowerCase();
+
+ // Get all items in dropdown (could be options or optgroups)
+ let menupopup = searchObj.parentElement;
+ let menuItems = menupopup.querySelectorAll("menuitem, menucaption");
+
+ // Flag used to detect any group headers with no visible options.
+ // These group headers should be hidden.
+ let allHidden = true;
+
+ // Keep a reference to the previous group header (menucaption) to go back
+ // and set to hidden if all options within are hidden.
+ let prevCaption = null;
+
+ for (let currentItem of menuItems) {
+ // Get label and tooltip (title) from option and change to
+ // lower case for comparison
+ let itemLabel = currentItem.getAttribute("label").toLowerCase();
+ let itemTooltip = currentItem.getAttribute("title").toLowerCase();
+
+ // If search input is empty, all options should be shown
+ if(input==""){
+ currentItem.setAttribute("hidden", "false");
+
+ } else if(currentItem.localName=="menucaption"){
+ if(prevCaption!=null){
+ prevCaption.setAttribute("hidden", (allHidden ? "true" : "false"));
+ }
+ prevCaption = currentItem;
+ allHidden = true;
+
+ } else{
+ if(!currentItem.classList.contains("contentSelectDropdown-ingroup") && currentItem.previousSibling.classList.contains("contentSelectDropdown-ingroup")){
+ if(prevCaption!=null){
+ prevCaption.setAttribute("hidden", (allHidden ? "true" : "false"));
+ }
+ prevCaption = null;
+ allHidden = true;
+ }
+
+ if(itemLabel.includes(input) || itemTooltip.includes(input)){
+ currentItem.setAttribute("hidden", "false");
+
+ allHidden = false;
+ } else{
+ currentItem.setAttribute("hidden", "true");
+ }
+ }
+
+ }
+ if(prevCaption!=null && allHidden){
+ prevCaption.setAttribute("hidden", (allHidden ? "true" : "false"));
+ }
+
+}