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