UserJS. Part 4: libretki framework

    libretki is a framework designed to simplify the creation of userjs and provide a ready-made set of useful functions.

    Other articles in the series:

    Core



    The core of the system is represented by the libretki.core.js file , which is a development of loader.js from the second article. The kernel also provides some basic functions. If all you need is the ability to attach other files, kernels are enough.

    A typical script using libretki:
    if (! ('libretki' in window)) {libretki = {__scripts: []}; }
    libretki .__ scripts.push ({
        name: 'habrahabr.example',
        requires: ['libretki.utilities'],
        init: function (unsafe) {
          // some code ...
          libretki.core.namespace ('habrahabr.example', {
            func: function () {/ * ... * /},
          });
        }
    });
    




    The func function is now available as habrahabr.example.func. The unsafe object is used as a namespace for functions that are unsafe to render outside userjs, such as file access.

    Function libraries



    Utilities (libretki.utilities)

    A set of small essentials of prime necessity: working with collections ( forEach , map , filter , ...), with optional arguments ( optional ), updating objects ( modifyObject ) and other utilities without any special focus.
    Used by almost all other scripts.

    Example:
    var positive = libretki.utilities.filter (arr, function (item) {return item.value> 0;});
    libretki.utilities.forEach (positive, function (item) {item.func ();});
    


    Managing cookies (libretki.cookies)


    Convenient work with cookies, instead of directly accessing document.cookies and parsing the result, provides the functions set , get and del .

    Example:
    libretki.cookies.set ('name', 'value');
    var value = libretki.cookies.get ('name');
    


    JSON (libretki.json)

    Serialization and deserialization of objects in JSON format.

    Example:
    var str = libretki.json.stringify ({name: 'name', value: 'value', active: true});
    var obj = libretki.json.parse (str);
    


    Storing objects in cookies (libretki.cookies_json)

    Storing objects in cookies. It is a simple combination of cookies and json libraries and, in principle, redundant, but remained for historical reasons.

    Example:
    libretki.cookies_json.set ('name', {value: 'value', active: true});
    var obj = libretki.cookies_json.get ('name');
    


    XPath (libretki.xpath)

    Retrieving elements and values ​​using XPath. It is a thin layer over document.evaluate , but eliminates the need to remember specific constants and fields.

    Example:
    var nodes = libretki.xpath.getNodes (document.body, '// img [@ class = "adv"]');
    var value = libretki.xpath.getNumber (tbody, 'tr / td [@ id = "header"] / @ colspan');
    


    Modifying a document using the DOM (libretki.visual.dom)

    Provides functions for quickly and conveniently creating elements, as well as functions for modifying the tree ("append", "prepend", "before", "after", ...) and adding / removing classes.

    Example:
    var dom = libretki.visual.dom;
    dom.before (elem, dom.html.a ({href: "http: // ...", className: "outlink"}, [
      dom.html.img ({src: "..."}), "link content"
    ]);
    


    Animation (libretki.visual.animation)

    Animation of elements. It was created for the toolbar, so for now it contains only animations “fadeIn”, “fadeOut” and “moveY”.

    Example:
    libretki.visual.animation.fadeOut (elem, {time: 500});
    


    General toolbar (libretki.visual.toolbar)

    A common toolbar on which each script can add its own buttons. The toolbar appears when you hover over a small square in the upper left corner of the page. You can add simple buttons and toggle buttons. It doesn’t look very good - I’m not a designer, I threw some kind of gradient and then plunged into the code. Example:

    toolbar.png - image uploaded to Picamatic


    // Add our button.
    libretki.toolbar.onShow (function (toolbar) {
      var group = new libretki.toolbar.ButtonsGroup ("Example");
      var button = new libretki.toolbar.CommandButton ("Alert", "data: image / svg + xml; base64, ...", function () {
        alert ("Example");
      });
      group.addButton (button);
      toolbar.addGroup (group);
    });
    


    Services


    A service is code that listens and responds to XDM messages. Services are necessary for the safe use of advanced userjs from any page.

    On bare JavaScript, a service and using code look like this:
    Service:
    if (location.href == 'http://0.0.0.0/') {
      window.addEventListener ('message', function (ev) {
        var fields = ev.data.split ('|');
        if (fields [0] == 'set') {
          // ...
          ev.source.postMessage ('ok');
        } else if (fields [0] == 'get') {
          // ...
          ev.source.postMessage (value);
        }
      }, true);
    }
    


    Using:
    window.addEventListener ('message', function (ev) {
      // Processing the response from the service.
    });
    var frame = document.createElement ('iframe');
    frame.onload = function () {
      // Here you can use the service.
      frame.contentWindow.postMessage ('get | key');
    };
    frame.src = 'http://0.0.0.0/';
    frame.style = 'display: none;';
    document.documentElement.appendChild (frame);
    


    As you can see, the case is troublesome and has several disadvantages:
    • you can only pass strings, so you have to manually parse them;
    • each service has to upload a separate frame with a different address;
    • it is difficult to process responses when using multiple services;
    • possibly inadvertently creating multiple frames with the same address;
    • the service may be accessible to scripts from the page, which is unsafe.


    Libretki takes care of all these difficulties.

    Cross-domain messaging (libretki.xdm)

    Safe and convenient use of XDM. Allows you to organize several services at the same address, distinguishing them by name. Used by JSON to pass objects. Prevents access to the service scripts from the page.

    Classes:
    • Server - accepts messages and can respond to them;
    • Client - sends messages, but cannot receive replies;
    • Channel - client and server in one person, can send messages and receive replies to them;
    • SeqClient, SeqServer are analogues of Channel and Server, respectively, but if the former do not track the correspondence between the request and the response, then these let you know the answer to which request came. Also detects missing messages.


    Example service on Server / Channel:
    if (location.href == 'http://0.0.0.0/') {
      new Server ('habrahabr.example', function (msg, client) {
        switch (msg.command) {
        case 'get':
          client.post ({command: 'get', key: msg.key, value: get_value (msg.key)});
          break;
        case 'set':
          set_value (msg.key, msg.value);
          client.post ({command: 'set', key: msg.key, success: true});
          break;
        }
      }
    }
    

    customer:
    load_page ('http://0.0.0.0/', function (win) {
      var channel = new Channel (win, 'habrahabr.example', function (msg) {
        switch (msg.command) {
          case 'get': data [msg.key] = msg.value; break;
          case 'set': if (msg.success) written [msg.key] = true; break;
        }
      }
      channel.post ({command: 'get', key: 'some'});
      channel.post ({command: 'set', key: 'some', value: 'bla'});
    });
    


    Same on SeqServer / SeqClient:
    new SeqServer ('habrahabr.example', function (msg) {
        switch (msg.command) {
        case 'get':
          return get_value (msg.key);
        case 'set':
          set_value (msg.key, msg.value);
          return true;
        }
    });
    

    load_page ('http://0.0.0.0/', function (win) {
      var client = new SeqClient (win, 'habrahabr.example');
      client.post ({command: 'get', key: 'some'}, function (result) {
        data ['some'] = result;
      });
      client.post ({command: 'set', key: 'some', value: 'bla'}, function (result) {
        if (result) written ['some'] = true;
      });
    });
    


    Remote procedure call (libretki.xdm.rpc)

    Simplifies the task of creating a service. Just write:
    unsafe.libretki.xdm.rpc.service ('http://0.0.0.0/', 'habrahabr.example', {
      get: function (key) {return data [key]; },
      set: function (key, value) {data [key] = value; },
    });
    

    use:
    var ex = unsafe .__ services.habrahabr.example;
    // Returns not just the result of the execution, but the function to be called
    // to get the result. This is to ensure that exceptions can be passed.
    ex.get ('key', function (res) {data ['key'] = res ();});
    ex.set ('key', 'value', function (res) {res (); written ['key'] = true;});
    


    Significantly less code compared to the initial version, right? Now you can begin to create useful services.

    Shared Data Warehouse (libretki.xdm.storage)

    Allows you to save data accessible from any page. Implemented by saving cookies on the page 'http://0.0.0.0/'.

    Example:
    var storage = unsafe.__services.libretki.storage;
    storage.set ('habrahabr_auth', {login: 'login', password: '123qwe'});
    storage.get ('habrahabr_auth', function (res) {
      var data = res ();
      login (data.login, data.password);
    });
    


    Clipboard (libretki.xdm.clipboard)

    Requires Java.

    Example:
    var clipboard = unsafe .__ services.libretki.clipboard;
    clipboard.set ('text');
    clipboard.get (function (res) {
      var text = res ();
      alert ('Clipboard content:' + text);
    });
    


    Access to the file system (libretki.xdm.io.file)

    Allows you to create, delete and rename files and folders, scan folders. Requires Java.

    Example:
    var file = unsafe .__ services.libretki.io.file;
    file.exists ('/ some / path', function (res) {alert (res ());});
    // Read a maximum of 10 lines.
    file.readLines ('/ another / path', 'utf-8', 10, function (res) {
      var lines = res ();
    });
    


    Cross-domain XMLHttpRequest (libretki.xmlhttprequest)

    I will not give an example of using XMLHttpRequest, everything is as usual, only you need to use "libretki.xmlhttprequest.XMLHttpRequest".

    XMLHttpRequest emulation is made to simplify the adaptation of someone else's code. If you write userjs from scratch, the “fetch” function is much more convenient:
    libretki.xmlhttprequest.fetch ('http: //some.url/path', {
      username: 'user',
      method: 'POST', content: 'blabla',
      onOpened: function () {},
      onDone: function (status, headers, response) {},
      onError: function () {},
    });
    


    A set of scripts for downloading images in the “Show cached only” mode (libretki.imaginate)

    This set of scripts is packaged in a separate archive. I will not describe individual scripts, I can only say that they help when working in the mode of displaying cached images. Since my channel is narrow, I always use this mode. You can upload individual images in various ways - by hovering the mouse over it, holding down the key, selecting an area on the screen, highlighting a piece of text, loading images visible in the window, etc.

    Instruments



    In the libretki / tools folder, you can find several tools executed as HTML pages.

    Customization (libretki / tools / libretki.settings.html)


    The interface for setting script parameters.

    Set the required parameters and do not forget to click the "Save" button. It works without Java, but then you have to save the settings file manually.

    settings.png - Picamatic - upload your images

    Script Management (libretki / tools / libretki.scripts.html)


    List of installed userjs with the ability to turn on and off. Can be used as a browser sidebar. Requires Java.

    scripts.png - Picamatic - upload your images

    Creating Buttons (libretki / tools / libretki.bookmarklets.html)


    Automates the creation of bookmarklets for various teams. Select a command, configure its arguments, give the command a name and drag the resulting link to the toolbar or bookmarks.

    bookmarklets.png - image uploaded to Picamatic

    Where to get


    You can download libretki at libretki.kriomant.net .

    Installation


    Installation is still quite complicated:
    1. unzip the contents of the archive into the user scripts folder;
    2. install Java if you want to use file access or clipboard;
    3. find out the location of the Java policy file ("opera: config # Java | SecurityPolicy"), copy it somewhere, add permissions using the sample in libretki / opera.policy , specify the path to the new file in the settings;
    4. open libretki / tools / libretki.settings.html and click "Save", this is necessary to generate a unique code that is used for XDM


    Examples


    In the "libretki / examples" folder there are examples of using some features. Since some features are specially hidden from the scripts on the page, for the corresponding examples to work, you must place the file “libretki / examples / libretki.allow-unsafe.js” in the scripts folder.

    Plans


    In the process of writing are installers for Windows and Linux.

    Problems


    First feedback is required. He announced libretki on OperaFan, it seems that a lot of people downloaded, but did not leave a single review. Express your attitude:
    • it is a useless thing;
    • too hard to install;
    • weighs too much;
    • lack of documentation;
    • another.


    Secondly, libretki needs a logo and website design, I myself am not a foot in this business. The place and domain are already there.

    Also popular now: