<p>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.</p>
<p>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.</p>
<h2>A Simple Example</h2>
<p>Let us suppose we want to add a text editor to an HTML5 page,
<p>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
<p>We will learn here how to create a gadget, how to use a gadget and how
to make gadgets interact.</p>
<h2>Tutorial 1: Hello Viewer</h2>
<p>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.</p>
<p>Here how to do.</p>
<p>Let us add an HTML document to our web server in <code>/var/www/html/hello_viewer/test.html</code></p>
<p>Let us add an SVG document to our web server in <code>/var/www/html/hello_viewer/test.svg</code></p>
<p>We are going to display both documents in the page using whichever editor is available to display it.</p>
<p>We create the HTML file <code>/var/www/html/hello_viewer/test.html</code> with the following code.</p>
<p>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 <code>data-gadget-sandbox</code> on
both gadgets in order to make sure that an iframe sandbox prevent CSS conflicts which most viewers generate because of poor namespacing.</p>
<h2>Tutorial 2: Hello World</h2>
<p>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.</p>
<code>/var/www/html/gadget/hello_world</code>
<p>Then we create the file <code>/var/www/html/gadget/hello_world/index.html</code> that will contain the gadget code.</p>
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.
</p>
<p>Let us now add some behaviour to our gadget. We create a script <code>/var/www/html/gadget/hello_world/hello.js</code> with the following code</p>
<pre>
€(this).declareMethod("foo", function () {
// replace body paragraph with Bang! word
$(this).find('p').text("Bang!");
});
</pre>
<p>We now need to attach a dependency to this script in the gadget definition. We are going also to use the <code>data-gadget-public</code> tag.</p>
<p>If we open our Web browser to <code>http://localhost/gadget/hello_world/index.html</code>, we can view the Hello Word gadget itself:</p>
[DRAWING]
<p>Now, if we type the URL <code>http://localhost/gadget/hello_world/index.html#foo</code>, we get something new:</p>
[DRAWING]
<p>What happens here is that the <code>data-gadget-public</code> has declared the method <code>foo</code> 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.
<code>http://localhost/gadget/hello_application/index.html#hello/foo</code>. Here is the result:</p>
[DRAWING]
<p>The content "Hello World" was replaced by "Bang!". This example shows the concept of recursive publication of gadgets provided by renderJS. By using the
<code>data-gadget-scope</code> tag, every public method of a gadget can be accessed through a simple URL.</p>
<h2>Tutorial 3: a slider gadget containing two forms and an interactor</h2>
<p>We will now show a more complex example to illustrate the advanced macro capabilities of renderJS and the concept of interactor.</p>
<p>Let us create a slider field where the slider widget itself can contain any gadgets, such as forms, date fields, animated sprite, etc.</p>
[DRAWING]
<p>Let us first define the HTML5 code of the gadget in <code>/var/www/gadget/slider/index.html</code></p>
<pre>
<html>
<!-- Define dependencies and supported interfaces -->
<!-- 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>
</pre>
<p>We can now define the CSS of <code>slider.css</code>:</p>
<pre>
.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;
}
</pre>
<p>The Javascript code of <code>slider.js</code> looks like this:</p>
<pre>
XXX TO BE COMPLETED
</pre>
<p>This example introduces some new concepts of renderJS. The <code>data-gadget-slot</code> 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.</p>
<p>Another important concept introduced in this example is the notion of interface. The relation type <code>http://www.renderjs.org/rel/interface</code> defines
an interface relation, following the concepts of link relation used increasingly in modern REST applications based on the <a
href="http://en.wikipedia.org/wiki/HATEOAS">HATEOAS</a> approach. We define here that our gadget follows the renderable interface and the field interface.</p>
<p>Interfaces are self-documented online:</p>
<pre>
# 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.
</pre>
<pre>
# 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.
</pre>
<p>Let us now create a small application which embeds two forms inside a slider gadget and created an interaction between forms and the slider.</p>
<p>We should first create a form gadget in <code>/var/www/gadget/slider/form.html</code></p>
<p>and define the <code>form.js</code> script which implements the field API for the form itself.</p>
<pre>
€(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);
});
</pre>
<p>It is time now to assemble all parts into an application: a slide gadget and two instances of the form in <code>/var/www/gadget/slider/example.html</code></p>
<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>
</pre>
<p>This example shows a typical example of the <code>data-gadget-scope</code> tag in order to distinguish to instances of the same gadget. It also shows how the
<code>data-gadget-fill</code> tag operates by filling the <code>data-gadget-slot</code> named "main" in the Slider gadget.</p>
<p>Let us display the result by opening the URL <code>http://localhost/gadget/slider/sample.html</code>:</p>
[DISPLAY]
<p>Let us illustrate how the <code>data-gadget-public</code> tag works in combination with <code>data-gadget-scope</code>.</p>
<p>And if we call <code>http://localhost/gadget/slider/sample.html#first/setValue?value=3</code>
[DISPLAY]
<p>The second form changes with value set to 3.</p>
<p>If we call <code>http://localhost/gadget/slider/sample.html#second/setValue?value=7</code>
[DISPLAY]
<p>The second form changes with value set to 7.</p>
<p>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.</p>
<p>What we just did here is to use the tag <code>data-gadget-public</code> which simulates the call to a URL each time a method of a gadget is invokes. For
example, if <code>setValue</code> is invoked on the first single field form, then we simulate a call to the URL <code>interactor/notifyUpdatedValue</code> and
pass to it the parameters of setValue which ere interested in.</p>
<p>We can now define the interactor HTML5 code for <code>interactor.html</code>:</p>
<p>can be invoked by a POST on the page with _route parameter set in the HTTP request to.</p>
<pre>_route: a/someOtherName</pre>
<h2>data-gadget-routed</h2>
<p>Routes a given method or event to the router.</p>
<p>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
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.
</pre>
<h2>Editor</h2>
<pre>
# 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).
</pre>
<h2>Text Editor</h2>
<pre>
# 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.
</pre>
<h2>Table Editor</h2>
<pre>
# 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.
</pre>
<h1>Application Standard Services</h1>
<p>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.</p>
<p>By using appropriate scope, the standard catalog and router are overloaded with dummy implementations which... do nothing.</p>
<h2>The Standard Router</h2>
<p>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.</p>
<p>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
// 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
</pre>
<p>The makeLink method converts a gadget to a link by concatenating its scope and parent scope.</p>
<pre>
// Compute the link of a gadget based on its scope and the scope of its parents
link = router.makeLink(gadget);
</pre>
<p>The makeLink method can receive option method parameters to create links to published methods more easily.</p>
<pre>
// 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});
</pre>
<p>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.</p>
<p>In this example, Gadget A in a remote host and Gadget B is on local host.</p>
<p>First we publish some method of Gadget A by running the following code on remote host:</p>
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.
</p>
<h2>The Standard Catalog</h2>
<p>RenderJS catalog uses the allDocs API of JIO, including queries.</p>
Who is allowed to publish a method ? (parent is allowed to publish method of child ?) -> parent for child OR security policy defined
</li><li>
Is it better to have promise based (setGadget) or imperative based (addGadget) -> declarative
</li><li>
are makeLink and makeHandle part of router API, global methods or gadget methods ? -> router API
</li><li>
Should it be router.makeLink(gadget) or gadget.makeLink() or makeLink(gadget, someMethod) etc. -> router API
</li><li>
Should fireLink be method of router or each gadget -> router
</li>
</ul>
<h1id="g2">Problems Solved by renderJS </h1>
<p> 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. </p>
<h1id="g3">Authors</h1>
<aname="Authors"></a>
<ul>
<li>Ivan Tyagov</li>
<li>Jean-Paul Smets</li>
<li>Sven Franck</li>
<li>Romain Courteaud</li>
</ul>
<h1id="g4">Copyright and license</h1>
<p>renderJS is an open-source library and is licensed under the LGPL license. More