Bug 1913305 - Add test. r=mtigley
[gecko.git] / devtools / server / actors / changes.js
blob16e24cb2e72c7edb791b94e7fbd040802181bf80
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/. */
5 "use strict";
7 const { Actor } = require("resource://devtools/shared/protocol.js");
8 const { changesSpec } = require("resource://devtools/shared/specs/changes.js");
10 const TrackChangeEmitter = require("resource://devtools/server/actors/utils/track-change-emitter.js");
12 /**
13  * The ChangesActor stores a stack of changes made by devtools on
14  * the document in the associated tab.
15  */
16 class ChangesActor extends Actor {
17   /**
18    * Create a ChangesActor.
19    *
20    * @param {DevToolsServerConnection} conn
21    *    The server connection.
22    * @param {TargetActor} targetActor
23    *    The top-level Actor for this tab.
24    */
25   constructor(conn, targetActor) {
26     super(conn, changesSpec);
27     this.targetActor = targetActor;
29     this.onTrackChange = this.pushChange.bind(this);
30     this.onWillNavigate = this.onWillNavigate.bind(this);
32     TrackChangeEmitter.on("track-change", this.onTrackChange);
33     this.targetActor.on("will-navigate", this.onWillNavigate);
35     this.changes = [];
36   }
38   destroy() {
39     // Stop trying to emit RDP event on destruction.
40     this._changesHaveBeenRequested = false;
41     this.clearChanges();
42     this.targetActor.off("will-navigate", this.onWillNavigate);
43     TrackChangeEmitter.off("track-change", this.onTrackChange);
44     super.destroy();
45   }
47   start() {
48     /**
49      * This function currently does nothing and returns nothing. It exists only
50      * so that the client can trigger the creation of the ChangesActor through
51      * the front, without triggering side effects, and with a sensible semantic
52      * meaning.
53      */
54   }
56   changeCount() {
57     return this.changes.length;
58   }
60   change(index) {
61     if (index >= 0 && index < this.changes.length) {
62       // Return a copy of the change at index.
63       return Object.assign({}, this.changes[index]);
64     }
65     // No change at that index -- return undefined.
66     return undefined;
67   }
69   allChanges() {
70     /**
71      * This function is called by all change event consumers on the client
72      * to get their initial state synchronized with the ChangesActor. We
73      * set a flag when this function is called so we know that it's worthwhile
74      * to send events.
75      */
76     this._changesHaveBeenRequested = true;
77     return this.changes.slice();
78   }
80   /**
81    * Handler for "will-navigate" event from the browsing context. The event is fired for
82    * the host page and any nested resources, like iframes. The list of changes should be
83    * cleared only when the host page navigates, ignoring any of its iframes.
84    *
85    * TODO: Clear changes made within sources in iframes when they navigate. Bug 1513940
86    *
87    * @param {Object} eventData
88    *        Event data with these properties:
89    *        {
90    *          window: Object      // Window DOM object of the event source page
91    *          isTopLevel: Boolean // true if the host page will navigate
92    *          newURI: String      // URI towards which the page will navigate
93    *          request: Object     // Request data.
94    *        }
95    */
96   onWillNavigate(eventData) {
97     if (eventData.isTopLevel) {
98       this.clearChanges();
99     }
100   }
102   pushChange(change) {
103     this.changes.push(change);
104     if (this._changesHaveBeenRequested) {
105       this.emit("add-change", change);
106     }
107   }
109   popChange() {
110     const change = this.changes.pop();
111     if (this._changesHaveBeenRequested) {
112       this.emit("remove-change", change);
113     }
114     return change;
115   }
117   clearChanges() {
118     this.changes.length = 0;
119     if (this._changesHaveBeenRequested) {
120       this.emit("clear-changes");
121     }
122   }
125 exports.ChangesActor = ChangesActor;