Skip to content

Commit c842e97

Browse files
ktranDevtools-frontend LUCI CQ
authored andcommitted
[styles-widget] Only render sections that are not hidden
The StylesSidebarPane usually renders all sections, even though they are hidden. This is entirely managed by the StylesPropertySections. However, if we do the same in the StandaloneStylesContainer, we get many nodes that are rendered into the DOM, that are however not shown. This causes a performance bottleneck, as for visual loggign we crawl through dom nodes (and in this case, unnecessarily) on e.g. resizes. Therefore, only render the sections that are actually showing. Drive-by: Also remove the `updateFilter` from the `performUpdate` path, which is called often. Fixed: 492111118 Change-Id: I55a8df84a1da908bb52b8352ea9eee96626ea21c Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7660901 Commit-Queue: Jack Franklin <jacktfranklin@chromium.org> Commit-Queue: Kim-Anh Tran <kimanh@chromium.org> Auto-Submit: Kim-Anh Tran <kimanh@chromium.org> Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
1 parent 0bef9d1 commit c842e97

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

front_end/panels/elements/StandaloneStylesContainer.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import {
1818
setMockConnectionResponseHandler,
1919
} from '../../testing/MockConnection.js';
2020
import {
21+
getMatchedStyles,
2122
getMatchedStylesWithProperties,
23+
ruleMatch,
2224
} from '../../testing/StyleHelpers.js';
2325

2426
import * as Elements from './elements.js';
@@ -157,4 +159,64 @@ describeWithMockConnection('StandaloneStylesContainer', () => {
157159
await container.updateComplete;
158160
sinon.assert.calledOnce(repositionSpy);
159161
});
162+
163+
it('should render only matching sections from the DOM when a filter is applied', async () => {
164+
const matchedStyles = await getMatchedStyles({
165+
cssModel,
166+
node,
167+
matchedPayload: [
168+
ruleMatch('.match', {color: 'red'}),
169+
ruleMatch('.no-match', {color: 'blue'}),
170+
],
171+
});
172+
sinon.stub(cssModel, 'cachedMatchedCascadeForNode').resolves(matchedStyles);
173+
const container = new Elements.StandaloneStylesContainer.StandaloneStylesContainer();
174+
renderElementIntoDOM(container);
175+
176+
const updatePromise = new Promise<void>(resolve => {
177+
container.addEventListener(
178+
Elements.StandaloneStylesContainer.Events.STYLES_UPDATE_COMPLETED, () => resolve(), {once: true});
179+
});
180+
container.domNode = node;
181+
await updatePromise;
182+
183+
assert.lengthOf(container.contentElement.querySelectorAll('.styles-section'), 2);
184+
185+
container.filter = /\.match/;
186+
await container.updateComplete;
187+
188+
const sections = container.contentElement.querySelectorAll('.styles-section');
189+
assert.lengthOf(sections, 1);
190+
assert.include(sections[0].textContent, '.match');
191+
assert.notInclude(sections[0].textContent, '.no-match');
192+
});
193+
194+
it('should restore sections to the DOM when the filter is cleared', async () => {
195+
const matchedStyles = await getMatchedStyles({
196+
cssModel,
197+
node,
198+
matchedPayload: [
199+
ruleMatch('.match', {color: 'red'}),
200+
ruleMatch('.no-match', {color: 'blue'}),
201+
],
202+
});
203+
sinon.stub(cssModel, 'cachedMatchedCascadeForNode').resolves(matchedStyles);
204+
const container = new Elements.StandaloneStylesContainer.StandaloneStylesContainer();
205+
renderElementIntoDOM(container);
206+
207+
const updatePromise = new Promise<void>(resolve => {
208+
container.addEventListener(
209+
Elements.StandaloneStylesContainer.Events.STYLES_UPDATE_COMPLETED, () => resolve(), {once: true});
210+
});
211+
container.domNode = node;
212+
await updatePromise;
213+
214+
container.filter = /\.match/;
215+
await container.updateComplete;
216+
assert.lengthOf(container.contentElement.querySelectorAll('.styles-section'), 1);
217+
218+
container.filter = null;
219+
await container.updateComplete;
220+
assert.lengthOf(container.contentElement.querySelectorAll('.styles-section'), 2);
221+
});
160222
});

front_end/panels/elements/StandaloneStylesContainer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,15 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
130130
this.sectionByElement.set(section.element, section);
131131
}
132132
this.#sections = newSections;
133+
this.#updateFilter();
133134
this.swatchPopoverHelper().reposition();
134135
}
135136

136137
override async performUpdate(): Promise<void> {
137138
this.hideAllPopovers();
138139

139-
this.#updateFilter();
140-
141140
const viewInput: ViewInput = {
142-
sections: this.#sections,
141+
sections: this.#sections.filter(section => !section.isHidden()),
143142
};
144143
this.#view(viewInput, undefined, this.contentElement);
145144
this.#onUpdateFinished();
@@ -170,6 +169,7 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
170169
set filter(regex: RegExp|null) {
171170
this.#filter = regex;
172171
this.#updateFilter();
172+
this.requestUpdate();
173173
}
174174

175175
node(): SDK.DOMModel.DOMNode|null {

0 commit comments

Comments
 (0)