~unifield-team/unifield-web/uf-2235

« back to all changes in this revision

Viewing changes to addons/openerp/static/javascript/form_state.js

  • Committer: jf
  • Date: 2013-05-24 16:03:21 UTC
  • mfrom: (4708.1.2 unifield-web)
  • Revision ID: jfb@tempo-consulting.fr-20130524160321-an28w20b8lsl3vq1
UF-748 [FIX] js performance
OEB-101 [FIX] exponential call to form_onAttrChange
lp:~unifield-team/unifield-web/web-UF-748

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
    }
56
56
}
57
57
 
 
58
function list_hookStateChange(list_name) {
 
59
    var fields = {};
 
60
    var list_fields_with_states = [ 'table[id='+list_name+'_grid] input.[states]',
 
61
                                    'table[id='+list_name+'_grid] selection.[states]' ].join(', ');
 
62
    jQuery(list_fields_with_states).each(function() {
 
63
        var $this = jQuery(this);
 
64
        var attrs = $this.attr('attrs') || '{}';
 
65
        var widget = $this.attr('widget') || '';
 
66
        var container = this;
 
67
        var prefix = widget.slice(0, widget.lastIndexOf('/')+1) || '';
 
68
 
 
69
        // convert states from Python serialization to JS/JSON
 
70
        var states = eval(
 
71
                '(' + $this.attr('states')
 
72
                      .replace(/u'/g, "'")
 
73
                      .replace(/True/g, '1')
 
74
                      .replace(/False/g, '0') + ')');
 
75
 
 
76
        var state = form_find_field_in_context(prefix, 'state', $this);
 
77
        if (!state || !state.length) {
 
78
            state = form_find_field_in_context(prefix, 'x_state', $this);
 
79
        }
 
80
 
 
81
        if (state && state.length) {
 
82
            var $state = state.bind('onStateChange', MochiKit.Base.partial(form_onStateChange, container, this, states));
 
83
            $state.change(function (){
 
84
                jQuery(this).trigger('onStateChange');
 
85
            });
 
86
            state.trigger('onStateChange');
 
87
        }
 
88
 
 
89
    });
 
90
}
 
91
 
58
92
function form_onStateChange(container, widget, states, evt) {
59
93
    var src;
60
94
    if(evt.src)
143
177
                    // events disconnected during hook_onStateChange,
144
178
                    // don't redisconnect or may break onStateChange
145
179
                    var $field = jQuery(field).bind('onAttrChange', partial(form_onAttrChange, container, widget, attr, attrs[attr], $this));
146
 
                    $field.change(function () {
147
 
                        jQuery(this).trigger('onAttrChange');
148
 
                    });
 
180
                    $field.change(partial(form_onAttrChange, container, widget, attr, attrs[attr], $this));
149
181
                }
150
182
            });
151
183
        }
156
188
    }
157
189
}
158
190
 
 
191
function list_hookAttrChange(list_name) {
 
192
    jQuery('table[id='+list_name+'_grid] [attrs]').each(function () {
 
193
        var $this = jQuery(this);
 
194
        var attrs = $this.attr('attrs') || '{}';
 
195
        var widget = $this.attr('widget') || '';
 
196
        var container = this;
 
197
        var prefix = widget.slice(0, widget.lastIndexOf('/')+1) || '';
 
198
 
 
199
        // Convert Python statement into it's equivalent in JavaScript.
 
200
        attrs = attrs.replace(/\(/g, '[');
 
201
        attrs = attrs.replace(/\)/g, ']');
 
202
        attrs = attrs.replace(/True/g, '1');
 
203
        attrs = attrs.replace(/False/g, '0');
 
204
        attrs = attrs.replace(/\buid\b/g, window.USER_ID);
 
205
 
 
206
        try {
 
207
            attrs = eval('(' + attrs + ')');
 
208
        } catch(e){
 
209
            return;
 
210
        }
 
211
 
 
212
        var row_is_editable = $this.parents('tr.grid-row').is('.editors')
 
213
        for (var attr in attrs) {
 
214
            if (!row_is_editable && attr != 'invisible') {
 
215
                // when row is not in editable mode we only care about invisible attributes
 
216
                // as others attrs (readonly, required) won't have any effects.
 
217
                continue;
 
218
            }
 
219
            if (attrs[attr] == '') {
 
220
                return form_onAttrChange(container, widget, attr, attrs[attr], $this);
 
221
            }
 
222
            forEach(attrs[attr], function(n) {
 
223
                if (typeof(n) == "number") { // {'invisible': [1]}
 
224
                    return form_onAttrChange(container, widget, attr, n, $this);
 
225
                }
 
226
                if (row_is_editable) {
 
227
                    var $field = jQuery(this).bind('onAttrChange', partial(form_onAttrChange, container, widget, attr, attrs[attr], $this));
 
228
                    $field.change(partial(form_onAttrChange, container, widget, attr, attrs[attr], $this));
 
229
                }
 
230
                return form_onAttrChange(container, widget, attr, attrs[attr], $this);
 
231
            });
 
232
        }
 
233
    });
 
234
}
 
235
 
159
236
function form_onAttrChange(container, widgetName, attr, expr, elem) {
160
237
 
161
238
    var prefix = widgetName.slice(0, widgetName.lastIndexOf('/') + 1);
181
258
    }
182
259
}
183
260
 
 
261
function form_find_field_in_context(prefix, field, ref_elem) {
 
262
    // try to find field in the context of reference element (ref_elem)
 
263
    var elem = null;
 
264
    if (ref_elem.parents('table.grid').length) {
 
265
        var parent = ref_elem.parents('tr.grid-row');
 
266
        elem = parent.find(idSelector(prefix + field));
 
267
 
 
268
        if (!elem || !elem.length) {
 
269
            var parent_selector = '[name='+prefix + field +']';
 
270
            elem = parent.find(parent_selector);
 
271
        }
 
272
 
 
273
        if (!elem || !elem.length) {
 
274
            // try getting with _terp_listfields/TABLE_ID/FIELD_NAME
 
275
            var parent_table_id = ref_elem.parents('table.grid')[0].id;
 
276
            if (parent_table_id && parent_table_id.match('_grid$')) {
 
277
                parent_table_id = parent_table_id.slice(0, parent_table_id.length - 5);
 
278
            }
 
279
            if (parent_table_id == '_terp_list') {
 
280
                // in case list name if '_terp_list' this means we're not inside a o2m/m2m fields,
 
281
                // and we no need need to prefix with parent_table_id name
 
282
                parent_table_id = ''
 
283
            } else {
 
284
                parent_table_id = parent_table_id + '/'
 
285
            }
 
286
            var parent_relative_fieldname = '[name=_terp_listfields/' + parent_table_id + prefix + field + ']';
 
287
            elem = parent.find(parent_relative_fieldname);
 
288
        }
 
289
    }
 
290
    if (!elem || !elem.length) {
 
291
        elem = jQuery(idSelector(prefix + field));
 
292
    }
 
293
    return elem;
 
294
}
 
295
 
184
296
function form_evalExpr(prefix, expr, ref_elem) {
185
297
 
186
298
    var stack = [];
187
299
    for (var i = 0; i < expr.length; i++) {
188
300
 
189
301
        var ex = expr[i];
190
 
        var elem = null;
191
 
        if (ref_elem.parents('table.grid').length) {
192
 
            var parent = ref_elem.parents('tr.grid-row');
193
 
            elem = parent.find(idSelector(prefix + ex[0]));
194
 
        }
195
 
        if (!elem || !elem.length) {
196
 
            elem = jQuery(idSelector(prefix + ex[0]));
197
 
        }
198
 
 
 
302
        var op = ex[1];
 
303
        var elem = form_find_field_in_context(prefix, ex[0], ref_elem);
199
304
        if (ex.length==1) {
200
305
            stack.push(ex[0]);
201
306
            continue;
202
307
        }
203
 
        
204
 
        if (!elem || !elem.length)
205
 
            continue;
206
 
 
207
 
        var op = ex[1];
208
308
        var val = ex[2];
209
309
 
210
310
        var elem_value;
397
497
    form_hookContextMenu();
398
498
    form_hookStateChange();
399
499
    form_hookAttrChange();
400
 
}).ajaxStop(function () {
401
 
    form_hookStateChange();
402
 
    form_hookAttrChange();
403
500
});