RenderJS Home RenderJS

    RenderJS Concepts

    • Last Update:2020-06-05
    • Version:001
    • Language:en

    Gadget definition

    The definition of a renderJS gadget consists of a single HTML file and its JS/CSS dependencies defined in the DOM header.

    This definition is referenced by the URL of the HTML document.

    HTML can also contain a link to the gadget interface URL, which acts a documentation.

    Minimal example:

    <html>
      <head>
        <script src="rsvp.js"></script>
        <script src="renderjs.js"></script>
      </head>
      <body>
    A minimal renderJS gadget
      </body>
    </html>

    Gadget definition loading

    When renderJS loads a new definition URL, it:

    1. fetches the HTML and parse it
    2. keep a copy of the BODY, to clone it on every instance
    3. loads all JS, CSS defined in the HEAD
    4. generates the "class" methods defined by .declareMethod and .declareJob

    Gadget's logic

    The gadget logic is configurable in javascript only. It requires you to create a file referenced by the HTML.

    <html>
      <head>
        <script src="rsvp.js"></script>
        <script src="renderjs.js"></script>
        <script src="logic.js"></script>
      </head>
      <body></body>
    </html>
    

    In the logic.js file, the gadget's definition is accessible by calling: rJS(window).

    (function (rJS) {
      "use strict";
      var gadget_definition = rJS(window);
    })(rJS)
    

    The gadget's definition object API is:

    • .ready
    • .declareMethod
    • .declareService
    • .declareJob
    • .onEvent
    • .onLoop
    • .declareAcquiredMethod
    • .allowPublicAcquisition
    • .setState
    • .onStateChange

    Root gadget

    Any gadget definition should be loadable in the browser URL bar.

    When done, renderJS:

    1. generate the gadget definition
    2. Instanciate the gadget

    Gadget instanciation

    1. Loads the "class" definition if not already loaded
      • if declareGadget(url1) is called twice, it only loads HTML, JS, CSS once
      • First instanciation is slow. Second one is fast.
    2. Instanciate child gadgets defined in the BODY
    3. Copy the BODY on gadget .element property
    4. Calls .setState callbacks
    5. Calls .ready callbacks
    6. When gadget .element is added to the DOM, declareServiceonEventonLoop are started
    7. When gadget .element is removed from the DOM, declareServiceonEventonLoop are cancelled

    Gadget API

    The API available on a gadget is:

    • .declareGadget
    • .getDeclaredGadget
    • .dropGadget
    • .changeState
    • + all declared methods and jobs
    • .getInterfaceList
    • .getMethodList
    • .getRequiredCSSList
    • .getRequiredJSList
    • .getPath
    • .getTitle

    A gadget has 2 built in attributes by default

    • .element
    • .state

    Automatically triggering code on gadget

    There are 3 ways to trigger code execution after a gadget has been created.

    .ready

    The callback is executed during the creation of the gadget.

    Do not run slow/blocking code here, as it will also block the parent gadget creation.

    .declareService

    The callback is executed when the gadget is attached to the document DOM.

    Multiple concurrent services can be declared and executed if needed.

    .onEvent

    The callback is in fact a service started when a specific DOM event (click, submit, change, input, ...) is triggered. 

    DOM management

    A gadget is not allowed to modify the document DOM globally.

    It should only manage its .element attribute.

    It must not manage its child gadget DOM.

    Preventing DOM write concurrency

    Managing the DOM of the gadget is HARD.

    Due to the asynchronous logic of javascript, the DOM can be concurrently modified by:

    • declareMethod callback
    • declareService
    • onEvent
    • onLoop
    • acquireMethod

    changeState is a mutex on the gadget level:

    • changeState is executed only when the previous call is resolved/rejected
    • sequential

    All DOM modifications MUST be done in onStateChange

    gadget.state attribute: dict like object

    changeState take dict as parameter and update all gadget.state keys

    onChangeState callback is ONLY called by changeState AND ONLY if there was a modification on 1 key

    It prevents DOM change if not needed

    Default state is defined by .setState

    Gadget's tree

    • One gadget can have many child gadgets (of different URL)
    • One gadget may have one parent gadget

    An application is a tree of gadgets

    Gadget's reference

    Gadget's reference is available with:

    • declareGadget / getDeclaredGadget, which return a child instance
    • on every renderJS callback, the this variable is the self instance

    You can NEVER get the parent gadget reference. You don't know the parent gadget class.

    Creating gadget's child

    A gadget can create as many child gadget it needs.

    All gadgets COULD be created inside an iframe to provide "isolation", to prevent 3rd party JS/CSS to destroy/pollute the global window/DOM

    There are 2 ways to create a gadget child

    Declarative child loading from the DOM
    <html>
      <head>
        <script src="rsvp.js"></script>
        <script src="renderjs.js"></script>
      </head>
      <body>
        <div data-gadget-url="url_of_the_gadget_definition"></div>
      </body>
    </html>
    Calling .declareGadget method

    Interacting with a gadget's child

    A gadget should only call child methods which have been defined by .declareMethod

    Interacting with a gadget ancestor 

    As it is not possible to get access to the parent gadget reference, it is only possible to call a gadget method defined with .declareAcquiredMethod.

    This will check all gadget ancestor until renderJS found one which defined a allowPublicAcquisition for this method.

    If no matching ancestor is found, a AcquisitionError is thrown.