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:
- fetches the HTML and parse it
- keep a copy of the BODY, to clone it on every instance
- loads all JS, CSS defined in the HEAD
- 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:
- generate the gadget definition
- Instanciate the gadget
Gadget instanciation
- 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.
- Instanciate child gadgets defined in the BODY
- Copy the BODY on gadget
.element
property
- Calls .
setState
callbacks
- Calls .
ready
callbacks
- When gadget
.element
is added to the DOM, declareService
, onEvent
, onLoop
are started
- When gadget
.element
is removed from the DOM, declareService
, onEvent
, onLoop
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
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.