svgui/pyjs/lib/pyjslib.py
changeset 3359 2c924cf26161
parent 3358 7478d0c0dc1c
child 3360 746e3e3f6537
equal deleted inserted replaced
3358:7478d0c0dc1c 3359:2c924cf26161
     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); ")