Changeset 286876 in webkit


Ignore:
Timestamp:
Dec 10, 2021 2:15:52 PM (7 months ago)
Author:
Razvan Caliman
Message:

Web Inspector: Computed Panel: Group CSS variables by value type
https://bugs.webkit.org/show_bug.cgi?id=233563
<rdar://82978905>

Reviewed by Devin Rousso and Patrick Angle.

Source/WebInspectorUI:

Add the ability to view CSS variables in the Computed styles details sidebar panel
groupped by value type in a few sections: "colors", "dimensions", "numbers" and a
catch-all group of "other".

  • Localizations/en.lproj/localizedStrings.js:
  • UserInterface/Models/DOMNodeStyles.js:

(WI.DOMNodeStyles):
(WI.DOMNodeStyles.prototype.variableStylesByType):
Iterate on-demand over all CSS variables found in the node's computed styles
and assign each to a group depending on its value type:

  • color
  • dimension (number followed by a CSS unit-like string)
  • number
  • other

Additional groups and refinements will come in follow-up patches.

(WI.DOMNodeStyles.prototype.refresh.fetchedComputedStyle):
The map of CSS variable groups gets invalidated when there's a significant
change in the node's computed style. This supports the use case where previously
empty groups become populated or, conversely, become empty.

  • UserInterface/Views/ComputedStyleDetailsPanel.js:

(WI.ComputedStyleDetailsPanel):
(WI.ComputedStyleDetailsPanel.prototype.refresh):
(WI.ComputedStyleDetailsPanel.prototype.applyFilter):
(WI.ComputedStyleDetailsPanel.prototype.initialLayout):
No longer generate the elements for laying out CSS variables during initialLayout()
but handle them during layout(). This support mutating the DOM for laying out
either one top-level list of CSS variables (ungrouped) or multiple lists of CSS variable
groups depeding on the grouping mode selected at runtime.

  • UserInterface/Views/ComputedStyleDetailsPanel.css:

(.sidebar > .panel.details.css-style > .content > .computed .details-section > .content):
Ensure both top-level and nested details sections overwrite styles. CSS variables groups are in nested details sections.

(.sidebar > .panel.details.css-style > .content > .computed .details-section.computed-style-variables .computed-property-item):
Adapt stylesheet to account for using WI.ComputedStyleSection instead of WI.SpreadsheetCSSStyleDeclarationEditor

(.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode):
(.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode.default-item-selected:not(:hover)):
(.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode.default-item-selected:hover):
Reuse the visual treatment from SourcesNavigationSidebarPanel.css to avoid highlighting the default grouping mode scope bar item.

(.sidebar > .panel.details.css-style > .content > .computed > .details-section > .content): Deleted.
(.sidebar > .panel.details.css-style > .content > .computed .property): Deleted.

(WI.ComputedStyleDetailsPanel.prototype.layout):
Skip destroying and rebuilding sections whose data sources change during
WI.ComputedStyleDetailsPanel.refresh() and which handle layout internally.
We need to remove and rebuild just the sections for CSS variables because
layout is requested in response to changing the CSS variables grouping mode.

(WI.ComputedStyleDetailsPanel.prototype._createVariablesStyleSection):
Replaces the use of WI.SpreadsheetCSSStyleDeclarationEditor for rendering CSS variables with
WI.ComputedStyleSection which is already used for rendering CSS properties.
It's a lighter-weight View that's fit for purpose.

(WI.ComputedStyleDetailsPanel.prototype._renderVariablesStyleSectionGroup):
Use a generic renderer for CSS variable sections that can be reused for any group type.

(WI.ComputedStyleDetailsPanel.prototype._handleDetailsSectionCollapsedStateChanged):
Generalize handling collapsed state change events for all sections, current and future.

(WI.ComputedStyleDetailsPanel.prototype._handleEditorFilterApplied):
Generalize handling filtering events for all sections, current and future.

(WI.ComputedStyleDetailsPanel.prototype._handleVariablesGroupingModeScopeBarSelectionChanged):
(WI.ComputedStyleDetailsPanel.prototype._handleVariablesGroupingSettingChanged):
(WI.ComputedStyleDetailsPanel.prototype._handlePropertiesSectionCollapsedStateChanged): Deleted.
(WI.ComputedStyleDetailsPanel.prototype._handleVariablesSectionCollapsedStateChanged): Deleted.

  • UserInterface/Views/ComputedStyleSection.js:

(WI.ComputedStyleSection):
Change the default value of _styleTraces to null instead of an empty array so that
WI.ComputedStyleSection.layout() doesn't attempt to access it like a Map.

LayoutTests:

Check logic for grouping CSS variables by value type in Web Inspector.

  • inspector/css/variableStylesByType-expected.txt: Added.
  • inspector/css/variableStylesByType.html: Added.
Location:
trunk
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r286869 r286876  
     12021-12-10  Razvan Caliman  <rcaliman@apple.com>
     2
     3        Web Inspector: Computed Panel: Group CSS variables by value type
     4        https://bugs.webkit.org/show_bug.cgi?id=233563
     5        <rdar://82978905>
     6
     7        Reviewed by Devin Rousso and Patrick Angle.
     8
     9        Check logic for grouping CSS variables by value type in Web Inspector.
     10
     11        * inspector/css/variableStylesByType-expected.txt: Added.
     12        * inspector/css/variableStylesByType.html: Added.
     13
    1142021-12-10  Chris Dumez  <cdumez@apple.com>
    215
  • trunk/Source/WebInspectorUI/ChangeLog

    r286875 r286876  
     12021-12-10  Razvan Caliman  <rcaliman@apple.com>
     2
     3        Web Inspector: Computed Panel: Group CSS variables by value type
     4        https://bugs.webkit.org/show_bug.cgi?id=233563
     5        <rdar://82978905>
     6
     7        Reviewed by Devin Rousso and Patrick Angle.
     8
     9        Add the ability to view CSS variables in the Computed styles details sidebar panel
     10        groupped by value type in a few sections: "colors", "dimensions", "numbers" and a
     11        catch-all group of "other".
     12
     13        * Localizations/en.lproj/localizedStrings.js:
     14        * UserInterface/Models/DOMNodeStyles.js:
     15        (WI.DOMNodeStyles):
     16        (WI.DOMNodeStyles.prototype.variableStylesByType):
     17        Iterate on-demand over all CSS variables found in the node's computed styles
     18        and assign each to a group depending on its value type:
     19        - color
     20        - dimension (number followed by a CSS unit-like string)
     21        - number
     22        - other
     23
     24        Additional groups and refinements will come in follow-up patches.
     25
     26        (WI.DOMNodeStyles.prototype.refresh.fetchedComputedStyle):
     27        The map of CSS variable groups gets invalidated when there's a significant
     28        change in the node's computed style. This supports the use case where previously
     29        empty groups become populated or, conversely, become empty.
     30
     31        * UserInterface/Views/ComputedStyleDetailsPanel.js:
     32        (WI.ComputedStyleDetailsPanel):
     33        (WI.ComputedStyleDetailsPanel.prototype.refresh):
     34        (WI.ComputedStyleDetailsPanel.prototype.applyFilter):
     35        (WI.ComputedStyleDetailsPanel.prototype.initialLayout):
     36        No longer generate the elements for laying out CSS variables during `initialLayout()`
     37        but handle them during `layout()`. This support mutating the DOM for laying out
     38        either one top-level list of CSS variables (ungrouped) or multiple lists of CSS variable
     39        groups depeding on the grouping mode selected at runtime.
     40
     41        * UserInterface/Views/ComputedStyleDetailsPanel.css:
     42        (.sidebar > .panel.details.css-style > .content > .computed .details-section > .content):
     43        Ensure both top-level and nested details sections overwrite styles. CSS variables groups are in nested details sections.
     44
     45        (.sidebar > .panel.details.css-style > .content > .computed .details-section.computed-style-variables .computed-property-item):
     46        Adapt stylesheet to account for using `WI.ComputedStyleSection` instead of `WI.SpreadsheetCSSStyleDeclarationEditor`
     47
     48        (.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode):
     49        (.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode.default-item-selected:not(:hover)):
     50        (.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode.default-item-selected:hover):
     51        Reuse the visual treatment from SourcesNavigationSidebarPanel.css to avoid highlighting the default grouping mode scope bar item.
     52
     53        (.sidebar > .panel.details.css-style > .content > .computed > .details-section > .content): Deleted.
     54        (.sidebar > .panel.details.css-style > .content > .computed .property): Deleted.
     55
     56        (WI.ComputedStyleDetailsPanel.prototype.layout):
     57        Skip destroying and rebuilding sections whose data sources change during
     58        `WI.ComputedStyleDetailsPanel.refresh()` and which handle layout internally.
     59        We need to remove and rebuild just the sections for CSS variables because
     60        layout is requested in response to changing the CSS variables grouping mode.
     61
     62        (WI.ComputedStyleDetailsPanel.prototype._createVariablesStyleSection):
     63        Replaces the use of `WI.SpreadsheetCSSStyleDeclarationEditor` for rendering CSS variables with
     64        `WI.ComputedStyleSection` which is already used for rendering CSS properties.
     65        It's a lighter-weight View that's fit for purpose.
     66
     67        (WI.ComputedStyleDetailsPanel.prototype._renderVariablesStyleSectionGroup):
     68        Use a generic renderer for CSS variable sections that can be reused for any group type.
     69
     70        (WI.ComputedStyleDetailsPanel.prototype._handleDetailsSectionCollapsedStateChanged):
     71        Generalize handling collapsed state change events for all sections, current and future.
     72
     73        (WI.ComputedStyleDetailsPanel.prototype._handleEditorFilterApplied):
     74        Generalize handling filtering events for all sections, current and future.
     75
     76        (WI.ComputedStyleDetailsPanel.prototype._handleVariablesGroupingModeScopeBarSelectionChanged):
     77        (WI.ComputedStyleDetailsPanel.prototype._handleVariablesGroupingSettingChanged):
     78        (WI.ComputedStyleDetailsPanel.prototype._handlePropertiesSectionCollapsedStateChanged): Deleted.
     79        (WI.ComputedStyleDetailsPanel.prototype._handleVariablesSectionCollapsedStateChanged): Deleted.
     80        * UserInterface/Views/ComputedStyleSection.js:
     81        (WI.ComputedStyleSection):
     82        Change the default value of `_styleTraces` to null instead of an empty array so that
     83        `WI.ComputedStyleSection.layout()` doesn't attempt to access it like a `Map`.
     84
    1852021-12-10  Nikita Vasilyev  <nvasilyev@apple.com>
    286
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r286611 r286876  
    245245localizedStrings["By Path"] = "By Path";
    246246localizedStrings["By Type"] = "By Type";
     247/* Label for button to show CSS variables grouped by type */
     248localizedStrings["By Type @ Computed Style variables grouping mode"] = "By Type";
    247249localizedStrings["Byte Range %s\u2013%s"] = "Byte Range %s\u2013%s";
    248250localizedStrings["Bytes Received"] = "Bytes Received";
     
    341343localizedStrings["Collapse columns"] = "Collapse columns";
    342344localizedStrings["Collect garbage"] = "Collect garbage";
     345/* Section header for the group of CSS variables with colors as values */
     346localizedStrings["Colors @ Computed Style variables section"] = "Colors";
    343347localizedStrings["Comment"] = "Comment";
    344348/* Property value for `font-variant-ligatures: common-ligatures`. */
     
    470474localizedStrings["Diagonal Fractions @ Font Details Sidebar Property Value"] = "Diagonal Fractions";
    471475localizedStrings["Dimensions"] = "Dimensions";
     476/* Section header for the group of CSS variables with dimensions as values */
     477localizedStrings["Dimensions @ Computed style variables section"] = "Dimensions";
    472478localizedStrings["Disable Audit"] = "Disable Audit";
    473479localizedStrings["Disable Breakpoint"] = "Disable Breakpoint";
     
    10081014/* Title of icon indicating that the selected audit has not been run yet. */
    10091015localizedStrings["Not yet run @ Audit Tab - Test Case"] = "Not yet run";
     1016/* Section header for the group of CSS variables with numbers as values */
     1017localizedStrings["Numbers @ Computed Style variables section"] = "Numbers";
    10101018/* Property title for `font-variant-numeric`. */
    10111019localizedStrings["Numeric @ Font Details Sidebar Property"] = "Numeric";
     
    10421050localizedStrings["Originator"] = "Originator";
    10431051localizedStrings["Other"] = "Other";
     1052/* Section header for the generic group of CSS variables */
     1053localizedStrings["Other @ Computed Style variables section"] = "Other";
    10441054localizedStrings["Other Issue"] = "Other Issue";
    10451055localizedStrings["Other Threads"] = "Other Threads";
     
    15901600localizedStrings["Uncaught Exceptions @ JavaScript Breakpoint"] = "Uncaught Exceptions";
    15911601localizedStrings["Undefined custom element"] = "Undefined custom element";
     1602/* Label for button to show CSS variables ungrouped */
     1603localizedStrings["Ungrouped @ Computed Style variables grouping mode"] = "Ungrouped";
     1604/* Section header for ungrouped CSS variables */
     1605localizedStrings["Ungrouped @ Computed Style variables section"] = "Ungrouped";
    15921606/* Property value for `font-variant-capitals: unicase`. */
    15931607localizedStrings["Unicase @ Font Details Sidebar Property Value"] = "Unicase";
  • trunk/Source/WebInspectorUI/UserInterface/Models/DOMNodeStyles.js

    r285896 r286876  
    4949        this._usedCSSVariables = new Set;
    5050        this._allCSSVariables = new Set;
     51        this._variableStylesByType = null;
    5152
    5253        this._pendingRefreshTask = null;
     
    143144    {
    144145        return WI.DOMNodeStyles.uniqueOrderedStyles(this._orderedStyles);
     146    }
     147
     148    get variableStylesByType()
     149    {
     150        if (this._variableStylesByType)
     151            return this._variableStylesByType;
     152
     153        let properties = this._computedStyle?.properties;
     154        if (!properties)
     155            return new Map;
     156
     157        // Will iterate in order through type checkers for each CSS variable to identify its type.
     158        // The catch-all "other" must always be last.
     159        const typeCheckFunctions = [
     160            {
     161                type: WI.DOMNodeStyles.VariablesGroupType.Colors,
     162                checker: (property) => WI.Color.fromString(property.value),
     163            },
     164            {
     165                type: WI.DOMNodeStyles.VariablesGroupType.Dimensions,
     166                // FIXME: <https://webkit.org/b/233576> build RegExp from `WI.CSSCompletions.lengthUnits`.
     167                checker: (property) => /^-?\d+(\.\d+)?\D+$/.test(property.value),
     168            },
     169            {
     170                type: WI.DOMNodeStyles.VariablesGroupType.Numbers,
     171                checker: (property) => /^-?\d+(\.\d+)?$/.test(property.value),
     172            },
     173            {
     174                type: WI.DOMNodeStyles.VariablesGroupType.Other,
     175                checker: (property) => true,
     176            },
     177        ];
     178
     179        let variablesForType = {};
     180        for (let property of properties) {
     181            if (!property.isVariable)
     182                continue;
     183
     184            for (let {type, checker} of typeCheckFunctions) {
     185                if (checker(property)) {
     186                    variablesForType[type] ||= [];
     187                    variablesForType[type].push(property);
     188                    break;
     189                }
     190            }
     191        }
     192
     193        this._variableStylesByType = new Map;
     194        for (let {type} of typeCheckFunctions) {
     195            if (!variablesForType[type]?.length)
     196                continue;
     197
     198            const ownerStyleSheet = null;
     199            const id = null;
     200            const inherited = false;
     201            const text = null;
     202            let style = new WI.CSSStyleDeclaration(this, ownerStyleSheet, id, WI.CSSStyleDeclaration.Type.Computed, this._node, inherited, text, variablesForType[type]);
     203            this._variableStylesByType.set(type, style);
     204        }
     205
     206        return this._variableStylesByType;
    145207    }
    146208
     
    316378            }
    317379
     380            if (significantChange)
     381                this._variableStylesByType = null;
     382
    318383            this._previousStylesMap = null;
    319384            this._includeUserAgentRulesOnNextRefresh = false;
     
    9931058    Refreshed: "dom-node-styles-refreshed"
    9941059};
     1060
     1061WI.DOMNodeStyles.VariablesGroupType = {
     1062    Ungrouped: "ungrouped",
     1063    Colors: "colors",
     1064    Dimensions: "dimensions",
     1065    Numbers: "numbers",
     1066    Other: "other",
     1067};
  • trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.css

    r279510 r286876  
    3333}
    3434
    35 .sidebar > .panel.details.css-style > .content > .computed > .details-section > .content {
     35/* Ensure that font is overwritten for both top-level and nested details sections. */
     36.sidebar > .panel.details.css-style > .content > .computed .details-section > .content {
    3637    font: 12px -webkit-system-font, sans-serif;
    3738}
     
    4647}
    4748
    48 .sidebar > .panel.details.css-style > .content > .computed .property {
    49     position: relative;
     49.sidebar > .panel.details.css-style > .content > .computed .details-section.computed-style-variables .computed-property-item {
    5050    text-indent: -13px; /* width of "--" in `11px Menlo` */
    5151}
     
    6060    display: none;
    6161}
     62
     63.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode {
     64    margin-top: -1px;
     65    font-weight: normal;
     66}
     67
     68.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode.default-item-selected:not(:hover) {
     69    --scope-bar-text-color-override: var(--text-color);
     70    --scope-bar-background-color-override: transparent;
     71    --scope-bar-border-color-override: transparent;
     72}
     73
     74.sidebar > .panel.details.css-style > .content > .computed > .details-section.computed-style-variables .scope-bar.computed-style-variables-grouping-mode.default-item-selected:hover {
     75    --scope-bar-background-opacity-override: 0.5;
     76}
  • trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.js

    r271927 r286876  
    3434
    3535        this._filterText = null;
     36        this._detailsSectionByStyleSectionMap = new Map;
     37        this._variablesStyleSectionForGroupTypeMap = new Map;
     38    }
     39
     40    // Static
     41
     42    static displayNameForVariablesGroupType(variablesGroupType)
     43    {
     44        switch (variablesGroupType) {
     45        case WI.DOMNodeStyles.VariablesGroupType.Colors:
     46            return WI.UIString("Colors", "Colors @ Computed Style variables section", "Section header for the group of CSS variables with colors as values");
     47
     48        case WI.DOMNodeStyles.VariablesGroupType.Dimensions:
     49            return WI.UIString("Dimensions", "Dimensions @ Computed style variables section", "Section header for the group of CSS variables with dimensions as values");
     50
     51        case WI.DOMNodeStyles.VariablesGroupType.Numbers:
     52            return WI.UIString("Numbers", "Numbers @ Computed Style variables section", "Section header for the group of CSS variables with numbers as values");
     53
     54        case WI.DOMNodeStyles.VariablesGroupType.Other:
     55            return WI.UIString("Other", "Other @ Computed Style variables section", "Section header for the generic group of CSS variables");
     56        }
     57
     58        console.assert(false, "Unknown group type", variablesGroupType);
     59        return "";
    3660    }
    3761
     
    4165    {
    4266        return this._boxModelDiagramRow?.minimumWidth ?? 0;
     67    }
     68
     69    get variablesGroupingMode()
     70    {
     71        console.assert(this._variablesGroupingModeScopeBar.selectedItems[0], "No selected variables grouping mode", this._variablesGroupingModeScopeBar.selectedItems);
     72        return this._variablesGroupingModeScopeBar.selectedItems[0].id;
    4373    }
    4474
     
    5585        this._computedStyleSection.style = this.nodeStyles.computedStyle;
    5686        this._propertiesSection.element.classList.toggle("hidden", !this._computedStyleSection.propertiesToRender.length);
    57 
    58         this._variablesTextEditor.style = this.nodeStyles.computedStyle;
    59         this._variablesSection.element.classList.toggle("hidden", !this._variablesTextEditor.propertiesToRender.length);
    60 
    6187        this._boxModelDiagramRow.nodeStyles = this.nodeStyles;
     88
     89        let styleGroups = new Map;
     90
     91        switch (this.variablesGroupingMode) {
     92        case WI.ComputedStyleDetailsPanel.VariablesGroupingMode.Ungrouped:
     93            styleGroups.set(this._variablesStyleSectionForGroupTypeMap.get(WI.DOMNodeStyles.VariablesGroupType.Ungrouped), this.nodeStyles.computedStyle);
     94            break;
     95
     96        case WI.ComputedStyleDetailsPanel.VariablesGroupingMode.ByType:
     97            styleGroups = this.nodeStyles.variableStylesByType;
     98            break;
     99        }
     100
     101        for (let [type, style] of styleGroups) {
     102            let variablesStyleSection = this._variablesStyleSectionForGroupTypeMap.get(type);
     103            if (!variablesStyleSection) {
     104                this.needsLayout();
     105                break;
     106            }
     107
     108            variablesStyleSection.style = style;
     109
     110            let detailsSection = this._detailsSectionByStyleSectionMap.get(variablesStyleSection);
     111            detailsSection.element.classList.toggle("hidden", !variablesStyleSection.propertiesToRender.length);
     112        }
    62113
    63114        if (this._filterText)
     
    74125            return;
    75126
    76         this._computedStyleSection.applyFilter(filterText);
    77         this._variablesTextEditor.applyFilter(filterText);
     127        for (let styleSection of this._detailsSectionByStyleSectionMap.keys())
     128            styleSection.applyFilter(filterText);
    78129    }
    79130
     
    119170        let propertiesGroup = new WI.DetailsSectionGroup([propertiesRow]);
    120171        this._propertiesSection = new WI.DetailsSection("computed-style-properties", WI.UIString("Properties"), [propertiesGroup], propertyFiltersElement);
    121         this._propertiesSection.addEventListener(WI.DetailsSection.Event.CollapsedStateChanged, this._handlePropertiesSectionCollapsedStateChanged, this);
     172        this._propertiesSection.addEventListener(WI.DetailsSection.Event.CollapsedStateChanged, this._handleDetailsSectionCollapsedStateChanged, this);
    122173
    123174        this.addSubview(this._computedStyleSection);
    124175
    125176        propertiesRow.element.appendChild(this._computedStyleSection.element);
    126 
    127         this._variablesTextEditor = new WI.SpreadsheetCSSStyleDeclarationEditor(this);
    128         this._variablesTextEditor.propertyVisibilityMode = WI.SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.HideNonVariables;
    129         this._variablesTextEditor.hideFilterNonMatchingProperties = true;
    130         this._variablesTextEditor.sortPropertiesByName = true;
    131         this._variablesTextEditor.addEventListener(WI.SpreadsheetCSSStyleDeclarationEditor.Event.FilterApplied, this._handleEditorFilterApplied, this);
    132         this._variablesTextEditor.element.dir = "ltr";
    133 
    134         let variablesRow = new WI.DetailsSectionRow;
    135         let variablesGroup = new WI.DetailsSectionGroup([variablesRow]);
    136         this._variablesSection = new WI.DetailsSection("computed-style-variables", WI.UIString("Variables"), [variablesGroup]);
    137         this._variablesSection.addEventListener(WI.DetailsSection.Event.CollapsedStateChanged, this._handleVariablesSectionCollapsedStateChanged, this);
    138 
    139         this.addSubview(this._variablesTextEditor);
    140 
    141         variablesRow.element.appendChild(this._variablesTextEditor.element);
     177        this._detailsSectionByStyleSectionMap.set(this._computedStyleSection, this._propertiesSection);
     178
     179        let variablesGroupingModeScopeBarItems = [
     180            new WI.ScopeBarItem(WI.ComputedStyleDetailsPanel.VariablesGroupingMode.Ungrouped, WI.UIString("Ungrouped", "Ungrouped @ Computed Style variables grouping mode", "Label for button to show CSS variables ungrouped")),
     181            new WI.ScopeBarItem(WI.ComputedStyleDetailsPanel.VariablesGroupingMode.ByType, WI.UIString("By Type", "By Type @ Computed Style variables grouping mode", "Label for button to show CSS variables grouped by type"))
     182        ];
     183
     184        const shouldGroupNonExclusiveItems = true;
     185        this._variablesGroupingModeScopeBar = new WI.ScopeBar("computed-style-variables-grouping-mode", variablesGroupingModeScopeBarItems, variablesGroupingModeScopeBarItems[0], shouldGroupNonExclusiveItems);
     186        this._variablesGroupingModeScopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._handleVariablesGroupingModeScopeBarSelectionChanged, this);
     187
     188        this._variablesRow = new WI.DetailsSectionRow;
     189        let variablesGroup = new WI.DetailsSectionGroup([this._variablesRow]);
     190        this._variablesSection = new WI.DetailsSection("computed-style-variables", WI.UIString("Variables"), [variablesGroup], this._variablesGroupingModeScopeBar.element);
     191        this._variablesSection.addEventListener(WI.DetailsSection.Event.CollapsedStateChanged, this._handleDetailsSectionCollapsedStateChanged, this);
    142192
    143193        this.element.appendChild(this._propertiesSection.element);
     
    148198    }
    149199
     200    layout()
     201    {
     202        super.layout();
     203
     204        for (let [styleSection, detailsSection] of this._detailsSectionByStyleSectionMap) {
     205            // The details section for computed properties is updated in-place by WI.ComputedStyleDetailsPanel.refresh().
     206            if (styleSection === this._computedStyleSection)
     207                continue;
     208
     209            // WI.ComputedStyleSection is a view but its element is attached to a WI.DetailsSection which isn't. Reparent it before removing.
     210            // FIXME: <https://webkit.org/b/152269> - Web Inspector: Convert DetailsSection classes to use View
     211            this.element.appendChild(styleSection.element);
     212            this.removeSubview(styleSection);
     213            styleSection.element.remove();
     214
     215            // The top-level details section for variables needs to be preserved because it's the host of nested details sections for variables groups.
     216            if (detailsSection === this._variablesSection)
     217                continue;
     218
     219            detailsSection.element.remove();
     220            this._detailsSectionByStyleSectionMap.delete(styleSection);
     221        }
     222
     223        this._variablesStyleSectionForGroupTypeMap.clear();
     224
     225        switch (this.variablesGroupingMode) {
     226        case WI.ComputedStyleDetailsPanel.VariablesGroupingMode.Ungrouped:
     227            this._renderVariablesStyleSectionGroup(this.nodeStyles.computedStyle, WI.DOMNodeStyles.VariablesGroupType.Ungrouped);
     228            break;
     229
     230        case WI.ComputedStyleDetailsPanel.VariablesGroupingMode.ByType:
     231            for (let [type, style] of this.nodeStyles.variableStylesByType)
     232                this._renderVariablesStyleSectionGroup(style, type, WI.ComputedStyleDetailsPanel.displayNameForVariablesGroupType(type));
     233            break;
     234        }
     235
     236        if (this._filterText)
     237            this.applyFilter(this._filterText);
     238    }
     239
    150240    filterDidChange(filterBar)
    151241    {
     
    154244
    155245    // Private
     246
     247    _renderVariablesStyleSectionGroup(style, groupType, label)
     248    {
     249        let variablesStyleSection = new WI.ComputedStyleSection(this);
     250        variablesStyleSection.propertyVisibilityMode = WI.ComputedStyleSection.PropertyVisibilityMode.HideNonVariables;
     251        variablesStyleSection.hideFilterNonMatchingProperties = true;
     252        variablesStyleSection.addEventListener(WI.ComputedStyleSection.Event.FilterApplied, this._handleEditorFilterApplied, this);
     253        variablesStyleSection.element.dir = "ltr";
     254        variablesStyleSection.style = style;
     255
     256        this.addSubview(variablesStyleSection);
     257
     258        let detailsSection;
     259        if (!label) {
     260            this._variablesRow.element.appendChild(variablesStyleSection.element);
     261            detailsSection = this._variablesSection;
     262        } else {
     263            let detailsSectionRow = new WI.DetailsSectionRow;
     264            let detailsSectionGroup = new WI.DetailsSectionGroup([detailsSectionRow]);
     265            detailsSection = new WI.DetailsSection(`computed-style-variables-group-${groupType}`, label, [detailsSectionGroup]);
     266            detailsSection.addEventListener(WI.DetailsSection.Event.CollapsedStateChanged, this._handleDetailsSectionCollapsedStateChanged, this);
     267
     268            detailsSectionRow.element.appendChild(variablesStyleSection.element);
     269            this._variablesRow.element.appendChild(detailsSection.element);
     270        }
     271
     272        this._detailsSectionByStyleSectionMap.set(variablesStyleSection, detailsSection);
     273        this._variablesStyleSectionForGroupTypeMap.set(groupType, variablesStyleSection);
     274    }
    156275
    157276    _computePropertyTraces(orderedDeclarations)
     
    172291    }
    173292
    174     _handlePropertiesSectionCollapsedStateChanged(event)
    175     {
    176         if (event && event.data && !event.data.collapsed)
    177             this._computedStyleSection.needsLayout();
    178     }
    179 
    180     _handleVariablesSectionCollapsedStateChanged(event)
    181     {
    182         if (event && event.data && !event.data.collapsed)
    183             this._variablesTextEditor.needsLayout();
    184     }
    185 
    186293    _handleEditorFilterApplied(event)
    187294    {
    188         let section = null;
    189         if (event.target === this._computedStyleSection)
    190             section = this._propertiesSection;
    191         else if (event.target === this._variablesTextEditor)
    192             section = this._variablesSection;
    193 
    194         if (section)
    195             section.element.classList.toggle("hidden", !event.data.matches);
     295        let section = this._detailsSectionByStyleSectionMap.get(event.target);
     296        section?.element.classList.toggle("hidden", !event.data.matches);
     297    }
     298
     299    _handleDetailsSectionCollapsedStateChanged(event)
     300    {
     301        if (event.data.collapsed)
     302            return;
     303
     304        for (let [styleSection, detailsSection] of this._detailsSectionByStyleSectionMap) {
     305            if (event.target === detailsSection) {
     306                styleSection.needsLayout();
     307                return;
     308            }
     309        }
    196310    }
    197311
     
    205319        this._computedStyleSection.showsShorthandsInsteadOfLonghands = this._computedStylePreferShorthandsSetting.value;
    206320    }
     321
     322    _handleVariablesGroupingModeScopeBarSelectionChanged(event)
     323    {
     324        this.needsLayout();
     325    }
    207326};
    208327
    209328WI.ComputedStyleDetailsPanel.StyleClassName = "computed";
     329WI.ComputedStyleDetailsPanel.VariablesGroupingMode = {
     330    Ungrouped: "ungrouped",
     331    ByType: "by-type",
     332};
  • trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleSection.js

    r270134 r286876  
    3535        this._delegate = delegate;
    3636        this._style = null;
    37         this._styleTraces = [];
     37        this._styleTraces = null;
    3838        this._propertyViews = [];
    3939
Note: See TracChangeset for help on using the changeset viewer.