document-event.js (3885B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 DocumentEventsListener, 9 } = require("resource://devtools/server/actors/webconsole/listeners/document-events.js"); 10 11 class DocumentEventWatcher { 12 #abortController = new AbortController(); 13 /** 14 * Start watching for all document event related to a given Target Actor. 15 * 16 * @param TargetActor targetActor 17 * The target actor from which we should observe document event 18 * @param Object options 19 * Dictionary object with following attributes: 20 * - onAvailable: mandatory function 21 * This will be called for each resource. 22 */ 23 async watch(targetActor, { onAvailable }) { 24 if (isWorker) { 25 return; 26 } 27 // Bug 1975277: ignore iframes which are destroying. 28 // The inner-window-destroyed event isn't yet fired and the actor is still 29 // registered, but it no longer has a valid window reference. 30 if (!targetActor.window) { 31 return; 32 } 33 34 const onDocumentEvent = ( 35 name, 36 { 37 time, 38 // This will be `true` when the user selected a document in the frame picker tool, 39 // in the toolbox toolbar. 40 isFrameSwitching, 41 // This is only passed for dom-complete event 42 hasNativeConsoleAPI, 43 // This is only passed for will-navigate event 44 newURI, 45 } = {} 46 ) => { 47 // Ignore will-navigate as that's managed by parent-process-document-event.js. 48 // Except frame switching, when selecting an iframe document via the dropdown menu, 49 // this is handled by the target actor in the content process and the parent process 50 // doesn't know about it. 51 if (name == "will-navigate" && !isFrameSwitching) { 52 return; 53 } 54 onAvailable([ 55 { 56 name, 57 time, 58 isFrameSwitching, 59 // only send `title` on dom interactive (once the HTML was parsed) so we don't 60 // make the payload bigger for events where we either don't have a title yet, 61 // or where we already had a chance to get the title. 62 title: name === "dom-interactive" ? targetActor.title : undefined, 63 // only send `url` on dom loading and dom-interactive so we don't make the 64 // payload bigger for other events 65 url: 66 name === "dom-loading" || name === "dom-interactive" 67 ? targetActor.url 68 : undefined, 69 // only send `newURI` on will navigate so we don't make the payload bigger for 70 // other events 71 newURI: name === "will-navigate" ? newURI : null, 72 // only send `hasNativeConsoleAPI` on dom complete so we don't make the payload bigger for 73 // other events 74 hasNativeConsoleAPI: 75 name == "dom-complete" ? hasNativeConsoleAPI : null, 76 }, 77 ]); 78 }; 79 80 this.listener = new DocumentEventsListener(targetActor); 81 82 this.listener.on( 83 "will-navigate", 84 data => onDocumentEvent("will-navigate", data), 85 { signal: this.#abortController.signal } 86 ); 87 this.listener.on( 88 "dom-loading", 89 data => onDocumentEvent("dom-loading", data), 90 { signal: this.#abortController.signal } 91 ); 92 this.listener.on( 93 "dom-interactive", 94 data => onDocumentEvent("dom-interactive", data), 95 { signal: this.#abortController.signal } 96 ); 97 this.listener.on( 98 "dom-complete", 99 data => onDocumentEvent("dom-complete", data), 100 { signal: this.#abortController.signal } 101 ); 102 103 this.listener.listen(); 104 } 105 106 destroy() { 107 this.#abortController.abort(); 108 if (this.listener) { 109 this.listener.destroy(); 110 } 111 } 112 } 113 114 module.exports = DocumentEventWatcher;