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/. */
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");
13 * The ChangesActor stores a stack of changes made by devtools on
14 * the document in the associated tab.
16 class ChangesActor extends Actor {
18 * Create a ChangesActor.
20 * @param {DevToolsServerConnection} conn
21 * The server connection.
22 * @param {TargetActor} targetActor
23 * The top-level Actor for this tab.
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);
39 // Stop trying to emit RDP event on destruction.
40 this._changesHaveBeenRequested = false;
42 this.targetActor.off("will-navigate", this.onWillNavigate);
43 TrackChangeEmitter.off("track-change", this.onTrackChange);
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
57 return this.changes.length;
61 if (index >= 0 && index < this.changes.length) {
62 // Return a copy of the change at index.
63 return Object.assign({}, this.changes[index]);
65 // No change at that index -- return undefined.
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
76 this._changesHaveBeenRequested = true;
77 return this.changes.slice();
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.
85 * TODO: Clear changes made within sources in iframes when they navigate. Bug 1513940
87 * @param {Object} eventData
88 * Event data with these properties:
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.
96 onWillNavigate(eventData) {
97 if (eventData.isTopLevel) {
103 this.changes.push(change);
104 if (this._changesHaveBeenRequested) {
105 this.emit("add-change", change);
110 const change = this.changes.pop();
111 if (this._changesHaveBeenRequested) {
112 this.emit("remove-change", change);
118 this.changes.length = 0;
119 if (this._changesHaveBeenRequested) {
120 this.emit("clear-changes");
125 exports.ChangesActor = ChangesActor;