more comment

bzr revid: al@openerp.com-20110303000835-6fc9p8vgqy2884m0
This commit is contained in:
Antony Lesuisse
2011-03-03 01:08:35 +01:00
2 changed files with 530 additions and 0 deletions
+188
View File
@@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- vim:fdl=1:
-->
<templates id="template" xml:space="preserve">
<t t-name="interface">
<div id="oe_loading" style="display: none;"></div>
<div id="oe_login" style="display: none; padding: 6px;"></div>
<div id="oe_header" style="padding: 4px; border-bottom: 1px solid #000;">
<h2>OpenERP Web Client <span style="font-size:50%; font-weight: normal;"><br/>Codename: from __future__ import openerpweb</span></h2>
</div>
<div id="oe_menu" style="border-bottom: 1px solid #000;"></div>
<div id="oe_main" style="padding-bottom: 6px; border-bottom: 1px solid #000;"></div>
<div id="oe_footer" style="text-align: center; font-size: 75%;">
Powered by OpenERP.
</div>
<div id="oe_errors" style="font-size: 90%;">
Debug:
</div>
<div style="position: absolute; right: 0; top: 0;">
<button onclick="QWeb.add_template('base.xml'); $('body').css('background-color', '#FFFF9C'); setTimeout(function() { $('body').css('background-color', '#FFF'); }, 500);">Reload QWEB</button>
</div>
</t>
<t t-name="Loading">
Loading...
</t>
<t t-name="login">
<form>
Login: <input type="text" name="login" value="admin"/><br/>
Password: <input type="password" name="password" value="a"/><br/>
<input type="submit" name="submit" value="Login"/>
</form>
</t>
<t t-name="Menu.root">
<ul class="sf-menu">
<t t-foreach="data.children" t-as="menu">
<t t-call="Menu.children"/>
</t>
</ul>
<div style="clear: both"></div>
</t>
<t t-name="Menu.children">
<!-- TODO prefix id with the element_id of the controller -->
<li><a href="#" t-attf-id="menu_#{menu.id}"><t t-esc="menu.name"/></a>
<t t-if="menu.children.length!=0">
<ul>
<t t-foreach="menu.children" t-as="menu">
<t t-call="Menu.children"/>
</t>
</ul>
</t>
</li>
</t>
<t t-name="ListView">
<!--
<h3><t t-esc="fields_view.arch['@string']"/></h3>
-->
<div style="text-align:right;">
<input type="button" value="First"/>
<input type="button" value="&lt;&lt;"/>
0 / 0
<input type="button" value="&gt;&gt;"/>
<input type="button" value="Last"/>
</div>
<table id="todo_use_unique_id" class="jqGrid"></table>
</t>
<t t-name="FormView">
<h3><t t-esc="fields_view.arch['@string']"/></h3>
<div style="text-align:right;">
<input type="button" value="First"/>
<input type="button" value="&lt;&lt;"/>
0 / 0
<input type="button" value="&gt;&gt;"/>
<input type="button" value="Last"/>
</div>
<t t-call="FormView.node">
<t t-set="node" t-value="fields_view.arch"/>
</t>
<div style="text-align:right;">
<input type="button" value="Save"/>
</div>
</t>
<t t-name="FormView.node">
<!--
tag: <t t-esc="node.tag"/> <t t-esc="node['@name']"/> <br/>
<t t-if="node.tag == 'filter'">
<input type="button" t-att-value="node['@string']"/>
<t t-esc="node['@name']"/>
<br/>
</t>
<t t-if="node.tag == 'separator'">
<hr/>
<t t-esc="node['@name']"/>
<t t-esc="node['@string']"/>
</t>
-->
<t t-if="node.tag == 'field'">
<t t-esc="node['@string']"/>
<t t-esc="node['@name']"/>
<input type="text" t-att-name="node['@name']"/>
<br/>
</t>
<t t-foreach="node.children || []" t-as="node">
<t t-call="FormView.node"/>
</t>
</t>
<t t-name="SearchView">
<h3><t t-esc="fields_view.arch['@string']"/></h3>
<table border="1">
<tr>
<t t-call="SearchView.node">
<t t-set="node" t-value="fields_view.arch"/>
<t t-set="previous_node_type"></t>
</t>
</tr>
</table>
<div style="text-align:right;">
<input id="search" type="button" value="Search"/>
<input type="button" value="Clear"/>
</div>
</t>
<t t-name="SearchView.node">
<t t-if="node.tag"> <!-- Should remove this condition once the xml2json removes whitespace -->
<!--
tag: <t t-esc="node.tag"/>
<t t-esc="node['@string']"/>
<t t-esc="node['@string']"/>
<br/>
<t t-esc="node['@name']"/>
-->
<t t-if="node.tag == 'filter'">
<t t-if="previous_node_type != 'filter'">
&lt;td nowrap="true"&gt;
</t>
<!-- TODO: buttons are inline elements. should not have whitespaces between them.
Either implement trim in qweb or use css3 white-space-collapsing (not stable now)
Yes implement t-trim it was noted in qweb.js as a TODO:
trim 'left' 'right' 'both' is it needed ? inner=render_trim(l_inner.join(), t_att)
Also add a TODO about t-code=""
-->
<button type="button" t-att-title="node['@help']"><t t-esc="node['@string']"/></button>
<t t-if="next_node_type != 'filter'">
&lt;/td&gt;
</t>
</t>
<t t-if="node.tag == 'separator'">
<!-- nothing in search view ? -->
</t>
<t t-if="node.tag == 'newline'">
<!-- TODO: check qweb support for cdata -->
&lt;/tr&gt;
&lt;/table&gt;
&lt;table border="1"&gt;
&lt;tr&gt;
</t>
<t t-if="node.tag == 'field'">
<td>
<table>
<tr><td> <t t-esc="node['@string']"/><t t-esc="node['@name']"/> </td></tr>
<tr><td> <input type="text" t-att-name="node['@name']"/> </td></tr>
</table>
</td>
</t>
<t t-if="node.children and node.tag != 'field' and node.tag != 'newline'">
<t t-foreach="node.children" t-as="node">
<t t-call="SearchView.node">
<t t-set="previous_node_type" t-value="node_all[node_index - 1] ? node_all[node_index - 1].tag : ''"/>
<t t-set="next_node_type" t-value="node_all[node_index + 1] ? node_all[node_index + 1].tag : ''"/>
</t>
</t>
</t>
</t>
</t>
<t t-name="Action">
<!-- TODO prefix id with the element_id of the controller t-attf-id="#{prefix}_localid" -->
<div style="text-align:right;">
<input id="mode_list" type="button" value="ListView"/>
<input id="mode_form" type="button" value="FormView"/>
</div>
<div id="oe_action_dataset" style="display:none;"></div>
<div id="oe_action_search" ></div>
<div id="oe_action_list" ></div>
<div id="oe_action_form" ></div>
</t>
</templates>
+342
View File
@@ -0,0 +1,342 @@
// vim:set noet fdm=syntax fdl=0 fdc=3 fdn=2:
//---------------------------------------------------------
// QWeb javascript
//---------------------------------------------------------
{
/*
TODO
String parsing
if (window.DOMParser) {
parser=new DOMParser();
xmlDoc=parser.parseFromString(text,"text/xml");
} else {
xmlDoc=new ActiveXObject("Msxml2.DOMDocument.4.0");
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
Which versions to try, it's confusing...
xmlDoc.async="false";
xmlDoc.async=false;
xmlDoc.preserveWhiteSpace=true;
xmlDoc.load("f.xml");
xmlDoc.loadXML(text); ?
}
Support space in IE by reparsing the responseText
xmlhttp.responseXML.loadXML(xmlhttp.responseText); ?
Preprocess: (nice optimization)
preprocess by flattening all non t- element to a TEXT_NODE.
count the number of "\n" in text nodes to give an aproximate LINE NUMBER on elements for error reporting
if from IE HTMLDOM use if(a[i].specified) to avoid 88 empty attributes per element during the preprocess,
implement t-trim 'left' 'right' 'both', is it needed ? inner=render_trim(l_inner.join(), t_att)
Ruby/python: to backport from javascript to python/ruby render_node to use regexp, factorize foreach %var, t-att test for tuple(attname,value)
DONE
we reintroduced t-att-id, no more t-esc-id because of the new convention t-att="["id","val"]"
*/
}
var QWeb={
templates:{},
prefix:"t",
reg:"",
tag:{},
att:{},
eval_object:function(e,v) {
// TODO: Currently this will also replace and, or, ... in strings. Try
// 'hi boys and girls' != '' and 1 == 1 -- will be replaced to : 'hi boys && girls' != '' && 1 == 1
// try to find a solution without tokenizing
e = e.replace(/\Wand\W/g, " && ");
e = e.replace(/\Wor\W/g, " and ");
e = e.replace(/\Wgt\W/g, " > ");
e = e.replace(/\Wgte\W/g, " >= ");
e = e.replace(/\Wlt\W/g, " < ");
e = e.replace(/\Wlte\W/g, " <= ");
if(v[e]!=undefined) {
return v[e]
} else {
with(v) return eval(e);
}
},
eval_str:function(e,v){
var r=this.eval_object(e,v)
r=(typeof(r)=="undefined"||r==null) ? "" : r.toString()
return e=="0" ? v["0"] : r
},
eval_format:function(e,v){
var i,m,r,src=e.split(/#/)
r=src[0]
for(i=1; i<src.length; i++) {
if(m=src[i].match(/^{(.*)}(.*)/)) {
r+=this.eval_str(m[1],v)+m[2]
} else {
r+="#"+src[i]
}
}
return r
},
eval_bool:function(e,v){
return this.eval_object(e,v)?true:false;
},
escape_text:function(s){
return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")
},
escape_att:function(s){
return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")
},
render_node:function(e,v){
var r=""
if(e.nodeType==3) {
r=e.data;
} else if(e.nodeType==1) {
var g_att={};
var t_att={};
var t_render=null;
var a=e.attributes;
for(var i=0; i<a.length; i++) {
var an=a[i].name,av=a[i].value;
var m,n;
if(m=an.match(this.reg)) {
n=m[1]
if(n=="eval") {
n=m[2].substring(1)
av=this.eval_str(av, v)
}
if(f=this.att[n]) {
this[f](e,t_att,g_att,v,m[2],av)
} else if(f=this.tag[n]) {
t_render=f
}
t_att[n]=av
} else {
g_att[an]=av
}
}
if (t_render) {
r = this[t_render](e, t_att, g_att, v)
} else {
r = this.render_element(e, t_att, g_att, v)
}
}
return r;
},
render_element:function(e,t_att,g_att,v){
var inner="",ec=e.childNodes;
for (var i=0; i<ec.length; i++) {
inner+=this.render_node(ec[i],v)
}
if(e.tagName==this.prefix) {
return inner;
} else {
var att="";
for(var an in g_att) {
av=g_att[an]
att+=" "+an+'="'+this.escape_att(av)+'"'
}
r=inner.length ? "<"+e.tagName+att+">"+inner+"</"+e.tagName+">" : "<"+e.tagName+att+"/>"
return r
}
},
render_att_att:function(e,t_att,g_att,v,ext,av){
if(ext) {
g_att[ext.substring(1)]=this.eval_str(av,v)
} else {
o=this.eval_object(av,v)
g_att[o[0]]=o[1]
}
},
render_att_attf:function(e,t_att,g_att,v,ext,av){
g_att[ext.substring(1)]=this.eval_format(av,v)
},
render_tag_raw:function(e,t_att,g_att,v){
return this.eval_str(t_att["raw"], v);
},
render_tag_rawf:function(e,t_att,g_att,v){
return this.eval_format(t_att["raw"], v);
},
render_tag_esc:function(e,t_att,g_att,v){
return this.escape_text(this.eval_str(t_att["esc"], v));
},
render_tag_escf:function(e,t_att,g_att,v){
return this.escape_text(this.eval_format(t_att["esc"], v));
},
render_tag_if:function(e,t_att,g_att,v){
return this.eval_bool(t_att["if"],v) ? this.render_element(e, t_att, g_att, v) : ""
},
render_tag_set:function(e,t_att,g_att,v){
var ev=t_att["value"]
if(ev && ev.constructor!=Function) {
v[t_att["set"]]=this.eval_object(ev,v)
} else {
v[t_att["set"]]=this.render_element(e, t_att, g_att, v)
}
return ""
},
render_tag_call:function(e,t_att,g_att,v){
var d=v;
if(!t_att["import"]) {
d = {}
for(var i in v) {
d[i]=v[i]
}
}
d["0"]=this.render_element(e, t_att, g_att, d)
return this.render(t_att["call"],d)
},
render_tag_js:function(e,t_att,g_att,v){
var r=this.eval_str(this.render_element(e, t_att, g_att, v),v)
return t_att["js"]!="quiet" ? r : ""
},
render_tag_foreach:function(e,t_att,g_att,v){
var expr=t_att["foreach"]
var enu=this.eval_object(expr,v)
var ru=[];
if(enu) {
var val=t_att['as'] || expr.replace(/[^a-zA-Z0-9]/g,'_')
d={}
for(var i in v) {
d[i]=v[i]
}
d[val+"_all"]=enu
val_value = val+"_value"
val_index = val+"_index"
val_first = val+"_first"
val_last = val+"_last"
val_parity = val+"_parity"
var size=enu.length
if(size) {
d[val+"_size"]=size
for (var i=0; i<size; i++) {
var cur=enu[i]
d[val_value]=cur
d[val_index]=i
d[val_first]=i==0
d[val_last]=i+1==size
d[val_parity]=(i%2==1 ? 'odd' : 'even')
if (cur.constructor==Object) {
for(var j in cur) {
d[j]=cur[j]
}
}
d[val]=cur
var r = this.render_element(e,t_att,g_att,d);
ru.push(r)
}
} else {
index=0
for(cur in enu) {
d[val_value]=cur
d[val_index]=index
d[val_first]=index==0
d[val_parity]=(index%2==1 ? 'odd' : 'even')
d[val]=cur
ru.push(this.render_element(e,t_att,g_att,d))
index+=1
}
}
return ru.join("")
} else {
return "qweb: foreach "+expr+" not found."
}
},
hash:function(){
var l=[]
for(var i in this) {
if(m=i.match(/render_tag_(.*)/)) {
this.tag[m[1]]=i
l.push(m[1])
} else if(m=i.match(/render_att_(.*)/)) {
this.att[m[1]]=i
l.push(m[1])
}
}
l.sort(function(a,b){return a.length>b.length?-1:1})
var s="^"+this.prefix+"-(eval|"+l.join("|")+"|.*)(.*)$"
this.reg=new RegExp(s);
},
load_xml:function(s){
var xml;
if(s[0]=="<") {
/*
manque ca pour sarrisa
if(window.DOMParser){
mozilla
if(!window.DOMParser){
var doc = Sarissa.getDomDocument();
doc.loadXML(sXml);
return doc;
};
};
*/
} else {
var w=window,r=w.XMLHttpRequest,j;
if(r)r=new r();else for(j in{"Msxml2":1,"Microsoft":1})try{r=new ActiveXObject(j+".XMLHTTP");break}catch(e){}
if(r) {
r.open("GET", s, false);
r.send(null);
//if ie r.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
xml=r.responseXML;
/*
TODO
if intsernetexploror
getdomimplmentation() for try catch
responseXML.getImplet
d=domimple()
d.preserverWhitespace=1
d.loadXML()
xml.preserverWhitespace=1
xml.loadXML(r.reponseText)
*/
return xml;
}
}
},
add_template:function(e){
// TODO: keep sources so we can implement reload()
this.hash()
if(e.constructor==String) {
e=this.load_xml(e)
}
var ec=[];
if(e.documentElement) {
ec=e.documentElement.childNodes
} else if(e.childNodes) {
ec=e.childNodes
}
for (var i=0; i<ec.length; i++) {
var n=ec[i];
if(n.nodeType==1) {
var name=n.getAttribute(this.prefix+"-name")
this.templates[name]=n;
}
}
},
render:function(name,v){
if(e=this.templates[name]) {
return this.render_node(e,v)
} else {
return "template "+name+" not found";
}
},
dump:function(o){
var r="";
if(typeof(o)=="object") {
for(var i in o) {
r+=i+" : "+this.dump(s)+"\n"
}
r=s+"{\n"+r+"}\n"
} else {
r=s+"";
}
return r;
},
debug:function(s){
var r=this.dump(s)
$("#debug")[0].append(this.escape_text(r)+"<br/>\n")
}
}