diff --git a/browser/devtools/styleinspector/computed-view.js b/browser/devtools/styleinspector/computed-view.js index 3e0b61e9c389..f7e23dc843f2 100644 --- a/browser/devtools/styleinspector/computed-view.js +++ b/browser/devtools/styleinspector/computed-view.js @@ -4,7 +4,8 @@ * 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/. */ -/* globals overlays, StyleInspectorMenu */ +/* globals overlays, StyleInspectorMenu, loader, clipboardHelper, + _Iterator, StopIteration */ "use strict"; @@ -49,8 +50,7 @@ const HTML_NS = "http://www.w3.org/1999/xhtml"; * * @constructor */ -function UpdateProcess(aWin, aGenerator, aOptions) -{ +function UpdateProcess(aWin, aGenerator, aOptions) { this.win = aWin; this.iter = _Iterator(aGenerator); this.onItem = aOptions.onItem || function() {}; @@ -66,8 +66,7 @@ UpdateProcess.prototype = { /** * Schedule a new batch on the main loop. */ - schedule: function UP_schedule() - { + schedule: function() { if (this.canceled) { return; } @@ -78,8 +77,7 @@ UpdateProcess.prototype = { * Cancel the running process. onItem will not be called again, * and onCancel will be called. */ - cancel: function UP_cancel() - { + cancel: function() { if (this._timeout) { this.win.clearTimeout(this._timeout); this._timeout = 0; @@ -88,7 +86,7 @@ UpdateProcess.prototype = { this.onCancel(); }, - _timeoutHandler: function UP_timeoutHandler() { + _timeoutHandler: function() { this._timeout = null; try { this._runBatch(); @@ -104,10 +102,9 @@ UpdateProcess.prototype = { } }, - _runBatch: function Y_runBatch() - { + _runBatch: function() { let time = Date.now(); - while(!this.canceled) { + while (!this.canceled) { // Continue until iter.next() throws... let next = this.iter.next(); this.onItem(next[1]); @@ -120,9 +117,9 @@ UpdateProcess.prototype = { }; /** - * CssComputedView is a panel that manages the display of a table sorted by style. - * There should be one instance of CssComputedView per style display (of which there - * will generally only be one). + * CssComputedView is a panel that manages the display of a table + * sorted by style. There should be one instance of CssComputedView + * per style display (of which there will generally only be one). * * @param {Inspector} inspector toolbox panel * @param {Document} document The document that will contain the computed view. @@ -142,8 +139,8 @@ function CssComputedView(inspector, document, pageStyle) { this._outputParser = new OutputParser(); - let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIXULChromeRegistry); + let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"] + .getService(Ci.nsIXULChromeRegistry); this.getRTLAttr = chromeReg.isLocaleRTL("global") ? "rtl" : "ltr"; // Create bound methods. @@ -211,8 +208,7 @@ function CssComputedView(inspector, document, pageStyle) { * @param {string} aName The key to lookup. * @returns A localized version of the given key. */ -CssComputedView.l10n = function CssComputedView_l10n(aName) -{ +CssComputedView.l10n = function(aName) { try { return CssComputedView._strings.GetStringFromName(aName); } catch (ex) { @@ -251,8 +247,7 @@ CssComputedView.prototype = { this.pageStyle = pageStyle; }, - get includeBrowserStyles() - { + get includeBrowserStyles() { return this.includeBrowserStylesCheckbox.checked; }, @@ -264,8 +259,9 @@ CssComputedView.prototype = { }, /** - * Update the view with a new selected element. - * The CssComputedView panel will show the style information for the given element. + * Update the view with a new selected element. The CssComputedView panel + * will show the style information for the given element. + * * @param {NodeFront} aElement The highlighted node to get styles for. * @returns a promise that will be resolved when highlighting is complete. */ @@ -383,8 +379,7 @@ CssComputedView.prototype = { return {type, value}; }, - _createPropertyViews: function() - { + _createPropertyViews: function() { if (this._createViewsPromise) { return this._createViewsPromise; } @@ -396,7 +391,8 @@ CssComputedView.prototype = { this.numVisibleProperties = 0; let fragment = this.styleDocument.createDocumentFragment(); - this._createViewsProcess = new UpdateProcess(this.styleWindow, CssComputedView.propertyNames, { + this._createViewsProcess = new UpdateProcess( + this.styleWindow, CssComputedView.propertyNames, { onItem: (aPropertyName) => { // Per-item callback. let propView = new PropertyView(this, aPropertyName); @@ -426,8 +422,7 @@ CssComputedView.prototype = { /** * Refresh the panel content. */ - refreshPanel: function CssComputedView_refreshPanel() - { + refreshPanel: function() { if (!this.viewedElement) { return promise.resolve(); } @@ -443,12 +438,12 @@ CssComputedView.prototype = { onlyMatched: !this.includeBrowserStyles, markMatched: true }) - ]).then(([createViews, computed]) => { + ]).then(([, computed]) => { if (viewedElement !== this.viewedElement) { - return; + return promise.resolve(); } - this._matchedProperties = new Set; + this._matchedProperties = new Set(); for (let name in computed) { if (computed[name].matched) { this._matchedProperties.add(name); @@ -469,7 +464,8 @@ CssComputedView.prototype = { this._darkStripe = true; let deferred = promise.defer(); - this._refreshProcess = new UpdateProcess(this.styleWindow, this.propertyViews, { + this._refreshProcess = new UpdateProcess( + this.styleWindow, this.propertyViews, { onItem: (aPropView) => { aPropView.refresh(); }, @@ -511,8 +507,7 @@ CssComputedView.prototype = { * * @param {Event} aEvent the DOM Event object. */ - _onFilterStyles: function(aEvent) - { + _onFilterStyles: function(aEvent) { let win = this.styleWindow; if (this._filterChangedTimeout) { @@ -580,8 +575,7 @@ CssComputedView.prototype = { * * @param {Event} aEvent the DOM Event object. */ - _onIncludeBrowserStyles: function(aEvent) - { + _onIncludeBrowserStyles: function(aEvent) { this.refreshSourceFilter(); this.refreshPanel(); }, @@ -592,16 +586,14 @@ CssComputedView.prototype = { * document or one of thedocument's stylesheets. If .checked is false we * display all properties including those that come from UA stylesheets. */ - refreshSourceFilter: function CssComputedView_setSourceFilter() - { + refreshSourceFilter: function() { this._matchedProperties = null; this._sourceFilter = this.includeBrowserStyles ? CssLogic.FILTER.UA : CssLogic.FILTER.USER; }, - _onSourcePrefChanged: function CssComputedView__onSourcePrefChanged() - { + _onSourcePrefChanged: function() { for (let propView of this.propertyViews) { propView.updateSourceLinks(); } @@ -611,8 +603,7 @@ CssComputedView.prototype = { /** * The CSS as displayed by the UI. */ - createStyleViews: function CssComputedView_createStyleViews() - { + createStyleViews: function() { if (CssComputedView.propertyNames) { return; } @@ -641,8 +632,8 @@ CssComputedView.prototype = { this._createPropertyViews().then(null, e => { if (!this._isDestroyed) { - console.warn("The creation of property views was cancelled because the " + - "computed-view was destroyed before it was done creating views"); + console.warn("The creation of property views was cancelled because " + + "the computed-view was destroyed before it was done creating views"); } else { console.error(e); } @@ -654,18 +645,16 @@ CssComputedView.prototype = { * * @return {Set} If a property name is in the set, it has matching selectors. */ - get matchedProperties() - { - return this._matchedProperties || new Set; + get matchedProperties() { + return this._matchedProperties || new Set(); }, /** * Focus the window on mousedown. * - * @param aEvent The event object + * @param event The event object */ - focusWindow: function(aEvent) - { + focusWindow: function(event) { let win = this.styleDocument.defaultView; win.focus(); }, @@ -707,8 +696,8 @@ CssComputedView.prototype = { let win = this.styleDocument.defaultView; let text = win.getSelection().toString().trim(); - // Tidy up block headings by moving CSS property names and their values onto - // the same line and inserting a colon between them. + // Tidy up block headings by moving CSS property names and their + // values onto the same line and inserting a colon between them. let textArray = text.split(/[\r\n]+/); let result = ""; @@ -737,8 +726,7 @@ CssComputedView.prototype = { /** * Destructor for CssComputedView. */ - destroy: function CssComputedView_destroy() - { + destroy: function() { this.viewedElement = null; this._outputParser = null; @@ -819,8 +807,7 @@ PropertyInfo.prototype = { * @param {string} aName the CSS property name for which this PropertyView * instance will render the rules. */ -function PropertyView(aTree, aName) -{ +function PropertyView(aTree, aName) { this.tree = aTree; this.name = aName; this.getRTLAttr = aTree.getRTLAttr; @@ -864,32 +851,28 @@ PropertyView.prototype = { * @return {string} the computed style for the current property of the * currently highlighted element. */ - get value() - { + get value() { return this.propertyInfo.value; }, /** * An easy way to access the CssPropertyInfo behind this PropertyView. */ - get propertyInfo() - { + get propertyInfo() { return this._propertyInfo; }, /** * Does the property have any matched selectors? */ - get hasMatchedSelectors() - { + get hasMatchedSelectors() { return this.tree.matchedProperties.has(this.name); }, /** * Should this property be visible? */ - get visible() - { + get visible() { if (!this.tree.viewedElement) { return false; } @@ -913,8 +896,7 @@ PropertyView.prototype = { * Returns the className that should be assigned to the propertyView. * @return string */ - get propertyHeaderClassName() - { + get propertyHeaderClassName() { if (this.visible) { let isDark = this.tree._darkStripe = !this.tree._darkStripe; return isDark ? "property-view row-striped" : "property-view"; @@ -927,8 +909,7 @@ PropertyView.prototype = { * container. * @return string */ - get propertyContentClassName() - { + get propertyContentClassName() { if (this.visible) { let isDark = this.tree._darkStripe; return isDark ? "property-content row-striped" : "property-content"; @@ -940,8 +921,7 @@ PropertyView.prototype = { * Build the markup for on computed style * @return Element */ - buildMain: function PropertyView_buildMain() - { + buildMain: function() { let doc = this.tree.styleDocument; // Build the container element @@ -998,8 +978,7 @@ PropertyView.prototype = { return this.element; }, - buildSelectorContainer: function PropertyView_buildSelectorContainer() - { + buildSelectorContainer: function() { let doc = this.tree.styleDocument; let element = doc.createElementNS(HTML_NS, "div"); element.setAttribute("class", this.propertyContentClassName); @@ -1013,8 +992,7 @@ PropertyView.prototype = { /** * Refresh the panel's CSS property value. */ - refresh: function PropertyView_refresh() - { + refresh: function() { this.element.className = this.propertyHeaderClassName; this.element.nextElementSibling.className = this.propertyContentClassName; @@ -1051,8 +1029,7 @@ PropertyView.prototype = { /** * Refresh the panel matched rules. */ - refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors() - { + refreshMatchedSelectors: function() { let hasMatchedSelectors = this.hasMatchedSelectors; this.matchedSelectorsContainer.parentNode.hidden = !hasMatchedSelectors; @@ -1063,28 +1040,29 @@ PropertyView.prototype = { } if (this.matchedExpanded && hasMatchedSelectors) { - return this.tree.pageStyle.getMatchedSelectors(this.tree.viewedElement, this.name).then(matched => { - if (!this.matchedExpanded) { - return; - } + return this.tree.pageStyle + .getMatchedSelectors(this.tree.viewedElement, this.name) + .then(matched => { + if (!this.matchedExpanded) { + return promise.resolve(undefined); + } - this._matchedSelectorResponse = matched; + this._matchedSelectorResponse = matched; - return this._buildMatchedSelectors().then(() => { - this.matchedExpander.setAttribute("open", ""); - this.tree.inspector.emit("computed-view-property-expanded"); - }); - }).then(null, console.error); - } else { - this.matchedSelectorsContainer.innerHTML = ""; - this.matchedExpander.removeAttribute("open"); - this.tree.inspector.emit("computed-view-property-collapsed"); - return promise.resolve(undefined); + return this._buildMatchedSelectors().then(() => { + this.matchedExpander.setAttribute("open", ""); + this.tree.inspector.emit("computed-view-property-expanded"); + }); + }).then(null, console.error); } + + this.matchedSelectorsContainer.innerHTML = ""; + this.matchedExpander.removeAttribute("open"); + this.tree.inspector.emit("computed-view-property-collapsed"); + return promise.resolve(undefined); }, - get matchedSelectors() - { + get matchedSelectors() { return this._matchedSelectorResponse; }, @@ -1130,13 +1108,13 @@ PropertyView.prototype = { * Provide access to the matched SelectorViews that we are currently * displaying. */ - get matchedSelectorViews() - { + get matchedSelectorViews() { if (!this._matchedSelectorViews) { this._matchedSelectorViews = []; this._matchedSelectorResponse.forEach( - function matchedSelectorViews_convert(aSelectorInfo) { - this._matchedSelectorViews.push(new SelectorView(this.tree, aSelectorInfo)); + function(aSelectorInfo) { + let selectorView = new SelectorView(this.tree, aSelectorInfo); + this._matchedSelectorViews.push(selectorView); }, this); } return this._matchedSelectorViews; @@ -1146,8 +1124,7 @@ PropertyView.prototype = { * Update all the selector source links to reflect whether we're linking to * original sources (e.g. Sass files). */ - updateSourceLinks: function PropertyView_updateSourceLinks() - { + updateSourceLinks: function() { if (!this._matchedSelectorViews) { return; } @@ -1162,8 +1139,7 @@ PropertyView.prototype = { * @param {Event} aEvent Used to determine the class name of the targets click * event. */ - onMatchedToggle: function PropertyView_onMatchedToggle(aEvent) - { + onMatchedToggle: function(aEvent) { if (aEvent.shiftKey) { return; } @@ -1175,8 +1151,7 @@ PropertyView.prototype = { /** * The action when a user clicks on the MDN help link for a property. */ - mdnLinkClick: function PropertyView_mdnLinkClick(aEvent) - { + mdnLinkClick: function(aEvent) { let inspector = this.tree.inspector; if (inspector.target.tab) { @@ -1189,7 +1164,7 @@ PropertyView.prototype = { /** * Destroy this property view, removing event listeners */ - destroy: function PropertyView_destroy() { + destroy: function() { this.element.removeEventListener("dblclick", this.onMatchedToggle, false); this.element.removeEventListener("keydown", this.onKeyDown, false); this.element = null; @@ -1210,8 +1185,7 @@ PropertyView.prototype = { * @param CssComputedView aTree, the owning CssComputedView * @param aSelectorInfo */ -function SelectorView(aTree, aSelectorInfo) -{ +function SelectorView(aTree, aSelectorInfo) { this.tree = aTree; this.selectorInfo = aSelectorInfo; this._cacheStatusNames(); @@ -1245,8 +1219,7 @@ SelectorView.prototype = { * * @return {void} */ - _cacheStatusNames: function SelectorView_cacheStatusNames() - { + _cacheStatusNames: function() { if (SelectorView.STATUS_NAMES.length) { return; } @@ -1256,7 +1229,7 @@ SelectorView.prototype = { if (i > CssLogic.STATUS.UNMATCHED) { let value = CssComputedView.l10n("rule.status." + status); // Replace normal spaces with non-breaking spaces - SelectorView.STATUS_NAMES[i] = value.replace(/ /g, '\u00A0'); + SelectorView.STATUS_NAMES[i] = value.replace(/ /g, "\u00A0"); } } }, @@ -1264,21 +1237,18 @@ SelectorView.prototype = { /** * A localized version of cssRule.status */ - get statusText() - { + get statusText() { return SelectorView.STATUS_NAMES[this.selectorInfo.status]; }, /** * Get class name for selector depending on status */ - get statusClass() - { + get statusClass() { return SelectorView.CLASS_NAMES[this.selectorInfo.status - 1]; }, - get href() - { + get href() { if (this._href) { return this._href; } @@ -1287,19 +1257,15 @@ SelectorView.prototype = { return this._href; }, - get sourceText() - { + get sourceText() { return this.selectorInfo.sourceText; }, - - get value() - { + get value() { return this.selectorInfo.value; }, - get outputFragment() - { + get outputFragment() { // Sadly, because this fragment is added to the template by DOM Templater // we lose any events that are attached. This means that URLs will open in a // new window. At some point we should fix this by stopping using the @@ -1320,8 +1286,7 @@ SelectorView.prototype = { * Update the text of the source link to reflect whether we're showing * original sources or not. */ - updateSourceLink: function() - { + updateSourceLink: function() { return this.updateSource().then((oldSource) => { if (oldSource != this.source && this.tree.element) { let selector = '[sourcelocation="' + oldSource + '"]'; @@ -1337,8 +1302,7 @@ SelectorView.prototype = { /** * Update the 'source' store based on our original sources preference. */ - updateSource: function() - { + updateSource: function() { let rule = this.selectorInfo.rule; this.sheet = rule.parentStyleSheet; @@ -1373,8 +1337,7 @@ SelectorView.prototype = { /** * Open the style editor if the RETURN key was pressed. */ - maybeOpenStyleEditor: function(aEvent) - { + maybeOpenStyleEditor: function(aEvent) { let keyEvent = Ci.nsIDOMKeyEvent; if (aEvent.keyCode == keyEvent.DOM_VK_RETURN) { this.openStyleEditor(); @@ -1391,8 +1354,7 @@ SelectorView.prototype = { * * @param aEvent The click event */ - openStyleEditor: function(aEvent) - { + openStyleEditor: function(aEvent) { let inspector = this.tree.inspector; let rule = this.selectorInfo.rule; @@ -1401,15 +1363,8 @@ SelectorView.prototype = { // // If the stylesheet is a content stylesheet we send it to the style // editor else we display it in the view source window. - let sheet = rule.parentStyleSheet; - if (!sheet || sheet.isSystem) { - let contentDoc = null; - if (this.tree.viewedElement.isLocal_toBeDeprecated()) { - let rawNode = this.tree.viewedElement.rawNode(); - if (rawNode) { - contentDoc = rawNode.ownerDocument; - } - } + let parentStyleSheet = rule.parentStyleSheet; + if (!parentStyleSheet || parentStyleSheet.isSystem) { let toolbox = gDevTools.getToolbox(inspector.target); toolbox.viewSource(rule.href, rule.line); return; @@ -1447,7 +1402,7 @@ function createChild(aParent, aTag, aAttributes={}) { if (aAttributes.hasOwnProperty(attr)) { if (attr === "textContent") { elt.textContent = aAttributes[attr]; - } else if(attr === "child") { + } else if (attr === "child") { elt.appendChild(aAttributes[attr]); } else { elt.setAttribute(attr, aAttributes[attr]); diff --git a/browser/devtools/styleinspector/rule-view.js b/browser/devtools/styleinspector/rule-view.js index ac6853cf671d..de3e8ab60f01 100644 --- a/browser/devtools/styleinspector/rule-view.js +++ b/browser/devtools/styleinspector/rule-view.js @@ -5,7 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* globals overlays, Services, EventEmitter, StyleInspectorMenu, - clipboardHelper, _strings, domUtils, AutocompletePopup */ + clipboardHelper, _strings, domUtils, AutocompletePopup, loader, + osString */ "use strict"; @@ -209,7 +210,7 @@ ElementStyle.prototype = { filter: this.showUserAgentStyles ? "ua" : undefined, }).then(entries => { if (this.destroyed) { - return; + return promise.resolve(undefined); } // Make sure the dummy element has been created before continuing... @@ -236,14 +237,12 @@ ElementStyle.prototype = { // We're done with the previous list of rules. delete this._refreshRules; - - return null; }); }).then(null, e => { // populate is often called after a setTimeout, // the connection may already be closed. if (this.destroyed) { - return; + return promise.resolve(undefined); } return promiseWarn(e); }); @@ -636,7 +635,7 @@ Rule.prototype = { disabled.delete(this.style); } - let promise = aModifications.apply().then(() => { + let modificationsPromise = aModifications.apply().then(() => { let cssProps = {}; for (let cssProp of parseDeclarations(this.style.cssText)) { cssProps[cssProp.name] = cssProp; @@ -668,8 +667,8 @@ Rule.prototype = { this.elementStyle._changed(); }).then(null, promiseWarn); - this._applyingModifications = promise; - return promise; + this._applyingModifications = modificationsPromise; + return modificationsPromise; }, /** @@ -1741,7 +1740,7 @@ CssRuleView.prototype = { refreshPanel: function() { // Ignore refreshes during editing or when no element is selected. if (this.isEditing || !this._elementStyle) { - return; + return promise.resolve(undefined); } // Repopulate the element style once the current modifications are done. @@ -1893,9 +1892,10 @@ CssRuleView.prototype = { /** * Creates an expandable container in the rule view - * @param {String} aLabel The label for the container header - * @param {Boolean} isPseudo Whether or not the container will hold - * pseudo element rules + * @param {String} aLabel + * The label for the container header + * @param {Boolean} isPseudo + * Whether or not the container will hold pseudo element rules * @return {DOMNode} The container element */ createExpandableContainer: function(aLabel, isPseudo = false) { @@ -1915,44 +1915,59 @@ CssRuleView.prototype = { container.classList.add("ruleview-expandable-container"); this.element.appendChild(container); - let toggleContainerVisibility = (isPseudo, showPseudo) => { - let isOpen = twisty.getAttribute("open"); - - if (isPseudo) { - this._showPseudoElements = !!showPseudo; - - Services.prefs.setBoolPref("devtools.inspector.show_pseudo_elements", - this.showPseudoElements); - - header.classList.toggle("show-expandable-container", - this.showPseudoElements); - - isOpen = !this.showPseudoElements; - } else { - header.classList.toggle("show-expandable-container"); - } - - if (isOpen) { - twisty.removeAttribute("open"); - } else { - twisty.setAttribute("open", "true"); - } - }; - header.addEventListener("dblclick", () => { - toggleContainerVisibility(isPseudo, !this.showPseudoElements); + this._toggleContainerVisibility(twisty, header, isPseudo, + !this.showPseudoElements); }, false); + twisty.addEventListener("click", () => { - toggleContainerVisibility(isPseudo, !this.showPseudoElements); + this._toggleContainerVisibility(twisty, header, isPseudo, + !this.showPseudoElements); }, false); if (isPseudo) { - toggleContainerVisibility(isPseudo, this.showPseudoElements); + this._toggleContainerVisibility(twisty, header, isPseudo, + this.showPseudoElements); } return container; }, + /** + * Toggle the visibility of an expandable container + * @param {DOMNode} twisty + * clickable toggle DOM Node + * @param {DOMNode} header + * expandable container header DOM Node + * @param {Boolean} isPseudo + * whether or not the container will hold pseudo element rules + * @param {Boolean} showPseudo + * whether or not pseudo element rules should be displayed + */ + _toggleContainerVisibility: function(twisty, header, isPseudo, showPseudo) { + let isOpen = twisty.getAttribute("open"); + + if (isPseudo) { + this._showPseudoElements = !!showPseudo; + + Services.prefs.setBoolPref("devtools.inspector.show_pseudo_elements", + this.showPseudoElements); + + header.classList.toggle("show-expandable-container", + this.showPseudoElements); + + isOpen = !this.showPseudoElements; + } else { + header.classList.toggle("show-expandable-container"); + } + + if (isOpen) { + twisty.removeAttribute("open"); + } else { + twisty.setAttribute("open", "true"); + } + }, + _getRuleViewHeaderClassName: function(isPseudo) { let baseClassName = "theme-gutter ruleview-header"; return isPseudo ? baseClassName + " ruleview-expandable-header" :