Sat, 03 Jan 2015 20:18:00 +0100
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 | const { Trait } = require("../deprecated/traits"); |
michael@0 | 11 | const { List } = require("../deprecated/list"); |
michael@0 | 12 | const { Tab } = require("../tabs/tab"); |
michael@0 | 13 | const { EventEmitter } = require("../deprecated/events"); |
michael@0 | 14 | const { EVENTS } = require("../tabs/events"); |
michael@0 | 15 | const { getOwnerWindow, getActiveTab, getTabs, |
michael@0 | 16 | openTab } = require("../tabs/utils"); |
michael@0 | 17 | const { Options } = require("../tabs/common"); |
michael@0 | 18 | const { observer: tabsObserver } = require("../tabs/observer"); |
michael@0 | 19 | const { ignoreWindow } = require("../private-browsing/utils"); |
michael@0 | 20 | const { when: unload } = require('../system/unload'); |
michael@0 | 21 | |
michael@0 | 22 | const TAB_BROWSER = "tabbrowser"; |
michael@0 | 23 | |
michael@0 | 24 | let unloaded = false; |
michael@0 | 25 | unload(_ => unloaded = true); |
michael@0 | 26 | |
michael@0 | 27 | /** |
michael@0 | 28 | * This is a trait that is used in composition of window wrapper. Trait tracks |
michael@0 | 29 | * tab related events of the wrapped window in order to keep track of open |
michael@0 | 30 | * tabs and maintain their wrappers. Every new tab gets wrapped and jetpack |
michael@0 | 31 | * type event is emitted. |
michael@0 | 32 | */ |
michael@0 | 33 | const WindowTabTracker = Trait.compose({ |
michael@0 | 34 | /** |
michael@0 | 35 | * Chrome window whose tabs are tracked. |
michael@0 | 36 | */ |
michael@0 | 37 | _window: Trait.required, |
michael@0 | 38 | /** |
michael@0 | 39 | * Function used to emit events. |
michael@0 | 40 | */ |
michael@0 | 41 | _emit: EventEmitter.required, |
michael@0 | 42 | _tabOptions: Trait.required, |
michael@0 | 43 | /** |
michael@0 | 44 | * Function to add event listeners. |
michael@0 | 45 | */ |
michael@0 | 46 | on: EventEmitter.required, |
michael@0 | 47 | removeListener: EventEmitter.required, |
michael@0 | 48 | /** |
michael@0 | 49 | * Initializes tab tracker for a browser window. |
michael@0 | 50 | */ |
michael@0 | 51 | _initWindowTabTracker: function _initWindowTabTracker() { |
michael@0 | 52 | // Ugly hack that we have to remove at some point (see Bug 658059). At this |
michael@0 | 53 | // point it is necessary to invoke lazy `tabs` getter on the windows object |
michael@0 | 54 | // which creates a `TabList` instance. |
michael@0 | 55 | this.tabs; |
michael@0 | 56 | |
michael@0 | 57 | // Binding all methods used as event listeners to the instance. |
michael@0 | 58 | this._onTabReady = this._emitEvent.bind(this, "ready"); |
michael@0 | 59 | this._onTabLoad = this._emitEvent.bind(this, "load"); |
michael@0 | 60 | this._onTabPageShow = this._emitEvent.bind(this, "pageshow"); |
michael@0 | 61 | this._onTabOpen = this._onTabEvent.bind(this, "open"); |
michael@0 | 62 | this._onTabClose = this._onTabEvent.bind(this, "close"); |
michael@0 | 63 | this._onTabActivate = this._onTabEvent.bind(this, "activate"); |
michael@0 | 64 | this._onTabDeactivate = this._onTabEvent.bind(this, "deactivate"); |
michael@0 | 65 | this._onTabPinned = this._onTabEvent.bind(this, "pinned"); |
michael@0 | 66 | this._onTabUnpinned = this._onTabEvent.bind(this, "unpinned"); |
michael@0 | 67 | |
michael@0 | 68 | for each (let tab in getTabs(this._window)) { |
michael@0 | 69 | // We emulate "open" events for all open tabs since gecko does not emits |
michael@0 | 70 | // them on the tabs that new windows are open with. Also this is |
michael@0 | 71 | // necessary to synchronize tabs lists with an actual state. |
michael@0 | 72 | this._onTabOpen(tab); |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | // We also emulate "activate" event so that it's picked up by a tab list. |
michael@0 | 76 | this._onTabActivate(getActiveTab(this._window)); |
michael@0 | 77 | |
michael@0 | 78 | // Setting up event listeners |
michael@0 | 79 | tabsObserver.on("open", this._onTabOpen); |
michael@0 | 80 | tabsObserver.on("close", this._onTabClose); |
michael@0 | 81 | tabsObserver.on("activate", this._onTabActivate); |
michael@0 | 82 | tabsObserver.on("deactivate", this._onTabDeactivate); |
michael@0 | 83 | tabsObserver.on("pinned", this._onTabPinned); |
michael@0 | 84 | tabsObserver.on("unpinned", this._onTabUnpinned); |
michael@0 | 85 | }, |
michael@0 | 86 | _destroyWindowTabTracker: function _destroyWindowTabTracker() { |
michael@0 | 87 | // We emulate close events on all tabs, since gecko does not emits such |
michael@0 | 88 | // events by itself. |
michael@0 | 89 | for each (let tab in this.tabs) |
michael@0 | 90 | this._emitEvent("close", tab); |
michael@0 | 91 | |
michael@0 | 92 | this._tabs._clear(); |
michael@0 | 93 | |
michael@0 | 94 | tabsObserver.removeListener("open", this._onTabOpen); |
michael@0 | 95 | tabsObserver.removeListener("close", this._onTabClose); |
michael@0 | 96 | tabsObserver.removeListener("activate", this._onTabActivate); |
michael@0 | 97 | tabsObserver.removeListener("deactivate", this._onTabDeactivate); |
michael@0 | 98 | }, |
michael@0 | 99 | _onTabEvent: function _onTabEvent(type, tab) { |
michael@0 | 100 | // Accept only tabs for the watched window, and ignore private tabs |
michael@0 | 101 | // if addon doesn't have private permission |
michael@0 | 102 | if (this._window === getOwnerWindow(tab) && !ignoreWindow(this._window)) { |
michael@0 | 103 | let options = this._tabOptions.shift() || {}; |
michael@0 | 104 | options.tab = tab; |
michael@0 | 105 | options.window = this._public; |
michael@0 | 106 | |
michael@0 | 107 | // Ignore zombie tabs on open that have already been removed |
michael@0 | 108 | if (type == "open" && !tab.linkedBrowser) |
michael@0 | 109 | return; |
michael@0 | 110 | |
michael@0 | 111 | // Create a tab wrapper on open event, otherwise, just fetch existing |
michael@0 | 112 | // tab object |
michael@0 | 113 | let wrappedTab = Tab(options, type !== "open"); |
michael@0 | 114 | if (!wrappedTab) |
michael@0 | 115 | return; |
michael@0 | 116 | |
michael@0 | 117 | // Setting up an event listener for ready events. |
michael@0 | 118 | if (type === "open") { |
michael@0 | 119 | wrappedTab.on("ready", this._onTabReady); |
michael@0 | 120 | wrappedTab.on("load", this._onTabLoad); |
michael@0 | 121 | wrappedTab.on("pageshow", this._onTabPageShow); |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | this._emitEvent(type, wrappedTab); |
michael@0 | 125 | } |
michael@0 | 126 | }, |
michael@0 | 127 | _emitEvent: function _emitEvent(type, tag) { |
michael@0 | 128 | if (unloaded) |
michael@0 | 129 | return; |
michael@0 | 130 | |
michael@0 | 131 | // Slices additional arguments and passes them into exposed |
michael@0 | 132 | // listener like other events (for pageshow) |
michael@0 | 133 | let args = Array.slice(arguments); |
michael@0 | 134 | // Notifies combined tab list that tab was added / removed. |
michael@0 | 135 | tabs._emit.apply(tabs, args); |
michael@0 | 136 | // Notifies contained tab list that window was added / removed. |
michael@0 | 137 | this._tabs._emit.apply(this._tabs, args); |
michael@0 | 138 | } |
michael@0 | 139 | }); |
michael@0 | 140 | exports.WindowTabTracker = WindowTabTracker; |
michael@0 | 141 | |
michael@0 | 142 | /** |
michael@0 | 143 | * This trait is used to create live representation of open tab lists. Each |
michael@0 | 144 | * window wrapper's tab list is represented by an object created from this |
michael@0 | 145 | * trait. It is also used to represent list of all the open windows. Trait is |
michael@0 | 146 | * composed out of `EventEmitter` in order to emit 'TabOpen', 'TabClose' events. |
michael@0 | 147 | * **Please note** that objects created by this trait can't be exposed outside |
michael@0 | 148 | * instead you should expose it's `_public` property, see comments in |
michael@0 | 149 | * constructor for details. |
michael@0 | 150 | */ |
michael@0 | 151 | const TabList = List.resolve({ constructor: "_init" }).compose( |
michael@0 | 152 | // This is ugly, but necessary. Will be removed by #596248 |
michael@0 | 153 | EventEmitter.resolve({ toString: null }), |
michael@0 | 154 | Trait.compose({ |
michael@0 | 155 | on: Trait.required, |
michael@0 | 156 | _emit: Trait.required, |
michael@0 | 157 | constructor: function TabList(options) { |
michael@0 | 158 | this._window = options.window; |
michael@0 | 159 | // Add new items to the list |
michael@0 | 160 | this.on(EVENTS.open.name, this._add.bind(this)); |
michael@0 | 161 | |
michael@0 | 162 | // Remove closed items from the list |
michael@0 | 163 | this.on(EVENTS.close.name, this._remove.bind(this)); |
michael@0 | 164 | |
michael@0 | 165 | // Set value whenever new tab becomes active. |
michael@0 | 166 | this.on("activate", function onTabActivate(tab) { |
michael@0 | 167 | this._activeTab = tab; |
michael@0 | 168 | }.bind(this)); |
michael@0 | 169 | |
michael@0 | 170 | // Initialize list. |
michael@0 | 171 | this._init(); |
michael@0 | 172 | // This list is not going to emit any events, object holding this list |
michael@0 | 173 | // will do it instead, to make that possible we return a private API. |
michael@0 | 174 | return this; |
michael@0 | 175 | }, |
michael@0 | 176 | get activeTab() this._activeTab, |
michael@0 | 177 | _activeTab: null, |
michael@0 | 178 | |
michael@0 | 179 | open: function open(options) { |
michael@0 | 180 | let window = this._window; |
michael@0 | 181 | let chromeWindow = window._window; |
michael@0 | 182 | options = Options(options); |
michael@0 | 183 | |
michael@0 | 184 | // save the tab options |
michael@0 | 185 | window._tabOptions.push(options); |
michael@0 | 186 | // open the tab |
michael@0 | 187 | let tab = openTab(chromeWindow, options.url, options); |
michael@0 | 188 | } |
michael@0 | 189 | // This is ugly, but necessary. Will be removed by #596248 |
michael@0 | 190 | }).resolve({ toString: null }) |
michael@0 | 191 | ); |
michael@0 | 192 | |
michael@0 | 193 | /** |
michael@0 | 194 | * Combined list of all open tabs on all the windows. |
michael@0 | 195 | * type {TabList} |
michael@0 | 196 | */ |
michael@0 | 197 | var tabs = TabList({ window: null }); |
michael@0 | 198 | exports.tabs = tabs._public; |
michael@0 | 199 | |
michael@0 | 200 | /** |
michael@0 | 201 | * Trait is a part of composition that represents window wrapper. This trait is |
michael@0 | 202 | * composed out of `WindowTabTracker` that allows it to keep track of open tabs |
michael@0 | 203 | * on the window being wrapped. |
michael@0 | 204 | */ |
michael@0 | 205 | const WindowTabs = Trait.compose( |
michael@0 | 206 | WindowTabTracker, |
michael@0 | 207 | Trait.compose({ |
michael@0 | 208 | _window: Trait.required, |
michael@0 | 209 | /** |
michael@0 | 210 | * List of tabs |
michael@0 | 211 | */ |
michael@0 | 212 | get tabs() (this._tabs || (this._tabs = TabList({ window: this })))._public, |
michael@0 | 213 | _tabs: null, |
michael@0 | 214 | }) |
michael@0 | 215 | ); |
michael@0 | 216 | exports.WindowTabs = WindowTabs; |