diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py
index 9c3aeb55b12..185f2d18bca 100644
--- a/addons/base/controllers/main.py
+++ b/addons/base/controllers/main.py
@@ -167,7 +167,7 @@ class DataSet(openerpweb.Controller):
@openerpweb.jsonrequest
def fields(self, req, model):
- return {'fields': req.session.model(model).fields_get(False)}
+ return {'fields': req.session.model(model).fields_get()}
@openerpweb.jsonrequest
def load(self, req, model, domain=[], fields=['id']):
diff --git a/addons/base/static/openerp/js/base_views.js b/addons/base/static/openerp/js/base_views.js
index d9db2348066..156b11a9f61 100644
--- a/addons/base/static/openerp/js/base_views.js
+++ b/addons/base/static/openerp/js/base_views.js
@@ -94,60 +94,195 @@ openerp.base.EmbbededView = openerp.base.Controller.extend({
// to replace Action
});
+/**
+ * Management interface between views and the collection of selected OpenERP
+ * records (represents the view's state?)
+ */
openerp.base.DataSet = openerp.base.Controller.extend({
- init: function(session, element_id, model) {
- this._super(session, element_id);
- this.model = model;
- // SHOULD USE THE ONE FROM FIELDS VIEW GET BECAUSE OF SELECTION
- // Should merge those 2
- this.model_fields = null;
- this.fields = [];
+ init: function(session, model) {
+ this._super(session);
+ this._model = model;
- this.domain = [];
- this.context = {};
- this.order = "";
- this.count = null;
- this.ids = [];
- this.values = {};
-/*
- group_by
- rows record
- fields of row1 field fieldname
- { type: value: text: text_format: text_completions type_*: a
-*/
+ this._fields = null;
+
+ this._ids = [];
+ this._active_ids = null;
+ this._active_id_index = 0;
+
+ this._sort = [];
+ this._domain = [];
+ this._context = {};
},
start: function() {
- this.rpc("/base/dataset/fields", {"model":this.model}, this.on_fields);
+ // TODO: fields_view_get fields selection?
+ this.rpc("/base/dataset/fields", {"model":this._model}, this.on_fields);
},
on_fields: function(result) {
- this.model_fields = result.fields;
+ this._fields = result._fields;
this.on_ready();
},
- do_load: function(offset, limit) {
- this.rpc("/base/dataset/load", {model: this.model, fields: this.fields }, this.on_loaded);
+
+ /**
+ * Fetch all the records selected by this DataSet, based on its domain
+ * and context.
+ *
+ * Fires the on_ids event.
+ *
+ * @param {Number} [offset=0] The index from which selected records should be returned
+ * @param {Number} [limit=null] The maximum number of records to return
+ * @returns itself
+ */
+ ids: function (offset, limit) {
+ offset = offset || 0;
+ limit = limit || null;
+ this.rpc('/base/dataset/load', {
+ model: this._model,
+ fields: this._fields,
+ domain: this._domain,
+ context: this._context,
+ sort: this._sort,
+ offset: offset,
+ limit: limit
+ }, _.bind(function (records) {
+ var data_records = _.map(
+ records, function (record) {
+ return new openerp.base.DataRecord(
+ this.session, this._model,
+ this._fields, record);
+ }, this);
+
+ this.on_ids(data_records, {
+ offset: offset,
+ limit: limit,
+ domain: this._domain,
+ context: this._context,
+ sort: this._sort
+ });
+ }, this));
+ return this;
},
- on_loaded: function(data) {
- this.ids = data.ids;
- this.values = data.values;
+ /**
+ * @event
+ *
+ * Fires after the DataSet fetched the records matching its internal ids selection
+ *
+ * @param {Array} records An array of the DataRecord fetched
+ * @param event The on_ids event object
+ * @param {Number} event.offset the offset with which the original DataSet#ids call was performed
+ * @param {Number} event.limit the limit set on the original DataSet#ids call
+ * @param {Array} event.domain the domain set on the DataSet before DataSet#ids was called
+ * @param {Object} event.context the context set on the DataSet before DataSet#ids was called
+ * @param {Array} event.sort the sorting criteria used to get the ids
+ */
+ on_ids: function (records, event) {
+
},
- on_reloaded: function(ids) {
+
+ /**
+ * Fetch all the currently active records for this DataSet (records selected via DataSet#select)
+ *
+ * @param {Number} [offset=0] The index from which selected records should be returned
+ * @param {Number} [limit=-1] The maximum number of records to return
+ * @returns itself
+ */
+ active_ids: function (offset, limit) {
+ return this;
+ },
+ /**
+ * @event
+ *
+ * Fires after the DataSet fetched the records matching its internal active ids selection
+ *
+ * @param {Array} records An array of the DataRecord fetched
+ * @param event The on_active_ids event object
+ * @param {Number} event.offset the offset with which the original DataSet#ids call was performed
+ * @param {Number} event.limit the limit set on the original DataSet#ids call
+ * @param {Array} event.sort the sorting criteria used to get the ids
+ */
+ on_active_ids: function (records, event) {
+
+ },
+
+ /**
+ * Fetches the current active record for this DataSet
+ *
+ * @returns itself
+ */
+ active_id: function () {
+ return this;
+ },
+ /**
+ * Fires after the DataSet fetched the record matching the current active record
+ *
+ * @param record the record matching the provided id, or null if there is no record for this id
+ */
+ on_active_id: function (record) {
+
+ },
+
+ /**
+ * Configures the DataSet
+ *
+ * @param options DataSet options
+ * @param {Array} options.domain the domain to assign to this DataSet for filtering
+ * @param {Object} options.context the context this DataSet should use during its calls
+ * @param {Array} options.sort the sorting criteria for this DataSet
+ * @returns itself
+ */
+ set: function (options) {
+ if (options.domain) {
+ this._domain = _.clone(options.domain);
+ }
+ if (options.context) {
+ this._context = _.clone(options.context);
+ }
+ if (options.sort) {
+ this._sort = _.clone(options.sort);
+ }
+ return this;
+ },
+
+ /**
+ * Activates the previous id in the active sequence. If there is no previous id, wraps around to the last one
+ * @returns itself
+ */
+ prev: function () {
+ return this;
+ },
+ /**
+ * Activates the next id in the active sequence. If there is no next id, wraps around to the first one
+ * @returns itself
+ */
+ next: function () {
+ return this;
+ },
+
+ /**
+ * Sets active_ids and/or active_id by value:
+ *
+ * * If only ids is provided
+ * - Activates all ids part of the current selection
+ * - Sets active_id to be the first id of the selection
+ * * If only id is provided, activates this id (for both active_id and active_ids)
+ * * If both id and ids are provided
+ * - Activates all ids part of the current selection
+ * - If id is part of the active ids, activates it, otherwise see first option
+ *
+ * @param {Array} [ids] the list of ids to activate
+ * @param {Object} [id] the id to activate
+ */
+ select: function (ids, id) {
+ return this;
}
});
openerp.base.DataRecord = openerp.base.Controller.extend({
- init: function(session, model, fields) {
+ init: function(session, model, fields, values) {
this._super(session, null);
this.model = model;
- this.id = null;
+ this.id = values.id || null;
this.fields = fields;
- this.values = {};
- },
- load: function(id) {
- this.id = id;
- this.rpc("/base/datarecord/load", {"model": this.model, "id": id, "fields": "todo"}, this.on_loaded);
- },
- on_loaded: function(result) {
- this.values = result.value;
+ this.values = values;
},
on_change: function() {
},
diff --git a/addons/base/static/openerp/js/tests.js b/addons/base/static/openerp/js/tests.js
index fe5a2998079..46d08ff8691 100644
--- a/addons/base/static/openerp/js/tests.js
+++ b/addons/base/static/openerp/js/tests.js
@@ -19,6 +19,18 @@ var module;
* @param {Function} test the testing code to run, holding a sequence of assertions (at least one)
*/
var test;
+/**
+ * @function
+ * Defines an asynchronous test: equivalent to calling stop() at the start of
+ * a normal test().
+ *
+ * The test code needs to restart the test runner via start()
+ *
+ * @param {String} name the name of the test
+ * @param {Number} [expected] number of assertions expected to run in this test (useful for asynchronous tests)
+ * @param {Function} test the testing code to run, holding a sequence of assertions (at least one)
+ */
+var asyncTest;
/**
* @function
* The most basic boolean assertion (~assertTrue or assert).
@@ -42,7 +54,7 @@ var ok;
var equal;
/**
* @function
- * Inequality assertion (~assertEqual)
+ * Inequality assertion (~assertNotEqual)
*
* Passes if the arguments are different (via !=)
*
@@ -50,7 +62,135 @@ var equal;
* @param {Object} expected the object to check against
* @param {String} [message] message output with the assertion result
*/
-var notEqual, deepEqual, notDeepEqual,
- strictEqual, notStrictEqual, raises, start, stop;
+var notEqual;
+/**
+ * @function
+ * Recursive equality assertion.
+ *
+ * Works on primitive types using === and traversing through
+ * Objects and Arrays as well checking their components
+ *
+ * @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;
+var notDeepEqual, strictEqual, notStrictEqual, raises;
+/**
+ * @function
+ * Starts running the test runner again from the point where it was
+ * stopped.
+ *
+ * Used to resume testing after a callback.
+ */
+var start;
+/**
+ * @function
+ * Stops the test runner in order to wait for an asynchronous test to run
+ *
+ * @param {Number} [timeout] fails the test after the timeout triggers, only for debugging tests
+ */
+var stop;
+
+var Session = function () {
+ return {
+ rpc: function (_url, params, on_success) {
+ setTimeout(on_success);
+ }
+ };
+};
$(document).ready(function () {
+ var openerp;
+ module("ids_callback", {
+ setup: function () {
+ openerp = window.openerp.init();
+ }
+ });
+ asyncTest("Baseline event attributes", 6, function () {
+ var dataset = new openerp.base.DataSet(
+ new Session());
+ dataset.on_ids.add(function (records, event) {
+ deepEqual(records, [], 'No records returned');
+ equal(event.offset, 0, 'No offset set in call');
+ equal(event.limit, null, 'No limit set in call');
+ deepEqual(event.domain, [], 'No domain on the dataset');
+ deepEqual(event.context, {}, 'No context on the dataset');
+ deepEqual(event.sort, [], 'The dataset is not sorted');
+ start();
+ });
+ dataset.ids();
+ });
+ asyncTest("Offset and limit", 2, function () {
+ var dataset = new openerp.base.DataSet(
+ new Session());
+ dataset.on_ids.add(function (records, event) {
+ equal(event.offset, 20);
+ equal(event.limit, 42);
+ start();
+ });
+ dataset.ids(20, 42);
+ });
+ asyncTest("Domain and context propagation", 3, function () {
+ var dataset = new openerp.base.DataSet(
+ new Session());
+ var domain_value = [['foo', '=', 'bar']];
+ var context_value= {active_id:3, active_ids:42};
+ var sort_value = ['foo'];
+ dataset.on_ids.add(function (records, event) {
+ deepEqual(event.domain, domain_value);
+ deepEqual(event.context, context_value);
+ deepEqual(event.sort, sort_value);
+ start();
+ });
+ dataset.set({
+ domain: domain_value,
+ context: context_value,
+ sort: sort_value
+ });
+ dataset.ids();
+ });
+ asyncTest("Data records", function () {
+ var dataset = new openerp.base.DataSet({
+ rpc: function (url, _params, on_success) {
+ equal('/base/dataset/load', url);
+ _.delay(on_success, 0, [
+ {id: 1, sequence: 3, name: "dummy", age: 42},
+ {id: 5, sequence: 7, name: "whee", age: 55}
+ ]);
+ }
+ });
+ dataset.on_ids.add(function (records) {
+ equal(records.length, 2, "I loaded two virtual records");
+ var d1 = records[0],
+ d2 = records[1];
+ ok(d1 instanceof openerp.base.DataRecord);
+ ok(d2 instanceof openerp.base.DataRecord);
+ start();
+ });
+ dataset.ids();
+ });
+
+ var dataset;
+ module("set", {
+ setup: function () {
+ var openerp = window.openerp.init();
+ dataset = new openerp.base.DataSet();
+ }
+ });
+ test('Basic properties setting', function () {
+ var domain_value = [['foo', '=', 'bar']];
+ var result = dataset.set({
+ domain: domain_value
+ });
+ ok(dataset === result);
+ deepEqual(domain_value, dataset._domain);
+ });
+ test("Ensure changes don't stick", function () {
+ var domain = [['foo', '=', 'bar']];
+ dataset.set({
+ domain: domain
+ });
+ domain.pop();
+ deepEqual([['foo', '=', 'bar']], dataset._domain);
+ });
});