blob: b45c9e82b7c56c6a50d58b029dd0a8d28aba8c29 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371// Copyright (c) 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Tim van der Lippe97611c92020-02-12 16:56:584
Tim van der Lippe115b1772021-03-23 15:22:085import * as Common from '../../common/common.js';
Tim van der Lippeaa1ed7a2021-03-31 14:38:276import * as Platform from '../../core/platform/platform.js';
Tim van der Lippe115b1772021-03-23 15:22:087import * as i18n from '../../i18n/i18n.js';
Tim van der Lippe115b1772021-03-23 15:22:088import * as SDK from '../../sdk/sdk.js';
9import * as UI from '../../ui/ui.js';
Tim van der Lippe97611c92020-02-12 16:56:5810
Tim van der Lippeaabc8302019-12-10 15:34:4511import {ElementsPanel} from './ElementsPanel.js';
12
Simon Zündfbfd1072021-03-01 07:38:5313const UIStrings = {
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4914 /**
Peter Marshallcc995412021-02-19 08:07:4315 * @description Prompt text for a text field in the Classes Pane Widget of the Elements panel.
16 * Class refers to a CSS class.
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4917 */
18 addNewClass: 'Add new class',
19 /**
Peter Marshallcc995412021-02-19 08:07:4320 * @description Screen reader announcement string when adding a CSS class via the Classes Pane Widget.
21 * @example {vbox flex-auto} PH1
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4922 */
Peter Marshallcc995412021-02-19 08:07:4323 classesSAdded: 'Classes {PH1} added',
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4924 /**
Peter Marshallcc995412021-02-19 08:07:4325 * @description Screen reader announcement string when adding a class via the Classes Pane Widget.
26 * @example {title-container} PH1
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4927 */
Peter Marshallcc995412021-02-19 08:07:4328 classSAdded: 'Class {PH1} added',
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4929 /**
Peter Marshallcc995412021-02-19 08:07:4330 * @description Accessible title read by screen readers for the Classes Pane Widget of the Elements
31 * panel. Element is a HTML DOM Element and classes refers to CSS classes.
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4932 */
33 elementClasses: 'Element Classes',
34};
Tim van der Lippe115b1772021-03-23 15:22:0835const str_ = i18n.i18n.registerUIStrings('panels/elements/ClassesPaneWidget.js', UIStrings);
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4936const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
Tim van der Lippe97611c92020-02-12 16:56:5837export class ClassesPaneWidget extends UI.Widget.Widget {
Blink Reformat4c46d092018-04-07 15:32:3738 constructor() {
39 super(true);
Tim van der Lippe115b1772021-03-23 15:22:0840 this.registerRequiredCSS('panels/elements/classesPaneWidget.css', {enableLegacyPatching: true});
Blink Reformat4c46d092018-04-07 15:32:3741 this.contentElement.className = 'styles-element-classes-pane';
42 const container = this.contentElement.createChild('div', 'title-container');
43 this._input = container.createChild('div', 'new-class-input monospace');
44 this.setDefaultFocusedElement(this._input);
45 this._classesContainer = this.contentElement.createChild('div', 'source-code');
46 this._classesContainer.classList.add('styles-element-classes-container');
Tim van der Lippe13f71fb2019-11-29 11:17:3947 this._prompt = new ClassNamePrompt(this._nodeClasses.bind(this));
Blink Reformat4c46d092018-04-07 15:32:3748 this._prompt.setAutocompletionTimeout(0);
49 this._prompt.renderAsBlock();
50
Tim van der Lippebcd6b5c2021-01-13 12:31:5151 const proxyElement = /** @type {!HTMLElement} */ (this._prompt.attach(this._input));
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4952 this._prompt.setPlaceholder(i18nString(UIStrings.addNewClass));
Blink Reformat4c46d092018-04-07 15:32:3753 this._prompt.addEventListener(UI.TextPrompt.Events.TextChanged, this._onTextChanged, this);
54 proxyElement.addEventListener('keydown', this._onKeyDown.bind(this), false);
55
Paul Lewisdaac1062020-03-05 14:37:1056 SDK.SDKModel.TargetManager.instance().addModelListener(
Tim van der Lippe97611c92020-02-12 16:56:5857 SDK.DOMModel.DOMModel, SDK.DOMModel.Events.DOMMutated, this._onDOMMutated, this);
58 /** @type {!Set<!SDK.DOMModel.DOMNode>} */
Blink Reformat4c46d092018-04-07 15:32:3759 this._mutatingNodes = new Set();
Tim van der Lippe97611c92020-02-12 16:56:5860 /** @type {!Map<!SDK.DOMModel.DOMNode, string>} */
Blink Reformat4c46d092018-04-07 15:32:3761 this._pendingNodeClasses = new Map();
Tim van der Lippe97611c92020-02-12 16:56:5862 this._updateNodeThrottler = new Common.Throttler.Throttler(0);
63 /** @type {?SDK.DOMModel.DOMNode} */
Blink Reformat4c46d092018-04-07 15:32:3764 this._previousTarget = null;
Tim van der Lipped1a00aa2020-08-19 16:03:5665 UI.Context.Context.instance().addFlavorChangeListener(SDK.DOMModel.DOMNode, this._onSelectedNodeChanged, this);
Blink Reformat4c46d092018-04-07 15:32:3766 }
67
68 /**
69 * @param {string} text
70 * @return {!Array.<string>}
71 */
72 _splitTextIntoClasses(text) {
Mathias Bynens3abc0952020-04-20 14:15:5273 return text.split(/[,\s]/).map(className => className.trim()).filter(className => className.length);
Blink Reformat4c46d092018-04-07 15:32:3774 }
75
76 /**
Tim van der Lippebcd6b5c2021-01-13 12:31:5177 * @param {!KeyboardEvent} event
Blink Reformat4c46d092018-04-07 15:32:3778 */
79 _onKeyDown(event) {
Tim van der Lippebcd6b5c2021-01-13 12:31:5180 if (!(event.key === 'Enter') && !isEscKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:3781 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3482 }
Blink Reformat4c46d092018-04-07 15:32:3783
Tim van der Lippebcd6b5c2021-01-13 12:31:5184 if (event.key === 'Enter') {
Blink Reformat4c46d092018-04-07 15:32:3785 event.consume();
Tim van der Lippe1d6e57a2019-09-30 11:55:3486 if (this._prompt.acceptAutoComplete()) {
Blink Reformat4c46d092018-04-07 15:32:3787 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3488 }
Blink Reformat4c46d092018-04-07 15:32:3789 }
90
Tim van der Lippe32f760f2020-10-01 10:52:1591 const eventTarget = /** @type {!HTMLElement} */ (event.target);
92 let text = /** @type {string} */ (eventTarget.textContent);
Blink Reformat4c46d092018-04-07 15:32:3793 if (isEscKey(event)) {
Simon Zündda7058f2020-02-28 13:57:2894 if (!Platform.StringUtilities.isWhitespace(text)) {
Blink Reformat4c46d092018-04-07 15:32:3795 event.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:3496 }
Blink Reformat4c46d092018-04-07 15:32:3797 text = '';
98 }
99
100 this._prompt.clearAutocomplete();
Tim van der Lippe32f760f2020-10-01 10:52:15101 eventTarget.textContent = '';
Blink Reformat4c46d092018-04-07 15:32:37102
Tim van der Lipped1a00aa2020-08-19 16:03:56103 const node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34104 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37105 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34106 }
Blink Reformat4c46d092018-04-07 15:32:37107
108 const classNames = this._splitTextIntoClasses(text);
Michael Liaocafccfd2020-04-02 17:11:59109 if (!classNames.length) {
Patrick Brosset78fa1f52020-08-17 14:33:48110 this._installNodeClasses(node);
Michael Liaocafccfd2020-04-02 17:11:59111 return;
112 }
113
Tim van der Lippe1d6e57a2019-09-30 11:55:34114 for (const className of classNames) {
Blink Reformat4c46d092018-04-07 15:32:37115 this._toggleClass(node, className, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34116 }
Michael Liaocafccfd2020-04-02 17:11:59117
118 // annoucementString is used for screen reader to announce that the class(es) has been added successfully.
119 const joinClassString = classNames.join(' ');
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:49120 const announcementString = classNames.length > 1 ? i18nString(UIStrings.classesSAdded, {PH1: joinClassString}) :
121 i18nString(UIStrings.classSAdded, {PH1: joinClassString});
Michael Liaocafccfd2020-04-02 17:11:59122 UI.ARIAUtils.alert(announcementString, this.contentElement);
123
Blink Reformat4c46d092018-04-07 15:32:37124 this._installNodeClasses(node);
125 this._update();
126 }
127
128 _onTextChanged() {
Tim van der Lipped1a00aa2020-08-19 16:03:56129 const node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34130 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37131 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34132 }
Blink Reformat4c46d092018-04-07 15:32:37133 this._installNodeClasses(node);
134 }
135
136 /**
Tim van der Lippec02a97c2020-02-14 14:39:27137 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37138 */
139 _onDOMMutated(event) {
Tim van der Lippe97611c92020-02-12 16:56:58140 const node = /** @type {!SDK.DOMModel.DOMNode} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34141 if (this._mutatingNodes.has(node)) {
Blink Reformat4c46d092018-04-07 15:32:37142 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34143 }
Tim van der Lippe32f760f2020-10-01 10:52:15144 cachedClassesMap.delete(node);
Blink Reformat4c46d092018-04-07 15:32:37145 this._update();
146 }
147
148 /**
Tim van der Lippec02a97c2020-02-14 14:39:27149 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37150 */
151 _onSelectedNodeChanged(event) {
152 if (this._previousTarget && this._prompt.text()) {
153 this._input.textContent = '';
154 this._installNodeClasses(this._previousTarget);
155 }
Tim van der Lippe97611c92020-02-12 16:56:58156 this._previousTarget = /** @type {?SDK.DOMModel.DOMNode} */ (event.data);
Blink Reformat4c46d092018-04-07 15:32:37157 this._update();
158 }
159
160 /**
161 * @override
162 */
163 wasShown() {
164 this._update();
165 }
166
167 _update() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34168 if (!this.isShowing()) {
Blink Reformat4c46d092018-04-07 15:32:37169 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34170 }
Blink Reformat4c46d092018-04-07 15:32:37171
Tim van der Lipped1a00aa2020-08-19 16:03:56172 let node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34173 if (node) {
Blink Reformat4c46d092018-04-07 15:32:37174 node = node.enclosingElementOrSelf();
Tim van der Lippe1d6e57a2019-09-30 11:55:34175 }
Blink Reformat4c46d092018-04-07 15:32:37176
177 this._classesContainer.removeChildren();
Tim van der Lippe32f760f2020-10-01 10:52:15178 // @ts-ignore this._input is a div, not an input element. So this line makes no sense at all
Blink Reformat4c46d092018-04-07 15:32:37179 this._input.disabled = !node;
180
Tim van der Lippe1d6e57a2019-09-30 11:55:34181 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37182 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34183 }
Blink Reformat4c46d092018-04-07 15:32:37184
185 const classes = this._nodeClasses(node);
Simon Zündf27be3d2020-02-11 14:46:27186 const keys = [...classes.keys()];
Tim van der Lippe32f760f2020-10-01 10:52:15187 keys.sort(Platform.StringUtilities.caseInsensetiveComparator);
188 for (const className of keys) {
Tim van der Lippe97611c92020-02-12 16:56:58189 const label = UI.UIUtils.CheckboxLabel.create(className, classes.get(className));
Blink Reformat4c46d092018-04-07 15:32:37190 label.classList.add('monospace');
191 label.checkboxElement.addEventListener('click', this._onClick.bind(this, className), false);
192 this._classesContainer.appendChild(label);
193 }
194 }
195
196 /**
197 * @param {string} className
198 * @param {!Event} event
199 */
200 _onClick(className, event) {
Tim van der Lipped1a00aa2020-08-19 16:03:56201 const node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34202 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37203 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34204 }
Tim van der Lippe32f760f2020-10-01 10:52:15205 const enabled = /** @type {!HTMLInputElement} */ (event.target).checked;
Blink Reformat4c46d092018-04-07 15:32:37206 this._toggleClass(node, className, enabled);
207 this._installNodeClasses(node);
208 }
209
210 /**
Tim van der Lippe97611c92020-02-12 16:56:58211 * @param {!SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37212 * @return {!Map<string, boolean>}
213 */
214 _nodeClasses(node) {
Tim van der Lippe32f760f2020-10-01 10:52:15215 let result = cachedClassesMap.get(node);
Blink Reformat4c46d092018-04-07 15:32:37216 if (!result) {
217 const classAttribute = node.getAttribute('class') || '';
218 const classes = classAttribute.split(/\s/);
219 result = new Map();
220 for (let i = 0; i < classes.length; ++i) {
221 const className = classes[i].trim();
Tim van der Lippe1d6e57a2019-09-30 11:55:34222 if (!className.length) {
Blink Reformat4c46d092018-04-07 15:32:37223 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34224 }
Blink Reformat4c46d092018-04-07 15:32:37225 result.set(className, true);
226 }
Tim van der Lippe32f760f2020-10-01 10:52:15227 cachedClassesMap.set(node, result);
Blink Reformat4c46d092018-04-07 15:32:37228 }
229 return result;
230 }
231
232 /**
Tim van der Lippe97611c92020-02-12 16:56:58233 * @param {!SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37234 * @param {string} className
235 * @param {boolean} enabled
236 */
237 _toggleClass(node, className, enabled) {
238 const classes = this._nodeClasses(node);
239 classes.set(className, enabled);
240 }
241
242 /**
Tim van der Lippe97611c92020-02-12 16:56:58243 * @param {!SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37244 */
245 _installNodeClasses(node) {
246 const classes = this._nodeClasses(node);
247 const activeClasses = new Set();
248 for (const className of classes.keys()) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34249 if (classes.get(className)) {
Blink Reformat4c46d092018-04-07 15:32:37250 activeClasses.add(className);
Tim van der Lippe1d6e57a2019-09-30 11:55:34251 }
Blink Reformat4c46d092018-04-07 15:32:37252 }
253
254 const additionalClasses = this._splitTextIntoClasses(this._prompt.textWithCurrentSuggestion());
Tim van der Lippe1d6e57a2019-09-30 11:55:34255 for (const className of additionalClasses) {
Blink Reformat4c46d092018-04-07 15:32:37256 activeClasses.add(className);
Tim van der Lippe1d6e57a2019-09-30 11:55:34257 }
Blink Reformat4c46d092018-04-07 15:32:37258
Simon Zünda0d40622020-02-12 13:16:42259 const newClasses = [...activeClasses.values()].sort();
Blink Reformat4c46d092018-04-07 15:32:37260
261 this._pendingNodeClasses.set(node, newClasses.join(' '));
262 this._updateNodeThrottler.schedule(this._flushPendingClasses.bind(this));
263 }
264
265 /**
Tim van der Lippe32f760f2020-10-01 10:52:15266 * @return {!Promise<void>}
Blink Reformat4c46d092018-04-07 15:32:37267 */
Tim van der Lippe32f760f2020-10-01 10:52:15268 async _flushPendingClasses() {
Blink Reformat4c46d092018-04-07 15:32:37269 const promises = [];
270 for (const node of this._pendingNodeClasses.keys()) {
271 this._mutatingNodes.add(node);
Tim van der Lippe32f760f2020-10-01 10:52:15272 const promise = node.setAttributeValuePromise('class', /** @type {string} */ (this._pendingNodeClasses.get(node)))
Blink Reformat4c46d092018-04-07 15:32:37273 .then(onClassValueUpdated.bind(this, node));
274 promises.push(promise);
275 }
276 this._pendingNodeClasses.clear();
Tim van der Lippe32f760f2020-10-01 10:52:15277 await Promise.all(promises);
Blink Reformat4c46d092018-04-07 15:32:37278
279 /**
Tim van der Lippe97611c92020-02-12 16:56:58280 * @param {!SDK.DOMModel.DOMNode} node
Tim van der Lippe13f71fb2019-11-29 11:17:39281 * @this {ClassesPaneWidget}
Blink Reformat4c46d092018-04-07 15:32:37282 */
283 function onClassValueUpdated(node) {
284 this._mutatingNodes.delete(node);
285 }
286 }
Tim van der Lippe13f71fb2019-11-29 11:17:39287}
Blink Reformat4c46d092018-04-07 15:32:37288
Tim van der Lippe32f760f2020-10-01 10:52:15289/** @type {!WeakMap<!SDK.DOMModel.DOMNode, !Map<string, boolean>>} */
290const cachedClassesMap = new WeakMap();
Blink Reformat4c46d092018-04-07 15:32:37291
Andres Olivares43c2d9f2021-02-10 16:48:39292/** @type {!ButtonProvider} */
293let buttonProviderInstance;
294
Blink Reformat4c46d092018-04-07 15:32:37295/**
Tim van der Lippe97611c92020-02-12 16:56:58296 * @implements {UI.Toolbar.Provider}
Blink Reformat4c46d092018-04-07 15:32:37297 */
Tim van der Lippe13f71fb2019-11-29 11:17:39298export class ButtonProvider {
Andres Olivares43c2d9f2021-02-10 16:48:39299 /** @private */
Blink Reformat4c46d092018-04-07 15:32:37300 constructor() {
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:49301 this._button = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.elementClasses), '');
Blink Reformat4c46d092018-04-07 15:32:37302 this._button.setText('.cls');
303 this._button.element.classList.add('monospace');
Tim van der Lippe97611c92020-02-12 16:56:58304 this._button.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._clicked, this);
Tim van der Lippe13f71fb2019-11-29 11:17:39305 this._view = new ClassesPaneWidget();
Blink Reformat4c46d092018-04-07 15:32:37306 }
307
Andres Olivares43c2d9f2021-02-10 16:48:39308 /**
309 * @param {{forceNew: ?boolean}} opts
310 */
311 static instance(opts = {forceNew: null}) {
312 const {forceNew} = opts;
313 if (!buttonProviderInstance || forceNew) {
314 buttonProviderInstance = new ButtonProvider();
315 }
316
317 return buttonProviderInstance;
318 }
319
Blink Reformat4c46d092018-04-07 15:32:37320 _clicked() {
Tim van der Lippeaabc8302019-12-10 15:34:45321 ElementsPanel.instance().showToolbarPane(!this._view.isShowing() ? this._view : null, this._button);
Blink Reformat4c46d092018-04-07 15:32:37322 }
323
324 /**
325 * @override
Tim van der Lippe97611c92020-02-12 16:56:58326 * @return {!UI.Toolbar.ToolbarItem}
Blink Reformat4c46d092018-04-07 15:32:37327 */
328 item() {
329 return this._button;
330 }
Tim van der Lippe13f71fb2019-11-29 11:17:39331}
Blink Reformat4c46d092018-04-07 15:32:37332
Tim van der Lippe97611c92020-02-12 16:56:58333export class ClassNamePrompt extends UI.TextPrompt.TextPrompt {
Blink Reformat4c46d092018-04-07 15:32:37334 /**
Tim van der Lippe97611c92020-02-12 16:56:58335 * @param {function(!SDK.DOMModel.DOMNode):!Map<string, boolean>} nodeClasses
Blink Reformat4c46d092018-04-07 15:32:37336 */
337 constructor(nodeClasses) {
338 super();
339 this._nodeClasses = nodeClasses;
340 this.initialize(this._buildClassNameCompletions.bind(this), ' ');
341 this.disableDefaultSuggestionForEmptyInput();
Tim van der Lippe32f760f2020-10-01 10:52:15342 /** @type {?string} */
Blink Reformat4c46d092018-04-07 15:32:37343 this._selectedFrameId = '';
344 this._classNamesPromise = null;
345 }
346
347 /**
Tim van der Lippe97611c92020-02-12 16:56:58348 * @param {!SDK.DOMModel.DOMNode} selectedNode
Blink Reformat4c46d092018-04-07 15:32:37349 * @return {!Promise.<!Array.<string>>}
350 */
Mathias Bynens3abc0952020-04-20 14:15:52351 async _getClassNames(selectedNode) {
Blink Reformat4c46d092018-04-07 15:32:37352 const promises = [];
353 const completions = new Set();
354 this._selectedFrameId = selectedNode.frameId();
355
356 const cssModel = selectedNode.domModel().cssModel();
357 const allStyleSheets = cssModel.allStyleSheets();
358 for (const stylesheet of allStyleSheets) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34359 if (stylesheet.frameId !== this._selectedFrameId) {
Blink Reformat4c46d092018-04-07 15:32:37360 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34361 }
Mathias Bynens3abc0952020-04-20 14:15:52362 const cssPromise = cssModel.classNamesPromise(stylesheet.id).then(classes => {
363 for (const className of classes) {
364 completions.add(className);
365 }
366 });
Blink Reformat4c46d092018-04-07 15:32:37367 promises.push(cssPromise);
368 }
369
Tim van der Lippe32f760f2020-10-01 10:52:15370 const ownerDocumentId = /** @type {number} */ (
371 /** @type {!SDK.DOMModel.DOMDocument} */ (selectedNode.ownerDocument).id);
372
373 const domPromise = selectedNode.domModel().classNamesPromise(ownerDocumentId).then(classes => {
Mathias Bynens3abc0952020-04-20 14:15:52374 for (const className of classes) {
375 completions.add(className);
376 }
377 });
Blink Reformat4c46d092018-04-07 15:32:37378 promises.push(domPromise);
Mathias Bynens3abc0952020-04-20 14:15:52379 await Promise.all(promises);
380 return [...completions];
Blink Reformat4c46d092018-04-07 15:32:37381 }
382
383 /**
384 * @param {string} expression
385 * @param {string} prefix
386 * @param {boolean=} force
387 * @return {!Promise<!UI.SuggestBox.Suggestions>}
388 */
Mathias Bynens41ea2632020-12-24 05:52:49389 async _buildClassNameCompletions(expression, prefix, force) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34390 if (!prefix || force) {
Blink Reformat4c46d092018-04-07 15:32:37391 this._classNamesPromise = null;
Tim van der Lippe1d6e57a2019-09-30 11:55:34392 }
Blink Reformat4c46d092018-04-07 15:32:37393
Tim van der Lipped1a00aa2020-08-19 16:03:56394 const selectedNode = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34395 if (!selectedNode || (!prefix && !force && !expression.trim())) {
Mathias Bynens41ea2632020-12-24 05:52:49396 return [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34397 }
Blink Reformat4c46d092018-04-07 15:32:37398
Tim van der Lippe1d6e57a2019-09-30 11:55:34399 if (!this._classNamesPromise || this._selectedFrameId !== selectedNode.frameId()) {
Blink Reformat4c46d092018-04-07 15:32:37400 this._classNamesPromise = this._getClassNames(selectedNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34401 }
Blink Reformat4c46d092018-04-07 15:32:37402
Mathias Bynens41ea2632020-12-24 05:52:49403 let completions = await this._classNamesPromise;
404 const classesMap = this._nodeClasses(/** @type {!SDK.DOMModel.DOMNode} */ (selectedNode));
405 completions = completions.filter(value => !classesMap.get(value));
Blink Reformat4c46d092018-04-07 15:32:37406
Mathias Bynens41ea2632020-12-24 05:52:49407 if (prefix[0] === '.') {
408 completions = completions.map(value => '.' + value);
409 }
410 return completions.filter(value => value.startsWith(prefix)).sort().map(completion => {
411 return {
412 text: completion,
413 title: undefined,
414 subtitle: undefined,
415 iconType: undefined,
416 priority: undefined,
417 isSecondary: undefined,
418 subtitleRenderer: undefined,
419 selectionRange: undefined,
420 hideGhostText: undefined,
421 iconElement: undefined,
422 };
Blink Reformat4c46d092018-04-07 15:32:37423 });
424 }
Tim van der Lippe13f71fb2019-11-29 11:17:39425}