An argument you could raise on the surface would be to "get the stuff
you need via XHR from within the jetpack's js context". The catch is
that Google Maps and many other script solutions assume the presence
of DOM elements that they then rely on to perform their actions (a
instance of such needs can be seen in Google Maps' map bound related
geo calls: http://code.google.com/apis/maps/documentation/introduction.html#GLatLng)
Background pages enable DOM reliant mash-ups and make DOM fragment
creation based on those mash-ups easier. I for one really would like
to see this in the 0.2 feature set.
- Daniel
On Feb 19, 10:47 am, Myk Melez <m...@mozilla.org> wrote:
> It's not clear what the use cases for the background page JEP
> <https://wiki.mozilla.org/Labs/Jetpack/Reboot/JEP/108> are. I was
> talking with Atul about it, and he mentioned that the idea originated in
> the hidden window iframes I used in my original implementation of
> dynamic personas, which Atul then reused in some later work.
>
> Google Chrome implements a feature called Background Pages
> <http://code.google.com/chrome/extensions/background_pages.html> that
Thanks, that makes the utility of this feature much clearer!
-myk
-myk
- I didn't see on the API how the URL of the chosen page will be
specified. Will we allow both trusted and untrusted pages to be
opened?
- It is not very clear to me what are the directions of chrome access
to be allowed here. Will the webpage itself be able to have chrome
privileges (this is also related to the previous question), or just
the code that we specify to run [posibly periodally] on it?
Felipe
Hey Daniel, I have two questions about this proposed API:
- How will the URL of the page that we want on the background be
specified? Will we allow both trusted and untrusted pages to be
opened?
- I didn't quite comprehend the chrome privileges directions for the
API. For example, will the page (possibly untrusted?) running be able
to access chrome, or is it just the code that we set to run [possibly
periodically] on it that will have the jetpack's chrome context?
Thanks!
Felipe
Here is an example of one way to change the page location if there
wasn't a specific method exposed for it:
$page.run( function(){
window.location = 'addons.mozilla.org';
});
The functions you passed in would have their this contexts bound to
the window object of the Page Worker.
You could load trusted and untrusted pages into it, and here is an
example of a periodical function being run:
$page.run({ interval: 10000 }, function(){
return window.someNode;
});
Essentially, many web conventions assume the presence of a DOM, we
thought it would be nice to provide an open web sandbox for you in
addition to the Jetpack's more unique chrome sandbox.
The API examples are just strawman ideas, feedback is welcome! :)
On Apr 9, 4:05 pm, "Felipe Gomes (:felipe)" <felipe.go...@gmail.com>
wrote:
Anyway, I have a somewhat "pseudo-code" implementation going on, which
made me notice some finer details of the api that I wanted to get
feedback:
- why do you propose $page to be a global object? Wouldn't it be
better to be a regular module like the others? in this case a jetpack
would also be able to load various background-pages if desided. e.g.:
let Page = require("background-page");
let mypage1 = new Page();
mypage1.reset();
mypage1.run(function() {
return window.location;
});
- you suggested that if called with a interval or timeout parameter,
the return value of _run_ should be an array as: [timerId to clear it,
the return value of the function]. However, if using timeouts or
intervals, it doesn't make sense for the function to return any
values, since it won't be executed immediately. Should we just return
the timer id then?
(also, at this point I'm not sure that it's possible to return a value
in the immediate case either. It depends on how the code will be
injected.. I believe most of the methods to inject code will be
async.. This doesn't matter to this thread right now, I just wanted to
add an observation)
- and just to confirm, at some point it was mentioned Web Workers..
but we don't want to use real Web Workers to run the actions here,
right? As far as I know, Web Workers can't modify the DOM, and since
one of the main use cases is to access the DOM, we probably have to
stick with traditional functions
Felipe
Web Workers are something we should enable, but they are not dynamic
because they require a static js file to evaluate passed arguments.
DOM mods can be done asyncronously using document fragments.
Our goal with Page Workers, is to have a wide-open mash-up engine that
you can do really interesting things with in the context of a
persistant DOM++ environment.
On Apr 13, 10:00 pm, "Felipe Gomes (:felipe)" <felipe.go...@gmail.com>
In other words, the more CommonJS-compliant, but less usable way to
write your above code would be:
var backgroundPage = require("background-page");
var mypage1 = new backgroundPage.Page();
Ugh. Aside from the fact that it's very easy to forget new and spend the
next hour figuring out why your code doesn't work, this is part of why I
tend to favor factory functions over constructors, e.g.:
var mypage1 = require("background-page").create();
It's also worthwhile to note that due to the way JS' operator precedence
works, this code doesn't do what one would expect:
var mypage1 = new require("background-page").Page();
This actually associates the operand of new with require rather than
with Page. In other words, it's trying to use require as a constructor,
and the results are powerfully confusing. The "correct" way to write
the above code is something like:
var mypage1 = new (require("background-page")).Page();
But I'm not even sure, I'd have to check. :(
On the one hand, it's easy to bikeshed over this stuff, but on the
otherhand there are real developer ergonomics in play here, particularly
when we start considering how easy/hard it is for coders to accidentally
forget something and end up with hard-to-debug code.
- Atul
For the context menu module I've been using this helper:
function makePublicConstructor(privateCtor) {
return function PublicCtor() {
let obj = {
constructor: PublicCtor,
__proto__: privateCtor.prototype
};
privateCtor.apply(obj, arguments);
return obj;
};
}
It wraps a "private" constructor -- i.e., one not exported that needs to
be called with |new| -- with a function that can be used with or without
|new|. Used like this:
exports.PublicCtor = makePublicConstructor(PrivateCtor);
It makes a liar out of instanceof though, but I don't see a way around
that if we want to let people omit |new|.
Drew
I also didn't realize that we actually decided to write constructors in
the high-level APIs such that new doesn't need to be used--my bad.
However, I don't think this resolves the case of "new
require("foo").Thing()"; though perhaps one solution there is to have
require() check to make sure its this isn't a freshly-minted object or
something, and raise a helpful exception if so. I guess another
alternative might be to just tell folks not to use new, though I'm not
sure how we could communicate that effectively to everyone who uses Jetpack.
Oh, wait... There's another solution here, I think. The problem we're
trying to solve isn't so much that we want to let folks leave out
new--in fact, I'm a fan of Python's "there's only one way to do it"
philosophy--but rather that if folks do things in the "wrong" way, they
should be notified as early and as clearly as possible so they don't
have to waste the next hour(s) figuring out what's wrong. So in other
words, creating constructors like this might be a solution:
function Foo(x) {
if (this.console) {
// console is a Jetpack global that's always truthy, which means
// someone just called us without the `new` operator!
throw new Error("Please call this constructor with the 'new'
operator.");
}
}
This way we solve the problem while still allowing instanceof to be
used, and preserving interface monotony (i.e., "there's only one way to
do it").
Thoughts?
- Atul
> In other words, the more CommonJS-compliant, but less usable way to
> write your above code would be:
>
> var backgroundPage = require("background-page");
> var mypage1 = new backgroundPage.Page();
Or (for the common case in which the symbols of modules you import don't
overlap):
var Page = require("background-page").Page;
var mypage1 = new Page();
And, for APIs that export multiple exported symbols that a consumer
wants to access:
var { Foo: Foo, Bar: Bar, Baz: Baz } = require("metasyntactic-variables");
> The "correct" way to write the above code is something like:
>
> var mypage1 = new (require("background-page")).Page();
>
> But I'm not even sure, I'd have to check. :(
I think it may actually be:
var mypage1 = new (require("background-page").Page)();
> On the one hand, it's easy to bikeshed over this stuff, but on the
> otherhand there are real developer ergonomics in play here,
> particularly when we start considering how easy/hard it is for coders
> to accidentally forget something and end up with hard-to-debug code.
Yup, so it's worth discussing at length and depth, despite the danger of
the bikeshed.
-myk
I'm a fan of Python's philosophy too, but John Resig makes a good case for simplifying JavaScript APIs by making |new| optional for constructor functions. And I don't think we gain much by enforcing one approach in our implementations.Ah, good point. JS has so many current users and history behind it; a new language "designed from scratch" might be good to make monotonous, but not necessarily an existing one, in which enforcement of monotony--or obj-cap "language subsetting" for that matter--could just end up causing confusion and frustration. :)
However, we would benefit from sticking to a common style in all documentation and examples, so developers who look at them to figure out how to use the APIs don't receive mixed messages. And new-less constructors are preferable there, both because they are simpler and because they don't require an extra set of parentheses when accessed via dot notation on a require call.Good points all! I am cool with this, yo.
And, FWIW, a new-less constructor is very much like a factory, except that, as with constructor functions, its name is indicative of the thing it creates, which is especially useful for APIs that let you construct multiple kinds of objects (f.e. Item, Menu, and Separator in the context-menu module).