tab-fennec.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. const { Cc, Ci } = require('chrome');
  6. const { Class } = require('../core/heritage');
  7. const { tabNS, rawTabNS } = require('./namespace');
  8. const { EventTarget } = require('../event/target');
  9. const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, getTabContentWindow,
  10. getTabForBrowser,
  11. setTabURL, getOwnerWindow, getTabContentType, getTabId } = require('./utils');
  12. const { emit } = require('../event/core');
  13. const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
  14. const { when: unload } = require('../system/unload');
  15. const { viewFor } = require('../view/core');
  16. const { EVENTS } = require('./events');
  17. const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
  18. const Tab = Class({
  19. extends: EventTarget,
  20. initialize: function initialize(options) {
  21. options = options.tab ? options : { tab: options };
  22. let tab = options.tab;
  23. EventTarget.prototype.initialize.call(this, options);
  24. let tabInternals = tabNS(this);
  25. rawTabNS(tab).tab = this;
  26. let window = tabInternals.window = options.window || getOwnerWindow(tab);
  27. tabInternals.tab = tab;
  28. // TabReady
  29. let onReady = tabInternals.onReady = onTabReady.bind(this);
  30. tab.browser.addEventListener(EVENTS.ready.dom, onReady, false);
  31. let onPageShow = tabInternals.onPageShow = onTabPageShow.bind(this);
  32. tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow, false);
  33. // TabClose
  34. let onClose = tabInternals.onClose = onTabClose.bind(this);
  35. window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onClose, false);
  36. unload(cleanupTab.bind(null, this));
  37. },
  38. /**
  39. * The title of the page currently loaded in the tab.
  40. * Changing this property changes an actual title.
  41. * @type {String}
  42. */
  43. get title() getTabTitle(tabNS(this).tab),
  44. set title(title) setTabTitle(tabNS(this).tab, title),
  45. /**
  46. * Location of the page currently loaded in this tab.
  47. * Changing this property will loads page under under the specified location.
  48. * @type {String}
  49. */
  50. get url() {
  51. return tabNS(this).closed ? undefined : getTabURL(tabNS(this).tab);
  52. },
  53. set url(url) setTabURL(tabNS(this).tab, url),
  54. /**
  55. * URI of the favicon for the page currently loaded in this tab.
  56. * @type {String}
  57. */
  58. get favicon() {
  59. /*
  60. * Synchronous favicon services were never supported on Fennec,
  61. * and as of FF22, are now deprecated. When/if favicon services
  62. * are supported for Fennec, this getter should reference
  63. * `require('sdk/places/favicon').getFavicon`
  64. */
  65. console.error(
  66. 'tab.favicon is deprecated, and currently ' +
  67. 'favicon helpers are not yet supported by Fennec'
  68. );
  69. // return 16x16 blank default
  70. return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAEklEQVQ4jWNgGAWjYBSMAggAAAQQAAF/TXiOAAAAAElFTkSuQmCC';
  71. },
  72. getThumbnail: function() {
  73. // TODO: implement!
  74. console.error(ERR_FENNEC_MSG);
  75. // return 80x45 blank default
  76. return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC';
  77. },
  78. get id() {
  79. return getTabId(tabNS(this).tab);
  80. },
  81. /**
  82. * The index of the tab relative to other tabs in the application window.
  83. * Changing this property will change order of the actual position of the tab.
  84. * @type {Number}
  85. */
  86. get index() {
  87. if (tabNS(this).closed) return undefined;
  88. let tabs = tabNS(this).window.BrowserApp.tabs;
  89. let tab = tabNS(this).tab;
  90. for (var i = tabs.length; i >= 0; i--) {
  91. if (tabs[i] === tab)
  92. return i;
  93. }
  94. return null;
  95. },
  96. set index(value) {
  97. console.error(ERR_FENNEC_MSG); // TODO
  98. },
  99. /**
  100. * Whether or not tab is pinned (Is an app-tab).
  101. * @type {Boolean}
  102. */
  103. get isPinned() {
  104. console.error(ERR_FENNEC_MSG); // TODO
  105. return false; // TODO
  106. },
  107. pin: function pin() {
  108. console.error(ERR_FENNEC_MSG); // TODO
  109. },
  110. unpin: function unpin() {
  111. console.error(ERR_FENNEC_MSG); // TODO
  112. },
  113. /**
  114. * Returns the MIME type that the document loaded in the tab is being
  115. * rendered as.
  116. * @type {String}
  117. */
  118. get contentType() getTabContentType(tabNS(this).tab),
  119. /**
  120. * Create a worker for this tab, first argument is options given to Worker.
  121. * @type {Worker}
  122. */
  123. attach: function attach(options) {
  124. // BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946
  125. // TODO: fix this circular dependency
  126. let { Worker } = require('./worker');
  127. return Worker(options, getTabContentWindow(tabNS(this).tab));
  128. },
  129. /**
  130. * Make this tab active.
  131. */
  132. activate: function activate() {
  133. activateTab(tabNS(this).tab, tabNS(this).window);
  134. },
  135. /**
  136. * Close the tab
  137. */
  138. close: function close(callback) {
  139. let tab = this;
  140. this.once(EVENTS.close.name, function () {
  141. tabNS(tab).closed = true;
  142. if (callback) callback();
  143. });
  144. closeTab(tabNS(this).tab);
  145. },
  146. /**
  147. * Reload the tab
  148. */
  149. reload: function reload() {
  150. tabNS(this).tab.browser.reload();
  151. }
  152. });
  153. exports.Tab = Tab;
  154. // Implement `viewFor` polymorphic function for the Tab
  155. // instances.
  156. viewFor.define(Tab, x => tabNS(x).tab);
  157. function cleanupTab(tab) {
  158. let tabInternals = tabNS(tab);
  159. if (!tabInternals.tab)
  160. return;
  161. if (tabInternals.tab.browser) {
  162. tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady, false);
  163. tabInternals.tab.browser.removeEventListener(EVENTS.pageshow.dom, tabInternals.onPageShow, false);
  164. }
  165. tabInternals.onReady = null;
  166. tabInternals.onPageShow = null;
  167. tabInternals.window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, tabInternals.onClose, false);
  168. tabInternals.onClose = null;
  169. rawTabNS(tabInternals.tab).tab = null;
  170. tabInternals.tab = null;
  171. tabInternals.window = null;
  172. }
  173. function onTabReady(event) {
  174. let win = event.target.defaultView;
  175. // ignore frames
  176. if (win === win.top) {
  177. emit(this, 'ready', this);
  178. }
  179. }
  180. function onTabPageShow(event) {
  181. let win = event.target.defaultView;
  182. if (win === win.top)
  183. emit(this, 'pageshow', this, event.persisted);
  184. }
  185. // TabClose
  186. function onTabClose(event) {
  187. let rawTab = getTabForBrowser(event.target);
  188. if (tabNS(this).tab !== rawTab)
  189. return;
  190. emit(this, EVENTS.close.name, this);
  191. cleanupTab(this);
  192. };
  193. getPBOwnerWindow.define(Tab, function(tab) {
  194. return getTabContentWindow(tabNS(tab).tab);
  195. });