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 windowGlobalTargetSpec,
8 } = require("resource://devtools/shared/specs/targets/window-global.js");
12 } = require("resource://devtools/shared/protocol.js");
15 } = require("resource://devtools/client/fronts/targets/target-mixin.js");
17 class WindowGlobalTargetFront extends TargetMixin(
18 FrontClassWithSpec(windowGlobalTargetSpec)
20 constructor(client, targetFront, parentFront) {
21 super(client, targetFront, parentFront);
23 // For targets which support the Watcher and configuration actor, the status
24 // for the `javascriptEnabled` setting will be available on the configuration
25 // front, and the target will only be used to read the initial value from older
27 // Note: this property is marked as private but is accessed by the
28 // TargetCommand to provide the "isJavascriptEnabled" wrapper. It should NOT be
29 // used anywhere else.
30 this._javascriptEnabled = null;
32 // If this target was retrieved via NodeFront connectToFrame, keep a
33 // reference to the parent NodeFront.
34 this._parentNodeFront = null;
36 this._onTabNavigated = this._onTabNavigated.bind(this);
37 this._onFrameUpdate = this._onFrameUpdate.bind(this);
39 this.on("tabNavigated", this._onTabNavigated);
40 this.on("frameUpdate", this._onFrameUpdate);
44 this.actorID = json.actor;
45 this.browsingContextID = json.browsingContextID;
46 this.innerWindowId = json.innerWindowId;
47 this.processID = json.processID;
49 // Save the full form for Target class usage.
50 // Do not use `form` name to avoid colliding with protocol.js's `form` method
51 this.targetForm = json;
53 this.outerWindowID = json.outerWindowID;
54 this.favicon = json.favicon;
56 // Initial value for the page title and url. Since the WindowGlobalTargetActor can
57 // be created very early, those might not represent the actual value we'd want to
58 // display for the user (e.g. the <title> might not have been parsed yet, and the
59 // url could still be about:blank, which is what the platform uses at the very start
60 // of a navigation to a new location).
61 // Those values are set again from the targetCommand when receiving DOCUMENT_EVENT
62 // resource, at which point both values should be in their expected form.
63 this.setTitle(json.title);
64 this.setUrl(json.url);
68 * Event listener for `frameUpdate` event.
70 _onFrameUpdate(packet) {
71 this.emit("frame-update", packet);
75 * Event listener for `tabNavigated` event.
77 _onTabNavigated(packet) {
78 const event = Object.create(null);
79 event.url = packet.url;
80 event.title = packet.title;
81 event.isFrameSwitching = packet.isFrameSwitching;
83 // Keep the title unmodified when a developer toolbox switches frame
84 // for a tab (Bug 1261687), but always update the title when the target
85 // is a WebExtension (where the addon name is always included in the title
86 // and the url is supposed to be updated every time the selected frame changes).
87 if (!packet.isFrameSwitching || this.isWebExtension) {
88 this.setTitle(packet.title);
89 this.setUrl(packet.url);
92 // Send any stored event payload (DOMWindow or nsIRequest) for backwards
93 // compatibility with non-remotable tools.
94 if (packet.state == "start") {
95 this.emit("will-navigate", event);
97 this.emit("navigate", event);
101 getParentNodeFront() {
102 return this._parentNodeFront;
105 setParentNodeFront(nodeFront) {
106 this._parentNodeFront = nodeFront;
110 * Set the targetFront url.
112 * @param {string} url
119 * Set the targetFront title.
121 * @param {string} title
128 // When calling this.destroy() at the end of this method,
129 // we will end up calling detach again from TargetMixin.destroy.
130 // Avoid invalid loops and do not try to resolve only once the previous call to detach
131 // is done as it would do async infinite loop that never resolves.
132 if (this._isDetaching) {
135 this._isDetaching = true;
137 // Remove listeners set in constructor
138 this.off("tabNavigated", this._onTabNavigated);
139 this.off("frameUpdate", this._onFrameUpdate);
142 await super.detach();
144 this.logDetachError(e, "browsing context");
147 // Detach will destroy the target actor, but the server won't emit any
148 // target-destroyed-form in such manual, client side destruction.
149 // So that we have to manually destroy the associated front on the client
151 // If detach was called by TargetFrontMixin.destroy, avoid recalling it from it
152 // as it would do an async infinite loop which would never resolve.
153 if (!this.isDestroyedOrBeingDestroyed()) {
159 const promise = super.destroy();
160 this._parentNodeFront = null;
162 // As detach isn't necessarily called on target's destroy
163 // (it isn't for local tabs), ensure removing listeners set in constructor.
164 this.off("tabNavigated", this._onTabNavigated);
165 this.off("frameUpdate", this._onFrameUpdate);
171 exports.WindowGlobalTargetFront = WindowGlobalTargetFront;
172 registerFront(exports.WindowGlobalTargetFront);