-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtranslate.html
133 lines (104 loc) · 5.02 KB
/
translate.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
---
layout: default
title: Translation Tool
---
# Translation Tool
For browsers that do not yet support JavaScript [Proxies][] (soon to
be [Direct-Proxies][]), code that is run within an AtomizeJS
transaction must be translated. AtomizeJS comes with a translation
tool which does this.
After doing an `npm install atomize-client`, you should find `npm` has
installed an `atomize-translate` binary.
# Usage
`atomize-translate` *`input`* *`output`* *`atomizeVar`* *[`ignore`...]*
* *`input`*: The path to the input file. The input file must be a pure
JavaScript file, not be an HTML file with JavaScript embedded.
* *`output`*: The path to the output file.
* *`atomizeVar`*: The name of the `atomize` variable, i.e. variable to
which the result `new Atomize(URL)` is assigned. A limitation of
using the translation tool is that it is assumed this variable is
both global, and that only one AtomizeJS server is ever connected to
at any one time.
* *[`ignore`...]*: Names of variables that should be excluded from
translation. This list always implicitly contains the `atomizeVar`.
The tool should be run on any JavaScript file that contains code that
can be reached from within an AtomizeJS transaction. For example, if
you have the code in `ball.js.raw`:
{% highlight javascript %}
var server = new Atomize("http://localhost:9999/atomize");
function Ball (x, y) {
this.x = x;
this.y = y;
this.raw = server.lift({x: x, y: y});
}
Ball.prototype = {
bounce: function () {
var self = this;
server.atomically(function () {
self.raw.y = -self.raw.y;
}, function (y) {
self.y = y;
});
}
};
{% endhighlight %}
Then you should run the translation tool as
atomize-translate ball.js.raw ball.js server Ball this
This will ensure that the `Ball` object itself and `this` is left
untouched, even though the functions within the `Ball` object will be
translated correctly. However, if in the transaction you manipulated
the global `Ball` object itself (rather than an instance of the `Ball`
object) then it would be wrong to have `Ball` in the ignored list.
It is normally safe to leave the *[`ignore`...]* list empty. However,
doing so will likely result in the connection to the AtomizeJS server
being required as the source code is itself being loaded by the
browser. Thus in the above example, as the connection to the server is
established as the first line, there would be no problem in leaving
the *[`ignore`...]* field empty. But were the connection established
in some other function later on, the `ball.js` file would fail to load
if the *[`ignore`...]* field does not contain the global `Ball`.
**In general, global variables which are accessed and assigned to as
part of loading the JavaScript file may well need to be provided to
the *[`ignore`...]* field.**
Also note that if in your transactions you call functions that reside
in other files, you should run the translation tool on those files
too.
You must also `<script/>`-include the
[compat.js](https://github.com/atomizejs/atomize-client/blob/master/lib/compat.js)
library *before* the
[atomize.js](https://github.com/atomizejs/atomize-client/blob/master/lib/atomize.js)
library in the browser. It does no harm to load this
[compat.js](https://github.com/atomizejs/atomize-client/blob/master/lib/compat.js)
library even on bleeding-edge browsers: the library will detect
whether or not it's really needed and act accordingly.
# Under the bonnet
AtomizeJS relies on proxies. A proxy gives the programmer the ability
to intercept *all* actions upon an object and AtomizeJS needs this to
be able to figure out the actions that are performed as part of a
transaction: to intercept and record these actions as part of the
transaction log. Thus even if you have `a[x] = 5`, the proxy will
ensure that the assignment will be intercepted regardless of where the
value of `x` came from - it might even come directly from the user.
If the browser does not support proxies then there's not much you can
do without re-writing the code, and that's what the translation tool
does. Yes, you could use the `Object.defineProperty` to implement
getters and setters, but that only works for existing properties. If
you have `var a = {}, x = Math.random(); a[x] = 'hello';` then you
can't intercept the assignment to a new field by using
`Object.defineProperty`.
The translation tool thus rewrites all assignments, accesses, `for a
in b` iterations, `a in b` checks, and `delete` operations to
explicitly go via an extended AtomizeJS API. Thus assuming the
connection to the AtomizeJS server is assigned to a variable called
`atomize`, the translation tool will, for example, rewrite
a[x] = 5;
into
atomize.assign(a, x, 5);
and will rewrite
a.b = c[d];
into
atomize.assign(a, 'b', atomize.access(c, [d]));
There is nothing to stop you from writing code which uses this API
directly, and indeed if you do so, then you will not need to use the
translation tool at all, and your code will work in both old and new
browsers. But it does make the code a little less concise.