1 # Copyright 2006 James Tauber and contributors |
|
2 # |
|
3 # Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 # you may not use this file except in compliance with the License. |
|
5 # You may obtain a copy of the License at |
|
6 # |
|
7 # http://www.apache.org/licenses/LICENSE-2.0 |
|
8 # |
|
9 # Unless required by applicable law or agreed to in writing, software |
|
10 # distributed under the License is distributed on an "AS IS" BASIS, |
|
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
12 # See the License for the specific language governing permissions and |
|
13 # limitations under the License. |
|
14 |
|
15 # pylint: disable=too-many-function-args,undefined-variable,no-absolute-import,assign-to-new-keyword,nonzero-method,next-method-called,next-method-defined |
|
16 |
|
17 # iteration from Bob Ippolito's Iteration in JavaScript |
|
18 |
|
19 from __pyjamas__ import JS |
|
20 |
|
21 # must declare import _before_ importing sys |
|
22 |
|
23 |
|
24 def import_module(path, parent_module, module_name, dynamic=1, async=False): |
|
25 |
|
26 JS(""" |
|
27 var cache_file; |
|
28 |
|
29 if (module_name == "sys" || module_name == 'pyjslib') |
|
30 { |
|
31 /*module_load_request[module_name] = 1;*/ |
|
32 return; |
|
33 } |
|
34 |
|
35 if (path == null) |
|
36 { |
|
37 path = './'; |
|
38 } |
|
39 |
|
40 var override_name = sys.platform + "." + module_name; |
|
41 if (((sys.overrides != null) && |
|
42 (sys.overrides.has_key(override_name)))) |
|
43 { |
|
44 cache_file = sys.overrides.__getitem__(override_name) ; |
|
45 } |
|
46 else |
|
47 { |
|
48 cache_file = module_name ; |
|
49 } |
|
50 |
|
51 cache_file = (path + cache_file + '.cache.js' ) ; |
|
52 |
|
53 //alert("cache " + cache_file + " " + module_name + " " + parent_module); |
|
54 |
|
55 /* already loaded? */ |
|
56 if (module_load_request[module_name]) |
|
57 { |
|
58 if (module_load_request[module_name] >= 3 && parent_module != null) |
|
59 { |
|
60 //onload_fn = parent_module + '.' + module_name + ' = ' + module_name + ';'; |
|
61 //pyjs_eval(onload_fn); /* set up the parent-module namespace */ |
|
62 } |
|
63 return; |
|
64 } |
|
65 if (typeof (module_load_request[module_name]) == 'undefined') |
|
66 { |
|
67 module_load_request[module_name] = 1; |
|
68 } |
|
69 |
|
70 /* following a load, this first executes the script |
|
71 * "preparation" function MODULENAME_loaded_fn() |
|
72 * and then sets up the loaded module in the namespace |
|
73 * of the parent. |
|
74 */ |
|
75 |
|
76 onload_fn = ''; // module_name + "_loaded_fn();" |
|
77 |
|
78 if (parent_module != null) |
|
79 { |
|
80 //onload_fn += parent_module + '.' + module_name + ' = ' + module_name + ';'; |
|
81 /*pmod = parent_module + '.' + module_name; |
|
82 onload_fn += 'alert("' + pmod + '"+' + pmod+');';*/ |
|
83 } |
|
84 |
|
85 |
|
86 if (dynamic) |
|
87 { |
|
88 /* this one tacks the script onto the end of the DOM |
|
89 */ |
|
90 |
|
91 pyjs_load_script(cache_file, onload_fn, async); |
|
92 |
|
93 /* this one actually RUNS the script (eval) into the page. |
|
94 my feeling is that this would be better for non-async |
|
95 but i can't get it to work entirely yet. |
|
96 */ |
|
97 /*pyjs_ajax_eval(cache_file, onload_fn, async);*/ |
|
98 } |
|
99 else |
|
100 { |
|
101 if (module_name != "pyjslib" && |
|
102 module_name != "sys") |
|
103 pyjs_eval(onload_fn); |
|
104 } |
|
105 |
|
106 """) |
|
107 |
|
108 |
|
109 JS(""" |
|
110 function import_wait(proceed_fn, parent_mod, dynamic) { |
|
111 |
|
112 var data = ''; |
|
113 var element = $doc.createElement("div"); |
|
114 $doc.body.appendChild(element); |
|
115 function write_dom(txt) { |
|
116 element.innerHTML = txt + '<br />'; |
|
117 } |
|
118 |
|
119 var timeoutperiod = 1; |
|
120 if (dynamic) |
|
121 var timeoutperiod = 1; |
|
122 |
|
123 var wait = function() { |
|
124 |
|
125 var status = ''; |
|
126 for (l in module_load_request) |
|
127 { |
|
128 var m = module_load_request[l]; |
|
129 if (l == "sys" || l == 'pyjslib') |
|
130 continue; |
|
131 status += l + m + " "; |
|
132 } |
|
133 |
|
134 //write_dom( " import wait " + wait_count + " " + status + " parent_mod " + parent_mod); |
|
135 wait_count += 1; |
|
136 |
|
137 if (status == '') |
|
138 { |
|
139 setTimeout(wait, timeoutperiod); |
|
140 return; |
|
141 } |
|
142 |
|
143 for (l in module_load_request) |
|
144 { |
|
145 var m = module_load_request[l]; |
|
146 if (l == "sys" || l == 'pyjslib') |
|
147 { |
|
148 module_load_request[l] = 4; |
|
149 continue; |
|
150 } |
|
151 if ((parent_mod != null) && (l == parent_mod)) |
|
152 { |
|
153 if (m == 1) |
|
154 { |
|
155 setTimeout(wait, timeoutperiod); |
|
156 return; |
|
157 } |
|
158 if (m == 2) |
|
159 { |
|
160 /* cheat and move app on to next stage */ |
|
161 module_load_request[l] = 3; |
|
162 } |
|
163 } |
|
164 if (m == 1 || m == 2) |
|
165 { |
|
166 setTimeout(wait, timeoutperiod); |
|
167 return; |
|
168 } |
|
169 if (m == 3) |
|
170 { |
|
171 //alert("waited for module " + l + ": loaded"); |
|
172 module_load_request[l] = 4; |
|
173 mod_fn = modules[l]; |
|
174 } |
|
175 } |
|
176 //alert("module wait done"); |
|
177 |
|
178 if (proceed_fn.importDone) |
|
179 proceed_fn.importDone(proceed_fn); |
|
180 else |
|
181 proceed_fn(); |
|
182 } |
|
183 |
|
184 wait(); |
|
185 } |
|
186 """) |
|
187 |
|
188 |
|
189 # pylint: disable=old-style-class |
|
190 class Object: |
|
191 def __init__(self): |
|
192 pass |
|
193 |
|
194 |
|
195 object = Object |
|
196 |
|
197 |
|
198 class Modload: |
|
199 |
|
200 def __init__(self, path, app_modlist, app_imported_fn, dynamic, |
|
201 parent_mod): |
|
202 self.app_modlist = app_modlist |
|
203 self.app_imported_fn = app_imported_fn |
|
204 self.path = path |
|
205 self.idx = 0 |
|
206 self.dynamic = dynamic |
|
207 self.parent_mod = parent_mod |
|
208 |
|
209 def next(self): |
|
210 |
|
211 for i in range(len(self.app_modlist[self.idx])): |
|
212 app = self.app_modlist[self.idx][i] |
|
213 import_module(self.path, self.parent_mod, app, self.dynamic, True) |
|
214 self.idx += 1 |
|
215 |
|
216 if self.idx >= len(self.app_modlist): |
|
217 import_wait(self.app_imported_fn, self.parent_mod, self.dynamic) |
|
218 else: |
|
219 import_wait(getattr(self, "next"), self.parent_mod, self.dynamic) |
|
220 |
|
221 |
|
222 def get_module(module_name): |
|
223 _ev = "__mod = %s;" % module_name |
|
224 JS("pyjs_eval(_ev);") |
|
225 return __mod |
|
226 |
|
227 |
|
228 def preload_app_modules(path, app_modnames, app_imported_fn, dynamic, |
|
229 parent_mod=None): |
|
230 |
|
231 loader = Modload(path, app_modnames, app_imported_fn, dynamic, parent_mod) |
|
232 loader.next() |
|
233 |
|
234 |
|
235 # as comment on line 20 says |
|
236 # import sys should be below |
|
237 import sys # noqa # pylint: disable=wrong-import-order,unused-import,wrong-import-position |
|
238 |
|
239 |
|
240 class BaseException: |
|
241 |
|
242 name = "BaseException" |
|
243 |
|
244 def __init__(self, *args): |
|
245 self.args = args |
|
246 |
|
247 def __str__(self): |
|
248 if len(self.args) is 0: |
|
249 return '' |
|
250 elif len(self.args) is 1: |
|
251 return repr(self.args[0]) |
|
252 return repr(self.args) |
|
253 |
|
254 def toString(self): |
|
255 return str(self) |
|
256 |
|
257 |
|
258 class Exception(BaseException): |
|
259 name = "Exception" |
|
260 |
|
261 |
|
262 class TypeError(BaseException): |
|
263 name = "TypeError" |
|
264 |
|
265 |
|
266 class StandardError(Exception): |
|
267 name = "StandardError" |
|
268 |
|
269 |
|
270 class LookupError(StandardError): |
|
271 name = "LookupError" |
|
272 |
|
273 def toString(self): |
|
274 return self.name + ": " + self.args[0] |
|
275 |
|
276 |
|
277 class KeyError(LookupError): |
|
278 name = "KeyError" |
|
279 |
|
280 |
|
281 class AttributeError(StandardError): |
|
282 name = "AttributeError" |
|
283 |
|
284 def toString(self): |
|
285 return "AttributeError: %s of %s" % (self.args[1], self.args[0]) |
|
286 |
|
287 |
|
288 JS(r""" |
|
289 pyjslib.StopIteration = function () { }; |
|
290 pyjslib.StopIteration.prototype = new Error(); |
|
291 pyjslib.StopIteration.name = 'StopIteration'; |
|
292 pyjslib.StopIteration.message = 'StopIteration'; |
|
293 |
|
294 pyjslib.String_find = function(sub, start, end) { |
|
295 var pos=this.indexOf(sub, start); |
|
296 if (pyjslib.isUndefined(end)) return pos; |
|
297 |
|
298 if (pos + sub.length>end) return -1; |
|
299 return pos; |
|
300 } |
|
301 |
|
302 pyjslib.String_join = function(data) { |
|
303 var text=""; |
|
304 |
|
305 if (pyjslib.isArray(data)) { |
|
306 return data.join(this); |
|
307 } |
|
308 else if (pyjslib.isIteratable(data)) { |
|
309 var iter=data.__iter__(); |
|
310 try { |
|
311 text+=iter.next(); |
|
312 while (true) { |
|
313 var item=iter.next(); |
|
314 text+=this + item; |
|
315 } |
|
316 } |
|
317 catch (e) { |
|
318 if (e != pyjslib.StopIteration) throw e; |
|
319 } |
|
320 } |
|
321 |
|
322 return text; |
|
323 } |
|
324 |
|
325 pyjslib.String_isdigit = function() { |
|
326 return (this.match(/^\d+$/g) != null); |
|
327 } |
|
328 |
|
329 pyjslib.String_replace = function(old, replace, count) { |
|
330 var do_max=false; |
|
331 var start=0; |
|
332 var new_str=""; |
|
333 var pos=0; |
|
334 |
|
335 if (!pyjslib.isString(old)) return this.__replace(old, replace); |
|
336 if (!pyjslib.isUndefined(count)) do_max=true; |
|
337 |
|
338 while (start<this.length) { |
|
339 if (do_max && !count--) break; |
|
340 |
|
341 pos=this.indexOf(old, start); |
|
342 if (pos<0) break; |
|
343 |
|
344 new_str+=this.substring(start, pos) + replace; |
|
345 start=pos+old.length; |
|
346 } |
|
347 if (start<this.length) new_str+=this.substring(start); |
|
348 |
|
349 return new_str; |
|
350 } |
|
351 |
|
352 pyjslib.String_split = function(sep, maxsplit) { |
|
353 var items=new pyjslib.List(); |
|
354 var do_max=false; |
|
355 var subject=this; |
|
356 var start=0; |
|
357 var pos=0; |
|
358 |
|
359 if (pyjslib.isUndefined(sep) || pyjslib.isNull(sep)) { |
|
360 sep=" "; |
|
361 subject=subject.strip(); |
|
362 subject=subject.replace(/\s+/g, sep); |
|
363 } |
|
364 else if (!pyjslib.isUndefined(maxsplit)) do_max=true; |
|
365 |
|
366 if (subject.length == 0) { |
|
367 return items; |
|
368 } |
|
369 |
|
370 while (start<subject.length) { |
|
371 if (do_max && !maxsplit--) break; |
|
372 |
|
373 pos=subject.indexOf(sep, start); |
|
374 if (pos<0) break; |
|
375 |
|
376 items.append(subject.substring(start, pos)); |
|
377 start=pos+sep.length; |
|
378 } |
|
379 if (start<=subject.length) items.append(subject.substring(start)); |
|
380 |
|
381 return items; |
|
382 } |
|
383 |
|
384 pyjslib.String___iter__ = function() { |
|
385 var i = 0; |
|
386 var s = this; |
|
387 return { |
|
388 'next': function() { |
|
389 if (i >= s.length) { |
|
390 throw pyjslib.StopIteration; |
|
391 } |
|
392 return s.substring(i++, i, 1); |
|
393 }, |
|
394 '__iter__': function() { |
|
395 return this; |
|
396 } |
|
397 }; |
|
398 } |
|
399 |
|
400 pyjslib.String_strip = function(chars) { |
|
401 return this.lstrip(chars).rstrip(chars); |
|
402 } |
|
403 |
|
404 pyjslib.String_lstrip = function(chars) { |
|
405 if (pyjslib.isUndefined(chars)) return this.replace(/^\s+/, ""); |
|
406 |
|
407 return this.replace(new RegExp("^[" + chars + "]+"), ""); |
|
408 } |
|
409 |
|
410 pyjslib.String_rstrip = function(chars) { |
|
411 if (pyjslib.isUndefined(chars)) return this.replace(/\s+$/, ""); |
|
412 |
|
413 return this.replace(new RegExp("[" + chars + "]+$"), ""); |
|
414 } |
|
415 |
|
416 pyjslib.String_startswith = function(prefix, start) { |
|
417 if (pyjslib.isUndefined(start)) start = 0; |
|
418 |
|
419 if (this.substring(start, prefix.length) == prefix) return true; |
|
420 return false; |
|
421 } |
|
422 |
|
423 pyjslib.abs = Math.abs; |
|
424 |
|
425 """) |
|
426 |
|
427 |
|
428 class Class: |
|
429 def __init__(self, name): |
|
430 self.name = name |
|
431 |
|
432 def __str___(self): |
|
433 return self.name |
|
434 |
|
435 |
|
436 def eq(a, b): |
|
437 JS(""" |
|
438 if (pyjslib.hasattr(a, "__cmp__")) { |
|
439 return a.__cmp__(b) == 0; |
|
440 } else if (pyjslib.hasattr(b, "__cmp__")) { |
|
441 return b.__cmp__(a) == 0; |
|
442 } |
|
443 return a == b; |
|
444 """) |
|
445 |
|
446 |
|
447 def cmp(a, b): |
|
448 if hasattr(a, "__cmp__"): |
|
449 return a.__cmp__(b) |
|
450 elif hasattr(b, "__cmp__"): |
|
451 return -b.__cmp__(a) |
|
452 if a > b: |
|
453 return 1 |
|
454 elif b > a: |
|
455 return -1 |
|
456 else: |
|
457 return 0 |
|
458 |
|
459 |
|
460 def bool(v): |
|
461 # this needs to stay in native code without any dependencies here, |
|
462 # because this is used by if and while, we need to prevent |
|
463 # recursion |
|
464 JS(""" |
|
465 if (!v) return false; |
|
466 switch(typeof v){ |
|
467 case 'boolean': |
|
468 return v; |
|
469 case 'object': |
|
470 if (v.__nonzero__){ |
|
471 return v.__nonzero__(); |
|
472 }else if (v.__len__){ |
|
473 return v.__len__()>0; |
|
474 } |
|
475 return true; |
|
476 } |
|
477 return Boolean(v); |
|
478 """) |
|
479 |
|
480 |
|
481 class List: |
|
482 def __init__(self, data=None): |
|
483 JS(""" |
|
484 this.l = []; |
|
485 this.extend(data); |
|
486 """) |
|
487 |
|
488 def append(self, item): |
|
489 JS(""" this.l[this.l.length] = item;""") |
|
490 |
|
491 def extend(self, data): |
|
492 JS(""" |
|
493 if (pyjslib.isArray(data)) { |
|
494 n = this.l.length; |
|
495 for (var i=0; i < data.length; i++) { |
|
496 this.l[n+i]=data[i]; |
|
497 } |
|
498 } |
|
499 else if (pyjslib.isIteratable(data)) { |
|
500 var iter=data.__iter__(); |
|
501 var i=this.l.length; |
|
502 try { |
|
503 while (true) { |
|
504 var item=iter.next(); |
|
505 this.l[i++]=item; |
|
506 } |
|
507 } |
|
508 catch (e) { |
|
509 if (e != pyjslib.StopIteration) throw e; |
|
510 } |
|
511 } |
|
512 """) |
|
513 |
|
514 def remove(self, value): |
|
515 JS(""" |
|
516 var index=this.index(value); |
|
517 if (index<0) return false; |
|
518 this.l.splice(index, 1); |
|
519 return true; |
|
520 """) |
|
521 |
|
522 def index(self, value, start=0): |
|
523 JS(""" |
|
524 var length=this.l.length; |
|
525 for (var i=start; i<length; i++) { |
|
526 if (this.l[i]==value) { |
|
527 return i; |
|
528 } |
|
529 } |
|
530 return -1; |
|
531 """) |
|
532 |
|
533 def insert(self, index, value): |
|
534 JS(""" var a = this.l; this.l=a.slice(0, index).concat(value, a.slice(index));""") |
|
535 |
|
536 def pop(self, index=-1): |
|
537 JS(""" |
|
538 if (index<0) index = this.l.length + index; |
|
539 var a = this.l[index]; |
|
540 this.l.splice(index, 1); |
|
541 return a; |
|
542 """) |
|
543 |
|
544 def __cmp__(self, l): |
|
545 if not isinstance(l, List): |
|
546 return -1 |
|
547 ll = len(self) - len(l) |
|
548 if ll != 0: |
|
549 return ll |
|
550 for x in range(len(l)): |
|
551 ll = cmp(self.__getitem__(x), l[x]) |
|
552 if ll != 0: |
|
553 return ll |
|
554 return 0 |
|
555 |
|
556 def slice(self, lower, upper): |
|
557 JS(""" |
|
558 if (upper==null) return pyjslib.List(this.l.slice(lower)); |
|
559 return pyjslib.List(this.l.slice(lower, upper)); |
|
560 """) |
|
561 |
|
562 def __getitem__(self, index): |
|
563 JS(""" |
|
564 if (index<0) index = this.l.length + index; |
|
565 return this.l[index]; |
|
566 """) |
|
567 |
|
568 def __setitem__(self, index, value): |
|
569 JS(""" this.l[index]=value;""") |
|
570 |
|
571 def __delitem__(self, index): |
|
572 JS(""" this.l.splice(index, 1);""") |
|
573 |
|
574 def __len__(self): |
|
575 JS(""" return this.l.length;""") |
|
576 |
|
577 def __contains__(self, value): |
|
578 return self.index(value) >= 0 |
|
579 |
|
580 def __iter__(self): |
|
581 JS(""" |
|
582 var i = 0; |
|
583 var l = this.l; |
|
584 return { |
|
585 'next': function() { |
|
586 if (i >= l.length) { |
|
587 throw pyjslib.StopIteration; |
|
588 } |
|
589 return l[i++]; |
|
590 }, |
|
591 '__iter__': function() { |
|
592 return this; |
|
593 } |
|
594 }; |
|
595 """) |
|
596 |
|
597 def reverse(self): |
|
598 JS(""" this.l.reverse();""") |
|
599 |
|
600 def sort(self, compareFunc=None, keyFunc=None, reverse=False): |
|
601 if not compareFunc: |
|
602 compareFunc = cmp |
|
603 if keyFunc and reverse: |
|
604 def thisSort1(a, b): |
|
605 return -compareFunc(keyFunc(a), keyFunc(b)) |
|
606 self.l.sort(thisSort1) |
|
607 elif keyFunc: |
|
608 def thisSort2(a, b): |
|
609 return compareFunc(keyFunc(a), keyFunc(b)) |
|
610 self.l.sort(thisSort2) |
|
611 elif reverse: |
|
612 def thisSort3(a, b): |
|
613 return -compareFunc(a, b) |
|
614 self.l.sort(thisSort3) |
|
615 else: |
|
616 self.l.sort(compareFunc) |
|
617 |
|
618 def getArray(self): |
|
619 """ |
|
620 Access the javascript Array that is used internally by this list |
|
621 """ |
|
622 return self.l |
|
623 |
|
624 def __str__(self): |
|
625 return repr(self) |
|
626 |
|
627 |
|
628 list = List |
|
629 |
|
630 |
|
631 class Tuple: |
|
632 def __init__(self, data=None): |
|
633 JS(""" |
|
634 this.l = []; |
|
635 this.extend(data); |
|
636 """) |
|
637 |
|
638 def append(self, item): |
|
639 JS(""" this.l[this.l.length] = item;""") |
|
640 |
|
641 def extend(self, data): |
|
642 JS(""" |
|
643 if (pyjslib.isArray(data)) { |
|
644 n = this.l.length; |
|
645 for (var i=0; i < data.length; i++) { |
|
646 this.l[n+i]=data[i]; |
|
647 } |
|
648 } |
|
649 else if (pyjslib.isIteratable(data)) { |
|
650 var iter=data.__iter__(); |
|
651 var i=this.l.length; |
|
652 try { |
|
653 while (true) { |
|
654 var item=iter.next(); |
|
655 this.l[i++]=item; |
|
656 } |
|
657 } |
|
658 catch (e) { |
|
659 if (e != pyjslib.StopIteration) throw e; |
|
660 } |
|
661 } |
|
662 """) |
|
663 |
|
664 def remove(self, value): |
|
665 JS(""" |
|
666 var index=this.index(value); |
|
667 if (index<0) return false; |
|
668 this.l.splice(index, 1); |
|
669 return true; |
|
670 """) |
|
671 |
|
672 def index(self, value, start=0): |
|
673 JS(""" |
|
674 var length=this.l.length; |
|
675 for (var i=start; i<length; i++) { |
|
676 if (this.l[i]==value) { |
|
677 return i; |
|
678 } |
|
679 } |
|
680 return -1; |
|
681 """) |
|
682 |
|
683 def insert(self, index, value): |
|
684 JS(""" var a = this.l; this.l=a.slice(0, index).concat(value, a.slice(index));""") |
|
685 |
|
686 def pop(self, index=-1): |
|
687 JS(""" |
|
688 if (index<0) index = this.l.length + index; |
|
689 var a = this.l[index]; |
|
690 this.l.splice(index, 1); |
|
691 return a; |
|
692 """) |
|
693 |
|
694 def __cmp__(self, l): |
|
695 if not isinstance(l, Tuple): |
|
696 return -1 |
|
697 ll = len(self) - len(l) |
|
698 if ll != 0: |
|
699 return ll |
|
700 for x in range(len(l)): |
|
701 ll = cmp(self.__getitem__(x), l[x]) |
|
702 if ll != 0: |
|
703 return ll |
|
704 return 0 |
|
705 |
|
706 def slice(self, lower, upper): |
|
707 JS(""" |
|
708 if (upper==null) return pyjslib.Tuple(this.l.slice(lower)); |
|
709 return pyjslib.Tuple(this.l.slice(lower, upper)); |
|
710 """) |
|
711 |
|
712 def __getitem__(self, index): |
|
713 JS(""" |
|
714 if (index<0) index = this.l.length + index; |
|
715 return this.l[index]; |
|
716 """) |
|
717 |
|
718 def __setitem__(self, index, value): |
|
719 JS(""" this.l[index]=value;""") |
|
720 |
|
721 def __delitem__(self, index): |
|
722 JS(""" this.l.splice(index, 1);""") |
|
723 |
|
724 def __len__(self): |
|
725 JS(""" return this.l.length;""") |
|
726 |
|
727 def __contains__(self, value): |
|
728 return self.index(value) >= 0 |
|
729 |
|
730 def __iter__(self): |
|
731 JS(""" |
|
732 var i = 0; |
|
733 var l = this.l; |
|
734 return { |
|
735 'next': function() { |
|
736 if (i >= l.length) { |
|
737 throw pyjslib.StopIteration; |
|
738 } |
|
739 return l[i++]; |
|
740 }, |
|
741 '__iter__': function() { |
|
742 return this; |
|
743 } |
|
744 }; |
|
745 """) |
|
746 |
|
747 def reverse(self): |
|
748 JS(""" this.l.reverse();""") |
|
749 |
|
750 def sort(self, compareFunc=None, keyFunc=None, reverse=False): |
|
751 if not compareFunc: |
|
752 compareFunc = cmp |
|
753 if keyFunc and reverse: |
|
754 def thisSort1(a, b): |
|
755 return -compareFunc(keyFunc(a), keyFunc(b)) |
|
756 self.l.sort(thisSort1) |
|
757 elif keyFunc: |
|
758 def thisSort2(a, b): |
|
759 return compareFunc(keyFunc(a), keyFunc(b)) |
|
760 self.l.sort(thisSort2) |
|
761 elif reverse: |
|
762 def thisSort3(a, b): |
|
763 return -compareFunc(a, b) |
|
764 self.l.sort(thisSort3) |
|
765 else: |
|
766 self.l.sort(compareFunc) |
|
767 |
|
768 def getArray(self): |
|
769 """ |
|
770 Access the javascript Array that is used internally by this list |
|
771 """ |
|
772 return self.l |
|
773 |
|
774 def __str__(self): |
|
775 return repr(self) |
|
776 |
|
777 |
|
778 tuple = Tuple |
|
779 |
|
780 |
|
781 class Dict: |
|
782 def __init__(self, data=None): |
|
783 JS(""" |
|
784 this.d = {}; |
|
785 |
|
786 if (pyjslib.isArray(data)) { |
|
787 for (var i in data) { |
|
788 var item=data[i]; |
|
789 this.__setitem__(item[0], item[1]); |
|
790 //var sKey=pyjslib.hash(item[0]); |
|
791 //this.d[sKey]=item[1]; |
|
792 } |
|
793 } |
|
794 else if (pyjslib.isIteratable(data)) { |
|
795 var iter=data.__iter__(); |
|
796 try { |
|
797 while (true) { |
|
798 var item=iter.next(); |
|
799 this.__setitem__(item.__getitem__(0), item.__getitem__(1)); |
|
800 } |
|
801 } |
|
802 catch (e) { |
|
803 if (e != pyjslib.StopIteration) throw e; |
|
804 } |
|
805 } |
|
806 else if (pyjslib.isObject(data)) { |
|
807 for (var key in data) { |
|
808 this.__setitem__(key, data[key]); |
|
809 } |
|
810 } |
|
811 """) |
|
812 |
|
813 def __setitem__(self, key, value): |
|
814 JS(""" |
|
815 var sKey = pyjslib.hash(key); |
|
816 this.d[sKey]=[key, value]; |
|
817 """) |
|
818 |
|
819 def __getitem__(self, key): |
|
820 JS(""" |
|
821 var sKey = pyjslib.hash(key); |
|
822 var value=this.d[sKey]; |
|
823 if (pyjslib.isUndefined(value)){ |
|
824 throw pyjslib.KeyError(key); |
|
825 } |
|
826 return value[1]; |
|
827 """) |
|
828 |
|
829 def __nonzero__(self): |
|
830 JS(""" |
|
831 for (var i in this.d){ |
|
832 return true; |
|
833 } |
|
834 return false; |
|
835 """) |
|
836 |
|
837 def __len__(self): |
|
838 JS(""" |
|
839 var size=0; |
|
840 for (var i in this.d) size++; |
|
841 return size; |
|
842 """) |
|
843 |
|
844 def has_key(self, key): |
|
845 return self.__contains__(key) |
|
846 |
|
847 def __delitem__(self, key): |
|
848 JS(""" |
|
849 var sKey = pyjslib.hash(key); |
|
850 delete this.d[sKey]; |
|
851 """) |
|
852 |
|
853 def __contains__(self, key): |
|
854 JS(""" |
|
855 var sKey = pyjslib.hash(key); |
|
856 return (pyjslib.isUndefined(this.d[sKey])) ? false : true; |
|
857 """) |
|
858 |
|
859 def keys(self): |
|
860 JS(""" |
|
861 var keys=new pyjslib.List(); |
|
862 for (var key in this.d) { |
|
863 keys.append(this.d[key][0]); |
|
864 } |
|
865 return keys; |
|
866 """) |
|
867 |
|
868 def values(self): |
|
869 JS(""" |
|
870 var values=new pyjslib.List(); |
|
871 for (var key in this.d) values.append(this.d[key][1]); |
|
872 return values; |
|
873 """) |
|
874 |
|
875 def items(self): |
|
876 JS(""" |
|
877 var items = new pyjslib.List(); |
|
878 for (var key in this.d) { |
|
879 var kv = this.d[key]; |
|
880 items.append(new pyjslib.List(kv)) |
|
881 } |
|
882 return items; |
|
883 """) |
|
884 |
|
885 def __iter__(self): |
|
886 return self.keys().__iter__() |
|
887 |
|
888 def iterkeys(self): |
|
889 return self.__iter__() |
|
890 |
|
891 def itervalues(self): |
|
892 return self.values().__iter__() |
|
893 |
|
894 def iteritems(self): |
|
895 return self.items().__iter__() |
|
896 |
|
897 def setdefault(self, key, default_value): |
|
898 if key not in self: |
|
899 self[key] = default_value |
|
900 |
|
901 def get(self, key, default_=None): |
|
902 if key not in self: |
|
903 return default_ |
|
904 return self[key] |
|
905 |
|
906 def update(self, d): |
|
907 for k, v in d.iteritems(): |
|
908 self[k] = v |
|
909 |
|
910 def getObject(self): |
|
911 """ |
|
912 Return the javascript Object which this class uses to store |
|
913 dictionary keys and values |
|
914 """ |
|
915 return self.d |
|
916 |
|
917 def copy(self): |
|
918 return Dict(self.items()) |
|
919 |
|
920 def __str__(self): |
|
921 return repr(self) |
|
922 |
|
923 |
|
924 dict = Dict |
|
925 |
|
926 # taken from mochikit: range( [start,] stop[, step] ) |
|
927 |
|
928 |
|
929 def range(): |
|
930 JS(""" |
|
931 var start = 0; |
|
932 var stop = 0; |
|
933 var step = 1; |
|
934 |
|
935 if (arguments.length == 2) { |
|
936 start = arguments[0]; |
|
937 stop = arguments[1]; |
|
938 } |
|
939 else if (arguments.length == 3) { |
|
940 start = arguments[0]; |
|
941 stop = arguments[1]; |
|
942 step = arguments[2]; |
|
943 } |
|
944 else if (arguments.length>0) stop = arguments[0]; |
|
945 |
|
946 return { |
|
947 'next': function() { |
|
948 if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) throw pyjslib.StopIteration; |
|
949 var rval = start; |
|
950 start += step; |
|
951 return rval; |
|
952 }, |
|
953 '__iter__': function() { |
|
954 return this; |
|
955 } |
|
956 } |
|
957 """) |
|
958 |
|
959 |
|
960 def slice(object, lower, upper): |
|
961 JS(""" |
|
962 if (pyjslib.isString(object)) { |
|
963 if (lower < 0) { |
|
964 lower = object.length + lower; |
|
965 } |
|
966 if (upper < 0) { |
|
967 upper = object.length + upper; |
|
968 } |
|
969 if (pyjslib.isNull(upper)) upper=object.length; |
|
970 return object.substring(lower, upper); |
|
971 } |
|
972 if (pyjslib.isObject(object) && object.slice) |
|
973 return object.slice(lower, upper); |
|
974 |
|
975 return null; |
|
976 """) |
|
977 |
|
978 |
|
979 def str(text): |
|
980 JS(""" |
|
981 if (pyjslib.hasattr(text,"__str__")) { |
|
982 return text.__str__(); |
|
983 } |
|
984 return String(text); |
|
985 """) |
|
986 |
|
987 |
|
988 def ord(x): |
|
989 if isString(x) and len(x) is 1: |
|
990 JS(""" |
|
991 return x.charCodeAt(0); |
|
992 """) |
|
993 else: |
|
994 JS(""" |
|
995 throw pyjslib.TypeError(); |
|
996 """) |
|
997 return None |
|
998 |
|
999 |
|
1000 def chr(x): |
|
1001 JS(""" |
|
1002 return String.fromCharCode(x) |
|
1003 """) |
|
1004 |
|
1005 |
|
1006 def is_basetype(x): |
|
1007 JS(""" |
|
1008 var t = typeof(x); |
|
1009 return t == 'boolean' || |
|
1010 t == 'function' || |
|
1011 t == 'number' || |
|
1012 t == 'string' || |
|
1013 t == 'undefined' |
|
1014 ; |
|
1015 """) |
|
1016 |
|
1017 |
|
1018 def get_pyjs_classtype(x): |
|
1019 JS(""" |
|
1020 if (pyjslib.hasattr(x, "__class__")) |
|
1021 if (pyjslib.hasattr(x.__class__, "__new__")) |
|
1022 var src = x.__class__.__name__; |
|
1023 return src; |
|
1024 return null; |
|
1025 """) |
|
1026 |
|
1027 |
|
1028 def repr(x): |
|
1029 """ Return the string representation of 'x'. |
|
1030 """ |
|
1031 JS(""" |
|
1032 if (x === null) |
|
1033 return "null"; |
|
1034 |
|
1035 if (x === undefined) |
|
1036 return "undefined"; |
|
1037 |
|
1038 var t = typeof(x); |
|
1039 |
|
1040 //alert("repr typeof " + t + " : " + x); |
|
1041 |
|
1042 if (t == "boolean") |
|
1043 return x.toString(); |
|
1044 |
|
1045 if (t == "function") |
|
1046 return "<function " + x.toString() + ">"; |
|
1047 |
|
1048 if (t == "number") |
|
1049 return x.toString(); |
|
1050 |
|
1051 if (t == "string") { |
|
1052 if (x.indexOf("'") == -1) |
|
1053 return "'" + x + "'"; |
|
1054 if (x.indexOf('"') == -1) |
|
1055 return '"' + x + '"'; |
|
1056 var s = x.replace(new RegExp('"', "g"), '\\\\"'); |
|
1057 return '"' + s + '"'; |
|
1058 }; |
|
1059 |
|
1060 if (t == "undefined") |
|
1061 return "undefined"; |
|
1062 |
|
1063 // If we get here, x is an object. See if it's a Pyjamas class. |
|
1064 |
|
1065 if (!pyjslib.hasattr(x, "__init__")) |
|
1066 return "<" + x.toString() + ">"; |
|
1067 |
|
1068 // Handle the common Pyjamas data types. |
|
1069 |
|
1070 var constructor = "UNKNOWN"; |
|
1071 |
|
1072 constructor = pyjslib.get_pyjs_classtype(x); |
|
1073 |
|
1074 //alert("repr constructor: " + constructor); |
|
1075 |
|
1076 if (constructor == "Tuple") { |
|
1077 var contents = x.getArray(); |
|
1078 var s = "("; |
|
1079 for (var i=0; i < contents.length; i++) { |
|
1080 s += pyjslib.repr(contents[i]); |
|
1081 if (i < contents.length - 1) |
|
1082 s += ", "; |
|
1083 }; |
|
1084 s += ")" |
|
1085 return s; |
|
1086 }; |
|
1087 |
|
1088 if (constructor == "List") { |
|
1089 var contents = x.getArray(); |
|
1090 var s = "["; |
|
1091 for (var i=0; i < contents.length; i++) { |
|
1092 s += pyjslib.repr(contents[i]); |
|
1093 if (i < contents.length - 1) |
|
1094 s += ", "; |
|
1095 }; |
|
1096 s += "]" |
|
1097 return s; |
|
1098 }; |
|
1099 |
|
1100 if (constructor == "Dict") { |
|
1101 var keys = new Array(); |
|
1102 for (var key in x.d) |
|
1103 keys.push(key); |
|
1104 |
|
1105 var s = "{"; |
|
1106 for (var i=0; i<keys.length; i++) { |
|
1107 var key = keys[i] |
|
1108 s += pyjslib.repr(key) + ": " + pyjslib.repr(x.d[key]); |
|
1109 if (i < keys.length-1) |
|
1110 s += ", " |
|
1111 }; |
|
1112 s += "}"; |
|
1113 return s; |
|
1114 }; |
|
1115 |
|
1116 // If we get here, the class isn't one we know -> return the class name. |
|
1117 // Note that we replace underscores with dots so that the name will |
|
1118 // (hopefully!) look like the original Python name. |
|
1119 |
|
1120 //var s = constructor.replace(new RegExp('_', "g"), '.'); |
|
1121 return "<" + constructor + " object>"; |
|
1122 """) |
|
1123 |
|
1124 |
|
1125 def float(text): |
|
1126 JS(""" |
|
1127 return parseFloat(text); |
|
1128 """) |
|
1129 |
|
1130 |
|
1131 def int(text, radix=0): |
|
1132 JS(""" |
|
1133 return parseInt(text, radix); |
|
1134 """) |
|
1135 |
|
1136 |
|
1137 def len(object): |
|
1138 JS(""" |
|
1139 if (object==null) return 0; |
|
1140 if (pyjslib.isObject(object) && object.__len__) return object.__len__(); |
|
1141 return object.length; |
|
1142 """) |
|
1143 |
|
1144 |
|
1145 def isinstance(object_, classinfo): |
|
1146 if pyjslib.isUndefined(object_): |
|
1147 return False |
|
1148 if not pyjslib.isObject(object_): |
|
1149 |
|
1150 return False |
|
1151 if _isinstance(classinfo, Tuple): |
|
1152 for ci in classinfo: |
|
1153 if isinstance(object_, ci): |
|
1154 return True |
|
1155 return False |
|
1156 else: |
|
1157 return _isinstance(object_, classinfo) |
|
1158 |
|
1159 |
|
1160 def _isinstance(object_, classinfo): |
|
1161 if not pyjslib.isObject(object_): |
|
1162 return False |
|
1163 JS(""" |
|
1164 if (object_.__class__){ |
|
1165 var res = object_ instanceof classinfo.constructor; |
|
1166 return res; |
|
1167 } |
|
1168 return false; |
|
1169 """) |
|
1170 |
|
1171 |
|
1172 def getattr(obj, name, default_=None): |
|
1173 JS(""" |
|
1174 if ((!pyjslib.isObject(obj))||(pyjslib.isUndefined(obj[name]))){ |
|
1175 if (pyjslib.isUndefined(default_)){ |
|
1176 throw pyjslib.AttributeError(obj, name); |
|
1177 }else{ |
|
1178 return default_; |
|
1179 } |
|
1180 } |
|
1181 if (!pyjslib.isFunction(obj[name])) return obj[name]; |
|
1182 var fnwrap = function() { |
|
1183 var args = []; |
|
1184 for (var i = 0; i < arguments.length; i++) { |
|
1185 args.push(arguments[i]); |
|
1186 } |
|
1187 return obj[name].apply(obj,args); |
|
1188 } |
|
1189 fnwrap.__name__ = name; |
|
1190 return fnwrap; |
|
1191 """) |
|
1192 |
|
1193 |
|
1194 def setattr(obj, name, value): |
|
1195 JS(""" |
|
1196 if (!pyjslib.isObject(obj)) return null; |
|
1197 |
|
1198 obj[name] = value; |
|
1199 |
|
1200 """) |
|
1201 |
|
1202 |
|
1203 def hasattr(obj, name): |
|
1204 JS(""" |
|
1205 if (!pyjslib.isObject(obj)) return false; |
|
1206 if (pyjslib.isUndefined(obj[name])) return false; |
|
1207 |
|
1208 return true; |
|
1209 """) |
|
1210 |
|
1211 |
|
1212 def dir(obj): |
|
1213 JS(""" |
|
1214 var properties=new pyjslib.List(); |
|
1215 for (property in obj) properties.append(property); |
|
1216 return properties; |
|
1217 """) |
|
1218 |
|
1219 |
|
1220 def filter(obj, method, sequence=None): |
|
1221 # object context is LOST when a method is passed, hence object must be passed separately |
|
1222 # to emulate python behaviour, should generate this code inline rather than as a function call |
|
1223 items = [] |
|
1224 if sequence is None: |
|
1225 sequence = method |
|
1226 method = obj |
|
1227 |
|
1228 for item in sequence: |
|
1229 if method(item): |
|
1230 items.append(item) |
|
1231 else: |
|
1232 for item in sequence: |
|
1233 if method.call(obj, item): |
|
1234 items.append(item) |
|
1235 |
|
1236 return items |
|
1237 |
|
1238 |
|
1239 def map(obj, method, sequence=None): |
|
1240 items = [] |
|
1241 |
|
1242 if sequence is None: |
|
1243 sequence = method |
|
1244 method = obj |
|
1245 |
|
1246 for item in sequence: |
|
1247 items.append(method(item)) |
|
1248 else: |
|
1249 for item in sequence: |
|
1250 items.append(method.call(obj, item)) |
|
1251 |
|
1252 return items |
|
1253 |
|
1254 |
|
1255 def enumerate(sequence): |
|
1256 enumeration = [] |
|
1257 nextIndex = 0 |
|
1258 for item in sequence: |
|
1259 enumeration.append([nextIndex, item]) |
|
1260 nextIndex = nextIndex + 1 |
|
1261 return enumeration |
|
1262 |
|
1263 |
|
1264 def min(*sequence): |
|
1265 minValue = None |
|
1266 for item in sequence: |
|
1267 if minValue is None: |
|
1268 minValue = item |
|
1269 elif item < minValue: |
|
1270 minValue = item |
|
1271 return minValue |
|
1272 |
|
1273 |
|
1274 def max(*sequence): |
|
1275 maxValue = None |
|
1276 for item in sequence: |
|
1277 if maxValue is None: |
|
1278 maxValue = item |
|
1279 elif item > maxValue: |
|
1280 maxValue = item |
|
1281 return maxValue |
|
1282 |
|
1283 |
|
1284 next_hash_id = 0 |
|
1285 |
|
1286 |
|
1287 def hash(obj): |
|
1288 JS(""" |
|
1289 if (obj == null) return null; |
|
1290 |
|
1291 if (obj.$H) return obj.$H; |
|
1292 if (obj.__hash__) return obj.__hash__(); |
|
1293 if (obj.constructor == String || obj.constructor == Number || obj.constructor == Date) return obj; |
|
1294 |
|
1295 obj.$H = ++pyjslib.next_hash_id; |
|
1296 return obj.$H; |
|
1297 """) |
|
1298 |
|
1299 |
|
1300 # type functions from Douglas Crockford's Remedial Javascript: http://www.crockford.com/javascript/remedial.html |
|
1301 def isObject(a): |
|
1302 JS(""" |
|
1303 return (a != null && (typeof a == 'object')) || pyjslib.isFunction(a); |
|
1304 """) |
|
1305 |
|
1306 |
|
1307 def isFunction(a): |
|
1308 JS(""" |
|
1309 return typeof a == 'function'; |
|
1310 """) |
|
1311 |
|
1312 |
|
1313 def isString(a): |
|
1314 JS(""" |
|
1315 return typeof a == 'string'; |
|
1316 """) |
|
1317 |
|
1318 |
|
1319 def isNull(a): |
|
1320 JS(""" |
|
1321 return typeof a == 'object' && !a; |
|
1322 """) |
|
1323 |
|
1324 |
|
1325 def isArray(a): |
|
1326 JS(""" |
|
1327 return pyjslib.isObject(a) && a.constructor == Array; |
|
1328 """) |
|
1329 |
|
1330 |
|
1331 def isUndefined(a): |
|
1332 JS(""" |
|
1333 return typeof a == 'undefined'; |
|
1334 """) |
|
1335 |
|
1336 |
|
1337 def isIteratable(a): |
|
1338 JS(""" |
|
1339 return pyjslib.isString(a) || (pyjslib.isObject(a) && a.__iter__); |
|
1340 """) |
|
1341 |
|
1342 |
|
1343 def isNumber(a): |
|
1344 JS(""" |
|
1345 return typeof a == 'number' && isFinite(a); |
|
1346 """) |
|
1347 |
|
1348 |
|
1349 def toJSObjects(x): |
|
1350 """ |
|
1351 Convert the pyjs pythonic List and Dict objects into javascript Object and Array |
|
1352 objects, recursively. |
|
1353 """ |
|
1354 if isArray(x): |
|
1355 JS(""" |
|
1356 var result = []; |
|
1357 for(var k=0; k < x.length; k++) { |
|
1358 var v = x[k]; |
|
1359 var tv = pyjslib.toJSObjects(v); |
|
1360 result.push(tv); |
|
1361 } |
|
1362 return result; |
|
1363 """) |
|
1364 if isObject(x): |
|
1365 if isinstance(x, Dict): |
|
1366 JS(""" |
|
1367 var o = x.getObject(); |
|
1368 var result = {}; |
|
1369 for (var i in o) { |
|
1370 result[o[i][0].toString()] = o[i][1]; |
|
1371 } |
|
1372 return pyjslib.toJSObjects(result) |
|
1373 """) |
|
1374 elif isinstance(x, List): |
|
1375 return toJSObjects(x.l) |
|
1376 elif hasattr(x, '__class__'): |
|
1377 # we do not have a special implementation for custom |
|
1378 # classes, just pass it on |
|
1379 return x |
|
1380 if isObject(x): |
|
1381 JS(""" |
|
1382 var result = {}; |
|
1383 for(var k in x) { |
|
1384 var v = x[k]; |
|
1385 var tv = pyjslib.toJSObjects(v) |
|
1386 result[k] = tv; |
|
1387 } |
|
1388 return result; |
|
1389 """) |
|
1390 return x |
|
1391 |
|
1392 |
|
1393 def printFunc(objs): |
|
1394 JS(""" |
|
1395 if ($wnd.console==undefined) return; |
|
1396 var s = ""; |
|
1397 for(var i=0; i < objs.length; i++) { |
|
1398 if(s != "") s += " "; |
|
1399 s += objs[i]; |
|
1400 } |
|
1401 console.debug(s) |
|
1402 """) |
|
1403 |
|
1404 |
|
1405 def type(clsname, bases=None, methods=None): |
|
1406 """ creates a class, derived from bases, with methods and variables |
|
1407 """ |
|
1408 |
|
1409 JS(" var mths = {}; ") |
|
1410 if methods: |
|
1411 for k in methods.keys(): |
|
1412 _mth = methods[k] |
|
1413 JS(" mths[k] = _mth; ") |
|
1414 |
|
1415 JS(" var bss = null; ") |
|
1416 if bases: |
|
1417 JS("bss = bases.l;") |
|
1418 JS(" return pyjs_type(clsname, bss, mths); ") |
|