Documentation Index

To be generated

What is renderJS?

renderJS is a JavaScript library which helps modularizing your HTML5 code and your JavaScript applications. It uses the HTML5 standard as an easy way to specify self-contained components which consist of HTML5 code, CSS code and Javascript code. It helps reusing components in different applications just as easily as linking an HTML5 page to another. It also helps combining multiple reusable component within the same single page application.

The main focus of renderJS is graphic user interface (GUI) components such as editors, viewers, fields or widgets. renderJS can also be used to define reusable components with no GUI such as translators or format converters.

A Simple Example

Let us suppose we want to add a text editor to an HTML5 page, here is how we proceed:

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Simple example</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>
  <body>
    <p>Text editor displays below:</p>
    <div data-gadget-path="http://www.renderjs.org/editor/rtl/index.html"></div>
  </body>
</html>

renderJS takes care if managing all dependencies and rendering.

How does it work?

renderJS is separated into 3 parts: renderJS library, renderJS interfaces and renderJS core gadgets.

renderJS library provides a simple way to load inside an existing HTML5 page third-party components which follow the renderJS specification. It implements a recursive macro language in pure HTML5. This macro language provides a way to embed and combine recursively components from different sources.

renderJS core interfaces (http://www.renderjs.org/interface/) provide the documentation to common interfaces shared by all renderJS components. It defines in particular the renderable interface for all components which can be rendered in a page such as editors, viewers, fields or widgets.

renderJS core gadgets (http://www.renderjs.org/gadget/core/) provide a reference implementation of renderJS interfaces. It provides in particular the default implementation of renderJS router and renderJS catalog. renderJS router is used to manage interactions between user and components or between components themselves. renderJS catalog provides a way to search for components which meet a given interface.

Getting started

This walkthrough is designed to get you started using a basic renderJS instance.

Download renderJS library, renderJS core as well as the dependencies required to start using core components.

Script

Description

Source

renderJS

The renderJS library

render.js

jquery

The JQuery library version XXX

jquery.js

Add the renderJS script to your HTML page:

<script src="jquery.js" type="text/javascript"></script>
<script src="render.js" type="text/javascript"></script>

renderJS fundamentals

renderJS can be used either by adding HTML5 tags to your page or by invoking Javascript methods.

The renderJS script provides 10 HTML5 tags which can be added to any HTML5 page.

Method

Sample Call

Description

data-gadget-path

<div data-gadget-path="hello-world.html"></div>

Embeds the HTML5 code of a gadget in a page, loads CSS and Javascript depencies and call render() method on the gadget if it is defined.

data-gadget-slot

<div data-gadget-slot="main">
  <p>This content is</p>
  <p>Going to be replaced/p>
</div>

Defines the porting of the DOM tree in the HTML5 code of a gadget which is going to be replaced after render() method is called

data-gadget-fill

<div data-gadget-path="hello-layout.html">
  <div data-gadget-fill="main">
    <div data-gadget-path="hello-world.html"/>
  </div>
</div>

Fills given slot in DOM parent gadget with HTML5 content defined in DOM child tree. Filling is applied recursively.

data-gadget-scope

<div data-gadget-path="hello-layout.html" data-gadget-scope="hello"></div>

Associates a gadget to a namespace which can later be used to retrieve a gadget by URL or programmatically

data-gadget-state

<div data-gadget-path="html-viewer.html" data-gadget-state="{'text_content':'<p>Some content</p>'"></div>

Defines the state of the gadget as serialized JSON string with properties. This state can be used to implement persistency of a gadget and ability to move it from one page to another.

data-gadget-cache

<div data-gadget-path="hello-layout.html" data-gadget-cache="form"></div>

Defines the caching policy of a gadget. Caching itself is implemented by a "Cache services" gadget.

data-gadget-sandbox

<div data-gadget-path="hello-layout.html" data-gadget-sandbox="iframe"></div>

Defines the sandboxing type of a gadget (iframe, safejs, etc.).

data-gadget-public

<div data-gadget-path="hello-layout.html" data-gadget-public="bang"></div>

Declares which methods or events of a gadget are public.

data-gadget-routed

<div data-gadget-path="hello-layout.html" data-gadget-routed="a.someMethod:bang; b.anotherEvent:bang"></div>

Declares which methods or events of a gadget are forwarded to the router.

The renderJS Javascript API replicates and extends HTML5 tags.

Method

Parameters

Returns

Description

€(scope_selector)

selector

Gadget selection.

Select all gadgets matching the scope selector.

€(scope_selector).declareGadget

 OR

$(selector).declareGadget

  • url, // the path of the gadget definition ex. "slide-gadget.html'
  • [settings] // A set of key/value pairs
    • state, // gadget state
    • scope, // some scope for all URLs published ????
    • position, // useful to try to order gadgets inside an element
    • sandbox, // defines the sandboxing type

Promise (for callback)

Declares that a given gadget with given parameters should exist as the parent of another gadget and should be attached to a given DOM position.

€(scope_selector).remove

scope

Promise (for callback)

Remove the set of matched gadgets

€(scope_selector).declareMethod

  • method name
  • function

Chainable gagdet selector

Declares a public method of a gadget.

Step by step tutorials

We will learn here how to create a gadget, how to use a gadget and how to make gadgets interact.

Tutorial 1: Hello Viewer

Many people just want to use renderJS in order to display and edit content and leverage the rich library of gadgets of OfficeJS which renderJS is based.

Here how to do.

Let us add an HTML document to our web server in /var/www/html/hello_viewer/test.html

Let us add an SVG document to our web server in /var/www/html/hello_viewer/test.svg

We are going to display both documents in the page using whichever editor is available to display it.

We create the HTML file /var/www/html/hello_viewer/test.html with the following code.

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Hello Viewer Application</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>
  <body>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Include two universal viewers -->
    <p>Display first viewer with HTML file</p>
    <div data-gadget-path="http://officejs.org/editor/universal/index.html"
         data-gadget-sandbox="iframe"
         data-gadget-state="{'src': '/hello_viewer/test.html'}" />
    <p>Display second viewer with SVG file</p>
    <div data-gadget-path="http://officejs.org/editor/universal/index.html"
         data-gadget-sandbox="iframe"
         data-gadget-state="{'src': '/hello_viewer/test.svg'}" />
  </body>
</html>

Here is the result:

[DRAWING]

We only use here a single gadget: the universal editor. This gadget has two instances. Each instance is able to download a file, guess its mime type and select the most appropriate viewer to display it. It removes the burden to select a viewer from the developer. We have used the tag data-gadget-sandbox on both gadgets in order to make sure that an iframe sandbox prevent CSS conflicts which most viewers generate because of poor namespacing.

Tutorial 2: Hello World

Let us now create a simple gadget from scratch. This gadget displays the text "Hello World". We first create a directory in our web server.

/var/www/html/gadget/hello_world

Then we create the file /var/www/html/gadget/hello_world/index.html that will contain the gadget code.

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Hello World</title>
  </head>
  <body>
    <p>Hello World</p>
  </body>
</html>

We can display the gadget by opening the URL

http://localhost/gadget/hello_world/index.html

Which displays the "Hello World" test in a blank page:

[DRAWING]

We will now embed the "Hello World" the gadget in a renderJS application.

Let us create the file /var/www/html/gadget/hello_application/index.html which will contain the HTML5 application.

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Hello World Application</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>
  <body>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Include Hello World gadget -->
    <div data-gadget-path="../hello_world/index.html" />
  </body>
</html>

Let us now check the result:

[DRAWING]

And the HTML5 code which was generated:

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Hello World Application</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head/>
  <body/>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Include Hello World gadget -->
    <div data-gadget-path="../hello_world/index.html"
         data-gadget-scope="Hello World">
      <p>Hello World</p>
    </div>
  </body>
</html>

This example shows the basic feature of renderJS: the ability to dynamically include in a page code defined in another page. You can consider in this example that renderJS is a kind of macro system which runs on the client side rather than on the server side. You will also take note that renderJS generated the tag "data-gadget-scope" automatically by taking the default value provided by the title of the gadget.

Let us now add some behaviour to our gadget. We create a script /var/www/html/gadget/hello_world/hello.js with the following code

€(this).declareMethod("foo", function () {
     // replace body paragraph with Bang! word
     $(this).find('p').text("Bang!");
  });

We now need to attach a dependency to this script in the gadget definition. We are going also to use the data-gadget-public tag.

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Hello World</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
    <script src="hello.js" type="text/javascript"></script>
  </head>
  <body data-gadget-public="foo">
    <p>Hello World</p>
  </body>
</html>

If we open our Web browser to http://localhost/gadget/hello_world/index.html, we can view the Hello Word gadget itself:

[DRAWING]

Now, if we type the URL http://localhost/gadget/hello_world/index.html#foo, we get something new:

[DRAWING]

What happens here is that the data-gadget-public has declared the method foo as a public method that can be invoked through a hashtag. This is simular to the concept of method publication in application servers such as Zope, Flash. http://localhost/gadget/hello_application/index.html#hello/foo. Here is the result:

[DRAWING]

The content "Hello World" was replaced by "Bang!". This example shows the concept of recursive publication of gadgets provided by renderJS. By using the data-gadget-scope tag, every public method of a gadget can be accessed through a simple URL.

Tutorial 3: a slider gadget containing two forms and an interactor

We will now show a more complex example to illustrate the advanced macro capabilities of renderJS and the concept of interactor.

Let us create a slider field where the slider widget itself can contain any gadgets, such as forms, date fields, animated sprite, etc.

[DRAWING]

Let us first define the HTML5 code of the gadget in /var/www/gadget/slider/index.html

<html>

  <!-- Define dependencies and supported interfaces -->
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Slider Gadget</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
    <link rel="stylesheet" src="slider.css"/>
    <script src="slider.js" type="text/javascript"></script>
    <link rel="http://www.renderjs.org/rel/interface"
          src="http://www.renderjs.org/interface/renderable"/>
    <link rel="http://www.renderjs.org/rel/interface"
          src="http://www.renderjs.org/interface/field"/>
  </head>

  <!-- Sample display made by HTML designer -->
  <body>
    <noscript>Please turn on Javascript.</noscript>

    <!-- Sample display made by HTML designer -->
    <div class="slider">
      <div class="slider_element">
        <!-- The content of this div is replaced dynamically by the call to render() -->
        <div data-gadget-slot="main"> <!-- main is the default -->
          <!-- This part is destroyed and replaced by render() -->
          <form>
            <input type="text" />
          </form>
        </div>
      </div>
    </div>
  </body>

</html>

We can now define the CSS of slider.css:

    .slider {
      background-color: black;
      display: inline-block;
      height: 0.5em;
      margin: 0.5em 0;
      position: relative;
      width: 20em;
    }
    .slider_element {
      background-clip: padding-box;
      background-color: #A1A1A1;
      border-radius: 0.75em 0.75em 0.75em 0.75em;
      border-width: 0;
      cursor: pointer;
      left: 50%;
      line-height: 1em;
      padding: 0.25em;
      position: absolute;
      top: -1em;
    }
    form input {
      cursor: pointer;
      max-width: 2em;
    }

The Javascript code of slider.js looks like this:

XXX TO BE COMPLETED

This example introduces some new concepts of renderJS. The data-gadget-slot slot defines a placeholder in the gadget which can be filled with another gadget at render time. It is now filled with a single form with a single field. We will show later how to dynamically replace this single form with two forms.

Another important concept introduced in this example is the notion of interface. The relation type http://www.renderjs.org/rel/interface defines an interface relation, following the concepts of link relation used increasingly in modern REST applications based on the HATEOAS approach. We define here that our gadget follows the renderable interface and the field interface.

Interfaces are self-documented online:

# http://www.renderjs.org/interface/renderable

A gadget is meant to be rendered as part of the DOM tree of an HTML5 page.

€(selector).render() [returns Promise]

Renders the gadget in the given DOM context.
# http://www.renderjs.org/interface/field

A renderJS gadget which provides a way for user to display information and
collect information.

€(selector).getValue() [returns Promise]

Returns the value of given gadget.

€(selector).setValue(value) [returns Promise]
* value -- value to set

Sets the value of a given gadget.

Let us now create a small application which embeds two forms inside a slider gadget and created an interaction between forms and the slider.

We should first create a form gadget in /var/www/gadget/slider/form.html

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Form Gadget</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
    <script src="form.js" type="text/javascript"></script>
    <link rel="http://www.renderjs.org/rel/interface"
          src="http://www.renderjs.org/interface/renderable"/>
    <link rel="http://www.renderjs.org/rel/interface"
          src="http://www.renderjs.org/interface/field"/>
  </head>
  <body data-gadget-public="setValue">
    <form>
      <input type="text" />
    </form>
  </body>
</html>

and define the form.js script which implements the field API for the form itself.

€(this)
  .declareMethod("getValue", function () {
       // Deferred object is returned automatically by renderJS
       return $(this).find('input').val();
    })
  .declareMethod("setValue", function (value) {
       // Deferred object is returned automatically by renderJS
       $(this).find('input').val(value);
    });

It is time now to assemble all parts into an application: a slide gadget and two instances of the form in /var/www/gadget/slider/example.html

<html>

  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Slider Example Application</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>

  <body>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Page structure -->
    <div data-gadget-path="slider.html">
      <div data-gadget-fill="main">
        <!-- First Form -->
        <div data-gadget-path="form.html"
             data-gadget-scope="first"/>
        <!-- Second Form -->
        <div data-gadget-path="form.html"
             data-gadget-scope="second"/>
      </div>
    </div>
  </body>

</html>

This example shows a typical example of the data-gadget-scope tag in order to distinguish to instances of the same gadget. It also shows how the data-gadget-fill tag operates by filling the data-gadget-slot named "main" in the Slider gadget.

Let us display the result by opening the URL http://localhost/gadget/slider/sample.html:

[DISPLAY]

Let us illustrate how the data-gadget-public tag works in combination with data-gadget-scope.

And if we call http://localhost/gadget/slider/sample.html#first/setValue?value=3 [DISPLAY]

The second form changes with value set to 3.

If we call http://localhost/gadget/slider/sample.html#second/setValue?value=7 [DISPLAY]

The second form changes with value set to 7.

We will now make the slider and forms interact so that moving the slider updates both forms and changing any form moves the slider. In order to achieve this, we need to add a interactor gadget to the application. The code of the application will look like this.

<html>

  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Slider Example Application</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>

  <body>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Page structure -->
    <div data-gadget-path="slider.html"
         data-gadget-scope="slider"
         data-gadget-routed="setValue:interactor/notifyUpdatedValue?value={$value}" >
      <div data-gadget-fill="main">
        <!-- First Form -->
        <div data-gadget-path="form.html"
             data-gadget-scope="first"
             data-gadget-routed="setValue:interactor/notifyUpdatedValue?value={$value}" />
        <!-- Second Form -->
        <div data-gadget-path="form.html"
             data-gadget-scope="second"
             data-gadget-routed="setValue:interactor/notifyUpdatedValue?value={$value}" />
      </div>
    </div>
    <div data-gadget-path="interactor.html"
         data-gadget-scope="interactor"
         data-gadget-public="notifyUpdatedValue" />
  </body>

</html>

What we just did here is to use the tag data-gadget-public which simulates the call to a URL each time a method of a gadget is invokes. For example, if setValue is invoked on the first single field form, then we simulate a call to the URL interactor/notifyUpdatedValue and pass to it the parameters of setValue which ere interested in.

We can now define the interactor HTML5 code for interactor.html:

<html/>
  <head/>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Slide Interactor</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
    <script src="interactor.js" type="text/javascript"></script>
  </head/>
  <body/>
    <!-- Warning message if no javascript --/>
    <noscript>Please turn on Javascript.</noscript>
  </body/>
</html/>

and its javascript code:

€(this).declareMethod("notifyUpdatedValue", function (value) {
   var slider = €("slider"),
     first = slider.find("first"),
     second = slider.find("second"),
   slider.getValue().done(function (current_value) {
     if (current_value !== value) {
       slider.setValue(value);
     }
   });
   first.getValue().done(function (current_value) {
     if (current_value !== value) {
       first.setValue(value);
     }
   });
   second.getValue().done(function (current_value) {
     if (current_value !== value) {
       second.setValue(value);
     }
   });
});

Now each time the user moves the slider, the forms are updated and each time forms are updated, the slider is moved.

Tutorial 4: using Javascript only

TBD, mainly by calling declareGadget, declarePublic and declareRouted

HTML5 Tags

data-gadget-path

TBD



data-gadget-scope

TBD



data-gadget-state

TBD



data-gadget-cache

TBD



data-gadget-sandbox

TBD



data-gadget-slot

TBD



data-gadget-fill

TBD



data-gadget-public

Makes a given method of the gadget accessible through the router.

The simple form does not require any parameter:

<div data-gadget-path="a.html"
     data-gadget-public="someMethodOfA"
     data-gadget-scope="a"/>

can be invoked by a GET as:

#a/someMethodOfA

A more complex form adds name translation:

<div data-gadget-path="a.html"
     data-gadget-public="someOtherName:someMethodOfA"
     data-gadget-scope="a"/>

can be invoked by a GET as:

#a/someOtherName

It is also possible to publish a method as a POST:

<div data-gadget-path="a.html"
     data-gadget-public="POST:someOtherName:someMethodOfA"
     data-gadget-scope="a"/>

can be invoked by a POST on the page with _route parameter set in the HTTP request to.

_route: a/someOtherName

data-gadget-routed

Routes a given method or event to the router.

In the first example, the interactor gadget defines routes on other gadgets. It is the preferred approach in terms of encapsulation but may cause security issues in the future.

<html>

  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Sample Application with 2 gadgets and interactor</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>

  <body>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Page structure -->
    <div data-gadget-path="a.html" data-gadget-scope="a"/>
    <div data-gadget-path="b.html" data-gadget-scope="b"/>
    <!-- tell the router that calling browser://interact/bang should call bang -->
    <!-- wrap on a.someMehod a call to browser://interact/bang -->
    <!-- wrap on b.anotherEvent a call to browser://interact/bang -->
    <div data-gadget-path="interactor.html" data-gadget-scope="interactor"
         data-gadget-public="bang:bang; "
         data-gadget-routed="a.someMethod:bang; b.anotherEvent:bang">
    </div>
  </body>

</html>

In the second example, each gadget defines its own routes.

<html>

  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Sample Application with 2 gadgets and interactor</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>

  <body>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Page structure -->
    <div data-gadget-path="a.html" data-gadget-scope="a"
         data-gadget-routed="someMethod:interactor/bang"/>
    <div data-gadget-path="b.html" data-gadget-scope="b"
         data-gadget-routed="someMethod:interactor/bang"/>
    <!-- tell the router that calling browser://interact/bang should call bang -->
    <!-- wrap on a.someMehod a call to browser://interact/bang -->
    <!-- wrap on b.anotherEvent a call to browser://interact/bang -->
    <div data-gadget-path="interactor.html" data-gadget-scope="interactor"
         data-gadget-public="bang:bang;">
    </div>
  </body>

</html>

API

Core

renderJS core consists of 3 global methods.

€(scope_selector).declareGadget OR $(selector).declareGadget

* url -- the path of the gadget definition ex. "slide-gadget.html'
* [settings] // A set of key/value pairs
  * state -- the state of the gadget (JSON)
  * scope -- it defines the URL path where the gadget is publishable and the way to retrieve for its parent
  * position -- useful to try to order gadgets inside an element
  * sandbox -- the type of sandboxing (iframe, safefs)

Declares the existence of a gadget by creating or updating it if necessary.

€(scope_selector)

Select all gadgets matching the scope selector.

€(scope_selector).remove

Remove the set of matched gadgets

Interfaces

renderJS provides a standard way to define interfaces using text files.

#http://standard/path/to/interface

Some description of the interface in plain English in one
or more lines of text.

methodName
* parameter1 -- description [OPTIONAL]
* parameter2 -- description [OPTIONAL]

Description of the method in in one or more lines of text.

anotherMethodName
* parameter1 -- description [OPTIONAL]
* parameter2 -- description [OPTIONAL]

Description of the method in in one or more lines of text.

All interfaces should returns promise because everything in renderJS is asynchronous.

Gadget

# http://www.renderjs.org/interface/gadget

The Gadget interface defines gadget introspection.
It should be implemented by every gadget.

getInterfaceList()

Return the list of URL of interfaces of a gadget

getPath()

Returns the path of the HTML5 code of a gadget

getTitle()

Returns the title of a gadget

getRequiredCSSList()

Returns a list of CSS required by the gadget

getRequiredJSList()

Returns a list of JS required by the gadget

Catalog

The Catalog interface defines how to search gadgets badget on gadget metadata.

# http://www.renderjs.org/interface/catalog

The Catalog interface defines a single method to search gadgets based
on their metadata. Its API mimics the API of JIO.

allDocs(filter)
* filter -- JSON dict which defines a predicate on metadata

allDocs returns a list of dictionnaries of the form:
{
  "path" :      "http://some/path/to/the/gadget/source",
  "title" :     "Gadget Title",
  "link" :      "http://some/link/to/the/gadget",
  "interface" : "http://officejs.org/interface/field",
}

Additional parameters can be added to the list in order to
extend the Catalog. For example, mime types and a priority
could be added:

{
  "path" :      "http://some/path/to/the/gadget/source",
  "title" :     "Gadget Title",
  "link" :      "http://some/link/to/the/gadget",
  "interface" : "http://officejs.org/interface/field",
  "mime_type" : "text/svg",
  "priority" :  3,
}

Router

# http://www.renderjs.org/interface/router

The Router interface describes how to make gadgets
communicate and interact eachother. It is based on the
idea of link and the possibility for two gadgets located
in different sandboxes or on different runtime to communicate.

makeLink(gadget, method, link_type)
* gadget -- a gadget or a handle to a gadget
* method -- the method of the gadget or the method ID [OPTIONAL]
* link_type -- the type of link (GET, POST, PUT).a list of mime types which the gadget supports
at least on certain platforms. This method can be used
to build a platform independent catalog of viewer gadgets.

Editor

# http://www.renderjs.org/interface/editor

The Editor interface provides a way to interact
with content in real time through menu actions.
It enables different editors with different menus
to share more commonality in their appearance.

setEditableState
* editable -- true or false

Turns on or off the ability to edit content.

setMenuVisibility
* visibility -- true or false

Shows of hides the default menu of the editor.

getMenuItemTree

Returns the tree of menu actions supported by the
editor. Each menu action is described as a JSON dict
with the following format.

{
  "id":     "open",
  "title":  "Open...",
  "dialog": true,
}

triggerAction
* action

Simulates an action on a menu item.

notifyChange
* location -- the location of the content
* value -- the value of the content which is changed

Each time some content is changes (title, paragraph, etc.)
notifyChange is invoked with two parameters, once which describes
the location of the content which was changed and the other the
new value if any. If undefined value is passed, it is considered
as a way to specify that location was deleted.

setContent
* location -- the location of the content
* value -- the value of the content which is changed

Updates content (by merging if needed).

Text Editor

# http://www.renderjs.org/interface/text-editor

The Text Editor interface provides common text
processing features.

searchAndReplace
* search_pattern --
* replace_pattern --

Replaces one string by another.

getParagraphItemList
* paragraph_type -- can be chapter or an HTML tag

Returns a list of JSON dicts which describe each chapter
in a text editor. This is useful for example to display
a list of chapters outside the text editor.

goToPosition
* position -- the position to set the editor to. Position is an
              arbitrary value defined by getParagraphItemList

Moves text editor to a given position.

Table Editor

# http://www.renderjs.org/interface/image-editor

The Table Editor interface provides a simple way to
access or change lines, columns and cells in a table.

Application Standard Services

Any application needs at least a gadget catalog and a router. By default, renderJS creates a standard router and a standard catalog. It is however possible to overload default services with your own as shown in the example below.

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Gadget Container Slider </title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="render.js" type="text/javascript"></script>
  </head>

  <body>
    <!-- Warning message if no javascript -->
    <noscript>Please turn on Javascript.</noscript>

    <!-- Overload dummy router and catalog with dummy ones -->
    <div data-gadget="dummy-router.html" data-gadget-scope="router"/>
    <div data-gadget="dummy-catalog.html" data-gadget-scope="catalog"/>
  </body>

</html>

By using appropriate scope, the standard catalog and router are overloaded with dummy implementations which... do nothing.

The Standard Router

The router is where everything happens to convert method calls into link invocations emissions and link invocations into method calls, both locally and remotely. It is key to communication between sandboxes in the same page, between URLs and gadgets and between gadgets on different hosts.

The makeHandle method converts a URL of a link to a handle. A handle is a proxy object capable of converting any method call to an AJAX POST. For performance reasons, gadgets in the same sandbox can access eachother directly, without conversion to link of method calls. Yet, the proxying is kept to enforce clean development.

// Get the router which is just a gadget
var router = €("router"),
  // Get a handle to a remote gadget
  handle = router.makeHandle('http://some.server/some/scope/some/gadget');
// Call a method on the remote gadget through the transparent invocation of a link
//   this is just a form of syntactic sugar
handle.someMethod(some_parameter);
// This will call AJAX POST http://some.server/some/scope/some/gadget/someMethod?some_parameter=some_parameter

The makeLink method converts a gadget to a link by concatenating its scope and parent scope.

// Compute the link of a gadget based on its scope and the scope of its parents
link = router.makeLink(gadget);

The makeLink method can receive option method parameters to create links to published methods more easily.

// Compute the link of a gadget based on its scope and the scope of its parents and pass parameters in link
link = router.makeLink(gadget, "POST", "someMethod", {"parameter_name": value});

The router can be used to connect to remote gadgets. In the not so distant future, two routers on different browsers can be interconected through WebRTC. Until this happens, two routers can be interconnected by COMET or Websocket and some intermediate server.

In this example, Gadget A in a remote host and Gadget B is on local host.

First we publish some method of Gadget A by running the following code on remote host:

// This code is executed on remote host (A)
var router_a = €("router"),
  gadget_a = €("a");
// Publish someMethod of gadget_a
router_a.declarePublic(gadget_a, "someMethod?parameter={value}", gadget_a.someMethod);
// Publish declareRouted method of router_a so that it can be remotely invoked
router_a.declarePublic(router_a, "declareRouted", router_a.declareRouted);

Next we invoke on local host the following code:

// This code is executed on local host (B)
var router_b = €("router"),
  gadget_b = €("b"),
  link_b = router.makeLink(gadget_b, 'callB'),
  router_a = router.makeHandle('http://remote.com/router'),
  link_a = "http://remote.com/a";
router_b.declarePublic(gadget_b, "callB", gadget_b.callB);
router_a.declareRouted(link_a, someAMethod, link_b);

What will happen after this is that each time someAMethod is called on Gadget A, Gadget A will invoke link_b which itself will call method callB on Gadget B. In order to achieve this we need to publish declareRouted method of router on A side sode that it can be invoked from B.

The Standard Catalog

RenderJS catalog uses the allDocs API of JIO, including queries.

var catalog = €("catalog"),
  i = 0,
  link,
  catalog_item;
// Use JIO syntax
catalog.allDocs(filter={}).done(function (catalog_item_list) {
  for (i = 0; i < catalog_item_list.length; i += 1) {
    catalog_item = catalog_item_list.length[i];
    link = catalog_item['link'];
    makeHandle(link).done(function (handle) {
      // does a remote call to a living gadget
      handle.getInterfaceList().done(function (interface_list) {
        ...
      });
    });
  }
}

Open Questions

Problems Solved by renderJS

It is possible for example to embed in an HTML5 an SVG editor gadget which itself embeds a menu gadget, both of which are defined by different sources.

Authors

Copyright and license

renderJS is an open-source library and is licensed under the LGPL license. More information on LGPL can be found here

Last update: Tuesday, June 12th, 2013