User:Asqueella/JEP 107: Difference between revisions

update with summary of discussion, deemphasize style mods
(update with summary of discussion, deemphasize style mods)
Line 5: Line 5:
----
----


There are two common ways to modify web pages from the browser:
== JEP 107 - Page Mods ==
* by specifying custom CSS to apply to specific pages, sites, or all web content. (This is what [https://addons.mozilla.org/en-US/firefox/addon/2108 Stylish extension] does.)
* by letting specified scripts run modify the web page (see [https://addons.mozilla.org/en-US/firefox/addon/748 Greasemonkey extension])


The CSS-only approach is less powerful, yet often simpler and allows to dynamically apply and cancel custom style modifications to the page.
* Champion: Nickolay Ponomarev <asqueella@gmail.com>
* Status: ?
* Bug Ticket: {{bug|546739}}
* Type: API


The JavaScript-based approach allows virtually any changes to the page to be implemented, but requires special (and non-trivial) effort to implement instant application and undoing of these modifications.
=== Proposal ===
Introduce an API allowing jetpacks to run script whenever a content page the jetpack is interested in loads.


This proposal focuses on the JavaScript-based approach.
This way of enhancing functionality of web sites was popularized by the [https://addons.mozilla.org/en-US/firefox/addon/748 Greasemonkey extension]. Unlike Greasemonkey scripts, in this proposal the pagemod's scripts all share the same Jetpack context and have the same privileges as the jetpack itself (but see [[#Discussion - e10s]] below).


=== Script Mods ===
=== Use Cases ===
* Porting Greasemonkey-style scripts to Jetpack (see [http://ehsanakhgari.org/blog/2010-01-07/bugzilla-tweaks-enhanced Bugzilla tweaks] for Jetpack prototype for example)
* Implementing scripts that enhance certain sites, while also having access to higher-privileged APIs.
* Adding methods and properties to the global window. For example, window.geolocation could have been implemented as a jetpack, and we could implement window.camera or window.microphone as a jetpack in the future. (via bsmedberg)
 
=== Non-Use Cases ===
* Porting Stylish-like CSS-based modifications to Jetpack (this could be added in a later version of the API)
 
=== Dependencies & Requirements ===
* <code>onWindowCreate</code> and current implementation of the module in general requires {{bug|549539}}'s fix, which (as of 2010-05-26) has only landed on mozilla-central (Firefox versions after 3.6.x). The plans are to land it on 3.6.x too, though.
* Making this API work in [[Electrolysis/Jetpack]] requires additional effort from the e10s team (see details on that page)
 
=== API Methods ===
Here's an example of how the ScriptMod API can be used in a jetpack:
Here's an example of how the ScriptMod API can be used in a jetpack:


Line 42: Line 56:


The <code>onDOMReady</code> callback is called as soon as the page's DOM is ready (on the [http://wiki.greasespot.net/DOMContentLoaded <code>DOMContentLoaded</code>] event)
The <code>onDOMReady</code> callback is called as soon as the page's DOM is ready (on the [http://wiki.greasespot.net/DOMContentLoaded <code>DOMContentLoaded</code>] event)
==== Dependencies ====
* This module requires {{bug|549539}}'s fix, which (as of 2010-04-02) has only landed on mozilla-central (Firefox versions after 3.6.x). The plans are to land it on 3.6.x too, though.
* It's not clear to me where the [[Labs/Jetpack/Reboot/JEP/107#Dependencies_.26_Requirements|dependencies in the original JEP]] come from, perhaps some of them apply to this case too.


==== <code>ScriptMod</code> constructor ====
==== <code>ScriptMod</code> constructor ====
Line 53: Line 63:
** Providing a string value <code>str</code> is equivalent to providing a single-item array <code>[str]</code>.
** Providing a string value <code>str</code> is equivalent to providing a single-item array <code>[str]</code>.
** The mod's scripts run on pages, matching ''any'' of <code>include</code> rules.
** The mod's scripts run on pages, matching ''any'' of <code>include</code> rules.
** Each <code>include</code> rule is a string using one of the following formats (see discussion below):
** Each <code>include</code> rule is a string using one of the following formats (see [[#Discussion - format for include|discussion below]]):
**# <code>*</code> (a single asterisk) - any page
**# <code>*</code> (a single asterisk) - any page
**# <code>*.domain.name</code> - pages from the specified domain and all its subdomains, regardless of their scheme.
**# <code>*.domain.name</code> - pages from the specified domain and all its subdomains, regardless of their scheme.
**# <code><nowiki>http://example.com/*</nowiki></code> - any URLs with the specified prefix.
**# <code><nowiki>http://example.com/*</nowiki></code> - any URLs with the specified prefix.
**# <code><nowiki>http://example.com/test</nowiki></code> - the single specified URL
**# <code><nowiki>http://example.com/test</nowiki></code> - the single specified URL
* '''TBD:''' <code>filter</code> function instead of (or in addition) to <code>exclude</code>.
* <code>onWindowCreate</code>, <code>onDOMReady</code>: optional parameters specifying the code to run on the matched pages.
* <code>onWindowCreate</code>, <code>onDOMReady</code>: optional parameters specifying the code to run on the matched pages.
** No code is run if these parameters are not specified.
** No code is run if these parameters are not specified.
Line 71: Line 80:
Creating a <code>ScriptMod</code> instance automatically [[#scriptMod-enable|enables it]].
Creating a <code>ScriptMod</code> instance automatically [[#scriptMod-enable|enables it]].


===== ISSUE: What format should be chosen for <code>include</code> rules? =====
==== <code>ScriptMod</code> APIs ====
* Instance properties
** <code id="scriptMod-disable">scriptMod.disable()</code>. Call this to stop a script mod from running on further pages. This does not undo the mod's effects on already loaded pages.
** <code id="scriptMod-enable">scriptMod.enable()</code>. Enabling a script mod makes it take effect on any matching pages that start to load after the script mod is enabled. Enabling a script mod does not apply it to existing matching pages.
 
=== Discussion ===
 
Extracted from [http://groups.google.com/group/mozilla-labs-jetpack/browse_thread/thread/09deffcc11fa00ea/2ce4c1ed979cb8da this thread].
 
==== Discussion - format for <code>include</code> ====
First, a short survey of existing formats:
First, a short survey of existing formats:
* [http://wiki.greasespot.net/Include_and_exclude_rules Greasemonkey scripts] specify include and exclude URLs, each may contain wildcards ("*") in any location and may use a special ".tld" domain. These rules get compiled to a regular expression (see [http://github.com/greasemonkey/greasemonkey/blob/master/content/convert2RegExp.js convert2RegExp]), which is then matched against every URL loaded in the browser.
* [http://wiki.greasespot.net/Include_and_exclude_rules Greasemonkey scripts] specify include and exclude URLs, each may contain wildcards ("*") in any location and may use a special ".tld" domain. These rules get compiled to a regular expression (see [http://github.com/greasemonkey/greasemonkey/blob/master/content/convert2RegExp.js convert2RegExp]), which is then matched against every URL loaded in the browser.
Line 79: Line 97:


[http://groups.google.com/group/mozilla-labs-jetpack/msg/decd886a1ae37018 Myk's thoughts], "I need to take a closer look at this, but at first glance it looks like Chrome's format balances these goals best."
[http://groups.google.com/group/mozilla-labs-jetpack/msg/decd886a1ae37018 Myk's thoughts], "I need to take a closer look at this, but at first glance it looks like Chrome's format balances these goals best."
==== Discussion - e10s ====
Context: in the 0.5 timeframe it is planned to move jetpacks to their own processes, as described on the [[Electrolysis/Jetpack]] page. In the long term, content tabs will run in their own processes as well ("out-of-process tabs").
Communication between different processes is not entirely transparent [http://groups.google.com/group/mozilla-labs-jetpack/msg/8a06fdd83b71242c]: while the jetpack process will be able to call content functions, reference content objects and pass primitive values to content, content won't be able to hold references to jetpack objects. This means it won't be possible to pass a jetpack-defined callback to content functions (with a few possible exceptions).
From the discussion referenced above, there are different possible models of pagemods execution (implying different implementation requirements):
<pre>
A. run a script in the web page context, and let it communicate with the
jetpack via postMessage-style APIs. [...]
B. run a script in the jetpack context and pass it the window/document for a
page being loaded. This requires CPOW wrappers, which have some limitations[...]
C. Run page mods in the content processes (to avoid getting involved with CPOWs
and their limitations), but in a separate context from the page (to make it
possible to write page mods that can do things that we don't want to expose
to regular pages). My understanding is that it is similar to what Google
Chrome does and similar to what Greasemonkey does.
</pre>
This proposal currently specifies (B). Comments collected from the discussion:
* on A:
** [Benjamin] This is trivially straightforward to do in a multi-process world[...]. But there are issues with polluting the content script namespace (e.g. if the jetpack needs to define functions).
** [Nickolay] this means we can't give it [the jetpack script in content] any additional privileges (e.g. by listening for postMessage'd requests asking to do something that requires chrome permissions or by providing additional APIs like GM_* in Greasemonkey). It's fine for simple scripts, but not in general, I think.
* on B:
** [Myk] Despite the limitations imposed by the requirement for CPOW wrappers, its developer ergonomics appeal to me. It's not yet clear what the relative security implications are, however.
** [Nickolay] thinks that inability to register a callback is a major flaw for those who need it (cited the case of using [http://code.google.com/p/gmail-greasemonkey/wiki/GmailGreasemonkey10API Gmail's Greasemonkey API] to get notified of changes in the web app)
* on C:
** [Nickolay] suggested this as an optional addition to (B) for scripts that need transparent interaction with content.
** [Benjamin] That's attractive in some ways, but it breaks the normal jetpack behavior of being a single script that does everything. I'm not sure it's worth breaking that programming model.
** '''Requires additional code in the single-process case, additions to the platform in the e10s case.'''
==== Discsussion - comparison to the original JEP ====
This JEP has three main differences from the [[Labs/Jetpack/Reboot/JEP/107|original JEP 107]]:
* CSS-based mods were deferred to a later version of the API.
* This JEP doesn't promise enabling/disabling page mods "instantly", since I don't see a way to implement it.
* Scripts in the original JEP run in the context of the page, while in this JEP they run in the jetpack context. Although it's an important feature, I think it can be implemented separately, since it requires substantially more effort and additional coordination for e10s.
* <code>add/remove/empty</code> methods on the page mod object were not included, since there's no clear use case for them, especially if the changes are not applied instantly, as in this proposal.


===== Other issues =====
===== Other issues =====
(Not discussed in the google groups thread)
* There's no easy way to clean up objects referenced from the web page (event listeners, exported APIs) when a jetpack using script mods is unloaded.
* There's no easy way to clean up objects referenced from the web page (event listeners, exported APIs) when a jetpack using script mods is unloaded.
* Since the design makes a promise to let one module hosting the script mod to touch a random set of sites, it's not clear if this is going to work well in the out of process tabs world.
* Should provide an example of using jQuery in a script mod. It's likely possible, but not obvious, given that the script mod runs in a hosting module's scope.
* Should provide an example of using jQuery in a script mod. It's likely possible, but not obvious, given that the script mod runs in a hosting module's scope.


==== <code>ScriptMod</code> APIs ====
=== TODO ===
* Instance properties
* For SDK 0.5:
** <code id="scriptMod-disable">scriptMod.disable()</code>. Call this to stop a script mod from running on further pages. This does not undo the mod's effects on already loaded pages.
*# Finalize the format for "include" rules and implement the necessary changes.
** <code id="scriptMod-enable">scriptMod.enable()</code>. Enabling a script mod makes it take effect on any matching pages that start to load after the script mod is enabled. Enabling a script mod does not apply it to existing matching pages.
*# Identify changes required for [[Electrolysis/Jetpack]] and implement them.
** ''<code>add/remove/empty</code> from the [[Labs/Jetpack/Reboot/JEP/107|original proposal]] appear inessential, especially if the changes are not applied instantly, as in this proposal.''
* Post-0.5:
* Helper functions available as properties on the <code>ScriptMod</code> constructor.
*# Possible API enhancements:
** TBD other helpers (insert <style>s, <script>s, etc.)
*#* implement helper functions for common actions (insert <style>s, <script>s, etc.)
 
*#* <code>filter</code> function instead of (or in addition) to <code>exclude</code>.
=== Style mods ===
*#* CSS-based mods
TBD
*# Provide a way to run scripts in separate context for each page (i.e. in the content process for out-of-process tabs)
Confirmed users
161

edits