← Back to team overview

openerp-dev-web team mailing list archive

[Merge] lp:~xmo/openobject-client-web/iframe-resize-events into lp:~openerp-dev/openobject-client-web/trunk-dev-web

 

Xavier (Open ERP) has proposed merging lp:~xmo/openobject-client-web/iframe-resize-events into lp:~openerp-dev/openobject-client-web/trunk-dev-web.

Requested reviews:
  OpenERP SA's Web Client R&D (openerp-dev-web)


Currently, the iframe is resized based on a timer which, every 10mn, does a full pass to re-set the height of #appFrame to ensure the scrollbar is on the page itself, not in the iframe.

This poses performance problems as the resizing operations are fairly expensive and restarted very often.

The current branch tries to fix that by hooking into specific events (which can change the size of the iframe's content and therefore require that the iframe element itself be resized to match) and removes the timer.

Could you:
* Check that I didn't introduce any outstanding bug (and review as "needs-fixing")
* See if you find obvious cases that I missed, and report them (and review as "needs-fixing")
-- 
https://code.launchpad.net/~xmo/openobject-client-web/iframe-resize-events/+merge/23005
Your team OpenERP SA's Web Client R&D is subscribed to branch lp:~openerp-dev/openobject-client-web/trunk-dev-web.
=== modified file 'addons/openerp/controllers/templates/menu.mako'
--- addons/openerp/controllers/templates/menu.mako	2010-04-06 09:51:49 +0000
+++ addons/openerp/controllers/templates/menu.mako	2010-04-08 09:53:18 +0000
@@ -2,53 +2,39 @@
 
 <%def name="header()">
     <title>OpenERP</title>
-    
+
     <link href="/openerp/static/css/accordion.css" rel="stylesheet" type="text/css"/>
     <link href="/openerp/static/css/treegrid.css" rel="stylesheet" type="text/css"/>
     <link href="/openerp/static/css/notebook.css" rel="stylesheet" type="text/css"/>
-    
-    <script type="text/javascript" src="/openerp/static/javascript/menubar.js"></script>
+
     <script type="text/javascript" src="/openerp/static/javascript/accordion.js"></script>
     <script type="text/javascript" src="/openerp/static/javascript/treegrid.js"></script>
     <script type="text/javascript" src="/openerp/static/javascript/notebook/notebook.js"></script>
-    
-    <script type="text/javascript">
-        
-            // call adjustAppFrame every 0.5 second
-            function adjustFrame(wait) {
-                try {
-                    adjustAppFrame();
-                } catch(e){}
-                setTimeout(adjustFrame, wait);
-            }
-            adjustFrame(0.5);
-            
-</script>
-    
-    <style>
+
+    <style type="text/css">
         .accordion-content {
         }
-        
+
         .accordion {
             border: none;
         }
-        
+
         .accordion-title {
             padding: 2px;
         }
-        
+
         #menubar_container {
             overflow: auto;
-            border: 1px solid black;            
+            border: 1px solid black;
         }
-        
+
         #content_iframe {
-        	overflow-x: auto;
-        	overflow-y: hidden;
+            overflow-x: auto;
+            overflow-y: hidden;
         }
-        
+
     </style>
-    
+
 </%def>
 
 <%def name="content()">
@@ -57,39 +43,39 @@
 
     <div id="menutabs" class="notebook menu-tabs">
         %for parent in parents:
-            <div id="${parent['id']}" title="${parent['name']}"></div>
+        <div id="${parent['id']}" title="${parent['name']}"></div>
         %endfor
     </div>
 
     <script type="text/javascript">
-    
+
         var nb = new Notebook('menutabs', {
             'closable': false,
             'scrollable': true
         });
-                
-        MochiKit.Signal.connect(nb, 'click', function(nb, tab){
+
+        MochiKit.Signal.connect(nb, 'click', function(nb, tab) {
             window.location.href = openobject.http.getURL("/menu", {active: tab.id});
         });
-        
+
     </script>
-    
+
     <table id="contents" width="100%">
         <tr>
             <td width="250" valign="top">
                 <div id="menubar" class="accordion">
                     % for tool in tools:
-                    <div class="accordion-block">
-                        <table class="accordion-title">
-                            <tr>
-                                <td><img src="${tool['icon']}" width="16" height="16" align="left"/></td>
-                                <td>${tool['name']}</td>
-                            </tr>
-                        </table>
-                        <div class="accordion-content">
-                            ${tool['tree'].display()}
+                        <div class="accordion-block">
+                            <table class="accordion-title">
+                                <tr>
+                                    <td><img alt="" src="${tool['icon']}" width="16" height="16" align="left"/></td>
+                                    <td>${tool['name']}</td>
+                                </tr>
+                            </table>
+                            <div class="accordion-content">
+                                ${tool['tree'].display()}
+                            </div>
                         </div>
-                    </div>
                     % endfor
                 </div>
                 <script type="text/javascript">
@@ -97,16 +83,16 @@
                 </script>
             </td>
             <td valign="top">
-            	% if setup:
-	                <iframe id="appFrame" width="100%"
-	                        scrolling="no"
-	                        frameborder="0" 
-	                        name="appFrame" src="${py.url('/home')}"></iframe>
+                % if setup:
+                    <iframe id="appFrame" width="100%"
+                        scrolling="no"
+                        frameborder="0"
+                        name="appFrame" src="${py.url('/home')}"></iframe>
                 % else:
-                	<iframe id="appFrame" width="100%"
-	                        scrolling="no"
-	                        frameborder="0" 
-	                        name="appFrame"></iframe>
+                    <iframe id="appFrame" width="100%"
+                        scrolling="no"
+                        frameborder="0"
+                        name="appFrame"></iframe>
                 % endif
             </td>
         </tr>

=== modified file 'addons/openerp/static/javascript/ajax_stat.js'
--- addons/openerp/static/javascript/ajax_stat.js	2010-04-06 09:51:49 +0000
+++ addons/openerp/static/javascript/ajax_stat.js	2010-04-08 09:53:18 +0000
@@ -79,7 +79,6 @@
     
     MochiKit.Signal.connect(window, "onresize", onAjaxStatPosition);
     MochiKit.Signal.connect(window, "onscroll", onAjaxStatPosition);
-    
     onAjaxStatPosition();
 });
 

=== modified file 'addons/openerp/static/javascript/form.js'
--- addons/openerp/static/javascript/form.js	2010-04-06 09:51:49 +0000
+++ addons/openerp/static/javascript/form.js	2010-04-08 09:53:18 +0000
@@ -593,6 +593,7 @@
                 }
 
                 MochiKit.Signal.signal(fld, 'onchange');
+                MochiKit.Signal.signal(window.document, 'onfieldchange', fld);
             }
 
             fld.__lock_onchange = false;

=== modified file 'addons/openerp/static/javascript/listgrid.js'
--- addons/openerp/static/javascript/listgrid.js	2010-04-07 08:47:43 +0000
+++ addons/openerp/static/javascript/listgrid.js	2010-04-08 09:53:18 +0000
@@ -40,11 +40,11 @@
     }
 
     this.__init__(name);
-}
+};
 
 ListView.prototype = {
 
-    __init__: function(name){
+    __init__: function(name) {
 
         var prefix = name == '_terp_list' ? '' : name + '/';
 
@@ -69,12 +69,12 @@
         openobject.dom.get(name).__listview = this;
     },
 
-    checkAll: function(clear){
+    checkAll: function(clear) {
 
         clear = clear ? false : true;
 
         boxes = openobject.dom.get(this.name).getElementsByTagName('input');
-        forEach(boxes, function(box){
+        forEach(boxes, function(box) {
             box.checked = clear;
         });
         var sb = openobject.dom.get('sidebar');
@@ -82,23 +82,23 @@
     },
 
     getRecords: function() {
-        var records = map(function(row){
+        var records = map(function(row) {
             return parseInt(getNodeAttribute(row, 'record')) || 0;
         }, openobject.dom.select('tr.grid-row', this.name));
 
-        return filter(function(rec){
+        return filter(function(rec) {
             return rec;
         }, records);
     },
 
     getSelectedRecords: function() {
-        return map(function(box){
+        return map(function(box) {
             return box.value;
         }, this.getSelectedItems());
     },
 
     getSelectedItems: function() {
-        return filter(function(box){
+        return filter(function(box) {
             return box.id && box.checked;
         }, openobject.dom.select('input.grid-record-selector', this.name));
     },
@@ -117,98 +117,93 @@
     	}
     },
 
-    getColumns: function(dom){
+    getColumns: function(dom) {
         dom = dom || this.name;
         var header = openobject.dom.select('tr.grid-header', dom)[0];
 
-        return filter(function(c){
+        return filter(function(c) {
             return c.id ? true : false;
         }, openobject.dom.select('th.grid-cell', header));
     },
-    
-    makeArgs: function(){
 
+    makeArgs: function() {
         var args = {};
-        var name = '/' + this.name;
-        var names = name.split('/');
+        var names = ('/' + this.name).split('/');
 
         var prefix = '';
         var items = openobject.dom.select('input');
 
-        while(names.length) {
+        while (names.length) {
 
             var name = names.shift();
             prefix = prefix + (name ? name + '/' : '');
 
-            var patern = prefix + '_terp_';
+            var pattern = prefix + '_terp_';
 
-            forEach(items, function(item){
-                if(item.name.match("^"+ patern) == patern && !item.name.match('^_terp_listfields/')) {
-                	args[item.name] = item.value;
+            forEach(items, function(item) {
+                if (item.name.match("^" + pattern) == pattern && !item.name.match('^_terp_listfields/')) {
+                    args[item.name] = item.value;
                 }
             });
         }
 
         return args;
     }
-}
+};
 
 // inline editor related functions
 MochiKit.Base.update(ListView.prototype, {
 
-    adjustEditors: function(newlist){
+    adjustEditors: function(newlist) {
 
         var editors = this.getEditors(false, newlist);
-
         forEach(editors, function(e) {
             // disable autocomplete (Firefox < 2.0 focus bug)
             setNodeAttribute(e, 'autocomplete', 'OFF');
         });
 
-        if (/MSIE/.test(navigator.userAgent)){
+        if (/MSIE/.test(navigator.userAgent)) {
             return editors;
         }
 
-        var widths = {};
-
+        var columnWidths = {};
         // set the column widths of the newlist
-        forEach(this.getColumns(), function(c){
-            widths[c.id] = parseInt(c.offsetWidth) - 8;
-        });
-
-        forEach(this.getColumns(newlist), function(c){
-            c.style.width = widths[c.id] + 'px';
-        });
-
-        var widths = {};
-        forEach(this.getEditors(), function(e){
-            widths[e.id] = parseInt(e.offsetWidth);
+        forEach(this.getColumns(), function(c) {
+            columnWidths[c.id] = parseInt(c.offsetWidth) - 8;
+        });
+
+        forEach(this.getColumns(newlist), function(c) {
+            c.style.width = columnWidths[c.id] + 'px';
+        });
+
+        var editorWidths = {};
+        forEach(this.getEditors(), function(e) {
+            editorWidths[e.id] = parseInt(e.offsetWidth);
         });
 
         return editors;
     },
 
-    bindKeyEventsToEditors: function(editors){
+    bindKeyEventsToEditors: function(editors) {
         var self = this;
-        var editors = filter(function(e){
+        var enabledEditors = filter(function(e) {
             return e.type != 'hidden' && !e.disabled
         }, editors);
 
-        forEach(editors, function(e){
+        forEach(enabledEditors, function(e) {
             connect(e, 'onkeydown', self, self.onKeyDown);
             addElementClass(e, 'listfields');
         });
     },
 
-    getEditors: function(named, dom){
-        var editors = [];
+    getEditors: function(named, dom) {
         var dom = dom ? dom : this.name;
 
-        editors = openobject.dom.select("input, select, textarea", dom);
+        var editors = openobject.dom.select("input, select, textarea", dom);
 
-        return filter(function(e){
+        return filter(function(e) {
             name = named ? e.name : e.id;
-            return name &&  name.indexOf('_terp_listfields') == 0;
+            return name && name.indexOf('_terp_listfields') == 0;
         }, editors);
     }
 
@@ -216,49 +211,49 @@
 
 // pagination & reordering
 MochiKit.Base.update(ListView.prototype, {
-	sort_by_order: function(id) {
-		var self = this
-		var domain = [];
-		var args = {}
-		if(getElement('_'+this.name+'_button1'))
-			domain = getNodeAttribute(getElement('_'+this.name+'_button1'),'domain')
-		
-		args['_terp_model'] = this.model
-		args['_terp_sort_order'] = id
-		args['_terp_sort_domain'] = domain
-		var _terp_id = openobject.dom.get(self.name + '/_terp_id') || openobject.dom.get('_terp_id');
+    sort_by_order: function(id) {
+        var self = this;
+        var domain = [];
+        var args = {};
+        if (getElement('_' + this.name + '_button1')) {
+            domain = getNodeAttribute(getElement('_' + this.name + '_button1'), 'domain');
+        }
+
+        args['_terp_model'] = this.model;
+        args['_terp_sort_order'] = id;
+        args['_terp_sort_domain'] = domain;
+        var _terp_id = openobject.dom.get(self.name + '/_terp_id') || openobject.dom.get('_terp_id');
         var _terp_ids = openobject.dom.get(self.name + '/_terp_ids') || openobject.dom.get('_terp_ids');
-        
-		if(this.ids!='[]')
-		{
-			var req = openobject.http.postJSON('/listgrid/sort_by_order', args);
-			req.addCallback(function(obj) {
-				if(obj.ids) {
-					_terp_ids.value = '[' + obj.ids.join(',') + ']';
-					self.reload();
-				}
-				else 
-					alert(obj.error)
-			})
-		}
-	},
-	
-	dragRow: function(drag,drop,event) {
-		var args = {}
-		var _list_view = new ListView(drag.parentNode.parentNode.id.split("_grid")[0]);
-		var _terp_model =  getElement(drag.parentNode.parentNode.id.split("_grid")[0]+'/_terp_model') || getElement('_terp_model')
-		args['_terp_model'] = _terp_model.value
-		var _terp_ids = getElement(drag.parentNode.parentNode.id.split("_grid")[0]+'/_terp_ids') || getElement('_terp_ids')
-		args['_terp_ids'] = _terp_ids.value
-		args['_terp_id'] = getNodeAttribute(drag,'record')
-		args['_terp_swap_id'] = getNodeAttribute(drop,'record')
-		
-		var req = openobject.http.postJSON('/listgrid/dragRow', args);
-		req.addCallback(function() {
-			_list_view.reload()
-		})
-	},
-	
+
+        if (this.ids != '[]') {
+            var req = openobject.http.postJSON('/listgrid/sort_by_order', args);
+            req.addCallback(function(obj) {
+                if (obj.ids) {
+                    _terp_ids.value = '[' + obj.ids.join(',') + ']';
+                    self.reload();
+                } else {
+                    alert(obj.error);
+                }
+            })
+        }
+    },
+
+    dragRow: function(drag, drop, event) {
+        var args = {};
+        var _list_view = new ListView(drag.parentNode.parentNode.id.split("_grid")[0]);
+        var _terp_model = getElement(drag.parentNode.parentNode.id.split("_grid")[0] + '/_terp_model') || getElement('_terp_model');
+        args['_terp_model'] = _terp_model.value;
+        var _terp_ids = getElement(drag.parentNode.parentNode.id.split("_grid")[0] + '/_terp_ids') || getElement('_terp_ids');
+        args['_terp_ids'] = _terp_ids.value;
+        args['_terp_id'] = getNodeAttribute(drag, 'record');
+        args['_terp_swap_id'] = getNodeAttribute(drop, 'record');
+
+        var req = openobject.http.postJSON('/listgrid/dragRow', args);
+        req.addCallback(function() {
+            _list_view.reload();
+        })
+    },
+
     moveUp: function(id) {
 
         var self = this;
@@ -266,11 +261,11 @@
 
         args['_terp_model'] = this.model;
         args['_terp_ids'] = this.ids;
-        
+
         args['_terp_id'] = id;
 
         var req = openobject.http.postJSON('/listgrid/moveUp', args);
-        req.addCallback(function(){
+        req.addCallback(function() {
             self.reload();
         });
     },
@@ -278,14 +273,14 @@
     moveDown: function(id) {
 
         var self = this;
-        var args = {};
-
-        args['_terp_model'] = this.model;
-        args['_terp_ids'] = this.ids;
-        args['_terp_id'] = id;
+        var args = {
+            '_terp_model': this.model,
+            '_terp_ids': this.ids,
+            '_terp_id': id
+        };
 
         var req = openobject.http.postJSON('/listgrid/moveDown', args);
-        req.addCallback(function(){
+        req.addCallback(function() {
             self.reload();
         });
     }
@@ -294,7 +289,7 @@
 // event handlers
 MochiKit.Base.update(ListView.prototype, {
 
-    onKeyDown: function(evt){
+    onKeyDown: function(evt) {
         var key = evt.key();
         var src = evt.src();
 
@@ -302,19 +297,19 @@
             return;
         }
 
-        if (key.string == "KEY_ESCAPE"){
+        if (key.string == "KEY_ESCAPE") {
             evt.stop();
             return this.reload();
         }
 
-        if (key.string == "KEY_ENTER"){
+        if (key.string == "KEY_ENTER") {
 
-            if (hasElementClass(src, "m2o")){
+            if (hasElementClass(src, "m2o")) {
 
                 var k = src.id;
                 k = k.slice(0, k.length - 5);
 
-                if (src.value && !openobject.dom.get(k).value){
+                if (src.value && !openobject.dom.get(k).value) {
                     return;
                 }
             }
@@ -327,21 +322,21 @@
             return this.save(this.current_record);
         }
 
-        var editors = openobject.dom.select('listfields',this.name);
+        var editors = openobject.dom.select('listfields', this.name);
 
         var first = editors.shift();
         var last = editors.pop();
 
-        if (src == last){
+        if (src == last) {
             evt.stop();
             first.focus();
             first.select();
         }
     },
 
-    onButtonClick: function(name, btype, id, sure, context){
+    onButtonClick: function(name, btype, id, sure, context) {
 
-        if (sure && !confirm(sure)){
+        if (sure && !confirm(sure)) {
             return;
         }
 
@@ -350,15 +345,15 @@
 
         if (btype == "open") {
             return window.open(get_form_action('/form/edit', {
-                        id: id,
-                        ids: openobject.dom.get(prefix + '_terp_ids').value,
-                        model: openobject.dom.get(prefix + '_terp_model').value,
-                        view_ids: openobject.dom.get(prefix + '_terp_view_ids').value,
-                        domain: openobject.dom.get(prefix + '_terp_domain').value,
-                        context: openobject.dom.get(prefix + '_terp_context').value,
-                        limit: openobject.dom.get(prefix + '_terp_limit').value,
-                        offset: openobject.dom.get(prefix + '_terp_offset').value,
-                        count: openobject.dom.get(prefix + '_terp_count').value}));
+                id: id,
+                ids: openobject.dom.get(prefix + '_terp_ids').value,
+                model: openobject.dom.get(prefix + '_terp_model').value,
+                view_ids: openobject.dom.get(prefix + '_terp_view_ids').value,
+                domain: openobject.dom.get(prefix + '_terp_domain').value,
+                context: openobject.dom.get(prefix + '_terp_context').value,
+                limit: openobject.dom.get(prefix + '_terp_limit').value,
+                offset: openobject.dom.get(prefix + '_terp_offset').value,
+                count: openobject.dom.get(prefix + '_terp_count').value}));
         }
 
         name = name.split('.').pop();
@@ -368,14 +363,14 @@
             _terp_id : id,
             _terp_button_name : name,
             _terp_button_type : btype
-        }
+        };
 
         var req = eval_domain_context_request({source: this.name, context : context || '{}'});
-        req.addCallback(function(res){
+        req.addCallback(function(res) {
             params['_terp_context'] = res.context;
             var req = openobject.http.postJSON('/listgrid/button_action', params);
-            req.addCallback(function(obj){
-                if (obj.error){
+            req.addCallback(function(obj) {
+                if (obj.error) {
                     return alert(obj.error);
                 }
 
@@ -385,8 +380,9 @@
 
                 if (obj.reload) {
                     window.location.reload();
-                } else
+                } else {
                     self.reload();
+                }
             });
         });
     }
@@ -395,15 +391,15 @@
 // standard actions
 MochiKit.Base.update(ListView.prototype, {
 
-    create: function(default_get_ctx){
+    create: function(default_get_ctx) {
         this.edit(-1, default_get_ctx);
     },
 
-    edit: function(edit_inline, default_get_ctx){
+    edit: function(edit_inline, default_get_ctx) {
         this.reload(edit_inline, null, default_get_ctx);
     },
 
-    save: function(id){
+    save: function(id) {
 
         if (openobject.http.AJAX_COUNT > 0) {
             return callLater(1, bind(this.save, this), id);
@@ -413,7 +409,7 @@
         var data = getFormData(true);
         var args = getFormParams('_terp_concurrency_info');
 
-        for(var k in data) {
+        for (var k in data) {
             if (k.indexOf(this.name + '/') == 0 || this.name == '_terp_list') {
                 args[k] = data[k];
             }
@@ -425,7 +421,7 @@
         args['_terp_ids'] = openobject.dom.get(prefix + '_terp_ids').value;
         args['_terp_model'] = this.model;
 
-        if (parent_field.length > 0){
+        if (parent_field.length > 0) {
             parent_field.pop();
         }
 
@@ -438,17 +434,18 @@
         args['_terp_source'] = this.name;
 
         var self = this;
-        var req= openobject.http.postJSON('/listgrid/save', args);
+        var req = openobject.http.postJSON('/listgrid/save', args);
 
-        req.addCallback(function(obj){
-            if (obj.error){
+        req.addCallback(function(obj) {
+            if (obj.error) {
                 alert(obj.error);
 
                 if (obj.error_field) {
                     var fld = openobject.dom.get('_terp_listfields/' + obj.error_field);
 
-                    if (fld && getNodeAttribute(fld, 'kind') == 'many2one')
+                    if (fld && getNodeAttribute(fld, 'kind') == 'many2one') {
                         fld = openobject.dom.get(fld.id + '_text');
+                    }
 
                     if (fld) {
                         fld.focus();
@@ -461,26 +458,26 @@
                 openobject.dom.get(prefix + '_terp_ids').value = obj.ids;
 
                 self.reload(id > 0 ? null : -1, prefix ? 1 : 0);
-             }
-         });
+            }
+        });
     },
 
-    remove: function(ids){
+    remove: function(ids) {
 
         var self = this;
-        var args = getFormParams('_terp_concurrency_info');;
-
-        if(!ids) {
+        var args = getFormParams('_terp_concurrency_info');
+
+
+        if (!ids) {
             var ids = this.getSelectedRecords();
-            if(ids.length > 0){
+            if (ids.length > 0) {
                 ids = '[' + ids.join(', ') + ']';
             }
         }
 
         if (ids.length == 0) {
             return alert(_('You must select at least one record.'));
-        }
-        else if (!confirm(_('Do you really want to delete selected record(s) ?'))) {
+        } else if (!confirm(_('Do you really want to delete selected record(s) ?'))) {
             return false;
         }
 
@@ -489,8 +486,8 @@
 
         var req = openobject.http.postJSON('/listgrid/remove', args);
 
-        req.addCallback(function(obj){
-            if (obj.error){
+        req.addCallback(function(obj) {
+            if (obj.error) {
                 alert(obj.error);
             } else {
                 self.reload();
@@ -498,9 +495,9 @@
         });
     },
 
-    go: function(action){
+    go: function(action) {
 
-        if (openobject.http.AJAX_COUNT > 0){
+        if (openobject.http.AJAX_COUNT > 0) {
             return;
         }
 
@@ -514,7 +511,7 @@
         var lv = l.value ? parseInt(l.value) : 0;
         var cv = c.value ? parseInt(c.value) : 0;
 
-        switch(action) {
+        switch (action) {
             case 'next':
                 o.value = ov + lv;
                 break;
@@ -532,7 +529,7 @@
         this.reload();
     },
 
-    reload: function(edit_inline, concurrency_info, default_get_ctx){
+    reload: function(edit_inline, concurrency_info, default_get_ctx) {
 
         if (openobject.http.AJAX_COUNT > 0) {
             return callLater(1, bind(this.reload, this), edit_inline, concurrency_info);
@@ -540,7 +537,7 @@
 
         var self = this;
         var args = this.makeArgs();
-        
+
         // add args
         args['_terp_source'] = this.name;
         args['_terp_edit_inline'] = edit_inline;
@@ -553,15 +550,15 @@
             args['_terp_search_data'] = openobject.dom.get('_terp_search_data').value;
             args['_terp_filter_domain'] = openobject.dom.get('_terp_filter_domain').value;
         }
-        
+
         var req = openobject.http.postJSON('/listgrid/get', args);
-        req.addCallback(function(obj){
+        req.addCallback(function(obj) {
 
             var _terp_id = openobject.dom.get(self.name + '/_terp_id') || openobject.dom.get('_terp_id');
             var _terp_ids = openobject.dom.get(self.name + '/_terp_ids') || openobject.dom.get('_terp_ids');
             var _terp_count = openobject.dom.get(self.name + '/_terp_count') || openobject.dom.get('_terp_count');
 
-            if(obj.ids) {
+            if (obj.ids) {
                 _terp_id.value = obj.ids.length ? obj.ids[0] : 'False';
                 _terp_ids.value = '[' + obj.ids.join(',') + ']';
                 _terp_count.value = obj.count;
@@ -573,8 +570,9 @@
             var newlist = d.getElementsByTagName('table')[0];
             var editors = self.adjustEditors(newlist);
 
-            if (editors.length > 0)
+            if (editors.length > 0) {
                 self.bindKeyEventsToEditors(editors);
+            }
 
             self.current_record = edit_inline;
 
@@ -587,20 +585,21 @@
             if ((navigator.appName != 'Netscape') || (ua.indexOf('safari') != -1)) {
                 // execute JavaScript
                 var scripts = openobject.dom.select('script', newlist);
-                forEach(scripts, function(s){
+                forEach(scripts, function(s) {
                     eval(s.innerHTML);
                 });
             }
 
             // update concurrency info
-            for(var key in obj.info) {
+            for (var key in obj.info) {
                 try {
                     var items = openobject.dom.select("[name=_terp_concurrency_info][value*=" + key + "]")
                     var value = "('" + key + "', '" + obj.info[key] + "')";
-                    for(var i=0; i<items.length;i++) {
+                    for (var i = 0; i < items.length; i++) {
                         items[i].value = value;
                     }
-                }catch(e){}
+                } catch(e) {
+                }
             }
 
             // set focus on the first field
@@ -612,7 +611,7 @@
 
             // call on_change for default values
             if (editors.length && edit_inline == -1) {
-                forEach(editors, function(e){
+                forEach(editors, function(e) {
                     if (e.value && getNodeAttribute(e, 'callback')) {
                         MochiKit.Signal.signal(e, 'onchange');
                     }
@@ -628,7 +627,7 @@
 // export/import functions
 MochiKit.Base.update(ListView.prototype, {
 
-    exportData: function(){
+    exportData: function() {
 
         var ids = this.getSelectedRecords();
 
@@ -639,69 +638,65 @@
         ids = '[' + ids.join(',') + ']';
 
         openobject.tools.openWindow(openobject.http.getURL('/impex/exp', {_terp_model: this.model,
-                                         _terp_source: this.name,
-                                         _terp_search_domain: openobject.dom.get('_terp_search_domain').value,
-                                         _terp_ids: ids,
-                                         _terp_view_ids : this.view_ids,
-                                         _terp_view_mode : this.view_mode}));
+            _terp_source: this.name,
+            _terp_search_domain: openobject.dom.get('_terp_search_domain').value,
+            _terp_ids: ids,
+            _terp_view_ids : this.view_ids,
+            _terp_view_mode : this.view_mode}));
     },
 
-    importData: function(){
+    importData: function() {
         openobject.tools.openWindow(openobject.http.getURL('/impex/imp', {_terp_model: this.model,
-                                         _terp_source: this.name,
-                                         _terp_view_ids : this.view_ids,
-                                         _terp_view_mode : this.view_mode}));
+            _terp_source: this.name,
+            _terp_view_ids : this.view_ids,
+            _terp_view_mode : this.view_mode}));
     }
 });
 
 var toggle_group_data = function(id) {
-	
-	img = openobject.dom.get('img_'+id);
-	rows = openobject.dom.select('tr.'+id);
-	
-	forEach(rows, function(rw){
-		if (rw.style.display == 'none') {
-			rw.style.display = '';
-			setNodeAttribute(img, 'src', '/openerp/static/images/treegrid/collapse.gif');
-		}
-		else {
-			rw.style.display = 'none';
-			setNodeAttribute(img, 'src', '/openerp/static/images/treegrid/expand.gif');
-		}
-	});
-}
+
+    img = openobject.dom.get('img_' + id);
+    rows = openobject.dom.select('tr.' + id);
+
+    forEach(rows, function(rw) {
+        if (rw.style.display == 'none') {
+            rw.style.display = '';
+            setNodeAttribute(img, 'src', '/openerp/static/images/treegrid/collapse.gif');
+        }
+        else {
+            rw.style.display = 'none';
+            setNodeAttribute(img, 'src', '/openerp/static/images/treegrid/expand.gif');
+        }
+    });
+};
 
 var row_edit = function(evt) {
-	var row = [];
-	row = getElementsByTagAndClassName('tr', 'grid-row');
-	
-    forEach(row, function(e){
-    	MochiKit.Signal.connect(e, 'ondblclick', e, select_row_edit);
+    var row = getElementsByTagAndClassName('tr', 'grid-row');
+
+    forEach(row, function(e) {
+        MochiKit.Signal.connect(e, 'ondblclick', e, select_row_edit);
     });
-}
+};
 
-var select_row_edit = function(e){
-	src = e.src();
-	src_record = getNodeAttribute(src, 'record');
-	target = e.target();
-	target_class = getNodeAttribute(target,'class');
+var select_row_edit = function(e) {
+    src = e.src();
+    src_record = getNodeAttribute(src, 'record');
+    target = e.target();
+    target_class = getNodeAttribute(target, 'class');
 
     var view_type = getElement('_terp_view_type').value;
     var editable = getElement('_terp_editable').value;
 
-	if (!(target_class == 'checkbox grid-record-selector' || target_class == 'listImage')) {
-		if ((view_type == 'tree' && editable != 'True')) {
-			do_select(src_record);
-		}
-		if ((view_type == 'tree' && editable == 'True')){
-			editRecord(src_record);
-		}
-	}
-}
+    if (!(target_class == 'checkbox grid-record-selector' || target_class == 'listImage')) {
+        if ((view_type == 'tree' && editable != 'True')) {
+            do_select(src_record);
+        }
+        if ((view_type == 'tree' && editable == 'True')) {
+            editRecord(src_record);
+        }
+    }
+};
 
-MochiKit.DOM.addLoadEvent(function(evt){
-	row_edit(evt);
+MochiKit.DOM.addLoadEvent(function(evt) {
+    row_edit(evt);
 });
-
-// vim: ts=4 sts=4 sw=4 si et
-

=== removed file 'addons/openerp/static/javascript/menubar.js'
--- addons/openerp/static/javascript/menubar.js	2010-04-06 09:51:49 +0000
+++ addons/openerp/static/javascript/menubar.js	1970-01-01 00:00:00 +0000
@@ -1,29 +0,0 @@
-/**
- * Allowable width for the left-hand menu (for the current application)
- */
-var MENU_WIDTH = 250;
-/**
- * Tries to fit the size of the #appFrame frame to better fit its current
- * content.extend
- * Has to be called from the document outside of the frame itself.
- *
- * Probably won't get it exactly right, you might want to call it
- * several times
- */
-function adjustAppFrame() {
-    var frameHeight = jQuery("#appFrame").contents().find("body").height();
-    var frameWidth = jQuery("#appFrame").contents().width();
-
-    jQuery("#menubar").width(MENU_WIDTH);
-    jQuery("#appFrame").height(Math.max(0, frameHeight));
-
-    var menuWidth = jQuery("#menubar").height();
-    var windowWidth = jQuery(window).width();
-    var totalWidth = jQuery("#menubar").width() + frameWidth;
-    var rw = windowWidth - jQuery("#menubar").width();
-
-    var newWidth = totalWidth > windowWidth ? frameWidth : rw - 16;
-
-    jQuery("#appFrame").width(Math.max(0, newWidth));
-    jQuery("table#contents").height(Math.max(frameHeight, menuWidth));
-}

=== modified file 'addons/openerp/static/javascript/notebook/notebook.js'
--- addons/openerp/static/javascript/notebook/notebook.js	2010-04-06 09:51:49 +0000
+++ addons/openerp/static/javascript/notebook/notebook.js	2010-04-08 09:53:18 +0000
@@ -27,6 +27,22 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 
+/**
+ *
+ * @event show triggered when a tab of the notebook is displayed
+ *  @argument notebook the notebook instance this
+ *                     event was triggered from
+ *  @argument tab the (DOM element) tab being showed
+ * @event hide triggered when a tab of the notebook is hidden
+ *  @arguments 'see show'
+ * @event activate triggered when a tab is set as the active tab
+ *  @arguments 'see show'
+ * @event remove triggered when a tab is removed from the notebook
+ *  @arguments 'see show'
+ * @event click triggered when the notebook's tab bar is clicked
+ *  @arguments 'see show'
+ *
+ */
 var Notebook = function(element, options) {
 
     var cls = arguments.callee;

=== modified file 'addons/openerp/static/javascript/openerp/openerp.ui.textarea.js'
--- addons/openerp/static/javascript/openerp/openerp.ui.textarea.js	2010-04-06 09:51:49 +0000
+++ addons/openerp/static/javascript/openerp/openerp.ui.textarea.js	2010-04-08 09:53:18 +0000
@@ -32,55 +32,59 @@
     throw "openerp.ui is required by 'openerp.ui.textarea'.";
 }
 
-openerp.ui.TextArea = function(ta){
+/**
+ * @event onresize triggered when the widget's grip is moved (to resize the text area)
+ *  @parameter 'the TextArea instance'
+ */
+openerp.ui.TextArea = function(ta) {
     this.__init__(ta);
-}
+};
 
 openerp.ui.TextArea.prototype = {
-    
-    __init__ : function(ta){
+
+    __init__ : function(ta) {
         this.textarea = openobject.dom.get(ta);
         this.gripper = DIV({'class' : 'grip'});
-        
+
         this.ta = this.textarea.cloneNode(true);
-        
-        MochiKit.DOM.swapDOM(this.textarea, DIV({'class' : 'resizable-textarea'}, this.ta, this.gripper));
-        
-        this.textarea = openobject.dom.get(this.ta);        
+
+        MochiKit.DOM.swapDOM(this.textarea,
+                DIV({'class' : 'resizable-textarea'},
+                    this.ta, this.gripper)).textarea = this;
+
+        this.textarea = openobject.dom.get(this.ta);
         this.draggin = false;
-        
+
         this.evtMouseDn = MochiKit.Signal.connect(this.gripper, 'onmousedown', this, "dragStart");
     },
-    
-    __delete__ : function(){
+
+    __delete__ : function() {
         MochiKit.Signal.disconnect(this.evtMouseDn);
     },
-    
-    dragStart : function(evt){
-        
-        if (!evt.mouse().button.left) 
+
+    dragStart : function(evt) {
+        if (!evt.mouse().button.left) {
             return;
+        }
 
         this.offset = openobject.dom.height(this.textarea) - evt.mouse().page.y;
-        
+
         this.evtMouseMv = MochiKit.Signal.connect(document, 'onmousemove', this, "dragUpdate");
         this.evtMouseUp = MochiKit.Signal.connect(document, 'onmouseup', this, "dragStop");
     },
-    
-    dragUpdate : function(evt){
+
+    dragUpdate : function(evt) {
         var h = Math.max(32, this.offset + evt.mouse().page.y);
         this.textarea.style.height = h + 'px';
-	evt.stop();
+        MochiKit.Signal.signal(this, 'onresize', this);
+        evt.stop();
     },
-    
-    dragStop : function(evt){
+
+    dragStop : function(evt) {
         //MochiKit.Signal.disconnect(this.evtMouseMv);
         //MochiKit.Signal.disconnect(this.evtMouseUp);
         MochiKit.Signal.disconnectAll(document, 'onmousemove', this, "dragUpdate");
         MochiKit.Signal.disconnectAll(document, 'onmouseup', this, "dragStop");
-	evt.stop();
+        evt.stop();
     }
-}
-
-// vim: ts=4 sts=4 sw=4 si et
-
+};

=== modified file 'addons/openerp/static/javascript/search.js'
--- addons/openerp/static/javascript/search.js	2010-04-06 11:03:33 +0000
+++ addons/openerp/static/javascript/search.js	2010-04-08 09:53:18 +0000
@@ -26,363 +26,380 @@
 // You can see the MPL licence at: http://www.mozilla.org/MPL/MPL-1.1.html
 //
 ////////////////////////////////////////////////////////////////////////////////
-
-var add_filter_row = function() {
-	
-	var filter_table = $('filter_table');
-	var vals = [];
-	var row_id = 1;
-	
-	var first_row = $('filter_row/0');
-	var trs = MochiKit.DOM.getElementsByTagAndClassName('tr', null, filter_table)
-	
-	if (filter_table.style.display == 'none') {
-		filter_table.style.display = '';
-	}
-	
-	else if (first_row.style.display == 'none' && trs.length <= 1) {
-		MochiKit.DOM.getFirstElementByTagAndClassName('select', 'filter_fields', first_row).selectedIndex = 0;
-		MochiKit.DOM.getFirstElementByTagAndClassName('select', 'expr', first_row).selectedIndex = 0;
-		var old_qstring = MochiKit.DOM.getFirstElementByTagAndClassName('input', 'qstring', first_row);
-		old_qstring.value = '';
-		old_qstring.style.background = '#FFFFFF';
-		first_row.style.display = ''
-	}
-	
-	else{
-		
-		var old_tr = trs[trs.length-1]
-		var old_qstring = MochiKit.DOM.getFirstElementByTagAndClassName('input', 'qstring', old_tr);
-		old_qstring.style.background = '#FFFFFF';
-		
-		var new_tr = old_tr.cloneNode(true);
-		keys = new_tr.id.split('/');
-		id = parseInt(keys[1], 0);
-		row_id = id + row_id
-		new_tr.id =  keys[0] +'/'+ row_id;
-		var filter_column = MochiKit.DOM.getFirstElementByTagAndClassName('td', 'filter_column', new_tr);
-		
-		var filter_fields = MochiKit.DOM.getFirstElementByTagAndClassName('select', 'filter_fields', new_tr);
-		var expr = MochiKit.DOM.getFirstElementByTagAndClassName('select', 'expr', new_tr);
-		var qstring = MochiKit.DOM.getFirstElementByTagAndClassName('input', 'qstring', new_tr);
-		
-		filter_column.id = filter_column.id.split('/')[0] + '/' + row_id;
-		filter_fields.id = filter_fields.id.split('/')[0] + '/' + row_id;
-		expr.id = expr.id.split('/')[0] + '/' + row_id;
-		qstring.id = qstring.id.split('/')[0] + '/' + row_id;
-		qstring.style.background = '#FFFFFF';
-		qstring.value = '';
-		
-		var image_col = MochiKit.DOM.getFirstElementByTagAndClassName('td', 'image_col', new_tr);
-		image_col.id = 'image_col/' + row_id
-		
-		var and_or = MochiKit.DOM.getFirstElementByTagAndClassName('td', 'and_or', new_tr);
-		if (and_or){removeElement(and_or); }
-		
-		var and_or = MochiKit.DOM.createDOM('td');
-		and_or.id = 'and_or/' + id;
-		and_or.className = 'and_or';
-		
-		var select_andor = MochiKit.DOM.createDOM('select');
-		select_andor.id = 'select_andor/' + id;
-		select_andor.className = 'select_andor';
-		
-		var option = MochiKit.DOM.createDOM('option');
-		
-		vals.push('AND');
-		vals.push('OR');
-		
-		option = map(function(x){return OPTION({'value': x}, x)}, vals);
-		image_replace = openobject.dom.get('image_col/'+ id);
-		if(MochiKit.DOM.getFirstElementByTagAndClassName('td', 'and_or', old_tr) == null){
-			insertSiblingNodesBefore(image_replace, and_or)
-		}
-		
-		appendChildNodes(select_andor, option);
-		appendChildNodes(and_or, select_andor);
-		insertSiblingNodesAfter(old_tr, new_tr);
-	}
+/**
+ * @event onaddfilter triggered when adding a filter row
+ *  @target #filter_table the element holding the filter rows
+ *  @argument 'the newly added (or showed for first row?) filter row'
+ */
+function add_filter_row() {
+    var filter_table = $('filter_table');
+    var vals = [];
+    var row_id = 1;
+
+    var first_row = $('filter_row/0');
+    var trs = MochiKit.DOM.getElementsByTagAndClassName('tr', null, filter_table);
+    var old_qstring;
+
+    if (filter_table.style.display == 'none') {
+        filter_table.style.display = '';
+    } else if (first_row.style.display == 'none' && trs.length <= 1) {
+        MochiKit.DOM.getFirstElementByTagAndClassName('select', 'filter_fields', first_row).selectedIndex = 0;
+        MochiKit.DOM.getFirstElementByTagAndClassName('select', 'expr', first_row).selectedIndex = 0;
+        old_qstring = MochiKit.DOM.getFirstElementByTagAndClassName('input', 'qstring', first_row);
+        old_qstring.value = '';
+        old_qstring.style.background = '#FFFFFF';
+        first_row.style.display = ''
+    } else {
+        var old_tr = trs[trs.length - 1];
+        old_qstring = MochiKit.DOM.getFirstElementByTagAndClassName('input', 'qstring', old_tr);
+        old_qstring.style.background = '#FFFFFF';
+
+        var new_tr = old_tr.cloneNode(true);
+        keys = new_tr.id.split('/');
+        id = parseInt(keys[1], 0);
+		row_id = id + row_id;
+
+        new_tr.id = keys[0] + '/' + row_id;
+        var filter_column = MochiKit.DOM.getFirstElementByTagAndClassName('td', 'filter_column', new_tr);
+
+        var filter_fields = MochiKit.DOM.getFirstElementByTagAndClassName('select', 'filter_fields', new_tr);
+        var expr = MochiKit.DOM.getFirstElementByTagAndClassName('select', 'expr', new_tr);
+        var qstring = MochiKit.DOM.getFirstElementByTagAndClassName('input', 'qstring', new_tr);
+
+        filter_column.id = filter_column.id.split('/')[0] + '/' + row_id;
+        filter_fields.id = filter_fields.id.split('/')[0] + '/' + row_id;
+        expr.id = expr.id.split('/')[0] + '/' + row_id;
+        qstring.id = qstring.id.split('/')[0] + '/' + row_id;
+        qstring.style.background = '#FFFFFF';
+        qstring.value = '';
+
+        var image_col = MochiKit.DOM.getFirstElementByTagAndClassName('td', 'image_col', new_tr);
+        image_col.id = 'image_col/' + row_id;
+
+        var old_and_or = MochiKit.DOM.getFirstElementByTagAndClassName('td', 'and_or', new_tr);
+        if (old_and_or) {
+            removeElement(old_and_or);
+        }
+
+        var and_or = MochiKit.DOM.createDOM('td');
+        and_or.id = 'and_or/' + id;
+        and_or.className = 'and_or';
+
+        var select_andor = MochiKit.DOM.createDOM('select');
+        select_andor.id = 'select_andor/' + id;
+        select_andor.className = 'select_andor';
+
+        var option = MochiKit.DOM.createDOM('option');
+
+        vals.push('AND');
+        vals.push('OR');
+
+        var options = map(function(x) {
+            return OPTION({'value': x}, x)
+        }, vals);
+        image_replace = openobject.dom.get('image_col/' + id);
+        if (MochiKit.DOM.getFirstElementByTagAndClassName('td', 'and_or', old_tr) == null) {
+            insertSiblingNodesBefore(image_replace, and_or)
+        }
+
+        appendChildNodes(select_andor, options);
+        appendChildNodes(and_or, select_andor);
+        insertSiblingNodesAfter(old_tr, new_tr);
+    }
+    MochiKit.Signal.signal(filter_table, 'onaddfilter', new_tr || first_row);
 }
 
-var remove_row = function(id) {
-	
-	var filter_table = $('filter_table');
-	
-	node = MochiKit.DOM.getFirstParentByTagAndClassName(id, 'tr', 'filter_row_class');
-	
-	if (node.id != 'filter_row/0') {
-		removeElement(node);
-	}
-	else {
-		node.style.display = 'none';
-		if ($('and_or/0'))
-			removeElement($('and_or/0'));
-		$('qstring/0').value = '';
-		$('qstring/0').style.background = '#FFFFFF';
-	}
+/**
+ * @event onremovefilter triggered when removing a filter row
+ *  @target #filter_table the element holding the filter rows
+ *  @argument 'the removed (or hidden) filter row'
+ */
+function remove_row(id) {
+    var filter_table = $('filter_table');
+
+    var node = MochiKit.DOM.getFirstParentByTagAndClassName(id, 'tr', 'filter_row_class');
+
+    if (node.id != 'filter_row/0') {
+        removeElement(node);
+    } else {
+        node.style.display = 'none';
+        if ($('and_or/0')) {
+            removeElement($('and_or/0'));
+        }
+        $('qstring/0').value = '';
+        $('qstring/0').style.background = '#FFFFFF';
+    }
+    MochiKit.Signal.signal(filter_table, 'onremovefilter', node);
 }
 // Direct click on icon.
-var search_image_filter = function(src, id) {
-	domain = getNodeAttribute(id, 'value');
-	search_filter(src);
+function search_image_filter(src, id) {
+    domain = getNodeAttribute(id, 'value');
+    search_filter(src);
 }
 
-var onKey_Event = function(evt) {
-	
-	dom = $('search_filter_data');
-	
-	var editors = [];
-	
-	editors = editors.concat(getElementsByTagAndClassName('input', null, dom));
-    editors = editors.concat(getElementsByTagAndClassName('select', null, dom));
-    editors = editors.concat(getElementsByTagAndClassName('textarea', null, dom));
-    
-    var editors = filter(function(e){
+function onKey_Event() {
+    var search_filter = $('search_filter_data');
+
+    var editors = [];
+
+    editors = editors.concat(getElementsByTagAndClassName('input', null, search_filter));
+    editors = editors.concat(getElementsByTagAndClassName('select', null, search_filter));
+    editors = editors.concat(getElementsByTagAndClassName('textarea', null, search_filter));
+
+    var active_editors = filter(function(e) {
         return e.type != 'hidden' && !e.disabled
     }, editors);
 
-    forEach(editors, function(e){
-        connect(e, 'onkeydown', self, onKeyDown_search);
-    });
-}
-
-var onKeyDown_search = function(evt) {
-	var key = evt.key();
-    var src = evt.src();
-    
-    if (key.string == "KEY_ENTER"){
-    	search_filter();
-    }
-}
-
-var search_filter = function(src, id) {
-	all_domains = {};
-	check_domain = 'None';
-	domains = {};
-	search_context = {};
-	var group_by_ctx = [];
-	
-	domain = 'None';
-	if(src) {
-		if(src.checked==false) {
-			src.checked = true
-			id.className = 'active_filter';
-		}
-		else {
-			src.checked = false
-			id.className = 'inactive_filter';
-		}
-	}
-	var filter_table = $('filter_table');
-	datas = $$('[name]', 'search_filter_data');
-	
-	forEach(datas, function(d) {
-		if (d.type != 'checkbox' && d.name && d.value && d.name.indexOf('_terp_') == -1  && d.name != 'filter_list') {
-			value = d.value;
-			if (getNodeAttribute(d, 'kind') == 'selection') {
-				value = parseInt(d.value);
-				if(getNodeAttribute(d, 'search_context')) {
-					search_context['context'] = getNodeAttribute(d, 'search_context');
-					search_context['value'] = value;
-				}
-			}
-			domains[d.name] = value;
-		}
-	});
-	
-	domains = serializeJSON(domains);
-	all_domains['domains'] = domains;
-	all_domains['search_context'] =  search_context;
-	selected_boxes = getElementsByTagAndClassName('input', 'grid-domain-selector');
-	
-	all_boxes = [];
-	
-	forEach(selected_boxes, function(box){
-		if (box.id && box.checked && box.value != '[]') {
-			all_boxes = all_boxes.concat(box.value);
-		}
-		if (box.id && box.checked && getNodeAttribute(box, 'group_by_ctx').length > 0) {
-    		group = getNodeAttribute(box, 'group_by_ctx');
-    		group_by_ctx = group_by_ctx.concat(group);
-		}
-	});
-	
-	openobject.dom.get('_terp_group_by_ctx').value = group_by_ctx;
-	
-	checked_button = all_boxes.toString();
-	
-	if (checked_button.length > 0) {
-		check_domain = checked_button.replace(/(]\,\[)/g, ', ');
-	}
-	else {
-		check_domain = 'None';
-	}
-	
-	all_domains['check_domain'] = check_domain;
-	
-	var selection_domain = $('filter_list').value;
-	
-	if (selection_domain) {
-		all_domains['selection_domain'] = selection_domain;
-	}
-	
-	if(openobject.dom.get('_terp_filter_domain').value != '[]') {
-		
-		var params = {};
-		var record = {};
-		
-		filter_table.style.display = ''
-		
-		children = MochiKit.DOM.getElementsByTagAndClassName('tr', 'filter_row_class', filter_table);
-		forEach(children, function(ch){
-			
-			var ids = ch['id'];	// row id...
-			var id = ids.split('/')[1];
-			var qid = 'qstring/' + id;
-			var fid = 'filter_fields/' + id;
-			var eid = 'expr/' + id;
-			if ($(qid) && $(qid).value) {
-				var rec = {};
-				rec[$(fid).value] = $(qid).value;
-				params['_terp_model'] = openobject.dom.get('_terp_model').value;
-			}
-			if (rec) {
-				record[ids] = rec;
-			}
-		});
-		
-		record = serializeJSON(record);
-		params['record'] = record;
-		
-		var search_req = openobject.http.postJSON('/search/get', params);
-
-		var custom_domain = [];
-		search_req.addCallback(function(obj){
-			if (obj.error) {
-				forEach(children, function(child){
-					var cids = child['id']
-					var id = cids.split('/')[1];
-					var fid = 'filter_fields/' + id;
-					if ($(fid).value == obj.error_field) {
-						f = fid.split('/')[1];
-						$('qstring/'+f).style.background = '#FF6666';
-						$('qstring/'+f).value = obj.error;
-					}
-				});
-			}
-			if (obj.frm) {
-    			for (var i in obj.frm) {
-    				var temp_domain = [];
-    				var operator = 'None';
-    				
-    				row_id = serializeJSON(i);
-					id = row_id.split('/')[1];
-					id = parseInt(id, 10);
-					
-					var fid = 'filter_fields/' + id;
-					var eid = 'expr/' + id;
-					var select_andor = 'select_andor/' + id;
-					var type = obj.frm[i].type;
-					if($(select_andor)){
-						if ($(select_andor).value == 'AND') {
-							var operator = '&';
-						}
-						else {
-							var operator = '|';
-						}
-					}  				
-    				if (operator != 'None') {
-    					temp_domain.push(operator);
-    				}
-    				
-    				var first_text = obj.frm[i].rec;
-    				var expression = $(eid).value;
-    				var right_text = obj.frm[i].rec_val;
-    				if (expression=='ilike'||expression=='not ilike'){
-    					if (type=='integer'||type=='float'||type=='date'||type=='datetime'||type=='boolean'){
-    						if (expression == 'ilike')
-    							expression = '=';
-    						else {
-    							expression = '!=';
-    						}
-    					}
-    				}
-    				if ((expression == '<' || expression == '>') && (type!='integer'||type!='float'||type!='date'||type!='datetime'||type!='boolean')){
-    					expression = '=';
-    				}
-    				if (expression == 'in' || expression == 'not in'){
-    					right_text = right_text.split(',');
-    				}
-    				
-					temp_domain.push(first_text);
-					temp_domain.push(expression);
-					temp_domain.push(right_text);
-					
-					custom_domain.push(temp_domain);
-    			}
-			}
-			custom_domain = serializeJSON(custom_domain);
-			all_domains = serializeJSON(all_domains);
-			
-			final_search_domain(custom_domain, all_domains, group_by_ctx);
-		});
-	}
-	else {
-		custom_domain = openobject.dom.get('_terp_filter_domain').value || []
-		all_domains = serializeJSON(all_domains);
-		final_search_domain(custom_domain, all_domains, group_by_ctx);	
-	}
-}
-
-var final_search_domain = function(custom_domain, all_domain, group_by_ctx) {
-	var req = openobject.http.postJSON('/search/eval_domain_filter', {source: '_terp_list',
-															model: $('_terp_model').value, 
-															custom_domain: custom_domain,
-															all_domains: all_domains,
-															group_by_ctx: group_by_ctx});
-	
-	req.addCallback(function(obj){
-		if (obj.flag) {
-			var params = {'domain': obj.sf_dom,
-							'model': openobject.dom.get('_terp_model').value,
-							'flag': obj.flag};
-			if(group_by_ctx!='')
-				params['group_by'] = group_by_ctx				
-			openobject.tools.openWindow(openobject.http.getURL('/search/save_filter', params), {width: 400, height: 250});
-		}
-		if (obj.action) { // For manage Filter
-			action = serializeJSON(obj.action);
-			window.location.href = openobject.http.getURL('/search/manage_filter', {action: action});
-		}
-		if (obj.domain) { // For direct search
-			var in_req = eval_domain_context_request({source: '_terp_list', domain: obj.domain, context: obj.context});
-
-		    in_req.addCallback(function(in_obj){
-		    	openobject.dom.get('_terp_search_domain').value = in_obj.domain;
-		    	openobject.dom.get('_terp_search_data').value = obj.search_data;
-		    	openobject.dom.get('_terp_context').value = in_obj.context;
-		    	openobject.dom.get('_terp_filter_domain').value = obj.filter_domain;
-		    	if (getElement('_terp_list') != null){
-		    		new ListView('_terp_list').reload()
-		    	}
-		    });	
-		}
-	});
-}
-
-var expand_group_option = function(id, event) {
-	if(getElement(id).style.display == '') {
-		getElement(id).style.display = 'none'
-		event.target.className = 'group-expand';
-	}
-	else {
-		getElement(id).style.display = '';
-		event.target.className = 'group-collapse';
-	}
-}
-
-MochiKit.DOM.addLoadEvent(function(evt){
-
-	onKey_Event(evt);
-	search_filter();
+    forEach(active_editors, function(e) {
+        MochiKit.Signal.connect(e, 'onkeydown', self, onKeyDown_search);
+    });
+}
+
+function onKeyDown_search(evt) {
+    if (evt.key().string == "KEY_ENTER") {
+        search_filter();
+    }
+}
+
+function search_filter(src, id) {
+    all_domains = {};
+    check_domain = 'None';
+    domains = {};
+    search_context = {};
+    var group_by_ctx = [];
+
+    domain = 'None';
+    if (src) {
+        src.checked = !src.checked;
+        id.className = src.checked ? 'active_filter' : 'inactive_filter';
+    }
+    var filter_table = $('filter_table');
+    datas = $$('[name]', 'search_filter_data');
+
+    forEach(datas, function(d) {
+        if (d.type != 'checkbox' && d.name && d.value && d.name.indexOf('_terp_') == -1 && d.name != 'filter_list') {
+            value = d.value;
+            if (getNodeAttribute(d, 'kind') == 'selection') {
+                value = parseInt(d.value);
+                if (getNodeAttribute(d, 'search_context')) {
+                    search_context['context'] = getNodeAttribute(d, 'search_context');
+                    search_context['value'] = value;
+                }
+            }
+            domains[d.name] = value;
+        }
+    });
+
+    domains = serializeJSON(domains);
+    all_domains['domains'] = domains;
+    all_domains['search_context'] = search_context;
+    selected_boxes = getElementsByTagAndClassName('input', 'grid-domain-selector');
+
+    all_boxes = [];
+
+    forEach(selected_boxes, function(box) {
+        if (box.id && box.checked && box.value != '[]') {
+            all_boxes = all_boxes.concat(box.value);
+        }
+        if (box.id && box.checked && getNodeAttribute(box, 'group_by_ctx').length > 0) {
+            group = getNodeAttribute(box, 'group_by_ctx');
+            group_by_ctx = group_by_ctx.concat(group);
+        }
+    });
+
+    openobject.dom.get('_terp_group_by_ctx').value = group_by_ctx;
+
+    checked_button = all_boxes.toString();
+
+    if (checked_button.length > 0) {
+        check_domain = checked_button.replace(/(]\,\[)/g, ', ');
+    }
+    else {
+        check_domain = 'None';
+    }
+
+    all_domains['check_domain'] = check_domain;
+
+    var selection_domain = $('filter_list').value;
+
+    if (selection_domain) {
+        all_domains['selection_domain'] = selection_domain;
+    }
+
+    if (openobject.dom.get('_terp_filter_domain').value != '[]') {
+
+        var params = {};
+        var record = {};
+
+        filter_table.style.display = '';
+
+        children = MochiKit.DOM.getElementsByTagAndClassName('tr', 'filter_row_class', filter_table);
+        forEach(children, function(ch) {
+
+            var ids = ch['id'];	// row id...
+            var id = ids.split('/')[1];
+            var qid = 'qstring/' + id;
+            var fid = 'filter_fields/' + id;
+            if ($(qid) && $(qid).value) {
+                var rec = {};
+                rec[$(fid).value] = $(qid).value;
+                params['_terp_model'] = openobject.dom.get('_terp_model').value;
+            }
+            if (rec) {
+                record[ids] = rec;
+            }
+        });
+
+        record = serializeJSON(record);
+        params['record'] = record;
+
+        var search_req = openobject.http.postJSON('/search/get', params);
+
+        var custom_domain = [];
+        search_req.addCallback(function(obj) {
+            if (obj.error) {
+                forEach(children, function(child) {
+                    var cids = child['id'];
+                    var id = cids.split('/')[1];
+                    var fid = 'filter_fields/' + id;
+                    if ($(fid).value == obj.error_field) {
+                        f = fid.split('/')[1];
+                        $('qstring/' + f).style.background = '#FF6666';
+                        $('qstring/' + f).value = obj.error;
+                    }
+                });
+            }
+            if (obj.frm) {
+                for (var i in obj.frm) {
+                    var temp_domain = [];
+                    var operator = 'None';
+
+                    row_id = serializeJSON(i);
+                    id = row_id.split('/')[1];
+                    id = parseInt(id, 10);
+
+                    var eid = 'expr/' + id;
+                    var select_andor = 'select_andor/' + id;
+                    var type = obj.frm[i].type;
+                    if ($(select_andor)) {
+                        if ($(select_andor).value == 'AND') {
+                            operator = '&';
+                        } else {
+                            operator = '|';
+                        }
+                    }
+                    if (operator != 'None') {
+                        temp_domain.push(operator);
+                    }
+
+                    var first_text = obj.frm[i].rec;
+                    var expression = $(eid).value;
+                    var right_text = obj.frm[i].rec_val;
+                    if (expression == 'ilike' || expression == 'not ilike') {
+                        if (type == 'integer' || type == 'float' || type == 'date' || type == 'datetime' || type == 'boolean') {
+                            if (expression == 'ilike') {
+                                expression = '=';
+                            } else {
+                                expression = '!=';
+                            }
+                        }
+                    }
+                    if ((expression == '<' || expression == '>') && (type != 'integer' || type != 'float' || type != 'date' || type != 'datetime' || type != 'boolean')) {
+                        expression = '=';
+                    }
+                    if (expression == 'in' || expression == 'not in') {
+                        right_text = right_text.split(',');
+                    }
+
+                    temp_domain.push(first_text);
+                    temp_domain.push(expression);
+                    temp_domain.push(right_text);
+
+                    custom_domain.push(temp_domain);
+                }
+            }
+            custom_domain = serializeJSON(custom_domain);
+            all_domains = serializeJSON(all_domains);
+
+            final_search_domain(custom_domain, all_domains, group_by_ctx);
+        });
+    } else {
+        custom_domain = openobject.dom.get('_terp_filter_domain').value || [];
+        all_domains = serializeJSON(all_domains);
+        final_search_domain(custom_domain, all_domains, group_by_ctx);
+    }
+}
+
+function final_search_domain(custom_domain, all_domain, group_by_ctx) {
+    var req = openobject.http.postJSON('/search/eval_domain_filter', {
+        source: '_terp_list',
+        model: $('_terp_model').value,
+        custom_domain: custom_domain,
+        all_domains: all_domains,
+        group_by_ctx: group_by_ctx
+    });
+
+    req.addCallback(function(obj) {
+        if (obj.flag) {
+            var params = {'domain': obj.sf_dom,
+                'model': openobject.dom.get('_terp_model').value,
+                'flag': obj.flag};
+            if (group_by_ctx != '') {
+                params['group_by'] = group_by_ctx;
+            }
+            openobject.tools.openWindow(openobject.http.getURL('/search/save_filter', params), {
+                width: 400,
+                height: 250
+            });
+        }
+        if (obj.action) { // For manage Filter
+            action = serializeJSON(obj.action);
+            window.location.href = openobject.http.getURL('/search/manage_filter', {action: action});
+        }
+        if (obj.domain) { // For direct search
+            var in_req = eval_domain_context_request({
+                source: '_terp_list',
+                domain: obj.domain,
+                context: obj.context
+            });
+
+            in_req.addCallback(function(in_obj) {
+                openobject.dom.get('_terp_search_domain').value = in_obj.domain;
+                openobject.dom.get('_terp_search_data').value = obj.search_data;
+                openobject.dom.get('_terp_context').value = in_obj.context;
+                openobject.dom.get('_terp_filter_domain').value = obj.filter_domain;
+                if (getElement('_terp_list') != null) {
+                    new ListView('_terp_list').reload()
+                }
+            });
+        }
+    });
+}
+
+/**
+ * @event groupby-toggle triggered when changing the display state of the groupby options
+ *  @target #search_filter_data the element holding the filter rows
+ *  @argument 'the action performed ("expand" or "collapse")
+ */
+function expand_group_option(id, event) {
+    var groupbyElement = getElement(id);
+    var action;
+    if (groupbyElement.style.display == '') {
+        groupbyElement.style.display = 'none';
+        event.target.className = 'group-expand';
+        action = 'collapse';
+    } else {
+        groupbyElement.style.display = '';
+        event.target.className = 'group-collapse';
+        action = 'expand';
+    }
+    MochiKit.Signal.signal(
+            $('search_filter_data'),
+            'groupby-toggle',
+            action);
+}
+
+MochiKit.DOM.addLoadEvent(function(evt) {
+    onKey_Event(evt);
+    search_filter();
 });

=== modified file 'addons/openerp/static/javascript/treegrid.js'
--- addons/openerp/static/javascript/treegrid.js	2010-04-06 09:51:49 +0000
+++ addons/openerp/static/javascript/treegrid.js	2010-04-08 09:53:18 +0000
@@ -31,22 +31,34 @@
 var KEY_ARROW_UP = 38;
 var KEY_ARROW_DOWN = 40;
 
-var TreeGrid = function(elem, options){
+/**
+ * @event treegrid-render triggered on treegrid rendering
+ *  @target document
+ *  @argument 'the treegrid instance being rendered'
+ *
+ * @event treenode-expand triggered when a sub-node is expanded
+ *  @target document
+ *  @argument 'the treenode being expanded'
+ *
+ * @event treenode-collapse triggered when a sub-node is collaped
+ *  @target document
+ *  @argument 'the treenode being collapsed'
+ */
+var TreeGrid = function(elem, options) {
     this.__init__(elem, options);
 };
 
 TreeGrid.prototype = {
     
     __init__ : function(elem, options) {
-        
         this.id = openobject.dom.get(elem).id;
         
         this.options = MochiKit.Base.update({
             'showheaders': true,
             'expandall' : false,
-            'onselect' : function(){},
-            'onbuttonclick' : function(){},
-            'onheaderclick' : function(){},
+            'onselect' : function() {},
+            'onbuttonclick' : function() {},
+            'onheaderclick' : function() {},
             'linktarget': null
         }, options || {});
         
@@ -63,39 +75,45 @@
         // references to ajax url and params
         this.ajax_url = null;
         this.ajax_params = {};
+
+        // receive some events from the treenodes and redispatch to the document
+        MochiKit.Signal.connect(this, 'onNodeExpand', function (tree, node) {
+            MochiKit.Signal.signal(window.document, 'treenode-expand', node);
+        });
+        MochiKit.Signal.connect(this, 'onNodeCollapse', function (tree, node) {
+            MochiKit.Signal.signal(window.document, 'treenode-collapse', node);
+        });
     },
     
     setHeaders : function(headers/*, params */) {
-        
         this.headers = headers;
         
-        if (typeof(headers) == 'string'){
+        if (typeof(headers) == 'string') {
             
-           var self = this;
-           var req = openobject.http.postJSON(headers, arguments[1]);
-           
-           self._ajax_counter += 1;
-           
-           req.addCallback(function(obj){
-               self.headers = obj.headers;
-           });
-           
-           req.addBoth(function(){
-               self._ajax_counter -= 1;
-           });
+            var self = this;
+            var req = openobject.http.postJSON(headers, arguments[1]);
+           
+            self._ajax_counter += 1;
+           
+            req.addCallback(function(obj) {
+                self.headers = obj.headers;
+            });
+           
+            req.addBoth(function() {
+                self._ajax_counter -= 1;
+            });
            
         }
     },
     
     setRecords : function(records/*, params */) {
-        
         if (!this.headers) {
             return;
         }
         
         this.records = records;
         
-        if (typeof(records) == 'string'){
+        if (typeof(records) == 'string') {
             
             this.ajax_url = records;
             this.ajax_params = arguments[1] || {};
@@ -108,12 +126,12 @@
            
             self._ajax_counter += 1;
            
-            req.addCallback(function(obj){
+            req.addCallback(function(obj) {
                 self.records = obj.records;
                 MochiKit.Signal.signal(self, 'onDataLoad', self, null);
             });
            
-            req.addBoth(function(obj){
+            req.addBoth(function() {
                 self._ajax_counter -= 1;
             });
            
@@ -121,8 +139,7 @@
         
     },
     
-    render : function(){
-        
+    render : function() {
         // wait till ajax calls finish
         if (this._ajax_counter > 0) {
             return MochiKit.Async.callLater(0.01, MochiKit.Base.bind(this.render, this));
@@ -141,6 +158,7 @@
         if (openobject.dom.get(this.id) != this.table) {
             MochiKit.DOM.swapDOM(this.id, this.table);
         }
+        MochiKit.Signal.signal(window.document, 'treegrid-render', this);
     },
     
     reload : function() {
@@ -153,11 +171,10 @@
         return new TreeNode(this, record);  
     },
     
-    _makeHeader : function(){
-        
+    _makeHeader : function() {
         var tr = MochiKit.DOM.TR({'class':'header'});
     
-        for(var i in this.headers){
+        for (var i in this.headers) {
             
             var header = this.headers[i];
             var th = MochiKit.DOM.TH(null, header.string);
@@ -167,9 +184,9 @@
             MochiKit.DOM.setNodeAttribute(th, 'width', header.width);
             MochiKit.DOM.setNodeAttribute(th, 'align', header.align);
             
-            if (this.options.onheaderclick){
-               th.onclick = MochiKit.Base.bind(MochiKit.Base.partial(this._onHeaderClick, header), this);
-               th.style.cursor = 'pointer';
+            if (this.options.onheaderclick) {
+                th.onclick = MochiKit.Base.bind(MochiKit.Base.partial(this._onHeaderClick, header), this);
+                th.style.cursor = 'pointer';
             }
             
             header.tree = this;
@@ -191,7 +208,6 @@
     },
     
     copy: function(elem, options, ids) {
-    
         var tree = new TreeGrid(elem, options);
         MochiKit.Base.update(tree.options, this.options);
         
@@ -247,7 +263,7 @@
     __delete__ : function() {
         
 
-        while(this.childNodes.length > 0) {
+        while (this.childNodes.length > 0) {
             this.childNodes[0].__delete__();
         }
         
@@ -258,14 +274,14 @@
         var pn = this.parentNode;
         var idx = MochiKit.Base.findIdentical(pn.childNodes, this);
         
-        pn.childNodes.splice(idx,1);
+        pn.childNodes.splice(idx, 1);
         
         if (pn.firsChild == this) {
             pn.firstChild = pn.childNodes[0] || null;
         }
         
         if (pn.lastChild == this) {
-            pn.lastChild = pn.childNodes[pn.childNodes.length-1] || null;
+            pn.lastChild = pn.childNodes[pn.childNodes.length - 1] || null;
         }
         
         if (this.previousSibling) {
@@ -276,7 +292,7 @@
             this.nextSibling.previousSibling = this.previousSibling;
         }
         
-        this.tree.selection.splice(MochiKit.Base.findIdentical(this.tree.selection, this),1);
+        this.tree.selection.splice(MochiKit.Base.findIdentical(this.tree.selection, this), 1);
         this.tree.selection_last = this.selection_last == this ? null : this.selection_last;
         
         var table = this.tree.table;
@@ -295,7 +311,7 @@
         }
     },
     
-    __repr__ : function(){
+    __repr__ : function() {
         return '<TreeNode ' + this.name + '>';
     },
     
@@ -307,7 +323,7 @@
         var indent = this.getPath().length - 1;
 
         var len = this.tree.headers.length;
-        for (var i=0; i<len; ++i) {            
+        for (var i = 0; i < len; ++i) {
             var header = this.tree.headers[i];
             
             var key = header.name;
@@ -345,9 +361,9 @@
                     MochiKit.Signal.connect(value, 'onclick', function (e) {
                         MochiKit.Signal.signal(e.src().tree, "onaction", e.src());
                         var frame = jQuery('#appFrame');
-                        if(frame.contentWindow) {
+                        if (frame.contentWindow) {
                             frame.contentWindow.location.replace(record.action);
-                        } else if(frame.contentDocument) {
+                        } else if (frame.contentDocument) {
                             frame.contentDocument.location.replace(record.action);
                         } else {
                             // just in case there's still a browser needing DOM0 frames
@@ -416,34 +432,34 @@
         
         MochiKit.Base.update(this.record, record || {});
         
-        var record = this.record;
+        var current_record = this.record;
 
-        for (var i in this.tree.headers){
+        for (var i in this.tree.headers) {
             
             var header = this.tree.headers[i];
             
             var key = header.name;
-            var value = record.items[key];
+            var value = current_record.items[key];
             
             var td = this.element.cells[i];
             
             if (i == 0) { // first column                
                 
-                if (record.icon && this.element_i) {
-                    this.element_i.src = record.icon;
+                if (current_record.icon && this.element_i) {
+                    this.element_i.src = current_record.icon;
                 }
                 
                 this.element_a.innerHTML = MochiKit.DOM.escapeHTML(value);
                 
-                if (record.action) {
-                    MochiKit.DOM.setNodeAttribute(this.element_a, 'href', openobject.http.getURL(record.action));
-                }
-                
-                if (record.target) {
-                    MochiKit.DOM.setNodeAttribute(this.element_a, 'target', openobject.http.getURL(record.target));
-                }
-                
-                if(record.required) {
+                if (current_record.action) {
+                    MochiKit.DOM.setNodeAttribute(this.element_a, 'href', openobject.http.getURL(current_record.action));
+                }
+                
+                if (current_record.target) {
+                    MochiKit.DOM.setNodeAttribute(this.element_a, 'target', openobject.http.getURL(current_record.target));
+                }
+                
+                if (current_record.required) {
                     MochiKit.DOM.setNodeAttribute(this.element_a, 'class', 'requiredfield');
                 }
 
@@ -455,7 +471,7 @@
                     case 'email':
                         var link = openobject.dom.select('a', td)[0];
                         MochiKit.DOM.setNodeAttribute(link, 'href', value);
-                        MochiKit.DOM.setNodeAttribute(link, 'target', record.target || '_blank');
+                        MochiKit.DOM.setNodeAttribute(link, 'target', current_record.target || '_blank');
 
                         link.innerHTML = MochiKit.DOM.escapeHTML(value);
                         break;
@@ -482,7 +498,7 @@
             case KEY_ARROW_LEFT:
                 if (this.expanded) {
                     this.collapse();
-                } else if (this.parentNode.element){
+                } else if (this.parentNode.element) {
                     this.parentNode.onSelect(evt);
                 }
                 return evt.stop();
@@ -496,7 +512,7 @@
                 return evt.stop();
 
             case KEY_ARROW_UP:
-                visible_nodes = MochiKit.Base.filter(function(node){
+                visible_nodes = MochiKit.Base.filter(function(node) {
                     return node.element && "none" != node.element.style.display;
                 }, this.tree.rootNode.getAllChildren());
 
@@ -509,11 +525,11 @@
                 return evt.stop();
             
             case KEY_ARROW_DOWN:
-                visible_nodes = MochiKit.Base.filter(function(node){
+                visible_nodes = MochiKit.Base.filter(function(node) {
                     return node.element && "none" != node.element.style.display;
                 }, this.tree.rootNode.getAllChildren());
                 
-                visible_nodes = visible_nodes.slice(MochiKit.Base.findIdentical(visible_nodes, this)+1);
+                visible_nodes = visible_nodes.slice(MochiKit.Base.findIdentical(visible_nodes, this) + 1);
 
                 if (visible_nodes.length > 0) {
                     visible_nodes[0].onSelect(evt);
@@ -535,12 +551,11 @@
         
         var trg = evt ? evt.target() : this.element;
     
-        if (MochiKit.Base.findValue(['collapse', 'expand', 'loading'], trg.className) > -1){
+        if (MochiKit.Base.findValue(['collapse', 'expand', 'loading'], trg.className) > -1) {
             return;
         }
         
         var tree = this.tree;
-        var src = this.element;
         
         var ctr = evt ? evt.modifier().ctrl : null;
         var sft = evt ? evt.modifier().shift : null;
@@ -549,12 +564,12 @@
             this.element_a.focus();
         }
         
-        forEach(tree.selection, function(node){
+        forEach(tree.selection, function(node) {
             MochiKit.DOM.removeElementClass(node.element, "selected");
         });
     
         if (ctr) {
-            if (MochiKit.Base.findIdentical(tree.selection, this) == -1){
+            if (MochiKit.Base.findIdentical(tree.selection, this) == -1) {
                 tree.selection.push(this);
             } else {
                 tree.selection.splice(MochiKit.Base.findIdentical(tree.selection, this), 1);
@@ -562,7 +577,7 @@
         } else if (sft) {
     
             var nodes = tree.rootNode.getAllChildren();
-            nodes = MochiKit.Base.filter(function(node){
+            nodes = MochiKit.Base.filter(function(node) {
                 return node.element.style.display != 'none';
             }, nodes);
     
@@ -572,17 +587,17 @@
             var begin = MochiKit.Base.findIdentical(nodes, this);
             var end = MochiKit.Base.findIdentical(nodes, last);
     
-            tree.selection = begin > end ? nodes.slice(end, begin+1) : nodes.slice(begin, end+1);
+            tree.selection = begin > end ? nodes.slice(end, begin + 1) : nodes.slice(begin, end + 1);
     
         } else {
             tree.selection = [this];
         }
     
-        if (!sft){
-            tree.selection_last = tree.selection[tree.selection.length-1];
+        if (!sft) {
+            tree.selection_last = tree.selection[tree.selection.length - 1];
         }
     
-        forEach(tree.selection, function(node){
+        forEach(tree.selection, function(node) {
             MochiKit.DOM.addElementClass(node.element, "selected");
         });
         
@@ -604,7 +619,7 @@
         
         var result = [];
         
-        forEach(this.childNodes, function(n){
+        forEach(this.childNodes, function(n) {
             result = result.concat(n);
             result = result.concat(n.getAllChildren());
         });
@@ -629,21 +644,23 @@
     },
     
     _loadChildNodes : function(/* optional */expandall) {
-        
-        if (this._ajax_counter > 0) 
-          return;
+        if (this._ajax_counter > 0) {
+            return;
+        }
         
         var self = this;
         
         function _makeChildNodes(records) {
             
-            MochiKit.Iter.forEach(records, function(record){
+            MochiKit.Iter.forEach(records, function(record) {
                 self.appendChild(self.tree.createNode(record));
             });
             
-            if (!expandall) { return; }
+            if (!expandall) {
+                return;
+            }
             
-            forEach(self.childNodes, function(child){
+            forEach(self.childNodes, function(child) {
                 child.expand(expandall);
             });
         }
@@ -665,13 +682,13 @@
            
             this.setState('loading');
            
-            req.addCallback(function(obj){
+            req.addCallback(function(obj) {
                 _makeChildNodes(obj.records);
                 MochiKit.Signal.signal(self.tree, 'onDataLoad', self.tree, self);
                 MochiKit.Signal.signal(self.tree, 'onNodeExpand', self.tree, self);
             });
            
-            req.addBoth(function(obj){
+            req.addBoth(function(obj) {
                 self.tree._ajax_counter -= 1;
                 self.setState('collapse');
             });
@@ -733,7 +750,8 @@
             return;
         }
 
-        var span = this.element.getElementsByTagName('span'); span = span[span.length-1];
+        var span = this.element.getElementsByTagName('span');
+        span = span[span.length - 1];
         MochiKit.DOM.setNodeAttribute(span, 'class', state);
     },
     

=== modified file 'openobject/static/javascript/openobject/openobject.base.js'
--- openobject/static/javascript/openobject/openobject.base.js	2010-04-06 09:51:49 +0000
+++ openobject/static/javascript/openobject/openobject.base.js	2010-04-08 09:53:18 +0000
@@ -31,67 +31,66 @@
     throw "MochiKit is required.";
 }
 
+var openobject;
 if (typeof(openobject) == "undefined") {
-    window.openobject = openobject = {};
+    openobject = {};
+    window.openobject = openobject;
 }
 
 openobject.base = {
-
     filter: function(items, callback, instance) {
         if (instance) {
             callback = MochiKit.Base.bind(callback, instance);
         }
         return MochiKit.Base.filter(callback, items);
     },
-    
+
     map: function(items, callback, instance) {
         if (instance) {
             callback = MochiKit.Base.bind(callback, instance);
         }
         return MochiKit.Base.map(callback, items);
     },
-    
+
     each: function(items, callback, instance) {
         return MochiKit.Iter.forEach(items, callback, instance);
     },
-    
+
     find: function(items, value, start, end) {
         return MochiKit.Base.findIdentical(items, value, start, end);
     }
-    
-}
+};
 
 // browser information
 openobject.browser = {
-
     // Internet Explorer
     isIE: /msie/.test(navigator.userAgent.toLowerCase()),
-    
+
     // Internet Explorer 6
     isIE6: /msie 6/.test(navigator.userAgent.toLowerCase()),
-    
+
     // Internet Explorer 7
     isIE7: /msie 7/.test(navigator.userAgent.toLowerCase()),
-    
+
     // Gecko(Mozilla) derived
     isGecko: /gecko\//.test(navigator.userAgent.toLowerCase()),
-    
+
     isGecko18: /rv:1.9.*gecko\//.test(navigator.userAgent.toLowerCase()),
-        
+
     isGecko19: /rv:1.9.*gecko\//.test(navigator.userAgent.toLowerCase()),
-    
+
     // Apple WebKit derived
     isWebKit: /webkit/.test(navigator.userAgent.toLowerCase()),
 
     // Opera
     isOpera: /opera/.test(navigator.userAgent.toLowerCase())
-}
-
-window.browser = openobject.browser
-
-// hack to prevent cross-domain secutiry errors, if window is opened 
+};
+
+window.browser = openobject.browser;
+
+// hack to prevent cross-domain security errors, if window is opened
 // from different domain.
-MochiKit.DOM.addLoadEvent(function(evt){
+MochiKit.DOM.addLoadEvent(function() {
     try {
         window.opener.document.domain;
     } catch (e) {
@@ -99,6 +98,89 @@
     }
 });
 
-
-// vim: ts=4 sts=4 sw=4 si et
-
+var MENU_WIDTH = 250;
+/**
+ * Tries to fit the size of the #appFrame frame to better fit its current
+ * content.extend
+ * Has to be called from the document outside of the frame itself.
+ *
+ * Probably won't get it exactly right, you might want to call it
+ * several times
+ */
+function adjustAppFrame() {
+    var frameHeight = jQuery("#appFrame").contents().find("body").height();
+    var frameWidth = jQuery("#appFrame").contents().width();
+
+    jQuery("#menubar").width(MENU_WIDTH);
+    jQuery("#appFrame").height(Math.max(0, frameHeight));
+
+    var menuWidth = jQuery("#menubar").height();
+    var windowWidth = jQuery(window).width();
+    var totalWidth = jQuery("#menubar").width() + frameWidth;
+    var rw = windowWidth - jQuery("#menubar").width();
+
+    var newWidth = totalWidth > windowWidth ? frameWidth : rw - 16;
+
+    jQuery("#appFrame").width(Math.max(0, newWidth));
+    jQuery("table#contents").height(Math.max(frameHeight, menuWidth));
+}
+function adjust(count) {
+    if (!count) {
+        count = 0;
+    }
+    if (count < 3) {
+        try {
+            adjustAppFrame();
+        } catch (e) {
+            // don't do anything when adjustment blows up.
+        }
+        setTimeout(adjust, 10, count + 1);
+    }
+}
+if (window !== window.parent) {
+    MochiKit.DOM.addLoadEvent(function () {
+        // Gecko blows up if we try to directly call window.parent.adjust()
+        // and cross-frame events don't seem to work either
+        // so use intermediate function.
+        var do_adjust = function () {
+            window.parent.adjust();
+        };
+        setTimeout(do_adjust, 10);
+        // bind on all modifying events of notebooks
+        forEach($$('.notebook'), function (notebook_element) {
+            forEach(['remove', 'show', 'hide', 'activate', 'click'], function (event) {
+                MochiKit.Signal.connect(notebook_element.notebook,
+                        event, do_adjust);
+            });
+        });
+        // bind to resize event of text area
+        forEach($$('.resizable-textarea'), function (textarea_element) {
+            MochiKit.Signal.connect(textarea_element.textarea, 'onresize', do_adjust);
+        });
+        // bind to alterations of the list views
+        forEach($$('.gridview'), function (listview_element) {
+            var name = listview_element.getAttribute('id');
+            MochiKit.Signal.connect(ListView(name), 'onreload', do_adjust);
+        });
+        // bind to addition and removal of filter rows in search widget
+        var filter_table = $('filter_table');
+        if (filter_table) {
+            MochiKit.Signal.connect(filter_table, 'onaddfilter',
+                                    do_adjust);
+            MochiKit.Signal.connect(filter_table, 'onremovefilter',
+                                    do_adjust);
+        }
+        // bind to change of the groupby display state in search widget
+        var search_filter = $('search_filter_data');
+        if(search_filter) {
+            MochiKit.Signal.connect(search_filter, 'groupby-toggle',
+                                    do_adjust);
+        }
+        // bind to changes to treegrids and treenodes
+        MochiKit.Signal.connect(window.document, 'treegrid-render', do_adjust);
+        MochiKit.Signal.connect(window.document, 'treenode-expand', do_adjust);
+        MochiKit.Signal.connect(window.document, 'treenode-collapse', do_adjust);
+        // bind to "onchange" attributes on view/form fields, maybe
+        MochiKit.Signal.connect(window.document, 'onfieldchange', do_adjust);
+    });
+}


Follow ups