addon-sdk/source/lib/sdk/window/utils.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 'use strict';
michael@0 5
michael@0 6 module.metadata = {
michael@0 7 'stability': 'unstable'
michael@0 8 };
michael@0 9
michael@0 10 const { Cc, Ci } = require('chrome');
michael@0 11 const array = require('../util/array');
michael@0 12 const { defer } = require('sdk/core/promise');
michael@0 13
michael@0 14 const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
michael@0 15 getService(Ci.nsIWindowWatcher);
michael@0 16 const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
michael@0 17 getService(Ci.nsIAppShellService);
michael@0 18 const WM = Cc['@mozilla.org/appshell/window-mediator;1'].
michael@0 19 getService(Ci.nsIWindowMediator);
michael@0 20 const io = Cc['@mozilla.org/network/io-service;1'].
michael@0 21 getService(Ci.nsIIOService);
michael@0 22 const FM = Cc["@mozilla.org/focus-manager;1"].
michael@0 23 getService(Ci.nsIFocusManager);
michael@0 24
michael@0 25 const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
michael@0 26
michael@0 27 const BROWSER = 'navigator:browser',
michael@0 28 URI_BROWSER = 'chrome://browser/content/browser.xul',
michael@0 29 NAME = '_blank',
michael@0 30 FEATURES = 'chrome,all,dialog=no,non-private';
michael@0 31
michael@0 32 function isWindowPrivate(win) {
michael@0 33 if (!win)
michael@0 34 return false;
michael@0 35
michael@0 36 // if the pbService is undefined, the PrivateBrowsingUtils.jsm is available,
michael@0 37 // and the app is Firefox, then assume per-window private browsing is
michael@0 38 // enabled.
michael@0 39 try {
michael@0 40 return win.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 41 .getInterface(Ci.nsIWebNavigation)
michael@0 42 .QueryInterface(Ci.nsILoadContext)
michael@0 43 .usePrivateBrowsing;
michael@0 44 }
michael@0 45 catch(e) {}
michael@0 46
michael@0 47 // Sometimes the input is not a nsIDOMWindow.. but it is still a winodw.
michael@0 48 try {
michael@0 49 return !!win.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing;
michael@0 50 }
michael@0 51 catch (e) {}
michael@0 52
michael@0 53 return false;
michael@0 54 }
michael@0 55 exports.isWindowPrivate = isWindowPrivate;
michael@0 56
michael@0 57 function getMostRecentBrowserWindow() {
michael@0 58 return getMostRecentWindow(BROWSER);
michael@0 59 }
michael@0 60 exports.getMostRecentBrowserWindow = getMostRecentBrowserWindow;
michael@0 61
michael@0 62 function getHiddenWindow() {
michael@0 63 return appShellService.hiddenDOMWindow;
michael@0 64 }
michael@0 65 exports.getHiddenWindow = getHiddenWindow;
michael@0 66
michael@0 67 function getMostRecentWindow(type) {
michael@0 68 return WM.getMostRecentWindow(type);
michael@0 69 }
michael@0 70 exports.getMostRecentWindow = getMostRecentWindow;
michael@0 71
michael@0 72 /**
michael@0 73 * Returns the ID of the window's current inner window.
michael@0 74 */
michael@0 75 function getInnerId(window) {
michael@0 76 return window.QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 77 getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
michael@0 78 };
michael@0 79 exports.getInnerId = getInnerId;
michael@0 80
michael@0 81 /**
michael@0 82 * Returns the ID of the window's outer window.
michael@0 83 */
michael@0 84 function getOuterId(window) {
michael@0 85 return window.QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 86 getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
michael@0 87 };
michael@0 88 exports.getOuterId = getOuterId;
michael@0 89
michael@0 90 /**
michael@0 91 * Returns window by the outer window id.
michael@0 92 */
michael@0 93 const getByOuterId = WM.getOuterWindowWithId;
michael@0 94 exports.getByOuterId = getByOuterId;
michael@0 95
michael@0 96 const getByInnerId = WM.getCurrentInnerWindowWithId;
michael@0 97 exports.getByInnerId = getByInnerId;
michael@0 98
michael@0 99 /**
michael@0 100 * Returns `nsIXULWindow` for the given `nsIDOMWindow`.
michael@0 101 */
michael@0 102 function getXULWindow(window) {
michael@0 103 return window.QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 104 getInterface(Ci.nsIWebNavigation).
michael@0 105 QueryInterface(Ci.nsIDocShellTreeItem).
michael@0 106 treeOwner.QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 107 getInterface(Ci.nsIXULWindow);
michael@0 108 };
michael@0 109 exports.getXULWindow = getXULWindow;
michael@0 110
michael@0 111 function getDOMWindow(xulWindow) {
michael@0 112 return xulWindow.QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 113 getInterface(Ci.nsIDOMWindow);
michael@0 114 }
michael@0 115 exports.getDOMWindow = getDOMWindow;
michael@0 116
michael@0 117 /**
michael@0 118 * Returns `nsIBaseWindow` for the given `nsIDOMWindow`.
michael@0 119 */
michael@0 120 function getBaseWindow(window) {
michael@0 121 return window.QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 122 getInterface(Ci.nsIWebNavigation).
michael@0 123 QueryInterface(Ci.nsIDocShell).
michael@0 124 QueryInterface(Ci.nsIDocShellTreeItem).
michael@0 125 treeOwner.
michael@0 126 QueryInterface(Ci.nsIBaseWindow);
michael@0 127 }
michael@0 128 exports.getBaseWindow = getBaseWindow;
michael@0 129
michael@0 130 /**
michael@0 131 * Returns the `nsIDOMWindow` toplevel window for any child/inner window
michael@0 132 */
michael@0 133 function getToplevelWindow(window) {
michael@0 134 return window.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 135 .getInterface(Ci.nsIWebNavigation)
michael@0 136 .QueryInterface(Ci.nsIDocShellTreeItem)
michael@0 137 .rootTreeItem
michael@0 138 .QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 139 .getInterface(Ci.nsIDOMWindow);
michael@0 140 }
michael@0 141 exports.getToplevelWindow = getToplevelWindow;
michael@0 142
michael@0 143 function getWindowDocShell(window) window.gBrowser.docShell;
michael@0 144 exports.getWindowDocShell = getWindowDocShell;
michael@0 145
michael@0 146 function getWindowLoadingContext(window) {
michael@0 147 return getWindowDocShell(window).
michael@0 148 QueryInterface(Ci.nsILoadContext);
michael@0 149 }
michael@0 150 exports.getWindowLoadingContext = getWindowLoadingContext;
michael@0 151
michael@0 152 const isTopLevel = window => window && getToplevelWindow(window) === window;
michael@0 153 exports.isTopLevel = isTopLevel;
michael@0 154
michael@0 155 /**
michael@0 156 * Takes hash of options and serializes it to a features string that
michael@0 157 * can be used passed to `window.open`. For more details on features string see:
michael@0 158 * https://developer.mozilla.org/en/DOM/window.open#Position_and_size_features
michael@0 159 */
michael@0 160 function serializeFeatures(options) {
michael@0 161 return Object.keys(options).reduce(function(result, name) {
michael@0 162 let value = options[name];
michael@0 163
michael@0 164 // the chrome and private features are special
michael@0 165 if ((name == 'private' || name == 'chrome'))
michael@0 166 return result + ((value === true) ? ',' + name : '');
michael@0 167
michael@0 168 return result + ',' + name + '=' +
michael@0 169 (value === true ? 'yes' : value === false ? 'no' : value);
michael@0 170 }, '').substr(1);
michael@0 171 }
michael@0 172
michael@0 173 /**
michael@0 174 * Opens a top level window and returns it's `nsIDOMWindow` representation.
michael@0 175 * @params {String} uri
michael@0 176 * URI of the document to be loaded into window.
michael@0 177 * @params {nsIDOMWindow} options.parent
michael@0 178 * Used as parent for the created window.
michael@0 179 * @params {String} options.name
michael@0 180 * Optional name that is assigned to the window.
michael@0 181 * @params {Object} options.features
michael@0 182 * Map of key, values like: `{ width: 10, height: 15, chrome: true, private: true }`.
michael@0 183 */
michael@0 184 function open(uri, options) {
michael@0 185 uri = uri || URI_BROWSER;
michael@0 186 options = options || {};
michael@0 187
michael@0 188 if (['chrome', 'resource', 'data'].indexOf(io.newURI(uri, null, null).scheme) < 0)
michael@0 189 throw new Error('only chrome, resource and data uris are allowed');
michael@0 190
michael@0 191 let newWindow = windowWatcher.
michael@0 192 openWindow(options.parent || null,
michael@0 193 uri,
michael@0 194 options.name || null,
michael@0 195 options.features ? serializeFeatures(options.features) : null,
michael@0 196 options.args || null);
michael@0 197
michael@0 198 return newWindow;
michael@0 199 }
michael@0 200 exports.open = open;
michael@0 201
michael@0 202 function onFocus(window) {
michael@0 203 let { resolve, promise } = defer();
michael@0 204
michael@0 205 if (isFocused(window)) {
michael@0 206 resolve(window);
michael@0 207 }
michael@0 208 else {
michael@0 209 window.addEventListener("focus", function focusListener() {
michael@0 210 window.removeEventListener("focus", focusListener, true);
michael@0 211 resolve(window);
michael@0 212 }, true);
michael@0 213 }
michael@0 214
michael@0 215 return promise;
michael@0 216 }
michael@0 217 exports.onFocus = onFocus;
michael@0 218
michael@0 219 function isFocused(window) {
michael@0 220 const FM = Cc["@mozilla.org/focus-manager;1"].
michael@0 221 getService(Ci.nsIFocusManager);
michael@0 222
michael@0 223 let childTargetWindow = {};
michael@0 224 FM.getFocusedElementForWindow(window, true, childTargetWindow);
michael@0 225 childTargetWindow = childTargetWindow.value;
michael@0 226
michael@0 227 let focusedChildWindow = {};
michael@0 228 if (FM.activeWindow) {
michael@0 229 FM.getFocusedElementForWindow(FM.activeWindow, true, focusedChildWindow);
michael@0 230 focusedChildWindow = focusedChildWindow.value;
michael@0 231 }
michael@0 232
michael@0 233 return (focusedChildWindow === childTargetWindow);
michael@0 234 }
michael@0 235 exports.isFocused = isFocused;
michael@0 236
michael@0 237 /**
michael@0 238 * Opens a top level window and returns it's `nsIDOMWindow` representation.
michael@0 239 * Same as `open` but with more features
michael@0 240 * @param {Object} options
michael@0 241 *
michael@0 242 */
michael@0 243 function openDialog(options) {
michael@0 244 options = options || {};
michael@0 245
michael@0 246 let features = options.features || FEATURES;
michael@0 247 let featureAry = features.toLowerCase().split(',');
michael@0 248
michael@0 249 if (!!options.private) {
michael@0 250 // add private flag if private window is desired
michael@0 251 if (!array.has(featureAry, 'private')) {
michael@0 252 featureAry.push('private');
michael@0 253 }
michael@0 254
michael@0 255 // remove the non-private flag ig a private window is desired
michael@0 256 let nonPrivateIndex = featureAry.indexOf('non-private');
michael@0 257 if (nonPrivateIndex >= 0) {
michael@0 258 featureAry.splice(nonPrivateIndex, 1);
michael@0 259 }
michael@0 260
michael@0 261 features = featureAry.join(',');
michael@0 262 }
michael@0 263
michael@0 264 let browser = getMostRecentBrowserWindow();
michael@0 265
michael@0 266 // if there is no browser then do nothing
michael@0 267 if (!browser)
michael@0 268 return undefined;
michael@0 269
michael@0 270 let newWindow = browser.openDialog.apply(
michael@0 271 browser,
michael@0 272 array.flatten([
michael@0 273 options.url || URI_BROWSER,
michael@0 274 options.name || NAME,
michael@0 275 features,
michael@0 276 options.args || null
michael@0 277 ])
michael@0 278 );
michael@0 279
michael@0 280 return newWindow;
michael@0 281 }
michael@0 282 exports.openDialog = openDialog;
michael@0 283
michael@0 284 /**
michael@0 285 * Returns an array of all currently opened windows.
michael@0 286 * Note that these windows may still be loading.
michael@0 287 */
michael@0 288 function windows(type, options) {
michael@0 289 options = options || {};
michael@0 290 let list = [];
michael@0 291 let winEnum = WM.getEnumerator(type);
michael@0 292 while (winEnum.hasMoreElements()) {
michael@0 293 let window = winEnum.getNext().QueryInterface(Ci.nsIDOMWindow);
michael@0 294 // Only add non-private windows when pb permission isn't set,
michael@0 295 // unless an option forces the addition of them.
michael@0 296 if (!window.closed && (options.includePrivate || !isWindowPrivate(window))) {
michael@0 297 list.push(window);
michael@0 298 }
michael@0 299 }
michael@0 300 return list;
michael@0 301 }
michael@0 302 exports.windows = windows;
michael@0 303
michael@0 304 /**
michael@0 305 * Check if the given window is interactive.
michael@0 306 * i.e. if its "DOMContentLoaded" event has already been fired.
michael@0 307 * @params {nsIDOMWindow} window
michael@0 308 */
michael@0 309 const isInteractive = window =>
michael@0 310 window.document.readyState === "interactive" ||
michael@0 311 isDocumentLoaded(window) ||
michael@0 312 // XUL documents stays '"uninitialized"' until it's `readyState` becomes
michael@0 313 // `"complete"`.
michael@0 314 isXULDocumentWindow(window) && window.document.readyState === "interactive";
michael@0 315 exports.isInteractive = isInteractive;
michael@0 316
michael@0 317 const isXULDocumentWindow = ({document}) =>
michael@0 318 document.documentElement &&
michael@0 319 document.documentElement.namespaceURI === XUL_NS;
michael@0 320
michael@0 321 /**
michael@0 322 * Check if the given window is completely loaded.
michael@0 323 * i.e. if its "load" event has already been fired and all possible DOM content
michael@0 324 * is done loading (the whole DOM document, images content, ...)
michael@0 325 * @params {nsIDOMWindow} window
michael@0 326 */
michael@0 327 function isDocumentLoaded(window) {
michael@0 328 return window.document.readyState == "complete";
michael@0 329 }
michael@0 330 exports.isDocumentLoaded = isDocumentLoaded;
michael@0 331
michael@0 332 function isBrowser(window) {
michael@0 333 try {
michael@0 334 return window.document.documentElement.getAttribute("windowtype") === BROWSER;
michael@0 335 }
michael@0 336 catch (e) {}
michael@0 337 return false;
michael@0 338 };
michael@0 339 exports.isBrowser = isBrowser;
michael@0 340
michael@0 341 function getWindowTitle(window) {
michael@0 342 return window && window.document ? window.document.title : null;
michael@0 343 }
michael@0 344 exports.getWindowTitle = getWindowTitle;
michael@0 345
michael@0 346 function isXULBrowser(window) {
michael@0 347 return !!(isBrowser(window) && window.XULBrowserWindow);
michael@0 348 }
michael@0 349 exports.isXULBrowser = isXULBrowser;
michael@0 350
michael@0 351 /**
michael@0 352 * Returns the most recent focused window
michael@0 353 */
michael@0 354 function getFocusedWindow() {
michael@0 355 let window = WM.getMostRecentWindow(BROWSER);
michael@0 356
michael@0 357 return window ? window.document.commandDispatcher.focusedWindow : null;
michael@0 358 }
michael@0 359 exports.getFocusedWindow = getFocusedWindow;
michael@0 360
michael@0 361 /**
michael@0 362 * Returns the focused browser window if any, or the most recent one.
michael@0 363 * Opening new window, updates most recent window, but focus window
michael@0 364 * changes later; so most recent window and focused window are not always
michael@0 365 * the same.
michael@0 366 */
michael@0 367 function getFocusedBrowser() {
michael@0 368 let window = FM.activeWindow;
michael@0 369 return isBrowser(window) ? window : getMostRecentBrowserWindow()
michael@0 370 }
michael@0 371 exports.getFocusedBrowser = getFocusedBrowser;
michael@0 372
michael@0 373 /**
michael@0 374 * Returns the focused element in the most recent focused window
michael@0 375 */
michael@0 376 function getFocusedElement() {
michael@0 377 let window = WM.getMostRecentWindow(BROWSER);
michael@0 378
michael@0 379 return window ? window.document.commandDispatcher.focusedElement : null;
michael@0 380 }
michael@0 381 exports.getFocusedElement = getFocusedElement;
michael@0 382
michael@0 383 function getFrames(window) {
michael@0 384 return Array.slice(window.frames).reduce(function(frames, frame) {
michael@0 385 return frames.concat(frame, getFrames(frame));
michael@0 386 }, []);
michael@0 387 }
michael@0 388 exports.getFrames = getFrames;
michael@0 389
michael@0 390 function getScreenPixelsPerCSSPixel(window) {
michael@0 391 return window.QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 392 getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
michael@0 393 }
michael@0 394 exports.getScreenPixelsPerCSSPixel = getScreenPixelsPerCSSPixel;
michael@0 395
michael@0 396 function getOwnerBrowserWindow(node) {
michael@0 397 /**
michael@0 398 Takes DOM node and returns browser window that contains it.
michael@0 399 **/
michael@0 400 let window = getToplevelWindow(node.ownerDocument.defaultView);
michael@0 401 // If anchored window is browser then it's target browser window.
michael@0 402 return isBrowser(window) ? window : null;
michael@0 403 }
michael@0 404 exports.getOwnerBrowserWindow = getOwnerBrowserWindow;
michael@0 405
michael@0 406 function getParentWindow(window) {
michael@0 407 try {
michael@0 408 return window.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 409 .getInterface(Ci.nsIWebNavigation)
michael@0 410 .QueryInterface(Ci.nsIDocShellTreeItem).parent
michael@0 411 .QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 412 .getInterface(Ci.nsIDOMWindow);
michael@0 413 }
michael@0 414 catch (e) {}
michael@0 415 return null;
michael@0 416 }
michael@0 417 exports.getParentWindow = getParentWindow;
michael@0 418
michael@0 419
michael@0 420 function getParentFrame(window) {
michael@0 421 try {
michael@0 422 return window.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 423 .getInterface(Ci.nsIWebNavigation)
michael@0 424 .QueryInterface(Ci.nsIDocShellTreeItem).parent
michael@0 425 .QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 426 .getInterface(Ci.nsIDOMWindow);
michael@0 427 }
michael@0 428 catch (e) {}
michael@0 429 return null;
michael@0 430 }
michael@0 431 exports.getParentWindow = getParentWindow;
michael@0 432
michael@0 433 // The element in which the window is embedded, or `null`
michael@0 434 // if the window is top-level. Similar to `window.frameElement`
michael@0 435 // but can cross chrome-content boundries.
michael@0 436 const getFrameElement = target =>
michael@0 437 (target instanceof Ci.nsIDOMDocument ? target.defaultView : target).
michael@0 438 QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 439 getInterface(Ci.nsIDOMWindowUtils).
michael@0 440 containerElement;
michael@0 441 exports.getFrameElement = getFrameElement;

mercurial