Skip to content

Commit aca4faa

Browse files
danilsomsikovDevtools-frontend LUCI CQ
authored andcommitted
Use LitHTML for rendering tree elements content in SearchResultsPane
This change refactors the `SearchResultsPane` to use LitHTML for rendering the file name, match count, and individual search matches. Bug: 407751814 Change-Id: I3d96c6a38adbba88ecaf352d463ad50e1ececacd Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6961076 Reviewed-by: Philip Pfaffe <[email protected]> Commit-Queue: Philip Pfaffe <[email protected]> Auto-Submit: Danil Somsikov <[email protected]>
1 parent 95eff53 commit aca4faa

File tree

3 files changed

+35
-49
lines changed

3 files changed

+35
-49
lines changed

front_end/panels/search/SearchResultsPane.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import * as TextUtils from '../../models/text_utils/text_utils.js';
66
import * as Workspace from '../../models/workspace/workspace.js';
7+
import {stripLitHtmlCommentNodes} from '../../testing/DOMHelpers.js';
78
import {describeWithLocale} from '../../testing/EnvironmentHelpers.js';
89

910
import * as Search from './search.js';
@@ -219,7 +220,7 @@ describeWithLocale('SearchResultsPane', () => {
219220

220221
const matchSpans = resultPane['treeOutline'].shadowRoot.querySelectorAll('.search-match-content');
221222
assert.lengthOf(matchSpans, 3);
222-
assert.deepEqual([...matchSpans].map(span => span.innerHTML), [
223+
assert.deepEqual([...matchSpans].map(span => stripLitHtmlCommentNodes(span.innerHTML)), [
223224
'This is <span class="highlighted-search-result">the</span> line with multiple "the" matches',
224225
'… the line with multiple "<span class="highlighted-search-result">the</span>" matches',
225226
'…is a line with only one "<span class="highlighted-search-result">the</span>" match',

front_end/panels/search/SearchResultsPane.ts

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44
/* eslint-disable rulesdir/no-imperative-dom-api */
5+
/* eslint-disable rulesdir/no-lit-render-outside-of-view */
56

67
import * as Common from '../../core/common/common.js';
78
import * as i18n from '../../core/i18n/i18n.js';
89
import * as Platform from '../../core/platform/platform.js';
910
import * as TextUtils from '../../models/text_utils/text_utils.js';
1011
import type * as Workspace from '../../models/workspace/workspace.js';
11-
import * as Components from '../../ui/legacy/components/utils/utils.js';
1212
import * as UI from '../../ui/legacy/legacy.js';
13+
import {html, render} from '../../ui/lit/lit.js';
1314

1415
import searchResultsPaneStyles from './searchResultsPane.css.js';
1516
import type {SearchResult} from './SearchScope.js';
@@ -137,31 +138,23 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
137138

138139
private updateSearchMatches(): void {
139140
this.listItemElement.classList.add('search-result');
140-
141-
const fileNameSpan = span(this.searchResult.label(), 'search-result-file-name');
142-
fileNameSpan.appendChild(span('\u2014', 'search-result-dash'));
143-
fileNameSpan.appendChild(span(this.searchResult.description(), 'search-result-qualifier'));
141+
// clang-format off
142+
render(html`
143+
<span class="search-result-file-name">${this.searchResult.label()}
144+
<span class="search-result-dash">${'\u2014'}</span>
145+
<span class="search-result-qualifier">${this.searchResult.description()}</span>
146+
</span>
147+
<span class="search-result-matches-count"
148+
aria-label=${i18nString(UIStrings.matchesCountS, {PH1: this.searchResult.matchesCount()})}>
149+
${this.searchResult.matchesCount()}
150+
</span>`,
151+
this.listItemElement);
152+
// clang-format on
144153

145154
this.tooltip = this.searchResult.description();
146-
this.listItemElement.appendChild(fileNameSpan);
147-
const matchesCountSpan = document.createElement('span');
148-
matchesCountSpan.className = 'search-result-matches-count';
149-
150-
matchesCountSpan.textContent = `${this.searchResult.matchesCount()}`;
151-
UI.ARIAUtils.setLabel(
152-
matchesCountSpan, i18nString(UIStrings.matchesCountS, {PH1: this.searchResult.matchesCount()}));
153-
154-
this.listItemElement.appendChild(matchesCountSpan);
155155
if (this.expanded) {
156156
this.updateMatchesUI();
157157
}
158-
159-
function span(text: string, className: string): Element {
160-
const span = document.createElement('span');
161-
span.className = className;
162-
span.textContent = text;
163-
return span;
164-
}
165158
}
166159

167160
private appendSearchMatches(fromIndex: number, toIndex: number): void {
@@ -195,28 +188,29 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
195188
({lineSegment: lineContent, matchRanges} = lineSegmentForMultipleMatches(lineContent, matchRanges));
196189
}
197190

198-
const anchor = Components.Linkifier.Linkifier.linkifyRevealable(
199-
searchResult.matchRevealable(i), '', undefined, undefined, undefined, 'search-match');
200-
anchor.classList.add('search-match-link');
201-
anchor.tabIndex = 0;
202-
const labelSpan = document.createElement('span');
203-
labelSpan.classList.add('search-match-line-number');
204191
const resultLabel = searchResult.matchLabel(i);
205-
labelSpan.textContent = resultLabel;
206-
if (typeof resultLabel === 'number' && !isNaN(resultLabel)) {
207-
UI.ARIAUtils.setLabel(labelSpan, i18nString(UIStrings.lineS, {PH1: resultLabel}));
208-
} else {
209-
UI.ARIAUtils.setLabel(labelSpan, resultLabel);
210-
}
211-
anchor.appendChild(labelSpan);
212-
213-
const contentSpan = this.createContentSpan(lineContent, matchRanges);
214-
anchor.appendChild(contentSpan);
215192

216193
const searchMatchElement = new UI.TreeOutline.TreeElement();
217194
this.appendChild(searchMatchElement);
195+
// clang-format off
196+
render(html`
197+
<button class="devtools-link text-button link-style search-match-link"
198+
jslog="Link; context: search-match; track: click" role="link" tabindex="0"
199+
@click=${() => void Common.Revealer.reveal(searchResult.matchRevealable(i))}>
200+
<span class="search-match-line-number"
201+
aria-label=${typeof resultLabel === 'number' && !isNaN(resultLabel)
202+
? i18nString(UIStrings.lineS, {PH1: resultLabel}) : resultLabel}>
203+
${resultLabel}
204+
</span>
205+
<span class="search-match-content" aria-label="${lineContent} line">
206+
${lineContent}
207+
</span>
208+
</button>`,
209+
searchMatchElement.listItemElement);
210+
// clang-format on
211+
const contentSpan = searchMatchElement.listItemElement.querySelector('.search-match-content') as HTMLElement;
212+
UI.UIUtils.highlightRangesWithStyleClass(contentSpan, matchRanges, 'highlighted-search-result');
218213
searchMatchElement.listItemElement.className = 'search-match';
219-
searchMatchElement.listItemElement.appendChild(anchor);
220214
searchMatchElement.listItemElement.addEventListener('keydown', event => {
221215
if (event.key === 'Enter') {
222216
event.consume(true);
@@ -237,15 +231,6 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
237231
this.showMoreMatchesElementSelected.bind(this, showMoreMatchesTreeElement, startMatchIndex);
238232
}
239233

240-
private createContentSpan(lineContent: string, matchRanges: TextUtils.TextRange.SourceRange[]): Element {
241-
const contentSpan = document.createElement('span');
242-
contentSpan.className = 'search-match-content';
243-
contentSpan.textContent = lineContent;
244-
UI.ARIAUtils.setLabel(contentSpan, `${lineContent} line`);
245-
UI.UIUtils.highlightRangesWithStyleClass(contentSpan, matchRanges, 'highlighted-search-result');
246-
return contentSpan;
247-
}
248-
249234
private regexMatchRanges(lineContent: string, regex: RegExp): TextUtils.TextRange.SourceRange[] {
250235
regex.lastIndex = 0;
251236
let match;

test/e2e_non_hosted/search/search-scope_test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe('The Search Panel', () => {
5555

5656
// Wrap the entries with the file details.
5757
return {
58-
fileName: fileNameElement.firstChild?.textContent || '',
58+
fileName: fileNameElement.deepInnerText().split('\u2014')[0],
5959
matchesCount: parseInt(matchesCountElement.textContent || '', 10),
6060
};
6161
})));

0 commit comments

Comments
 (0)