summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.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/CSSStyleDetailsSidebarPanel.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js454
1 files changed, 454 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js b/Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js
new file mode 100644
index 000000000..797a0f218
--- /dev/null
+++ b/Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2013, 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.CSSStyleDetailsSidebarPanel = class CSSStyleDetailsSidebarPanel extends WebInspector.DOMDetailsSidebarPanel
+{
+ constructor()
+ {
+ super("css-style", WebInspector.UIString("Styles"), WebInspector.UIString("Style"), null, true);
+
+ this._selectedPanel = null;
+ this._computedStyleDetailsPanel = new WebInspector.ComputedStyleDetailsPanel(this);
+ this._rulesStyleDetailsPanel = new WebInspector.RulesStyleDetailsPanel(this);
+ this._visualStyleDetailsPanel = new WebInspector.VisualStyleDetailsPanel(this);
+
+ this._panels = [this._computedStyleDetailsPanel, this._rulesStyleDetailsPanel, this._visualStyleDetailsPanel];
+ this._panelNavigationInfo = [this._computedStyleDetailsPanel.navigationInfo, this._rulesStyleDetailsPanel.navigationInfo, this._visualStyleDetailsPanel.navigationInfo];
+
+ this._lastSelectedPanelSetting = new WebInspector.Setting("last-selected-style-details-panel", this._rulesStyleDetailsPanel.navigationInfo.identifier);
+ this._classListContainerToggledSetting = new WebInspector.Setting("class-list-container-toggled", false);
+
+ this._initiallySelectedPanel = this._panelMatchingIdentifier(this._lastSelectedPanelSetting.value) || this._rulesStyleDetailsPanel;
+
+ this._navigationItem = new WebInspector.ScopeRadioButtonNavigationItem(this.identifier, this.displayName, this._panelNavigationInfo, this._initiallySelectedPanel.navigationInfo);
+ this._navigationItem.addEventListener(WebInspector.ScopeRadioButtonNavigationItem.Event.SelectedItemChanged, this._handleSelectedItemChanged, this);
+
+ this._forcedPseudoClassCheckboxes = {};
+ }
+
+ // Public
+
+ supportsDOMNode(nodeToInspect)
+ {
+ return nodeToInspect.nodeType() === Node.ELEMENT_NODE;
+ }
+
+ visibilityDidChange()
+ {
+ super.visibilityDidChange();
+
+ if (!this._selectedPanel)
+ return;
+
+ if (!this.visible) {
+ this._selectedPanel.hidden();
+ return;
+ }
+
+ this._updateNoForcedPseudoClassesScrollOffset();
+
+ this._selectedPanel.shown();
+ this._selectedPanel.markAsNeedsRefresh(this.domNode);
+ }
+
+ computedStyleDetailsPanelShowProperty(property)
+ {
+ this._rulesStyleDetailsPanel.scrollToSectionAndHighlightProperty(property);
+ this._switchPanels(this._rulesStyleDetailsPanel);
+
+ this._navigationItem.selectedItemIdentifier = this._lastSelectedPanelSetting.value;
+ }
+
+ // Protected
+
+ layout()
+ {
+ let domNode = this.domNode;
+ if (!domNode)
+ return;
+
+ this.contentView.element.scrollTop = this._initialScrollOffset;
+
+ for (let panel of this._panels) {
+ panel.element._savedScrollTop = undefined;
+ panel.markAsNeedsRefresh(domNode);
+ }
+
+ this._updatePseudoClassCheckboxes();
+
+ if (!this._classListContainer.hidden)
+ this._populateClassToggles();
+ }
+
+ addEventListeners()
+ {
+ let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
+ if (!effectiveDOMNode)
+ return;
+
+ effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.EnabledPseudoClassesChanged, this._updatePseudoClassCheckboxes, this);
+ effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.AttributeModified, this._handleNodeAttributeModified, this);
+ effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.AttributeRemoved, this._handleNodeAttributeRemoved, this);
+ }
+
+ removeEventListeners()
+ {
+ let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
+ if (!effectiveDOMNode)
+ return;
+
+ effectiveDOMNode.removeEventListener(null, null, this);
+ }
+
+ initialLayout()
+ {
+ if (WebInspector.cssStyleManager.canForcePseudoClasses()) {
+ this._forcedPseudoClassContainer = document.createElement("div");
+ this._forcedPseudoClassContainer.className = "pseudo-classes";
+
+ let groupElement = null;
+
+ WebInspector.CSSStyleManager.ForceablePseudoClasses.forEach(function(pseudoClass) {
+ // We don't localize the label since it is a CSS pseudo-class from the CSS standard.
+ let label = pseudoClass.capitalize();
+
+ let labelElement = document.createElement("label");
+
+ let checkboxElement = document.createElement("input");
+ checkboxElement.addEventListener("change", this._forcedPseudoClassCheckboxChanged.bind(this, pseudoClass));
+ checkboxElement.type = "checkbox";
+
+ this._forcedPseudoClassCheckboxes[pseudoClass] = checkboxElement;
+
+ labelElement.appendChild(checkboxElement);
+ labelElement.append(label);
+
+ if (!groupElement || groupElement.children.length === 2) {
+ groupElement = document.createElement("div");
+ groupElement.className = "group";
+ this._forcedPseudoClassContainer.appendChild(groupElement);
+ }
+
+ groupElement.appendChild(labelElement);
+ }, this);
+
+ this.contentView.element.appendChild(this._forcedPseudoClassContainer);
+ }
+
+ this._computedStyleDetailsPanel.addEventListener(WebInspector.StyleDetailsPanel.Event.Refreshed, this._filterDidChange, this);
+ this._rulesStyleDetailsPanel.addEventListener(WebInspector.StyleDetailsPanel.Event.Refreshed, this._filterDidChange, this);
+
+ console.assert(this._initiallySelectedPanel, "Should have an initially selected panel.");
+
+ this._switchPanels(this._initiallySelectedPanel);
+ this._initiallySelectedPanel = null;
+
+ let optionsContainer = this.element.createChild("div", "options-container");
+
+ let newRuleButton = optionsContainer.createChild("img", "new-rule");
+ newRuleButton.title = WebInspector.UIString("Add new rule");
+ newRuleButton.addEventListener("click", this._newRuleButtonClicked.bind(this));
+
+ this._filterBar = new WebInspector.FilterBar;
+ this._filterBar.placeholder = WebInspector.UIString("Filter Styles");
+ this._filterBar.addEventListener(WebInspector.FilterBar.Event.FilterDidChange, this._filterDidChange, this);
+ optionsContainer.appendChild(this._filterBar.element);
+
+ this._classToggleButton = optionsContainer.createChild("button", "toggle-class-toggle");
+ this._classToggleButton.textContent = WebInspector.UIString("Classes");
+ this._classToggleButton.title = WebInspector.UIString("Toggle Classes");
+ this._classToggleButton.addEventListener("click", this._classToggleButtonClicked.bind(this));
+
+ this._classListContainer = this.element.createChild("div", "class-list-container");
+ this._classListContainer.hidden = true;
+
+ this._addClassContainer = this._classListContainer.createChild("div", "new-class");
+ this._addClassContainer.title = WebInspector.UIString("Add a Class");
+ this._addClassContainer.addEventListener("click", this._addClassContainerClicked.bind(this));
+
+ let addClassCheckbox = this._addClassContainer.createChild("input");
+ addClassCheckbox.type = "checkbox";
+ addClassCheckbox.checked = true;
+
+ let addClassIcon = useSVGSymbol("Images/Plus13.svg", "add-class-icon");
+ this._addClassContainer.appendChild(addClassIcon);
+
+ this._addClassInput = this._addClassContainer.createChild("input", "class-name-input");
+ this._addClassInput.setAttribute("placeholder", WebInspector.UIString("Enter Class Name"));
+ this._addClassInput.addEventListener("keypress", this._addClassInputKeyPressed.bind(this));
+ this._addClassInput.addEventListener("blur", this._addClassInputBlur.bind(this));
+
+ WebInspector.cssStyleManager.addEventListener(WebInspector.CSSStyleManager.Event.StyleSheetAdded, this._styleSheetAddedOrRemoved, this);
+ WebInspector.cssStyleManager.addEventListener(WebInspector.CSSStyleManager.Event.StyleSheetRemoved, this._styleSheetAddedOrRemoved, this);
+
+ if (this._classListContainerToggledSetting.value)
+ this._classToggleButtonClicked();
+ }
+
+ sizeDidChange()
+ {
+ super.sizeDidChange();
+
+ this._updateNoForcedPseudoClassesScrollOffset();
+
+ if (this._selectedPanel)
+ this._selectedPanel.sizeDidChange();
+ }
+
+ // Private
+
+ get _initialScrollOffset()
+ {
+ if (!WebInspector.cssStyleManager.canForcePseudoClasses())
+ return 0;
+ return this.domNode && this.domNode.enabledPseudoClasses.length ? 0 : WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset;
+ }
+
+ _updateNoForcedPseudoClassesScrollOffset()
+ {
+ if (this._forcedPseudoClassContainer)
+ WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset = this._forcedPseudoClassContainer.offsetHeight;
+ }
+
+ _panelMatchingIdentifier(identifier)
+ {
+ let selectedPanel = null;
+ for (let panel of this._panels) {
+ if (panel.navigationInfo.identifier !== identifier)
+ continue;
+
+ selectedPanel = panel;
+ break;
+ }
+
+ return selectedPanel;
+ }
+
+ _handleSelectedItemChanged()
+ {
+ let selectedIdentifier = this._navigationItem.selectedItemIdentifier;
+ let selectedPanel = this._panelMatchingIdentifier(selectedIdentifier);
+ this._switchPanels(selectedPanel);
+ }
+
+ _switchPanels(selectedPanel)
+ {
+ console.assert(selectedPanel);
+
+ if (this._selectedPanel) {
+ this._selectedPanel.hidden();
+ this._selectedPanel.element._savedScrollTop = this.contentView.element.scrollTop;
+ this.contentView.removeSubview(this._selectedPanel);
+ }
+
+ this._selectedPanel = selectedPanel;
+ if (!this._selectedPanel)
+ return;
+
+ this.contentView.addSubview(this._selectedPanel);
+
+ if (typeof this._selectedPanel.element._savedScrollTop === "number")
+ this.contentView.element.scrollTop = this._selectedPanel.element._savedScrollTop;
+ else
+ this.contentView.element.scrollTop = this._initialScrollOffset;
+
+ let hasFilter = typeof this._selectedPanel.filterDidChange === "function";
+ this.contentView.element.classList.toggle("has-filter-bar", hasFilter);
+ if (this._filterBar)
+ this.contentView.element.classList.toggle(WebInspector.CSSStyleDetailsSidebarPanel.FilterInProgressClassName, hasFilter && this._filterBar.hasActiveFilters());
+
+ this.contentView.element.classList.toggle("supports-new-rule", typeof this._selectedPanel.newRuleButtonClicked === "function");
+ this._selectedPanel.shown();
+
+ this._lastSelectedPanelSetting.value = selectedPanel.navigationInfo.identifier;
+ }
+
+ _forcedPseudoClassCheckboxChanged(pseudoClass, event)
+ {
+ if (!this.domNode)
+ return;
+
+ let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
+
+ effectiveDOMNode.setPseudoClassEnabled(pseudoClass, event.target.checked);
+ }
+
+ _updatePseudoClassCheckboxes()
+ {
+ if (!this.domNode)
+ return;
+
+ let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
+
+ let enabledPseudoClasses = effectiveDOMNode.enabledPseudoClasses;
+
+ for (let pseudoClass in this._forcedPseudoClassCheckboxes) {
+ let checkboxElement = this._forcedPseudoClassCheckboxes[pseudoClass];
+ checkboxElement.checked = enabledPseudoClasses.includes(pseudoClass);
+ }
+ }
+
+ _handleNodeAttributeModified(event)
+ {
+ if (event && event.data && event.data.name === "class")
+ this._populateClassToggles();
+ }
+
+ _handleNodeAttributeRemoved(event)
+ {
+ if (event && event.data && event.data.name === "class")
+ this._populateClassToggles();
+ }
+
+
+ _newRuleButtonClicked()
+ {
+ if (this._selectedPanel && typeof this._selectedPanel.newRuleButtonClicked === "function")
+ this._selectedPanel.newRuleButtonClicked();
+ }
+
+ _classToggleButtonClicked(event)
+ {
+ this._classToggleButton.classList.toggle("selected");
+ this._classListContainer.hidden = !this._classListContainer.hidden;
+ this._classListContainerToggledSetting.value = !this._classListContainer.hidden;
+ if (this._classListContainer.hidden)
+ return;
+
+ this._populateClassToggles();
+ }
+
+ _addClassContainerClicked(event)
+ {
+ this._addClassContainer.classList.add("active");
+ this._addClassInput.focus();
+ }
+
+ _addClassInputKeyPressed(event)
+ {
+ if (event.keyCode !== WebInspector.KeyboardShortcut.Key.Enter.keyCode)
+ return;
+
+ this._addClassInput.blur();
+ }
+
+ _addClassInputBlur(event)
+ {
+ this.domNode.toggleClass(this._addClassInput.value, true);
+ this._addClassContainer.classList.remove("active");
+ this._addClassInput.value = null;
+ }
+
+ _populateClassToggles()
+ {
+ // Ensure that _addClassContainer is the first child of _classListContainer.
+ while (this._classListContainer.children.length > 1)
+ this._classListContainer.children[1].remove();
+
+ let classes = this.domNode.getAttribute("class");
+ let classToggledMap = this.domNode[WebInspector.CSSStyleDetailsSidebarPanel.ToggledClassesSymbol];
+ if (!classToggledMap)
+ classToggledMap = this.domNode[WebInspector.CSSStyleDetailsSidebarPanel.ToggledClassesSymbol] = new Map;
+
+ if (classes && classes.length) {
+ for (let className of classes.split(/\s+/))
+ classToggledMap.set(className, true);
+ }
+
+ for (let [className, toggled] of classToggledMap) {
+ if ((toggled && !classes.includes(className)) || (!toggled && classes.includes(className))) {
+ toggled = !toggled;
+ classToggledMap.set(className, toggled);
+ }
+
+ this._createToggleForClassName(className);
+ }
+ }
+
+ _createToggleForClassName(className)
+ {
+ if (!className || !className.length)
+ return;
+
+ let classToggledMap = this.domNode[WebInspector.CSSStyleDetailsSidebarPanel.ToggledClassesSymbol];
+ if (!classToggledMap)
+ return;
+
+ if (!classToggledMap.has(className))
+ classToggledMap.set(className, true);
+
+ let toggled = classToggledMap.get(className);
+
+ let classNameContainer = document.createElement("div");
+ classNameContainer.classList.add("class-toggle");
+
+ let classNameToggle = classNameContainer.createChild("input");
+ classNameToggle.type = "checkbox";
+ classNameToggle.checked = toggled;
+
+ let classNameTitle = classNameContainer.createChild("span");
+ classNameTitle.textContent = className;
+ classNameTitle.draggable = true;
+ classNameTitle.addEventListener("dragstart", (event) => {
+ event.dataTransfer.setData(WebInspector.CSSStyleDetailsSidebarPanel.ToggledClassesDragType, className);
+ event.dataTransfer.effectAllowed = "copy";
+ });
+
+ let classNameToggleChanged = (event) => {
+ this.domNode.toggleClass(className, classNameToggle.checked);
+ classToggledMap.set(className, classNameToggle.checked);
+ };
+
+ classNameToggle.addEventListener("click", classNameToggleChanged);
+ classNameTitle.addEventListener("click", (event) => {
+ classNameToggle.checked = !classNameToggle.checked;
+ classNameToggleChanged();
+ });
+
+ this._classListContainer.appendChild(classNameContainer);
+ }
+
+ _filterDidChange()
+ {
+ this.contentView.element.classList.toggle(WebInspector.CSSStyleDetailsSidebarPanel.FilterInProgressClassName, this._filterBar.hasActiveFilters());
+
+ this._selectedPanel.filterDidChange(this._filterBar);
+ }
+
+ _styleSheetAddedOrRemoved()
+ {
+ this.needsLayout();
+ }
+};
+
+WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset = 30; // Default height of the forced pseudo classes container. Updated in sizeDidChange.
+WebInspector.CSSStyleDetailsSidebarPanel.FilterInProgressClassName = "filter-in-progress";
+WebInspector.CSSStyleDetailsSidebarPanel.FilterMatchingSectionHasLabelClassName = "filter-section-has-label";
+WebInspector.CSSStyleDetailsSidebarPanel.FilterMatchSectionClassName = "filter-matching";
+WebInspector.CSSStyleDetailsSidebarPanel.NoFilterMatchInSectionClassName = "filter-section-non-matching";
+WebInspector.CSSStyleDetailsSidebarPanel.NoFilterMatchInPropertyClassName = "filter-property-non-matching";
+
+WebInspector.CSSStyleDetailsSidebarPanel.ToggledClassesSymbol = Symbol("css-style-details-sidebar-panel-toggled-classes-symbol");
+WebInspector.CSSStyleDetailsSidebarPanel.ToggledClassesDragType = "text/classname";