blob: 346d25c0dc30e8283334f17e01e5fb72b165a9f8 [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);
Christy Chend05ba962020-06-05 23:12:2588 element.tabIndex = -1;
Jack Lynch8a344762019-12-12 03:17:3889
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);
Christy Chend05ba962020-06-05 23:12:2593 checkboxElement.tabIndex = this._list.selectedItem() === item ? 0 : -1;
94 element.checkboxElement = checkboxElement;
Jack Lynch8a344762019-12-12 03:17:3895 UI.ARIAUtils.markAsHidden(checkboxLabel);
96 element.appendChild(checkboxLabel);
97
Tim van der Lippef49e2322020-05-01 15:03:0998 const labelElement = document.createElement('div');
99 labelElement.classList.add('dom-breakpoint');
Jack Lynch8a344762019-12-12 03:17:38100 element.appendChild(labelElement);
Jack Lynch8a344762019-12-12 03:17:38101 const description = createElement('div');
Paul Lewis2a4f9fe2020-01-09 15:19:41102 const breakpointTypeLabel = BreakpointTypeLabels.get(item.type);
Jack Lynch8a344762019-12-12 03:17:38103 description.textContent = breakpointTypeLabel;
Tim van der Lippe6ab9f462020-05-01 14:22:38104 const linkifiedNode = document.createElement('monospace');
Jack Lynch8a344762019-12-12 03:17:38105 linkifiedNode.style.display = 'block';
106 labelElement.appendChild(linkifiedNode);
Tim van der Lippe046db882020-02-13 13:55:11107 Common.Linkifier.Linkifier.linkify(item.node, {preventKeyboardFocus: true}).then(linkified => {
Jack Lynch8a344762019-12-12 03:17:38108 linkifiedNode.appendChild(linkified);
109 UI.ARIAUtils.setAccessibleName(checkboxElement, ls`${breakpointTypeLabel}: ${linkified.deepTextContent()}`);
110 });
111
112 labelElement.appendChild(description);
113
114 const checkedStateText = item.enabled ? ls`checked` : ls`unchecked`;
115 if (item === this._highlightedBreakpoint) {
116 element.classList.add('breakpoint-hit');
117 UI.ARIAUtils.setDescription(element, ls`${checkedStateText} breakpoint hit`);
Christy Chend05ba962020-06-05 23:12:25118 UI.ARIAUtils.setDescription(checkboxElement, ls`breakpoint hit`);
Jack Lynch8a344762019-12-12 03:17:38119 } else {
120 UI.ARIAUtils.setDescription(element, checkedStateText);
121 }
122
123
124 this._emptyElement.classList.add('hidden');
125 this._list.element.classList.remove('hidden');
126
127 return element;
128 }
129
130 /**
131 * @override
132 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} item
133 * @return {number}
134 */
135 heightForItem(item) {
136 return 0;
137 }
138
139 /**
140 * @override
141 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} item
142 * @return {boolean}
143 */
144 isItemSelectable(item) {
145 return true;
146 }
147
148 /**
149 * @override
150 * @param {?Element} fromElement
151 * @param {?Element} toElement
152 * @return {boolean}
153 */
154 updateSelectedItemARIA(fromElement, toElement) {
155 return true;
156 }
157
158 /**
159 * @override
160 * @param {?SDK.DOMDebuggerModel.DOMBreakpoint} from
161 * @param {?SDK.DOMDebuggerModel.DOMBreakpoint} to
162 * @param {?Element} fromElement
163 * @param {?Element} toElement
164 */
165 selectedItemChanged(from, to, fromElement, toElement) {
166 if (fromElement) {
Christy Chend05ba962020-06-05 23:12:25167 fromElement.checkboxElement.tabIndex = -1;
Jack Lynch8a344762019-12-12 03:17:38168 }
169
170 if (toElement) {
Christy Chend05ba962020-06-05 23:12:25171 this.setDefaultFocusedElement(toElement.checkboxElement);
172 toElement.checkboxElement.tabIndex = 0;
Jack Lynch8a344762019-12-12 03:17:38173 if (this.hasFocus()) {
Christy Chend05ba962020-06-05 23:12:25174 toElement.checkboxElement.focus();
Jack Lynch8a344762019-12-12 03:17:38175 }
176 }
177 }
178
179 /**
Tim van der Lippec02a97c2020-02-14 14:39:27180 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37181 */
182 _breakpointAdded(event) {
183 this._addBreakpoint(/** @type {!SDK.DOMDebuggerModel.DOMBreakpoint} */ (event.data));
184 }
185
186 /**
Tim van der Lippec02a97c2020-02-14 14:39:27187 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37188 */
189 _breakpointToggled(event) {
Jack Lynch8a344762019-12-12 03:17:38190 const hadFocus = this.hasFocus();
Blink Reformat4c46d092018-04-07 15:32:37191 const breakpoint = /** @type {!SDK.DOMDebuggerModel.DOMBreakpoint} */ (event.data);
Jack Lynch8a344762019-12-12 03:17:38192 this._list.refreshItem(breakpoint);
193 if (hadFocus) {
194 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34195 }
Blink Reformat4c46d092018-04-07 15:32:37196 }
197
198 /**
Tim van der Lippec02a97c2020-02-14 14:39:27199 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37200 */
201 _breakpointsRemoved(event) {
Jack Lynch8a344762019-12-12 03:17:38202 const hadFocus = this.hasFocus();
Blink Reformat4c46d092018-04-07 15:32:37203 const breakpoints = /** @type {!Array<!SDK.DOMDebuggerModel.DOMBreakpoint>} */ (event.data);
Jack Lynch8a344762019-12-12 03:17:38204 let lastIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37205 for (const breakpoint of breakpoints) {
Jack Lynch8a344762019-12-12 03:17:38206 const index = this._breakpoints.indexOf(breakpoint);
207 if (index >= 0) {
208 this._breakpoints.remove(index);
209 lastIndex = index;
Blink Reformat4c46d092018-04-07 15:32:37210 }
211 }
Jack Lynch8a344762019-12-12 03:17:38212 if (this._breakpoints.length === 0) {
Blink Reformat4c46d092018-04-07 15:32:37213 this._emptyElement.classList.remove('hidden');
Jack Lynch8a344762019-12-12 03:17:38214 this.setDefaultFocusedElement(this._emptyElement);
215 this._list.element.classList.add('hidden');
216 } else if (lastIndex >= 0) {
217 const breakpointToSelect = this._breakpoints.at(lastIndex);
218 if (breakpointToSelect) {
219 this._list.selectItem(breakpointToSelect);
220 }
221 }
222 if (hadFocus) {
223 this.focus();
Blink Reformat4c46d092018-04-07 15:32:37224 }
225 }
226
227 /**
228 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
229 */
230 _addBreakpoint(breakpoint) {
Jack Lynch8a344762019-12-12 03:17:38231 this._breakpoints.insertWithComparator(breakpoint, (breakpointA, breakpointB) => {
232 if (breakpointA.type > breakpointB.type) {
233 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34234 }
Jack Lynch8a344762019-12-12 03:17:38235 if (breakpointA.type < breakpointB.type) {
236 return 1;
237 }
238 return 0;
239 });
240 if (!this.hasFocus()) {
241 this._list.selectItem(this._breakpoints.at(0));
Blink Reformat4c46d092018-04-07 15:32:37242 }
Blink Reformat4c46d092018-04-07 15:32:37243 }
244
245 /**
246 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
247 * @param {!Event} event
248 */
249 _contextMenu(breakpoint, event) {
Tim van der Lippe046db882020-02-13 13:55:11250 const contextMenu = new UI.ContextMenu.ContextMenu(event);
Jack Lynch8a344762019-12-12 03:17:38251 contextMenu.defaultSection().appendItem(
252 ls`Reveal DOM node in Elements panel`, Common.Revealer.reveal.bind(null, breakpoint.node));
Tim van der Lippe046db882020-02-13 13:55:11253 contextMenu.defaultSection().appendItem(Common.UIString.UIString('Remove breakpoint'), () => {
Blink Reformat4c46d092018-04-07 15:32:37254 breakpoint.domDebuggerModel.removeDOMBreakpoint(breakpoint.node, breakpoint.type);
255 });
Tim van der Lippe046db882020-02-13 13:55:11256 contextMenu.defaultSection().appendItem(Common.UIString.UIString('Remove all DOM breakpoints'), () => {
Blink Reformat4c46d092018-04-07 15:32:37257 breakpoint.domDebuggerModel.removeAllDOMBreakpoints();
258 });
259 contextMenu.show();
260 }
261
262 /**
263 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
Jack Lynch8a344762019-12-12 03:17:38264 * @param {!Event} event
Blink Reformat4c46d092018-04-07 15:32:37265 */
Jack Lynch8a344762019-12-12 03:17:38266 _checkboxClicked(breakpoint, event) {
267 breakpoint.domDebuggerModel.toggleDOMBreakpoint(breakpoint, event.target.checked);
Blink Reformat4c46d092018-04-07 15:32:37268 }
269
270 /**
271 * @override
272 * @param {?Object} object
273 */
274 flavorChanged(object) {
275 this._update();
276 }
277
278 _update() {
Tim van der Lippe046db882020-02-13 13:55:11279 const details = self.UI.context.flavor(SDK.DebuggerModel.DebuggerPausedDetails);
Jack Lynch8a344762019-12-12 03:17:38280 if (this._highlightedBreakpoint) {
281 const oldHighlightedBreakpoint = this._highlightedBreakpoint;
282 delete this._highlightedBreakpoint;
283 this._list.refreshItem(oldHighlightedBreakpoint);
284 }
Blink Reformat4c46d092018-04-07 15:32:37285 if (!details || !details.auxData || details.reason !== SDK.DebuggerModel.BreakReason.DOM) {
Blink Reformat4c46d092018-04-07 15:32:37286 return;
287 }
Jack Lynch8a344762019-12-12 03:17:38288
Tim van der Lippe046db882020-02-13 13:55:11289 const domDebuggerModel = details.debuggerModel.target().model(SDK.DOMDebuggerModel.DOMDebuggerModel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34290 if (!domDebuggerModel) {
Blink Reformat4c46d092018-04-07 15:32:37291 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34292 }
Blink Reformat4c46d092018-04-07 15:32:37293 const data = domDebuggerModel.resolveDOMBreakpointData(/** @type {!Object} */ (details.auxData));
Tim van der Lippe1d6e57a2019-09-30 11:55:34294 if (!data) {
Blink Reformat4c46d092018-04-07 15:32:37295 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34296 }
Blink Reformat4c46d092018-04-07 15:32:37297
Jack Lynch8a344762019-12-12 03:17:38298 for (const breakpoint of this._breakpoints) {
299 if (breakpoint.node === data.node && breakpoint.type === data.type) {
300 this._highlightedBreakpoint = breakpoint;
Tim van der Lippe1d6e57a2019-09-30 11:55:34301 }
Blink Reformat4c46d092018-04-07 15:32:37302 }
Jack Lynch8a344762019-12-12 03:17:38303 if (this._highlightedBreakpoint) {
304 this._list.refreshItem(this._highlightedBreakpoint);
Tim van der Lippe1d6e57a2019-09-30 11:55:34305 }
Paul Lewis75c7d0d2020-03-19 12:17:26306 UI.ViewManager.ViewManager.instance().showView('sources.domBreakpoints');
Blink Reformat4c46d092018-04-07 15:32:37307 }
Paul Lewis7f7a9202019-11-26 16:10:56308}
Blink Reformat4c46d092018-04-07 15:32:37309
Paul Lewis7f7a9202019-11-26 16:10:56310export const BreakpointTypeLabels = new Map([
Tim van der Lippe046db882020-02-13 13:55:11311 [Protocol.DOMDebugger.DOMBreakpointType.SubtreeModified, Common.UIString.UIString('Subtree modified')],
312 [Protocol.DOMDebugger.DOMBreakpointType.AttributeModified, Common.UIString.UIString('Attribute modified')],
313 [Protocol.DOMDebugger.DOMBreakpointType.NodeRemoved, Common.UIString.UIString('Node removed')],
Blink Reformat4c46d092018-04-07 15:32:37314]);
315
316/**
317 * @implements {UI.ContextMenu.Provider}
318 */
Paul Lewis7f7a9202019-11-26 16:10:56319export class ContextMenuProvider {
Blink Reformat4c46d092018-04-07 15:32:37320 /**
321 * @override
322 * @param {!Event} event
Tim van der Lippe046db882020-02-13 13:55:11323 * @param {!UI.ContextMenu.ContextMenu} contextMenu
Blink Reformat4c46d092018-04-07 15:32:37324 * @param {!Object} object
325 */
326 appendApplicableItems(event, contextMenu, object) {
Tim van der Lippe046db882020-02-13 13:55:11327 const node = /** @type {!SDK.DOMModel.DOMNode} */ (object);
Tim van der Lippe1d6e57a2019-09-30 11:55:34328 if (node.pseudoType()) {
Blink Reformat4c46d092018-04-07 15:32:37329 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34330 }
Tim van der Lippe046db882020-02-13 13:55:11331 const domDebuggerModel = node.domModel().target().model(SDK.DOMDebuggerModel.DOMDebuggerModel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34332 if (!domDebuggerModel) {
Blink Reformat4c46d092018-04-07 15:32:37333 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34334 }
Blink Reformat4c46d092018-04-07 15:32:37335
336 /**
Tim van der Lippe046db882020-02-13 13:55:11337 * @param {!Protocol.DOMDebugger.DOMBreakpointType} type
Blink Reformat4c46d092018-04-07 15:32:37338 */
339 function toggleBreakpoint(type) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34340 if (domDebuggerModel.hasDOMBreakpoint(node, type)) {
Blink Reformat4c46d092018-04-07 15:32:37341 domDebuggerModel.removeDOMBreakpoint(node, type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34342 } else {
Blink Reformat4c46d092018-04-07 15:32:37343 domDebuggerModel.setDOMBreakpoint(node, type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34344 }
Blink Reformat4c46d092018-04-07 15:32:37345 }
346
Tim van der Lippe046db882020-02-13 13:55:11347 const breakpointsMenu = contextMenu.debugSection().appendSubMenuItem(Common.UIString.UIString('Break on'));
348 for (const key in Protocol.DOMDebugger.DOMBreakpointType) {
349 const type = Protocol.DOMDebugger.DOMBreakpointType[key];
Blink Reformat4c46d092018-04-07 15:32:37350 const label = Sources.DebuggerPausedMessage.BreakpointTypeNouns.get(type);
351 breakpointsMenu.defaultSection().appendCheckboxItem(
352 label, toggleBreakpoint.bind(null, type), domDebuggerModel.hasDOMBreakpoint(node, type));
353 }
354 }
Paul Lewis7f7a9202019-11-26 16:10:56355}