mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Merge mozilla-central to mozilla-inbound
--HG-- extra : rebase_source : 4b15946d1de3c0e3d7fed8fc0f68b5f653d8836a
This commit is contained in:
commit
3b1e93ac5e
@ -146,9 +146,25 @@ BrowserAction.prototype = {
|
||||
badgeNode.style.backgroundColor = color || "";
|
||||
}
|
||||
|
||||
let iconURL = IconDetails.getURL(
|
||||
tabData.icon, node.ownerDocument.defaultView, this.extension);
|
||||
node.setAttribute("image", iconURL);
|
||||
const LEGACY_CLASS = "toolbarbutton-legacy-addon";
|
||||
node.classList.remove(LEGACY_CLASS);
|
||||
|
||||
|
||||
let win = node.ownerDocument.defaultView;
|
||||
let {icon, size} = IconDetails.getURL(tabData.icon, win, this.extension);
|
||||
|
||||
// If the best available icon size is not divisible by 16, check if we have
|
||||
// an 18px icon to fall back to, and trim off the padding instead.
|
||||
if (size % 16 && !icon.endsWith(".svg")) {
|
||||
let result = IconDetails.getURL(tabData.icon, win, this.extension, 18);
|
||||
|
||||
if (result.size % 18 == 0) {
|
||||
icon = result.icon;
|
||||
node.classList.add(LEGACY_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
node.setAttribute("image", icon);
|
||||
},
|
||||
|
||||
// Update the toolbar button for a given window.
|
||||
|
@ -91,7 +91,7 @@ PageAction.prototype = {
|
||||
button.setAttribute("tooltiptext", title);
|
||||
button.setAttribute("aria-label", title);
|
||||
|
||||
let icon = IconDetails.getURL(tabData.icon, window, this.extension);
|
||||
let {icon} = IconDetails.getURL(tabData.icon, window, this.extension);
|
||||
button.setAttribute("src", icon);
|
||||
}
|
||||
|
||||
|
@ -103,10 +103,29 @@ global.IconDetails = {
|
||||
|
||||
// Returns the appropriate icon URL for the given icons object and the
|
||||
// screen resolution of the given window.
|
||||
getURL(icons, window, extension, size = 18) {
|
||||
getURL(icons, window, extension, size = 16) {
|
||||
const DEFAULT = "chrome://browser/content/extension.svg";
|
||||
|
||||
return AddonManager.getPreferredIconURL({icons: icons}, size, window) || DEFAULT;
|
||||
size *= window.devicePixelRatio;
|
||||
|
||||
let bestSize = null;
|
||||
if (icons[size]) {
|
||||
bestSize = size;
|
||||
} else if (icons[2 * size]) {
|
||||
bestSize = 2 * size;
|
||||
} else {
|
||||
let sizes = Object.keys(icons)
|
||||
.map(key => parseInt(key, 10))
|
||||
.sort((a, b) => a - b);
|
||||
|
||||
bestSize = sizes.find(candidate => candidate > size) || sizes.pop();
|
||||
}
|
||||
|
||||
if (bestSize) {
|
||||
return {size: bestSize, icon: icons[bestSize]};
|
||||
}
|
||||
|
||||
return {size, icon: DEFAULT};
|
||||
},
|
||||
|
||||
convertImageDataToPNG(imageData, context) {
|
||||
|
@ -104,27 +104,56 @@ add_task(function* testDetailsObjects() {
|
||||
"2": browser.runtime.getURL("data/a.png")}},
|
||||
|
||||
// Various resolutions
|
||||
{details: {"path": {"18": "a.png", "32": "a-x2.png"}},
|
||||
{details: {"path": {"18": "a.png", "36": "a-x2.png"}},
|
||||
legacy: true,
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/a.png"),
|
||||
"2": browser.runtime.getURL("data/a-x2.png")}},
|
||||
{details: {"path": {"16": "a.png", "30": "a-x2.png"}},
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/a.png"),
|
||||
"2": browser.runtime.getURL("data/a-x2.png")}},
|
||||
{details: {"path": {"16": "16.png", "100": "100.png"}},
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/100.png"),
|
||||
"1": browser.runtime.getURL("data/16.png"),
|
||||
"2": browser.runtime.getURL("data/100.png")}},
|
||||
{details: {"path": {"2": "2.png"}},
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/2.png"),
|
||||
"2": browser.runtime.getURL("data/2.png")}},
|
||||
{details: {"path": {
|
||||
"16": "16.svg",
|
||||
"18": "18.svg"}},
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/16.svg"),
|
||||
"2": browser.runtime.getURL("data/18.svg")}},
|
||||
{details: {"path": {
|
||||
"6": "6.png",
|
||||
"18": "18.png",
|
||||
"36": "36.png",
|
||||
"48": "48.png",
|
||||
"128": "128.png"}},
|
||||
legacy: true,
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/18.png"),
|
||||
"2": browser.runtime.getURL("data/36.png")}},
|
||||
{details: {"path": {
|
||||
"16": "16.png",
|
||||
"18": "18.png",
|
||||
"32": "32.png",
|
||||
"48": "48.png",
|
||||
"128": "128.png"}},
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/18.png"),
|
||||
"2": browser.runtime.getURL("data/48.png")}},
|
||||
"1": browser.runtime.getURL("data/16.png"),
|
||||
"2": browser.runtime.getURL("data/32.png")}},
|
||||
{details: {"path": {
|
||||
"18": "18.png",
|
||||
"32": "32.png",
|
||||
"48": "48.png",
|
||||
"128": "128.png"}},
|
||||
resolutions: {
|
||||
"1": browser.runtime.getURL("data/32.png"),
|
||||
"2": browser.runtime.getURL("data/32.png")}},
|
||||
];
|
||||
|
||||
// Allow serializing ImageData objects for logging.
|
||||
@ -146,7 +175,7 @@ add_task(function* testDetailsObjects() {
|
||||
browser.browserAction.setIcon(Object.assign({tabId}, details.details));
|
||||
browser.pageAction.setIcon(Object.assign({tabId}, details.details));
|
||||
|
||||
browser.test.sendMessage("imageURL", expectedURL);
|
||||
browser.test.sendMessage("imageURL", [expectedURL, !!details.legacy]);
|
||||
});
|
||||
|
||||
// Generate a list of tests and resolutions to send back to the test
|
||||
@ -209,11 +238,14 @@ add_task(function* testDetailsObjects() {
|
||||
|
||||
extension.sendMessage("setIcon", test);
|
||||
|
||||
let imageURL = yield extension.awaitMessage("imageURL");
|
||||
let [imageURL, legacy] = yield extension.awaitMessage("imageURL");
|
||||
|
||||
let browserActionButton = document.getElementById(browserActionId);
|
||||
is(browserActionButton.getAttribute("image"), imageURL, "browser action has the correct image");
|
||||
|
||||
let isLegacy = browserActionButton.classList.contains("toolbarbutton-legacy-addon");
|
||||
is(isLegacy, legacy, "Legacy class should be present?");
|
||||
|
||||
let pageActionImage = document.getElementById(pageActionId);
|
||||
is(pageActionImage.src, imageURL, "page action has the correct image");
|
||||
}
|
||||
|
@ -576,8 +576,8 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
max-width: 16px;
|
||||
}
|
||||
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
max-width: 18px;
|
||||
}
|
||||
@ -606,9 +606,9 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon)) > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon)) > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
padding: 3px 7px;
|
||||
}
|
||||
|
||||
|
@ -601,8 +601,8 @@ toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-p
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
|
||||
max-width: 18px;
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -681,8 +681,8 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
max-width: 16px;
|
||||
}
|
||||
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon) > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
max-width: 18px;
|
||||
}
|
||||
@ -793,9 +793,9 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
border-inline-end-style: none;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon)) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon)) > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@, .toolbarbutton-legacy-addon)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
padding: calc(var(--toolbarbutton-vertical-inner-padding) + 1px) 7px;
|
||||
}
|
||||
|
||||
|
@ -144,8 +144,9 @@ ToolSidebar.prototype = {
|
||||
// Add menuitems to the alltabs menu if there are already tabs in the
|
||||
// sidebar
|
||||
for (let [id, tab] of this._tabs) {
|
||||
if (!tab.hidden) {
|
||||
this._addItemToAllTabsMenu(id, tab, tab.hasAttribute("selected"));
|
||||
let item = this._addItemToAllTabsMenu(id, tab, tab.hasAttribute("selected"));
|
||||
if (tab.hidden) {
|
||||
item.hidden = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -20,6 +20,7 @@ const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/u
|
||||
const {createChild} = require("devtools/client/inspector/shared/utils");
|
||||
const {gDevTools} = require("devtools/client/framework/devtools");
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
|
||||
|
||||
loader.lazyRequireGetter(this, "overlays",
|
||||
"devtools/client/inspector/shared/style-inspector-overlays");
|
||||
@ -148,7 +149,8 @@ function CssComputedView(inspector, document, pageStyle) {
|
||||
|
||||
this.propertyViews = [];
|
||||
|
||||
this._outputParser = new OutputParser(document);
|
||||
let cssProperties = getCssProperties(inspector.toolbox);
|
||||
this._outputParser = new OutputParser(document, cssProperties.supportsType);
|
||||
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry);
|
||||
|
@ -410,7 +410,7 @@ InspectorPanel.prototype = {
|
||||
if (Services.prefs.getBoolPref("devtools.fontinspector.enabled") &&
|
||||
this.canGetUsedFontFaces) {
|
||||
this.fontInspector = new FontInspector(this, this.panelWin);
|
||||
this.panelDoc.getElementById("sidebar-tab-fontinspector").hidden = false;
|
||||
this.sidebar.toggleTab(true, "fontinspector");
|
||||
}
|
||||
|
||||
this.layoutview = new LayoutView(this, this.panelWin);
|
||||
|
@ -14,7 +14,6 @@ const {TextProperty} =
|
||||
require("devtools/client/inspector/rules/models/text-property");
|
||||
const {promiseWarn} = require("devtools/client/inspector/shared/utils");
|
||||
const {parseDeclarations} = require("devtools/shared/css-parsing-utils");
|
||||
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "osString", function () {
|
||||
@ -55,8 +54,7 @@ function Rule(elementStyle, options) {
|
||||
this.mediaText = this.domRule.mediaText;
|
||||
}
|
||||
|
||||
const toolbox = this.elementStyle.ruleView.inspector.toolbox;
|
||||
this.cssProperties = getCssProperties(toolbox);
|
||||
this.cssProperties = this.elementStyle.ruleView.cssProperties;
|
||||
|
||||
// Populate the text properties with the style's current authoredText
|
||||
// value, and add in any disabled properties from the store.
|
||||
|
@ -16,16 +16,13 @@ const {Tools} = require("devtools/client/definitions");
|
||||
const {CssLogic} = require("devtools/shared/inspector/css-logic");
|
||||
const {ELEMENT_STYLE} = require("devtools/server/actors/styles");
|
||||
const {OutputParser} = require("devtools/client/shared/output-parser");
|
||||
const {PrefObserver, PREF_ORIG_SOURCES} =
|
||||
require("devtools/client/styleeditor/utils");
|
||||
const {ElementStyle} =
|
||||
require("devtools/client/inspector/rules/models/element-style");
|
||||
const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
|
||||
const {ElementStyle} = require("devtools/client/inspector/rules/models/element-style");
|
||||
const {Rule} = require("devtools/client/inspector/rules/models/rule");
|
||||
const {RuleEditor} =
|
||||
require("devtools/client/inspector/rules/views/rule-editor");
|
||||
const {createChild, promiseWarn} =
|
||||
require("devtools/client/inspector/shared/utils");
|
||||
const {RuleEditor} = require("devtools/client/inspector/rules/views/rule-editor");
|
||||
const {createChild, promiseWarn} = require("devtools/client/inspector/shared/utils");
|
||||
const {gDevTools} = require("devtools/client/framework/devtools");
|
||||
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
|
||||
|
||||
loader.lazyRequireGetter(this, "overlays",
|
||||
"devtools/client/inspector/shared/style-inspector-overlays");
|
||||
@ -161,7 +158,9 @@ function CssRuleView(inspector, document, store, pageStyle) {
|
||||
this.store = store || {};
|
||||
this.pageStyle = pageStyle;
|
||||
|
||||
this._outputParser = new OutputParser(document);
|
||||
this.cssProperties = getCssProperties(inspector.toolbox);
|
||||
|
||||
this._outputParser = new OutputParser(document, this.cssProperties.supportsType);
|
||||
|
||||
this._onAddRule = this._onAddRule.bind(this);
|
||||
this._onContextMenu = this._onContextMenu.bind(this);
|
||||
|
@ -9,7 +9,8 @@
|
||||
// This is more of a unit test than a mochitest-browser test, but can't be
|
||||
// tested with an xpcshell test as the output-parser requires the DOM to work.
|
||||
|
||||
var {OutputParser} = require("devtools/client/shared/output-parser");
|
||||
const {OutputParser} = require("devtools/client/shared/output-parser");
|
||||
const {initCssProperties, getCssProperties} = require("devtools/shared/fronts/css-properties");
|
||||
|
||||
const COLOR_CLASS = "color-class";
|
||||
const URL_CLASS = "url-class";
|
||||
@ -296,7 +297,12 @@ const TEST_DATA = [
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
let parser = new OutputParser(document);
|
||||
// Mock the toolbox that initCssProperties expect so we get the fallback css properties.
|
||||
let toolbox = {target: {client: {}, hasActor: () => false}};
|
||||
yield initCssProperties(toolbox);
|
||||
let cssProperties = getCssProperties(toolbox);
|
||||
|
||||
let parser = new OutputParser(document, cssProperties.supportsType);
|
||||
for (let i = 0; i < TEST_DATA.length; i++) {
|
||||
let data = TEST_DATA[i];
|
||||
info("Output-parser test data " + i + ". {" + data.name + " : " +
|
||||
|
@ -9,38 +9,15 @@ const {angleUtils} = require("devtools/client/shared/css-angle");
|
||||
const {colorUtils} = require("devtools/client/shared/css-color");
|
||||
const {getCSSLexer} = require("devtools/shared/css-lexer");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {
|
||||
ANGLE_TAKING_FUNCTIONS,
|
||||
BEZIER_KEYWORDS,
|
||||
COLOR_TAKING_FUNCTIONS,
|
||||
CSS_TYPES
|
||||
} = require("devtools/shared/css-properties-db");
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
const BEZIER_KEYWORDS = ["linear", "ease-in-out", "ease-in", "ease-out",
|
||||
"ease"];
|
||||
|
||||
// Functions that accept a color argument.
|
||||
const COLOR_TAKING_FUNCTIONS = ["linear-gradient",
|
||||
"-moz-linear-gradient",
|
||||
"repeating-linear-gradient",
|
||||
"-moz-repeating-linear-gradient",
|
||||
"radial-gradient",
|
||||
"-moz-radial-gradient",
|
||||
"repeating-radial-gradient",
|
||||
"-moz-repeating-radial-gradient",
|
||||
"drop-shadow"];
|
||||
|
||||
// Functions that accept an angle argument.
|
||||
const ANGLE_TAKING_FUNCTIONS = ["linear-gradient",
|
||||
"-moz-linear-gradient",
|
||||
"repeating-linear-gradient",
|
||||
"-moz-repeating-linear-gradient",
|
||||
"rotate",
|
||||
"rotateX",
|
||||
"rotateY",
|
||||
"rotateZ",
|
||||
"rotate3d",
|
||||
"skew",
|
||||
"skewX",
|
||||
"skewY",
|
||||
"hue-rotate"];
|
||||
|
||||
loader.lazyGetter(this, "DOMUtils", function () {
|
||||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
});
|
||||
@ -57,13 +34,20 @@ loader.lazyGetter(this, "DOMUtils", function () {
|
||||
* Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
* const {OutputParser} = require("devtools/client/shared/output-parser");
|
||||
*
|
||||
* let parser = new OutputParser(document);
|
||||
* let parser = new OutputParser(document, supportsType);
|
||||
*
|
||||
* parser.parseCssProperty("color", "red"); // Returns document fragment.
|
||||
*
|
||||
* @param {Document} document Used to create DOM nodes.
|
||||
* @param {Function} supportsTypes A function that returns a boolean when asked if a css
|
||||
* property name supports a given css type.
|
||||
* The function is executed like supportsType("color", CSS_TYPES.COLOR) where CSS_TYPES is
|
||||
* defined in devtools/shared/css-properties-db.js
|
||||
*/
|
||||
function OutputParser(document) {
|
||||
function OutputParser(document, supportsType) {
|
||||
this.parsed = [];
|
||||
this.doc = document;
|
||||
this.supportsType = supportsType;
|
||||
this.colorSwatches = new WeakMap();
|
||||
this.angleSwatches = new WeakMap();
|
||||
this._onColorSwatchMouseDown = this._onColorSwatchMouseDown.bind(this);
|
||||
@ -89,12 +73,10 @@ OutputParser.prototype = {
|
||||
parseCssProperty: function (name, value, options = {}) {
|
||||
options = this._mergeOptions(options);
|
||||
|
||||
options.expectCubicBezier =
|
||||
safeCssPropertySupportsType(name, DOMUtils.TYPE_TIMING_FUNCTION);
|
||||
options.expectCubicBezier = this.supportsType(name, CSS_TYPES.TIMING_FUNCTION);
|
||||
options.expectFilter = name === "filter";
|
||||
options.supportsColor =
|
||||
safeCssPropertySupportsType(name, DOMUtils.TYPE_COLOR) ||
|
||||
safeCssPropertySupportsType(name, DOMUtils.TYPE_GRADIENT);
|
||||
options.supportsColor = this.supportsType(name, CSS_TYPES.COLOR) ||
|
||||
this.supportsType(name, CSS_TYPES.GRADIENT);
|
||||
|
||||
// The filter property is special in that we want to show the
|
||||
// swatch even if the value is invalid, because this way the user
|
||||
@ -681,20 +663,3 @@ OutputParser.prototype = {
|
||||
return defaults;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper for DOMUtils.cssPropertySupportsType that ignores invalid
|
||||
* properties.
|
||||
*
|
||||
* @param {String} name The property name.
|
||||
* @param {number} type The type tested for support.
|
||||
* @return {Boolean} Whether the property supports the type.
|
||||
* If the property is unknown, false is returned.
|
||||
*/
|
||||
function safeCssPropertySupportsType(name, type) {
|
||||
try {
|
||||
return DOMUtils.cssPropertySupportsType(name, type);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var {OutputParser} = require("devtools/client/shared/output-parser");
|
||||
const {OutputParser} = require("devtools/client/shared/output-parser");
|
||||
const {initCssProperties, getCssProperties} = require("devtools/shared/fronts/css-properties");
|
||||
|
||||
add_task(function* () {
|
||||
yield addTab("about:blank");
|
||||
@ -15,7 +16,12 @@ function* performTest() {
|
||||
let [host, , doc] = yield createHost("bottom", "data:text/html," +
|
||||
"<h1>browser_outputParser.js</h1><div></div>");
|
||||
|
||||
let parser = new OutputParser(doc);
|
||||
// Mock the toolbox that initCssProperties expect so we get the fallback css properties.
|
||||
let toolbox = {target: {client: {}, hasActor: () => false}};
|
||||
yield initCssProperties(toolbox);
|
||||
let cssProperties = getCssProperties(toolbox);
|
||||
|
||||
let parser = new OutputParser(doc, cssProperties.supportsType);
|
||||
testParseCssProperty(doc, parser);
|
||||
testParseCssVar(doc, parser);
|
||||
testParseURL(doc, parser);
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { Cc, Ci } = require("chrome");
|
||||
|
||||
loader.lazyGetter(this, "DOMUtils", () => {
|
||||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
@ -13,32 +13,40 @@ loader.lazyGetter(this, "DOMUtils", () => {
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const { ActorClassWithSpec, Actor } = protocol;
|
||||
const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
|
||||
const clientCssDatabase = require("devtools/shared/css-properties-db")
|
||||
const { CSS_PROPERTIES, CSS_TYPES } = require("devtools/shared/css-properties-db");
|
||||
|
||||
var CssPropertiesActor = exports.CssPropertiesActor = ActorClassWithSpec(cssPropertiesSpec, {
|
||||
exports.CssPropertiesActor = ActorClassWithSpec(cssPropertiesSpec, {
|
||||
typeName: "cssProperties",
|
||||
|
||||
initialize: function(conn, parent) {
|
||||
initialize(conn, parent) {
|
||||
Actor.prototype.initialize.call(this, conn);
|
||||
this.parent = parent;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
destroy() {
|
||||
Actor.prototype.destroy.call(this);
|
||||
},
|
||||
|
||||
getCSSDatabase: function() {
|
||||
getCSSDatabase() {
|
||||
const db = {};
|
||||
const properties = DOMUtils.getCSSPropertyNames(DOMUtils.INCLUDE_ALIASES);
|
||||
|
||||
properties.forEach(name => {
|
||||
// In order to maintain any backwards compatible changes when debugging
|
||||
// older clients, take the definition from the static database in the
|
||||
// devtools client, and fill it in with the most recent property
|
||||
// definition from the server.
|
||||
const clientDefinition = clientCssDatabase[name] || {};
|
||||
// Get the list of CSS types this property supports.
|
||||
let supports = [];
|
||||
for (let type in CSS_TYPES) {
|
||||
if (safeCssPropertySupportsType(name, DOMUtils["TYPE_" + type])) {
|
||||
supports.push(CSS_TYPES[type]);
|
||||
}
|
||||
}
|
||||
|
||||
// In order to maintain any backwards compatible changes when debugging older
|
||||
// clients, take the definition from the static CSS properties database, and fill it
|
||||
// in with the most recent property definition from the server.
|
||||
const clientDefinition = CSS_PROPERTIES[name] || {};
|
||||
const serverDefinition = {
|
||||
isInherited: DOMUtils.isInheritedProperty(name)
|
||||
isInherited: DOMUtils.isInheritedProperty(name),
|
||||
supports
|
||||
};
|
||||
db[name] = Object.assign(clientDefinition, serverDefinition);
|
||||
});
|
||||
@ -65,4 +73,21 @@ function isCssPropertyKnown(name) {
|
||||
}
|
||||
}
|
||||
|
||||
exports.isCssPropertyKnown = isCssPropertyKnown
|
||||
exports.isCssPropertyKnown = isCssPropertyKnown;
|
||||
|
||||
/**
|
||||
* A wrapper for DOMUtils.cssPropertySupportsType that ignores invalid
|
||||
* properties.
|
||||
*
|
||||
* @param {String} name The property name.
|
||||
* @param {number} type The type tested for support.
|
||||
* @return {Boolean} Whether the property supports the type.
|
||||
* If the property is unknown, false is returned.
|
||||
*/
|
||||
function safeCssPropertySupportsType(name, type) {
|
||||
try {
|
||||
return DOMUtils.cssPropertySupportsType(name, type);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,7 @@
|
||||
const { FrontClassWithSpec, Front } = require("devtools/shared/protocol");
|
||||
const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { CSS_PROPERTIES } = require("devtools/shared/css-properties-db");
|
||||
|
||||
/**
|
||||
* Build up a regular expression that matches a CSS variable token. This is an
|
||||
@ -49,6 +50,8 @@ exports.CssPropertiesFront = CssPropertiesFront;
|
||||
/**
|
||||
* Ask questions to a CSS database. This class does not care how the database
|
||||
* gets loaded in, only the questions that you can ask to it.
|
||||
* Prototype functions are bound to 'this' so they can be passed around as helper
|
||||
* functions.
|
||||
*
|
||||
* @param {Array} propertiesList
|
||||
* A list of known properties.
|
||||
@ -58,10 +61,10 @@ exports.CssPropertiesFront = CssPropertiesFront;
|
||||
*/
|
||||
function CssProperties(properties) {
|
||||
this.properties = properties;
|
||||
// Bind isKnown and isInherited so it can be passed around to helper
|
||||
// functions.
|
||||
|
||||
this.isKnown = this.isKnown.bind(this);
|
||||
this.isInherited = this.isInherited.bind(this);
|
||||
this.supportsType = this.supportsType.bind(this);
|
||||
}
|
||||
|
||||
CssProperties.prototype = {
|
||||
@ -69,16 +72,33 @@ CssProperties.prototype = {
|
||||
* Checks to see if the property is known by the browser. This function has
|
||||
* `this` already bound so that it can be passed around by reference.
|
||||
*
|
||||
* @param {String} property
|
||||
* The property name to be checked.
|
||||
* @param {String} property The property name to be checked.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isKnown(property) {
|
||||
return !!this.properties[property] || isCssVariable(property);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks to see if the property is an inherited one.
|
||||
*
|
||||
* @param {String} property The property name to be checked.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isInherited(property) {
|
||||
return this.properties[property] && this.properties[property].isInherited;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the property supports the given CSS type.
|
||||
* CSS types should come from devtools/shared/css-properties-db.js' CSS_TYPES.
|
||||
*
|
||||
* @param {String} property The property to be checked.
|
||||
* @param {Number} type One of the type values from CSS_TYPES.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
supportsType(property, type) {
|
||||
return this.properties[property] && this.properties[property].supports.includes(type);
|
||||
}
|
||||
};
|
||||
|
||||
@ -103,15 +123,28 @@ exports.initCssProperties = Task.async(function* (toolbox) {
|
||||
|
||||
let db, front;
|
||||
|
||||
// Get the list dynamically if the cssProperties exists.
|
||||
// Get the list dynamically if the cssProperties actor exists.
|
||||
if (toolbox.target.hasActor("cssProperties")) {
|
||||
front = CssPropertiesFront(client, toolbox.target.form);
|
||||
db = yield front.getCSSDatabase();
|
||||
|
||||
// Even if the target has the cssProperties actor, it may not be the latest version.
|
||||
// So, the "supports" data may be missing.
|
||||
// Start with the server's list (because that's the correct one), and add the supports
|
||||
// information if required.
|
||||
if (!db.color.supports) {
|
||||
for (let name in db) {
|
||||
if (typeof CSS_PROPERTIES[name] === "object") {
|
||||
db[name].supports = CSS_PROPERTIES[name].supports;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The target does not support this actor, so require a static list of
|
||||
// supported properties.
|
||||
db = require("devtools/shared/css-properties-db");
|
||||
// The target does not support this actor, so require a static list of supported
|
||||
// properties.
|
||||
db = CSS_PROPERTIES;
|
||||
}
|
||||
|
||||
const cssProperties = new CssProperties(db);
|
||||
cachedCssProperties.set(client, {cssProperties, front});
|
||||
return {cssProperties, front};
|
||||
|
@ -16,11 +16,10 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_type"
|
||||
android:layout_width="@dimen/favicon_bg"
|
||||
android:layout_height="@dimen/favicon_bg"
|
||||
android:layout_margin="16dp"
|
||||
android:padding="2dp"
|
||||
android:scaleType="center"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_margin="20dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center_vertical"
|
||||
tools:src="@drawable/cloud"/>
|
||||
|
||||
|
@ -79,6 +79,13 @@
|
||||
}
|
||||
},
|
||||
|
||||
"incognito": {
|
||||
"type": "string",
|
||||
"enum": ["spanning"],
|
||||
"optional": true,
|
||||
"onError": "warn"
|
||||
},
|
||||
|
||||
"background": {
|
||||
"choices": [
|
||||
{
|
||||
|
@ -0,0 +1,27 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
|
||||
add_task(function* test_manifest_incognito() {
|
||||
let normalized = yield normalizeManifest({
|
||||
"incognito": "spanning",
|
||||
});
|
||||
|
||||
equal(normalized.error, undefined, "Should not have an error");
|
||||
equal(normalized.errors.length, 0, "Should not have warnings");
|
||||
equal(normalized.value.incognito,
|
||||
"spanning",
|
||||
"Should have the expected incognito string");
|
||||
|
||||
normalized = yield normalizeManifest({
|
||||
"incognito": "split",
|
||||
});
|
||||
|
||||
equal(normalized.error, undefined, "Should not have an error");
|
||||
Assert.deepEqual(normalized.errors,
|
||||
['Error processing incognito: Invalid enumeration value "split"'],
|
||||
"Should have the expected warning");
|
||||
equal(normalized.value.incognito, null,
|
||||
"Invalid incognito string should be omitted");
|
||||
});
|
@ -11,6 +11,7 @@ skip-if = toolkit == 'gonk' || appname == "thunderbird"
|
||||
[test_ext_contexts.js]
|
||||
[test_ext_json_parser.js]
|
||||
[test_ext_manifest_content_security_policy.js]
|
||||
[test_ext_manifest_incognito.js]
|
||||
[test_ext_schemas.js]
|
||||
[test_getAPILevelForWindow.js]
|
||||
[test_native_messaging.js]
|
||||
|
@ -28,15 +28,33 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=360220
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/** Test for Bug 360220 **/
|
||||
|
||||
var menulist = document.getElementById("menulist");
|
||||
var secondItem = document.getElementById("secondItem");
|
||||
menulist.selectedItem = secondItem;
|
||||
|
||||
ok(menulist.label == "bar", "second item was not selected");
|
||||
is(menulist.label, "bar", "second item was not selected");
|
||||
|
||||
let mutObserver = new MutationObserver(() => {
|
||||
is(menulist.label, "new label", "menulist label was not updated to the label of its selected item");
|
||||
done();
|
||||
});
|
||||
mutObserver.observe(menulist, { attributeFilter: ['label'] });
|
||||
secondItem.label = "new label";
|
||||
ok(menulist.label == "new label", "menulist label was not updated to the label of its selected item");
|
||||
|
||||
let failureTimeout = setTimeout(function() {
|
||||
ok(false, "menulist label should have updated");
|
||||
done();
|
||||
}, 2000);
|
||||
|
||||
function done() {
|
||||
mutObserver.disconnect();
|
||||
clearTimeout(failureTimeout);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
|
@ -84,13 +84,6 @@ SimpleTest.waitForExplicitFinish();
|
||||
function testtag_menulists()
|
||||
{
|
||||
testtag_menulist_UI_start($("menulist"), false);
|
||||
testtag_menulist_UI_start($("menulist-editable"), true);
|
||||
|
||||
// bug 566154, the menulist width should account for vertical scrollbar
|
||||
ok(document.getElementById("menulist-size").getBoundingClientRect().width >= 210,
|
||||
"menulist popup width includes scrollbar width");
|
||||
|
||||
$("menulist").open = true;
|
||||
}
|
||||
|
||||
function testtag_menulist_UI_start(element, editable)
|
||||
@ -104,11 +97,25 @@ function testtag_menulist_UI_start(element, editable)
|
||||
|
||||
// test the interfaces that menulist implements
|
||||
test_nsIDOMXULMenuListElement(element, testprefix, editable);
|
||||
}
|
||||
|
||||
function testtag_menulist_UI_finish(element, editable)
|
||||
{
|
||||
element.value = "";
|
||||
|
||||
test_nsIDOMXULSelectControlElement(element, "menuitem",
|
||||
editable ? "editable" : null);
|
||||
|
||||
if (!editable) {
|
||||
testtag_menulist_UI_start($("menulist-editable"), true);
|
||||
}
|
||||
else {
|
||||
// bug 566154, the menulist width should account for vertical scrollbar
|
||||
ok(document.getElementById("menulist-size").getBoundingClientRect().width >= 210,
|
||||
"menulist popup width includes scrollbar width");
|
||||
|
||||
$("menulist").open = true;
|
||||
}
|
||||
}
|
||||
|
||||
function test_nsIDOMXULMenuListElement(element, testprefix, editable)
|
||||
@ -152,6 +159,7 @@ function test_nsIDOMXULMenuListElement(element, testprefix, editable)
|
||||
element.selectedIndex = 1;
|
||||
is(element.image, "", testprefix + " image set to selected");
|
||||
is(element.description, "", testprefix + " description set to selected");
|
||||
test_nsIDOMXULMenuListElement_finish(element, testprefix, editable);
|
||||
}
|
||||
else {
|
||||
element.selectedIndex = 1;
|
||||
@ -165,27 +173,66 @@ function test_nsIDOMXULMenuListElement(element, testprefix, editable)
|
||||
is(element.description, "This is the third description", testprefix + " description set to selected again");
|
||||
|
||||
// check that changing the properties of the selected item changes the menulist's properties
|
||||
thirditem.label = "Item Number Three";
|
||||
is(element.label, "Item Number Three", testprefix + " label modified");
|
||||
thirditem.value = "item-three";
|
||||
is(element.value, "item-three", testprefix + " value modified");
|
||||
thirditem.image = "smile.png";
|
||||
is(element.image, "smile.png", testprefix + " image modified");
|
||||
thirditem.setAttribute("description", "Changed description");
|
||||
is(element.description, "Changed description", testprefix + " description modified");
|
||||
seconditem.label = "Changed Label 2";
|
||||
is(element.label, "Item Number Three", testprefix + " label of another item modified");
|
||||
let properties = [{attr: "label", value: "Item Number Three"},
|
||||
{attr: "value", value: "item-three"},
|
||||
{attr: "image", value: "smile.png"},
|
||||
{attr: "description", value: "Changed description"}];
|
||||
test_nsIDOMXULMenuListElement_properties(element, testprefix, editable, thirditem, properties);
|
||||
}
|
||||
}
|
||||
|
||||
element.selectedIndex = 0;
|
||||
is(element.image, "", testprefix + " image set to selected with no image");
|
||||
is(element.description, "", testprefix + " description set to selected with no description");
|
||||
function test_nsIDOMXULMenuListElement_properties(element, testprefix, editable, thirditem, properties)
|
||||
{
|
||||
let {attr, value} = properties.shift();
|
||||
let last = (properties.length == 0);
|
||||
|
||||
let mutObserver = new MutationObserver(() => {
|
||||
is(element.getAttribute(attr), value, `${testprefix} ${attr} modified`);
|
||||
done();
|
||||
});
|
||||
mutObserver.observe(element, { attributeFilter: [attr] });
|
||||
|
||||
let failureTimeout = setTimeout(() => {
|
||||
ok(false, `${testprefix} ${attr} should have updated`);
|
||||
done();
|
||||
}, 2000);
|
||||
|
||||
function done()
|
||||
{
|
||||
clearTimeout(failureTimeout);
|
||||
mutObserver.disconnect();
|
||||
if (!last) {
|
||||
test_nsIDOMXULMenuListElement_properties(element, testprefix, editable, thirditem, properties);
|
||||
}
|
||||
else {
|
||||
test_nsIDOMXULMenuListElement_unselected(element, testprefix, editable, thirditem);
|
||||
}
|
||||
}
|
||||
|
||||
thirditem.setAttribute(attr, value)
|
||||
}
|
||||
|
||||
function test_nsIDOMXULMenuListElement_unselected(element, testprefix, editable, thirditem)
|
||||
{
|
||||
let seconditem = thirditem.previousElementSibling;
|
||||
seconditem.label = "Changed Label 2";
|
||||
is(element.label, "Item Number Three", testprefix + " label of another item modified");
|
||||
|
||||
element.selectedIndex = 0;
|
||||
is(element.image, "", testprefix + " image set to selected with no image");
|
||||
is(element.description, "", testprefix + " description set to selected with no description");
|
||||
test_nsIDOMXULMenuListElement_finish(element, testprefix, editable);
|
||||
}
|
||||
|
||||
function test_nsIDOMXULMenuListElement_finish(element, testprefix, editable)
|
||||
{
|
||||
// check the removeAllItems method
|
||||
element.appendItem("An Item", "anitem");
|
||||
element.appendItem("Another Item", "anotheritem");
|
||||
element.removeAllItems();
|
||||
is(element.itemCount, 0, testprefix + " removeAllItems");
|
||||
|
||||
testtag_menulist_UI_finish(element, editable);
|
||||
}
|
||||
|
||||
function test_menulist_open(element, scroller)
|
||||
|
@ -1025,7 +1025,6 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
|
||||
<implementation implements="nsIAutoCompletePopup">
|
||||
<field name="_currentIndex">0</field>
|
||||
<field name="_rowHeight">0</field>
|
||||
<field name="_rlbAnimated">false</field>
|
||||
|
||||
<!-- =================== nsIAutoCompletePopup =================== -->
|
||||
@ -1165,10 +1164,8 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
// Default the height to 0 if we have no rows to show
|
||||
let height = 0;
|
||||
if (numRows) {
|
||||
if (!this._rowHeight) {
|
||||
let firstRowRect = rows[0].getBoundingClientRect();
|
||||
this._rowHeight = firstRowRect.height;
|
||||
|
||||
let firstRowRect = rows[0].getBoundingClientRect();
|
||||
if (this._rlbPadding == undefined) {
|
||||
let style = window.getComputedStyle(this.richlistbox);
|
||||
|
||||
let transition = style.transitionProperty;
|
||||
@ -1177,14 +1174,20 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
let paddingTop = parseInt(style.paddingTop) || 0;
|
||||
let paddingBottom = parseInt(style.paddingBottom) || 0;
|
||||
this._rlbPadding = paddingTop + paddingBottom;
|
||||
|
||||
// Set a fixed max-height to avoid flicker when growing the panel.
|
||||
this.richlistbox.style.maxHeight =
|
||||
((this._rowHeight * this.maxRows) + this._rlbPadding) + "px";
|
||||
}
|
||||
|
||||
if (numRows > this.maxRows) {
|
||||
// Set a fixed max-height to avoid flicker when growing the panel.
|
||||
let lastVisibleRowRect = rows[this.maxRows - 1].getBoundingClientRect();
|
||||
let visibleHeight = lastVisibleRowRect.bottom - firstRowRect.top;
|
||||
this.richlistbox.style.maxHeight =
|
||||
visibleHeight + this._rlbPadding + "px";
|
||||
}
|
||||
|
||||
let lastRowRect = rows[numRows - 1].getBoundingClientRect();
|
||||
// Calculate the height to have the first row to last row shown
|
||||
height = (this._rowHeight * numRows) + this._rlbPadding;
|
||||
height = lastRowRect.bottom - firstRowRect.top +
|
||||
this._rlbPadding;
|
||||
}
|
||||
|
||||
let animate = this._rlbAnimated &&
|
||||
|
@ -66,10 +66,11 @@
|
||||
</handler>
|
||||
</handlers>
|
||||
|
||||
<implementation implements="nsIDOMXULMenuListElement, nsIDOMEventListener">
|
||||
<implementation implements="nsIDOMXULMenuListElement">
|
||||
<constructor>
|
||||
this.mInputField = null;
|
||||
this.mSelectedInternal = null;
|
||||
this.mAttributeObserver = null;
|
||||
this.menuBoxObject = this.boxObject;
|
||||
this.setInitialSelection();
|
||||
</constructor>
|
||||
@ -211,39 +212,29 @@
|
||||
|
||||
if (oldval) {
|
||||
oldval.removeAttribute('selected');
|
||||
if (document instanceof Components.interfaces.nsIDOMXULDocument) {
|
||||
document.removeBroadcastListenerFor(oldval, this, "value");
|
||||
document.removeBroadcastListenerFor(oldval, this, "label");
|
||||
document.removeBroadcastListenerFor(oldval, this, "image");
|
||||
document.removeBroadcastListenerFor(oldval, this, "description");
|
||||
}
|
||||
else
|
||||
oldval.removeEventListener("DOMAttrModified", this, false);
|
||||
this.mAttributeObserver.disconnect();
|
||||
}
|
||||
|
||||
this.mSelectedInternal = val;
|
||||
let attributeFilter = ["value", "label", "image", "description"];
|
||||
if (val) {
|
||||
val.setAttribute('selected', 'true');
|
||||
this.setAttribute('value', val.getAttribute('value'));
|
||||
this.setAttribute('image', val.getAttribute('image'));
|
||||
this.setAttribute('label', val.getAttribute('label'));
|
||||
this.setAttribute('description', val.getAttribute('description'));
|
||||
// DOMAttrModified listeners slow down setAttribute calls within
|
||||
// the document, see bug 395496
|
||||
if (document instanceof Components.interfaces.nsIDOMXULDocument) {
|
||||
document.addBroadcastListenerFor(val, this, "value");
|
||||
document.addBroadcastListenerFor(val, this, "label");
|
||||
document.addBroadcastListenerFor(val, this, "image");
|
||||
document.addBroadcastListenerFor(val, this, "description");
|
||||
for (let attr of attributeFilter) {
|
||||
if (val.hasAttribute(attr)) {
|
||||
this.setAttribute(attr, val.getAttribute(attr));
|
||||
}
|
||||
else {
|
||||
this.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
else
|
||||
val.addEventListener("DOMAttrModified", this, false);
|
||||
|
||||
this.mAttributeObserver = new MutationObserver(this.handleMutation.bind(this));
|
||||
this.mAttributeObserver.observe(val, { attributeFilter });
|
||||
}
|
||||
else {
|
||||
this.removeAttribute('value');
|
||||
this.removeAttribute('image');
|
||||
this.removeAttribute('label');
|
||||
this.removeAttribute('description');
|
||||
for (let attr of attributeFilter) {
|
||||
this.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
var event = document.createEvent("Events");
|
||||
@ -259,19 +250,26 @@
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<method name="handleEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<method name="handleMutation">
|
||||
<parameter name="aRecords"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (aEvent.type == "DOMAttrModified" &&
|
||||
aEvent.target == this.mSelectedInternal) {
|
||||
var attrName = aEvent.attrName;
|
||||
switch (attrName) {
|
||||
case "value":
|
||||
case "label":
|
||||
case "image":
|
||||
case "description":
|
||||
this.setAttribute(attrName, aEvent.newValue);
|
||||
for (let record of aRecords) {
|
||||
let t = record.target;
|
||||
if (t == this.mSelectedInternal) {
|
||||
let attrName = record.attributeName;
|
||||
switch (attrName) {
|
||||
case "value":
|
||||
case "label":
|
||||
case "image":
|
||||
case "description":
|
||||
if (t.hasAttribute(attrName)) {
|
||||
this.setAttribute(attrName, t.getAttribute(attrName));
|
||||
}
|
||||
else {
|
||||
this.removeAttribute(attrName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
@ -384,15 +382,8 @@
|
||||
|
||||
<destructor>
|
||||
<![CDATA[
|
||||
if (this.mSelectedInternal) {
|
||||
if (document instanceof Components.interfaces.nsIDOMXULDocument) {
|
||||
document.removeBroadcastListenerFor(this.mSelectedInternal, this, "value");
|
||||
document.removeBroadcastListenerFor(this.mSelectedInternal, this, "label");
|
||||
document.removeBroadcastListenerFor(this.mSelectedInternal, this, "image");
|
||||
document.removeBroadcastListenerFor(this.mSelectedInternal, this, "description");
|
||||
}
|
||||
else
|
||||
this.mSelectedInternal.removeEventListener("DOMAttrModified", this, false);
|
||||
if (this.mAttributeObserver) {
|
||||
this.mAttributeObserver.disconnect();
|
||||
}
|
||||
]]>
|
||||
</destructor>
|
||||
|
Loading…
Reference in New Issue
Block a user