Labs/Jetpack/Reboot/JEP/110: Difference between revisions

 
(9 intermediate revisions by 3 users not shown)
Line 1: Line 1:
== JEP 110 - Tabs ==
= JEP 110 - Tabs =


* Champion: Aza Raskin - aza@mozilla.com
* Champion: Myk Melez <myk@mozilla.org>
* Status: Accepted/In-Queue
* Status: Approved
* Bug Ticket:
* Bug Ticket: {{bug|549317}}
* Type: API
* Type: API


= Introduction =


=== Proposal ===
Tabs are a fundamental element of the browser.  Add-ons should have access to them.


Tabs are a fundamental unit of the browser (for now). We need reasonable ways
= Use Cases =
of interacting with them.


Import lives in the "tabs" module.
* move a tab to be the first tab, or re-order tabs based on semantic grouping;
* close a set of tabs;
* open a new tab to a contextually aware location;
* change the background color of the currently active tab;
* change the color of the background of a tab-handle;
* show the Delicious tab-o-meter of the current tab.


<pre class="brush:js">
= Interface =
/**
/* tabs is an immutable array of Tab objects
/**
tabs = require("tabs");


/**
== <tt>tabs</tt> module ==
/* These are global callbacks that come into affect when
/* any of these happen to any tab.
/* @param eventName {string}
/*        Is one of focus, blur, close, open, load, domready, mozafterpaint,
/*        move
/* @param callback {function}
/*        The function gets passed an "event" object and the the "this" of
/*        that function is the tab in question.
/**
tabs.bind( eventName, callback );


/**
The <tt>tabs</tt> module provides the API. It exports one symbol: the <tt>tabs</tt> singleton.
/* Unbinds the event handler
/* Without any arguments, all bound events are removed. You can also unbind
/* custom events registered with bind. If the type is provided, all bound
/* events of that type are removed. If the function that was passed to bind is
/* provided as the second argument, only that specific event handler is
/* removed.
/* @param [eventName] {string}
/* @param [func] {function}
/**
tabs.bind( eventName, func );


/**
let tabs = require("tabs").tabs;
/* This causes an event to occur or a message to be sent to all tabs.
/* @param eventName {string}
/*        The event to trigger. For now this is only "open"
/* @param data {string|object}
/*        In the case of open this is the URL, if this is a dictionary
/*        then otherData won't be needed.
/* @param [otherData] {object}
/*        Other data to be passed to the event handler.
/**
tabs.trigger( eventName, data, otherData )


/**
== <tt>tabs</tt> singleton ==
/* The properties of the tab.
/* @prop activeTab {Tab}
/*      The currently active tab
/**
tabs.property


// Get one of the tab objects
=== Properties ===
var tab = tab[0];


/**
The <tt>tabs</tt> singleton has one property, <tt>activeTab</tt>, which is a <tt>Tab</tt> object that represents the currently active tab.
/* Same as for tabs, but effects the particular tab in question.
/**
tab.bind( eventName, callback )


/**
=== Methods ===
/* Same as for tabs, but effects the particular tab in question.
/**
tab.unbind( eventName, callback )


/**
The <tt>tabs</tt> singleton has one method, <tt>open</tt>, which opens a new tab:
/* Mostly the same as for the tabs case, the only difference being:
/* @param eventName {string}
/*        Is one of focus, close, load, move
/**
tab.trigger( eventName, data, otherData )


/**
/**
/* The properties for the tabs.
  * Open a new tab.
/* @prop style {cssStyleString}
  * @param url {URL} the URL to load in the tab; optional;
/*      The css style string for the tab.
  *       if not provided, about:blank will be loaded in the tab
/* @prop index {integer}
  * @param window {Window} the window in which to open the tab;
/*       The index the tab is displayed at in its parent window
  *       optional; if not provided, the tab will be opened
/* @prop location {url} URL of the tab
  *       in the most recently active application window
/* @prop title {string} The title of the page
  **/
/* @prop favicon {url} URL of the displayed favicon
tabs.open(url, window)
/* @prop [window] {jetpack window} The window the tab belongs to
/* @prop [thumbnail] {canvas} A thumbnail of the currently displayed page   
/**
tab.property


</pre>
=== Callbacks ===


== Sugar Functions ==
The <tt>tabs</tt> singleton has a number of event callback properties with which consumers can register callback functions via the standard mechanisms as described in the [[Labs/Jetpack/Design_Guidelines|design guidelines]]:


<pre class="brush:js">
; onActivate: a tab is activated, whether programmatically or by user action (clicking on the tab, switching windows, etc.)
; onDeactivate: a tab is deactivated
; onOpen: a tab is opened
; onClose: a tab is closed
; onReady: the text content of a top-level document in a tab has been loaded and parsed into a DOMDocument object (i.e. the <tt>DOMContentLoaded</tt> event has occurred)
; onLoad: the text, image, style, and script content of a top-level document in a tab has been loaded (i.e. the DOM <tt>load</tt> event has occurred)
; onPaint: the visual representation of a top-level document in a tab has changed (i.e. the <tt>MozAfterPaint</tt> event has occurred)


// Sugar for tabs.on functionality
When a callback function is called, its first parameter is an <tt>Event</tt> object representing the event that occurred, and its second parameter is a <tt>Tab</tt> object representing the tab on which it occurred, i.e.:
tabs.onFocus( function )
tabs.onBlur( function )
tabs.onClose( function )
tabs.onOpen( function )
tabs.onLoad( function )
tabs.onDomReady( function )
...
// and the same for each Tab instance.


// Sugar for tabs.trigger functionality
tabs.onActivate = function(event, tab) { ... };
tabs.open( url, options )
...
// And the same for each Tab instance, plus
tab.move( index, options )
// index = absolute index, "+3"/"-1" for relative
// options for moving to other windows
</pre>


=== Difficulty ===
When the <tt>tabs</tt> singleton is iterated via <tt>[https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for_each...in for each...in]</tt>, it yields a sequence of <tt>Tab</tt> objects representing the tabs in all application windows:


This is a medium difficulty to implement, but made easier by a pre-existing implementation.
for each (let tab in tabs) { ... }


=== Key Issues ===
The order by which tabs are returned in the iteration is not specified, may change in the future, and should not be counted upon.


== <tt>Tab</tt> objects ==


=== Dependencies & Requirements ===
=== Properties ===
* Are there any Firefox platform bugs blocking it?
* Does other Jetpack platform code need to be modified or added?
* Does its implementation affect any other projects or code?


<tt>Tab</tt> objects have the following properties:


=== Internal Methods ===
/**
* What methods, mechanisms, or resources does this provide internally within the Jetpack platform code.
  * The properties for the tabs.
  * @prop title {String}
  *      the title of the page currently loaded in the tab
  * @prop location {URL}
  *      the URL of the page currently loaded in the tab
  * @prop contentWindow {DOMWindow}
  *      the window object for the page currently loaded in the tab
  * @prop contentDocument {DOMDocument}
  *      the document object for the page currently loaded in the tab
  * @prop favicon {URL}
  *      the URL of the favicon for the page currently loaded in the tab
  * @prop style {String}
  *      the CSS style for the tab
  * @prop index {Number}
  *      the index of the tab relative to other tabs in the application window
  * @prop window {Window}
  *      the window to which the tab belongs
  * @prop thumbnail {Canvas}
  *      a thumbnail of the page currently loaded in the tab
**/
tab.property


=== Methods ===


=== API Methods ===
<tt>Tab</tt> objects have the following methods:
* What are the pretty API wrapped methods externally exposed to Jetpack developers?
 
/**
  * Make this the active tab.
  **/
tab.activate()
/**
  * Load a URL in the tab.
  * @param url {URL} the URL to load in the tab
  **/
tab.load(url)
/**
  * Close the tab.
  **/
tab.close()
/**
  * Move the tab within the window-specific set of tabs to which it belongs.
  * @param index {Number}
  *        the new location in the tab set
  * @param window {Window}
  *        the new window; optional if moving to a new location
  *        within the existing window
  **/
tab.move(index, window)
 
=== Callbacks ===
 
<tt>Tab</tt> objects have the same event callback properties as the <tt>tabs</tt> singleton, except that they don't have the <tt>onOpen</tt> callback.
 
= Implementation Phases =
 
== Phase One ==
 
In the first phase of development, the following elements of the API should be implemented:
 
* <tt>tabs</tt> singleton
** properties:
*** activeTab
** methods:
*** open
** callbacks:
*** onActivate
*** onDeactivate
*** onOpen
*** onClose
*** onLoad
* <tt>Tab</tt> objects
** properties
*** title
*** location
*** contentWindow
*** contentDocument
** methods
*** activate
*** load
*** close
** callbacks
*** onActivate
*** onDeactivate
*** onClose
*** onLoad
Confirmed users, Bureaucrats and Sysops emeriti
2,088

edits