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

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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
michael@0 11 // NOTE: This file should only deal with xul/native tabs
michael@0 12
michael@0 13
michael@0 14 const { Ci } = require('chrome');
michael@0 15 const { defer } = require("../lang/functional");
michael@0 16 const { windows, isBrowser } = require('../window/utils');
michael@0 17 const { isPrivateBrowsingSupported } = require('../self');
michael@0 18 const { isGlobalPBSupported } = require('../private-browsing/utils');
michael@0 19
michael@0 20 // Bug 834961: ignore private windows when they are not supported
michael@0 21 function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported });
michael@0 22
michael@0 23 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
michael@0 24
michael@0 25 // Define predicate functions that can be used to detech weather
michael@0 26 // we deal with fennec tabs or firefox tabs.
michael@0 27
michael@0 28 // Predicate to detect whether tab is XUL "Tab" node.
michael@0 29 const isXULTab = tab =>
michael@0 30 tab instanceof Ci.nsIDOMNode &&
michael@0 31 tab.nodeName === "tab" &&
michael@0 32 tab.namespaceURI === XUL_NS;
michael@0 33 exports.isXULTab = isXULTab;
michael@0 34
michael@0 35 // Predicate to detecet whether given tab is a fettec tab.
michael@0 36 // Unfortunately we have to guess via duck typinng of:
michael@0 37 // http://mxr.mozilla.org/mozilla-central/source/mobile/android/chrome/content/browser.js#2583
michael@0 38 const isFennecTab = tab =>
michael@0 39 tab &&
michael@0 40 tab.QueryInterface &&
michael@0 41 Ci.nsIBrowserTab &&
michael@0 42 tab.QueryInterface(Ci.nsIBrowserTab) === tab;
michael@0 43 exports.isFennecTab = isFennecTab;
michael@0 44
michael@0 45 const isTab = x => isXULTab(x) || isFennecTab(x);
michael@0 46 exports.isTab = isTab;
michael@0 47
michael@0 48 function activateTab(tab, window) {
michael@0 49 let gBrowser = getTabBrowserForTab(tab);
michael@0 50
michael@0 51 // normal case
michael@0 52 if (gBrowser) {
michael@0 53 gBrowser.selectedTab = tab;
michael@0 54 }
michael@0 55 // fennec ?
michael@0 56 else if (window && window.BrowserApp) {
michael@0 57 window.BrowserApp.selectTab(tab);
michael@0 58 }
michael@0 59 return null;
michael@0 60 }
michael@0 61 exports.activateTab = activateTab;
michael@0 62
michael@0 63 function getTabBrowser(window) {
michael@0 64 return window.gBrowser;
michael@0 65 }
michael@0 66 exports.getTabBrowser = getTabBrowser;
michael@0 67
michael@0 68 function getTabContainer(window) {
michael@0 69 return getTabBrowser(window).tabContainer;
michael@0 70 }
michael@0 71 exports.getTabContainer = getTabContainer;
michael@0 72
michael@0 73 /**
michael@0 74 * Returns the tabs for the `window` if given, or the tabs
michael@0 75 * across all the browser's windows otherwise.
michael@0 76 *
michael@0 77 * @param {nsIWindow} [window]
michael@0 78 * A reference to a window
michael@0 79 *
michael@0 80 * @returns {Array} an array of Tab objects
michael@0 81 */
michael@0 82 function getTabs(window) {
michael@0 83 if (arguments.length === 0) {
michael@0 84 return getWindows().filter(isBrowser).reduce(function(tabs, window) {
michael@0 85 return tabs.concat(getTabs(window))
michael@0 86 }, []);
michael@0 87 }
michael@0 88
michael@0 89 // fennec
michael@0 90 if (window.BrowserApp)
michael@0 91 return window.BrowserApp.tabs;
michael@0 92
michael@0 93 // firefox - default
michael@0 94 return Array.slice(getTabContainer(window).children);
michael@0 95 }
michael@0 96 exports.getTabs = getTabs;
michael@0 97
michael@0 98 function getActiveTab(window) {
michael@0 99 return getSelectedTab(window);
michael@0 100 }
michael@0 101 exports.getActiveTab = getActiveTab;
michael@0 102
michael@0 103 function getOwnerWindow(tab) {
michael@0 104 // normal case
michael@0 105 if (tab.ownerDocument)
michael@0 106 return tab.ownerDocument.defaultView;
michael@0 107
michael@0 108 // try fennec case
michael@0 109 return getWindowHoldingTab(tab);
michael@0 110 }
michael@0 111 exports.getOwnerWindow = getOwnerWindow;
michael@0 112
michael@0 113 // fennec
michael@0 114 function getWindowHoldingTab(rawTab) {
michael@0 115 for each (let window in getWindows()) {
michael@0 116 // this function may be called when not using fennec,
michael@0 117 // but BrowserApp is only defined on Fennec
michael@0 118 if (!window.BrowserApp)
michael@0 119 continue;
michael@0 120
michael@0 121 for each (let tab in window.BrowserApp.tabs) {
michael@0 122 if (tab === rawTab)
michael@0 123 return window;
michael@0 124 }
michael@0 125 }
michael@0 126
michael@0 127 return null;
michael@0 128 }
michael@0 129
michael@0 130 function openTab(window, url, options) {
michael@0 131 options = options || {};
michael@0 132
michael@0 133 // fennec?
michael@0 134 if (window.BrowserApp) {
michael@0 135 return window.BrowserApp.addTab(url, {
michael@0 136 selected: options.inBackground ? false : true,
michael@0 137 pinned: options.isPinned || false,
michael@0 138 isPrivate: options.isPrivate || false
michael@0 139 });
michael@0 140 }
michael@0 141
michael@0 142 // firefox
michael@0 143 let newTab = window.gBrowser.addTab(url);
michael@0 144 if (!options.inBackground) {
michael@0 145 activateTab(newTab);
michael@0 146 }
michael@0 147 return newTab;
michael@0 148 };
michael@0 149 exports.openTab = openTab;
michael@0 150
michael@0 151 function isTabOpen(tab) {
michael@0 152 // try normal case then fennec case
michael@0 153 return !!((tab.linkedBrowser) || getWindowHoldingTab(tab));
michael@0 154 }
michael@0 155 exports.isTabOpen = isTabOpen;
michael@0 156
michael@0 157 function closeTab(tab) {
michael@0 158 let gBrowser = getTabBrowserForTab(tab);
michael@0 159 // normal case?
michael@0 160 if (gBrowser) {
michael@0 161 // Bug 699450: the tab may already have been detached
michael@0 162 if (!tab.parentNode)
michael@0 163 return;
michael@0 164 return gBrowser.removeTab(tab);
michael@0 165 }
michael@0 166
michael@0 167 let window = getWindowHoldingTab(tab);
michael@0 168 // fennec?
michael@0 169 if (window && window.BrowserApp) {
michael@0 170 // Bug 699450: the tab may already have been detached
michael@0 171 if (!tab.browser)
michael@0 172 return;
michael@0 173 return window.BrowserApp.closeTab(tab);
michael@0 174 }
michael@0 175 return null;
michael@0 176 }
michael@0 177 exports.closeTab = closeTab;
michael@0 178
michael@0 179 function getURI(tab) {
michael@0 180 if (tab.browser) // fennec
michael@0 181 return tab.browser.currentURI.spec;
michael@0 182 return tab.linkedBrowser.currentURI.spec;
michael@0 183 }
michael@0 184 exports.getURI = getURI;
michael@0 185
michael@0 186 function getTabBrowserForTab(tab) {
michael@0 187 let outerWin = getOwnerWindow(tab);
michael@0 188 if (outerWin)
michael@0 189 return getOwnerWindow(tab).gBrowser;
michael@0 190 return null;
michael@0 191 }
michael@0 192 exports.getTabBrowserForTab = getTabBrowserForTab;
michael@0 193
michael@0 194 function getBrowserForTab(tab) {
michael@0 195 if (tab.browser) // fennec
michael@0 196 return tab.browser;
michael@0 197
michael@0 198 return tab.linkedBrowser;
michael@0 199 }
michael@0 200 exports.getBrowserForTab = getBrowserForTab;
michael@0 201
michael@0 202 function getTabId(tab) {
michael@0 203 if (tab.browser) // fennec
michael@0 204 return tab.id
michael@0 205
michael@0 206 return String.split(tab.linkedPanel, 'panel').pop();
michael@0 207 }
michael@0 208 exports.getTabId = getTabId;
michael@0 209
michael@0 210 function getTabForId(id) {
michael@0 211 return getTabs().find(tab => getTabId(tab) === id) || null;
michael@0 212 }
michael@0 213 exports.getTabForId = getTabForId;
michael@0 214
michael@0 215 function getTabTitle(tab) {
michael@0 216 return getBrowserForTab(tab).contentDocument.title || tab.label || "";
michael@0 217 }
michael@0 218 exports.getTabTitle = getTabTitle;
michael@0 219
michael@0 220 function setTabTitle(tab, title) {
michael@0 221 title = String(title);
michael@0 222 if (tab.browser)
michael@0 223 tab.browser.contentDocument.title = title;
michael@0 224 tab.label = String(title);
michael@0 225 }
michael@0 226 exports.setTabTitle = setTabTitle;
michael@0 227
michael@0 228 function getTabContentWindow(tab) {
michael@0 229 return getBrowserForTab(tab).contentWindow;
michael@0 230 }
michael@0 231 exports.getTabContentWindow = getTabContentWindow;
michael@0 232
michael@0 233 /**
michael@0 234 * Returns all tabs' content windows across all the browsers' windows
michael@0 235 */
michael@0 236 function getAllTabContentWindows() {
michael@0 237 return getTabs().map(getTabContentWindow);
michael@0 238 }
michael@0 239 exports.getAllTabContentWindows = getAllTabContentWindows;
michael@0 240
michael@0 241 // gets the tab containing the provided window
michael@0 242 function getTabForContentWindow(window) {
michael@0 243 // Retrieve the topmost frame container. It can be either <xul:browser>,
michael@0 244 // <xul:iframe/> or <html:iframe/>. But in our case, it should be xul:browser.
michael@0 245 let browser;
michael@0 246 try {
michael@0 247 browser = window.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 248 .getInterface(Ci.nsIWebNavigation)
michael@0 249 .QueryInterface(Ci.nsIDocShell)
michael@0 250 .chromeEventHandler;
michael@0 251 } catch(e) {
michael@0 252 // Bug 699450: The tab may already have been detached so that `window` is
michael@0 253 // in a almost destroyed state and can't be queryinterfaced anymore.
michael@0 254 }
michael@0 255
michael@0 256 // Is null for toplevel documents
michael@0 257 if (!browser) {
michael@0 258 return null;
michael@0 259 }
michael@0 260
michael@0 261 // Retrieve the owner window, should be browser.xul one
michael@0 262 let chromeWindow = browser.ownerDocument.defaultView;
michael@0 263
michael@0 264 // Ensure that it is top-level browser window.
michael@0 265 // We need extra checks because of Mac hidden window that has a broken
michael@0 266 // `gBrowser` global attribute.
michael@0 267 if ('gBrowser' in chromeWindow && chromeWindow.gBrowser &&
michael@0 268 'browsers' in chromeWindow.gBrowser) {
michael@0 269 // Looks like we are on Firefox Desktop
michael@0 270 // Then search for the position in tabbrowser in order to get the tab object
michael@0 271 let browsers = chromeWindow.gBrowser.browsers;
michael@0 272 let i = browsers.indexOf(browser);
michael@0 273 if (i !== -1)
michael@0 274 return chromeWindow.gBrowser.tabs[i];
michael@0 275 return null;
michael@0 276 }
michael@0 277 // Fennec
michael@0 278 else if ('BrowserApp' in chromeWindow) {
michael@0 279 return getTabForWindow(window);
michael@0 280 }
michael@0 281
michael@0 282 return null;
michael@0 283 }
michael@0 284 exports.getTabForContentWindow = getTabForContentWindow;
michael@0 285
michael@0 286 // used on fennec
michael@0 287 function getTabForWindow(window) {
michael@0 288 for each (let { BrowserApp } in getWindows()) {
michael@0 289 if (!BrowserApp)
michael@0 290 continue;
michael@0 291
michael@0 292 for each (let tab in BrowserApp.tabs) {
michael@0 293 if (tab.browser.contentWindow == window.top)
michael@0 294 return tab;
michael@0 295 }
michael@0 296 }
michael@0 297 return null;
michael@0 298 }
michael@0 299
michael@0 300 function getTabURL(tab) {
michael@0 301 if (tab.browser) // fennec
michael@0 302 return String(tab.browser.currentURI.spec);
michael@0 303 return String(getBrowserForTab(tab).currentURI.spec);
michael@0 304 }
michael@0 305 exports.getTabURL = getTabURL;
michael@0 306
michael@0 307 function setTabURL(tab, url) {
michael@0 308 url = String(url);
michael@0 309 if (tab.browser)
michael@0 310 return tab.browser.loadURI(url);
michael@0 311 return getBrowserForTab(tab).loadURI(url);
michael@0 312 }
michael@0 313 // "TabOpen" event is fired when it's still "about:blank" is loaded in the
michael@0 314 // changing `location` property of the `contentDocument` has no effect since
michael@0 315 // seems to be either ignored or overridden by internal listener, there for
michael@0 316 // location change is enqueued for the next turn of event loop.
michael@0 317 exports.setTabURL = defer(setTabURL);
michael@0 318
michael@0 319 function getTabContentType(tab) {
michael@0 320 return getBrowserForTab(tab).contentDocument.contentType;
michael@0 321 }
michael@0 322 exports.getTabContentType = getTabContentType;
michael@0 323
michael@0 324 function getSelectedTab(window) {
michael@0 325 if (window.BrowserApp) // fennec?
michael@0 326 return window.BrowserApp.selectedTab;
michael@0 327 if (window.gBrowser)
michael@0 328 return window.gBrowser.selectedTab;
michael@0 329 return null;
michael@0 330 }
michael@0 331 exports.getSelectedTab = getSelectedTab;
michael@0 332
michael@0 333
michael@0 334 function getTabForBrowser(browser) {
michael@0 335 for each (let window in getWindows()) {
michael@0 336 // this function may be called when not using fennec
michael@0 337 if (!window.BrowserApp)
michael@0 338 continue;
michael@0 339
michael@0 340 for each (let tab in window.BrowserApp.tabs) {
michael@0 341 if (tab.browser === browser)
michael@0 342 return tab;
michael@0 343 }
michael@0 344 }
michael@0 345 return null;
michael@0 346 }
michael@0 347 exports.getTabForBrowser = getTabForBrowser;
michael@0 348
michael@0 349 function pin(tab) {
michael@0 350 let gBrowser = getTabBrowserForTab(tab);
michael@0 351 // TODO: Implement Fennec support
michael@0 352 if (gBrowser) gBrowser.pinTab(tab);
michael@0 353 }
michael@0 354 exports.pin = pin;
michael@0 355
michael@0 356 function unpin(tab) {
michael@0 357 let gBrowser = getTabBrowserForTab(tab);
michael@0 358 // TODO: Implement Fennec support
michael@0 359 if (gBrowser) gBrowser.unpinTab(tab);
michael@0 360 }
michael@0 361 exports.unpin = unpin;
michael@0 362
michael@0 363 function isPinned(tab) !!tab.pinned
michael@0 364 exports.isPinned = isPinned;
michael@0 365
michael@0 366 function reload(tab) {
michael@0 367 let gBrowser = getTabBrowserForTab(tab);
michael@0 368 // Firefox
michael@0 369 if (gBrowser) gBrowser.unpinTab(tab);
michael@0 370 // Fennec
michael@0 371 else if (tab.browser) tab.browser.reload();
michael@0 372 }
michael@0 373 exports.reload = reload
michael@0 374
michael@0 375 function getIndex(tab) {
michael@0 376 let gBrowser = getTabBrowserForTab(tab);
michael@0 377 // Firefox
michael@0 378 if (gBrowser) {
michael@0 379 let document = getBrowserForTab(tab).contentDocument;
michael@0 380 return gBrowser.getBrowserIndexForDocument(document);
michael@0 381 }
michael@0 382 // Fennec
michael@0 383 else {
michael@0 384 let window = getWindowHoldingTab(tab)
michael@0 385 let tabs = window.BrowserApp.tabs;
michael@0 386 for (let i = tabs.length; i >= 0; i--)
michael@0 387 if (tabs[i] === tab) return i;
michael@0 388 }
michael@0 389 }
michael@0 390 exports.getIndex = getIndex;
michael@0 391
michael@0 392 function move(tab, index) {
michael@0 393 let gBrowser = getTabBrowserForTab(tab);
michael@0 394 // Firefox
michael@0 395 if (gBrowser) gBrowser.moveTabTo(tab, index);
michael@0 396 // TODO: Implement fennec support
michael@0 397 }
michael@0 398 exports.move = move;

mercurial