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.

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

mercurial