Web Inspector: Uncaught Exception: null is not an object (evaluating 'this.ownerDocum...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Controllers / DOMDebuggerManager.js
1 /*
2  * Copyright (C) 2017 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object
27 {
28     constructor()
29     {
30         super();
31
32         this._domBreakpointURLMap = new Multimap;
33         this._domBreakpointFrameIdentifierMap = new Map;
34
35         this._eventBreakpoints = [];
36
37         this._urlBreakpoints = [];
38         this._allRequestsBreakpointEnabledSetting = new WI.Setting("break-on-all-requests", false);
39
40         this._allRequestsBreakpoint = new WI.URLBreakpoint(WI.URLBreakpoint.Type.Text, "", {
41             disabled: !this._allRequestsBreakpointEnabledSetting.value,
42         });
43
44         WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DisabledStateChanged, this._handleDOMBreakpointDisabledStateChanged, this);
45         WI.EventBreakpoint.addEventListener(WI.EventBreakpoint.Event.DisabledStateChanged, this._handleEventBreakpointDisabledStateChanged, this);
46         WI.URLBreakpoint.addEventListener(WI.URLBreakpoint.Event.DisabledStateChanged, this._handleURLBreakpointDisabledStateChanged, this);
47
48         WI.domManager.addEventListener(WI.DOMManager.Event.NodeRemoved, this._nodeRemoved, this);
49         WI.domManager.addEventListener(WI.DOMManager.Event.NodeInserted, this._nodeInserted, this);
50
51         WI.networkManager.addEventListener(WI.NetworkManager.Event.MainFrameDidChange, this._mainFrameDidChange, this);
52
53         WI.Frame.addEventListener(WI.Frame.Event.ChildFrameWasRemoved, this._childFrameWasRemoved, this);
54         WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
55
56         let loadBreakpoints = async (constructor, objectStore, oldSettings, callback) => {
57             for (let key of oldSettings) {
58                 let existingSerializedBreakpoints = WI.Setting.migrateValue(key);
59                 if (existingSerializedBreakpoints) {
60                     for (let existingSerializedBreakpoint of existingSerializedBreakpoints)
61                         await objectStore.putObject(constructor.deserialize(existingSerializedBreakpoint));
62                 }
63             }
64
65             let serializedBreakpoints = await objectStore.getAll();
66
67             this._restoringBreakpoints = true;
68             for (let serializedBreakpoint of serializedBreakpoints) {
69                 let breakpoint = constructor.deserialize(serializedBreakpoint);
70
71                 const key = null;
72                 objectStore.associateObject(breakpoint, key, serializedBreakpoint);
73
74                 callback(breakpoint);
75             }
76             this._restoringBreakpoints = false;
77         };
78
79         if (this.supported) {
80             loadBreakpoints(WI.DOMBreakpoint, WI.objectStores.domBreakpoints, ["dom-breakpoints"], (breakpoint) => {
81                 this.addDOMBreakpoint(breakpoint);
82             });
83
84             loadBreakpoints(WI.EventBreakpoint, WI.objectStores.eventBreakpoints, ["event-breakpoints"], (breakpoint) => {
85                 this.addEventBreakpoint(breakpoint);
86             });
87
88             loadBreakpoints(WI.URLBreakpoint, WI.objectStores.urlBreakpoints, ["xhr-breakpoints", "url-breakpoints"], (breakpoint) => {
89                 this.addURLBreakpoint(breakpoint);
90             });
91         }
92     }
93
94     // Target
95
96     initializeTarget(target)
97     {
98         if (target.DOMDebuggerAgent) {
99             if (target === WI.assumingMainTarget() && target.mainResource)
100                 this._speculativelyResolveDOMBreakpointsForURL(target.mainResource.url);
101
102             for (let breakpoint of this._eventBreakpoints) {
103                 if (!breakpoint.disabled)
104                     this._updateEventBreakpoint(breakpoint, target);
105             }
106
107             for (let breakpoint of this._urlBreakpoints) {
108                 if (!breakpoint.disabled)
109                     this._updateURLBreakpoint(breakpoint, target);
110             }
111
112             if (!this._allRequestsBreakpoint.disabled)
113                 this._updateURLBreakpoint(this._allRequestsBreakpoint, target);
114         }
115     }
116
117     // Static
118
119     static supportsEventBreakpoints()
120     {
121         return InspectorBackend.domains.DOMDebugger.setEventBreakpoint && InspectorBackend.domains.DOMDebugger.removeEventBreakpoint;
122     }
123
124     static supportsURLBreakpoints()
125     {
126         return InspectorBackend.domains.DOMDebugger.setURLBreakpoint && InspectorBackend.domains.DOMDebugger.removeURLBreakpoint;
127     }
128
129     // Public
130
131     get supported()
132     {
133         return !!InspectorBackend.domains.DOMDebugger;
134     }
135
136     get allRequestsBreakpoint() { return this._allRequestsBreakpoint; }
137
138     get domBreakpoints()
139     {
140         let mainFrame = WI.networkManager.mainFrame;
141         if (!mainFrame)
142             return [];
143
144         let resolvedBreakpoints = [];
145         let frames = [mainFrame];
146         while (frames.length) {
147             let frame = frames.shift();
148             let domBreakpointNodeIdentifierMap = this._domBreakpointFrameIdentifierMap.get(frame.id);
149             if (domBreakpointNodeIdentifierMap) {
150                 for (let breakpoints of domBreakpointNodeIdentifierMap.values())
151                     resolvedBreakpoints = resolvedBreakpoints.concat(breakpoints);
152             }
153
154             frames.push(...frame.childFrameCollection);
155         }
156
157         return resolvedBreakpoints;
158     }
159
160     get eventBreakpoints() { return this._eventBreakpoints; }
161
162     get urlBreakpoints() { return this._urlBreakpoints; }
163
164     isBreakpointSpecial(breakpoint)
165     {
166         return breakpoint === this._allRequestsBreakpoint;
167     }
168
169     domBreakpointsForNode(node)
170     {
171         console.assert(node instanceof WI.DOMNode);
172
173         if (!node || !node.frame)
174             return [];
175
176         let domBreakpointNodeIdentifierMap = this._domBreakpointFrameIdentifierMap.get(node.frame.id);
177         if (!domBreakpointNodeIdentifierMap)
178             return [];
179
180         let breakpoints = domBreakpointNodeIdentifierMap.get(node.id);
181         return breakpoints ? breakpoints.slice() : [];
182     }
183
184     addDOMBreakpoint(breakpoint)
185     {
186         console.assert(breakpoint instanceof WI.DOMBreakpoint);
187         if (!breakpoint || !breakpoint.url)
188             return;
189
190         if (this.isBreakpointSpecial(breakpoint)) {
191             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointAdded, {breakpoint});
192             return;
193         }
194
195         this._domBreakpointURLMap.add(breakpoint.url, breakpoint);
196
197         if (breakpoint.domNodeIdentifier)
198             this._resolveDOMBreakpoint(breakpoint, breakpoint.domNodeIdentifier);
199
200         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointAdded, {breakpoint});
201
202         if (!this._restoringBreakpoints)
203             WI.objectStores.domBreakpoints.putObject(breakpoint);
204     }
205
206     removeDOMBreakpoint(breakpoint)
207     {
208         console.assert(breakpoint instanceof WI.DOMBreakpoint);
209         if (!breakpoint)
210             return;
211
212         if (this.isBreakpointSpecial(breakpoint)) {
213             breakpoint.disabled = true;
214             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointRemoved, {breakpoint});
215             return;
216         }
217
218         let nodeIdentifier = breakpoint.domNodeIdentifier;
219         console.assert(nodeIdentifier, "Cannot remove unresolved DOM breakpoint.");
220         if (!nodeIdentifier)
221             return;
222
223         this._detachDOMBreakpoint(breakpoint);
224
225         this._domBreakpointURLMap.delete(breakpoint.url);
226
227         if (!breakpoint.disabled) {
228             // We should get the target associated with the nodeIdentifier of this breakpoint.
229             let target = WI.assumingMainTarget();
230             target.DOMDebuggerAgent.removeDOMBreakpoint(nodeIdentifier, breakpoint.type);
231         }
232
233         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointRemoved, {breakpoint});
234
235         breakpoint.domNodeIdentifier = null;
236
237         if (!this._restoringBreakpoints)
238             WI.objectStores.domBreakpoints.deleteObject(breakpoint);
239     }
240
241     removeDOMBreakpointsForNode(node)
242     {
243         this.domBreakpointsForNode(node).forEach(this.removeDOMBreakpoint, this);
244     }
245
246     eventBreakpointForTypeAndEventName(type, eventName)
247     {
248         return this._eventBreakpoints.find((breakpoint) => breakpoint.type === type && breakpoint.eventName === eventName) || null;
249     }
250
251     addEventBreakpoint(breakpoint)
252     {
253         console.assert(breakpoint instanceof WI.EventBreakpoint);
254         if (!breakpoint)
255             return;
256
257         if (this.isBreakpointSpecial(breakpoint)) {
258             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
259             return;
260         }
261
262         if (this.eventBreakpointForTypeAndEventName(breakpoint.type, breakpoint.eventName))
263             return;
264
265         this._eventBreakpoints.push(breakpoint);
266
267         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
268
269         if (!breakpoint.disabled) {
270             for (let target of WI.targets) {
271                 if (target.DOMDebuggerAgent)
272                     this._updateEventBreakpoint(breakpoint, target);
273             }
274         }
275
276         if (!this._restoringBreakpoints)
277             WI.objectStores.eventBreakpoints.putObject(breakpoint);
278     }
279
280     removeEventBreakpoint(breakpoint)
281     {
282         console.assert(breakpoint instanceof WI.EventBreakpoint);
283         if (!breakpoint)
284             return;
285
286         if (this.isBreakpointSpecial(breakpoint)) {
287             breakpoint.disabled = true;
288             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint});
289             return;
290         }
291
292         if (!this._eventBreakpoints.includes(breakpoint))
293             return;
294
295         this._eventBreakpoints.remove(breakpoint);
296
297         if (!this._restoringBreakpoints)
298             WI.objectStores.eventBreakpoints.deleteObject(breakpoint);
299
300         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint});
301
302         if (breakpoint.disabled)
303             return;
304
305         for (let target of WI.targets) {
306             if (target.DOMDebuggerAgent) {
307                 // Compatibility (iOS 12): DOMDebuggerAgent.removeEventBreakpoint did not exist.
308                 if (!WI.DOMDebuggerManager.supportsEventBreakpoints()) {
309                     console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
310                     target.DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
311                     continue;
312                 }
313
314                 target.DOMDebuggerAgent.removeEventBreakpoint(breakpoint.type, breakpoint.eventName);
315             }
316         }
317     }
318
319     urlBreakpointForURL(url)
320     {
321         return this._urlBreakpoints.find((breakpoint) => breakpoint.url === url) || null;
322     }
323
324     addURLBreakpoint(breakpoint)
325     {
326         console.assert(breakpoint instanceof WI.URLBreakpoint);
327         if (!breakpoint)
328             return;
329
330         if (this.isBreakpointSpecial(breakpoint)) {
331             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.URLBreakpointAdded, {breakpoint});
332             return;
333         }
334
335         console.assert(!this._urlBreakpoints.includes(breakpoint), "Already added URL breakpoint.", breakpoint);
336         if (this._urlBreakpoints.includes(breakpoint))
337             return;
338
339         if (this._urlBreakpoints.some((entry) => entry.type === breakpoint.type && entry.url === breakpoint.url))
340             return;
341
342         this._urlBreakpoints.push(breakpoint);
343
344         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.URLBreakpointAdded, {breakpoint});
345
346         if (!breakpoint.disabled) {
347             for (let target of WI.targets) {
348                 if (target.DOMDebuggerAgent)
349                     this._updateURLBreakpoint(breakpoint, target);
350             }
351         }
352
353         if (!this._restoringBreakpoints)
354             WI.objectStores.urlBreakpoints.putObject(breakpoint);
355     }
356
357     removeURLBreakpoint(breakpoint)
358     {
359         console.assert(breakpoint instanceof WI.URLBreakpoint);
360         if (!breakpoint)
361             return;
362
363         if (this.isBreakpointSpecial(breakpoint)) {
364             breakpoint.disabled = true;
365             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.URLBreakpointRemoved, {breakpoint});
366             return;
367         }
368
369         if (!this._urlBreakpoints.includes(breakpoint))
370             return;
371
372         this._urlBreakpoints.remove(breakpoint, true);
373
374         if (!this._restoringBreakpoints)
375             WI.objectStores.urlBreakpoints.deleteObject(breakpoint);
376
377         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.URLBreakpointRemoved, {breakpoint});
378
379         if (breakpoint.disabled)
380             return;
381
382         for (let target of WI.targets) {
383             if (target.DOMDebuggerAgent) {
384                 // Compatibility (iOS 12.1): DOMDebuggerAgent.removeURLBreakpoint did not exist.
385                 if (WI.DOMDebuggerManager.supportsURLBreakpoints())
386                     target.DOMDebuggerAgent.removeURLBreakpoint(breakpoint.url);
387                 else
388                     target.DOMDebuggerAgent.removeXHRBreakpoint(breakpoint.url);
389             }
390         }
391     }
392
393     // Private
394
395     _detachDOMBreakpoint(breakpoint)
396     {
397         let nodeIdentifier = breakpoint.domNodeIdentifier;
398         let node = WI.domManager.nodeForId(nodeIdentifier);
399         console.assert(node, "Missing DOM node for breakpoint.", breakpoint);
400         if (!node || !node.frame)
401             return;
402
403         let frameIdentifier = node.frame.id;
404         let domBreakpointNodeIdentifierMap = this._domBreakpointFrameIdentifierMap.get(frameIdentifier);
405         console.assert(domBreakpointNodeIdentifierMap, "Missing DOM breakpoints for node parent frame.", node);
406         if (!domBreakpointNodeIdentifierMap)
407             return;
408
409         let breakpoints = domBreakpointNodeIdentifierMap.get(nodeIdentifier);
410         console.assert(breakpoints, "Missing DOM breakpoints for node.", node);
411         if (!breakpoints)
412             return;
413
414         breakpoints.remove(breakpoint, true);
415
416         if (breakpoints.length)
417             return;
418
419         domBreakpointNodeIdentifierMap.delete(nodeIdentifier);
420
421         if (!domBreakpointNodeIdentifierMap.size)
422             this._domBreakpointFrameIdentifierMap.delete(frameIdentifier);
423     }
424
425     _detachBreakpointsForFrame(frame)
426     {
427         let domBreakpointNodeIdentifierMap = this._domBreakpointFrameIdentifierMap.get(frame.id);
428         if (!domBreakpointNodeIdentifierMap)
429             return;
430
431         this._domBreakpointFrameIdentifierMap.delete(frame.id);
432
433         for (let breakpoints of domBreakpointNodeIdentifierMap.values()) {
434             for (let breakpoint of breakpoints)
435                 breakpoint.domNodeIdentifier = null;
436         }
437     }
438
439     _speculativelyResolveDOMBreakpointsForURL(url)
440     {
441         let domBreakpoints = this._domBreakpointURLMap.get(url);
442         if (!domBreakpoints)
443             return;
444
445         for (let breakpoint of domBreakpoints) {
446             if (breakpoint.domNodeIdentifier)
447                 continue;
448
449             WI.domManager.pushNodeByPathToFrontend(breakpoint.path, (nodeIdentifier) => {
450                 if (nodeIdentifier)
451                     this._resolveDOMBreakpoint(breakpoint, nodeIdentifier);
452             });
453         }
454     }
455
456     _resolveDOMBreakpoint(breakpoint, nodeIdentifier)
457     {
458         let node = WI.domManager.nodeForId(nodeIdentifier);
459         console.assert(node, "Missing DOM node for nodeIdentifier.", nodeIdentifier);
460         if (!node || !node.frame)
461             return;
462
463         let frameIdentifier = node.frame.id;
464         let domBreakpointNodeIdentifierMap = this._domBreakpointFrameIdentifierMap.get(frameIdentifier);
465         if (!domBreakpointNodeIdentifierMap) {
466             domBreakpointNodeIdentifierMap = new Map;
467             this._domBreakpointFrameIdentifierMap.set(frameIdentifier, domBreakpointNodeIdentifierMap);
468         }
469
470         let breakpoints = domBreakpointNodeIdentifierMap.get(nodeIdentifier);
471         if (breakpoints)
472             breakpoints.push(breakpoint);
473         else
474             domBreakpointNodeIdentifierMap.set(nodeIdentifier, [breakpoint]);
475
476         breakpoint.domNodeIdentifier = nodeIdentifier;
477
478         if (!breakpoint.disabled) {
479             // We should get the target associated with the nodeIdentifier of this breakpoint.
480             let target = WI.assumingMainTarget();
481             if (target && target.DOMDebuggerAgent)
482                 this._updateDOMBreakpoint(breakpoint, target);
483         }
484     }
485
486     _updateDOMBreakpoint(breakpoint, target)
487     {
488         console.assert(target.DOMDebuggerAgent);
489
490         if (!breakpoint.domNodeIdentifier)
491             return;
492
493         if (breakpoint.disabled)
494             target.DOMDebuggerAgent.removeDOMBreakpoint(breakpoint.domNodeIdentifier, breakpoint.type);
495         else
496             target.DOMDebuggerAgent.setDOMBreakpoint(breakpoint.domNodeIdentifier, breakpoint.type);
497     }
498
499     _updateEventBreakpoint(breakpoint, target)
500     {
501         console.assert(target.DOMDebuggerAgent);
502
503         // Compatibility (iOS 12): DOMDebuggerAgent.removeEventBreakpoint did not exist.
504         if (!WI.DOMDebuggerManager.supportsEventBreakpoints()) {
505             console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
506             if (breakpoint.disabled)
507                 target.DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
508             else
509                 target.DOMDebuggerAgent.setEventListenerBreakpoint(breakpoint.eventName);
510             return;
511         }
512
513         if (breakpoint.disabled)
514             target.DOMDebuggerAgent.removeEventBreakpoint(breakpoint.type, breakpoint.eventName);
515         else
516             target.DOMDebuggerAgent.setEventBreakpoint(breakpoint.type, breakpoint.eventName);
517     }
518
519     _updateURLBreakpoint(breakpoint, target)
520     {
521         console.assert(target.DOMDebuggerAgent);
522
523         // Compatibility (iOS 12.1): DOMDebuggerAgent.removeURLBreakpoint did not exist.
524         if (!WI.DOMDebuggerManager.supportsURLBreakpoints()) {
525             if (breakpoint.disabled)
526                 target.DOMDebuggerAgent.removeXHRBreakpoint(breakpoint.url);
527             else {
528                 let isRegex = breakpoint.type === WI.URLBreakpoint.Type.RegularExpression;
529                 target.DOMDebuggerAgent.setXHRBreakpoint(breakpoint.url, isRegex);
530             }
531             return;
532         }
533
534         if (breakpoint.disabled)
535             target.DOMDebuggerAgent.removeURLBreakpoint(breakpoint.url);
536         else {
537             let isRegex = breakpoint.type === WI.URLBreakpoint.Type.RegularExpression;
538             target.DOMDebuggerAgent.setURLBreakpoint(breakpoint.url, isRegex);
539         }
540     }
541
542     _handleDOMBreakpointDisabledStateChanged(event)
543     {
544         let breakpoint = event.target;
545         let target = WI.assumingMainTarget();
546         if (target && target.DOMDebuggerAgent)
547             this._updateDOMBreakpoint(breakpoint, target);
548
549         if (!this._restoringBreakpoints)
550             WI.objectStores.domBreakpoints.putObject(breakpoint);
551     }
552
553     _handleEventBreakpointDisabledStateChanged(event)
554     {
555         let breakpoint = event.target;
556
557         // Specific event listener breakpoints are handled by `DOMManager`.
558         if (breakpoint.eventListener)
559             return;
560
561         for (let target of WI.targets) {
562             if (target.DOMDebuggerAgent)
563                 this._updateEventBreakpoint(breakpoint, target);
564         }
565
566         if (!this._restoringBreakpoints)
567             WI.objectStores.eventBreakpoints.putObject(breakpoint);
568     }
569
570     _handleURLBreakpointDisabledStateChanged(event)
571     {
572         let breakpoint = event.target;
573
574         if (breakpoint === this._allRequestsBreakpoint)
575             this._allRequestsBreakpointEnabledSetting.value = !breakpoint.disabled;
576
577         for (let target of WI.targets) {
578             if (target.DOMDebuggerAgent)
579                 this._updateURLBreakpoint(breakpoint, target);
580         }
581
582         if (!this._restoringBreakpoints)
583             WI.objectStores.urlBreakpoints.putObject(breakpoint);
584     }
585
586     _childFrameWasRemoved(event)
587     {
588         let frame = event.data.childFrame;
589         this._detachBreakpointsForFrame(frame);
590     }
591
592     _mainFrameDidChange(event)
593     {
594         this._speculativelyResolveDOMBreakpointsForURL(WI.networkManager.mainFrame.url);
595     }
596
597     _mainResourceDidChange(event)
598     {
599         let frame = event.target;
600         if (frame.isMainFrame()) {
601             for (let breakpoint of this._domBreakpointURLMap.values())
602                 breakpoint.domNodeIdentifier = null;
603
604             this._domBreakpointFrameIdentifierMap.clear();
605         } else
606             this._detachBreakpointsForFrame(frame);
607
608         this._speculativelyResolveDOMBreakpointsForURL(frame.url);
609     }
610
611     _nodeInserted(event)
612     {
613         let node = event.data.node;
614         if (node.nodeType() !== Node.ELEMENT_NODE || !node.frame)
615             return;
616
617         let url = node.frame.url;
618         let breakpoints = this._domBreakpointURLMap.get(url);
619         if (!breakpoints)
620             return;
621
622         for (let breakpoint of breakpoints) {
623             if (breakpoint.domNodeIdentifier)
624                 continue;
625
626             if (breakpoint.path !== node.path())
627                 continue;
628
629             this._resolveDOMBreakpoint(breakpoint, node.id);
630         }
631     }
632
633     _nodeRemoved(event)
634     {
635         let node = event.data.node;
636         if (node.nodeType() !== Node.ELEMENT_NODE || !node.frame)
637             return;
638
639         let domBreakpointNodeIdentifierMap = this._domBreakpointFrameIdentifierMap.get(node.frame.id);
640         if (!domBreakpointNodeIdentifierMap)
641             return;
642
643         let breakpoints = domBreakpointNodeIdentifierMap.get(node.id);
644         if (!breakpoints)
645             return;
646
647         domBreakpointNodeIdentifierMap.delete(node.id);
648
649         if (!domBreakpointNodeIdentifierMap.size)
650             this._domBreakpointFrameIdentifierMap.delete(node.frame.id);
651
652         for (let breakpoint of breakpoints)
653             breakpoint.domNodeIdentifier = null;
654     }
655 };
656
657 WI.DOMDebuggerManager.Event = {
658     DOMBreakpointAdded: "dom-debugger-manager-dom-breakpoint-added",
659     DOMBreakpointRemoved: "dom-debugger-manager-dom-breakpoint-removed",
660     EventBreakpointAdded: "dom-debugger-manager-event-breakpoint-added",
661     EventBreakpointRemoved: "dom-debugger-manager-event-breakpoint-removed",
662     URLBreakpointAdded: "dom-debugger-manager-url-breakpoint-added",
663     URLBreakpointRemoved: "dom-debugger-manager-url-breakpoint-removed",
664 };