豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit a4a64ee

Browse files
danilsomsikovDevtools-frontend LUCI CQ
authored andcommitted
Move the utilities related to the markup highlighting to a dedicated component
Also converted layout test to a unit test Bug: 414792736 Change-Id: I2c91125cb7c146f277a0d7c98e327805510cf724 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7207547 Reviewed-by: Nikolay Vitkov <nvitkov@chromium.org> Commit-Queue: Danil Somsikov <dsv@chromium.org>
1 parent a88394a commit a4a64ee

File tree

17 files changed

+313
-202
lines changed

17 files changed

+313
-202
lines changed

config/gni/devtools_grd_files.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,6 +2388,7 @@ grd_files_unbundled_sources = [
23882388
"front_end/ui/components/helpers/scheduled-render.js",
23892389
"front_end/ui/components/highlighting/HighlightElement.js",
23902390
"front_end/ui/components/highlighting/HighlightManager.js",
2391+
"front_end/ui/components/highlighting/MarkupHighlight.js",
23912392
"front_end/ui/components/icon_button/FileSourceIcon.js",
23922393
"front_end/ui/components/icon_button/Icon.js",
23932394
"front_end/ui/components/icon_button/IconButton.js",

front_end/panels/console/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ devtools_ui_module("console") {
5353
"../../models/text_utils:bundle",
5454
"../../third_party/codemirror.next:bundle",
5555
"../../ui/components/code_highlighter:bundle",
56+
"../../ui/components/highlighting:bundle",
5657
"../../ui/components/icon_button:bundle",
5758
"../../ui/components/request_link_icon:bundle",
5859
"../../ui/components/text_editor:bundle",

front_end/panels/console/ConsoleView.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
4747
import * as Logs from '../../models/logs/logs.js';
4848
import * as TextUtils from '../../models/text_utils/text_utils.js';
4949
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
50+
import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
5051
import * as IconButton from '../../ui/components/icon_button/icon_button.js';
5152
import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
5253
// eslint-disable-next-line @devtools/es-modules-import
@@ -1618,7 +1619,7 @@ export class ConsoleView extends UI.Widget.VBox implements
16181619
matchRange = this.regexMatchRanges[this.currentMatchRangeIndex];
16191620
const message = this.visibleViewMessages[matchRange.messageIndex];
16201621
message.searchHighlightNode(matchRange.matchIndex)
1621-
.classList.remove(UI.UIUtils.highlightedCurrentSearchResultClassName);
1622+
.classList.remove(Highlighting.highlightedCurrentSearchResultClassName);
16221623
}
16231624

16241625
index = Platform.NumberUtilities.mod(index, this.regexMatchRanges.length);
@@ -1627,7 +1628,7 @@ export class ConsoleView extends UI.Widget.VBox implements
16271628
matchRange = this.regexMatchRanges[index];
16281629
const message = this.visibleViewMessages[matchRange.messageIndex];
16291630
const highlightNode = message.searchHighlightNode(matchRange.matchIndex);
1630-
highlightNode.classList.add(UI.UIUtils.highlightedCurrentSearchResultClassName);
1631+
highlightNode.classList.add(Highlighting.highlightedCurrentSearchResultClassName);
16311632
if (scrollIntoView) {
16321633
this.viewport.scrollItemIntoView(matchRange.messageIndex);
16331634
highlightNode.scrollIntoViewIfNeeded();

front_end/panels/console/ConsoleViewMessage.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import * as TextUtils from '../../models/text_utils/text_utils.js';
4949
import * as Workspace from '../../models/workspace/workspace.js';
5050
import * as Buttons from '../../ui/components/buttons/buttons.js';
5151
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
52+
import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
5253
import * as IconButton from '../../ui/components/icon_button/icon_button.js';
5354
import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
5455
import * as RequestLinkIcon from '../../ui/components/request_link_icon/request_link_icon.js';
@@ -323,7 +324,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
323324
protected contentElementInternal: HTMLElement|null;
324325
private nestingLevelMarkers: HTMLElement[]|null;
325326
private searchHighlightNodes: Element[];
326-
private searchHighlightNodeChanges: UI.UIUtils.HighlightChange[];
327+
private searchHighlightNodeChanges: Highlighting.HighlightChange[];
327328
private isVisibleInternal: boolean;
328329
private cachedHeight: number;
329330
private messagePrefix: string;
@@ -1739,7 +1740,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
17391740

17401741
setSearchRegex(regex: RegExp|null): void {
17411742
if (this.searchHighlightNodeChanges?.length) {
1742-
UI.UIUtils.revertDomChanges(this.searchHighlightNodeChanges);
1743+
Highlighting.revertDomChanges(this.searchHighlightNodeChanges);
17431744
}
17441745
this.searchRegexInternal = regex;
17451746
this.searchHighlightNodes = [];
@@ -1757,8 +1758,9 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
17571758
}
17581759

17591760
if (sourceRanges.length) {
1760-
this.searchHighlightNodes =
1761-
UI.UIUtils.highlightSearchResults(this.contentElement(), sourceRanges, this.searchHighlightNodeChanges);
1761+
this.searchHighlightNodes = Highlighting.highlightRangesWithStyleClass(
1762+
this.contentElement(), sourceRanges, Highlighting.highlightedSearchResultClassName,
1763+
this.searchHighlightNodeChanges);
17621764
}
17631765
}
17641766

front_end/panels/elements/ElementsTreeElement.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,7 +2006,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
20062006
++highlightIndex;
20072007
}
20082008
element.setTextContentTruncatedIfNeeded(value);
2009-
UI.UIUtils.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
2009+
Highlighting.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
20102010
}
20112011

20122012
const hasText = (forceValue || value.length > 0);
@@ -2274,7 +2274,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
22742274
}
22752275
const result = convertUnicodeCharsToHTMLEntities(firstChild.nodeValue());
22762276
textNodeElement.textContent = Platform.StringUtilities.collapseWhitespace(result.text);
2277-
UI.UIUtils.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, 'webkit-html-entity-value');
2277+
Highlighting.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, 'webkit-html-entity-value');
22782278
UI.UIUtils.createTextChild(titleDOM, '\u200B');
22792279
this.buildTagDOM(titleDOM, tagName, true, false, updateRecord);
22802280
if (updateRecord?.hasChangedChildren()) {
@@ -2314,7 +2314,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
23142314
'jslog', `${VisualLogging.value('text-node').track({change: true, dblclick: true})}`);
23152315
const result = convertUnicodeCharsToHTMLEntities(node.nodeValue());
23162316
textNodeElement.textContent = Platform.StringUtilities.collapseWhitespace(result.text);
2317-
UI.UIUtils.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, 'webkit-html-entity-value');
2317+
Highlighting.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, 'webkit-html-entity-value');
23182318
UI.UIUtils.createTextChild(titleDOM, '"');
23192319
if (updateRecord?.isCharDataModified()) {
23202320
UI.UIUtils.runCSSAnimationOnce(textNodeElement, 'dom-update-highlight');

front_end/panels/elements/ElementsTreeOutline.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import * as Badges from '../../models/badges/badges.js';
4141
import * as Elements from '../../models/elements/elements.js';
4242
import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
4343
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
44+
import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
4445
import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
4546
import * as UI from '../../ui/legacy/legacy.js';
4647
import {html, nothing, render} from '../../ui/lit/lit.js';
@@ -369,7 +370,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
369370
treeElement.highlightSearchResults(query);
370371
}
371372
treeElement.reveal();
372-
const matches = treeElement.listItemElement.getElementsByClassName(UI.UIUtils.highlightedSearchResultClassName);
373+
const matches = treeElement.listItemElement.getElementsByClassName(Highlighting.highlightedSearchResultClassName);
373374
if (matches.length) {
374375
matches[0].scrollIntoViewIfNeeded(false);
375376
}

front_end/panels/sources/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ devtools_ui_module("sources") {
9292
"../../panels/utils:bundle",
9393
"../../third_party/diff:bundle",
9494
"../../ui/components/buttons:bundle",
95+
"../../ui/components/highlighting:bundle",
9596
"../../ui/components/icon_button:bundle",
9697
"../../ui/components/spinners:bundle",
9798
"../../ui/components/text_editor:bundle",

front_end/panels/sources/FilteredUISourceCodeListProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as i18n from '../../core/i18n/i18n.js';
77
import * as Root from '../../core/root/root.js';
88
import * as Persistence from '../../models/persistence/persistence.js';
99
import * as Workspace from '../../models/workspace/workspace.js';
10+
import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
1011
import * as QuickOpen from '../../ui/legacy/components/quick_open/quick_open.js';
1112
import * as UI from '../../ui/legacy/legacy.js';
1213

@@ -181,9 +182,9 @@ export class FilteredUISourceCodeListProvider extends QuickOpen.FilteredListWidg
181182
for (let i = 0; i < ranges.length; ++i) {
182183
ranges[i].offset -= fileNameIndex + 1;
183184
}
184-
UI.UIUtils.highlightRangesWithStyleClass(titleElement, ranges, 'highlight');
185+
Highlighting.highlightRangesWithStyleClass(titleElement, ranges, 'highlight');
185186
} else {
186-
UI.UIUtils.highlightRangesWithStyleClass(subtitleElement, ranges, 'highlight');
187+
Highlighting.highlightRangesWithStyleClass(subtitleElement, ranges, 'highlight');
187188
}
188189
}
189190

front_end/ui/components/highlighting/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ devtools_ui_module("highlighting") {
1212
sources = [
1313
"HighlightElement.ts",
1414
"HighlightManager.ts",
15+
"MarkupHighlight.ts",
1516
]
1617
deps = [ "../../../models/text_utils:bundle" ]
1718
}
@@ -30,6 +31,7 @@ devtools_ui_module("unittests") {
3031
sources = [
3132
"HighlightElement.test.ts",
3233
"HighlightManager.test.ts",
34+
"MarkupHighlight.test.ts",
3335
]
3436

3537
deps = [
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright 2025 The Chromium Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import * as TextUtils from '../../../models/text_utils/text_utils.js';
6+
import {renderElementIntoDOM} from '../../../testing/DOMHelpers.js';
7+
8+
import * as Highlighting from './highlighting.js';
9+
10+
describe('MarkupHighlight', () => {
11+
let container: HTMLDivElement;
12+
13+
beforeEach(() => {
14+
container = document.createElement('div');
15+
renderElementIntoDOM(container);
16+
});
17+
18+
function range(offset: number, length: number): TextUtils.TextRange.SourceRange {
19+
return new TextUtils.TextRange.SourceRange(offset, length);
20+
}
21+
22+
function performTest(innerHTML: string[], ranges: TextUtils.TextRange.SourceRange[], expectedHighlighted: string[]) {
23+
const element = document.createElement('div');
24+
element.innerHTML = innerHTML.join('');
25+
container.appendChild(element);
26+
27+
const initialHTML = element.innerHTML;
28+
const initialText = element.textContent || '';
29+
const changes: Highlighting.HighlightChange[] = [];
30+
Highlighting.highlightRangesWithStyleClass(element, ranges, 'highlighted', changes);
31+
assert.strictEqual(element.innerHTML, expectedHighlighted.join(''), 'After highlight');
32+
Highlighting.revertDomChanges(changes);
33+
assert.strictEqual(element.innerHTML, initialHTML, 'After revert');
34+
assert.strictEqual(element.textContent, initialText, 'After revert');
35+
}
36+
37+
it('highlights whole text node', () => {
38+
performTest(['function'], [range(0, 8)], ['<span class="highlighted">function</span>']);
39+
});
40+
41+
it('highlights only text node beginning', () => {
42+
performTest(['function'], [range(0, 7)], ['<span class="highlighted">functio</span>n']);
43+
});
44+
45+
it('highlights only text node ending', () => {
46+
performTest(['function'], [range(1, 7)], ['f<span class="highlighted">unction</span>']);
47+
});
48+
49+
it('highlights in the middle of text node', () => {
50+
performTest(['function'], [range(1, 6)], ['f<span class="highlighted">unctio</span>n']);
51+
});
52+
53+
it('highlights all text in 3 text nodes', () => {
54+
performTest(
55+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'], [range(0, 21)],
56+
['<span><span class="highlighted">function functionName</span></span>', '<span></span>', '<span></span>']);
57+
});
58+
59+
it('highlights all text in 3 text nodes except for the last character', () => {
60+
performTest(
61+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'], [range(0, 20)],
62+
['<span><span class="highlighted">function functionNam</span></span>', '<span></span>', '<span>e</span>']);
63+
});
64+
65+
it('highlights all text in 3 text nodes except for the first character', () => {
66+
performTest(
67+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'], [range(1, 20)],
68+
['<span>f<span class="highlighted">unction functionName</span></span>', '<span></span>', '<span></span>']);
69+
});
70+
71+
it('highlights all text in 3 text nodes except for the first and the last characters', () => {
72+
performTest(
73+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'], [range(1, 19)],
74+
['<span>f<span class="highlighted">unction functionNam</span></span>', '<span></span>', '<span>e</span>']);
75+
});
76+
77+
it('highlights across nodes', () => {
78+
performTest(
79+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'], [range(7, 3)],
80+
['<span>functio<span class="highlighted">n f</span></span>', '<span></span>', '<span>unctionName</span>']);
81+
});
82+
83+
it('highlights first characters in text nodes', () => {
84+
performTest(
85+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'],
86+
[range(0, 1), range(8, 1), range(9, 1)], [
87+
'<span><span class="highlighted">f</span>unction</span>', //
88+
'<span><span class="highlighted"> </span></span>',
89+
'<span><span class="highlighted">f</span>unctionName</span>'
90+
]);
91+
});
92+
93+
it('highlights last characters in text node', () => {
94+
performTest(
95+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'],
96+
[range(7, 1), range(8, 1), range(20, 1)], [
97+
'<span>functio<span class="highlighted">n</span></span>', //
98+
'<span><span class="highlighted"> </span></span>',
99+
'<span>functionNam<span class="highlighted">e</span></span>'
100+
]);
101+
});
102+
103+
it('highlights across nodes with first and last characters', () => {
104+
performTest(
105+
['<span>function</span>', '<span> </span>', '<span>functionName</span>'],
106+
[range(0, 1), range(7, 3), range(20, 1)], [
107+
'<span><span class="highlighted">f</span>unctio<span class="highlighted">n f</span></span>', //
108+
'<span></span>', //
109+
'<span>unctionNam<span class="highlighted">e</span></span>'
110+
]);
111+
});
112+
});

0 commit comments

Comments
 (0)