summaryrefslogtreecommitdiffstats
path: root/toolkit/jetpack/sdk/tabs/tab-fennec.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/jetpack/sdk/tabs/tab-fennec.js')
-rw-r--r--toolkit/jetpack/sdk/tabs/tab-fennec.js249
1 files changed, 249 insertions, 0 deletions
diff --git a/toolkit/jetpack/sdk/tabs/tab-fennec.js b/toolkit/jetpack/sdk/tabs/tab-fennec.js
new file mode 100644
index 000000000..3927337f6
--- /dev/null
+++ b/toolkit/jetpack/sdk/tabs/tab-fennec.js
@@ -0,0 +1,249 @@
+/* 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() {
+ return 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() {
+ return 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;
+});