blob: 57bc07e696849f203516b5b942b7e47cdab45ede [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
5import * as Common from '../common/common.js';
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:496import * as i18n from '../i18n/i18n.js';
Simon Zündda7058f2020-02-28 13:57:287import * as Platform from '../platform/platform.js';
Tim van der Lippe97611c92020-02-12 16:56:588import * as SDK from '../sdk/sdk.js';
9import * as UI from '../ui/ui.js';
10
Tim van der Lippeaabc8302019-12-10 15:34:4511import {ElementsPanel} from './ElementsPanel.js';
12
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4913export const UIStrings = {
14 /**
15 *@description Text in Classes Pane Widget of the Elements panel
16 */
17 addNewClass: 'Add new class',
18 /**
19 *@description Screen reader announcement string when adding a class via the Classes Pane Widget.
20 *@example {vbox flex-auto} PH1
21 */
22 classesSAdded: 'Classes {PH1} added.',
23 /**
24 *@description Screen reader announcement string when adding a class via the Classes Pane Widget.
25 *@example {title-container} PH1
26 */
27 classSAdded: 'Class {PH1} added.',
28 /**
29 *@description Text in Classes Pane Widget of the Elements panel
30 */
31 elementClasses: 'Element Classes',
32};
33const str_ = i18n.i18n.registerUIStrings('elements/ClassesPaneWidget.js', UIStrings);
34const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
Tim van der Lippe97611c92020-02-12 16:56:5835export class ClassesPaneWidget extends UI.Widget.Widget {
Blink Reformat4c46d092018-04-07 15:32:3736 constructor() {
37 super(true);
Jack Franklin71519f82020-11-03 12:08:5938 this.registerRequiredCSS('elements/classesPaneWidget.css', {enableLegacyPatching: true});
Blink Reformat4c46d092018-04-07 15:32:3739 this.contentElement.className = 'styles-element-classes-pane';
40 const container = this.contentElement.createChild('div', 'title-container');
41 this._input = container.createChild('div', 'new-class-input monospace');
42 this.setDefaultFocusedElement(this._input);
43 this._classesContainer = this.contentElement.createChild('div', 'source-code');
44 this._classesContainer.classList.add('styles-element-classes-container');
Tim van der Lippe13f71fb2019-11-29 11:17:3945 this._prompt = new ClassNamePrompt(this._nodeClasses.bind(this));
Blink Reformat4c46d092018-04-07 15:32:3746 this._prompt.setAutocompletionTimeout(0);
47 this._prompt.renderAsBlock();
48
Tim van der Lippebcd6b5c2021-01-13 12:31:5149 const proxyElement = /** @type {!HTMLElement} */ (this._prompt.attach(this._input));
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:4950 this._prompt.setPlaceholder(i18nString(UIStrings.addNewClass));
Blink Reformat4c46d092018-04-07 15:32:3751 this._prompt.addEventListener(UI.TextPrompt.Events.TextChanged, this._onTextChanged, this);
52 proxyElement.addEventListener('keydown', this._onKeyDown.bind(this), false);
53
Paul Lewisdaac1062020-03-05 14:37:1054 SDK.SDKModel.TargetManager.instance().addModelListener(
Tim van der Lippe97611c92020-02-12 16:56:5855 SDK.DOMModel.DOMModel, SDK.DOMModel.Events.DOMMutated, this._onDOMMutated, this);
56 /** @type {!Set<!SDK.DOMModel.DOMNode>} */
Blink Reformat4c46d092018-04-07 15:32:3757 this._mutatingNodes = new Set();
Tim van der Lippe97611c92020-02-12 16:56:5858 /** @type {!Map<!SDK.DOMModel.DOMNode, string>} */
Blink Reformat4c46d092018-04-07 15:32:3759 this._pendingNodeClasses = new Map();
Tim van der Lippe97611c92020-02-12 16:56:5860 this._updateNodeThrottler = new Common.Throttler.Throttler(0);
61 /** @type {?SDK.DOMModel.DOMNode} */
Blink Reformat4c46d092018-04-07 15:32:3762 this._previousTarget = null;
Tim van der Lipped1a00aa2020-08-19 16:03:5663 UI.Context.Context.instance().addFlavorChangeListener(SDK.DOMModel.DOMNode, this._onSelectedNodeChanged, this);
Blink Reformat4c46d092018-04-07 15:32:3764 }
65
66 /**
67 * @param {string} text
68 * @return {!Array.<string>}
69 */
70 _splitTextIntoClasses(text) {
Mathias Bynens3abc0952020-04-20 14:15:5271 return text.split(/[,\s]/).map(className => className.trim()).filter(className => className.length);
Blink Reformat4c46d092018-04-07 15:32:3772 }
73
74 /**
Tim van der Lippebcd6b5c2021-01-13 12:31:5175 * @param {!KeyboardEvent} event
Blink Reformat4c46d092018-04-07 15:32:3776 */
77 _onKeyDown(event) {
Tim van der Lippebcd6b5c2021-01-13 12:31:5178 if (!(event.key === 'Enter') && !isEscKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:3779 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3480 }
Blink Reformat4c46d092018-04-07 15:32:3781
Tim van der Lippebcd6b5c2021-01-13 12:31:5182 if (event.key === 'Enter') {
Blink Reformat4c46d092018-04-07 15:32:3783 event.consume();
Tim van der Lippe1d6e57a2019-09-30 11:55:3484 if (this._prompt.acceptAutoComplete()) {
Blink Reformat4c46d092018-04-07 15:32:3785 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3486 }
Blink Reformat4c46d092018-04-07 15:32:3787 }
88
Tim van der Lippe32f760f2020-10-01 10:52:1589 const eventTarget = /** @type {!HTMLElement} */ (event.target);
90 let text = /** @type {string} */ (eventTarget.textContent);
Blink Reformat4c46d092018-04-07 15:32:3791 if (isEscKey(event)) {
Simon Zündda7058f2020-02-28 13:57:2892 if (!Platform.StringUtilities.isWhitespace(text)) {
Blink Reformat4c46d092018-04-07 15:32:3793 event.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:3494 }
Blink Reformat4c46d092018-04-07 15:32:3795 text = '';
96 }
97
98 this._prompt.clearAutocomplete();
Tim van der Lippe32f760f2020-10-01 10:52:1599 eventTarget.textContent = '';
Blink Reformat4c46d092018-04-07 15:32:37100
Tim van der Lipped1a00aa2020-08-19 16:03:56101 const node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34102 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37103 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34104 }
Blink Reformat4c46d092018-04-07 15:32:37105
106 const classNames = this._splitTextIntoClasses(text);
Michael Liaocafccfd2020-04-02 17:11:59107 if (!classNames.length) {
Patrick Brosset78fa1f52020-08-17 14:33:48108 this._installNodeClasses(node);
Michael Liaocafccfd2020-04-02 17:11:59109 return;
110 }
111
Tim van der Lippe1d6e57a2019-09-30 11:55:34112 for (const className of classNames) {
Blink Reformat4c46d092018-04-07 15:32:37113 this._toggleClass(node, className, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34114 }
Michael Liaocafccfd2020-04-02 17:11:59115
116 // annoucementString is used for screen reader to announce that the class(es) has been added successfully.
117 const joinClassString = classNames.join(' ');
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:49118 const announcementString = classNames.length > 1 ? i18nString(UIStrings.classesSAdded, {PH1: joinClassString}) :
119 i18nString(UIStrings.classSAdded, {PH1: joinClassString});
Michael Liaocafccfd2020-04-02 17:11:59120 UI.ARIAUtils.alert(announcementString, this.contentElement);
121
Blink Reformat4c46d092018-04-07 15:32:37122 this._installNodeClasses(node);
123 this._update();
124 }
125
126 _onTextChanged() {
Tim van der Lipped1a00aa2020-08-19 16:03:56127 const node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34128 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37129 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34130 }
Blink Reformat4c46d092018-04-07 15:32:37131 this._installNodeClasses(node);
132 }
133
134 /**
Tim van der Lippec02a97c2020-02-14 14:39:27135 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37136 */
137 _onDOMMutated(event) {
Tim van der Lippe97611c92020-02-12 16:56:58138 const node = /** @type {!SDK.DOMModel.DOMNode} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34139 if (this._mutatingNodes.has(node)) {
Blink Reformat4c46d092018-04-07 15:32:37140 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34141 }
Tim van der Lippe32f760f2020-10-01 10:52:15142 cachedClassesMap.delete(node);
Blink Reformat4c46d092018-04-07 15:32:37143 this._update();
144 }
145
146 /**
Tim van der Lippec02a97c2020-02-14 14:39:27147 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37148 */
149 _onSelectedNodeChanged(event) {
150 if (this._previousTarget && this._prompt.text()) {
151 this._input.textContent = '';
152 this._installNodeClasses(this._previousTarget);
153 }
Tim van der Lippe97611c92020-02-12 16:56:58154 this._previousTarget = /** @type {?SDK.DOMModel.DOMNode} */ (event.data);
Blink Reformat4c46d092018-04-07 15:32:37155 this._update();
156 }
157
158 /**
159 * @override
160 */
161 wasShown() {
162 this._update();
163 }
164
165 _update() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34166 if (!this.isShowing()) {
Blink Reformat4c46d092018-04-07 15:32:37167 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34168 }
Blink Reformat4c46d092018-04-07 15:32:37169
Tim van der Lipped1a00aa2020-08-19 16:03:56170 let node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34171 if (node) {
Blink Reformat4c46d092018-04-07 15:32:37172 node = node.enclosingElementOrSelf();
Tim van der Lippe1d6e57a2019-09-30 11:55:34173 }
Blink Reformat4c46d092018-04-07 15:32:37174
175 this._classesContainer.removeChildren();
Tim van der Lippe32f760f2020-10-01 10:52:15176 // @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:37177 this._input.disabled = !node;
178
Tim van der Lippe1d6e57a2019-09-30 11:55:34179 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37180 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34181 }
Blink Reformat4c46d092018-04-07 15:32:37182
183 const classes = this._nodeClasses(node);
Simon Zündf27be3d2020-02-11 14:46:27184 const keys = [...classes.keys()];
Tim van der Lippe32f760f2020-10-01 10:52:15185 keys.sort(Platform.StringUtilities.caseInsensetiveComparator);
186 for (const className of keys) {
Tim van der Lippe97611c92020-02-12 16:56:58187 const label = UI.UIUtils.CheckboxLabel.create(className, classes.get(className));
Blink Reformat4c46d092018-04-07 15:32:37188 label.classList.add('monospace');
189 label.checkboxElement.addEventListener('click', this._onClick.bind(this, className), false);
190 this._classesContainer.appendChild(label);
191 }
192 }
193
194 /**
195 * @param {string} className
196 * @param {!Event} event
197 */
198 _onClick(className, event) {
Tim van der Lipped1a00aa2020-08-19 16:03:56199 const node = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34200 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37201 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34202 }
Tim van der Lippe32f760f2020-10-01 10:52:15203 const enabled = /** @type {!HTMLInputElement} */ (event.target).checked;
Blink Reformat4c46d092018-04-07 15:32:37204 this._toggleClass(node, className, enabled);
205 this._installNodeClasses(node);
206 }
207
208 /**
Tim van der Lippe97611c92020-02-12 16:56:58209 * @param {!SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37210 * @return {!Map<string, boolean>}
211 */
212 _nodeClasses(node) {
Tim van der Lippe32f760f2020-10-01 10:52:15213 let result = cachedClassesMap.get(node);
Blink Reformat4c46d092018-04-07 15:32:37214 if (!result) {
215 const classAttribute = node.getAttribute('class') || '';
216 const classes = classAttribute.split(/\s/);
217 result = new Map();
218 for (let i = 0; i < classes.length; ++i) {
219 const className = classes[i].trim();
Tim van der Lippe1d6e57a2019-09-30 11:55:34220 if (!className.length) {
Blink Reformat4c46d092018-04-07 15:32:37221 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34222 }
Blink Reformat4c46d092018-04-07 15:32:37223 result.set(className, true);
224 }
Tim van der Lippe32f760f2020-10-01 10:52:15225 cachedClassesMap.set(node, result);
Blink Reformat4c46d092018-04-07 15:32:37226 }
227 return result;
228 }
229
230 /**
Tim van der Lippe97611c92020-02-12 16:56:58231 * @param {!SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37232 * @param {string} className
233 * @param {boolean} enabled
234 */
235 _toggleClass(node, className, enabled) {
236 const classes = this._nodeClasses(node);
237 classes.set(className, enabled);
238 }
239
240 /**
Tim van der Lippe97611c92020-02-12 16:56:58241 * @param {!SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37242 */
243 _installNodeClasses(node) {
244 const classes = this._nodeClasses(node);
245 const activeClasses = new Set();
246 for (const className of classes.keys()) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34247 if (classes.get(className)) {
Blink Reformat4c46d092018-04-07 15:32:37248 activeClasses.add(className);
Tim van der Lippe1d6e57a2019-09-30 11:55:34249 }
Blink Reformat4c46d092018-04-07 15:32:37250 }
251
252 const additionalClasses = this._splitTextIntoClasses(this._prompt.textWithCurrentSuggestion());
Tim van der Lippe1d6e57a2019-09-30 11:55:34253 for (const className of additionalClasses) {
Blink Reformat4c46d092018-04-07 15:32:37254 activeClasses.add(className);
Tim van der Lippe1d6e57a2019-09-30 11:55:34255 }
Blink Reformat4c46d092018-04-07 15:32:37256
Simon Zünda0d40622020-02-12 13:16:42257 const newClasses = [...activeClasses.values()].sort();
Blink Reformat4c46d092018-04-07 15:32:37258
259 this._pendingNodeClasses.set(node, newClasses.join(' '));
260 this._updateNodeThrottler.schedule(this._flushPendingClasses.bind(this));
261 }
262
263 /**
Tim van der Lippe32f760f2020-10-01 10:52:15264 * @return {!Promise<void>}
Blink Reformat4c46d092018-04-07 15:32:37265 */
Tim van der Lippe32f760f2020-10-01 10:52:15266 async _flushPendingClasses() {
Blink Reformat4c46d092018-04-07 15:32:37267 const promises = [];
268 for (const node of this._pendingNodeClasses.keys()) {
269 this._mutatingNodes.add(node);
Tim van der Lippe32f760f2020-10-01 10:52:15270 const promise = node.setAttributeValuePromise('class', /** @type {string} */ (this._pendingNodeClasses.get(node)))
Blink Reformat4c46d092018-04-07 15:32:37271 .then(onClassValueUpdated.bind(this, node));
272 promises.push(promise);
273 }
274 this._pendingNodeClasses.clear();
Tim van der Lippe32f760f2020-10-01 10:52:15275 await Promise.all(promises);
Blink Reformat4c46d092018-04-07 15:32:37276
277 /**
Tim van der Lippe97611c92020-02-12 16:56:58278 * @param {!SDK.DOMModel.DOMNode} node
Tim van der Lippe13f71fb2019-11-29 11:17:39279 * @this {ClassesPaneWidget}
Blink Reformat4c46d092018-04-07 15:32:37280 */
281 function onClassValueUpdated(node) {
282 this._mutatingNodes.delete(node);
283 }
284 }
Tim van der Lippe13f71fb2019-11-29 11:17:39285}
Blink Reformat4c46d092018-04-07 15:32:37286
Tim van der Lippe32f760f2020-10-01 10:52:15287/** @type {!WeakMap<!SDK.DOMModel.DOMNode, !Map<string, boolean>>} */
288const cachedClassesMap = new WeakMap();
Blink Reformat4c46d092018-04-07 15:32:37289
Andres Olivares43c2d9f2021-02-10 16:48:39290/** @type {!ButtonProvider} */
291let buttonProviderInstance;
292
Blink Reformat4c46d092018-04-07 15:32:37293/**
Tim van der Lippe97611c92020-02-12 16:56:58294 * @implements {UI.Toolbar.Provider}
Blink Reformat4c46d092018-04-07 15:32:37295 */
Tim van der Lippe13f71fb2019-11-29 11:17:39296export class ButtonProvider {
Andres Olivares43c2d9f2021-02-10 16:48:39297 /** @private */
Blink Reformat4c46d092018-04-07 15:32:37298 constructor() {
Vidal Guillermo Diazleal Ortega0cfa0ed2021-02-17 20:35:49299 this._button = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.elementClasses), '');
Blink Reformat4c46d092018-04-07 15:32:37300 this._button.setText('.cls');
301 this._button.element.classList.add('monospace');
Tim van der Lippe97611c92020-02-12 16:56:58302 this._button.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._clicked, this);
Tim van der Lippe13f71fb2019-11-29 11:17:39303 this._view = new ClassesPaneWidget();
Blink Reformat4c46d092018-04-07 15:32:37304 }
305
Andres Olivares43c2d9f2021-02-10 16:48:39306 /**
307 * @param {{forceNew: ?boolean}} opts
308 */
309 static instance(opts = {forceNew: null}) {
310 const {forceNew} = opts;
311 if (!buttonProviderInstance || forceNew) {
312 buttonProviderInstance = new ButtonProvider();
313 }
314
315 return buttonProviderInstance;
316 }
317
Blink Reformat4c46d092018-04-07 15:32:37318 _clicked() {
Tim van der Lippeaabc8302019-12-10 15:34:45319 ElementsPanel.instance().showToolbarPane(!this._view.isShowing() ? this._view : null, this._button);
Blink Reformat4c46d092018-04-07 15:32:37320 }
321
322 /**
323 * @override
Tim van der Lippe97611c92020-02-12 16:56:58324 * @return {!UI.Toolbar.ToolbarItem}
Blink Reformat4c46d092018-04-07 15:32:37325 */
326 item() {
327 return this._button;
328 }
Tim van der Lippe13f71fb2019-11-29 11:17:39329}
Blink Reformat4c46d092018-04-07 15:32:37330
Tim van der Lippe97611c92020-02-12 16:56:58331export class ClassNamePrompt extends UI.TextPrompt.TextPrompt {
Blink Reformat4c46d092018-04-07 15:32:37332 /**
Tim van der Lippe97611c92020-02-12 16:56:58333 * @param {function(!SDK.DOMModel.DOMNode):!Map<string, boolean>} nodeClasses
Blink Reformat4c46d092018-04-07 15:32:37334 */
335 constructor(nodeClasses) {
336 super();
337 this._nodeClasses = nodeClasses;
338 this.initialize(this._buildClassNameCompletions.bind(this), ' ');
339 this.disableDefaultSuggestionForEmptyInput();
Tim van der Lippe32f760f2020-10-01 10:52:15340 /** @type {?string} */
Blink Reformat4c46d092018-04-07 15:32:37341 this._selectedFrameId = '';
342 this._classNamesPromise = null;
343 }
344
345 /**
Tim van der Lippe97611c92020-02-12 16:56:58346 * @param {!SDK.DOMModel.DOMNode} selectedNode
Blink Reformat4c46d092018-04-07 15:32:37347 * @return {!Promise.<!Array.<string>>}
348 */
Mathias Bynens3abc0952020-04-20 14:15:52349 async _getClassNames(selectedNode) {
Blink Reformat4c46d092018-04-07 15:32:37350 const promises = [];
351 const completions = new Set();
352 this._selectedFrameId = selectedNode.frameId();
353
354 const cssModel = selectedNode.domModel().cssModel();
355 const allStyleSheets = cssModel.allStyleSheets();
356 for (const stylesheet of allStyleSheets) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34357 if (stylesheet.frameId !== this._selectedFrameId) {
Blink Reformat4c46d092018-04-07 15:32:37358 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34359 }
Mathias Bynens3abc0952020-04-20 14:15:52360 const cssPromise = cssModel.classNamesPromise(stylesheet.id).then(classes => {
361 for (const className of classes) {
362 completions.add(className);
363 }
364 });
Blink Reformat4c46d092018-04-07 15:32:37365 promises.push(cssPromise);
366 }
367
Tim van der Lippe32f760f2020-10-01 10:52:15368 const ownerDocumentId = /** @type {number} */ (
369 /** @type {!SDK.DOMModel.DOMDocument} */ (selectedNode.ownerDocument).id);
370
371 const domPromise = selectedNode.domModel().classNamesPromise(ownerDocumentId).then(classes => {
Mathias Bynens3abc0952020-04-20 14:15:52372 for (const className of classes) {
373 completions.add(className);
374 }
375 });
Blink Reformat4c46d092018-04-07 15:32:37376 promises.push(domPromise);
Mathias Bynens3abc0952020-04-20 14:15:52377 await Promise.all(promises);
378 return [...completions];
Blink Reformat4c46d092018-04-07 15:32:37379 }
380
381 /**
382 * @param {string} expression
383 * @param {string} prefix
384 * @param {boolean=} force
385 * @return {!Promise<!UI.SuggestBox.Suggestions>}
386 */
Mathias Bynens41ea2632020-12-24 05:52:49387 async _buildClassNameCompletions(expression, prefix, force) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34388 if (!prefix || force) {
Blink Reformat4c46d092018-04-07 15:32:37389 this._classNamesPromise = null;
Tim van der Lippe1d6e57a2019-09-30 11:55:34390 }
Blink Reformat4c46d092018-04-07 15:32:37391
Tim van der Lipped1a00aa2020-08-19 16:03:56392 const selectedNode = UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34393 if (!selectedNode || (!prefix && !force && !expression.trim())) {
Mathias Bynens41ea2632020-12-24 05:52:49394 return [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34395 }
Blink Reformat4c46d092018-04-07 15:32:37396
Tim van der Lippe1d6e57a2019-09-30 11:55:34397 if (!this._classNamesPromise || this._selectedFrameId !== selectedNode.frameId()) {
Blink Reformat4c46d092018-04-07 15:32:37398 this._classNamesPromise = this._getClassNames(selectedNode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34399 }
Blink Reformat4c46d092018-04-07 15:32:37400
Mathias Bynens41ea2632020-12-24 05:52:49401 let completions = await this._classNamesPromise;
402 const classesMap = this._nodeClasses(/** @type {!SDK.DOMModel.DOMNode} */ (selectedNode));
403 completions = completions.filter(value => !classesMap.get(value));
Blink Reformat4c46d092018-04-07 15:32:37404
Mathias Bynens41ea2632020-12-24 05:52:49405 if (prefix[0] === '.') {
406 completions = completions.map(value => '.' + value);
407 }
408 return completions.filter(value => value.startsWith(prefix)).sort().map(completion => {
409 return {
410 text: completion,
411 title: undefined,
412 subtitle: undefined,
413 iconType: undefined,
414 priority: undefined,
415 isSecondary: undefined,
416 subtitleRenderer: undefined,
417 selectionRange: undefined,
418 hideGhostText: undefined,
419 iconElement: undefined,
420 };
Blink Reformat4c46d092018-04-07 15:32:37421 });
422 }
Tim van der Lippe13f71fb2019-11-29 11:17:39423}