[MERGE] forward port of branch saas-1 up to revid 3751 chs@openerp.com-20131115104909...
[odoo/odoo.git] / addons / web / static / src / js / view_list.js
index b9c789c..ff99eb5 100644 (file)
@@ -1,4 +1,7 @@
-openerp.web.list = function (instance) {
+(function() {
+
+var instance = openerp;
+openerp.web.list = {};
 var _t = instance.web._t,
     _lt = instance.web._lt;
 var QWeb = instance.web.qweb;
@@ -132,8 +135,8 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
 
         this.groups = groups;
         $(this.groups).bind({
-            'selected': function (e, ids, records) {
-                self.do_select(ids, records);
+            'selected': function (e, ids, records, deselected) {
+                self.do_select(ids, records, deselected);
             },
             'deleted': function (e, ids) {
                 self.do_delete(ids);
@@ -171,11 +174,13 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
             current_date: new Date().toString('yyyy-MM-dd')
             // TODO: time, datetime, relativedelta
         });
-
+        var i;
+        var pair;
+        var expression;
         if (this.fonts) {
-            for(var i=0, len=this.fonts.length; i<len; ++i) {
-                var pair = this.fonts[i],
-                font = pair[0],
+            for(i=0, len=this.fonts.length; i<len; ++i) {
+                pair = this.fonts[i];
+                var font = pair[0];
                 expression = pair[1];
                 if (py.evaluate(expression, context).toJSON()) {
                     switch(font) {
@@ -194,10 +199,10 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
         }
 
         if (!this.colors) { return style; }
-        for(var i=0, len=this.colors.length; i<len; ++i) {
-            var pair = this.colors[i],
-                color = pair[0],
-                expression = pair[1];
+        for(i=0, len=this.colors.length; i<len; ++i) {
+            pair = this.colors[i];
+            var color = pair[0];
+            expression = pair[1];
             if (py.evaluate(expression, context).toJSON()) {
                 return style += 'color: ' + color + ';';
             }
@@ -361,7 +366,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
     sort_by_column: function (e) {
         e.stopPropagation();
         var $column = $(e.currentTarget);
-        var col_name = $column.data('id')
+        var col_name = $column.data('id');
         var field = this.fields_view.fields[col_name];
         // test if the field is a function field with store=false, since it's impossible
         // for the server to sort those fields we desactivate the feature
@@ -394,7 +399,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
 
         var total = dataset.size();
         var limit = this.limit() || total;
-        if (total == 0)
+        if (total === 0)
             this.$pager.hide();
         else
             this.$pager.css("display", "");
@@ -454,7 +459,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
      * @param {String} [view="page"] the view type to switch to
      */
     select_record:function (index, view) {
-        view = view || index == null ? 'form' : 'form';
+        view = view || index === null || index === undefined ? 'form' : 'form';
         this.dataset.index = index;
         _.delay(_.bind(function () {
             this.do_switch_view(view);
@@ -503,6 +508,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
         var reloaded = $.Deferred();
         this.$el.find('.oe_list_content').append(
             this.groups.render(function () {
+                // Keep '=='. This is not a mistake, this is a wanted behaviour to match null & undefined
                 if (self.dataset.index == null) {
                     if (self.records.length) {
                         self.dataset.index = 0;
@@ -607,7 +613,12 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
      * @param {Array} ids selected record ids
      * @param {Array} records selected record values
      */
-    do_select: function (ids, records) {
+    do_select: function (ids, records, deselected) {
+        // uncheck header hook if at least one row has been deselected
+        if (deselected) {
+            this.$('.oe_list_record_selector').prop('checked', false);
+        }
+
         if (!ids.length) {
             this.dataset.index = 0;
             if (this.sidebar) {
@@ -795,6 +806,29 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
         return ids;
     },
     /**
+     * Calculate the active domain of the list view. This should be done only
+     * if the header checkbox has been checked. This is done by evaluating the
+     * search results, and then adding the dataset domain (i.e. action domain).
+     */
+    get_active_domain: function () {
+        var self = this;
+        if (this.$('.oe_list_record_selector').prop('checked')) {
+            var search_view = this.getParent().searchview;
+            var search_data = search_view.build_search_data();
+            return instance.web.pyeval.eval_domains_and_contexts({
+                domains: search_data.domains,
+                contexts: search_data.contexts,
+                group_by_seq: search_data.groupbys || []
+            }).then(function (results) {
+                var domain = self.dataset.domain.concat(results.domain || []);
+                return domain
+            });
+        }
+        else {
+            return $.Deferred().resolve();
+        }
+    },
+    /**
      * Adds padding columns at the start or end of all table rows (including
      * field names row)
      *
@@ -955,8 +989,9 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
             .delegate('th.oe_list_record_selector', 'click', function (e) {
                 e.stopPropagation();
                 var selection = self.get_selection();
+                var checked = $(e.currentTarget).find('input').prop('checked');
                 $(self).trigger(
-                        'selected', [selection.ids, selection.records]);
+                        'selected', [selection.ids, selection.records, ! checked]);
             })
             .delegate('td.oe_list_record_delete button', 'click', function (e) {
                 e.stopPropagation();
@@ -1412,10 +1447,10 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
     bind_child_events: function (child) {
         var $this = $(this),
              self = this;
-        $(child).bind('selected', function (e) {
+        $(child).bind('selected', function (e, _0, _1, deselected) {
             // can have selections spanning multiple links
             var selection = self.get_selection();
-            $this.trigger(e, [selection.ids, selection.records]);
+            $this.trigger(e, [selection.ids, selection.records, deselected]);
         }).bind(this.passthrough_events, function (e) {
             // additional positional parameters are provided to trigger as an
             // Array, following the event type or event object, but are
@@ -1441,7 +1476,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
            limit = view.limit(),
             page = this.datagroup.openable ? this.page : view.page;
 
-        var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
+        var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name');
         var options = { offset: page * limit, limit: limit, context: {bin_size: true} };
         //TODO xmo: investigate why we need to put the setTimeout
         return $.async_when().then(function() {
@@ -1529,20 +1564,21 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
                     // if drag to 1st row (to = 0), start sequencing from 0
                     // (exclusive lower bound)
                     seq = to ? list.records.at(to - 1).get(seqname) : 0;
-                while (++seq, record = list.records.at(index++)) {
+                var fct = function (dataset, id, seq) {
+                    $.async_when().done(function () {
+                        var attrs = {};
+                        attrs[seqname] = seq;
+                        dataset.write(id, attrs);
+                    });
+                };
+                while (++seq, (record = list.records.at(index++))) {
                     // write are independent from one another, so we can just
                     // launch them all at the same time and we don't really
                     // give a fig about when they're done
                     // FIXME: breaks on o2ms (e.g. Accounting > Financial
                     //        Accounting > Taxes > Taxes, child tax accounts)
                     //        when synchronous (without setTimeout)
-                    (function (dataset, id, seq) {
-                        $.async_when().done(function () {
-                            var attrs = {};
-                            attrs[seqname] = seq;
-                            dataset.write(id, attrs);
-                        });
-                    }(dataset, record.get('id'), seq));
+                    fct(dataset, record.get('id'), seq);
                     record.set(seqname, seq);
                 }
             }
@@ -1555,7 +1591,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
 
         this.datagroup.list(
             _(this.view.visible_columns).chain()
-                .filter(function (column) { return column.tag === 'field' })
+                .filter(function (column) { return column.tag === 'field';})
                 .pluck('name').value(),
             function (groups) {
                 $el[0].appendChild(
@@ -1601,7 +1637,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
             return {
                 count: this.datagroup.length,
                 values: this.datagroup.aggregates
-            }
+            };
         }
         return _(this.children).chain()
             .map(function (child) {
@@ -1858,7 +1894,7 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
             var instance_ = (records[i] instanceof Record) ? records[i] : new Record(records[i]);
             instance_.bind(null, this._onRecordEvent);
             this._byId[instance_.get('id')] = instance_;
-            if (options.at == undefined) {
+            if (options.at === undefined || options.at === null) {
                 this.records.push(instance_);
                 if (!options.silent) {
                     this.trigger('add', this, instance_, this.records.length-1);
@@ -1900,7 +1936,8 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
         if (!_(this._proxies).isEmpty()) {
             var record = null;
             _(this._proxies).detect(function (proxy) {
-                return record = proxy.get(id);
+                record = proxy.get(id);
+                return record;
             });
             return record;
         }
@@ -1914,10 +1951,11 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
      * @returns {Collection}
      */
     proxy: function (section) {
-        return this._proxies[section] = new Collection(null, {
+        this._proxies[section] = new Collection(null, {
             parent: this,
             key: section
         }).bind(null, this._onRecordEvent);
+        return this._proxies[section];
     },
     /**
      * @param {Array} [records]
@@ -1987,7 +2025,7 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
         var record;
         for(var section in this._proxies) {
             if (!this._proxies.hasOwnProperty(section)) {
-                continue
+                continue;
             }
             if ((record = this._proxies[section].find(callback))) {
                 return record;
@@ -2089,6 +2127,7 @@ instance.web.list.columns = new instance.web.Registry({
     'field': 'instance.web.list.Column',
     'field.boolean': 'instance.web.list.Boolean',
     'field.binary': 'instance.web.list.Binary',
+    'field.char': 'instance.web.list.Char',
     'field.progressbar': 'instance.web.list.ProgressBar',
     'field.handle': 'instance.web.list.Handle',
     'button': 'instance.web.list.Button',
@@ -2103,7 +2142,7 @@ instance.web.list.columns.for_ = function (id, field, node) {
         tag + '.'+ description.type,
         tag
     ]);
-    return new Type(id, node.tag, description)
+    return new Type(id, node.tag, description);
 };
 
 instance.web.list.Column = instance.web.Class.extend({
@@ -2257,6 +2296,20 @@ instance.web.list.Binary = instance.web.list.Column.extend({
         });
     }
 });
+instance.web.list.Char = instance.web.list.Column.extend({
+    replacement: '*',
+    /**
+     * If password field, only display replacement characters (if value is
+     * non-empty)
+     */
+    _format: function (row_data, options) {
+        var value = row_data[this.id].value;
+        if (value && this.password === 'True') {
+            return value.replace(/[\s\S]/g, _.escape(this.replacement));
+        }
+        return this._super(row_data, options);
+    }
+});
 instance.web.list.ProgressBar = instance.web.list.Column.extend({
     /**
      * Return a formatted progress bar display
@@ -2305,5 +2358,5 @@ instance.web.list.Many2Many = instance.web.list.Column.extend({
         return this._super(row_data, options);
     }
 });
-};
+})();
 // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: