1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/deprecated/window-utils.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,227 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +'use strict'; 1.8 + 1.9 +module.metadata = { 1.10 + 'stability': 'deprecated' 1.11 +}; 1.12 + 1.13 +const { Cc, Ci } = require('chrome'); 1.14 +const { EventEmitter } = require('../deprecated/events'); 1.15 +const { Trait } = require('../deprecated/traits'); 1.16 +const { when } = require('../system/unload'); 1.17 +const events = require('../system/events'); 1.18 +const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser, 1.19 + getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils'); 1.20 +const errors = require('../deprecated/errors'); 1.21 +const { deprecateFunction } = require('../util/deprecate'); 1.22 +const { ignoreWindow, isGlobalPBSupported } = require('sdk/private-browsing/utils'); 1.23 +const { isPrivateBrowsingSupported } = require('../self'); 1.24 + 1.25 +const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1']. 1.26 + getService(Ci.nsIWindowWatcher); 1.27 +const appShellService = Cc['@mozilla.org/appshell/appShellService;1']. 1.28 + getService(Ci.nsIAppShellService); 1.29 + 1.30 +// Bug 834961: ignore private windows when they are not supported 1.31 +function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported }); 1.32 + 1.33 +/** 1.34 + * An iterator for XUL windows currently in the application. 1.35 + * 1.36 + * @return A generator that yields XUL windows exposing the 1.37 + * nsIDOMWindow interface. 1.38 + */ 1.39 +function windowIterator() { 1.40 + // Bug 752631: We only pass already loaded window in order to avoid 1.41 + // breaking XUL windows DOM. DOM is broken when some JS code try 1.42 + // to access DOM during "uninitialized" state of the related document. 1.43 + let list = getWindows().filter(isDocumentLoaded); 1.44 + for (let i = 0, l = list.length; i < l; i++) { 1.45 + yield list[i]; 1.46 + } 1.47 +}; 1.48 +exports.windowIterator = windowIterator; 1.49 + 1.50 +/** 1.51 + * An iterator for browser windows currently open in the application. 1.52 + * @returns {Function} 1.53 + * A generator that yields browser windows exposing the `nsIDOMWindow` 1.54 + * interface. 1.55 + */ 1.56 +function browserWindowIterator() { 1.57 + for each (let window in windowIterator()) { 1.58 + if (isBrowser(window)) 1.59 + yield window; 1.60 + } 1.61 +} 1.62 +exports.browserWindowIterator = browserWindowIterator; 1.63 + 1.64 +function WindowTracker(delegate) { 1.65 + if (!(this instanceof WindowTracker)) { 1.66 + return new WindowTracker(delegate); 1.67 + } 1.68 + 1.69 + this._delegate = delegate; 1.70 + this._loadingWindows = []; 1.71 + 1.72 + for each (let window in getWindows()) 1.73 + this._regWindow(window); 1.74 + windowWatcher.registerNotification(this); 1.75 + this._onToplevelWindowReady = this._onToplevelWindowReady.bind(this); 1.76 + events.on('toplevel-window-ready', this._onToplevelWindowReady); 1.77 + 1.78 + require('../system/unload').ensure(this); 1.79 + 1.80 + return this; 1.81 +}; 1.82 + 1.83 +WindowTracker.prototype = { 1.84 + _regLoadingWindow: function _regLoadingWindow(window) { 1.85 + // Bug 834961: ignore private windows when they are not supported 1.86 + if (ignoreWindow(window)) 1.87 + return; 1.88 + 1.89 + this._loadingWindows.push(window); 1.90 + window.addEventListener('load', this, true); 1.91 + }, 1.92 + 1.93 + _unregLoadingWindow: function _unregLoadingWindow(window) { 1.94 + var index = this._loadingWindows.indexOf(window); 1.95 + 1.96 + if (index != -1) { 1.97 + this._loadingWindows.splice(index, 1); 1.98 + window.removeEventListener('load', this, true); 1.99 + } 1.100 + }, 1.101 + 1.102 + _regWindow: function _regWindow(window) { 1.103 + // Bug 834961: ignore private windows when they are not supported 1.104 + if (ignoreWindow(window)) 1.105 + return; 1.106 + 1.107 + if (window.document.readyState == 'complete') { 1.108 + this._unregLoadingWindow(window); 1.109 + this._delegate.onTrack(window); 1.110 + } else 1.111 + this._regLoadingWindow(window); 1.112 + }, 1.113 + 1.114 + _unregWindow: function _unregWindow(window) { 1.115 + if (window.document.readyState == 'complete') { 1.116 + if (this._delegate.onUntrack) 1.117 + this._delegate.onUntrack(window); 1.118 + } else { 1.119 + this._unregLoadingWindow(window); 1.120 + } 1.121 + }, 1.122 + 1.123 + unload: function unload() { 1.124 + windowWatcher.unregisterNotification(this); 1.125 + events.off('toplevel-window-ready', this._onToplevelWindowReady); 1.126 + for each (let window in getWindows()) 1.127 + this._unregWindow(window); 1.128 + }, 1.129 + 1.130 + handleEvent: errors.catchAndLog(function handleEvent(event) { 1.131 + if (event.type == 'load' && event.target) { 1.132 + var window = event.target.defaultView; 1.133 + if (window) 1.134 + this._regWindow(window); 1.135 + } 1.136 + }), 1.137 + 1.138 + _onToplevelWindowReady: function _onToplevelWindowReady({subject}) { 1.139 + let window = subject; 1.140 + // ignore private windows if they are not supported 1.141 + if (ignoreWindow(window)) 1.142 + return; 1.143 + this._regWindow(window); 1.144 + }, 1.145 + 1.146 + observe: errors.catchAndLog(function observe(subject, topic, data) { 1.147 + var window = subject.QueryInterface(Ci.nsIDOMWindow); 1.148 + // ignore private windows if they are not supported 1.149 + if (ignoreWindow(window)) 1.150 + return; 1.151 + if (topic == 'domwindowclosed') 1.152 + this._unregWindow(window); 1.153 + }) 1.154 +}; 1.155 +exports.WindowTracker = WindowTracker; 1.156 + 1.157 +const WindowTrackerTrait = Trait.compose({ 1.158 + _onTrack: Trait.required, 1.159 + _onUntrack: Trait.required, 1.160 + constructor: function WindowTrackerTrait() { 1.161 + WindowTracker({ 1.162 + onTrack: this._onTrack.bind(this), 1.163 + onUntrack: this._onUntrack.bind(this) 1.164 + }); 1.165 + } 1.166 +}); 1.167 +exports.WindowTrackerTrait = WindowTrackerTrait; 1.168 + 1.169 +var gDocsToClose = []; 1.170 + 1.171 +function onDocUnload(event) { 1.172 + var index = gDocsToClose.indexOf(event.target); 1.173 + if (index == -1) 1.174 + throw new Error('internal error: unloading document not found'); 1.175 + var document = gDocsToClose.splice(index, 1)[0]; 1.176 + // Just in case, let's remove the event listener too. 1.177 + document.defaultView.removeEventListener('unload', onDocUnload, false); 1.178 +} 1.179 + 1.180 +onDocUnload = require('./errors').catchAndLog(onDocUnload); 1.181 + 1.182 +exports.closeOnUnload = function closeOnUnload(window) { 1.183 + window.addEventListener('unload', onDocUnload, false); 1.184 + gDocsToClose.push(window.document); 1.185 +}; 1.186 + 1.187 +Object.defineProperties(exports, { 1.188 + activeWindow: { 1.189 + enumerable: true, 1.190 + get: function() { 1.191 + return getMostRecentWindow(null); 1.192 + }, 1.193 + set: function(window) { 1.194 + try { 1.195 + window.focus(); 1.196 + } catch (e) {} 1.197 + } 1.198 + }, 1.199 + activeBrowserWindow: { 1.200 + enumerable: true, 1.201 + get: getMostRecentBrowserWindow 1.202 + } 1.203 +}); 1.204 + 1.205 + 1.206 +/** 1.207 + * Returns the ID of the window's current inner window. 1.208 + */ 1.209 +exports.getInnerId = deprecateFunction(getInnerId, 1.210 + 'require("window-utils").getInnerId is deprecated, ' + 1.211 + 'please use require("sdk/window/utils").getInnerId instead' 1.212 +); 1.213 + 1.214 +exports.getOuterId = deprecateFunction(getOuterId, 1.215 + 'require("window-utils").getOuterId is deprecated, ' + 1.216 + 'please use require("sdk/window/utils").getOuterId instead' 1.217 +); 1.218 + 1.219 +exports.isBrowser = deprecateFunction(isBrowser, 1.220 + 'require("window-utils").isBrowser is deprecated, ' + 1.221 + 'please use require("sdk/window/utils").isBrowser instead' 1.222 +); 1.223 + 1.224 +exports.hiddenWindow = appShellService.hiddenDOMWindow; 1.225 + 1.226 +when( 1.227 + function() { 1.228 + gDocsToClose.slice().forEach( 1.229 + function(doc) { doc.defaultView.close(); }); 1.230 + });