Taming the GreaseMonkey

    Over the past couple of weeks I have had to work closely with the user script management system for Mozilla products - GreaseMonkey . And since I myself appointed the administrator of the blog of the same name, it means to write an introduction to the question - my holy duty.



    Introduction



    GreaseMonkey (hereinafter GM) is a user script management system for Mozilla products. In my article I will talk about the browser of this company, about Firefox further (FF). Also in some places I will touch on its competitors, namely Opera, Safari and, of course, Internet Explorer (hereinafter IE).

    User Script (User Script) - a script written in JavaScript (hereinafter JS), installed by the user in a browser and executed when loading web pages. Used to change their design (in the broad sense of the word).

    Simply put, with the help of user scripts, you can add / remove / change elements of a web page, change their behavior, improve the User Experience.

    Installation



    GM is easily put as an extension to FF from the add-ons site . So GM also has an official website where you can find a lot of useful information.

    After installation and restart, the FF icon will appear:



    And this means that you can install custom scripts.

    The largest warehouse of user scripts is userscripts.org . Installation is very simple. GreaseMonkey simply intercepts the response to the request of the JS file, and if it has a special header (I will talk about it below), it calls the installation dialog:



    Overview



    You can control GM and installed scripts through the context menu, which is called up by right-clicking on the monkey’s face:



    At the top of the menu a list of scripts active for this page is displayed. Any script can be disabled by unchecking.

    Using the GM API, you can expand this menu. All actions registered through GM_registerMenuCommand will appear in the "Script Commands" submenu.

    I will skip the “New Script” menu item, as I’m sure it’s more convenient to make a script in the editor, including editing the meta-information. In any case, I hope that mastering this wizard will not cause readers any problems.

    "Script Management" brings up the following window:



    In this window, you can customize any installed user script yourself. To do this, select it in the left list. You can add remove URL masks for which this script will be loaded or NOT loaded (classic Allow / Deny), enable / disable / delete the script, and, most important for the developer, edit it live.

    To edit the script, click the "Change" button. For the first time GM will ask you to choose an editor. In the following, it will automatically open a working copy of the script in the selected editor.

    On this, the GM tour is considered complete and you can go directly to the intricacies of developing custom scripts.

    Custom scripts



    GM-scripts are practically nothing (about some features, I will discuss in the next section) do not differ from ordinary JS-scripts, so no special knowledge for writing is needed. But in order for GM to recognize the script as a user, you need to add a special header: With name, author, description everything is clear, you need to dwell on the remaining parameters of namespace - any URI (this is not a link, but an analog of HTML namespace). You can consider this parameter a unique identifier for the script. include - a mask for pages that will activate this script. There may be several directives. @exclude - mask for pages that will NOT activate this script. There may be several directives.

    // ==UserScript==
    // @name Weborama Inline Player
    // @namespace tbms.ru/weborama/inline
    // @description Includes weborama inline player
    // @author Konstantin Shvydky, Nick Mitin
    // @include *
    // @exclude file://*
    // ==/UserScript==
    /*
    This code is licenced under the GPL
    www.fsf.org/licensing/licenses/gpl.html
    */








    It’s also good practice to indicate the license under which the script itself is distributed. This can be done below metadata.

    * About metadata at greasespot.net.

    The second prerequisite is the end of the file name. It must end with ".user.js", otherwise GM will not recognize the script.

    The script for GM is run in order of priority upon the occurrence of the DOMContentLoaded event on the processed web page. Keep that in mind.

    Tips & Tricks



    We have already found out that user scripts usually change the design of web pages. Therefore, the main tasks that developers face are related to DOM programming, namely manipulating the DOM model of web pages. The problem here is that it is sometimes very difficult to get the script to work properly on antisemantic sites. And I would like to give some tips for GM developers.

    Opera, Safari and Firefox have built-in XPath support through the document.evaluate () function. A good description of this feature is in the MDC . For those unaware, XPath (XML Path Language) is a language for accessing parts of an XML document. In the case of the web, this definition is also true for HTML. Great tutorial on ZVON.org. The essence of the method is that you create and send a “request” to the DOM model, and in return you get an iterator with all the nodes that satisfy this request.

    It is important to know that you cannot directly modify these nodes in the iterator, since any change rebuilds the DOM, thus making the iterator invalid. Therefore, first create an array and copy the links to these nodes there, and then work with them. In the example in MDC, all this is considered.

    IE also has partial support for evaluate, which is implemented through a hack created by Dimitri Glazkov and Mehdi Hassan.

    We added it to our JS-Extender , fixing some bugs in it. However, we were unable to execute complex XPath queries, so we do not use this function in IE.

    Another important point worth noting is that when using the element.childNodes property, FF counts line breaks between tags as text nodes. For example, a div with id = container will have not three, but five child nodes:


    content1

    content2



    Be carefull!

    And last, but most important. In JS, there is a window object, which is somehow a global namespace for all global JS entities. if we write

    var myVar = 1;

    then it will be available through

    window.myVar or window ['myVar'].

    So, GM also has a window, but it is a wrapper around the window of the web page itself. this is done so that your code does not overlap with the original page code and does not interfere with it. But there are situations when you need to directly access the window itself, for example, to get the value of a site variable. The global unsafeWindow property comes to the rescue, which provides access to it.

    If you are writing a cross-browser user script, then keep in mind that unsafeWindow is only in GM, it is not in Opera. Therefore, it’s better to immediately populate a global variable and put the window you need into it, for example like this:

    var aWindow = (typeof unsafeWindow! = 'Undefined')? unsafeWindow: window;

    A spoon of tar



    Despite its great capabilities, GM has a significant drawback, which is the lack of a centralized mechanism for updating user scripts.

    There are several attempts to solve this problem:

    yoast.com/greasemonkey-auto-update-notification
    splintor.wordpress.com/2007/05/01/greasemonkey-wish-auto-update-user-scripts
    userscripts.org/scripts/show/2296

    At the moment, none of them suit me. We have taken this issue into development by the poem, and we will certainly come up with an elegant solution to the problem. What I will tell you separately.

    In general, we can say that GreaseMonkey is a special case of the user script management mechanism. In Opera, they are supported without any extensions, according to information received from pepelsbeythere is a plug-in for Safari that allows you to run these scripts - GreaseKit , according to information from jursovet script support has already been implemented and for Chrome

    I consider my report finished. Thank you for reading.

    Also popular now: