|
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'; |
|
5 |
|
6 const { Class } = require('../core/heritage'); |
|
7 const { Tab } = require('../tabs/tab'); |
|
8 const { browserWindows } = require('./fennec'); |
|
9 const { windowNS } = require('../window/namespace'); |
|
10 const { tabsNS, tabNS } = require('../tabs/namespace'); |
|
11 const { openTab, getTabs, getSelectedTab, getTabForBrowser: getRawTabForBrowser, |
|
12 getTabContentWindow } = require('../tabs/utils'); |
|
13 const { Options } = require('../tabs/common'); |
|
14 const { getTabForBrowser, getTabForRawTab } = require('../tabs/helpers'); |
|
15 const { on, once, off, emit } = require('../event/core'); |
|
16 const { method } = require('../lang/functional'); |
|
17 const { EVENTS } = require('../tabs/events'); |
|
18 const { EventTarget } = require('../event/target'); |
|
19 const { when: unload } = require('../system/unload'); |
|
20 const { windowIterator } = require('../deprecated/window-utils'); |
|
21 const { List, addListItem, removeListItem } = require('../util/list'); |
|
22 const { isPrivateBrowsingSupported } = require('../self'); |
|
23 const { isTabPBSupported, ignoreWindow } = require('../private-browsing/utils'); |
|
24 |
|
25 const mainWindow = windowNS(browserWindows.activeWindow).window; |
|
26 |
|
27 const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec'; |
|
28 |
|
29 const supportPrivateTabs = isPrivateBrowsingSupported && isTabPBSupported; |
|
30 |
|
31 const Tabs = Class({ |
|
32 implements: [ List ], |
|
33 extends: EventTarget, |
|
34 initialize: function initialize(options) { |
|
35 let tabsInternals = tabsNS(this); |
|
36 let window = tabsNS(this).window = options.window || mainWindow; |
|
37 |
|
38 EventTarget.prototype.initialize.call(this, options); |
|
39 List.prototype.initialize.apply(this, getTabs(window).map(Tab)); |
|
40 |
|
41 // TabOpen event |
|
42 window.BrowserApp.deck.addEventListener(EVENTS.open.dom, onTabOpen, false); |
|
43 |
|
44 // TabSelect |
|
45 window.BrowserApp.deck.addEventListener(EVENTS.activate.dom, onTabSelect, false); |
|
46 }, |
|
47 get activeTab() { |
|
48 return getTabForRawTab(getSelectedTab(tabsNS(this).window)); |
|
49 }, |
|
50 open: function(options) { |
|
51 options = Options(options); |
|
52 let activeWin = browserWindows.activeWindow; |
|
53 |
|
54 if (options.isPinned) { |
|
55 console.error(ERR_FENNEC_MSG); // TODO |
|
56 } |
|
57 |
|
58 let rawTab = openTab(windowNS(activeWin).window, options.url, { |
|
59 inBackground: options.inBackground, |
|
60 isPrivate: supportPrivateTabs && options.isPrivate |
|
61 }); |
|
62 |
|
63 // by now the tab has been created |
|
64 let tab = getTabForRawTab(rawTab); |
|
65 |
|
66 if (options.onClose) |
|
67 tab.on('close', options.onClose); |
|
68 |
|
69 if (options.onOpen) { |
|
70 // NOTE: on Fennec this will be true |
|
71 if (tabNS(tab).opened) |
|
72 options.onOpen(tab); |
|
73 |
|
74 tab.on('open', options.onOpen); |
|
75 } |
|
76 |
|
77 if (options.onReady) |
|
78 tab.on('ready', options.onReady); |
|
79 |
|
80 if (options.onLoad) |
|
81 tab.on('load', options.onLoad); |
|
82 |
|
83 if (options.onPageShow) |
|
84 tab.on('pageshow', options.onPageShow); |
|
85 |
|
86 if (options.onActivate) |
|
87 tab.on('activate', options.onActivate); |
|
88 |
|
89 return tab; |
|
90 } |
|
91 }); |
|
92 let gTabs = exports.tabs = Tabs(mainWindow); |
|
93 |
|
94 function tabsUnloader(event, window) { |
|
95 window = window || (event && event.target); |
|
96 if (!(window && window.BrowserApp)) |
|
97 return; |
|
98 window.BrowserApp.deck.removeEventListener(EVENTS.open.dom, onTabOpen, false); |
|
99 window.BrowserApp.deck.removeEventListener(EVENTS.activate.dom, onTabSelect, false); |
|
100 } |
|
101 |
|
102 // unload handler |
|
103 unload(function() { |
|
104 for (let window in windowIterator()) { |
|
105 tabsUnloader(null, window); |
|
106 } |
|
107 }); |
|
108 |
|
109 function addTab(tab) { |
|
110 addListItem(gTabs, tab); |
|
111 return tab; |
|
112 } |
|
113 |
|
114 function removeTab(tab) { |
|
115 removeListItem(gTabs, tab); |
|
116 return tab; |
|
117 } |
|
118 |
|
119 // TabOpen |
|
120 function onTabOpen(event) { |
|
121 let browser = event.target; |
|
122 |
|
123 // Eventually ignore private tabs |
|
124 if (ignoreWindow(browser.contentWindow)) |
|
125 return; |
|
126 |
|
127 let tab = getTabForBrowser(browser); |
|
128 if (tab === null) { |
|
129 let rawTab = getRawTabForBrowser(browser); |
|
130 |
|
131 // create a Tab instance for this new tab |
|
132 tab = addTab(Tab(rawTab)); |
|
133 } |
|
134 |
|
135 tabNS(tab).opened = true; |
|
136 |
|
137 tab.on('ready', function() emit(gTabs, 'ready', tab)); |
|
138 tab.once('close', onTabClose); |
|
139 |
|
140 tab.on('pageshow', function(_tab, persisted) |
|
141 emit(gTabs, 'pageshow', tab, persisted)); |
|
142 |
|
143 emit(tab, 'open', tab); |
|
144 emit(gTabs, 'open', tab); |
|
145 } |
|
146 |
|
147 // TabSelect |
|
148 function onTabSelect(event) { |
|
149 let browser = event.target; |
|
150 |
|
151 // Eventually ignore private tabs |
|
152 if (ignoreWindow(browser.contentWindow)) |
|
153 return; |
|
154 |
|
155 // Set value whenever new tab becomes active. |
|
156 let tab = getTabForBrowser(browser); |
|
157 emit(tab, 'activate', tab); |
|
158 emit(gTabs, 'activate', tab); |
|
159 |
|
160 for each (let t in gTabs) { |
|
161 if (t === tab) continue; |
|
162 emit(t, 'deactivate', t); |
|
163 emit(gTabs, 'deactivate', t); |
|
164 } |
|
165 } |
|
166 |
|
167 // TabClose |
|
168 function onTabClose(tab) { |
|
169 removeTab(tab); |
|
170 emit(gTabs, EVENTS.close.name, tab); |
|
171 } |