/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils", "@mozilla.org/inspector/dom-utils;1", "inIDOMUtils"); XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm"); const kStateActive = 0x00000001; // NS_EVENT_STATE_ACTIVE const kStateHover = 0x00000004; // NS_EVENT_STATE_HOVER const SUPPORTED_PROPERTIES = [ "color", "background-color", "text-shadow", ]; // A process global state for whether or not content thinks // that a while it was open, so // we'll poke a DeferredTask to update the parent sometime // in the very near future. this._updateTimer.arm(); }); this.mut.observe(this.element, {childList: true, subtree: true, attributes: true}); }, uninit() { this.element.openInParentProcess = false; this.global.removeMessageListener("Forms:SelectDropDownItem", this); this.global.removeMessageListener("Forms:DismissedDropDown", this); this.global.removeMessageListener("Forms:MouseOver", this); this.global.removeMessageListener("Forms:MouseOut", this); this.global.removeMessageListener("Forms:MouseUp", this); this.global.removeMessageListener("Forms:SearchFocused", this); this.global.removeMessageListener("Forms:BlurDropDown-Pong", this); this.global.removeEventListener("pagehide", this, { mozSystemGroup: true }); this.global.removeEventListener("mozhidedropdown", this, { mozSystemGroup: true }); this.element.removeEventListener("blur", this, { mozSystemGroup: true }); this.element.removeEventListener("transitionend", this, { mozSystemGroup: true }); this.element = null; this.global = null; this.mut.disconnect(); this._updateTimer.disarm(); this._updateTimer = null; gOpen = false; }, showDropDown() { this.element.openInParentProcess = true; this._setupPseudoClassStyles(); let rect = this._getBoundingContentRect(); let computedStyles = getComputedStyles(this.element); this._selectBackgroundColor = computedStyles.backgroundColor; this._selectColor = computedStyles.color; this._selectTextShadow = computedStyles.textShadow; this.global.sendAsyncMessage("Forms:ShowDropDown", { direction: computedStyles.direction, isOpenedViaTouch: this.isOpenedViaTouch, options: this._buildOptionList(), rect, selectedIndex: this.element.selectedIndex, selectBackgroundColor: this._selectBackgroundColor, selectColor: this._selectColor, selectTextShadow: this._selectTextShadow, uaBackgroundColor: this.uaBackgroundColor, uaColor: this.uaColor, uaSelectBackgroundColor: this.uaSelectBackgroundColor, uaSelectColor: this.uaSelectColor }); this._clearPseudoClassStyles(); gOpen = true; }, _setupPseudoClassStyles() { if (this._pseudoStylesSetup) { throw new Error("pseudo styles must not be set up yet"); } // Do all of the things that change style at once, before we read // any styles. this._pseudoStylesSetup = true; DOMUtils.addPseudoClassLock(this.element, ":focus"); let lockedDescendants = this._lockedDescendants = this.element.querySelectorAll(":checked"); for (let child of lockedDescendants) { // Selected options have the :checked pseudo-class, which // we want to disable before calculating the computed // styles since the user agent styles alter the styling // based on :checked. DOMUtils.addPseudoClassLock(child, ":checked", false); } }, _clearPseudoClassStyles() { if (!this._pseudoStylesSetup) { throw new Error("pseudo styles must be set up already"); } // Undo all of the things that change style at once, after we're // done reading styles. DOMUtils.clearPseudoClassLocks(this.element); let lockedDescendants = this._lockedDescendants; for (let child of lockedDescendants) { DOMUtils.clearPseudoClassLocks(child); } this._lockedDescendants = null; this._pseudoStylesSetup = false; }, _getBoundingContentRect() { return BrowserUtils.getElementBoundingScreenRect(this.element); }, _buildOptionList() { if (!this._pseudoStylesSetup) { throw new Error("pseudo styles must be set up"); } return buildOptionListForChildren(this.element); }, _update() { // The