blob: 1ed5f74b62b302302609779b2460e3d16dc35e86 [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) {
84 const element = createElementWithClass('div', 'breakpoint-entry');
85 element.addEventListener('contextmenu', this._contextMenu.bind(this, item), true);
86 UI.ARIAUtils.markAsListitem(element);
87 element.tabIndex = this._list.selectedItem() === item ? 0 : -1;
88
Tim van der Lippe046db882020-02-13 13:55:1189 const checkboxLabel = UI.UIUtils.CheckboxLabel.create(/* title */ '', item.enabled);
Jack Lynch8a344762019-12-12 03:17:3890 const checkboxElement = checkboxLabel.checkboxElement;
91 checkboxElement.addEventListener('click', this._checkboxClicked.bind(this, item), false);
92 checkboxElement.tabIndex = -1;
93 UI.ARIAUtils.markAsHidden(checkboxLabel);
94 element.appendChild(checkboxLabel);
95
96 const labelElement = createElementWithClass('div', 'dom-breakpoint');
97 element.appendChild(labelElement);
98 element.addEventListener('keydown', event => {
99 if (event.key === ' ') {
100 checkboxElement.click();
101 event.consume(true);
102 }
103 });
104
105 const description = createElement('div');
Paul Lewis2a4f9fe2020-01-09 15:19:41106 const breakpointTypeLabel = BreakpointTypeLabels.get(item.type);
Jack Lynch8a344762019-12-12 03:17:38107 description.textContent = breakpointTypeLabel;
Tim van der Lippe6ab9f462020-05-01 14:22:38108 const linkifiedNode = document.createElement('monospace');
Jack Lynch8a344762019-12-12 03:17:38109 linkifiedNode.style.display = 'block';
110 labelElement.appendChild(linkifiedNode);
Tim van der Lippe046db882020-02-13 13:55:11111 Common.Linkifier.Linkifier.linkify(item.node, {preventKeyboardFocus: true}).then(linkified => {
Jack Lynch8a344762019-12-12 03:17:38112 linkifiedNode.appendChild(linkified);
113 UI.ARIAUtils.setAccessibleName(checkboxElement, ls`${breakpointTypeLabel}: ${linkified.deepTextContent()}`);
114 });
115
116 labelElement.appendChild(description);
117
118 const checkedStateText = item.enabled ? ls`checked` : ls`unchecked`;
119 if (item === this._highlightedBreakpoint) {
120 element.classList.add('breakpoint-hit');
121 UI.ARIAUtils.setDescription(element, ls`${checkedStateText} breakpoint hit`);
122 } else {
123 UI.ARIAUtils.setDescription(element, checkedStateText);
124 }
125
126
127 this._emptyElement.classList.add('hidden');
128 this._list.element.classList.remove('hidden');
129
130 return element;
131 }
132
133 /**
134 * @override
135 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} item
136 * @return {number}
137 */
138 heightForItem(item) {
139 return 0;
140 }
141
142 /**
143 * @override
144 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} item
145 * @return {boolean}
146 */
147 isItemSelectable(item) {
148 return true;
149 }
150
151 /**
152 * @override
153 * @param {?Element} fromElement
154 * @param {?Element} toElement
155 * @return {boolean}
156 */
157 updateSelectedItemARIA(fromElement, toElement) {
158 return true;
159 }
160
161 /**
162 * @override
163 * @param {?SDK.DOMDebuggerModel.DOMBreakpoint} from
164 * @param {?SDK.DOMDebuggerModel.DOMBreakpoint} to
165 * @param {?Element} fromElement
166 * @param {?Element} toElement
167 */
168 selectedItemChanged(from, to, fromElement, toElement) {
169 if (fromElement) {
170 fromElement.tabIndex = -1;
171 }
172
173 if (toElement) {
174 this.setDefaultFocusedElement(toElement);
175 toElement.tabIndex = 0;
176 if (this.hasFocus()) {
177 toElement.focus();
178 }
179 }
180 }
181
182 /**
Tim van der Lippec02a97c2020-02-14 14:39:27183 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37184 */
185 _breakpointAdded(event) {
186 this._addBreakpoint(/** @type {!SDK.DOMDebuggerModel.DOMBreakpoint} */ (event.data));
187 }
188
189 /**
Tim van der Lippec02a97c2020-02-14 14:39:27190 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37191 */
192 _breakpointToggled(event) {
Jack Lynch8a344762019-12-12 03:17:38193 const hadFocus = this.hasFocus();
Blink Reformat4c46d092018-04-07 15:32:37194 const breakpoint = /** @type {!SDK.DOMDebuggerModel.DOMBreakpoint} */ (event.data);
Jack Lynch8a344762019-12-12 03:17:38195 this._list.refreshItem(breakpoint);
196 if (hadFocus) {
197 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34198 }
Blink Reformat4c46d092018-04-07 15:32:37199 }
200
201 /**
Tim van der Lippec02a97c2020-02-14 14:39:27202 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37203 */
204 _breakpointsRemoved(event) {
Jack Lynch8a344762019-12-12 03:17:38205 const hadFocus = this.hasFocus();
Blink Reformat4c46d092018-04-07 15:32:37206 const breakpoints = /** @type {!Array<!SDK.DOMDebuggerModel.DOMBreakpoint>} */ (event.data);
Jack Lynch8a344762019-12-12 03:17:38207 let lastIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37208 for (const breakpoint of breakpoints) {
Jack Lynch8a344762019-12-12 03:17:38209 const index = this._breakpoints.indexOf(breakpoint);
210 if (index >= 0) {
211 this._breakpoints.remove(index);
212 lastIndex = index;
Blink Reformat4c46d092018-04-07 15:32:37213 }
214 }
Jack Lynch8a344762019-12-12 03:17:38215 if (this._breakpoints.length === 0) {
Blink Reformat4c46d092018-04-07 15:32:37216 this._emptyElement.classList.remove('hidden');
Jack Lynch8a344762019-12-12 03:17:38217 this.setDefaultFocusedElement(this._emptyElement);
218 this._list.element.classList.add('hidden');
219 } else if (lastIndex >= 0) {
220 const breakpointToSelect = this._breakpoints.at(lastIndex);
221 if (breakpointToSelect) {
222 this._list.selectItem(breakpointToSelect);
223 }
224 }
225 if (hadFocus) {
226 this.focus();
Blink Reformat4c46d092018-04-07 15:32:37227 }
228 }
229
230 /**
231 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
232 */
233 _addBreakpoint(breakpoint) {
Jack Lynch8a344762019-12-12 03:17:38234 this._breakpoints.insertWithComparator(breakpoint, (breakpointA, breakpointB) => {
235 if (breakpointA.type > breakpointB.type) {
236 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34237 }
Jack Lynch8a344762019-12-12 03:17:38238 if (breakpointA.type < breakpointB.type) {
239 return 1;
240 }
241 return 0;
242 });
243 if (!this.hasFocus()) {
244 this._list.selectItem(this._breakpoints.at(0));
Blink Reformat4c46d092018-04-07 15:32:37245 }
Blink Reformat4c46d092018-04-07 15:32:37246 }
247
248 /**
249 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
250 * @param {!Event} event
251 */
252 _contextMenu(breakpoint, event) {
Tim van der Lippe046db882020-02-13 13:55:11253 const contextMenu = new UI.ContextMenu.ContextMenu(event);
Jack Lynch8a344762019-12-12 03:17:38254 contextMenu.defaultSection().appendItem(
255 ls`Reveal DOM node in Elements panel`, Common.Revealer.reveal.bind(null, breakpoint.node));
Tim van der Lippe046db882020-02-13 13:55:11256 contextMenu.defaultSection().appendItem(Common.UIString.UIString('Remove breakpoint'), () => {
Blink Reformat4c46d092018-04-07 15:32:37257 breakpoint.domDebuggerModel.removeDOMBreakpoint(breakpoint.node, breakpoint.type);
258 });
Tim van der Lippe046db882020-02-13 13:55:11259 contextMenu.defaultSection().appendItem(Common.UIString.UIString('Remove all DOM breakpoints'), () => {
Blink Reformat4c46d092018-04-07 15:32:37260 breakpoint.domDebuggerModel.removeAllDOMBreakpoints();
261 });
262 contextMenu.show();
263 }
264
265 /**
266 * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
Jack Lynch8a344762019-12-12 03:17:38267 * @param {!Event} event
Blink Reformat4c46d092018-04-07 15:32:37268 */
Jack Lynch8a344762019-12-12 03:17:38269 _checkboxClicked(breakpoint, event) {
270 breakpoint.domDebuggerModel.toggleDOMBreakpoint(breakpoint, event.target.checked);
Blink Reformat4c46d092018-04-07 15:32:37271 }
272
273 /**
274 * @override
275 * @param {?Object} object
276 */
277 flavorChanged(object) {
278 this._update();
279 }
280
281 _update() {
Tim van der Lippe046db882020-02-13 13:55:11282 const details = self.UI.context.flavor(SDK.DebuggerModel.DebuggerPausedDetails);
Jack Lynch8a344762019-12-12 03:17:38283 if (this._highlightedBreakpoint) {
284 const oldHighlightedBreakpoint = this._highlightedBreakpoint;
285 delete this._highlightedBreakpoint;
286 this._list.refreshItem(oldHighlightedBreakpoint);
287 }
Blink Reformat4c46d092018-04-07 15:32:37288 if (!details || !details.auxData || details.reason !== SDK.DebuggerModel.BreakReason.DOM) {
Blink Reformat4c46d092018-04-07 15:32:37289 return;
290 }
Jack Lynch8a344762019-12-12 03:17:38291
Tim van der Lippe046db882020-02-13 13:55:11292 const domDebuggerModel = details.debuggerModel.target().model(SDK.DOMDebuggerModel.DOMDebuggerModel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34293 if (!domDebuggerModel) {
Blink Reformat4c46d092018-04-07 15:32:37294 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34295 }
Blink Reformat4c46d092018-04-07 15:32:37296 const data = domDebuggerModel.resolveDOMBreakpointData(/** @type {!Object} */ (details.auxData));
Tim van der Lippe1d6e57a2019-09-30 11:55:34297 if (!data) {
Blink Reformat4c46d092018-04-07 15:32:37298 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34299 }
Blink Reformat4c46d092018-04-07 15:32:37300
Jack Lynch8a344762019-12-12 03:17:38301 for (const breakpoint of this._breakpoints) {
302 if (breakpoint.node === data.node && breakpoint.type === data.type) {
303 this._highlightedBreakpoint = breakpoint;
Tim van der Lippe1d6e57a2019-09-30 11:55:34304 }
Blink Reformat4c46d092018-04-07 15:32:37305 }
Jack Lynch8a344762019-12-12 03:17:38306 if (this._highlightedBreakpoint) {
307 this._list.refreshItem(this._highlightedBreakpoint);
Tim van der Lippe1d6e57a2019-09-30 11:55:34308 }
Paul Lewis75c7d0d2020-03-19 12:17:26309 UI.ViewManager.ViewManager.instance().showView('sources.domBreakpoints');
Blink Reformat4c46d092018-04-07 15:32:37310 }
Paul Lewis7f7a9202019-11-26 16:10:56311}
Blink Reformat4c46d092018-04-07 15:32:37312
Paul Lewis7f7a9202019-11-26 16:10:56313export const BreakpointTypeLabels = new Map([
Tim van der Lippe046db882020-02-13 13:55:11314 [Protocol.DOMDebugger.DOMBreakpointType.SubtreeModified, Common.UIString.UIString('Subtree modified')],
315 [Protocol.DOMDebugger.DOMBreakpointType.AttributeModified, Common.UIString.UIString('Attribute modified')],
316 [Protocol.DOMDebugger.DOMBreakpointType.NodeRemoved, Common.UIString.UIString('Node removed')],
Blink Reformat4c46d092018-04-07 15:32:37317]);
318
319/**
320 * @implements {UI.ContextMenu.Provider}
321 */
Paul Lewis7f7a9202019-11-26 16:10:56322export class ContextMenuProvider {
Blink Reformat4c46d092018-04-07 15:32:37323 /**
324 * @override
325 * @param {!Event} event
Tim van der Lippe046db882020-02-13 13:55:11326 * @param {!UI.ContextMenu.ContextMenu} contextMenu
Blink Reformat4c46d092018-04-07 15:32:37327 * @param {!Object} object
328 */
329 appendApplicableItems(event, contextMenu, object) {
Tim van der Lippe046db882020-02-13 13:55:11330 const node = /** @type {!SDK.DOMModel.DOMNode} */ (object);
Tim van der Lippe1d6e57a2019-09-30 11:55:34331 if (node.pseudoType()) {
Blink Reformat4c46d092018-04-07 15:32:37332 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34333 }
Tim van der Lippe046db882020-02-13 13:55:11334 const domDebuggerModel = node.domModel().target().model(SDK.DOMDebuggerModel.DOMDebuggerModel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34335 if (!domDebuggerModel) {
Blink Reformat4c46d092018-04-07 15:32:37336 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34337 }
Blink Reformat4c46d092018-04-07 15:32:37338
339 /**
Tim van der Lippe046db882020-02-13 13:55:11340 * @param {!Protocol.DOMDebugger.DOMBreakpointType} type
Blink Reformat4c46d092018-04-07 15:32:37341 */
342 function toggleBreakpoint(type) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34343 if (domDebuggerModel.hasDOMBreakpoint(node, type)) {
Blink Reformat4c46d092018-04-07 15:32:37344 domDebuggerModel.removeDOMBreakpoint(node, type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34345 } else {
Blink Reformat4c46d092018-04-07 15:32:37346 domDebuggerModel.setDOMBreakpoint(node, type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34347 }
Blink Reformat4c46d092018-04-07 15:32:37348 }
349
Tim van der Lippe046db882020-02-13 13:55:11350 const breakpointsMenu = contextMenu.debugSection().appendSubMenuItem(Common.UIString.UIString('Break on'));
351 for (const key in Protocol.DOMDebugger.DOMBreakpointType) {
352 const type = Protocol.DOMDebugger.DOMBreakpointType[key];
Blink Reformat4c46d092018-04-07 15:32:37353 const label = Sources.DebuggerPausedMessage.BreakpointTypeNouns.get(type);
354 breakpointsMenu.defaultSection().appendCheckboxItem(
355 label, toggleBreakpoint.bind(null, type), domDebuggerModel.hasDOMBreakpoint(node, type));
356 }
357 }
Paul Lewis7f7a9202019-11-26 16:10:56358}