| /* |
| * Copyright (C) 2017 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. |
| */ |
| |
| WI.SpreadsheetCSSStyleDeclarationSection = class SpreadsheetCSSStyleDeclarationSection extends WI.View |
| { |
| constructor(delegate, style) |
| { |
| console.assert(style instanceof WI.CSSStyleDeclaration, style); |
| |
| let element = document.createElement("section"); |
| element.classList.add("spreadsheet-css-declaration"); |
| |
| super(element); |
| |
| this._delegate = delegate || null; |
| this._style = style; |
| this._propertiesEditor = null; |
| this._selectorElements = []; |
| this._groupingElements = []; |
| this._filterText = null; |
| this._shouldFocusSelectorElement = false; |
| this._wasEditing = false; |
| |
| this._isMousePressed = false; |
| this._mouseDownIndex = NaN; |
| this._mouseDownPoint = null; |
| this._boundHandleWindowMouseMove = null; |
| } |
| |
| // Public |
| |
| get style() { return this._style; } |
| |
| get editable() |
| { |
| return this._style.editable; |
| } |
| |
| set propertyVisibilityMode(propertyVisibilityMode) |
| { |
| this._propertiesEditor.propertyVisibilityMode = propertyVisibilityMode; |
| } |
| |
| initialLayout() |
| { |
| super.initialLayout(); |
| |
| let iconClassName = null; |
| switch (this._style.type) { |
| case WI.CSSStyleDeclaration.Type.Rule: |
| console.assert(this._style.ownerRule); |
| if (this._style.inherited) { |
| iconClassName = "inherited-style-rule-icon"; |
| break; |
| } |
| |
| switch (this._style.ownerRule.type) { |
| case WI.CSSStyleSheet.Type.Author: |
| iconClassName = "author-style-rule-icon"; |
| break; |
| case WI.CSSStyleSheet.Type.User: |
| iconClassName = "user-style-rule-icon"; |
| break; |
| case WI.CSSStyleSheet.Type.UserAgent: |
| iconClassName = "user-agent-style-rule-icon"; |
| break; |
| case WI.CSSStyleSheet.Type.Inspector: |
| iconClassName = "inspector-style-rule-icon"; |
| break; |
| } |
| break; |
| case WI.CSSStyleDeclaration.Type.Inline: |
| case WI.CSSStyleDeclaration.Type.Attribute: |
| if (this._style.inherited) |
| iconClassName = "inherited-element-style-rule-icon"; |
| else |
| iconClassName = WI.DOMTreeElementPathComponent.DOMElementIconStyleClassName; |
| break; |
| } |
| console.assert(iconClassName); |
| this._element.classList.add("has-icon", iconClassName); |
| |
| let groupings = this._style.groupings.filter((grouping) => !grouping.isMedia || grouping.text !== "all").reverse(); |
| if (groupings.length) { |
| let groupingsElement = this.element.appendChild(document.createElement("div")); |
| groupingsElement.classList.add("header-groupings"); |
| |
| let currentGroupingType = null; |
| let currentGroupingHadText = false; |
| let groupingTypeElement = null; |
| this._groupingElements = groupings.map((grouping) => { |
| if (grouping.type !== currentGroupingType || !grouping.text || !currentGroupingHadText) { |
| groupingTypeElement = groupingsElement.appendChild(document.createElement("div")); |
| groupingTypeElement.classList.add("grouping"); |
| groupingTypeElement.textContent = grouping.prefix + " "; |
| currentGroupingType = grouping.type; |
| } else |
| groupingTypeElement.append(grouping.isLayer && grouping.text ? "." : ", "); |
| |
| currentGroupingHadText = !!grouping.text; |
| let span = groupingTypeElement.appendChild(document.createElement("span")); |
| span.textContent = grouping.text ?? ""; |
| return span; |
| }); |
| } |
| |
| this._headerElement = this._element.appendChild(document.createElement("div")); |
| this._headerElement.classList.add("header"); |
| |
| this._styleOriginView = new WI.StyleOriginView(); |
| this._headerElement.append(this._styleOriginView.element); |
| |
| this._selectorElement = document.createElement("span"); |
| this._selectorElement.classList.add("selector"); |
| this._selectorElement.addEventListener("mouseenter", this._highlightNodesWithSelector.bind(this)); |
| this._selectorElement.addEventListener("mouseleave", this._hideDOMNodeHighlight.bind(this)); |
| this._headerElement.append(this._selectorElement); |
| |
| this._openBrace = document.createElement("span"); |
| this._openBrace.classList.add("open-brace"); |
| this._openBrace.textContent = " {"; |
| this._headerElement.append(this._openBrace); |
| |
| if (this._style.selectorEditable) { |
| this._selectorTextField = new WI.SpreadsheetSelectorField(this, this._selectorElement); |
| this._selectorTextField.addEventListener(WI.SpreadsheetSelectorField.Event.StartedEditing, function(event) { |
| this._headerElement.classList.add("editing-selector"); |
| }, this); |
| this._selectorTextField.addEventListener(WI.SpreadsheetSelectorField.Event.StoppedEditing, function(event) { |
| this._headerElement.classList.remove("editing-selector"); |
| }, this); |
| |
| this._selectorElement.tabIndex = 0; |
| } |
| |
| this._propertiesEditor = new WI.SpreadsheetCSSStyleDeclarationEditor(this, this._style); |
| this._propertiesEditor.element.classList.add("properties"); |
| this._propertiesEditor.addEventListener(WI.SpreadsheetCSSStyleDeclarationEditor.Event.FilterApplied, this._handleEditorFilterApplied, this); |
| |
| this._closeBrace = document.createElement("span"); |
| this._closeBrace.classList.add("close-brace"); |
| this._closeBrace.textContent = "}"; |
| |
| |
| this.addSubview(this._propertiesEditor); |
| this._propertiesEditor.needsLayout(); |
| this._element.append(this._closeBrace); |
| |
| if (!this._style.editable) |
| this._element.classList.add("locked"); |
| else if (!this._style.ownerRule) |
| this._element.classList.add("selector-locked"); |
| |
| this.element.addEventListener("mousedown", this._handleMouseDown.bind(this)); |
| |
| if (this._style.editable) { |
| this.element.addEventListener("click", this._handleClick.bind(this)); |
| |
| if (WI.FileUtilities.canSave(WI.FileUtilities.SaveMode.SingleFile)) { |
| new WI.KeyboardShortcut(WI.KeyboardShortcut.Modifier.CommandOrControl, "S", this._save.bind(this), this._element); |
| new WI.KeyboardShortcut(WI.KeyboardShortcut.Modifier.CommandOrControl | WI.KeyboardShortcut.Modifier.Shift, "S", this._save.bind(this), this._element); |
| } |
| } |
| } |
| |
| layout() |
| { |
| super.layout(); |
| |
| this._styleOriginView.update(this._style); |
| this._renderSelector(); |
| |
| if (this._shouldFocusSelectorElement) |
| this.startEditingRuleSelector(); |
| } |
| |
| startEditingRuleSelector() |
| { |
| if (!this._selectorElement) { |
| this._shouldFocusSelectorElement = true; |
| return; |
| } |
| |
| this._shouldFocusSelectorElement = false; |
| |
| if (this._style.selectorEditable) |
| this._selectorTextField.startEditing(); |
| else |
| this._propertiesEditor.startEditingFirstProperty(); |
| } |
| |
| highlightProperty(property) |
| { |
| // When navigating from the Computed panel to the Styles panel, the latter |
| // could be empty. Layout all properties so they can be highlighted. |
| if (!this.didInitialLayout) |
| this.updateLayout(); |
| |
| if (this._propertiesEditor.highlightProperty(property)) { |
| this._element.scrollIntoView(); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // SpreadsheetSelectorField delegate |
| |
| spreadsheetSelectorFieldDidCommit(changed) |
| { |
| let selectorText = this._selectorElement.textContent.trim(); |
| if (selectorText && changed) { |
| this.dispatchEventToListeners(WI.SpreadsheetCSSStyleDeclarationSection.Event.SelectorWillChange); |
| this._style.ownerRule.setSelectorText(selectorText).finally(this._renderSelector.bind(this)); |
| } else |
| this._discardSelectorChange(); |
| } |
| |
| spreadsheetSelectorFieldWillNavigate(direction) |
| { |
| console.assert(direction); |
| if (direction === "forward") |
| this._propertiesEditor.startEditingFirstProperty(); |
| else if (direction === "backward") { |
| if (this._delegate.spreadsheetCSSStyleDeclarationSectionStartEditingAdjacentRule) { |
| const delta = -1; |
| this._delegate.spreadsheetCSSStyleDeclarationSectionStartEditingAdjacentRule(this, delta); |
| } else |
| this._propertiesEditor.startEditingLastProperty(); |
| } |
| } |
| |
| spreadsheetSelectorFieldDidDiscard() |
| { |
| this._discardSelectorChange(); |
| } |
| |
| // SpreadsheetCSSStyleDeclarationEditor delegate |
| |
| spreadsheetCSSStyleDeclarationEditorStartEditingRuleSelector() |
| { |
| this.startEditingRuleSelector(); |
| } |
| |
| spreadsheetCSSStyleDeclarationEditorStartEditingAdjacentRule(propertiesEditor, delta) |
| { |
| if (!this._delegate) |
| return; |
| |
| if (this._delegate.spreadsheetCSSStyleDeclarationSectionStartEditingAdjacentRule) |
| this._delegate.spreadsheetCSSStyleDeclarationSectionStartEditingAdjacentRule(this, delta); |
| } |
| |
| spreadsheetCSSStyleDeclarationEditorPropertyBlur(event, property) |
| { |
| if (!this._isMousePressed) |
| this._propertiesEditor.deselectProperties(); |
| } |
| |
| spreadsheetCSSStyleDeclarationEditorPropertyMouseEnter(event, property) |
| { |
| if (this._isMousePressed) { |
| let index = parseInt(property.element.dataset.propertyIndex); |
| this._propertiesEditor.selectProperties(this._mouseDownIndex, index); |
| } |
| } |
| |
| spreadsheetCSSStyleDeclarationEditorSelectProperty(property) |
| { |
| if (this._delegate && this._delegate.spreadsheetCSSStyleDeclarationSectionSelectProperty) |
| this._delegate.spreadsheetCSSStyleDeclarationSectionSelectProperty(property); |
| } |
| |
| spreadsheetCSSStyleDeclarationEditorSetAllPropertyVisibilityMode(editor, propertyVisibilityMode) |
| { |
| this._delegate?.spreadsheetCSSStyleDeclarationSectionSetAllPropertyVisibilityMode?.(this, propertyVisibilityMode); |
| } |
| |
| applyFilter(filterText) |
| { |
| this._filterText = filterText; |
| |
| if (!this.didInitialLayout) |
| return; |
| |
| this._element.classList.remove(WI.GeneralStyleDetailsSidebarPanel.NoFilterMatchInSectionClassName); |
| |
| this._propertiesEditor.applyFilter(this._filterText); |
| } |
| |
| // Private |
| |
| _discardSelectorChange() |
| { |
| // Re-render selector for syntax highlighting. |
| this._renderSelector(); |
| } |
| |
| _renderSelector() |
| { |
| this._selectorElement.removeChildren(); |
| this._selectorElements = []; |
| |
| let appendSelector = (selector, matched) => { |
| console.assert(selector instanceof WI.CSSSelector); |
| |
| let selectorElement = this._selectorElement.appendChild(document.createElement("span")); |
| selectorElement.textContent = selector.text; |
| |
| if (matched) |
| selectorElement.classList.add(WI.SpreadsheetCSSStyleDeclarationSection.MatchedSelectorElementStyleClassName); |
| |
| if (selector.specificity) { |
| let specificity = selector.specificity.map((number) => number.toLocaleString()); |
| let tooltip = WI.UIString("Specificity: (%d, %d, %d)").format(...specificity); |
| if (selector.dynamic) { |
| tooltip += "\n"; |
| if (this._style.inherited) |
| tooltip += WI.UIString("Dynamically calculated for the parent element"); |
| else |
| tooltip += WI.UIString("Dynamically calculated for the selected element"); |
| } |
| selectorElement.title = tooltip; |
| } else if (selector.dynamic) { |
| let tooltip = WI.UIString("Specificity: No value for selected element"); |
| tooltip += "\n"; |
| tooltip += WI.UIString("Dynamically calculated for the selected element and did not match"); |
| selectorElement.title = tooltip; |
| } |
| |
| this._selectorElements.push(selectorElement); |
| }; |
| |
| let appendSelectorTextKnownToMatch = (selectorText) => { |
| let selectorElement = this._selectorElement.appendChild(document.createElement("span")); |
| selectorElement.textContent = selectorText; |
| selectorElement.classList.add(WI.SpreadsheetCSSStyleDeclarationSection.MatchedSelectorElementStyleClassName); |
| }; |
| |
| if (!this._iconElement) { |
| this._iconElement = document.createElement("img"); |
| this._iconElement.classList.add("icon"); |
| WI.addMouseDownContextMenuHandlers(this._iconElement, this._populateIconElementContextMenu.bind(this)); |
| } |
| this._selectorElement.appendChild(this._iconElement); |
| |
| switch (this._style.type) { |
| case WI.CSSStyleDeclaration.Type.Rule: |
| console.assert(this._style.ownerRule); |
| |
| var hasMatchingPseudoSelector = false; |
| |
| var selectors = this._style.ownerRule.selectors; |
| if (selectors.length) { |
| for (let i = 0; i < selectors.length; ++i) { |
| let matched = this._style.ownerRule.matchedSelectorIndices.includes(i); |
| if (matched && selectors[i].isPseudoSelector()) |
| hasMatchingPseudoSelector = true; |
| |
| appendSelector(selectors[i], matched); |
| if (i < selectors.length - 1) |
| this._selectorElement.append(", "); |
| } |
| } else |
| appendSelectorTextKnownToMatch(this._style.ownerRule.selectorText); |
| |
| this._element.classList.toggle("pseudo-selector", hasMatchingPseudoSelector); |
| break; |
| |
| case WI.CSSStyleDeclaration.Type.Inline: { |
| this._selectorElement.classList.add("style-attribute"); |
| let wrapper = this._selectorElement.appendChild(document.createElement("span")); |
| wrapper.textContent = WI.UIString("Style Attribute", "CSS properties defined via HTML style attribute"); |
| break; |
| } |
| |
| case WI.CSSStyleDeclaration.Type.Attribute: |
| appendSelectorTextKnownToMatch(this._style.node.displayName); |
| break; |
| } |
| |
| if (this._filterText) |
| this.applyFilter(this._filterText); |
| } |
| |
| _save(event) |
| { |
| event.stop(); |
| |
| if (this._style.type !== WI.CSSStyleDeclaration.Type.Rule) { |
| // FIXME: Can't save CSS inside <style></style> <https://webkit.org/b/150357> |
| InspectorFrontendHost.beep(); |
| return; |
| } |
| |
| console.assert(this._style.ownerRule instanceof WI.CSSRule); |
| console.assert(this._style.ownerRule.sourceCodeLocation instanceof WI.SourceCodeLocation); |
| |
| let sourceCode = this._style.ownerRule.sourceCodeLocation.sourceCode; |
| if (sourceCode.type !== WI.Resource.Type.StyleSheet) { |
| // FIXME: Can't save CSS inside style="" <https://webkit.org/b/150357> |
| InspectorFrontendHost.beep(); |
| return; |
| } |
| |
| let url; |
| if (sourceCode.urlComponents.scheme === "data") { |
| let mainResource = WI.networkManager.mainFrame.mainResource; |
| if (mainResource.urlComponents.lastPathComponent.endsWith(".html")) |
| url = mainResource.url.replace(/\.html$/, "-data.css"); |
| else { |
| let pathDirectory = mainResource.url.slice(0, -mainResource.urlComponents.lastPathComponent.length); |
| url = pathDirectory + "data.css"; |
| } |
| } else |
| url = sourceCode.url; |
| |
| let forceSaveAs = event.shiftKey; |
| WI.FileUtilities.save(WI.FileUtilities.SaveMode.SingleFile, {url, content: sourceCode.content}, forceSaveAs); |
| } |
| |
| _handleMouseDown(event) |
| { |
| if (event.button !== 0) |
| return; |
| |
| this._wasEditing = this._propertiesEditor.editing || document.activeElement === this._selectorElement; |
| |
| let propertyElement = event.target.closest(".property"); |
| if (!propertyElement) |
| return; |
| |
| this._isMousePressed = true; |
| |
| // Disable text selection on mousemove. |
| event.preventDefault(); |
| |
| // Canceling mousedown event prevents blur event from firing on the previously focused element. |
| if (this._wasEditing && document.activeElement) |
| document.activeElement.blur(); |
| |
| // Prevent name/value fields from editing when properties selected. |
| window.addEventListener("click", this._handleWindowClick.bind(this), {capture: true, once: true}); |
| |
| let propertyIndex = parseInt(propertyElement.dataset.propertyIndex); |
| if (event.shiftKey && this._propertiesEditor.hasSelectedProperties()) |
| this._propertiesEditor.extendSelectedProperties(propertyIndex); |
| else { |
| this._propertiesEditor.deselectProperties(); |
| this._mouseDownPoint = WI.Point.fromEvent(event); |
| if (!this._boundHandleWindowMouseMove) |
| this._boundHandleWindowMouseMove = this._handleWindowMouseMove.bind(this); |
| window.addEventListener("mousemove", this._boundHandleWindowMouseMove); |
| } |
| |
| if (propertyElement.parentNode) { |
| this._mouseDownIndex = propertyIndex; |
| this._element.classList.add("selecting"); |
| } else |
| this._stopSelection(); |
| } |
| |
| _populateIconElementContextMenu(contextMenu) |
| { |
| contextMenu.appendItem(WI.UIString("Copy Rule"), () => { |
| InspectorFrontendHost.copyText(this._style.generateFormattedText({includeGroupingsAndSelectors: true, multiline: true})); |
| }); |
| |
| if (this._style.editable && this._style.properties.length) { |
| let shouldDisable = this._style.properties.some((property) => property.enabled); |
| contextMenu.appendItem(shouldDisable ? WI.UIString("Disable Rule") : WI.UIString("Enable Rule"), () => { |
| for (let property of this._style.properties) |
| property.commentOut(shouldDisable); |
| }); |
| } |
| |
| if (!this._style.inherited && InspectorBackend.hasCommand("CSS.addRule")) { |
| let generateSelector = () => { |
| if (this._style.type === WI.CSSStyleDeclaration.Type.Attribute) |
| return this._style.node.displayName; |
| return this._style.selectorText; |
| }; |
| |
| let createNewRule = (selector, text) => { |
| if (this._delegate && this._delegate.spreadsheetCSSStyleDeclarationSectionAddNewRule) |
| this._delegate.spreadsheetCSSStyleDeclarationSectionAddNewRule(this, selector, text); |
| else |
| this._style.nodeStyles.addRule(selector, text); |
| }; |
| |
| contextMenu.appendSeparator(); |
| |
| contextMenu.appendItem(WI.UIString("Duplicate Selector"), () => { |
| createNewRule(generateSelector()); |
| }); |
| |
| if (!WI.CSSManager.PseudoElementNames.some((className) => this._style.selectorText.includes(":" + className))) { |
| let addPseudoRule = (pseudoSelector, text) => { |
| let selector = null; |
| if (this._style.ownerRule) |
| selector = this._style.ownerRule.selectors.map((selector) => selector.text + pseudoSelector).join(", "); |
| else |
| selector = generateSelector() + pseudoSelector; |
| createNewRule(selector, text); |
| }; |
| |
| if (WI.cssManager.canForcePseudoClass() && Object.values(WI.CSSManager.ForceablePseudoClass).every((className) => !this._style.selectorText.includes(":" + className))) { |
| contextMenu.appendSeparator(); |
| |
| for (let pseudoClass of Object.values(WI.CSSManager.ForceablePseudoClass)) { |
| if (!WI.cssManager.canForcePseudoClass(pseudoClass)) |
| continue; |
| |
| if (pseudoClass === WI.CSSManager.ForceablePseudoClass.Visited && this._style.node.nodeName() !== "A") |
| continue; |
| |
| let pseudoClassSelector = ":" + pseudoClass; |
| contextMenu.appendItem(WI.UIString("Add %s Rule").format(pseudoClassSelector), () => { |
| this._style.node.setPseudoClassEnabled(pseudoClass, true); |
| |
| addPseudoRule(pseudoClassSelector); |
| }); |
| } |
| } |
| |
| if (this._style.type === WI.CSSStyleDeclaration.Type.Rule) { |
| contextMenu.appendSeparator(); |
| |
| for (let pseudoElement of WI.CSSManager.PseudoElementNames) { |
| let pseudoElementSelector = "::" + pseudoElement; |
| contextMenu.appendItem(WI.UIString("Create %s Rule").format(pseudoElementSelector), () => { |
| addPseudoRule(pseudoElementSelector, "content: \"\";"); |
| }); |
| } |
| } |
| } |
| } |
| |
| if (this._style.ownerRule && this._style.ownerRule.sourceCodeLocation) { |
| contextMenu.appendSeparator(); |
| |
| let label = null; |
| let sourceCode = this._style.ownerRule.sourceCodeLocation.displaySourceCode; |
| if (sourceCode instanceof WI.CSSStyleSheet || (sourceCode instanceof WI.Resource && sourceCode.type === WI.Resource.Type.StyleSheet)) |
| label = WI.UIString("Reveal in Style Sheet"); |
| else |
| label = WI.UIString("Reveal in Sources Tab"); |
| contextMenu.appendItem(label, () => { |
| WI.showSourceCodeLocation(this._style.ownerRule.sourceCodeLocation, { |
| ignoreNetworkTab: true, |
| ignoreSearchTab: true, |
| initiatorHint: WI.TabBrowser.TabNavigationInitiator.ContextMenu, |
| }); |
| }); |
| } |
| } |
| |
| _handleWindowClick(event) |
| { |
| if (this._propertiesEditor.hasSelectedProperties()) { |
| // Don't start editing name/value if there's selection. |
| event.stop(); |
| } |
| this._stopSelection(); |
| } |
| |
| _handleWindowMouseMove(event) |
| { |
| console.assert(this._mouseDownPoint); |
| |
| if (this._mouseDownPoint.distance(WI.Point.fromEvent(event)) < 8) |
| return; |
| |
| if (!this._propertiesEditor.hasSelectedProperties()) { |
| console.assert(!isNaN(this._mouseDownIndex)); |
| this._propertiesEditor.selectProperties(this._mouseDownIndex, this._mouseDownIndex); |
| } |
| |
| window.removeEventListener("mousemove", this._boundHandleWindowMouseMove); |
| this._mouseDownPoint = null; |
| } |
| |
| _handleClick(event) |
| { |
| this._stopSelection(); |
| |
| if (this._wasEditing || this._propertiesEditor.hasSelectedProperties()) |
| return; |
| |
| if (window.getSelection().type === "Range") |
| return; |
| |
| event.stop(); |
| |
| if (event.target.classList.contains(WI.SpreadsheetStyleProperty.StyleClassName)) { |
| let propertyIndex = parseInt(event.target.dataset.propertyIndex); |
| this._propertiesEditor.addBlankProperty(propertyIndex + 1); |
| return; |
| } |
| |
| if (event.target === this._headerElement || event.target === this._openBrace) { |
| this._propertiesEditor.addBlankProperty(0); |
| return; |
| } |
| |
| if (event.target === this._element || event.target === this._closeBrace) { |
| const appendAfterLast = -1; |
| this._propertiesEditor.addBlankProperty(appendAfterLast); |
| } |
| } |
| |
| _stopSelection() |
| { |
| this._isMousePressed = false; |
| this._mouseDownIndex = NaN; |
| this._element.classList.remove("selecting"); |
| |
| // "copy" and "cut" events won't fire on SpreadsheetCSSStyleDeclarationEditor unless it has text selected. |
| // Placing a text caret inside of a property has no visible effects but it allows the events to fire. |
| this._propertiesEditor.placeTextCaretInFocusedProperty(); |
| |
| window.removeEventListener("mousemove", this._boundHandleWindowMouseMove); |
| this._mouseDownPoint = null; |
| } |
| |
| _highlightNodesWithSelector() |
| { |
| let node = this._style.node; |
| |
| if (!this._style.ownerRule) { |
| node.highlight(); |
| return; |
| } |
| |
| let selectorText = this._selectorElement.textContent.trim(); |
| if (node.frame) |
| WI.domManager.highlightSelector(selectorText, node.frame.id); |
| else |
| WI.domManager.highlightSelector(selectorText); |
| } |
| |
| _hideDOMNodeHighlight() |
| { |
| WI.domManager.hideDOMNodeHighlight(); |
| } |
| |
| _handleEditorFilterApplied(event) |
| { |
| let matchesGrouping = false; |
| for (let groupingElement of this._groupingElements) { |
| groupingElement.classList.remove(WI.GeneralStyleDetailsSidebarPanel.FilterMatchSectionClassName); |
| |
| if (groupingElement.textContent.includes(this._filterText)) { |
| groupingElement.classList.add(WI.GeneralStyleDetailsSidebarPanel.FilterMatchSectionClassName); |
| matchesGrouping = true; |
| } |
| } |
| |
| let matchesSelector = false; |
| for (let selectorElement of this._selectorElements) { |
| selectorElement.classList.remove(WI.GeneralStyleDetailsSidebarPanel.FilterMatchSectionClassName); |
| |
| if (selectorElement.textContent.includes(this._filterText)) { |
| selectorElement.classList.add(WI.GeneralStyleDetailsSidebarPanel.FilterMatchSectionClassName); |
| matchesSelector = true; |
| } |
| } |
| |
| let matches = event.data.matches || matchesGrouping || matchesSelector; |
| if (!matches) |
| this._element.classList.add(WI.GeneralStyleDetailsSidebarPanel.NoFilterMatchInSectionClassName); |
| |
| this.dispatchEventToListeners(WI.SpreadsheetCSSStyleDeclarationSection.Event.FilterApplied, {matches}); |
| } |
| }; |
| |
| WI.SpreadsheetCSSStyleDeclarationSection.Event = { |
| FilterApplied: "spreadsheet-css-style-declaration-section-filter-applied", |
| SelectorWillChange: "spreadsheet-css-style-declaration-section-selector-will-change", |
| }; |
| |
| WI.SpreadsheetCSSStyleDeclarationSection.MatchedSelectorElementStyleClassName = "matched"; |