blob: 2fe65b81b183fe4e471ec5cae4bafbf9f48f52e6 [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 Lippe046db882020-02-13 13:55:114
5import * as Common from '../common/common.js';
6import * as SDK from '../sdk/sdk.js';
7import * as UI from '../ui/ui.js';
8
Blink Reformat4c46d092018-04-07 15:32:379/**
Tim van der Lippe046db882020-02-13 13:55:1110 * @implements {UI.ContextFlavorListener.ContextFlavorListener}
11 * @implements {UI.Toolbar.ItemsProvider}
12 * @implements {UI.ListControl.ListDelegate}
Blink Reformat4c46d092018-04-07 15:32:3713 * @unrestricted
14 */
Tim van der Lippe046db882020-02-13 13:55:1115export class XHRBreakpointsSidebarPane extends UI.Widget.VBox {
Blink Reformat4c46d092018-04-07 15:32:3716 constructor() {
17 super(true);
18 this.registerRequiredCSS('browser_debugger/xhrBreakpointsSidebarPane.css');
19
Tim van der Lippe046db882020-02-13 13:55:1120 /** @type {!UI.ListModel.ListModel<string>} */
21 this._breakpoints = new UI.ListModel.ListModel();
22 this._list = new UI.ListControl.ListControl(this._breakpoints, this, UI.ListControl.ListMode.NonViewport);
Jack Lynchde07ab82020-01-07 23:40:5923 this.contentElement.appendChild(this._list.element);
24 this._list.element.classList.add('breakpoint-list', 'hidden');
25 UI.ARIAUtils.markAsList(this._list.element);
26 UI.ARIAUtils.setAccessibleName(this._list.element, ls`XHR/fetch Breakpoints`);
Blink Reformat4c46d092018-04-07 15:32:3727 this._emptyElement = this.contentElement.createChild('div', 'gray-info-message');
Tim van der Lippe046db882020-02-13 13:55:1128 this._emptyElement.textContent = Common.UIString.UIString('No breakpoints');
Blink Reformat4c46d092018-04-07 15:32:3729
30 /** @type {!Map.<string, !Element>} */
31 this._breakpointElements = new Map();
32
Tim van der Lippe046db882020-02-13 13:55:1133 this._addButton = new UI.Toolbar.ToolbarButton(ls`Add XHR/fetch breakpoint`, 'largeicon-add');
Tim van der Lippe37a35ff2020-03-03 13:49:0234 this._addButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, event => {
35 this._addButtonClicked();
36 });
Blink Reformat4c46d092018-04-07 15:32:3737
38 this._emptyElement.addEventListener('contextmenu', this._emptyElementContextMenu.bind(this), true);
Jack Lynchde07ab82020-01-07 23:40:5939 this._emptyElement.tabIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:3740 this._restoreBreakpoints();
41 this._update();
42 }
43
44 /**
45 * @override
Tim van der Lippe046db882020-02-13 13:55:1146 * @return {!Array<!UI.Toolbar.ToolbarItem>}
Blink Reformat4c46d092018-04-07 15:32:3747 */
48 toolbarItems() {
49 return [this._addButton];
50 }
51
Tim van der Lippe37a35ff2020-03-03 13:49:0252 /**
53 * @param {!Event} event
54 */
Blink Reformat4c46d092018-04-07 15:32:3755 _emptyElementContextMenu(event) {
Tim van der Lippe046db882020-02-13 13:55:1156 const contextMenu = new UI.ContextMenu.ContextMenu(event);
57 contextMenu.defaultSection().appendItem(
58 Common.UIString.UIString('Add breakpoint'), this._addButtonClicked.bind(this));
Blink Reformat4c46d092018-04-07 15:32:3759 contextMenu.show();
60 }
61
Joel Einbinder4ea53552018-12-13 23:18:0462 async _addButtonClicked() {
Paul Lewis75c7d0d2020-03-19 12:17:2663 await UI.ViewManager.ViewManager.instance().showView('sources.xhrBreakpoints');
Blink Reformat4c46d092018-04-07 15:32:3764
Tim van der Lippef49e2322020-05-01 15:03:0965 const inputElementContainer = document.createElement('p');
66 inputElementContainer.classList.add('breakpoint-condition');
Tim van der Lippe046db882020-02-13 13:55:1167 inputElementContainer.textContent = Common.UIString.UIString('Break when URL contains:');
Blink Reformat4c46d092018-04-07 15:32:3768
69 const inputElement = inputElementContainer.createChild('span', 'breakpoint-condition-input');
Jack Lynchde07ab82020-01-07 23:40:5970 this._addListElement(inputElementContainer, /** @type {?Element} */ (this._list.element.firstChild));
Blink Reformat4c46d092018-04-07 15:32:3771
72 /**
73 * @param {boolean} accept
74 * @param {!Element} e
75 * @param {string} text
Paul Lewis2a4f9fe2020-01-09 15:19:4176 * @this {XHRBreakpointsSidebarPane}
Blink Reformat4c46d092018-04-07 15:32:3777 */
78 function finishEditing(accept, e, text) {
79 this._removeListElement(inputElementContainer);
80 if (accept) {
Paul Lewis5e21b5e2020-01-24 14:01:2281 self.SDK.domDebuggerManager.addXHRBreakpoint(text, true);
Jack Lynchde07ab82020-01-07 23:40:5982 this._setBreakpoint(text);
Blink Reformat4c46d092018-04-07 15:32:3783 }
Jack Lynchde07ab82020-01-07 23:40:5984 this._update();
Blink Reformat4c46d092018-04-07 15:32:3785 }
86
87 const config = new UI.InplaceEditor.Config(finishEditing.bind(this, true), finishEditing.bind(this, false));
Tim van der Lippe046db882020-02-13 13:55:1188 UI.InplaceEditor.InplaceEditor.startEditing(inputElement, config);
Blink Reformat4c46d092018-04-07 15:32:3789 }
90
91 /**
Jack Lynchde07ab82020-01-07 23:40:5992 * @override
93 * @param {string} item
94 * @return {number}
Blink Reformat4c46d092018-04-07 15:32:3795 */
Jack Lynchde07ab82020-01-07 23:40:5996 heightForItem(item) {
97 return 0;
98 }
99
100 /**
101 * @override
102 * @param {string} item
103 * @return {boolean}
104 */
105 isItemSelectable(item) {
106 return true;
107 }
108
109 /**
110 * @param {string} url
111 */
112 _setBreakpoint(url) {
113 if (this._breakpoints.indexOf(url) !== -1) {
114 this._list.refreshItem(url);
115 } else {
116 this._breakpoints.insertWithComparator(url, (a, b) => {
117 if (a > b) {
118 return 1;
119 }
120 if (a < b) {
121 return -1;
122 }
123 return 0;
124 });
Blink Reformat4c46d092018-04-07 15:32:37125 }
Jack Lynchde07ab82020-01-07 23:40:59126 if (!this._list.selectedItem() || !this.hasFocus()) {
127 this._list.selectItem(this._breakpoints.at(0));
128 }
129 }
Blink Reformat4c46d092018-04-07 15:32:37130
Jack Lynchde07ab82020-01-07 23:40:59131 /**
132 * @override
133 * @param {string} item
134 * @return {!Element}
135 */
136 createElementForItem(item) {
137 const listItemElement = createElement('div');
138 UI.ARIAUtils.markAsListitem(listItemElement);
139 const element = listItemElement.createChild('div', 'breakpoint-entry');
140 listItemElement.checkboxElement = element;
Paul Lewis5e21b5e2020-01-24 14:01:22141 const enabled = self.SDK.domDebuggerManager.xhrBreakpoints().get(item);
Jack Lynchde07ab82020-01-07 23:40:59142 UI.ARIAUtils.markAsCheckbox(element);
143 UI.ARIAUtils.setChecked(element, enabled);
144 element._url = item;
145 element.addEventListener('contextmenu', this._contextMenu.bind(this, item), true);
Blink Reformat4c46d092018-04-07 15:32:37146
Tim van der Lippe046db882020-02-13 13:55:11147 const title =
148 item ? Common.UIString.UIString('URL contains "%s"', item) : Common.UIString.UIString('Any XHR or fetch');
149 const label = UI.UIUtils.CheckboxLabel.create(title, enabled);
Jack Lynchde07ab82020-01-07 23:40:59150 UI.ARIAUtils.markAsHidden(label);
151 UI.ARIAUtils.setAccessibleName(element, title);
Blink Reformat4c46d092018-04-07 15:32:37152 element.appendChild(label);
Jack Lynchde07ab82020-01-07 23:40:59153 label.checkboxElement.addEventListener('click', this._checkboxClicked.bind(this, item, enabled), false);
154 element.addEventListener('click', event => {
155 if (event.target === element) {
156 this._checkboxClicked(item, enabled);
157 }
158 }, false);
Blink Reformat4c46d092018-04-07 15:32:37159 element._checkboxElement = label.checkboxElement;
Jack Lynchde07ab82020-01-07 23:40:59160 label.checkboxElement.tabIndex = -1;
161 element.tabIndex = -1;
162 if (item === this._list.selectedItem()) {
163 element.tabIndex = 0;
164 this.setDefaultFocusedElement(element);
165 }
166 element.addEventListener('keydown', event => {
167 let handled = false;
168 if (event.key === ' ') {
169 this._checkboxClicked(item, enabled);
170 handled = true;
171 } else if (isEnterKey(event)) {
172 this._labelClicked(item);
173 handled = true;
174 }
175
176 if (handled) {
177 event.consume(true);
178 }
179 });
180
181 if (item === this._hitBreakpoint) {
182 element.classList.add('breakpoint-hit');
183 UI.ARIAUtils.setDescription(element, ls`breakpoint hit`);
184 }
Blink Reformat4c46d092018-04-07 15:32:37185
186 label.classList.add('cursor-auto');
Jack Lynchde07ab82020-01-07 23:40:59187 label.textElement.addEventListener('dblclick', this._labelClicked.bind(this, item), false);
188 this._breakpointElements.set(item, listItemElement);
189 return listItemElement;
190 }
Blink Reformat4c46d092018-04-07 15:32:37191
Jack Lynchde07ab82020-01-07 23:40:59192 /**
193 * @override
194 * @param {string} from
195 * @param {string} to
196 * @param {?Element} fromElement
197 * @param {?Element} toElement
198 */
199 selectedItemChanged(from, to, fromElement, toElement) {
200 if (fromElement) {
201 fromElement.checkboxElement.tabIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37202 }
Jack Lynchde07ab82020-01-07 23:40:59203 if (toElement) {
204 this.setDefaultFocusedElement(toElement.checkboxElement);
205 toElement.checkboxElement.tabIndex = 0;
206 if (this.hasFocus()) {
207 toElement.checkboxElement.focus();
208 }
209 }
210 }
211
212 /**
213 * @override
214 * @param {?Element} fromElement
215 * @param {?Element} toElement
216 */
217 updateSelectedItemARIA(fromElement, toElement) {
218 return true;
Blink Reformat4c46d092018-04-07 15:32:37219 }
220
221 /**
222 * @param {string} url
223 */
224 _removeBreakpoint(url) {
Jack Lynchde07ab82020-01-07 23:40:59225 const index = this._breakpoints.indexOf(url);
226 if (index >= 0) {
227 this._breakpoints.remove(index);
Tim van der Lippe1d6e57a2019-09-30 11:55:34228 }
Blink Reformat4c46d092018-04-07 15:32:37229 this._breakpointElements.delete(url);
Jack Lynchde07ab82020-01-07 23:40:59230 this._update();
Blink Reformat4c46d092018-04-07 15:32:37231 }
232
233 /**
234 * @param {!Element} element
235 * @param {?Node} beforeNode
236 */
237 _addListElement(element, beforeNode) {
Jack Lynchde07ab82020-01-07 23:40:59238 this._list.element.insertBefore(element, beforeNode);
Blink Reformat4c46d092018-04-07 15:32:37239 this._emptyElement.classList.add('hidden');
Jack Lynchde07ab82020-01-07 23:40:59240 this._list.element.classList.remove('hidden');
Blink Reformat4c46d092018-04-07 15:32:37241 }
242
243 /**
244 * @param {!Element} element
245 */
246 _removeListElement(element) {
Jack Lynchde07ab82020-01-07 23:40:59247 this._list.element.removeChild(element);
248 if (!this._list.element.firstElementChild) {
Blink Reformat4c46d092018-04-07 15:32:37249 this._emptyElement.classList.remove('hidden');
Jack Lynchde07ab82020-01-07 23:40:59250 this._list.element.classList.add('hidden');
Blink Reformat4c46d092018-04-07 15:32:37251 }
252 }
253
254 _contextMenu(url, event) {
Tim van der Lippe046db882020-02-13 13:55:11255 const contextMenu = new UI.ContextMenu.ContextMenu(event);
Blink Reformat4c46d092018-04-07 15:32:37256
257 /**
Paul Lewis2a4f9fe2020-01-09 15:19:41258 * @this {XHRBreakpointsSidebarPane}
Blink Reformat4c46d092018-04-07 15:32:37259 */
260 function removeBreakpoint() {
Paul Lewis5e21b5e2020-01-24 14:01:22261 self.SDK.domDebuggerManager.removeXHRBreakpoint(url);
Blink Reformat4c46d092018-04-07 15:32:37262 this._removeBreakpoint(url);
263 }
264
265 /**
Paul Lewis2a4f9fe2020-01-09 15:19:41266 * @this {XHRBreakpointsSidebarPane}
Blink Reformat4c46d092018-04-07 15:32:37267 */
268 function removeAllBreakpoints() {
269 for (const url of this._breakpointElements.keys()) {
Paul Lewis5e21b5e2020-01-24 14:01:22270 self.SDK.domDebuggerManager.removeXHRBreakpoint(url);
Blink Reformat4c46d092018-04-07 15:32:37271 this._removeBreakpoint(url);
272 }
Jack Lynchde07ab82020-01-07 23:40:59273 this._update();
Blink Reformat4c46d092018-04-07 15:32:37274 }
Tim van der Lippe046db882020-02-13 13:55:11275 const removeAllTitle = Common.UIString.UIString('Remove all breakpoints');
Blink Reformat4c46d092018-04-07 15:32:37276
Tim van der Lippe046db882020-02-13 13:55:11277 contextMenu.defaultSection().appendItem(
278 Common.UIString.UIString('Add breakpoint'), this._addButtonClicked.bind(this));
279 contextMenu.defaultSection().appendItem(Common.UIString.UIString('Remove breakpoint'), removeBreakpoint.bind(this));
Blink Reformat4c46d092018-04-07 15:32:37280 contextMenu.defaultSection().appendItem(removeAllTitle, removeAllBreakpoints.bind(this));
281 contextMenu.show();
282 }
283
Jack Lynchde07ab82020-01-07 23:40:59284 /**
285 * @param {string} url
286 * @param {boolean} checked
287 */
288 _checkboxClicked(url, checked) {
289 const hadFocus = this.hasFocus();
Paul Lewis5e21b5e2020-01-24 14:01:22290 self.SDK.domDebuggerManager.toggleXHRBreakpoint(url, !checked);
Jack Lynchde07ab82020-01-07 23:40:59291 this._list.refreshItem(url);
292 this._list.selectItem(url);
293 if (hadFocus) {
294 this.focus();
295 }
Blink Reformat4c46d092018-04-07 15:32:37296 }
297
Jack Lynchde07ab82020-01-07 23:40:59298 /**
299 * @param {string} url
300 */
Blink Reformat4c46d092018-04-07 15:32:37301 _labelClicked(url) {
302 const element = this._breakpointElements.get(url) || null;
Tim van der Lippef49e2322020-05-01 15:03:09303 const inputElement = document.createElement('span');
304 inputElement.classList.add('breakpoint-condition');
Blink Reformat4c46d092018-04-07 15:32:37305 inputElement.textContent = url;
Jack Lynchde07ab82020-01-07 23:40:59306 this._list.element.insertBefore(inputElement, element);
Blink Reformat4c46d092018-04-07 15:32:37307 element.classList.add('hidden');
308
309 /**
310 * @param {boolean} accept
311 * @param {!Element} e
312 * @param {string} text
Paul Lewis2a4f9fe2020-01-09 15:19:41313 * @this {XHRBreakpointsSidebarPane}
Blink Reformat4c46d092018-04-07 15:32:37314 */
315 function finishEditing(accept, e, text) {
316 this._removeListElement(inputElement);
317 if (accept) {
Paul Lewis5e21b5e2020-01-24 14:01:22318 self.SDK.domDebuggerManager.removeXHRBreakpoint(url);
Blink Reformat4c46d092018-04-07 15:32:37319 this._removeBreakpoint(url);
Jack Lynchde07ab82020-01-07 23:40:59320 const enabled = element ? element.checkboxElement._checkboxElement.checked : true;
Paul Lewis5e21b5e2020-01-24 14:01:22321 self.SDK.domDebuggerManager.addXHRBreakpoint(text, enabled);
Jack Lynchde07ab82020-01-07 23:40:59322 this._setBreakpoint(text);
323 this._list.selectItem(text);
Blink Reformat4c46d092018-04-07 15:32:37324 } else {
325 element.classList.remove('hidden');
326 }
Jack Lynchde07ab82020-01-07 23:40:59327 this.focus();
Blink Reformat4c46d092018-04-07 15:32:37328 }
329
Tim van der Lippe046db882020-02-13 13:55:11330 UI.InplaceEditor.InplaceEditor.startEditing(
Blink Reformat4c46d092018-04-07 15:32:37331 inputElement, new UI.InplaceEditor.Config(finishEditing.bind(this, true), finishEditing.bind(this, false)));
332 }
333
334 /**
335 * @override
336 * @param {?Object} object
337 */
338 flavorChanged(object) {
339 this._update();
340 }
341
342 _update() {
Jack Lynchde07ab82020-01-07 23:40:59343 const isEmpty = this._breakpoints.length === 0;
344 this._list.element.classList.toggle('hidden', isEmpty);
345 this._emptyElement.classList.toggle('hidden', !isEmpty);
346
Tim van der Lippe046db882020-02-13 13:55:11347 const details = self.UI.context.flavor(SDK.DebuggerModel.DebuggerPausedDetails);
Blink Reformat4c46d092018-04-07 15:32:37348 if (!details || details.reason !== SDK.DebuggerModel.BreakReason.XHR) {
Jack Lynchde07ab82020-01-07 23:40:59349 if (this._hitBreakpoint) {
350 const oldHitBreakpoint = this._hitBreakpoint;
351 delete this._hitBreakpoint;
352 if (this._breakpoints.indexOf(oldHitBreakpoint) >= 0) {
353 this._list.refreshItem(oldHitBreakpoint);
354 }
Blink Reformat4c46d092018-04-07 15:32:37355 }
356 return;
357 }
358 const url = details.auxData['breakpointURL'];
Jack Lynchde07ab82020-01-07 23:40:59359 this._hitBreakpoint = url;
360 if (this._breakpoints.indexOf(url) < 0) {
Blink Reformat4c46d092018-04-07 15:32:37361 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34362 }
Jack Lynchde07ab82020-01-07 23:40:59363 this._list.refreshItem(url);
Paul Lewis75c7d0d2020-03-19 12:17:26364 UI.ViewManager.ViewManager.instance().showView('sources.xhrBreakpoints');
Blink Reformat4c46d092018-04-07 15:32:37365 }
366
367 _restoreBreakpoints() {
Paul Lewis5e21b5e2020-01-24 14:01:22368 const breakpoints = self.SDK.domDebuggerManager.xhrBreakpoints();
Tim van der Lippe1d6e57a2019-09-30 11:55:34369 for (const url of breakpoints.keys()) {
Jack Lynchde07ab82020-01-07 23:40:59370 this._setBreakpoint(url);
Tim van der Lippe1d6e57a2019-09-30 11:55:34371 }
Blink Reformat4c46d092018-04-07 15:32:37372 }
Paul Lewis7f7a9202019-11-26 16:10:56373}