Most Powerful Open Source ERP

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.