Backed out 3 changesets (bug 1877678, bug 1849175) for causing failures on browser_op...
[gecko.git] / devtools / client / fronts / targets / window-global.js
blob8bf69383e02473aa4d23bba521875f3fe29c3697
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 "use strict";
6 const {
7   windowGlobalTargetSpec,
8 } = require("resource://devtools/shared/specs/targets/window-global.js");
9 const {
10   FrontClassWithSpec,
11   registerFront,
12 } = require("resource://devtools/shared/protocol.js");
13 const {
14   TargetMixin,
15 } = require("resource://devtools/client/fronts/targets/target-mixin.js");
17 class WindowGlobalTargetFront extends TargetMixin(
18   FrontClassWithSpec(windowGlobalTargetSpec)
19 ) {
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
26     // servers.
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);
41   }
43   form(json) {
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);
65   }
67   /**
68    * Event listener for `frameUpdate` event.
69    */
70   _onFrameUpdate(packet) {
71     this.emit("frame-update", packet);
72   }
74   /**
75    * Event listener for `tabNavigated` event.
76    */
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);
90     }
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);
96     } else {
97       this.emit("navigate", event);
98     }
99   }
101   getParentNodeFront() {
102     return this._parentNodeFront;
103   }
105   setParentNodeFront(nodeFront) {
106     this._parentNodeFront = nodeFront;
107   }
109   /**
110    * Set the targetFront url.
111    *
112    * @param {string} url
113    */
114   setUrl(url) {
115     this._url = url;
116   }
118   /**
119    * Set the targetFront title.
120    *
121    * @param {string} title
122    */
123   setTitle(title) {
124     this._title = title;
125   }
127   async detach() {
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) {
133       return;
134     }
135     this._isDetaching = true;
137     // Remove listeners set in constructor
138     this.off("tabNavigated", this._onTabNavigated);
139     this.off("frameUpdate", this._onFrameUpdate);
141     try {
142       await super.detach();
143     } catch (e) {
144       this.logDetachError(e, "browsing context");
145     }
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
150     //
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()) {
154       this.destroy();
155     }
156   }
158   destroy() {
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);
167     return promise;
168   }
171 exports.WindowGlobalTargetFront = WindowGlobalTargetFront;
172 registerFront(exports.WindowGlobalTargetFront);