summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js329
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"
+};