blob: 844e2d4491b80c172b718f6b6865241d2b2f3446 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export default class DOMDebuggerModel extends SDK.SDKModel {
/**
* @param {!SDK.Target} target
*/
constructor(target) {
super(target);
this._agent = target.domdebuggerAgent();
this._runtimeModel = /** @type {!SDK.RuntimeModel} */ (target.model(SDK.RuntimeModel));
this._domModel = /** @type {!SDK.DOMModel} */ (target.model(SDK.DOMModel));
this._domModel.addEventListener(SDK.DOMModel.Events.DocumentUpdated, this._documentUpdated, this);
this._domModel.addEventListener(SDK.DOMModel.Events.NodeRemoved, this._nodeRemoved, this);
/** @type {!Array<!DOMBreakpoint>} */
this._domBreakpoints = [];
this._domBreakpointsSetting = Common.settings.createLocalSetting('domBreakpoints', []);
if (this._domModel.existingDocument()) {
this._documentUpdated();
}
}
/**
* @return {!SDK.RuntimeModel}
*/
runtimeModel() {
return this._runtimeModel;
}
/**
* @param {!SDK.RemoteObject} remoteObject
* @return {!Promise<!Array<!SDK.EventListener>>}
*/
async eventListeners(remoteObject) {
console.assert(remoteObject.runtimeModel() === this._runtimeModel);
if (!remoteObject.objectId) {
return [];
}
const payloads = await this._agent.getEventListeners(/** @type {string} */ (remoteObject.objectId));
const eventListeners = [];
for (const payload of payloads || []) {
const location = this._runtimeModel.debuggerModel().createRawLocationByScriptId(
payload.scriptId, payload.lineNumber, payload.columnNumber);
if (!location) {
continue;
}
eventListeners.push(new SDK.EventListener(
this, remoteObject, payload.type, payload.useCapture, payload.passive, payload.once,
payload.handler ? this._runtimeModel.createRemoteObject(payload.handler) : null,
payload.originalHandler ? this._runtimeModel.createRemoteObject(payload.originalHandler) : null, location,
null));
}
return eventListeners;
}
retrieveDOMBreakpoints() {
this._domModel.requestDocument();
}
/**
* @return {!Array<!DOMBreakpoint>}
*/
domBreakpoints() {
return this._domBreakpoints.slice();
}
/**
* @param {!SDK.DOMNode} node
* @param {!SDK.DOMDebuggerModel.DOMBreakpoint.Type} type
* @return {boolean}
*/
hasDOMBreakpoint(node, type) {
return this._domBreakpoints.some(breakpoint => (breakpoint.node === node && breakpoint.type === type));
}
/**
* @param {!SDK.DOMNode} node
* @param {!SDK.DOMDebuggerModel.DOMBreakpoint.Type} type
* @return {!DOMBreakpoint}
*/
setDOMBreakpoint(node, type) {
for (const breakpoint of this._domBreakpoints) {
if (breakpoint.node === node && breakpoint.type === type) {
this.toggleDOMBreakpoint(breakpoint, true);
return breakpoint;
}
}
const breakpoint = new DOMBreakpoint(this, node, type, true);
this._domBreakpoints.push(breakpoint);
this._saveDOMBreakpoints();
this._enableDOMBreakpoint(breakpoint);
this.dispatchEventToListeners(Events.DOMBreakpointAdded, breakpoint);
return breakpoint;
}
/**
* @param {!SDK.DOMNode} node
* @param {!SDK.DOMDebuggerModel.DOMBreakpoint.Type} type
*/
removeDOMBreakpoint(node, type) {
this._removeDOMBreakpoints(breakpoint => breakpoint.node === node && breakpoint.type === type);
}
removeAllDOMBreakpoints() {
this._removeDOMBreakpoints(breakpoint => true);
}
/**
* @param {!DOMBreakpoint} breakpoint
* @param {boolean} enabled
*/
toggleDOMBreakpoint(breakpoint, enabled) {
if (enabled === breakpoint.enabled) {
return;
}
breakpoint.enabled = enabled;
if (enabled) {
this._enableDOMBreakpoint(breakpoint);
} else {
this._disableDOMBreakpoint(breakpoint);
}
this.dispatchEventToListeners(Events.DOMBreakpointToggled, breakpoint);
}
/**
* @param {!DOMBreakpoint} breakpoint
*/
_enableDOMBreakpoint(breakpoint) {
this._agent.setDOMBreakpoint(breakpoint.node.id, breakpoint.type);
breakpoint.node.setMarker(Marker, true);
}
/**
* @param {!DOMBreakpoint} breakpoint
*/
_disableDOMBreakpoint(breakpoint) {
this._agent.removeDOMBreakpoint(breakpoint.node.id, breakpoint.type);
breakpoint.node.setMarker(Marker, this._nodeHasBreakpoints(breakpoint.node) ? true : null);
}
/**
* @param {!SDK.DOMNode} node
* @return {boolean}
*/
_nodeHasBreakpoints(node) {
for (const breakpoint of this._domBreakpoints) {
if (breakpoint.node === node && breakpoint.enabled) {
return true;
}
}
return false;
}
/**
* @param {!Object} auxData
* @return {?{type: !SDK.DOMDebuggerModel.DOMBreakpoint.Type, node: !SDK.DOMNode, targetNode: ?SDK.DOMNode, insertion: boolean}}
*/
resolveDOMBreakpointData(auxData) {
const type = auxData['type'];
const node = this._domModel.nodeForId(auxData['nodeId']);
if (!type || !node) {
return null;
}
let targetNode = null;
let insertion = false;
if (type === SDK.DOMDebuggerModel.DOMBreakpoint.Type.SubtreeModified) {
insertion = auxData['insertion'] || false;
targetNode = this._domModel.nodeForId(auxData['targetNodeId']);
}
return {type: type, node: node, targetNode: targetNode, insertion: insertion};
}
/**
* @return {string}
*/
_currentURL() {
const domDocument = this._domModel.existingDocument();
return domDocument ? domDocument.documentURL : '';
}
_documentUpdated() {
const removed = this._domBreakpoints;
this._domBreakpoints = [];
this.dispatchEventToListeners(Events.DOMBreakpointsRemoved, removed);
const currentURL = this._currentURL();
for (const breakpoint of this._domBreakpointsSetting.get()) {
if (breakpoint.url === currentURL) {
this._domModel.pushNodeByPathToFrontend(breakpoint.path).then(appendBreakpoint.bind(this, breakpoint));
}
}
/**
* @param {!{type: !SDK.DOMDebuggerModel.DOMBreakpoint.Type, enabled: boolean}} breakpoint
* @param {?number} nodeId
* @this {DOMDebuggerModel}
*/
function appendBreakpoint(breakpoint, nodeId) {
const node = nodeId ? this._domModel.nodeForId(nodeId) : null;
if (!node) {
return;
}
const domBreakpoint = new DOMBreakpoint(this, node, breakpoint.type, breakpoint.enabled);
this._domBreakpoints.push(domBreakpoint);
if (breakpoint.enabled) {
this._enableDOMBreakpoint(domBreakpoint);
}
this.dispatchEventToListeners(Events.DOMBreakpointAdded, domBreakpoint);
}
}
/**
* @param {function(!DOMBreakpoint):boolean} filter
*/
_removeDOMBreakpoints(filter) {
const removed = [];
const left = [];
for (const breakpoint of this._domBreakpoints) {
if (filter(breakpoint)) {
removed.push(breakpoint);
if (breakpoint.enabled) {
breakpoint.enabled = false;
this._disableDOMBreakpoint(breakpoint);
}
} else {
left.push(breakpoint);
}
}
if (!removed.length) {
return;
}
this._domBreakpoints = left;
this._saveDOMBreakpoints();
this.dispatchEventToListeners(Events.DOMBreakpointsRemoved, removed);
}
/**
* @param {!Common.Event} event
*/
_nodeRemoved(event) {
const node = /** @type {!SDK.DOMNode} */ (event.data.node);
const children = node.children() || [];
this._removeDOMBreakpoints(breakpoint => breakpoint.node === node || children.indexOf(breakpoint.node) !== -1);
}
_saveDOMBreakpoints() {
const currentURL = this._currentURL();
const breakpoints = this._domBreakpointsSetting.get().filter(breakpoint => breakpoint.url !== currentURL);
for (const breakpoint of this._domBreakpoints) {
breakpoints.push(
{url: currentURL, path: breakpoint.node.path(), type: breakpoint.type, enabled: breakpoint.enabled});
}
this._domBreakpointsSetting.set(breakpoints);
}
}
/** @enum {symbol} */
export const Events = {
DOMBreakpointAdded: Symbol('DOMBreakpointAdded'),
DOMBreakpointToggled: Symbol('DOMBreakpointToggled'),
DOMBreakpointsRemoved: Symbol('DOMBreakpointsRemoved'),
};
const Marker = 'breakpoint-marker';
export class DOMBreakpoint {
/**
* @param {!DOMDebuggerModel} domDebuggerModel
* @param {!SDK.DOMNode} node
* @param {!SDK.DOMDebuggerModel.DOMBreakpoint.Type} type
* @param {boolean} enabled
*/
constructor(domDebuggerModel, node, type, enabled) {
this.domDebuggerModel = domDebuggerModel;
this.node = node;
this.type = type;
this.enabled = enabled;
}
}
export class EventListener {
/**
* @param {!DOMDebuggerModel} domDebuggerModel
* @param {!SDK.RemoteObject} eventTarget
* @param {string} type
* @param {boolean} useCapture
* @param {boolean} passive
* @param {boolean} once
* @param {?SDK.RemoteObject} handler
* @param {?SDK.RemoteObject} originalHandler
* @param {!SDK.DebuggerModel.Location} location
* @param {?SDK.RemoteObject} customRemoveFunction
* @param {!EventListener.Origin=} origin
*/
constructor(
domDebuggerModel, eventTarget, type, useCapture, passive, once, handler, originalHandler, location,
customRemoveFunction, origin) {
this._domDebuggerModel = domDebuggerModel;
this._eventTarget = eventTarget;
this._type = type;
this._useCapture = useCapture;
this._passive = passive;
this._once = once;
this._handler = handler;
this._originalHandler = originalHandler || handler;
this._location = location;
const script = location.script();
this._sourceURL = script ? script.contentURL() : '';
this._customRemoveFunction = customRemoveFunction;
this._origin = origin || EventListener.Origin.Raw;
}
/**
* @return {!DOMDebuggerModel}
*/
domDebuggerModel() {
return this._domDebuggerModel;
}
/**
* @return {string}
*/
type() {
return this._type;
}
/**
* @return {boolean}
*/
useCapture() {
return this._useCapture;
}
/**
* @return {boolean}
*/
passive() {
return this._passive;
}
/**
* @return {boolean}
*/
once() {
return this._once;
}
/**
* @return {?SDK.RemoteObject}
*/
handler() {
return this._handler;
}
/**
* @return {!SDK.DebuggerModel.Location}
*/
location() {
return this._location;
}
/**
* @return {string}
*/
sourceURL() {
return this._sourceURL;
}
/**
* @return {?SDK.RemoteObject}
*/
originalHandler() {
return this._originalHandler;
}
/**
* @return {boolean}
*/
canRemove() {
return !!this._customRemoveFunction || this._origin !== EventListener.Origin.FrameworkUser;
}
/**
* @return {!Promise<undefined>}
*/
remove() {
if (!this.canRemove()) {
return Promise.resolve();
}
if (this._origin !== EventListener.Origin.FrameworkUser) {
/**
* @param {string} type
* @param {function()} listener
* @param {boolean} useCapture
* @this {Object}
* @suppressReceiverCheck
*/
function removeListener(type, listener, useCapture) {
this.removeEventListener(type, listener, useCapture);
if (this['on' + type]) {
this['on' + type] = undefined;
}
}
return /** @type {!Promise<undefined>} */ (this._eventTarget.callFunction(removeListener, [
SDK.RemoteObject.toCallArgument(this._type), SDK.RemoteObject.toCallArgument(this._originalHandler),
SDK.RemoteObject.toCallArgument(this._useCapture)
]));
}
return this._customRemoveFunction
.callFunction(
callCustomRemove,
[
SDK.RemoteObject.toCallArgument(this._type),
SDK.RemoteObject.toCallArgument(this._originalHandler),
SDK.RemoteObject.toCallArgument(this._useCapture),
SDK.RemoteObject.toCallArgument(this._passive),
])
.then(() => undefined);
/**
* @param {string} type
* @param {function()} listener
* @param {boolean} useCapture
* @param {boolean} passive
* @this {Function}
* @suppressReceiverCheck
*/
function callCustomRemove(type, listener, useCapture, passive) {
this.call(null, type, listener, useCapture, passive);
}
}
/**
* @return {boolean}
*/
canTogglePassive() {
return this._origin !== EventListener.Origin.FrameworkUser;
}
/**
* @return {!Promise<undefined>}
*/
togglePassive() {
return /** @type {!Promise<undefined>} */ (this._eventTarget.callFunction(callTogglePassive, [
SDK.RemoteObject.toCallArgument(this._type),
SDK.RemoteObject.toCallArgument(this._originalHandler),
SDK.RemoteObject.toCallArgument(this._useCapture),
SDK.RemoteObject.toCallArgument(this._passive),
]));
/**
* @param {string} type
* @param {function()} listener
* @param {boolean} useCapture
* @param {boolean} passive
* @this {Object}
* @suppressReceiverCheck
*/
function callTogglePassive(type, listener, useCapture, passive) {
this.removeEventListener(type, listener, {capture: useCapture});
this.addEventListener(type, listener, {capture: useCapture, passive: !passive});
}
}
/**
* @return {!EventListener.Origin}
*/
origin() {
return this._origin;
}
markAsFramework() {
this._origin = EventListener.Origin.Framework;
}
/**
* @return {boolean}
*/
isScrollBlockingType() {
return this._type === 'touchstart' || this._type === 'touchmove' || this._type === 'mousewheel' ||
this._type === 'wheel';
}
}
/** @enum {string} */
EventListener.Origin = {
Raw: 'Raw',
Framework: 'Framework',
FrameworkUser: 'FrameworkUser'
};
export class EventListenerBreakpoint {
/**
* @param {string} instrumentationName
* @param {string} eventName
* @param {!Array<string>} eventTargetNames
* @param {string} category
* @param {string} title
*/
constructor(instrumentationName, eventName, eventTargetNames, category, title) {
this._instrumentationName = instrumentationName;
this._eventName = eventName;
this._eventTargetNames = eventTargetNames;
this._category = category;
this._title = title;
this._enabled = false;
}
/**
* @return {string}
*/
category() {
return this._category;
}
/**
* @return {boolean}
*/
enabled() {
return this._enabled;
}
/**
* @param {boolean} enabled
*/
setEnabled(enabled) {
if (this._enabled === enabled) {
return;
}
this._enabled = enabled;
for (const model of SDK.targetManager.models(DOMDebuggerModel)) {
this._updateOnModel(model);
}
}
/**
* @param {!DOMDebuggerModel} model
*/
_updateOnModel(model) {
if (this._instrumentationName) {
if (this._enabled) {
model._agent.setInstrumentationBreakpoint(this._instrumentationName);
} else {
model._agent.removeInstrumentationBreakpoint(this._instrumentationName);
}
} else {
for (const eventTargetName of this._eventTargetNames) {
if (this._enabled) {
model._agent.setEventListenerBreakpoint(this._eventName, eventTargetName);
} else {
model._agent.removeEventListenerBreakpoint(this._eventName, eventTargetName);
}
}
}
}
/**
* @return {string}
*/
title() {
return this._title;
}
}
EventListenerBreakpoint._listener = 'listener:';
EventListenerBreakpoint._instrumentation = 'instrumentation:';
/**
* @implements {SDK.SDKModelObserver<!DOMDebuggerModel>}
*/
export class DOMDebuggerManager {
constructor() {
this._xhrBreakpointsSetting = Common.settings.createLocalSetting('xhrBreakpoints', []);
/** @type {!Map<string, boolean>} */
this._xhrBreakpoints = new Map();
for (const breakpoint of this._xhrBreakpointsSetting.get()) {
this._xhrBreakpoints.set(breakpoint.url, breakpoint.enabled);
}
/** @type {!Array<!EventListenerBreakpoint>} */
this._eventListenerBreakpoints = [];
this._createInstrumentationBreakpoints(
Common.UIString('Animation'),
['requestAnimationFrame', 'cancelAnimationFrame', 'requestAnimationFrame.callback']);
this._createInstrumentationBreakpoints(
Common.UIString('Canvas'), ['canvasContextCreated', 'webglErrorFired', 'webglWarningFired']);
this._createInstrumentationBreakpoints(
Common.UIString('Geolocation'), ['Geolocation.getCurrentPosition', 'Geolocation.watchPosition']);
this._createInstrumentationBreakpoints(Common.UIString('Notification'), ['Notification.requestPermission']);
this._createInstrumentationBreakpoints(Common.UIString('Parse'), ['Element.setInnerHTML', 'Document.write']);
this._createInstrumentationBreakpoints(Common.UIString('Script'), ['scriptFirstStatement', 'scriptBlockedByCSP']);
this._createInstrumentationBreakpoints(
Common.UIString('Timer'),
['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setTimeout.callback', 'setInterval.callback']);
this._createInstrumentationBreakpoints(Common.UIString('Window'), ['DOMWindow.close']);
this._createInstrumentationBreakpoints(
Common.UIString('WebAudio'),
['audioContextCreated', 'audioContextClosed', 'audioContextResumed', 'audioContextSuspended']);
this._createEventListenerBreakpoints(
Common.UIString('Media'),
[
'play', 'pause', 'playing', 'canplay', 'canplaythrough', 'seeking',
'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange',
'loadstart', 'progress', 'suspend', 'abort', 'error', 'emptied',
'stalled', 'loadedmetadata', 'loadeddata', 'waiting'
],
['audio', 'video']);
this._createEventListenerBreakpoints(
Common.UIString('Picture-in-Picture'), ['enterpictureinpicture', 'leavepictureinpicture'], ['video']);
this._createEventListenerBreakpoints(Common.UIString('Picture-in-Picture'), ['resize'], ['PictureInPictureWindow']);
this._createEventListenerBreakpoints(
Common.UIString('Clipboard'), ['copy', 'cut', 'paste', 'beforecopy', 'beforecut', 'beforepaste'], ['*']);
this._createEventListenerBreakpoints(
Common.UIString('Control'),
['resize', 'scroll', 'zoom', 'focus', 'blur', 'select', 'change', 'submit', 'reset'], ['*']);
this._createEventListenerBreakpoints(Common.UIString('Device'), ['deviceorientation', 'devicemotion'], ['*']);
this._createEventListenerBreakpoints(
Common.UIString('DOM Mutation'),
[
'DOMActivate', 'DOMFocusIn', 'DOMFocusOut', 'DOMAttrModified', 'DOMCharacterDataModified', 'DOMNodeInserted',
'DOMNodeInsertedIntoDocument', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument', 'DOMSubtreeModified',
'DOMContentLoaded'
],
['*']);
this._createEventListenerBreakpoints(
Common.UIString('Drag / drop'), ['drag', 'dragstart', 'dragend', 'dragenter', 'dragover', 'dragleave', 'drop'],
['*']);
this._createEventListenerBreakpoints(Common.UIString('Keyboard'), ['keydown', 'keyup', 'keypress', 'input'], ['*']);
this._createEventListenerBreakpoints(
Common.UIString('Load'), ['load', 'beforeunload', 'unload', 'abort', 'error', 'hashchange', 'popstate'], ['*']);
this._createEventListenerBreakpoints(
Common.UIString('Mouse'),
[
'auxclick', 'click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout', 'mouseenter',
'mouseleave', 'mousewheel', 'wheel', 'contextmenu'
],
['*']);
this._createEventListenerBreakpoints(
Common.UIString('Pointer'),
[
'pointerover', 'pointerout', 'pointerenter', 'pointerleave', 'pointerdown', 'pointerup', 'pointermove',
'pointercancel', 'gotpointercapture', 'lostpointercapture', 'pointerrawupdate'
],
['*']);
this._createEventListenerBreakpoints(
Common.UIString('Touch'), ['touchstart', 'touchmove', 'touchend', 'touchcancel'], ['*']);
this._createEventListenerBreakpoints(Common.UIString('Worker'), ['message', 'messageerror'], ['*']);
this._createEventListenerBreakpoints(
Common.UIString('XHR'),
['readystatechange', 'load', 'loadstart', 'loadend', 'abort', 'error', 'progress', 'timeout'],
['xmlhttprequest', 'xmlhttprequestupload']);
this._resolveEventListenerBreakpoint('instrumentation:setTimeout.callback')._title =
Common.UIString('setTimeout fired');
this._resolveEventListenerBreakpoint('instrumentation:setInterval.callback')._title =
Common.UIString('setInterval fired');
this._resolveEventListenerBreakpoint('instrumentation:scriptFirstStatement')._title =
Common.UIString('Script First Statement');
this._resolveEventListenerBreakpoint('instrumentation:scriptBlockedByCSP')._title =
Common.UIString('Script Blocked by Content Security Policy');
this._resolveEventListenerBreakpoint('instrumentation:requestAnimationFrame')._title =
Common.UIString('Request Animation Frame');
this._resolveEventListenerBreakpoint('instrumentation:cancelAnimationFrame')._title =
Common.UIString('Cancel Animation Frame');
this._resolveEventListenerBreakpoint('instrumentation:requestAnimationFrame.callback')._title =
Common.UIString('Animation Frame Fired');
this._resolveEventListenerBreakpoint('instrumentation:webglErrorFired')._title =
Common.UIString('WebGL Error Fired');
this._resolveEventListenerBreakpoint('instrumentation:webglWarningFired')._title =
Common.UIString('WebGL Warning Fired');
this._resolveEventListenerBreakpoint('instrumentation:Element.setInnerHTML')._title =
Common.UIString('Set innerHTML');
this._resolveEventListenerBreakpoint('instrumentation:canvasContextCreated')._title =
Common.UIString('Create canvas context');
this._resolveEventListenerBreakpoint('instrumentation:Geolocation.getCurrentPosition')._title =
'getCurrentPosition';
this._resolveEventListenerBreakpoint('instrumentation:Geolocation.watchPosition')._title = 'watchPosition';
this._resolveEventListenerBreakpoint('instrumentation:Notification.requestPermission')._title = 'requestPermission';
this._resolveEventListenerBreakpoint('instrumentation:DOMWindow.close')._title = 'window.close';
this._resolveEventListenerBreakpoint('instrumentation:Document.write')._title = 'document.write';
this._resolveEventListenerBreakpoint('instrumentation:audioContextCreated')._title =
Common.UIString('Create AudioContext');
this._resolveEventListenerBreakpoint('instrumentation:audioContextClosed')._title =
Common.UIString('Close AudioContext');
this._resolveEventListenerBreakpoint('instrumentation:audioContextResumed')._title =
Common.UIString('Resume AudioContext');
this._resolveEventListenerBreakpoint('instrumentation:audioContextSuspended')._title =
Common.UIString('Suspend AudioContext');
SDK.targetManager.observeModels(SDK.DOMDebuggerModel, this);
}
/**
* @param {string} category
* @param {!Array<string>} instrumentationNames
*/
_createInstrumentationBreakpoints(category, instrumentationNames) {
for (const instrumentationName of instrumentationNames) {
this._eventListenerBreakpoints.push(
new EventListenerBreakpoint(instrumentationName, '', [], category, instrumentationName));
}
}
/**
* @param {string} category
* @param {!Array<string>} eventNames
* @param {!Array<string>} eventTargetNames
*/
_createEventListenerBreakpoints(category, eventNames, eventTargetNames) {
for (const eventName of eventNames) {
this._eventListenerBreakpoints.push(
new EventListenerBreakpoint('', eventName, eventTargetNames, category, eventName));
}
}
/**
* @param {string} eventName
* @param {string=} eventTargetName
* @return {?EventListenerBreakpoint}
*/
_resolveEventListenerBreakpoint(eventName, eventTargetName) {
const instrumentationPrefix = 'instrumentation:';
const listenerPrefix = 'listener:';
let instrumentationName = '';
if (eventName.startsWith(instrumentationPrefix)) {
instrumentationName = eventName.substring(instrumentationPrefix.length);
eventName = '';
} else if (eventName.startsWith(listenerPrefix)) {
eventName = eventName.substring(listenerPrefix.length);
} else {
return null;
}
eventTargetName = (eventTargetName || '*').toLowerCase();
let result = null;
for (const breakpoint of this._eventListenerBreakpoints) {
if (instrumentationName && breakpoint._instrumentationName === instrumentationName) {
result = breakpoint;
}
if (eventName && breakpoint._eventName === eventName &&
breakpoint._eventTargetNames.indexOf(eventTargetName) !== -1) {
result = breakpoint;
}
if (!result && eventName && breakpoint._eventName === eventName &&
breakpoint._eventTargetNames.indexOf('*') !== -1) {
result = breakpoint;
}
}
return result;
}
/**
* @return {!Array<!EventListenerBreakpoint>}
*/
eventListenerBreakpoints() {
return this._eventListenerBreakpoints.slice();
}
/**
* @param {!Object} auxData
* @return {string}
*/
resolveEventListenerBreakpointTitle(auxData) {
const id = auxData['eventName'];
if (id === 'instrumentation:webglErrorFired' && auxData['webglErrorName']) {
let errorName = auxData['webglErrorName'];
// If there is a hex code of the error, display only this.
errorName = errorName.replace(/^.*(0x[0-9a-f]+).*$/i, '$1');
return Common.UIString('WebGL Error Fired (%s)', errorName);
}
if (id === 'instrumentation:scriptBlockedByCSP' && auxData['directiveText']) {
return Common.UIString('Script blocked due to Content Security Policy directive: %s', auxData['directiveText']);
}
const breakpoint = this._resolveEventListenerBreakpoint(id, auxData['targetName']);
if (!breakpoint) {
return '';
}
if (auxData['targetName']) {
return auxData['targetName'] + '.' + breakpoint._title;
}
return breakpoint._title;
}
/**
* @param {!Object} auxData
* @return {?EventListenerBreakpoint}
*/
resolveEventListenerBreakpoint(auxData) {
return this._resolveEventListenerBreakpoint(auxData['eventName'], auxData['targetName']);
}
/**
* @return {!Map<string, boolean>}
*/
xhrBreakpoints() {
return this._xhrBreakpoints;
}
_saveXHRBreakpoints() {
const breakpoints = [];
for (const url of this._xhrBreakpoints.keys()) {
breakpoints.push({url: url, enabled: this._xhrBreakpoints.get(url)});
}
this._xhrBreakpointsSetting.set(breakpoints);
}
/**
* @param {string} url
* @param {boolean} enabled
*/
addXHRBreakpoint(url, enabled) {
this._xhrBreakpoints.set(url, enabled);
if (enabled) {
for (const model of SDK.targetManager.models(DOMDebuggerModel)) {
model._agent.setXHRBreakpoint(url);
}
}
this._saveXHRBreakpoints();
}
/**
* @param {string} url
*/
removeXHRBreakpoint(url) {
const enabled = this._xhrBreakpoints.get(url);
this._xhrBreakpoints.delete(url);
if (enabled) {
for (const model of SDK.targetManager.models(DOMDebuggerModel)) {
model._agent.removeXHRBreakpoint(url);
}
}
this._saveXHRBreakpoints();
}
/**
* @param {string} url
* @param {boolean} enabled
*/
toggleXHRBreakpoint(url, enabled) {
this._xhrBreakpoints.set(url, enabled);
for (const model of SDK.targetManager.models(DOMDebuggerModel)) {
if (enabled) {
model._agent.setXHRBreakpoint(url);
} else {
model._agent.removeXHRBreakpoint(url);
}
}
this._saveXHRBreakpoints();
}
/**
* @override
* @param {!DOMDebuggerModel} domDebuggerModel
*/
modelAdded(domDebuggerModel) {
for (const url of this._xhrBreakpoints.keys()) {
if (this._xhrBreakpoints.get(url)) {
domDebuggerModel._agent.setXHRBreakpoint(url);
}
}
for (const breakpoint of this._eventListenerBreakpoints) {
if (breakpoint._enabled) {
breakpoint._updateOnModel(domDebuggerModel);
}
}
}
/**
* @override
* @param {!DOMDebuggerModel} domDebuggerModel
*/
modelRemoved(domDebuggerModel) {
}
}
/* Legacy exported object */
self.SDK = self.SDK || {};
/* Legacy exported object */
SDK = SDK || {};
/** @constructor */
SDK.DOMDebuggerModel = DOMDebuggerModel;
/** @enum {symbol} */
SDK.DOMDebuggerModel.Events = Events;
/** @constructor */
SDK.DOMDebuggerModel.DOMBreakpoint = DOMBreakpoint;
/** @constructor */
SDK.DOMDebuggerModel.EventListenerBreakpoint = EventListenerBreakpoint;
/** @constructor */
SDK.EventListener = EventListener;
/** @constructor */
SDK.DOMDebuggerManager = DOMDebuggerManager;
SDK.SDKModel.register(SDK.DOMDebuggerModel, SDK.Target.Capability.DOM, false);
/** @typedef {Protocol.DOMDebugger.DOMBreakpointType} */
SDK.DOMDebuggerModel.DOMBreakpoint.Type = Protocol.DOMDebugger.DOMBreakpointType;
/** @type {!SDK.DOMDebuggerManager} */
SDK.domDebuggerManager;