In Opera's current version, they don't go quite as far as does Chrome with its process separation, so an extension's popup can actually read from and write to
localStoragefrom the same origin as its background page (which lets you simplify the message passing a little if you're not aiming for easy porting). Your content script runs in its own global object, but it has a
windowreference to the current window object, as the page sees it, and in the interest of not automatically leaking your script's guts into the page's global scope, it is not in the inheritance chain, so you actually have to use long references like
window.localStorageto access them. (I tried assigning
this.__proto__ = window;, which in theory should import all window properties in my content script's scope, and while that seemed to allow the former, it still failed on the latter, so I guess I hit unsupported stuff or beta bugs.)
To try it out, I made my github improved user script an Opera 11 extension. Run
raketo build the zipped-up oex from the content script if you check out or fork the codebase, which puts the content script in
includes/(all scripts in
// ==UserScript==block with Greasemonkey-style
@excluderules run, not at the
DOMContentLoadedevent, but at page start, so you have to set your own
DOMContentLoadedlistener in a browser forked section if you want to execute under the same page conditions under Opera as in Firefox or a Chrome content script set to load at page ready).
Touting standards, Opera decided that a browser extension is essentially a Widget, and reused the W3C Widget standard they helped coin a while back, making its manifest sit in
config.xmlin the oex (a zip file) root directory (and emphasized that it also means you have to have an
index.htmlnext to it – the background page – but that it can be empty, if you like). For instance:
<?xml version="1.0" encoding="utf-8"?> <widget xmlns="http://www.w3.org/ns/widgets" version="1.0.0-0"> <name>Github improved</name> <icon src="icon.png"/> <author href="http://ecmanaut.blogspot.com/">Johan Sundström</author> <description xml:lang="en">Adds github changeset unfolding and other site improvements.</description> </widget>
This also means that you can use Widget storage and config-based preference init, if you like. It indeed even seems to be the recommended way, as that gets you unlimited storage (actually: the same total cap Opera sets for itself globally), whereas your background page's
localStoragegets subjected to the same arbitrary per-domain storage size cap that web sites are.
As for extension distribution, they of course have their own extension gallery you may want to submit your things to, and like all human-driven approval processes, they have a slightly anal process to get through first. Essentially, the less you can state about your add-on, the fewer opportunities you'll have to fail their test criteria; I was advised by the presenters not to add an add-on homepage, for example.
Currently, every submission attempt of yours in the approval process requires you to update your version number, so you can't aim for releasing a final 1.0 and treat all the attempts on the way there as release candidate 1 through N; my test add-on went through three revisions before coming out, and ended up named 1.0.0-0 in the end. It also was required to list change notes, that are reflected on the download page even when for an add-on that never existed before. Badly implemented good intentions also featured in the insistent numerous-stage wizard walking you through many steps every time (including screen shots, icons, et c), but there is at least the option to copy data from a previous version.
I think I may make Opera extensions of some of the extension-worthy hacks I do, but having tried the Chrome extension gallery's really smooth process, showing how it should be done, I don't think I'll have the patience to jump through Opera's hoops very often unless they improve notably.
DOMContentLoadedevent listener to start the main part of the script) ever. Their js hooks still thorougly beat both Greasemonkey and Chrome, yet the lack of installation when visiting a
*.user.jsfile locks that feature set in for only the really expert of browser users.