1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/tabs/tab-fennec.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,245 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +'use strict'; 1.8 + 1.9 +const { Cc, Ci } = require('chrome'); 1.10 +const { Class } = require('../core/heritage'); 1.11 +const { tabNS, rawTabNS } = require('./namespace'); 1.12 +const { EventTarget } = require('../event/target'); 1.13 +const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, getTabContentWindow, 1.14 + getTabForBrowser, 1.15 + setTabURL, getOwnerWindow, getTabContentType, getTabId } = require('./utils'); 1.16 +const { emit } = require('../event/core'); 1.17 +const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils'); 1.18 +const { when: unload } = require('../system/unload'); 1.19 +const { viewFor } = require('../view/core'); 1.20 +const { EVENTS } = require('./events'); 1.21 + 1.22 +const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec'; 1.23 + 1.24 +const Tab = Class({ 1.25 + extends: EventTarget, 1.26 + initialize: function initialize(options) { 1.27 + options = options.tab ? options : { tab: options }; 1.28 + let tab = options.tab; 1.29 + 1.30 + EventTarget.prototype.initialize.call(this, options); 1.31 + let tabInternals = tabNS(this); 1.32 + rawTabNS(tab).tab = this; 1.33 + 1.34 + let window = tabInternals.window = options.window || getOwnerWindow(tab); 1.35 + tabInternals.tab = tab; 1.36 + 1.37 + // TabReady 1.38 + let onReady = tabInternals.onReady = onTabReady.bind(this); 1.39 + tab.browser.addEventListener(EVENTS.ready.dom, onReady, false); 1.40 + 1.41 + // TabPageShow 1.42 + let onPageShow = tabInternals.onPageShow = onTabPageShow.bind(this); 1.43 + tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow, false); 1.44 + 1.45 + // TabLoad 1.46 + let onLoad = tabInternals.onLoad = onTabLoad.bind(this); 1.47 + tab.browser.addEventListener(EVENTS.load.dom, onLoad, true); 1.48 + 1.49 + // TabClose 1.50 + let onClose = tabInternals.onClose = onTabClose.bind(this); 1.51 + window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onClose, false); 1.52 + 1.53 + unload(cleanupTab.bind(null, this)); 1.54 + }, 1.55 + 1.56 + /** 1.57 + * The title of the page currently loaded in the tab. 1.58 + * Changing this property changes an actual title. 1.59 + * @type {String} 1.60 + */ 1.61 + get title() getTabTitle(tabNS(this).tab), 1.62 + set title(title) setTabTitle(tabNS(this).tab, title), 1.63 + 1.64 + /** 1.65 + * Location of the page currently loaded in this tab. 1.66 + * Changing this property will loads page under under the specified location. 1.67 + * @type {String} 1.68 + */ 1.69 + get url() { 1.70 + return tabNS(this).closed ? undefined : getTabURL(tabNS(this).tab); 1.71 + }, 1.72 + set url(url) setTabURL(tabNS(this).tab, url), 1.73 + 1.74 + /** 1.75 + * URI of the favicon for the page currently loaded in this tab. 1.76 + * @type {String} 1.77 + */ 1.78 + get favicon() { 1.79 + /* 1.80 + * Synchronous favicon services were never supported on Fennec, 1.81 + * and as of FF22, are now deprecated. When/if favicon services 1.82 + * are supported for Fennec, this getter should reference 1.83 + * `require('sdk/places/favicon').getFavicon` 1.84 + */ 1.85 + console.error( 1.86 + 'tab.favicon is deprecated, and currently ' + 1.87 + 'favicon helpers are not yet supported by Fennec' 1.88 + ); 1.89 + 1.90 + // return 16x16 blank default 1.91 + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAEklEQVQ4jWNgGAWjYBSMAggAAAQQAAF/TXiOAAAAAElFTkSuQmCC'; 1.92 + }, 1.93 + 1.94 + getThumbnail: function() { 1.95 + // TODO: implement! 1.96 + console.error(ERR_FENNEC_MSG); 1.97 + 1.98 + // return 80x45 blank default 1.99 + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC'; 1.100 + }, 1.101 + 1.102 + get id() { 1.103 + return getTabId(tabNS(this).tab); 1.104 + }, 1.105 + 1.106 + /** 1.107 + * The index of the tab relative to other tabs in the application window. 1.108 + * Changing this property will change order of the actual position of the tab. 1.109 + * @type {Number} 1.110 + */ 1.111 + get index() { 1.112 + if (tabNS(this).closed) return undefined; 1.113 + 1.114 + let tabs = tabNS(this).window.BrowserApp.tabs; 1.115 + let tab = tabNS(this).tab; 1.116 + for (var i = tabs.length; i >= 0; i--) { 1.117 + if (tabs[i] === tab) 1.118 + return i; 1.119 + } 1.120 + return null; 1.121 + }, 1.122 + set index(value) { 1.123 + console.error(ERR_FENNEC_MSG); // TODO 1.124 + }, 1.125 + 1.126 + /** 1.127 + * Whether or not tab is pinned (Is an app-tab). 1.128 + * @type {Boolean} 1.129 + */ 1.130 + get isPinned() { 1.131 + console.error(ERR_FENNEC_MSG); // TODO 1.132 + return false; // TODO 1.133 + }, 1.134 + pin: function pin() { 1.135 + console.error(ERR_FENNEC_MSG); // TODO 1.136 + }, 1.137 + unpin: function unpin() { 1.138 + console.error(ERR_FENNEC_MSG); // TODO 1.139 + }, 1.140 + 1.141 + /** 1.142 + * Returns the MIME type that the document loaded in the tab is being 1.143 + * rendered as. 1.144 + * @type {String} 1.145 + */ 1.146 + get contentType() getTabContentType(tabNS(this).tab), 1.147 + 1.148 + /** 1.149 + * Create a worker for this tab, first argument is options given to Worker. 1.150 + * @type {Worker} 1.151 + */ 1.152 + attach: function attach(options) { 1.153 + // BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946 1.154 + // TODO: fix this circular dependency 1.155 + let { Worker } = require('./worker'); 1.156 + return Worker(options, getTabContentWindow(tabNS(this).tab)); 1.157 + }, 1.158 + 1.159 + /** 1.160 + * Make this tab active. 1.161 + */ 1.162 + activate: function activate() { 1.163 + activateTab(tabNS(this).tab, tabNS(this).window); 1.164 + }, 1.165 + 1.166 + /** 1.167 + * Close the tab 1.168 + */ 1.169 + close: function close(callback) { 1.170 + let tab = this; 1.171 + this.once(EVENTS.close.name, function () { 1.172 + tabNS(tab).closed = true; 1.173 + if (callback) callback(); 1.174 + }); 1.175 + 1.176 + closeTab(tabNS(this).tab); 1.177 + }, 1.178 + 1.179 + /** 1.180 + * Reload the tab 1.181 + */ 1.182 + reload: function reload() { 1.183 + tabNS(this).tab.browser.reload(); 1.184 + } 1.185 +}); 1.186 +exports.Tab = Tab; 1.187 + 1.188 +// Implement `viewFor` polymorphic function for the Tab 1.189 +// instances. 1.190 +viewFor.define(Tab, x => tabNS(x).tab); 1.191 + 1.192 +function cleanupTab(tab) { 1.193 + let tabInternals = tabNS(tab); 1.194 + if (!tabInternals.tab) 1.195 + return; 1.196 + 1.197 + if (tabInternals.tab.browser) { 1.198 + tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady, false); 1.199 + tabInternals.tab.browser.removeEventListener(EVENTS.pageshow.dom, tabInternals.onPageShow, false); 1.200 + tabInternals.tab.browser.removeEventListener(EVENTS.load.dom, tabInternals.onLoad, true); 1.201 + } 1.202 + tabInternals.onReady = null; 1.203 + tabInternals.onPageShow = null; 1.204 + tabInternals.onLoad = null; 1.205 + tabInternals.window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, tabInternals.onClose, false); 1.206 + tabInternals.onClose = null; 1.207 + rawTabNS(tabInternals.tab).tab = null; 1.208 + tabInternals.tab = null; 1.209 + tabInternals.window = null; 1.210 +} 1.211 + 1.212 +function onTabReady(event) { 1.213 + let win = event.target.defaultView; 1.214 + 1.215 + // ignore frames 1.216 + if (win === win.top) { 1.217 + emit(this, 'ready', this); 1.218 + } 1.219 +} 1.220 + 1.221 +function onTabLoad (event) { 1.222 + let win = event.target.defaultView; 1.223 + 1.224 + // ignore frames 1.225 + if (win === win.top) { 1.226 + emit(this, 'load', this); 1.227 + } 1.228 +} 1.229 + 1.230 +function onTabPageShow(event) { 1.231 + let win = event.target.defaultView; 1.232 + if (win === win.top) 1.233 + emit(this, 'pageshow', this, event.persisted); 1.234 +} 1.235 + 1.236 +// TabClose 1.237 +function onTabClose(event) { 1.238 + let rawTab = getTabForBrowser(event.target); 1.239 + if (tabNS(this).tab !== rawTab) 1.240 + return; 1.241 + 1.242 + emit(this, EVENTS.close.name, this); 1.243 + cleanupTab(this); 1.244 +}; 1.245 + 1.246 +getPBOwnerWindow.define(Tab, function(tab) { 1.247 + return getTabContentWindow(tabNS(tab).tab); 1.248 +});