1. Olemis Lang
  2. brython

Commits

pier...@gmail.com@570a7cb1-34e0-a994-6e4f-44535eead511  committed d849fbd

Many updtaes inclunding first version of Ajax

  • Participants
  • Parent commits 5140aa2
  • Branches default

Comments (0)

Files changed (13)

File ajax.html

View file
+<html>
+<head>
+<style>
+body,td,th{font-family:sans-serif}
+a.sort_link{margin-left:10px;text-decoration:none}
+</style>
+
+<script src="py_tokenizer.js"></script>
+<script src="py_utils.js"></script>
+<script src="py_classes.js"></script>
+<script src="py_dom.js"></script>
+<script src="py_ajax.js"></script>
+<script src="py2js.js"></script>
+
+</head>
+<body onLoad="brython()">
+
+<input id="name">
+<button onClick="go()">ajax !</button>
+<div id="result">(empty)</div>
+
+<script id="ascript" type="text/brython">
+def on_complete(status,text):
+    status = int(status)
+    if status==0:
+        doc["result"].set_html("server doesn't reply")
+    elif status==200:
+        doc["result"].set_html(text)
+
+def err_msg():
+    doc["result"].set_html("server didn't reply after %s seconds" %timeout)
+
+timeout = 4
+
+def go():
+    req = ajax()
+    req.on_complete = on_complete
+    req.set_timeout(timeout,err_msg)
+    req.open('GET','cgi-bin/test.py',True)
+    req.send()
+
+</script>
+</body>
+</html>

File ajax_data.txt

View file
+essai

File cgi-bin/test.py

View file
+#!c:/python33/python.exe
+import cgi
+import time
+
+print("Content-type: text/html")
+print()
+
+time.sleep(10)
+print('script cgi')

File console.html

View file
 <html>
 <head>
+<script src="py_tokenizer.js"></script>
 <script src="py_utils.js"></script>
 <script src="py_classes.js"></script>
-<script src="py_tokenizer.js"></script>
-<script src="stack.js"></script>
+<script src="py_dom.js"></script>
 <script src="py2js.js"></script>
 <script>
 var js=null
 </script>
 </head>
 <body>
+<div id="test">Brython</div>
+
 <table>
 <tr>
 <td><textarea id="src" cols=60 rows=20></textarea></td>

File py2js.js

View file
     Document = $Document()
     eval(js)
 }
+
+function brython(debug){
+    var elts = document.getElementsByTagName("script")
+    for($i=0;$i<elts.length;$i++){
+        elt = elts[$i]
+        if(elt.type=="text/brython"){
+            var src = (elt.innerHTML || elt.textContent)
+            js = py2js(src)
+            if(debug){document.write('<textarea cols=120 rows=30>'+js+'</textarea>')}
+            $run(js)
+        }
+    }
+}

File py_ajax.js

View file
+// ajax
+function $AjaxClass(){
+
+    if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
+        var $xmlhttp=new XMLHttpRequest();
+    }else{// code for IE6, IE5
+        var $xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
+    }
+    $xmlhttp.$ajax = this
+    $xmlhttp.$requestTimer = null
+    
+    $xmlhttp.onreadystatechange = function(){
+        // here, "this" refers to $xmlhttp, *not* to the $AjaxClass instance !!!
+        var state = this.readyState
+        var req = this.$ajax
+        var timer = this.$requestTimer
+        if(state===0 && 'on_uninitialized' in req){
+            req.on_uninitialized(str($xmlhttp.status),str($xmlhttp.responseText))
+        }else if(state===1 && 'on_loading' in req){
+            req.on_loading(str($xmlhttp.status),str($xmlhttp.responseText))
+        }else if(state===2 && 'on_loaded' in req){
+            req.on_loaded(str($xmlhttp.status),str($xmlhttp.responseText))
+        }else if(state===3 && 'on_interactive' in req){
+            req.on_interactive(str($xmlhttp.status),str($xmlhttp.responseText))
+        }else if(state===4 && 'on_complete' in req){
+            if(timer !== null){window.clearTimeout(timer)}
+            req.on_complete(str($xmlhttp.status),str($xmlhttp.responseText))
+        }
+    }
+
+    this.open = function(method,url,async){
+        $xmlhttp.open(method.value,url.value,$bool(async));
+    }
+
+    this.set_header = function(key,value){
+        $xmlhttp.setRequestHeader(key.value,value.value)
+    }
+    
+    this.send = function(params){
+        // params is a Python dictionary
+        if(!params || params.$keys.length==0){$xmlhttp.send();return}
+        if(!$isinstance(params,dict)){$Exception("TypeError",
+            "send() argument must be dictonary, not '"+$str(params.__class__)+"'")}
+        var res = ''
+        for(i=0;i<params.$keys.length;i++){
+            res += $str(params.$keys[i])+'='+$str(params.$values[i])+'&'
+        }
+        res = res.substtr(0,res.length-1)
+        $xmlhttp.send(res)
+    }
+
+    // if no reply after requestTimeOut seconds, abort request
+    // found at http://ajaxpatterns.org/XMLHttpRequest_Call#Detecting_Errors
+    this.set_timeout = function(seconds,func){
+        $xmlhttp.$requestTimer = setTimeout(
+            function() {$xmlhttp.abort();func()}, 
+            seconds.value*1000); 
+    }
+}
+
+function ajax(){
+    return new $AjaxClass()
+}
+
+function unfold(periode,code_prog){
+
+    xmlhttp.onreadystatechange=function(){
+        $("progress").innerHTML = "sending, state "+xmlhttp.readyState
+        if(xmlhttp.readyState==4){
+            clearTimeout(requestTimer);
+            if(xmlhttp.status==200){
+                resp=xmlhttp.responseText;
+                document.getElementById("progress").innerHTML = 'ok'
+                elt = $('div'+code_prog)
+                elt.innerHTML = resp
+                toggler.innerHTML='-'
+            } else {
+                msg = '<b style="color:red;">Your changes could not been saved</b>'
+                msg += ' - Error status '+xmlhttp.status
+                document.getElementById("progress").innerHTML = msg
+                trace(xmlhttp.responseText)
+            }
+        } else {
+            document.getElementById("progress").style.visibility = "visible"
+        }
+    }
+    params = "periode="+periode
+    params += "&code_prog="+code_prog
+
+    // if no reply after requestTimeOut seconds, abort request
+    // found at http://ajaxpatterns.org/XMLHttpRequest_Call#Detecting_Errors
+    requestTimeout = 7
+    requestTimer = setTimeout(function() {
+           xmlhttp.abort();
+           msg = 'Server did not within '+requestTimeout+' seconds - abort request'
+           document.getElementById("progress").innerHTML = msg
+         }, requestTimeout*1000); 
+    
+    try{
+        xmlhttp.open("POST","liste_projets",false);
+        xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
+        xmlhttp.send(params);
+    } catch(err) {
+        document.getElementById("progress").innerHTML = "error "+err.description
+        document.getElementById("progress").style.visibility = "visible" 
+    }
+}

File py_classes.js

View file
 }
 
 function getattr(obj,attr,_default){
-    if(attr in obj){return obj[attr]}
+    if(!$isinstance(attr,str)){$Exception("TypeError",
+        "getattr(): attribute name must be string")}
+    if(attr.value in obj){return obj[attr.value]}
     else if(_default !==undefined){return _default}
     else{$Exception('AttributeError',
         "'"+$str(obj.__class__)+"' object has no attribute '"+attr.value+"'")}
 
     this.append = function(item){items.push(item)}
 
+    this.index = function(elt){
+        for(i=0;i<items.length;i++){
+            if($bool(items[i].__eq__(elt))){return int(i)}
+        }
+        $Exception("ValueError",$str(elt)+" is not in list")
+    }
+
     this.reverse = function(){
         for(i=0;i<parseInt(items.length/2);i++){
             buf = items[i]
     if($bool(obj)){return False}else{return True}
 }
 
-// round
+function $ReversedClass(seq){
+    this.iter = null
+    this.__next__ = function(){
+        if(this.iter===null){this.iter=len(seq)}
+        if(this.iter.value===0){throw new $StopIteration()}
+        this.iter.value--
+        return seq.__getitem__(this.iter)
+    }
+}
+function reversed(seq){
+    // returns an iterator with elements in the reverse order from seq
+    // only implemented for strings and lists
+    if(!$isinstance(seq,list(str,list))){$Exception("TypeError",
+        "argument to reversed() must be a sequence")}
+    return new $ReversedClass(seq)
+}
+
 function round(arg,n){
     if(!$isinstance(arg,(int,float))){
         $Exception('TypeError',
         return False
     }
 
+    this.index = function(elt){
+        if(!$isinstance(elt,str)){$Exception("Typeerror",
+            "Can't convert '"+$str(elt.__class__)+"' object to str implicitly")}
+        for(i=0;i<value.length-elt.value.length+1;i++){
+            if(value.substr(i,elt.value.length)===elt.value){return int(i)}
+        }
+        $Exception("ValueError","substring not found")
+    }
+
     this.strip = function(x){
         if(x==undefined){
             x = "\\s"
 function object(){
     return new Object()
 }
-
-// DOM classes
-
-function $Document(){}
-
-function $DomElement(elt){
-    var i = null
-    var elt_name = elt.tagName
-    if(elt_name===undefined && elt.nodeName=="#text"){ // text node
-        return str(elt.data)
-    }
-    var obj = new $TagClass()
-    if(elt_name===undefined && elt.nodeName=="#document"){ // document
-        obj.__class__ = $Document
-    }else{
-        obj.__class__ = eval(elt_name)
-    }
-    obj.elt = elt
-    return obj
-}
-
-// classes to interact with DOM
-function $AbstractTagClass(){
-    // for abstract tags
-    this.__class__ = $AbstractTag
-    this.children = []
-    this.appendChild = function(child){    
-        this.children.push(child)
-    }
-
-    this.__add__ = function(other){
-        if($isinstance(other,$AbstractTag)){
-            this.children = this.children.concat(other.children)
-        } else {this.children.push(other.elt)}
-        return this
-    }        
-
-   this.__iadd__ = function(other){
-        if($isinstance(other,$AbstractTag)){
-            this.children = this.children.concat(other.children)
-        } else {this.children.push(other.elt)}
-    }        
-
-    this.clone = function(){
-        var res = $AbstractTag(), $i=0
-        for($i=0;$i<this.children.length;$i++){
-            res.children.push(this.children[$i].cloneNode(true))
-        }
-        return res
-    }
-}
-
-function $AbstractTag(){
-    return new $AbstractTagClass()
-}
-
-$events = $List2Dict('onabort','onactivate','onafterprint','onafterupdate',
-'onbeforeactivate','onbeforecopy','onbeforecut','onbeforedeactivate',
-'onbeforeeditfocus','onbeforepaste','onbeforeprint','onbeforeunload',
-'onbeforeupdate','onblur','onbounce','oncellchange','onchange','onclick',
-'oncontextmenu','oncontrolselect','oncopy','oncut','ondataavailable',
-'ondatasetchanged','ondatasetcomplete','ondblclick','ondeactivate','ondrag',
-'ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop',
-'onerror','onerrorupdate','onfilterchange','onfinish','onfocus','onfocusin',
-'onfocusout','onhashchange','onhelp','oninput','onkeydown','onkeypress',
-'onkeyup','onload','onlosecapture','onmessage','onmousedown','onmouseenter',
-'onmouseleave','onmousemove','onmouseout','onmouseover','onmouseup',
-'onmousewheel','onmove','onmoveend','onmovestart','onoffline','ononline',
-'onpaste','onpropertychange','onreadystatechange','onreset','onresize',
-'onresizeend','onresizestart','onrowenter','onrowexit','onrowsdelete',
-'onrowsinserted','onscroll','onsearch','onselect','onselectionchange',
-'onselectstart','onstart','onstop','onsubmit','onunload')
-
-function $TagClass(_class,args){
-    // represents an HTML tag
-    var $i = null
-    if(_class!=undefined){
-        this.name = str(_class).value
-        eval("this.__class__ ="+_class)
-        this.elt = document.createElement(this.name)
-    }
-    if(args!=undefined && args.length>0){
-        $start = 0
-        $first = args[0]
-        // if first argument is not a keyword, it's the tag content
-        if(!$isinstance($first,$Kw)){
-            $start = 1
-            if($isinstance($first,str)){
-                txt = document.createTextNode($first.value)
-                this.elt.appendChild(txt)
-            } else if($isinstance($first,int) || $isinstance($first,float)){
-                txt = document.createTextNode($first.value.toString())
-                this.elt.appendChild(txt)
-            } else if($isinstance($first,$AbstractTag)){
-                for($i=0;$i<$first.children.length;$i++){
-                    this.elt.appendChild($first.children[$i])
-                }
-            } else {
-                try{this.elt.appendChild($first.elt)}
-                catch(err){$Exception('ValueError','wrong element '+$first.elt)}
-            }
-        }
-        // attributes
-        for($i=$start;$i<args.length;$i++){
-            // keyword arguments
-            $arg = args[$i]
-            if($isinstance($arg,$Kw)){
-                if($arg.name.toLowerCase() in $events){
-                    eval('this.elt.'+$arg.name.toLowerCase()+'=function(){'+$arg.value.value+'}')
-                } else {
-                    this.elt.setAttribute($arg.name,$arg.value.value)
-                }
-            }
-        }
-    }
-    // if not id was provided, generate one
-    if('elt' in this){
-        if(!this.elt.getAttribute('id')){ // '' for IE, null for Chrome and Firefox
-            this.elt.setAttribute('id',Math.random().toString(36).substr(2, 8))
-        }
-    }
-
-    this.__le__ = function(other){
-        if($isinstance(other,$AbstractTag)){
-            var $i=0
-            for($i=0;$i<other.children.length;$i++){
-                this.elt.appendChild(other.children[$i])
-            }
-        } else {this.elt.appendChild(other.elt)}
-    }
-    
-    this.__add__ = function(other){
-        var res = $AbstractTag() // abstract tag
-        res.children = [this.elt]
-        if($isinstance(other,$AbstractTag)){
-            var $i=0
-            for($i=0;$i<other.children.length;$i++){
-                res.children.push(other.children[$i])
-            }
-        } else {res.children.push(other.elt)}
-        return res
-    }
-
-    this.__radd__ = function(other){ // add to a string
-        var res = $AbstractTag() // abstract tag
-        var txt = document.createTextNode(other.value)
-        res.children = [txt,this.elt]
-        return res        
-    }
-
-    this.__iadd__ = function(other){
-        this.__class__ = $AbstractTag // change to abstract tag
-        this.children = [this.elt]
-        if($isinstance(other,$AbstractTag)){
-            for($i=0;$i<other.children.length;$i++){
-                this.children.push(other.children[$i])
-            }
-        } else {this.children.push(other.elt)}
-    }
-
-    this.__eq__ = function(other){
-        if(!('getAttribute' in other.elt)){return False}
-        return $bool_conv(this.elt.getAttribute('id')==other.elt.getAttribute('id'))
-    }
-
-    this.__ne__ = function(other){return not(this.__eq__(other))}
-
-    this.__getitem__ = function(key){
-        return $JS2Py(this.elt[$str(key)])
-    }
-    
-    this.__setitem__ = function(key,value){
-        this.elt.setAttribute($str(key),$str(value))
-    }
-    
-    this.clone = function(){
-        res = new TagClass(this.name)
-        res.elt = this.elt.cloneNode(true)
-        return res
-    }
-
-    this.parent = function(){
-        if(this.elt.parentElement){return $DomElement(this.elt.parentElement)}
-        else{return None}
-    }
-
-    this.children = function(){
-        var res = list()
-        for(i=0;i<this.elt.childNodes.length;i++){
-            res.append($DomElement(this.elt.childNodes[i]))
-        }
-        return res
-    }
-
-    this.text = function(){
-        return str(this.elt.innerText || this.elt.textContent)
-    }
-    
-    this.html = function(){return str(this.elt.innerHTML)}
-    this.set_html = function(value){this.elt.innerHTML=$str(value)}
-
-    this.show = function(){
-        document.body.appendChild(this.elt)
-    }
-}
-
-function A(){
-    var $args = [],$i=0
-    for($i=0;$i<arguments.length;$i++){$args.push(arguments[$i])}
-    return new $TagClass(A,$args)
-}
-
-var $src = A+'' // source of function A
-$tags = ['A', 'ABBR', 'ACRONYM', 'ADDRESS', 'APPLET',
-            'B', 'BDO', 'BIG', 'BLOCKQUOTE', 'BUTTON',
-            'CAPTION', 'CENTER', 'CITE', 'CODE',
-            'DEL', 'DFN', 'DIR', 'DIV', 'DL',
-            'EM', 'FIELDSET', 'FONT', 'FORM', 'FRAMESET',
-            'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
-            'I', 'IFRAME', 'INS', 'KBD', 'LABEL', 'LEGEND',
-            'MAP', 'MENU', 'NOFRAMES', 'NOSCRIPT', 'OBJECT',
-            'OL', 'OPTGROUP', 'PRE', 'Q', 'S', 'SAMP',
-            'SCRIPT', 'SMALL', 'SPAN', 'STRIKE',
-            'STRONG', 'STYLE', 'SUB', 'SUP', 'TABLE',
-            'TEXTAREA', 'TITLE', 'TT', 'U', 'UL',
-            'VAR', 'BODY', 'COLGROUP', 'DD', 'DT', 'HEAD',
-            'HTML', 'LI', 'P', 'TBODY','OPTION', 
-            'TD', 'TFOOT', 'TH', 'THEAD', 'TR',
-            'AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME',
-            'HR', 'IMG', 'INPUT', 'ISINDEX', 'LINK',
-            'META', 'PARAM']
-
-$tags = $tags.concat(['CIRCLE','ELLIPSE','SVG','TEXT','RECT'])
-            
-for($i=0;$i<$tags.length;$i++){
-    $code = $src.replace(/A/gm,$tags[$i])
-    eval($code)
-}

File py_dom.js

View file
+// DOM classes
+
+function $Document(){
+
+    this.__le__ = function(other){
+        if($isinstance(other,$AbstractTag)){
+            var $i=0
+            for($i=0;$i<other.children.length;$i++){
+                document.body.appendChild(other.children[$i])
+            }
+        } else {document.body.appendChild(other.elt)}
+    }
+    
+    this.insert_before = function(other,ref_elt){
+        document.insertBefore(other.elt,ref_elt.elt)
+    }
+
+    this.__getitem__ = function(id){
+        return $DomElement(document.getElementById(id.value))
+    }
+
+}
+
+doc = new $Document()
+
+function $DomElement(elt){
+    var i = null
+    var elt_name = elt.tagName
+    if(elt_name===undefined && elt.nodeName=="#text"){ // text node
+        return str(elt.data)
+    }
+    var obj = new $TagClass()
+    if(elt_name===undefined && elt.nodeName=="#document"){ // document
+        obj.__class__ = $Document
+    }else{
+        obj.__class__ = eval(elt_name)
+    }
+    obj.elt = elt
+    return obj
+}
+
+// classes to interact with DOM
+function $AbstractTagClass(){
+    // for abstract tags
+    this.__class__ = $AbstractTag
+    this.children = []
+    this.appendChild = function(child){    
+        this.children.push(child)
+    }
+
+    this.__add__ = function(other){
+        if($isinstance(other,$AbstractTag)){
+            this.children = this.children.concat(other.children)
+        } else {this.children.push(other.elt)}
+        return this
+    }        
+
+   this.__iadd__ = function(other){
+        if($isinstance(other,$AbstractTag)){
+            this.children = this.children.concat(other.children)
+        } else {this.children.push(other.elt)}
+    }        
+
+    this.clone = function(){
+        var res = $AbstractTag(), $i=0
+        for($i=0;$i<this.children.length;$i++){
+            res.children.push(this.children[$i].cloneNode(true))
+        }
+        return res
+    }
+}
+
+function $AbstractTag(){
+    return new $AbstractTagClass()
+}
+
+$events = $List2Dict('onabort','onactivate','onafterprint','onafterupdate',
+'onbeforeactivate','onbeforecopy','onbeforecut','onbeforedeactivate',
+'onbeforeeditfocus','onbeforepaste','onbeforeprint','onbeforeunload',
+'onbeforeupdate','onblur','onbounce','oncellchange','onchange','onclick',
+'oncontextmenu','oncontrolselect','oncopy','oncut','ondataavailable',
+'ondatasetchanged','ondatasetcomplete','ondblclick','ondeactivate','ondrag',
+'ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop',
+'onerror','onerrorupdate','onfilterchange','onfinish','onfocus','onfocusin',
+'onfocusout','onhashchange','onhelp','oninput','onkeydown','onkeypress',
+'onkeyup','onload','onlosecapture','onmessage','onmousedown','onmouseenter',
+'onmouseleave','onmousemove','onmouseout','onmouseover','onmouseup',
+'onmousewheel','onmove','onmoveend','onmovestart','onoffline','ononline',
+'onpaste','onpropertychange','onreadystatechange','onreset','onresize',
+'onresizeend','onresizestart','onrowenter','onrowexit','onrowsdelete',
+'onrowsinserted','onscroll','onsearch','onselect','onselectionchange',
+'onselectstart','onstart','onstop','onsubmit','onunload')
+
+function $TagClass(_class,args){
+    // represents an HTML tag
+    var $i = null
+    if(_class!=undefined){
+        this.name = str(_class).value
+        eval("this.__class__ ="+_class)
+        this.elt = document.createElement(this.name)
+    }
+    if(args!=undefined && args.length>0){
+        $start = 0
+        $first = args[0]
+        // if first argument is not a keyword, it's the tag content
+        if(!$isinstance($first,$Kw)){
+            $start = 1
+            if($isinstance($first,str)){
+                txt = document.createTextNode($first.value)
+                this.elt.appendChild(txt)
+            } else if($isinstance($first,int) || $isinstance($first,float)){
+                txt = document.createTextNode($first.value.toString())
+                this.elt.appendChild(txt)
+            } else if($isinstance($first,$AbstractTag)){
+                for($i=0;$i<$first.children.length;$i++){
+                    this.elt.appendChild($first.children[$i])
+                }
+            } else {
+                try{this.elt.appendChild($first.elt)}
+                catch(err){$Exception('ValueError','wrong element '+$first.elt)}
+            }
+        }
+        // attributes
+        for($i=$start;$i<args.length;$i++){
+            // keyword arguments
+            $arg = args[$i]
+            if($isinstance($arg,$Kw)){
+                if($arg.name.toLowerCase() in $events){
+                    eval('this.elt.'+$arg.name.toLowerCase()+'=function(){'+$arg.value.value+'}')
+                } else {
+                    this.elt.setAttribute($arg.name,$arg.value.value)
+                }
+            }
+        }
+    }
+    // if not id was provided, generate one
+    if('elt' in this){
+        if(!this.elt.getAttribute('id')){ // '' for IE, null for Chrome and Firefox
+            this.elt.setAttribute('id',Math.random().toString(36).substr(2, 8))
+        }
+    }
+
+    this.__le__ = function(other){
+        if($isinstance(other,$AbstractTag)){
+            var $i=0
+            for($i=0;$i<other.children.length;$i++){
+                this.elt.appendChild(other.children[$i])
+            }
+        } else {this.elt.appendChild(other.elt)}
+    }
+    
+    this.__add__ = function(other){
+        var res = $AbstractTag() // abstract tag
+        res.children = [this.elt]
+        if($isinstance(other,$AbstractTag)){
+            var $i=0
+            for($i=0;$i<other.children.length;$i++){
+                res.children.push(other.children[$i])
+            }
+        } else {res.children.push(other.elt)}
+        return res
+    }
+
+    this.__radd__ = function(other){ // add to a string
+        var res = $AbstractTag() // abstract tag
+        var txt = document.createTextNode(other.value)
+        res.children = [txt,this.elt]
+        return res        
+    }
+
+    this.__iadd__ = function(other){
+        this.__class__ = $AbstractTag // change to abstract tag
+        this.children = [this.elt]
+        if($isinstance(other,$AbstractTag)){
+            for($i=0;$i<other.children.length;$i++){
+                this.children.push(other.children[$i])
+            }
+        } else {this.children.push(other.elt)}
+    }
+
+    this.__eq__ = function(other){
+        if(!('getAttribute' in other.elt)){return False}
+        return $bool_conv(this.elt.getAttribute('id')==other.elt.getAttribute('id'))
+    }
+
+    this.__ne__ = function(other){return not(this.__eq__(other))}
+
+    this.__getitem__ = function(key){
+        return $JS2Py(this.elt[$str(key)])
+    }
+    
+    this.__setitem__ = function(key,value){
+        this.elt.setAttribute($str(key),$str(value))
+    }
+    
+    this.clone = function(){
+        res = new TagClass(this.name)
+        res.elt = this.elt.cloneNode(true)
+        return res
+    }
+
+    this.parent = function(){
+        if(this.elt.parentElement){return $DomElement(this.elt.parentElement)}
+        else{return None}
+    }
+
+    this.children = function(){
+        var res = list()
+        for(i=0;i<this.elt.childNodes.length;i++){
+            res.append($DomElement(this.elt.childNodes[i]))
+        }
+        return res
+    }
+
+    this.text = function(){
+        return str(this.elt.innerText || this.elt.textContent)
+    }
+    
+    this.html = function(){return str(this.elt.innerHTML)}
+    this.set_html = function(value){this.elt.innerHTML=$str(value)}
+
+    this.show = function(){document.body.appendChild(this.elt)}
+    
+    this.value = function(){
+        if(value in this.elt){return str(this.elt.value)}
+        else{$Exception("AttributeError",
+            "'"+$str(this.name)+"' object has no attribute 'value'")}
+    }
+}
+
+function A(){
+    var $args = [],$i=0
+    for($i=0;$i<arguments.length;$i++){$args.push(arguments[$i])}
+    return new $TagClass(A,$args)
+}
+
+var $src = A+'' // source of function A
+$tags = ['A', 'ABBR', 'ACRONYM', 'ADDRESS', 'APPLET',
+            'B', 'BDO', 'BIG', 'BLOCKQUOTE', 'BUTTON',
+            'CAPTION', 'CENTER', 'CITE', 'CODE',
+            'DEL', 'DFN', 'DIR', 'DIV', 'DL',
+            'EM', 'FIELDSET', 'FONT', 'FORM', 'FRAMESET',
+            'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
+            'I', 'IFRAME', 'INS', 'KBD', 'LABEL', 'LEGEND',
+            'MAP', 'MENU', 'NOFRAMES', 'NOSCRIPT', 'OBJECT',
+            'OL', 'OPTGROUP', 'PRE', 'Q', 'S', 'SAMP',
+            'SCRIPT', 'SMALL', 'SPAN', 'STRIKE',
+            'STRONG', 'STYLE', 'SUB', 'SUP', 'TABLE',
+            'TEXTAREA', 'TITLE', 'TT', 'U', 'UL',
+            'VAR', 'BODY', 'COLGROUP', 'DD', 'DT', 'HEAD',
+            'HTML', 'LI', 'P', 'TBODY','OPTION', 
+            'TD', 'TFOOT', 'TH', 'THEAD', 'TR',
+            'AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME',
+            'HR', 'IMG', 'INPUT', 'ISINDEX', 'LINK',
+            'META', 'PARAM']
+
+$tags = $tags.concat(['CIRCLE','ELLIPSE','SVG','TEXT','RECT'])
+            
+for($i=0;$i<$tags.length;$i++){
+    $code = $src.replace(/A/gm,$tags[$i])
+    eval($code)
+}

File py_tokenizer.js

View file
                 } else if(name in $operators) { // and, or
                     stack.push(["operator",name,pos-name.length])
                 } else if(stack.length>1 && $last(stack)[0]=="point"
-                    && (stack[stack.length-2][0] in $List2Dict('id','qualifier'))) {
+                    && (stack[stack.length-2][0] in $List2Dict('id','qualifier','bracket'))) {
                     stack.push(["qualifier",name,pos-name.length])
                 } else {
                     stack.push(["id",name,pos-name.length])

File py_utils.js

View file
     if(typeof item=="string"){return item.charAt(item.length-1)}
     else if(typeof item=="object"){return item[item.length-1]}
 }
+
+// classes to manipulate the tokens generated by py_tokenizer
+
+function Atom(stack){
+    this.parent = stack
+    this.type = null
+    this.stack = function(){
+        return new Stack(this.parent.list.slice(this.start,this.end+1))
+    }
+    this.list = function(){
+        return this.parent.list.slice(this.start,this.end+1)
+    }
+    this.to_js = function(){return this.stack().to_js()}
+}
+
+function Stack(stack_list){
+    this.list = stack_list
+    
+    this.find_next = function(){
+        // arguments are position to search from, researched type and
+        // optional researched values
+        // return position of next matching stack item or null
+        var pos = arguments[0]
+        var _type = arguments[1]
+        var values = null
+        if(arguments.length>2){
+            values = {}
+            for(i=2;i<arguments.length;i++){values[arguments[i]]=0}
+        }
+        for(i=pos;i<this.list.length;i++){
+            if(this.list[i][0]==_type){
+                if(values==null){
+                    return i
+                } else if(this.list[i][1] in values){
+                    return i
+                }
+            }
+        }
+        return null
+    }
+
+    this.find_next_at_same_level = function(){
+        // same as find_next but skips enclosures to find the token
+        // at the same level as the one where search starts
+        var pos = arguments[0]
+        var _type = arguments[1]
+        var values = null
+        if(arguments.length>2){
+            values = {}
+            for(i=2;i<arguments.length;i++){values[arguments[i]]=0}
+        }
+        while(true){
+            if(this.list[pos][0]=="bracket" 
+                && this.list[pos][1] in $OpeningBrackets){
+                // opening bracket
+                pos = this.find_next_matching(pos)
+            } else if(this.list[pos][0]==_type){
+                if(values==null){return pos}
+                else if(this.list[pos][1] in values){return pos}
+            }
+            pos++
+            if (pos>this.list.length-1){return null}
+        }
+    }
+    
+    this.find_previous = function(){
+        // same as find_next but search backwards from pos
+        var pos = arguments[0]
+        var _type = arguments[1]
+        var values = null
+        if(arguments.length>2){
+            values = {}
+            for(i=2;i<arguments.length;i++){values[arguments[i]]=0}
+        }
+        for(i=pos;i>=0;i--){
+            if(this.list[i][0]==_type){
+                if(values==null){
+                    return i
+                } else if(this.list[i][1] in values){
+                    return i
+                }
+            }
+        }
+        return null
+    }
+
+    this.find_next_matching = function(pos){
+        // find position of stack item closing the bracket 
+        // at specified position in the tokens stack
+        
+        var brackets = {"(":")","[":"]","{":"}"}
+        var _item = this.list[pos]
+        if(_item[0]=="bracket"){
+            opening = _item[1]
+            count = 0
+            for(i=pos;i<this.list.length;i++){
+                if(this.list[i][0]=="bracket"){
+                    var value = this.list[i][1]
+                    if(value==opening){count += 1}
+                    else if(value==brackets[opening]){
+                        count -= 1
+                        if(count==0){return i}
+                    }
+                }
+            }
+        }
+        return null
+    }
+
+    this.find_previous_matching = function(pos){
+        // find position of stack item closing the bracket 
+        // at specified position in the tokens stack
+        
+        var brackets = {")":"(","]":"[","}":"{"}
+        var item = this.list[pos]
+        var i=0
+        if(item[0]=="bracket"){
+            closing = item[1]
+            count = 0
+            for(i=pos;i>=0;i--){
+                if(this.list[i][0]=="bracket"){
+                    var value = this.list[i][1]
+                    if(value==closing){count += 1;}
+                    else if(value==brackets[closing]){
+                        count -= 1
+                        if(count==0){return i}
+                    }
+                }
+            }
+        }
+        return null
+    }
+    
+    
+    this.get_atoms = function(){
+        var pos = 0
+        var nb = 0
+        var atoms = []
+        while(pos<this.list.length){
+            atom = this.atom_at(pos,true)
+            atoms.push(atom)
+            pos += atom.end-atom.start
+        }
+        return atoms
+    }
+
+    this.atom_at = function(pos,implicit_tuple){
+        // return the atom starting at specified position
+        // an atom is an identifier
+        // with optional qualifiers :  x.foo
+        // and calls : x(...)
+        // if implicit_tuple is set, consume all atoms joined by ,
+        atom = new Atom(this)
+        atom.start = pos
+        if(this.list[pos][0] in $List2Dict('id','assign_id','literal')){
+            atom.type = this.list[pos][0]
+            end = pos
+            while(end<this.list.length-1){
+                var item = this.list[end+1]
+                if(item[0] in $List2Dict("id","assign_id","literal")){
+                    end += 1
+                } else if(item[0] in $List2Dict("point","qualifier")){
+                    atom.type = "qualified_id"
+                    end += 1
+                } else if(item[0]=="bracket" && item[1]=='('){
+                    atom.type = "function_call"
+                    end = this.find_next_matching(end+1)
+                } else if(item[0]=="bracket" && item[1]=='['){
+                    atom.type = "slicing"
+                    end = this.find_next_matching(end+1)
+                } else if(implicit_tuple && item[0]=="delimiter" && item[1]==','){
+                    // implicit tuple
+                    if(atom.type=="id" || atom.type=="literal"){
+                        atom.type = "tuple"
+                    }
+                    end += 1
+                } else if(atom.type=="tuple" && item[0]=="id"){
+                    end += 1
+                } else {
+                    break
+                }
+            }
+            atom.end = end
+            return atom
+        } else if(this.list[pos][0]=="bracket" && 
+            (this.list[pos][1]=="(" || this.list[pos][1]=='[')){
+            atom.type = "tuple"
+            atom.end = this.find_next_matching(pos)
+            return atom
+        } else {
+            atom.type = this.list[pos][0]
+            atom.end = pos
+            return atom
+        }
+    }
+
+    this.atom_before = function(pos,implicit_tuple){
+        // return the atom before specified position
+        atom = new Atom(this)
+        if(pos==0){return null}
+        atom.end = pos-1
+        atom.start = pos-1
+        // find position before atom
+        var atom_parts=$List2Dict("id","assign_id","literal","point","qualifier")
+        var closing = $List2Dict(')',']')
+        while(true){
+            if(atom.start==-1){break}
+            var item = this.list[atom.start]
+            if(item[0] in atom_parts){atom.start--;continue}
+            else if(item[0]=="bracket" && item[1] in closing){
+                atom.start = this.find_previous_matching(atom.start)-1
+                continue
+            }
+            else if(implicit_tuple && item[0]=="delimiter"
+                    && item[1]==","){atom.start--;continue}
+            break
+        }
+        atom.start++
+        return this.atom_at(atom.start,implicit_tuple)
+    }
+    
+    this.indent = function(pos){
+        // return indentation of the line of the item at specified position
+        var nl = this.find_previous(pos,"newline")
+        if(nl==null){nl=0}
+        if(nl<this.list.length-1 && this.list[nl+1][0]=="indent"){
+            return this.list[nl+1][1]
+        } else{return 0}
+    }
+    
+    this.split = function(delimiter){
+        // split stack with specified delimiter
+        var items = new Array()
+        var count = 0
+        var pos = 0
+        var start = 0
+        while(pos<this.list.length){
+            pos = this.find_next_at_same_level(pos,'delimiter',delimiter)
+            if(pos==null){pos=this.list.length;break}
+            var s = new Stack(this.list.slice(start,pos))
+            s.start = start
+            s.end = pos-1
+            items.push(s)
+            start = pos+1
+            pos++
+        }
+        var s = new Stack(this.list.slice(start,pos))
+        s.start = start
+        s.end = pos-1
+        if(s.end<start){s.end=start}
+        items.push(s)
+        return items
+    }
+
+    this.find_block = function(pos){
+        var kw = $List2Dict('def','if','else','elif','class','for')
+        var item = this.list[pos]
+        if(item[0]=="keyword" && item[1] in kw) {
+            var closing_pos = null
+            for(i=pos+1;i<this.list.length;i++){
+                if(this.list[i][0]=="delimiter" && this.list[i][1]==":"){
+                    closing_pos = i
+                    break
+                }
+            }
+            if(closing_pos!=null){
+                // find block end : the newline before the first indentation equal
+                // to the indentation of the line beginning with the keyword
+                var kw_indent = 0
+                var line_start = this.find_previous(pos,"newline")
+                if(line_start==null){kw_indent=0}
+                else if(this.list[line_start+1][0]=="indent"){
+                    kw_indent = this.list[line_start+1][1]
+                }
+                var stop = closing_pos
+                while(true){
+                    nl = this.find_next(stop,"newline")
+                    if(nl==null){stop = this.list.length-1;break}
+                    if(nl<this.list.length-1){
+                        if(this.list[nl+1][0]=="indent"){
+                            if(this.list[nl+1][1]<=kw_indent){
+                                stop = nl
+                                break
+                            }
+                        } else { // no indent
+                            stop = nl
+                            break
+                        }
+                    } else {
+                        stop = this.list.length-1
+                        break
+                    }
+                    stop = nl+1
+                }
+                return [closing_pos,stop,kw_indent]
+            }
+        }
+        return null
+    }
+
+    this.to_js = function(){
+        // build Javascript code
+        var i=0,j=0,x=null
+        var js = "",scope_stack=[]
+        for(i=0;i<this.list.length;i++){
+            x = this.list[i]
+            t2 = $List2Dict("id","assign_id","literal","keyword","code")
+            if(x[0]=="indent") {
+                for(j=0;j<x[1];j++){js += " "}
+            } else if(x[0] in t2) {
+                if(x[0]=='literal'){
+                    if(typeof x[1]=='string'){
+                        js += '$JS2Py('+x[1].replace(/\n/gm,'\\\n')+')'
+                    } else {
+                        js += '$JS2Py('+x[1]+')'
+                    }
+                } else if(x[0]=="id"){
+                    // resolve id name with scope
+                    if(x[3]==undefined){js += x[1]}
+                    else{js += '$resolve("'+x[1]+'","'+x[3]+'")'}
+                } else if(x[0]=="assign_id"){
+                    // assignment inside a scope
+                    if(x[3]==undefined){js += x[1]}
+                    else{js += '$ns["'+x[3]+'"]["'+x[1]+'"]'}
+                } else {
+                    js += x[1]
+                }
+                if(i<this.list.length-1 && this.list[i+1][0] != "bracket"){
+                    js += " "
+                }
+            } else {
+                if(x[0]=="newline"){js += '\r\n'}
+                else{js += x[1]}
+            }
+        }
+        return js
+    }
+
+    this.dump = function(){
+        ch = ''
+        $ForEach(this.list).Do(function(item){
+            ch += item[0]+' '+item[1]+'\n'
+        })
+        alert(ch)
+    }
+}
+
+

File server.py

View file
+import http.server
+server_address = ('', 8000)
+httpd = http.server.HTTPServer(server_address, http.server.CGIHTTPRequestHandler)
+httpd.serve_forever()

File sort_table.html

View file
+<html>
+<head>
+<style>
+body,td,th{font-family:sans-serif}
+a.sort_link{margin-left:10px;text-decoration:none}
+</style>
+
+<script src="py_tokenizer.js"></script>
+<script src="py_utils.js"></script>
+<script src="py_classes.js"></script>
+<script src="py_dom.js"></script>
+<script src="py2js.js"></script>
+
+</head>
+<body onLoad="brython()">
+<script id="ascript" type="text/brython">
+
+orders = {}
+
+def sort_by_col(cell,numeric=False):
+    th_elt = cell.parent()
+    th_id = th_elt['id']
+    if th_id not in orders:
+        if numeric:
+            orders[th_id]='down'
+        else:
+            orders[th_id]='up'
+    elif orders[th_id]=='up':
+        orders[th_id]='down'
+    else:
+        orders[th_id]='up'
+    ascending = orders[th_id]
+
+    tr_elt = th_elt.parent()
+    rank = -1
+    for child in tr_elt.children():
+        if isinstance(child,TH):
+            rank += 1
+        if child == th_elt:
+            num = rank
+            break
+
+    nb_val = 0
+    tb_elt = tr_elt.parent()
+    lines = []
+    line_nums = []
+    col_values = []
+
+    for i,row in enumerate(tb_elt.children()):
+        line = []
+        flag = False
+        if isinstance(row,TR) and row != tr_elt:
+            rank = -1
+            for cell in row.children():
+                if isinstance(cell,TD):
+                    flag = True
+                    rank += 1
+                    if rank==num:
+                        nb_val += 1
+                        val = cell.text()
+                        col_values.append(val)
+                    line.append(cell.html())
+            if flag: # only if row has TD cells : skip table header (TH)
+                lines.append(line) # list of values
+                line_nums.append(i) # rank in table children
+
+    deco = []
+    for i,col_value in enumerate(col_values):
+        deco.append([col_value,i])
+    deco1 = deco[:]
+
+    def _first(_item):
+        return _item[0]
+    
+    deco.sort(_first)
+
+    if ascending == 'down':
+        deco.reverse()
+
+    was_sorted = True
+    for x,y in zip(deco,deco1):
+        if x!=y:
+            was_sorted = False
+            break
+
+    if was_sorted:
+        # table was already sorted : do nothing
+        return
+
+    new_lines = []
+    for item in deco:
+        new_lines.append(lines[item[1]])
+
+    # replace by new lines
+    rank = 0
+    for line_num in line_nums:
+        row = tb_elt.children()[line_num]
+        if isinstance(row,TR) and row != tr_elt:
+            k = 0
+            for cell in row.children():
+                if isinstance(cell,TD):
+                    cell.set_html(new_lines[rank][k])
+                    k += 1
+            rank += 1
+
+lines = ['Allemagne','Berlin',357026,81.8,
+'Autriche','Vienne',83871,8.40,
+'Belgique','Bruxelles',30518,10.91,
+'Bulgarie','Sofia',110944,7.50,
+'Chypre','Nicosie',9251,0.80,
+'Danemark','Copenhague',43098,5.56,
+'Espagne','Madrid',505997,46.15,
+'Estonie','Tallinn',43698,1.34,
+'Finlande','Helsinki',338144,5.37,
+'France','Paris',544000,65.07,
+'Gr�ce','Ath�nes',131625,11.32,
+'Hongrie','Budapest',93029,9.98,
+'Irlande','Dublin',69797,4.48,
+'Italie','Rome',301336,60.62,
+'Lettonie','Riga',64589,2.22,
+'Lituanie','Vilnius',62678,3.24,
+'Luxembourg','Luxembourg',2586,0.51,
+'Malte','La Valette',315,0.41,
+'Pays-Bas','Amsterdam',41528,16.65,
+'Pologne','Varsovie',312685,38.20,
+'Portugal','Lisbonne',91946,10.63,
+'R�publique tch�que','Prague',78867,10.53,
+'Roumanie','Bucarest',238391,21.41,
+'Royaume-Uni','Londres',243820,62.43,
+'Slovaquie','Bratislava',49034,5.43,
+'Slov�nie','Ljubljana',20273,2.05,
+'Su�de','Stockholm',441369,9.41]
+
+doc <= H2("Pays d'Europe")
+
+table = TABLE()
+t = TBODY()
+title = TR()
+link = A('\u2191\u2193',Class="sort_link",href="#",onClick="sort_by_col(this)")
+title <= TH('Pays')+TH('Capitale'+link)+TH('Superficie')+TH('Population')
+t <= title
+
+for i in range(len(lines)/4):
+    row = TR()
+    for j in range(4):
+        row <= TD(lines[4*i+j])
+    t <= row
+
+table <= t
+
+doc <= table
+
+foot = P()+I('Ecrit en '+A('Brython',href="http://www.brython.info"))
+
+doc <= foot
+
+</script>
+</body>
+</html>

File test_suite.py

View file
+def foo(x):
+ return x.upper()
+alert(max(['a','Z'],key=foo))
+alert(max(['A','Z']))
+t = ['a','b']
+t[0]+='bsdfqs'
+alert(t)
+alert('ab'*3)
+z = 'a'
+z += 'bc'
+alert('Z'+z)
+
+x={1:'a',2:'b'}
+for k,v in x.items():
+ alert('%s:%s' %(k,v))
+
+x='azerty'
+v = ''
+for u in reversed(x):
+ v += u
+alert(v)