Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 module.metadata = {
7 'stability': 'deprecated'
8 };
10 const { Cc, Ci } = require('chrome');
11 const { EventEmitter } = require('../deprecated/events');
12 const { Trait } = require('../deprecated/traits');
13 const { when } = require('../system/unload');
14 const events = require('../system/events');
15 const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser,
16 getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils');
17 const errors = require('../deprecated/errors');
18 const { deprecateFunction } = require('../util/deprecate');
19 const { ignoreWindow, isGlobalPBSupported } = require('sdk/private-browsing/utils');
20 const { isPrivateBrowsingSupported } = require('../self');
22 const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
23 getService(Ci.nsIWindowWatcher);
24 const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
25 getService(Ci.nsIAppShellService);
27 // Bug 834961: ignore private windows when they are not supported
28 function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported });
30 /**
31 * An iterator for XUL windows currently in the application.
32 *
33 * @return A generator that yields XUL windows exposing the
34 * nsIDOMWindow interface.
35 */
36 function windowIterator() {
37 // Bug 752631: We only pass already loaded window in order to avoid
38 // breaking XUL windows DOM. DOM is broken when some JS code try
39 // to access DOM during "uninitialized" state of the related document.
40 let list = getWindows().filter(isDocumentLoaded);
41 for (let i = 0, l = list.length; i < l; i++) {
42 yield list[i];
43 }
44 };
45 exports.windowIterator = windowIterator;
47 /**
48 * An iterator for browser windows currently open in the application.
49 * @returns {Function}
50 * A generator that yields browser windows exposing the `nsIDOMWindow`
51 * interface.
52 */
53 function browserWindowIterator() {
54 for each (let window in windowIterator()) {
55 if (isBrowser(window))
56 yield window;
57 }
58 }
59 exports.browserWindowIterator = browserWindowIterator;
61 function WindowTracker(delegate) {
62 if (!(this instanceof WindowTracker)) {
63 return new WindowTracker(delegate);
64 }
66 this._delegate = delegate;
67 this._loadingWindows = [];
69 for each (let window in getWindows())
70 this._regWindow(window);
71 windowWatcher.registerNotification(this);
72 this._onToplevelWindowReady = this._onToplevelWindowReady.bind(this);
73 events.on('toplevel-window-ready', this._onToplevelWindowReady);
75 require('../system/unload').ensure(this);
77 return this;
78 };
80 WindowTracker.prototype = {
81 _regLoadingWindow: function _regLoadingWindow(window) {
82 // Bug 834961: ignore private windows when they are not supported
83 if (ignoreWindow(window))
84 return;
86 this._loadingWindows.push(window);
87 window.addEventListener('load', this, true);
88 },
90 _unregLoadingWindow: function _unregLoadingWindow(window) {
91 var index = this._loadingWindows.indexOf(window);
93 if (index != -1) {
94 this._loadingWindows.splice(index, 1);
95 window.removeEventListener('load', this, true);
96 }
97 },
99 _regWindow: function _regWindow(window) {
100 // Bug 834961: ignore private windows when they are not supported
101 if (ignoreWindow(window))
102 return;
104 if (window.document.readyState == 'complete') {
105 this._unregLoadingWindow(window);
106 this._delegate.onTrack(window);
107 } else
108 this._regLoadingWindow(window);
109 },
111 _unregWindow: function _unregWindow(window) {
112 if (window.document.readyState == 'complete') {
113 if (this._delegate.onUntrack)
114 this._delegate.onUntrack(window);
115 } else {
116 this._unregLoadingWindow(window);
117 }
118 },
120 unload: function unload() {
121 windowWatcher.unregisterNotification(this);
122 events.off('toplevel-window-ready', this._onToplevelWindowReady);
123 for each (let window in getWindows())
124 this._unregWindow(window);
125 },
127 handleEvent: errors.catchAndLog(function handleEvent(event) {
128 if (event.type == 'load' && event.target) {
129 var window = event.target.defaultView;
130 if (window)
131 this._regWindow(window);
132 }
133 }),
135 _onToplevelWindowReady: function _onToplevelWindowReady({subject}) {
136 let window = subject;
137 // ignore private windows if they are not supported
138 if (ignoreWindow(window))
139 return;
140 this._regWindow(window);
141 },
143 observe: errors.catchAndLog(function observe(subject, topic, data) {
144 var window = subject.QueryInterface(Ci.nsIDOMWindow);
145 // ignore private windows if they are not supported
146 if (ignoreWindow(window))
147 return;
148 if (topic == 'domwindowclosed')
149 this._unregWindow(window);
150 })
151 };
152 exports.WindowTracker = WindowTracker;
154 const WindowTrackerTrait = Trait.compose({
155 _onTrack: Trait.required,
156 _onUntrack: Trait.required,
157 constructor: function WindowTrackerTrait() {
158 WindowTracker({
159 onTrack: this._onTrack.bind(this),
160 onUntrack: this._onUntrack.bind(this)
161 });
162 }
163 });
164 exports.WindowTrackerTrait = WindowTrackerTrait;
166 var gDocsToClose = [];
168 function onDocUnload(event) {
169 var index = gDocsToClose.indexOf(event.target);
170 if (index == -1)
171 throw new Error('internal error: unloading document not found');
172 var document = gDocsToClose.splice(index, 1)[0];
173 // Just in case, let's remove the event listener too.
174 document.defaultView.removeEventListener('unload', onDocUnload, false);
175 }
177 onDocUnload = require('./errors').catchAndLog(onDocUnload);
179 exports.closeOnUnload = function closeOnUnload(window) {
180 window.addEventListener('unload', onDocUnload, false);
181 gDocsToClose.push(window.document);
182 };
184 Object.defineProperties(exports, {
185 activeWindow: {
186 enumerable: true,
187 get: function() {
188 return getMostRecentWindow(null);
189 },
190 set: function(window) {
191 try {
192 window.focus();
193 } catch (e) {}
194 }
195 },
196 activeBrowserWindow: {
197 enumerable: true,
198 get: getMostRecentBrowserWindow
199 }
200 });
203 /**
204 * Returns the ID of the window's current inner window.
205 */
206 exports.getInnerId = deprecateFunction(getInnerId,
207 'require("window-utils").getInnerId is deprecated, ' +
208 'please use require("sdk/window/utils").getInnerId instead'
209 );
211 exports.getOuterId = deprecateFunction(getOuterId,
212 'require("window-utils").getOuterId is deprecated, ' +
213 'please use require("sdk/window/utils").getOuterId instead'
214 );
216 exports.isBrowser = deprecateFunction(isBrowser,
217 'require("window-utils").isBrowser is deprecated, ' +
218 'please use require("sdk/window/utils").isBrowser instead'
219 );
221 exports.hiddenWindow = appShellService.hiddenDOMWindow;
223 when(
224 function() {
225 gDocsToClose.slice().forEach(
226 function(doc) { doc.defaultView.close(); });
227 });