Files
tubestation/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
2015-06-30 15:10:35 -07:00

242 lines
6.6 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { Cc, Ci } = require('chrome');
const { Class } = require('../core/heritage');
const { tabNS, rawTabNS } = require('./namespace');
const { EventTarget } = require('../event/target');
const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL,
getTabContentWindow, getTabForBrowser, setTabURL, getOwnerWindow,
getTabContentDocument, getTabContentType, getTabId, isTab } = require('./utils');
const { emit } = require('../event/core');
const { isPrivate } = require('../private-browsing/utils');
const { isWindowPrivate } = require('../window/utils');
const { when: unload } = require('../system/unload');
const { BLANK } = require('../content/thumbnail');
const { viewFor } = require('../view/core');
const { EVENTS } = require('./events');
const { modelFor } = require('../model/core');
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
const Tab = Class({
extends: EventTarget,
initialize: function initialize(options) {
options = options.tab ? options : { tab: options };
let tab = options.tab;
EventTarget.prototype.initialize.call(this, options);
let tabInternals = tabNS(this);
rawTabNS(tab).tab = this;
let window = tabInternals.window = options.window || getOwnerWindow(tab);
tabInternals.tab = tab;
// TabReady
let onReady = tabInternals.onReady = onTabReady.bind(this);
tab.browser.addEventListener(EVENTS.ready.dom, onReady, false);
// TabPageShow
let onPageShow = tabInternals.onPageShow = onTabPageShow.bind(this);
tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow, false);
// TabLoad
let onLoad = tabInternals.onLoad = onTabLoad.bind(this);
tab.browser.addEventListener(EVENTS.load.dom, onLoad, true);
// TabClose
let onClose = tabInternals.onClose = onTabClose.bind(this);
window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onClose, false);
unload(cleanupTab.bind(null, this));
},
/**
* The title of the page currently loaded in the tab.
* Changing this property changes an actual title.
* @type {String}
*/
get title() getTabTitle(tabNS(this).tab),
set title(title) setTabTitle(tabNS(this).tab, title),
/**
* Location of the page currently loaded in this tab.
* Changing this property will loads page under under the specified location.
* @type {String}
*/
get url() {
return tabNS(this).closed ? undefined : getTabURL(tabNS(this).tab);
},
set url(url) setTabURL(tabNS(this).tab, url),
getThumbnail: function() {
// TODO: implement!
console.error(ERR_FENNEC_MSG);
// return 80x45 blank default
return BLANK;
},
/**
* tab's document readyState, or 'uninitialized' if it doesn't even exist yet.
*/
get readyState() {
let doc = getTabContentDocument(tabNS(this).tab);
return doc && doc.readyState || 'uninitialized';
},
get id() {
return getTabId(tabNS(this).tab);
},
/**
* The index of the tab relative to other tabs in the application window.
* Changing this property will change order of the actual position of the tab.
* @type {Number}
*/
get index() {
if (tabNS(this).closed) return undefined;
let tabs = tabNS(this).window.BrowserApp.tabs;
let tab = tabNS(this).tab;
for (var i = tabs.length; i >= 0; i--) {
if (tabs[i] === tab)
return i;
}
return null;
},
set index(value) {
console.error(ERR_FENNEC_MSG); // TODO
},
/**
* Whether or not tab is pinned (Is an app-tab).
* @type {Boolean}
*/
get isPinned() {
console.error(ERR_FENNEC_MSG); // TODO
return false; // TODO
},
pin: function pin() {
console.error(ERR_FENNEC_MSG); // TODO
},
unpin: function unpin() {
console.error(ERR_FENNEC_MSG); // TODO
},
/**
* Returns the MIME type that the document loaded in the tab is being
* rendered as.
* @type {String}
*/
get contentType() getTabContentType(tabNS(this).tab),
/**
* Create a worker for this tab, first argument is options given to Worker.
* @type {Worker}
*/
attach: function attach(options) {
// BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946
// TODO: fix this circular dependency
let { Worker } = require('./worker');
return Worker(options, getTabContentWindow(tabNS(this).tab));
},
/**
* Make this tab active.
*/
activate: function activate() {
activateTab(tabNS(this).tab, tabNS(this).window);
},
/**
* Close the tab
*/
close: function close(callback) {
let tab = this;
this.once(EVENTS.close.name, function () {
tabNS(tab).closed = true;
if (callback) callback();
});
closeTab(tabNS(this).tab);
},
/**
* Reload the tab
*/
reload: function reload() {
tabNS(this).tab.browser.reload();
}
});
exports.Tab = Tab;
// Implement `viewFor` polymorphic function for the Tab
// instances.
viewFor.define(Tab, x => tabNS(x).tab);
function cleanupTab(tab) {
let tabInternals = tabNS(tab);
if (!tabInternals.tab)
return;
if (tabInternals.tab.browser) {
tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady, false);
tabInternals.tab.browser.removeEventListener(EVENTS.pageshow.dom, tabInternals.onPageShow, false);
tabInternals.tab.browser.removeEventListener(EVENTS.load.dom, tabInternals.onLoad, true);
}
tabInternals.onReady = null;
tabInternals.onPageShow = null;
tabInternals.onLoad = null;
tabInternals.window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, tabInternals.onClose, false);
tabInternals.onClose = null;
rawTabNS(tabInternals.tab).tab = null;
tabInternals.tab = null;
tabInternals.window = null;
}
function onTabReady(event) {
let win = event.target.defaultView;
// ignore frames
if (win === win.top) {
emit(this, 'ready', this);
}
}
function onTabLoad (event) {
let win = event.target.defaultView;
// ignore frames
if (win === win.top) {
emit(this, 'load', this);
}
}
function onTabPageShow(event) {
let win = event.target.defaultView;
if (win === win.top)
emit(this, 'pageshow', this, event.persisted);
}
// TabClose
function onTabClose(event) {
let rawTab = getTabForBrowser(event.target);
if (tabNS(this).tab !== rawTab)
return;
emit(this, EVENTS.close.name, this);
cleanupTab(this);
};
isPrivate.implement(Tab, tab => {
return isWindowPrivate(getTabContentWindow(tabNS(tab).tab));
});
// Implement `modelFor` function for the Tab instances.
modelFor.when(isTab, rawTab => {
return rawTabNS(rawTab).tab;
});