adamc@580
|
1 function cons(v, ls) {
|
adamc@580
|
2 return { n : ls, v : v };
|
adamc@580
|
3 }
|
adamc@670
|
4
|
adamc@579
|
5 function callAll(ls) {
|
adamc@585
|
6 for (; ls; ls = ls.n)
|
adamc@579
|
7 ls.v();
|
adamc@579
|
8 }
|
adamc@574
|
9
|
adamc@580
|
10 function sc(v) {
|
adamc@580
|
11 return {v : v, h : null};
|
adamc@580
|
12 }
|
adamc@580
|
13 function sv(s, v) {
|
adamc@580
|
14 s.v = v;
|
adamc@580
|
15 callAll(s.h);
|
adamc@580
|
16 }
|
adamc@601
|
17 function sg(s) {
|
adamc@601
|
18 return s.v;
|
adamc@601
|
19 }
|
adamc@579
|
20
|
adamc@580
|
21 function ss(s) {
|
adamc@580
|
22 return s;
|
adamc@580
|
23 }
|
adamc@580
|
24 function sr(v) {
|
adamc@580
|
25 return {v : v, h : null};
|
adamc@580
|
26 }
|
adamc@580
|
27 function sb(x,y) {
|
adamc@580
|
28 var z = y(x.v);
|
adamc@580
|
29 var s = {v : z.v, h : null};
|
adamc@580
|
30
|
adamc@580
|
31 function reZ() {
|
adamc@580
|
32 z.h = cons(function() { s.v = z.v; callAll(s.h); }, z.h);
|
adamc@580
|
33 }
|
adamc@580
|
34
|
adamc@580
|
35 x.h = cons(function() { z = y(x.v); reZ(); s.v = z.v; callAll(s.h); }, x.h);
|
adamc@580
|
36 reZ();
|
adamc@580
|
37
|
adamc@580
|
38 return s;
|
adamc@580
|
39 }
|
adamc@571
|
40
|
adamc@604
|
41 function lastParent() {
|
adamc@604
|
42 var pos = document;
|
adamc@604
|
43
|
adamc@600
|
44 while (pos.lastChild && pos.lastChild.nodeType == 1)
|
adamc@600
|
45 pos = pos.lastChild;
|
adamc@600
|
46
|
adamc@600
|
47 return pos.parentNode;
|
adamc@600
|
48 }
|
adamc@600
|
49
|
adamc@604
|
50 var thisScript = null;
|
adamc@603
|
51
|
adamc@604
|
52 function addNode(node) {
|
adamc@604
|
53 if (thisScript) {
|
adamc@604
|
54 thisScript.parentNode.appendChild(node);
|
adamc@604
|
55 thisScript.parentNode.removeChild(thisScript);
|
adamc@604
|
56 } else
|
adamc@604
|
57 lastParent().appendChild(node);
|
adamc@603
|
58 }
|
adamc@603
|
59
|
adamc@604
|
60 function runScripts(node) {
|
adamc@604
|
61 var savedScript = thisScript;
|
adamc@603
|
62
|
adamc@646
|
63 var scripts = node.getElementsByTagName("script"), scriptsCopy = {};
|
adamc@604
|
64 var len = scripts.length;
|
adamc@646
|
65 for (var i = 0; i < len; ++i)
|
adamc@646
|
66 scriptsCopy[i] = scripts[i];
|
adamc@604
|
67 for (var i = 0; i < len; ++i) {
|
adamc@646
|
68 thisScript = scriptsCopy[i];
|
adamc@604
|
69 eval(thisScript.textContent);
|
adamc@604
|
70 }
|
adamc@604
|
71
|
adamc@604
|
72 thisScript = savedScript;
|
adamc@603
|
73 }
|
adamc@603
|
74
|
adamc@603
|
75 function populate(node, html) {
|
adamc@603
|
76 node.innerHTML = html;
|
adamc@604
|
77 runScripts(node);
|
adamc@603
|
78 }
|
adamc@603
|
79
|
adamc@571
|
80 function dyn(s) {
|
adamc@571
|
81 var x = document.createElement("span");
|
adamc@604
|
82 populate(x, s.v);
|
adamc@604
|
83 addNode(x);
|
adamc@603
|
84 s.h = cons(function() { populate(x, s.v) }, s.h);
|
adamc@571
|
85 }
|
adamc@582
|
86
|
adamc@598
|
87 function inp(t, s) {
|
adamc@598
|
88 var x = document.createElement(t);
|
adamc@598
|
89 x.value = s.v;
|
adamc@604
|
90 addNode(x);
|
adamc@598
|
91 s.h = cons(function() { x.value = s.v }, s.h);
|
adamc@598
|
92 x.onkeyup = function() { sv(s, x.value) };
|
adamc@606
|
93 return x;
|
adamc@598
|
94 }
|
adamc@598
|
95
|
adamc@597
|
96 function eh(x) {
|
adamc@597
|
97 return x.split("&").join("&").split("<").join("<").split(">").join(">");
|
adamc@597
|
98 }
|
adamc@597
|
99
|
adamc@582
|
100 function ts(x) { return x.toString() }
|
adamc@586
|
101 function bs(b) { return (b ? "True" : "False") }
|
adamc@586
|
102
|
adamc@649
|
103 function pi(s) {
|
adamc@649
|
104 var r = parseInt(s);
|
adamc@649
|
105 if (r.toString() == s)
|
adamc@649
|
106 return r;
|
adamc@649
|
107 else
|
adamc@649
|
108 throw "Can't parse int: " + s;
|
adamc@649
|
109 }
|
adamc@649
|
110
|
adamc@649
|
111 function pfl(s) {
|
adamc@649
|
112 var r = parseFloat(s);
|
adamc@649
|
113 if (r.toString() == s)
|
adamc@649
|
114 return r;
|
adamc@649
|
115 else
|
adamc@649
|
116 throw "Can't parse float: " + s;
|
adamc@649
|
117 }
|
adamc@649
|
118
|
adamc@669
|
119 function whine(msg) {
|
adamc@669
|
120 alert(msg);
|
adamc@669
|
121 throw msg;
|
adamc@669
|
122 }
|
adamc@669
|
123
|
adamc@649
|
124 function pf() {
|
adamc@669
|
125 whine("Pattern match failure");
|
adamc@649
|
126 }
|
adamc@589
|
127
|
adamc@603
|
128 var closures = [];
|
adamc@603
|
129
|
adamc@603
|
130 function ca(f) {
|
adamc@603
|
131 var n = closures.length;
|
adamc@603
|
132 closures[n] = f;
|
adamc@603
|
133 return n;
|
adamc@603
|
134 }
|
adamc@603
|
135
|
adamc@603
|
136 function cr(n) {
|
adamc@603
|
137 return closures[n]();
|
adamc@603
|
138 }
|
adamc@603
|
139
|
adamc@609
|
140
|
adamc@668
|
141 var client_id = 0;
|
adamc@668
|
142 var client_pass = 0;
|
adamc@668
|
143 var url_prefix = "/";
|
adamc@668
|
144
|
adamc@668
|
145 function getXHR(uri)
|
adamc@609
|
146 {
|
adamc@609
|
147 try {
|
adamc@609
|
148 return new XMLHttpRequest();
|
adamc@609
|
149 } catch (e) {
|
adamc@609
|
150 try {
|
adamc@609
|
151 return new ActiveXObject("Msxml2.XMLHTTP");
|
adamc@609
|
152 } catch (e) {
|
adamc@609
|
153 try {
|
adamc@609
|
154 return new ActiveXObject("Microsoft.XMLHTTP");
|
adamc@609
|
155 } catch (e) {
|
adamc@609
|
156 throw "Your browser doesn't seem to support AJAX.";
|
adamc@609
|
157 }
|
adamc@609
|
158 }
|
adamc@609
|
159 }
|
adamc@609
|
160 }
|
adamc@609
|
161
|
adamc@668
|
162 function requestUri(xhr, uri) {
|
adamc@668
|
163 xhr.open("GET", uri, true);
|
adamc@668
|
164
|
adamc@668
|
165 if (client_id != 0) {
|
adamc@668
|
166 xhr.setRequestHeader("UrWeb-Client", client_id.toString());
|
adamc@668
|
167 xhr.setRequestHeader("UrWeb-Pass", client_pass.toString());
|
adamc@668
|
168 }
|
adamc@668
|
169
|
adamc@668
|
170 xhr.send(null);
|
adamc@668
|
171 }
|
adamc@668
|
172
|
adamc@613
|
173 function rc(uri, parse, k) {
|
adamc@609
|
174 var xhr = getXHR();
|
adamc@609
|
175
|
adamc@609
|
176 xhr.onreadystatechange = function() {
|
adamc@612
|
177 if (xhr.readyState == 4) {
|
adamc@612
|
178 var isok = false;
|
adamc@612
|
179
|
adamc@612
|
180 try {
|
adamc@612
|
181 if (xhr.status == 200)
|
adamc@612
|
182 isok = true;
|
adamc@612
|
183 } catch (e) { }
|
adamc@612
|
184
|
adamc@612
|
185 if (isok)
|
adamc@613
|
186 k(parse(xhr.responseText));
|
adamc@649
|
187 else {
|
adamc@669
|
188 whine("Error querying remote server!");
|
adamc@649
|
189 }
|
adamc@612
|
190 }
|
adamc@609
|
191 };
|
adamc@609
|
192
|
adamc@668
|
193 requestUri(xhr, uri);
|
adamc@609
|
194 }
|
adamc@667
|
195
|
adamc@667
|
196 function path_join(s1, s2) {
|
adamc@667
|
197 if (s1.length > 0 && s1[s1.length-1] == '/')
|
adamc@667
|
198 return s1 + s2;
|
adamc@667
|
199 else
|
adamc@667
|
200 return s1 + "/" + s2;
|
adamc@667
|
201 }
|
adamc@667
|
202
|
adamc@670
|
203 var channels = [];
|
adamc@670
|
204
|
adamc@670
|
205 function newQueue() {
|
adamc@670
|
206 return { front : null, back : null };
|
adamc@670
|
207 }
|
adamc@670
|
208 function enqueue(q, v) {
|
adamc@670
|
209 if (q.front == null) {
|
adamc@670
|
210 q.front = cons(v, null);
|
adamc@670
|
211 q.back = q.front;
|
adamc@670
|
212 } else {
|
adamc@670
|
213 var node = cons(v, null);
|
adamc@670
|
214 q.back.n = node;
|
adamc@670
|
215 q.back = node;
|
adamc@670
|
216 }
|
adamc@670
|
217 }
|
adamc@670
|
218 function dequeue(q) {
|
adamc@670
|
219 if (q.front == null)
|
adamc@670
|
220 return null;
|
adamc@670
|
221 else {
|
adamc@670
|
222 var r = q.front.v;
|
adamc@670
|
223 q.front = q.front.n;
|
adamc@670
|
224 if (q.front == null)
|
adamc@670
|
225 q.back = null;
|
adamc@670
|
226 return r;
|
adamc@670
|
227 }
|
adamc@670
|
228 }
|
adamc@670
|
229
|
adamc@670
|
230 function newChannel() {
|
adamc@670
|
231 return { msgs : newQueue(), listeners : newQueue() };
|
adamc@670
|
232 }
|
adamc@670
|
233
|
adamc@667
|
234 function listener() {
|
adamc@668
|
235 var uri = path_join(url_prefix, ".msgs");
|
adamc@667
|
236 var xhr = getXHR();
|
adamc@669
|
237 var orsc = function() {
|
adamc@667
|
238 if (xhr.readyState == 4) {
|
adamc@667
|
239 var isok = false;
|
adamc@667
|
240
|
adamc@667
|
241 try {
|
adamc@667
|
242 if (xhr.status == 200)
|
adamc@667
|
243 isok = true;
|
adamc@667
|
244 } catch (e) { }
|
adamc@667
|
245
|
adamc@668
|
246 if (isok) {
|
adamc@669
|
247 var lines = xhr.responseText.split("\n");
|
adamc@669
|
248 if (lines.length < 2)
|
adamc@671
|
249 throw "Empty message from remote server";
|
adamc@669
|
250
|
adamc@669
|
251 for (var i = 0; i+1 < lines.length; i += 2) {
|
adamc@670
|
252 var chn = lines[i];
|
adamc@670
|
253 var msg = lines[i+1];
|
adamc@670
|
254
|
adamc@670
|
255 if (chn < 0)
|
adamc@670
|
256 whine("Out-of-bounds channel in message from remote server");
|
adamc@670
|
257
|
adamc@670
|
258 var ch;
|
adamc@670
|
259
|
adamc@670
|
260 if (chn >= channels.length || channels[chn] == null) {
|
adamc@670
|
261 ch = newChannel();
|
adamc@670
|
262 channels[chn] = ch;
|
adamc@670
|
263 } else
|
adamc@670
|
264 ch = channels[chn];
|
adamc@670
|
265
|
adamc@670
|
266 var listener = dequeue(ch.listeners);
|
adamc@670
|
267 if (listener == null) {
|
adamc@670
|
268 enqueue(ch.msgs, msg);
|
adamc@670
|
269 } else {
|
adamc@670
|
270 listener(msg);
|
adamc@670
|
271 }
|
adamc@669
|
272 }
|
adamc@669
|
273
|
adamc@669
|
274 xhr.onreadystatechange = orsc;
|
adamc@668
|
275 requestUri(xhr, uri);
|
adamc@668
|
276 }
|
adamc@667
|
277 else {
|
adamc@672
|
278 try {
|
adamc@672
|
279 whine("Error querying remote server for messages! " + xhr.status);
|
adamc@672
|
280 } catch (e) { }
|
adamc@667
|
281 }
|
adamc@667
|
282 }
|
adamc@667
|
283 };
|
adamc@667
|
284
|
adamc@669
|
285 xhr.onreadystatechange = orsc;
|
adamc@668
|
286 requestUri(xhr, uri);
|
adamc@667
|
287 }
|
adamc@670
|
288
|
adamc@670
|
289 function rv(chn, parse, k) {
|
adamc@670
|
290 if (chn < 0)
|
adamc@670
|
291 whine("Out-of-bounds channel receive");
|
adamc@670
|
292
|
adamc@670
|
293 var ch;
|
adamc@670
|
294
|
adamc@670
|
295 if (chn >= channels.length || channels[chn] == null) {
|
adamc@670
|
296 ch = newChannel();
|
adamc@670
|
297 channels[chn] = ch;
|
adamc@670
|
298 } else
|
adamc@670
|
299 ch = channels[chn];
|
adamc@670
|
300
|
adamc@670
|
301 var msg = dequeue(ch.msgs);
|
adamc@670
|
302 if (msg == null) {
|
adamc@670
|
303 enqueue(ch.listeners, function(msg) { k(parse(msg))(null); });
|
adamc@670
|
304 } else {
|
adamc@670
|
305 k(parse(msg))(null);
|
adamc@670
|
306 }
|
adamc@670
|
307 }
|
adamc@670
|
308
|
adamc@670
|
309 function unesc(s) {
|
adamc@670
|
310 return unescape(s).replace("+", " ");
|
adamc@670
|
311 }
|