blob: fb5edda52720478d6514b6583de4fb0100044b06 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
Tim van der Lippe046db882020-02-13 13:55:1131import * as Common from '../common/common.js';
32import * as SDK from '../sdk/sdk.js';
33import * as UI from '../ui/ui.js';
34
Blink Reformat4c46d092018-04-07 15:32:3735/**
Tim van der Lippe046db882020-02-13 13:55:1136 * @implements {UI.ContextFlavorListener.ContextFlavorListener}
37 * @implements {UI.ListControl.ListDelegate<!SDK.DOMDebuggerModel.DOMBreakpoint>}
Blink Reformat4c46d092018-04-07 15:32:3738 */
Tim van der Lippe046db882020-02-13 13:55:1139export class DOMBreakpointsSidebarPane extends UI.Widget.VBox {
Blink Reformat4c46d092018-04-07 15:32:3740 constructor() {
41 super(true);
42 this.registerRequiredCSS('browser_debugger/domBreakpointsSidebarPane.css');
43
Blink Reformat4c46d092018-04-07 15:32:3744 this._emptyElement = this.contentElement.createChild('div', 'gray-info-message');
Tim van der Lippe046db882020-02-13 13:55:1145 this._emptyElement.textContent = Common.UIString.UIString('No breakpoints');
46 /** @type {!UI.ListModel.ListModel.<!SDK.DOMDebuggerModel.DOMBreakpoint>} */
47 this._breakpoints = new UI.ListModel.ListModel();
48 /** @type {!UI.ListControl.ListControl.<!SDK.DOMDebuggerModel.DOMBreakpoint>} */
49 this._list = new UI.ListControl.ListControl(this._breakpoints, this, UI.ListControl.ListMode.NonViewport);
Jack Lynch8a344762019-12-12 03:17:3850 this.contentElement.appendChild(this._list.element);
51 this._list.element.classList.add('breakpoint-list', 'hidden');
52 UI.ARIAUtils.markAsList(this._list.element);
53 UI.ARIAUtils.setAccessibleName(this._list.element, ls`DOM Breakpoints list`);
54 this._emptyElement.tabIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:3755
Paul Lewisdaac1062020-03-05 14:37:1056 SDK.SDKModel.TargetManager.instance().addModelListener(
Tim van der Lippe046db882020-02-13 13:55:1157 SDK.DOMDebuggerModel.DOMDebuggerModel, SDK.DOMDebuggerModel.Events.DOMBreakpointAdded, this._breakpointAdded,
58 this);
Paul Lewisdaac1062020-03-05 14:37:1059 SDK.SDKModel.TargetManager.instance().addModelListener(
Tim van der Lippe046db882020-02-13 13:55:1160 SDK.DOMDebuggerModel.DOMDebuggerModel, SDK.DOMDebuggerModel.Events.DOMBreakpointToggled,
61 this._breakpointToggled, this);
Paul Lewisdaac1062020-03-05 14:37:1062 SDK.SDKModel.TargetManager.instance().addModelListener(
Tim van der Lippe046db882020-02-13 13:55:1163 SDK.DOMDebuggerModel.DOMDebuggerModel, SDK.DOMDebuggerModel.Events.DOMBreakpointsRemoved,
64 this._breakpointsRemoved, this);
Blink Reformat4c46d092018-04-07 15:32:3765
Paul Lewisdaac1062020-03-05 14:37:1066 for (const domDebuggerModel of SDK.SDKModel.TargetManager.instance().models(
67 SDK.DOMDebuggerModel.DOMDebuggerModel)) {
Blink Reformat4c46d092018-04-07 15:32:3768 domDebuggerModel.retrieveDOMBreakpoints();
Tim van der Lippe1d6e57a2019-09-30 11:55:3469 for (const breakpoint of domDebuggerModel.domBreakpoints()) {
Blink Reformat4c46d092018-04-07 15:32:3770 this._addBreakpoint(breakpoint);
Tim van der Lippe1d6e57a2019-09-30 11:55:3471 }
Blink Reformat4c46d092018-04-07 15:32:3772 }
73
Jack Lynch8a344762019-12-12 03:17:3874 this._highlightedBreakpoint = null;
Blink Reformat4c46d092018-04-07 15:32:3775 this._update();
76 }
77
78 /**
Jack Lynch8a344762019-12-12 03:17:3879 * @override
80 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} item
81 * @return {!Element}
82 */
83 createElementForItem(item) {
Tim van der Lippef49e2322020-05-01 15:03:0984 const element = document.createElement('div');
85 element.classList.add('breakpoint-entry');
Jack Lynch8a344762019-12-12 03:17:3886 element.addEventListener('contextmenu', this._contextMenu.bind(this, item), true);
87 UI.ARIAUtils.markAsListitem(element);
88 element.tabIndex = this._list.selectedItem() === item ? 0 : -1;
89
Tim van der Lippe046db882020-02-13 13:55:1190 const checkboxLabel = UI.UIUtils.CheckboxLabel.create(/* title */ '', item.enabled);
Jack Lynch8a344762019-12-12 03:17:3891 const checkboxElement = checkboxLabel.checkboxElement;
92 checkboxElement.addEventListener('click', this._checkboxClicked.bind(this, item), false);
93 checkboxElement.tabIndex = -1;
94 UI.ARIAUtils.markAsHidden(checkboxLabel);
95 element.appendChild(checkboxLabel);
96
Tim van der Lippef49e2322020-05-01 15:03:0997 const labelElement = document.createElement('div');
98 labelElement.classList.add('dom-breakpoint');
Jack Lynch8a344762019-12-12 03:17:3899 element.appendChild(labelElement);
100 element.addEventListener('keydown', event => {
101 if (event.key === ' ') {
102 checkboxElement.click();
103 event.consume(true);
104 }
105 });
106
107 const description = createElement('div');
Paul Lewis2a4f9fe2020-01-09 15:19:41108 const breakpointTypeLabel = BreakpointTypeLabels.get(item.type);
Jack Lynch8a344762019-12-12 03:17:38109 description.textContent = breakpointTypeLabel;
Tim van der Lippe6ab9f462020-05-01 14:22:38110 const linkifiedNode = document.createElement('monospace');
Jack Lynch8a344762019-12-12 03:17:38111 linkifiedNode.style.display = 'block';
112 labelElement.appendChild(linkifiedNode);
Tim van der Lippe046db882020-02-13 13:55:11113 Common.Linkifier.Linkifier.linkify(item.node, {preventKeyboardFocus: true}).then(linkified => {
Jack Lynch8a344762019-12-12 03:17:38114 linkifiedNode.appendChild(linkified);
115 UI.ARIAUtils.setAccessibleName(checkboxElement, ls`${breakpointTypeLabel}: ${linkified.deepTextContent()}`);
116 });
117
118 labelElement.appendChild(description);
119
120 const checkedStateText = item.enabled ? ls`checked` : ls`unchecked`;
121 if (item === this._highlightedBreakpoint) {
122 element.classList.add('breakpoint-hit');
123 UI.ARIAUtils.setDescription(element, ls`${checkedStateText} breakpoint hit`);
124 } else {
125 UI.ARIAUtils.setDescription(element, checkedStateText);
126 }
127
128
129 this._emptyElement.classList.add('hidden');
130 this._list.element.classList.remove('hidden');
131
132 return element;
133 }
134
135 /**
136 * @override
137 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} item
138 * @return {number}
139 */
140 heightForItem(item) {
141 return 0;
142 }
143
144 /**
145 * @override
146 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} item
147 * @return {boolean}
148 */
149 isItemSelectable(item) {
150 return true;
151 }
152
153 /**
154 * @override
155 * @param {?Element} fromElement
156 * @param {?Element} toElement
157 * @return {boolean}
158 */
159 updateSelectedItemARIA(fromElement, toElement) {
160 return true;
161 }
162
163 /**
164 * @override
165 * @param {?SDK.DOMDebuggerModel.DOMBreakpoint} from
166 * @param {?SDK.DOMDebuggerModel.DOMBreakpoint} to
167 * @param {?Element} fromElement
168 * @param {?Element} toElement
169 */
170 selectedItemChanged(from, to, fromElement, toElement) {
171 if (fromElement) {
172 fromElement.tabIndex = -1;
173 }
174
175 if (toElement) {
176 this.setDefaultFocusedElement(toElement);
177 toElement.tabIndex = 0;
178 if (this.hasFocus()) {
179 toElement.focus();
180 }
181 }
182 }
183
184 /**
Tim van der Lippec02a97c2020-02-14 14:39:27185 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37186 */
187 _breakpointAdded(event) {
188 this._addBreakpoint(/** @type {!SDK.DOMDebuggerModel.DOMBreakpoint} */ (event.data));
189 }
190
191 /**
Tim van der Lippec02a97c2020-02-14 14:39:27192 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37193 */
194 _breakpointToggled(event) {
Jack Lynch8a344762019-12-12 03:17:38195 const hadFocus = this.hasFocus();
Blink Reformat4c46d092018-04-07 15:32:37196 const breakpoint = /** @type {!SDK.DOMDebuggerModel.DOMBreakpoint} */ (event.data);
Jack Lynch8a344762019-12-12 03:17:38197 this._list.refreshItem(breakpoint);
198 if (hadFocus) {
199 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34200 }
Blink Reformat4c46d092018-04-07 15:32:37201 }
202
203 /**
Tim van der Lippec02a97c2020-02-14 14:39:27204 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37205 */
206 _breakpointsRemoved(event) {
Jack Lynch8a344762019-12-12 03:17:38207 const hadFocus = this.hasFocus();
Blink Reformat4c46d092018-04-07 15:32:37208 const breakpoints = /** @type {!Array<!SDK.DOMDebuggerModel.DOMBreakpoint>} */ (event.data);
Jack Lynch8a344762019-12-12 03:17:38209 let lastIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37210 for (const breakpoint of breakpoints) {
Jack Lynch8a344762019-12-12 03:17:38211 const index = this._breakpoints.indexOf(breakpoint);
212 if (index >= 0) {
213 this._breakpoints.remove(index);
214 lastIndex = index;
Blink Reformat4c46d092018-04-07 15:32:37215 }
216 }
Jack Lynch8a344762019-12-12 03:17:38217 if (this._breakpoints.length === 0) {
Blink Reformat4c46d092018-04-07 15:32:37218 this._emptyElement.classList.remove('hidden');
Jack Lynch8a344762019-12-12 03:17:38219 this.setDefaultFocusedElement(this._emptyElement);
220 this._list.element.classList.add('hidden');
221 } else if (lastIndex >= 0) {
222 const breakpointToSelect = this._breakpoints.at(lastIndex);
223 if (breakpointToSelect) {
224 this._list.selectItem(breakpointToSelect);
225 }
226 }
227 if (hadFocus) {
228 this.focus();
Blink Reformat4c46d092018-04-07 15:32:37229 }
230 }
231
232 /**
233 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
234 */
235 _addBreakpoint(breakpoint) {
Jack Lynch8a344762019-12-12 03:17:38236 this._breakpoints.insertWithComparator(breakpoint, (breakpointA, breakpointB) => {
237 if (breakpointA.type > breakpointB.type) {
238 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34239 }
Jack Lynch8a344762019-12-12 03:17:38240 if (breakpointA.type < breakpointB.type) {
241 return 1;
242 }
243 return 0;
244 });
245 if (!this.hasFocus()) {
246 this._list.selectItem(this._breakpoints.at(0));
Blink Reformat4c46d092018-04-07 15:32:37247 }
Blink Reformat4c46d092018-04-07 15:32:37248 }
249
250 /**
251 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
252 * @param {!Event} event
253 */
254 _contextMenu(breakpoint, event) {
Tim van der Lippe046db882020-02-13 13:55:11255 const contextMenu = new UI.ContextMenu.ContextMenu(event);
Jack Lynch8a344762019-12-12 03:17:38256 contextMenu.defaultSection().appendItem(
257 ls`Reveal DOM node in Elements panel`, Common.Revealer.reveal.bind(null, breakpoint.node));
Tim van der Lippe046db882020-02-13 13:55:11258 contextMenu.defaultSection().appendItem(Common.UIString.UIString('Remove breakpoint'), () => {
Blink Reformat4c46d092018-04-07 15:32:37259 breakpoint.domDebuggerModel.removeDOMBreakpoint(breakpoint.node, breakpoint.type);
260 });
Tim van der Lippe046db882020-02-13 13:55:11261 contextMenu.defaultSection().appendItem(Common.UIString.UIString('Remove all DOM breakpoints'), () => {
Blink Reformat4c46d092018-04-07 15:32:37262 breakpoint.domDebuggerModel.removeAllDOMBreakpoints();
263 });
264 contextMenu.show();
265 }
266
267 /**
268 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
Jack Lynch8a344762019-12-12 03:17:38269 * @param {!Event} event
Blink Reformat4c46d092018-04-07 15:32:37270 */
Jack Lynch8a344762019-12-12 03:17:38271 _checkboxClicked(breakpoint, event) {
272 breakpoint.domDebuggerModel.toggleDOMBreakpoint(breakpoint, event.target.checked);
Blink Reformat4c46d092018-04-07 15:32:37273 }
274
275 /**
276 * @override
277 * @param {?Object} object
278 */
279 flavorChanged(object) {
280 this._update();
281 }
282
283 _update() {
Tim van der Lippe046db882020-02-13 13:55:11284 const details = self.UI.context.flavor(SDK.DebuggerModel.DebuggerPausedDetails);
Jack Lynch8a344762019-12-12 03:17:38285 if (this._highlightedBreakpoint) {
286 const oldHighlightedBreakpoint = this._highlightedBreakpoint;
287 delete this._highlightedBreakpoint;
288 this._list.refreshItem(oldHighlightedBreakpoint);
289 }
Blink Reformat4c46d092018-04-07 15:32:37290 if (!details || !details.auxData || details.reason !== SDK.DebuggerModel.BreakReason.DOM) {
Blink Reformat4c46d092018-04-07 15:32:37291 return;
292 }
Jack Lynch8a344762019-12-12 03:17:38293
Tim van der Lippe046db882020-02-13 13:55:11294 const domDebuggerModel = details.debuggerModel.target().model(SDK.DOMDebuggerModel.DOMDebuggerModel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34295 if (!domDebuggerModel) {
Blink Reformat4c46d092018-04-07 15:32:37296 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34297 }
Blink Reformat4c46d092018-04-07 15:32:37298 const data = domDebuggerModel.resolveDOMBreakpointData(/** @type {!Object} */ (details.auxData));
Tim van der Lippe1d6e57a2019-09-30 11:55:34299 if (!data) {
Blink Reformat4c46d092018-04-07 15:32:37300 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34301 }
Blink Reformat4c46d092018-04-07 15:32:37302
Jack Lynch8a344762019-12-12 03:17:38303 for (const breakpoint of this._breakpoints) {
304 if (breakpoint.node === data.node && breakpoint.type === data.type) {
305 this._highlightedBreakpoint = breakpoint;
Tim van der Lippe1d6e57a2019-09-30 11:55:34306 }
Blink Reformat4c46d092018-04-07 15:32:37307 }
Jack Lynch8a344762019-12-12 03:17:38308 if (this._highlightedBreakpoint) {
309 this._list.refreshItem(this._highlightedBreakpoint);
Tim van der Lippe1d6e57a2019-09-30 11:55:34310 }
Paul Lewis75c7d0d2020-03-19 12:17:26311 UI.ViewManager.ViewManager.instance().showView('sources.domBreakpoints');
Blink Reformat4c46d092018-04-07 15:32:37312 }
Paul Lewis7f7a9202019-11-26 16:10:56313}
Blink Reformat4c46d092018-04-07 15:32:37314
Paul Lewis7f7a9202019-11-26 16:10:56315export const BreakpointTypeLabels = new Map([
Tim van der Lippe046db882020-02-13 13:55:11316 [Protocol.DOMDebugger.DOMBreakpointType.SubtreeModified, Common.UIString.UIString('Subtree modified')],
317 [Protocol.DOMDebugger.DOMBreakpointType.AttributeModified, Common.UIString.UIString('Attribute modified')],
318 [Protocol.DOMDebugger.DOMBreakpointType.NodeRemoved, Common.UIString.UIString('Node removed')],
Blink Reformat4c46d092018-04-07 15:32:37319]);
320
321/**
322 * @implements {UI.ContextMenu.Provider}
323 */
Paul Lewis7f7a9202019-11-26 16:10:56324export class ContextMenuProvider {
Blink Reformat4c46d092018-04-07 15:32:37325 /**
326 * @override
327 * @param {!Event} event
Tim van der Lippe046db882020-02-13 13:55:11328 * @param {!UI.ContextMenu.ContextMenu} contextMenu
Blink Reformat4c46d092018-04-07 15:32:37329 * @param {!Object} object
330 */
331 appendApplicableItems(event, contextMenu, object) {
Tim van der Lippe046db882020-02-13 13:55:11332 const node = /** @type {!SDK.DOMModel.DOMNode} */ (object);
Tim van der Lippe1d6e57a2019-09-30 11:55:34333 if (node.pseudoType()) {
Blink Reformat4c46d092018-04-07 15:32:37334 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34335 }
Tim van der Lippe046db882020-02-13 13:55:11336 const domDebuggerModel = node.domModel().target().model(SDK.DOMDebuggerModel.DOMDebuggerModel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34337 if (!domDebuggerModel) {
Blink Reformat4c46d092018-04-07 15:32:37338 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34339 }
Blink Reformat4c46d092018-04-07 15:32:37340
341 /**
Tim van der Lippe046db882020-02-13 13:55:11342 * @param {!Protocol.DOMDebugger.DOMBreakpointType} type
Blink Reformat4c46d092018-04-07 15:32:37343 */
344 function toggleBreakpoint(type) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34345 if (domDebuggerModel.hasDOMBreakpoint(node, type)) {
Blink Reformat4c46d092018-04-07 15:32:37346 domDebuggerModel.removeDOMBreakpoint(node, type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34347 } else {
Blink Reformat4c46d092018-04-07 15:32:37348 domDebuggerModel.setDOMBreakpoint(node, type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34349 }
Blink Reformat4c46d092018-04-07 15:32:37350 }
351
Tim van der Lippe046db882020-02-13 13:55:11352 const breakpointsMenu = contextMenu.debugSection().appendSubMenuItem(Common.UIString.UIString('Break on'));
353 for (const key in Protocol.DOMDebugger.DOMBreakpointType) {
354 const type = Protocol.DOMDebugger.DOMBreakpointType[key];
Blink Reformat4c46d092018-04-07 15:32:37355 const label = Sources.DebuggerPausedMessage.BreakpointTypeNouns.get(type);
356 breakpointsMenu.defaultSection().appendCheckboxItem(
357 label, toggleBreakpoint.bind(null, type), domDebuggerModel.hasDOMBreakpoint(node, type));
358 }
359 }
Paul Lewis7f7a9202019-11-26 16:10:56360}