Advanced User JavaScript: event handling

Why User JavaScript events?

Any script can ask Opera to be notified when a specific event occurs, for instance a mouse click on a button. By using the special User JavaScript events your user script can ask Opera to be notified in advance of the page script. The user script can then either cancel the event, change the event or allow the page script to receive it unchanged.

Opera also can notify the user script about special events that normal scripts can not detect, such as when an external JavaScript library will be loaded.

How to use User JavaScript event handling

A user JavaScript can add event listeners to the window.opera object with the command window.opera.addEventListener(). The following new events are available to allow the user script to enhance and control the environment:

BeforeExternalScript

This event takes place before Opera loads an external JavaScript file.

BeforeScript / AfterScript

These events happen before and after any SCRIPT tag is ran.

BeforeEvent / AfterEvent

BeforeEventListener / AfterEventListener


These are 'meta-events' you can use to either be notified in advance or after about every event taking place in the document, or every event that the scripts in the page will use.

To the 'meta-events' you can add .TYPE to detect specific events only, for instance BeforeEventListener.load . This is the preferred way of using these events because a generic handler will be called a lot – for instance every time you move the mouse.

Cancelling events with event.preventDefault() in the event handler stops the default action. If you cancel 'Before' script notification events, scripts will not be loaded or ran. If you cancel 'meta-events' the page script will not receive the real events. (If this explanation is too confusing see the examples! 🙂 )

Writing User JavaScript event handlers

The event handler function receives an object with information about the event. The function can check various properties of this object to get information about the event. The element property tells you what element the event is happening to, and the event property is the event object that will be passed to the page's script.

Examples

1

To prevent the script on a page from running its onload handler you could add the following to a User JavaScript:

opera.addEventListener('BeforeEventListener.load', function(ev){ ev.preventDefault(); }, false);

2

Say you have a form with an onsubmit handler that prevents Opera from sending the form:

<form action=''http://example.com” onsubmit=''return false;''>

The event.preventDefault() in the following example will cancel the return false from the page's script because the page's onsubmit event handler will not be called:

opera.addEventListener('BeforeEvent.submit', function(ev){ ev.preventDefault(); }, false);

3

The following user script will fix a buggy DHTML script on <http://www.thegreenbutton.com/downloads.aspx> by rewriting the script source code with a regular expression:

if(window.location.href.indexOf('thegreenbutton.com')>-1){

window.opera.addEventListener( 'BeforeScript', function (ev){ev.element.text = ev.element.text.replace(/!=

null/g,''); },false);

}

Advertisements

17 thoughts on “Advanced User JavaScript: event handling

  1. Awesome!
    But why there is no complementary AfterExternalScript event? Especially that Opera does not support onload event for <script>…

  2. Please put some of this (particularly the "fix a broken script" example) in the official documentation. Outwitting a sniffer script would also be a good example.

    In that same location, it would be good to link to a very basic javascript intro that does show how to register for an event.

  3. You've got AfterScript.. I'm not entirely sure what you would want to do specifically after an external file has loaded.

  4. Well. For example I wrote userJS which adds Google Suggest features to normal Google pages:
    http://my.opera.com/forums/showthread.php?s=&amp;postid=870518#post867265

    I create <script> element to download Google Suggest engine. After that I have to run engine via InstallAC function. As you may see I've done a nasty hack by adding <script> element right after document.body is available in DOM and registering 'load' eventlistener that triggers 'InstallAC'.

    Obviously 'setTimeout' is not a good solution.

  5. You're using function(ev) in your examples. Where does the 'ev' come from or what does it represent exactly? Is 'ev' a name you chose yourself and would 'pi' work just as well?

  6. In these examples, "ev" is the object with information about the event (mainly the "element" and "event" properties). You can name it anything you want 🙂

    I could also have omitted the argument part and just used the global "event" property as in function(){event.preventDefault()} but this is an IEism AFAIK. I recommend you write event handlers that take one argument.

    Was that making things any clearer?

  7. I think Opera at the moment actually pauses the script until the newly added script has been loaded and ran, but this behaviour may change.

    You might set up a while loop doing nothing, but I'm not sure if I like that idea – if for some reason the external file failed to load Opera would be stuck in that loop forever.

    x.type = 'text/javascript';
    x.src = '/ac.js';
    document.body.insertBefore(x, document.body.firstChild);

    // Empty while loop example below

    while (typeof(InstallAC) == 'undefined');

    var googleFrm = (document.gs ? document.gs : document.f);
    InstallAC(googleFrm, googleFrm.q, googleFrm.btnG, 'search', 'en');

    Perhaps experiment with adding an AfterScript event handler that calls InstallAC and removes itself?

  8. Yes, that makes things clearer. Thanks. I'm now looking for a way to insert all these other events into a user.js that has the structure of Rijk's suggestion… :smurf:

  9. I have a working "Google Suggest" in user JS, but the Google Labs terms of service are _very_ unlclear regarding what is permitted and not.

    I have written Google Labs, asking permission to release this script, but they have not responded so far.

    Side-question: Does the event.element act like any other DOM node:
    * Is reading properties/attributes of the script element possible, such as source, type, language, defer and anything else added to it?

  10. My 'setTimeout' loop is not the optimal solution but 'while' loop is even worse 🙂
    What do you mean "adding an AfterScript event handler that calls InstallAC and removes itself"? I thought that AfterScript runs right after the closing tag is parsed. I don't think this will do the job for external scripts (I mean it wont wait until script is loaded) but I'll check it.

  11. I don't think it breaks licence. You use _their_ technology on _their_ site 🙂 They can't blame you for that… 😉

    As for the event.element, for my experience it's a fully functional node.

  12. "Better safe than sorry". If I receive a positive answer from Google, I will release the code. Patience.

    (The general advice, though, if you want to try yourself: The Greasemonkey extension for Google Suggest works, with some conceptual alterations, since Opera doesn't support XPath).

  13. I meant something like

    function InstallGoogleAutoComplete(){
    if(typeof(InstallAC)!='undefined'){
    var googleFrm = (document.gs ? document.gs : document.f);
    InstallAC(googleFrm, googleFrm.q, googleFrm.btnG, 'search', 'en');
    opera.removeEventListener('AfterScript', InstallGoogleAutoComplete, false); /* Event listener no longer required */
    }
    }

    opera.addEventListener('AfterScript', InstallGoogleAutoComplete, false);

    x.type = 'text/javascript';
    x.src = '/ac.js';
    document.body.insertBefore(x, document.body.firstChild);

  14. > Does the event.element act like any other DOM node

    Yes. On one point User JS has wider powers than a normal script: it can read event.element.text even if the element in question has loaded its content from another domain. Apart from that everything is the same as normal DOM scripting.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s