version 0.0.1
Hiphop.js is a Hop.js library witch allow orchestrate web applications.
$HOME/.node_modules/
"use hopscript"
const hiphop = require("hiphop")
The goal of this tutorial is to glimpse the benefit of using Hiphop.js to orchestrate JavaScript events. We'll building a simple translator form. Each time a user add a new character, the program will query a web service to ask the translation from a language to another of the form' string. When the web service sends a result, it is display in the screen.
A naive implementation of the example would be the following:
"use hopscript"
service translator() {
return <html>
<head>
~{
var trad;
function translate(value) {
var xhttp = new XMLHttpRequest();
var svc = "http://mymemory.translated.net/api/get";
var opt = "?langpair=fr|en&q=" + value;
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
let res = JSON.parse(xhttp.responseText);
trad.value = res.responseData.translatedText
}
}.bind(this);
xhttp.open("GET", svc + opt, true);
xhttp.send();
}
onload = function() {
trad = hop.reactProxy({value: ""});
}
}
</head>
<body>
<input type="text" oninput=~{translate(this.value)}/>
<div><react>~{trad.value}</react></div>
</body>
</html>;
}
But this implementation had two major drawbacks:
The translation result is updated each times an answer comes. It is difficult to know if we have to wait or if this is the actual translation.
Since there is no guarantee of the scheduling of the events with the web service, the last answer can be the answer of the first query, and the translation would be wrong.
It is possible to correct this behavior my manually associating a sequence number to each request, and update the translation only when the answer from the last query comes, and drop the others. However, this is related to a hack which lead to:
A complex code, hard to maintains.
A non-understandable semantics when reading the program.
Here is the Hiphop.js version, without the previous drawbacks:
"use hopscript"
const hh = require("hiphop");
service translator() {
return <html>
<head module=${"hiphop"}>
~{
var hh;
var m;
var trad;
function translate() {
var xhttp = new XMLHttpRequest();
var svc = "http://mymemory.translated.net/api/get";
var opt = "?langpair=fr|en&q=" + this.value.text;
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
let res = JSON.parse(xhttp.responseText);
this.notifyAndReact(res.responseData.translatedText);
}
}.bind(this);
xhttp.open("GET", svc + opt, true);
xhttp.send();
}
onload = function() {
hh = require("hiphop");
m = new hh.ReactiveMachine(
<hh.module text trad>
<hh.every immediate text>
<hh.exec trad apply=${translate}/>
</hh.every>
</hh.module>);
trad = m.reactProxy("trad");
}
}
</head>
<body>
<input type="text" oninput=~{m.inputAndReact("text", this.value)}/>
<div><react>~{trad.value}</react></div>
</body>
</html>;
}