diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js b/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js new file mode 100644 index 000000000..0d7240557 --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.VisualStyleSelectorSection = class VisualStyleSelectorSection extends WebInspector.DetailsSection +{ + constructor() + { + let selectorSection = {element: document.createElement("div")}; + selectorSection.element.classList.add("selectors"); + + let controlElement = document.createElement("div"); + controlElement.classList.add("controls"); + + super("visual-style-selector-section", WebInspector.UIString("Style Rules"), [selectorSection], controlElement); + + this._nodeStyles = null; + + this._currentSelectorElement = document.createElement("div"); + this._currentSelectorElement.classList.add("current-selector"); + + let currentSelectorIconElement = document.createElement("img"); + currentSelectorIconElement.classList.add("icon"); + this._currentSelectorElement.appendChild(currentSelectorIconElement); + + this._currentSelectorText = document.createElement("span"); + this._currentSelectorElement.appendChild(this._currentSelectorText); + + this._headerElement.appendChild(this._currentSelectorElement); + + let selectorListElement = document.createElement("ol"); + selectorListElement.classList.add("selector-list"); + selectorSection.element.appendChild(selectorListElement); + + this._selectors = new WebInspector.TreeOutline(selectorListElement); + this._selectors.disclosureButtons = false; + this._selectors.addEventListener(WebInspector.TreeOutline.Event.SelectionDidChange, this._selectorChanged, this); + + this._newInspectorRuleSelector = null; + + let addGlyphElement = useSVGSymbol("Images/Plus13.svg", "visual-style-selector-section-add-rule", WebInspector.UIString("Add new rule")); + addGlyphElement.addEventListener("click", this._addNewRule.bind(this)); + controlElement.appendChild(addGlyphElement); + + this._headerElement.addEventListener("mouseover", this._handleMouseOver.bind(this)); + this._headerElement.addEventListener("mouseout", this._handleMouseOut.bind(this)); + } + + // Public + + update(nodeStyles) + { + let style = this.currentStyle(); + if (style) + this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] = style; + + if (nodeStyles) + this._nodeStyles = nodeStyles; + + if (!this._nodeStyles) + return; + + this._selectors.removeChildren(); + let previousRule = null; + + // Pseudo Styles + let pseudoRules = []; + let pseudoElements = this._nodeStyles.pseudoElements; + for (let pseudoIdentifier in pseudoElements) + pseudoRules = pseudoRules.concat(pseudoElements[pseudoIdentifier].matchedRules); + + let orderedPseudoRules = uniqueOrderedRules(pseudoRules); + // Reverse the array to ensure that splicing the array will not mess with the order. + if (orderedPseudoRules.length) + orderedPseudoRules.reverse(); + + function createSelectorItem(style, title, subtitle) { + let selector = new WebInspector.VisualStyleSelectorTreeItem(this, style, title, subtitle); + selector.addEventListener(WebInspector.VisualStyleSelectorTreeItem.Event.CheckboxChanged, this._treeElementCheckboxToggled, this); + this._selectors.appendChild(selector); + + if (style.isInspectorRule() && this._newInspectorRuleSelector === style.selectorText && !style.hasProperties()) { + selector.select(true); + selector.element.scrollIntoView(); + this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] = style; + this._newInspectorRuleSelector = null; + return; + } + + if (this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] === style) { + selector.select(true); + selector.element.scrollIntoView(); + } + } + + function uniqueOrderedRules(orderedRules) + { + if (!orderedRules || !orderedRules.length) + return new Array; + + let uniqueRules = new Map; + for (let rule of orderedRules) { + if (!uniqueRules.has(rule.id)) + uniqueRules.set(rule.id, rule); + } + return Array.from(uniqueRules.values()); + } + + function insertAllMatchingPseudoRules(force) + { + if (!orderedPseudoRules.length) + return; + + if (force) { + for (let i = orderedPseudoRules.length - 1; i >= 0; --i) { + let pseudoRule = orderedPseudoRules[i]; + createSelectorItem.call(this, pseudoRule.style, pseudoRule.selectorText, pseudoRule.mediaText); + } + orderedPseudoRules = []; + } + + if (!previousRule) + return; + + for (let i = orderedPseudoRules.length - 1; i >= 0; --i) { + let pseudoRule = orderedPseudoRules[i]; + if (!pseudoRule.selectorIsGreater(previousRule.mostSpecificSelector)) + continue; + + createSelectorItem.call(this, pseudoRule.style, pseudoRule.selectorText, pseudoRule.mediaText); + previousRule = pseudoRule; + orderedPseudoRules.splice(i, 1); + } + } + + if (this._nodeStyles.inlineStyle) { + if (!this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol]) + this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] = this._nodeStyles.inlineStyle; + + // Inline Style + createSelectorItem.call(this, this._nodeStyles.inlineStyle, WebInspector.UIString("This Element")); + } else if (!this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol]) + this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] = this._nodeStyles.matchedRules[0].style; + + // Matched Rules + for (let rule of uniqueOrderedRules(this._nodeStyles.matchedRules)) { + if (rule.type === WebInspector.CSSStyleSheet.Type.UserAgent) { + insertAllMatchingPseudoRules.call(this, true); + continue; + } + + insertAllMatchingPseudoRules.call(this); + createSelectorItem.call(this, rule.style, rule.selectorText, rule.mediaText); + previousRule = rule; + } + + // Just in case there are any remaining pseudo-styles. + insertAllMatchingPseudoRules.call(this, true); + + // Inherited Rules + for (let inherited of this._nodeStyles.inheritedRules) { + if (!inherited.matchedRules || !inherited.matchedRules.length) + continue; + + let divider = null; + + for (let rule of uniqueOrderedRules(inherited.matchedRules)) { + if (rule.type === WebInspector.CSSStyleSheet.Type.UserAgent) + continue; + + if (!divider) { + let dividerText = WebInspector.UIString("Inherited from %s").format(inherited.node.displayName); + divider = new WebInspector.GeneralTreeElement("section-divider", dividerText); + divider.selectable = false; + this._selectors.appendChild(divider); + } + + createSelectorItem.call(this, rule.style, rule.selectorText, rule.mediaText); + } + } + + this._newInspectorRuleSelector = null; + } + + currentStyle() + { + if (!this._nodeStyles || !this._selectors.selectedTreeElement) + return null; + + return this._selectors.selectedTreeElement.representedObject; + } + + treeItemForStyle(style) + { + for (let item of this._selectors.children) { + if (item.representedObject === style) + return item; + } + return null; + } + + selectEmptyStyleTreeItem(style) + { + if (style.hasProperties()) + return false; + + let treeItem = this.treeItemForStyle(style); + if (!treeItem) + return false; + + treeItem.select(true, true); + return true; + } + + // Private + + _selectorChanged(event) + { + let selectedTreeElement = event.data.selectedElement; + if (!selectedTreeElement) + return; + + // The class needs to be completely reset as the previously selected treeElement most likely had + // a different icon className and it is simpler to regenerate the class than to find out which + // class was previously applied. + this._currentSelectorElement.className = "current-selector " + selectedTreeElement.iconClassName; + + let selectorText = selectedTreeElement.mainTitle; + let mediaText = selectedTreeElement.subtitle; + if (mediaText && mediaText.length) + selectorText += " \u2014 " + mediaText; // em-dash + + this._currentSelectorText.textContent = selectorText; + + this.dispatchEventToListeners(WebInspector.VisualStyleSelectorSection.Event.SelectorChanged); + } + + _addNewRule(event) + { + if (!this._nodeStyles || this._nodeStyles.node.isInUserAgentShadowTree()) + return; + + let selector = this.currentStyle().selectorText; + let existingRules = this._nodeStyles.rulesForSelector(selector); + for (let rule of existingRules) { + if (this.selectEmptyStyleTreeItem(rule.style)) + return; + } + + this._newInspectorRuleSelector = selector; + this._nodeStyles.addRule(selector); + } + + _treeElementCheckboxToggled(event) + { + let style = this.currentStyle(); + if (!style) + return; + + let styleText = style.text; + if (!styleText || !styleText.length) + return; + + // Comment or uncomment the style text. + let newStyleText = ""; + let styleEnabled = event && event.data && event.data.enabled; + if (styleEnabled) + newStyleText = styleText.replace(/\s*(\/\*|\*\/)\s*/g, ""); + else + newStyleText = "/* " + styleText.replace(/(\s*;(?!$)\s*)/g, "$1 *//* ") + " */"; + + style.text = newStyleText; + style[WebInspector.VisualStyleDetailsPanel.StyleDisabledSymbol] = !styleEnabled; + this.dispatchEventToListeners(WebInspector.VisualStyleSelectorSection.Event.SelectorChanged); + + } + + _handleMouseOver() + { + if (!this.collapsed) + return; + + let style = this.currentStyle(); + if (!style) + return; + + if (!style.ownerRule) { + WebInspector.domTreeManager.highlightDOMNode(style.node.id); + return; + } + + WebInspector.domTreeManager.highlightSelector(style.ownerRule.selectorText, style.node.ownerDocument.frameIdentifier); + } + + _handleMouseOut() + { + if (!this.collapsed) + return; + + WebInspector.domTreeManager.hideDOMNodeHighlight(); + } +}; + +WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol = Symbol("visual-style-selector-section-last-selected-rule"); + +WebInspector.VisualStyleSelectorSection.Event = { + SelectorChanged: "visual-style-selector-section-selector-changed" +}; |