diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 19dbde26f5d..65f503649b8 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -1,9 +1,22 @@ - openerp.base.list = function (openerp) { - openerp.base.views.add('list', 'openerp.base.ListView'); -openerp.base.ListView = openerp.base.Controller.extend({ - init: function(view_manager, session, element_id, dataset, view_id) { +openerp.base.ListView = openerp.base.Controller.extend( + /** @lends openerp.base.ListView# */ { + defaults: { + // records can be selected one by one + 'selectable': true + }, + /** + * @constructs + * @param view_manager + * @param session An OpenERP session object + * @param element_id the id of the DOM elements this view should link itself to + * @param {openerp.base.DataSet} dataset the dataset the view should work with + * @param {String} view_id the listview's identifier, if any + * @param {Object} options A set of options used to configure the view + * @param {Boolean} [options.selectable=true] determines whether view rows are selectable (e.g. via a checkbox) + */ + init: function(view_manager, session, element_id, dataset, view_id, options) { this._super(session, element_id); this.view_manager = view_manager; this.dataset = dataset; @@ -12,6 +25,8 @@ openerp.base.ListView = openerp.base.Controller.extend({ this.columns = []; this.rows = []; + + this.options = _.extend({}, this.defaults, options || {}); }, start: function() { //this.log('Starting ListView '+this.model+this.view_id) @@ -30,6 +45,12 @@ openerp.base.ListView = openerp.base.Controller.extend({ }).value(); this.$element.html(QWeb.render("ListView", this)); + this.$element.find('table').delegate( + 'th.oe-record-selector', 'click', function (e) { + // A click in the selection cell should not activate the + // linking feature + e.stopImmediatePropagation(); + }); this.$element.find('table').delegate( 'tr', 'click', this.on_select_row); @@ -37,36 +58,49 @@ openerp.base.ListView = openerp.base.Controller.extend({ if (this.view_manager.sidebar) this.view_manager.sidebar.load_multi_actions(); }, + /** + * Fills the table with the provided records after emptying it + * + * @param {Array} records the records to fill the list view with + * @returns {Promise} promise to the end of view rendering (list views are asynchronously filled for improved responsiveness) + */ do_fill_table: function(records) { this.rows = records; - var $table = this.$element.find('table'); // remove all data lines $table.find('tbody').remove(); // add new content - var columns = this.columns; - var rows = this.rows; + var columns = this.columns, + rows = this.rows, + options = this.options; + // Paginate by groups of 50 for rendering - var PAGE_SIZE = 50; - var bodies_count = Math.ceil(this.rows.length / PAGE_SIZE); - var body = 0; - var $body = $('
').appendTo($table); + var PAGE_SIZE = 50, + bodies_count = Math.ceil(this.rows.length / PAGE_SIZE), + body = 0, + $body = $('').appendTo($table); + var render_body = function () { + var rendered = $.Deferred(); setTimeout(function () { $body.append( QWeb.render("ListView.rows", { columns: columns, - rows: rows.slice(body*PAGE_SIZE, (body+1)*PAGE_SIZE) + rows: rows.slice(body*PAGE_SIZE, (body+1)*PAGE_SIZE), + options: options })); ++body; if (body < bodies_count) { render_body(); + } else { + rendered.resolve(); } }, 0); + return rendered.promise(); }; - render_body(); + return render_body(); }, on_select_row: function (event) { var $target = $(event.currentTarget); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index e04de920943..1dcb30006d4 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -166,24 +166,30 @@==)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var equal;
+/**
+ * Inequality assertion (~assertNotEqual)
+ *
+ * Passes if the arguments are different (via !=)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var notEqual;
+/**
+ * Recursive equality assertion.
+ *
+ * Works on primitive types using === and traversing through
+ * Objects and Arrays as well checking their components
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var deepEqual;
+/**
+ * Recursive inequality assertion.
+ *
+ * Works on primitive types using !== and traversing through
+ * Objects and Arrays as well checking their components
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var notDeepEqual;
+/**
+ * Strict equality assertion (~assertEqual)
+ *
+ * Passes if both arguments are identical (via ===)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var strictEqual;
+/**
+ * Strict inequality assertion (~assertNotEqual)
+ *
+ * Passes if both arguments are identical (via !==)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var notStrictEqual;
+/**
+ * Passes if the provided block raised an exception.
+ *
+ * The expect argument can be provided to perform further assertion checks on the exception itself:
+ * * If it's a RegExp test the exception against the regexp (message?)
+ * * If it's a constructor, check if the exception is an instance of it
+ * * If it's an other type of function, call it with the exception as first parameter
+ * - If the function returns true, the assertion validates
+ * - Otherwise it fails
+ *
+ * @function
+ * @param {Function} block function which should raise an exception when called
+ * @param {Object} [expect] a RegExp, a constructor or a Function
+ * @param {String} [message] message output with the assertion result
+ */
+var raises;
+/**
+ * Starts running the test runner again from the point where it was
+ * stopped.
+ *
+ * Used to resume testing after a callback.
+ *
+ * @function
+ */
+var start;
+/**
+ * Stops the test runner in order to wait for an asynchronous test to run
+ *
+ * @function
+ * @param {Number} [timeout] fails the test after the timeout triggers, only for debugging tests
+ */
+var stop;
diff --git a/addons/base/static/test/test.html b/addons/base/static/test/test.html
index 9681be8e389..776b03146ff 100644
--- a/addons/base/static/test/test.html
+++ b/addons/base/static/test/test.html
@@ -21,6 +21,7 @@
+
@@ -35,4 +36,5 @@