summaryrefslogtreecommitdiff
path: root/addons/base/static/src/js/data.js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/base/static/src/js/data.js')
-rw-r--r--addons/base/static/src/js/data.js787
1 files changed, 0 insertions, 787 deletions
diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js
deleted file mode 100644
index e95adaf8870..00000000000
--- a/addons/base/static/src/js/data.js
+++ /dev/null
@@ -1,787 +0,0 @@
-
-openerp.base.data = function(openerp) {
-
-/**
- * Serializes the sort criterion array of a dataset into a form which can be
- * consumed by OpenERP's RPC APIs.
- *
- * @param {Array} criterion array of fields, from first to last criteria, prefixed with '-' for reverse sorting
- * @returns {String} SQL-like sorting string (``ORDER BY``) clause
- */
-openerp.base.serialize_sort = function (criterion) {
- return _.map(criterion,
- function (criteria) {
- if (criteria[0] === '-') {
- return criteria.slice(1) + ' DESC';
- }
- return criteria + ' ASC';
- }).join(', ');
-};
-
-openerp.base.DataGroup = openerp.base.Widget.extend( /** @lends openerp.base.DataGroup# */{
- /**
- * Management interface between views and grouped collections of OpenERP
- * records.
- *
- * The root DataGroup is instantiated with the relevant information
- * (a session, a model, a domain, a context and a group_by sequence), the
- * domain and context may be empty. It is then interacted with via
- * :js:func:`~openerp.base.DataGroup.list`, which is used to read the
- * content of the current grouping level.
- *
- * @constructs
- * @extends openerp.base.Widget
- *
- * @param {openerp.base.Session} session Current OpenERP session
- * @param {String} model name of the model managed by this DataGroup
- * @param {Array} domain search domain for this DataGroup
- * @param {Object} context context of the DataGroup's searches
- * @param {Array} group_by sequence of fields by which to group
- * @param {Number} [level=0] nesting level of the group
- */
- init: function(parent, model, domain, context, group_by, level) {
- this._super(parent, null);
- if (group_by) {
- if (group_by.length || context['group_by_no_leaf']) {
- return new openerp.base.ContainerDataGroup( this, model, domain, context, group_by, level);
- } else {
- return new openerp.base.GrouplessDataGroup( this, model, domain, context, level);
- }
- }
-
- this.model = model;
- this.context = context;
- this.domain = domain;
-
- this.level = level || 0;
- },
- cls: 'DataGroup'
-});
-openerp.base.ContainerDataGroup = openerp.base.DataGroup.extend( /** @lends openerp.base.ContainerDataGroup# */ {
- /**
- *
- * @constructs
- * @extends openerp.base.DataGroup
- *
- * @param session
- * @param model
- * @param domain
- * @param context
- * @param group_by
- * @param level
- */
- init: function (parent, model, domain, context, group_by, level) {
- this._super(parent, model, domain, context, null, level);
-
- this.group_by = group_by;
- },
- /**
- * The format returned by ``read_group`` is absolutely dreadful:
- *
- * * A ``__context`` key provides future grouping levels
- * * A ``__domain`` key provides the domain for the next search
- * * The current grouping value is provided through the name of the
- * current grouping name e.g. if currently grouping on ``user_id``, then
- * the ``user_id`` value for this group will be provided through the
- * ``user_id`` key.
- * * Similarly, the number of items in the group (not necessarily direct)
- * is provided via ``${current_field}_count``
- * * Other aggregate fields are just dumped there
- *
- * This function slightly improves the grouping records by:
- *
- * * Adding a ``grouped_on`` property providing the current grouping field
- * * Adding a ``value`` and a ``length`` properties which replace the
- * ``$current_field`` and ``${current_field}_count`` ones
- * * Moving aggregate values into an ``aggregates`` property object
- *
- * Context and domain keys remain as-is, they should not be used externally
- * but in case they're needed...
- *
- * @param {Object} group ``read_group`` record
- */
- transform_group: function (group) {
- var field_name = this.group_by[0];
- // In cases where group_by_no_leaf and no group_by, the result of
- // read_group has aggregate fields but no __context or __domain.
- // Create default (empty) values for those so that things don't break
- var fixed_group = _.extend(
- {__context: {group_by: []}, __domain: []},
- group);
-
- var aggregates = {};
- _(fixed_group).each(function (value, key) {
- if (key.indexOf('__') === 0
- || key === field_name
- || key === field_name + '_count') {
- return;
- }
- aggregates[key] = value || 0;
- });
-
- return {
- __context: fixed_group.__context,
- __domain: fixed_group.__domain,
-
- grouped_on: field_name,
- // if terminal group (or no group) and group_by_no_leaf => use group.__count
- length: fixed_group[field_name + '_count'] || fixed_group.__count,
- value: fixed_group[field_name],
-
- openable: !(this.context['group_by_no_leaf']
- && fixed_group.__context.group_by.length === 0),
-
- aggregates: aggregates
- };
- },
- fetch: function (fields) {
- // internal method
- var d = new $.Deferred();
- var self = this;
-
- this.rpc('/base/group/read', {
- model: this.model,
- context: this.context,
- domain: this.domain,
- fields: _.uniq(this.group_by.concat(fields)),
- group_by_fields: this.group_by,
- sort: openerp.base.serialize_sort(this.sort)
- }, function () { }).then(function (response) {
- var data_groups = _(response).map(
- _.bind(self.transform_group, self));
- self.groups = data_groups;
- d.resolveWith(self, [data_groups]);
- }, function () {
- d.rejectWith.apply(d, [self, arguments]);
- });
- return d.promise();
- },
- /**
- * The items of a list have the following properties:
- *
- * ``length``
- * the number of records contained in the group (and all of its
- * sub-groups). This does *not* provide the size of the "next level"
- * of the group, unless the group is terminal (no more groups within
- * it).
- * ``grouped_on``
- * the name of the field this level was grouped on, this is mostly
- * used for display purposes, in order to know the name of the current
- * level of grouping. The ``grouped_on`` should be the same for all
- * objects of the list.
- * ``value``
- * the value which led to this group (this is the value all contained
- * records have for the current ``grouped_on`` field name).
- * ``aggregates``
- * a mapping of other aggregation fields provided by ``read_group``
- *
- * @param {Array} fields the list of fields to aggregate in each group, can be empty
- * @param {Function} ifGroups function executed if any group is found (DataGroup.group_by is non-null and non-empty), called with a (potentially empty) list of groups as parameters.
- * @param {Function} ifRecords function executed if there is no grouping left to perform, called with a DataSet instance as parameter
- */
- list: function (fields, ifGroups, ifRecords) {
- var self = this;
- this.fetch(fields).then(function (group_records) {
- ifGroups(_(group_records).map(function (group) {
- var child_context = _.extend({}, self.context, group.__context);
- return _.extend(
- new openerp.base.DataGroup(
- self, self.model, group.__domain,
- child_context, child_context.group_by,
- self.level + 1),
- group, {sort: self.sort});
- }));
- });
- }
-});
-openerp.base.GrouplessDataGroup = openerp.base.DataGroup.extend( /** @lends openerp.base.GrouplessDataGroup# */ {
- /**
- *
- * @constructs
- * @extends openerp.base.DataGroup
- *
- * @param session
- * @param model
- * @param domain
- * @param context
- * @param level
- */
- init: function (parent, model, domain, context, level) {
- this._super(parent, model, domain, context, null, level);
- },
- list: function (fields, ifGroups, ifRecords) {
- ifRecords(_.extend(
- new openerp.base.DataSetSearch(this, this.model),
- {domain: this.domain, context: this.context, _sort: this.sort}));
- }
-});
-openerp.base.StaticDataGroup = openerp.base.GrouplessDataGroup.extend( /** @lends openerp.base.StaticDataGroup# */ {
- /**
- * A specialization of groupless data groups, relying on a single static
- * dataset as its records provider.
- *
- * @constructs
- * @extends openerp.base.GrouplessDataGroup
- * @param {openep.base.DataSetStatic} dataset a static dataset backing the groups
- */
- init: function (dataset) {
- this.dataset = dataset;
- },
- list: function (fields, ifGroups, ifRecords) {
- ifRecords(this.dataset);
- }
-});
-
-openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.DataSet# */{
- /**
- * DateaManagement interface between views and the collection of selected
- * OpenERP records (represents the view's state?)
- *
- * @constructs
- * @extends openerp.base.Widget
- *
- * @param {String} model the OpenERP model this dataset will manage
- */
- init: function(source_controller, model, context) {
- // we don't want the dataset to be a child of anything!
- this._super(null);
- this.session = source_controller ? source_controller.session : undefined;
- this.model = model;
- this.context = context || {};
- this.index = null;
- },
- start: function() {
- },
- previous: function () {
- this.index -= 1;
- if (this.index < 0) {
- this.index = this.ids.length - 1;
- }
- return this;
- },
- next: function () {
- this.index += 1;
- if (this.index >= this.ids.length) {
- this.index = 0;
- }
- return this;
- },
- /**
- * Read records.
- *
- * @param {Array} ids identifiers of the records to read
- * @param {Array} fields fields to read and return, by default all fields are returned
- * @param {Function} callback function called with read result
- * @returns {$.Deferred}
- */
- read_ids: function (ids, fields, callback) {
- return this.rpc('/base/dataset/get', {
- model: this.model,
- ids: ids,
- fields: fields,
- context: this.get_context()
- }, callback);
- },
- /**
- * Read a slice of the records represented by this DataSet, based on its
- * domain and context.
- *
- * @param {Array} [fields] fields to read and return, by default all fields are returned
- * @params {Object} options
- * @param {Number} [options.offset=0] The index from which selected records should be returned
- * @param {Number} [options.limit=null] The maximum number of records to return
- * @param {Function} callback function called with read_slice result
- * @returns {$.Deferred}
- */
- read_slice: function (fields, options, callback) {
- return null;
- },
- /**
- * Reads the current dataset record (from its index)
- *
- * @params {Array} [fields] fields to read and return, by default all fields are returned
- * @params {Function} callback function called with read_index result
- * @returns {$.Deferred}
- */
- read_index: function (fields, callback) {
- var def = $.Deferred().then(callback);
- if (_.isEmpty(this.ids)) {
- def.reject();
- } else {
- fields = fields || false;
- return this.read_ids([this.ids[this.index]], fields).then(function(records) {
- def.resolve(records[0]);
- }, function() {
- def.reject.apply(def, arguments);
- });
- }
- return def.promise();
- },
- /**
- * Reads default values for the current model
- *
- * @param {Array} [fields] fields to get default values for, by default all defaults are read
- * @param {Function} callback function called with default_get result
- * @returns {$.Deferred}
- */
- default_get: function(fields, callback) {
- return this.rpc('/base/dataset/default_get', {
- model: this.model,
- fields: fields,
- context: this.get_context()
- }, callback);
- },
- /**
- * Creates a new record in db
- *
- * @param {Object} data field values to set on the new record
- * @param {Function} callback function called with operation result
- * @param {Function} error_callback function called in case of creation error
- * @returns {$.Deferred}
- */
- create: function(data, callback, error_callback) {
- return this.rpc('/base/dataset/create', {
- model: this.model,
- data: data,
- context: this.get_context()
- }, callback, error_callback);
- },
- /**
- * Saves the provided data in an existing db record
- *
- * @param {Number|String} id identifier for the record to alter
- * @param {Object} data field values to write into the record
- * @param {Function} callback function called with operation result
- * @param {Function} error_callback function called in case of write error
- * @returns {$.Deferred}
- */
- write: function (id, data, options, callback, error_callback) {
- var options = options || {};
- return this.rpc('/base/dataset/save', {
- model: this.model,
- id: id,
- data: data,
- context: this.get_context(options.context)
- }, callback, error_callback);
- },
- /**
- * Deletes an existing record from the database
- *
- * @param {Number|String} ids identifier of the record to delete
- * @param {Function} callback function called with operation result
- * @param {Function} error_callback function called in case of deletion error
- */
- unlink: function(ids, callback, error_callback) {
- var self = this;
- return this.call_and_eval("unlink", [ids, this.get_context()], null, 1,
- callback, error_callback);
- },
- /**
- * Calls an arbitrary RPC method
- *
- * @param {String} method name of the method (on the current model) to call
- * @param {Array} [args] arguments to pass to the method
- * @param {Function} callback
- * @param {Function} error_callback
- * @returns {$.Deferred}
- */
- call: function (method, args, callback, error_callback) {
- return this.rpc('/base/dataset/call', {
- model: this.model,
- method: method,
- args: args || []
- }, callback, error_callback);
- },
- /**
- * Calls an arbitrary method, with more crazy
- *
- * @param {String} method
- * @param {Array} [args]
- * @param {Number} [domain_index] index of a domain to evaluate in the args array
- * @param {Number} [context_index] index of a context to evaluate in the args array
- * @param {Function} callback
- * @param {Function }error_callback
- * @returns {$.Deferred}
- */
- call_and_eval: function (method, args, domain_index, context_index, callback, error_callback) {
- return this.rpc('/base/dataset/call', {
- model: this.model,
- method: method,
- domain_id: domain_index || null,
- context_id: context_index || null,
- args: args || []
- }, callback, error_callback);
- },
- /**
- * Calls a button method, usually returning some sort of action
- *
- * @param {String} method
- * @param {Array} [args]
- * @param {Function} callback
- * @param {Function} error_callback
- * @returns {$.Deferred}
- */
- call_button: function (method, args, callback, error_callback) {
- return this.rpc('/base/dataset/call_button', {
- model: this.model,
- method: method,
- domain_id: null,
- context_id: 1,
- args: args || []
- }, callback, error_callback);
- },
- /**
- * Fetches the "readable name" for records, based on intrinsic rules
- *
- * @param {Array} ids
- * @param {Function} callback
- * @returns {$.Deferred}
- */
- name_get: function(ids, callback) {
- return this.call_and_eval('name_get', [ids, this.get_context()], null, 1, callback);
- },
- /**
- *
- * @param {String} name name to perform a search for/on
- * @param {Array} [domain=[]] filters for the objects returned, OpenERP domain
- * @param {String} [operator='ilike'] matching operator to use with the provided name value
- * @param {Number} [limit=100] maximum number of matches to return
- * @param {Function} callback function to call with name_search result
- * @returns {$.Deferred}
- */
- name_search: function (name, domain, operator, limit, callback) {
- return this.call_and_eval('name_search',
- [name || '', domain || false, operator || 'ilike', this.get_context(), limit || 100],
- 1, 3, callback);
- },
- /**
- * @param name
- * @param callback
- */
- name_create: function(name, callback) {
- return this.call_and_eval('name_create', [name, this.get_context()], null, 1, callback);
- },
- exec_workflow: function (id, signal, callback) {
- return this.rpc('/base/dataset/exec_workflow', {
- model: this.model,
- id: id,
- signal: signal
- }, callback);
- },
- get_context: function(request_context) {
- if (request_context) {
- return new openerp.base.CompoundContext(this.context, request_context);
- }
- return this.context;
- }
-});
-openerp.base.DataSetStatic = openerp.base.DataSet.extend({
- init: function(parent, model, context, ids) {
- this._super(parent, model, context);
- // all local records
- this.ids = ids || [];
- },
- read_slice: function (fields, options, callback) {
- // TODO remove fields from options
- var self = this,
- offset = options.offset || 0,
- limit = options.limit || false,
- fields = fields || false;
- var end_pos = limit && limit !== -1 ? offset + limit : undefined;
- return this.read_ids(this.ids.slice(offset, end_pos), fields, callback);
- },
- set_ids: function (ids) {
- this.ids = ids;
- if (this.index !== null) {
- this.index = this.index <= this.ids.length - 1 ?
- this.index : (this.ids.length > 0 ? this.length - 1 : 0);
- }
- },
- unlink: function(ids) {
- this.on_unlink(ids);
- return $.Deferred().resolve({result: true});
- },
- on_unlink: function(ids) {
- this.set_ids(_.without.apply(null, [this.ids].concat(ids)));
- }
-});
-openerp.base.DataSetSearch = openerp.base.DataSet.extend({
- /**
- * @constructs
- *
- * @param {Object} parent
- * @param {String} model
- * @param {Object} context
- * @param {Array} domain
- */
- init: function(parent, model, context, domain) {
- this._super(parent, model, context);
- this.domain = domain || [];
- this._sort = [];
- this.offset = 0;
- // subset records[offset:offset+limit]
- // is it necessary ?
- this.ids = [];
- },
- /**
- * Read a slice of the records represented by this DataSet, based on its
- * domain and context.
- *
- * @params {Object} options
- * @param {Array} [options.fields] fields to read and return, by default all fields are returned
- * @param {Object} [options.context] context data to add to the request payload, on top of the DataSet's own context
- * @param {Array} [options.domain] domain data to add to the request payload, ANDed with the dataset's domain
- * @param {Number} [options.offset=0] The index from which selected records should be returned
- * @param {Number} [options.limit=null] The maximum number of records to return
- * @param {Function} callback function called with read_slice result
- * @returns {$.Deferred}
- */
- read_slice: function (fields, options, callback) {
- var self = this;
- var options = options || {};
- var offset = options.offset || 0;
- return this.rpc('/base/dataset/search_read', {
- model: this.model,
- fields: fields || false,
- domain: this.get_domain(options.domain),
- context: this.get_context(options.context),
- sort: this.sort(),
- offset: offset,
- limit: options.limit || false
- }, function (result) {
- self.ids = result.ids;
- self.offset = offset;
- if (callback) {
- callback(result.records);
- }
- });
- },
- get_domain: function (other_domain) {
- if (other_domain) {
- return new openerp.base.CompoundDomain(this.domain, other_domain);
- }
- return this.domain;
- },
- /**
- * Reads or changes sort criteria on the dataset.
- *
- * If not provided with any argument, serializes the sort criteria to
- * an SQL-like form usable by OpenERP's ORM.
- *
- * If given a field, will set that field as first sorting criteria or,
- * if the field is already the first sorting criteria, will reverse it.
- *
- * @param {String} [field] field to sort on, reverses it (toggle from ASC to DESC) if already the main sort criteria
- * @param {Boolean} [force_reverse=false] forces inserting the field as DESC
- * @returns {String|undefined}
- */
- sort: function (field, force_reverse) {
- if (!field) {
- return openerp.base.serialize_sort(this._sort);
- }
- var reverse = force_reverse || (this._sort[0] === field);
- this._sort.splice.apply(
- this._sort, [0, this._sort.length].concat(
- _.without(this._sort, field, '-' + field)));
-
- this._sort.unshift((reverse ? '-' : '') + field);
- return undefined;
- },
- unlink: function(ids, callback, error_callback) {
- var self = this;
- return this._super(ids, function(result) {
- self.ids = _.without.apply(_, [self.ids].concat(ids));
- if (this.index !== null) {
- self.index = self.index <= self.ids.length - 1 ?
- self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
- }
- if (callback)
- callback(result);
- }, error_callback);
- }
-});
-openerp.base.BufferedDataSet = openerp.base.DataSetStatic.extend({
- virtual_id_prefix: "one2many_v_id_",
- virtual_id_regex: /one2many_v_id_.*/,
- debug_mode: true,
- init: function() {
- this._super.apply(this, arguments);
- this.reset_ids([]);
- },
- create: function(data, callback, error_callback) {
- var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data};
- this.to_create.push(cached);
- this.cache.push(cached);
- var to_return = $.Deferred().then(callback);
- to_return.resolve({result: cached.id});
- return to_return.promise();
- },
- write: function (id, data, callback) {
- var self = this;
- var record = _.detect(this.to_create, function(x) {return x.id === id;});
- record = record || _.detect(this.to_write, function(x) {return x.id === id;});
- var dirty = false;
- if (record) {
- for (k in data) {
- if (record.values[k] === undefined || record.values[k] !== data[k]) {
- dirty = true;
- break;
- }
- }
- $.extend(record.values, data);
- } else {
- dirty = true;
- record = {id: id, values: data};
- self.to_write.push(record);
- }
- var cached = _.detect(this.cache, function(x) {return x.id === id;});
- $.extend(cached.values, record.values);
- if (dirty)
- this.on_change();
- var to_return = $.Deferred().then(callback);
- to_return.resolve({result: true});
- return to_return.promise();
- },
- unlink: function(ids, callback, error_callback) {
- var self = this;
- _.each(ids, function(id) {
- if (! _.detect(self.to_create, function(x) { return x.id === id; })) {
- self.to_delete.push({id: id})
- }
- });
- this.to_create = _.reject(this.to_create, function(x) { return _.include(ids, x.id);});
- this.to_write = _.reject(this.to_write, function(x) { return _.include(ids, x.id);});
- this.cache = _.reject(this.cache, function(x) { return _.include(ids, x.id);});
- this.set_ids(_.without.apply(_, [this.ids].concat(ids)));
- this.on_change();
- var to_return = $.Deferred().then(callback);
- setTimeout(function () {to_return.resolve({result: true});}, 0);
- return to_return.promise();
- },
- reset_ids: function(ids) {
- this.set_ids(ids);
- this.to_delete = [];
- this.to_create = [];
- this.to_write = [];
- this.cache = [];
- this.delete_all = false;
- },
- on_change: function() {},
- read_ids: function (ids, fields, callback) {
- var self = this;
- var to_get = [];
- _.each(ids, function(id) {
- var cached = _.detect(self.cache, function(x) {return x.id === id;});
- var created = _.detect(self.to_create, function(x) {return x.id === id;});
- if (created) {
- _.each(fields, function(x) {if (cached.values[x] === undefined) cached.values[x] = false;});
- } else {
- if (!cached || !_.all(fields, function(x) {return cached.values[x] !== undefined}))
- to_get.push(id);
- }
- });
- var completion = $.Deferred().then(callback);
- var return_records = function() {
- var records = _.map(ids, function(id) {
- return _.extend({}, _.detect(self.cache, function(c) {return c.id === id;}).values, {"id": id});
- });
- if (self.debug_mode) {
- if (_.include(records, undefined)) {
- throw "Record not correctly loaded";
- }
- }
- setTimeout(function () {completion.resolve(records);}, 0);
- }
- if(to_get.length > 0) {
- var rpc_promise = this._super(to_get, fields, function(records) {
- _.each(records, function(record, index) {
- var id = to_get[index];
- var cached = _.detect(self.cache, function(x) {return x.id === id;});
- if (!cached) {
- self.cache.push({id: id, values: record});
- } else {
- // I assume cache value is prioritary
- _.defaults(cached.values, record);
- }
- });
- return_records();
- });
- $.when(rpc_promise).fail(function() {completion.reject();});
- } else {
- return_records();
- }
- return completion.promise();
- }
-});
-openerp.base.ReadOnlyDataSetSearch = openerp.base.DataSetSearch.extend({
- create: function(data, callback, error_callback) {
- this.on_create(data);
- var to_return = $.Deferred().then(callback);
- setTimeout(function () {to_return.resolve({"result": undefined});}, 0);
- return to_return.promise();
- },
- on_create: function(data) {},
- write: function (id, data, callback) {
- this.on_write(id, data);
- var to_return = $.Deferred().then(callback);
- setTimeout(function () {to_return.resolve({"result": true});}, 0);
- return to_return.promise();
- },
- on_write: function(id, data) {},
- unlink: function(ids, callback, error_callback) {
- this.on_unlink(ids);
- var to_return = $.Deferred().then(callback);
- setTimeout(function () {to_return.resolve({"result": true});}, 0);
- return to_return.promise();
- },
- on_unlink: function(ids) {}
-});
-
-openerp.base.CompoundContext = openerp.base.Class.extend({
- init: function () {
- this.__ref = "compound_context";
- this.__contexts = [];
- this.__eval_context = null;
- var self = this;
- _.each(arguments, function(x) {
- self.add(x);
- });
- },
- add: function (context) {
- this.__contexts.push(context);
- return this;
- },
- set_eval_context: function (eval_context) {
- this.__eval_context = eval_context;
- return this;
- },
- get_eval_context: function () {
- return this.__eval_context;
- }
-});
-
-openerp.base.CompoundDomain = openerp.base.Class.extend({
- init: function () {
- this.__ref = "compound_domain";
- this.__domains = [];
- this.__eval_context = null;
- var self = this;
- _.each(arguments, function(x) {
- self.add(x);
- });
- },
- add: function(domain) {
- this.__domains.push(domain);
- return this;
- },
- set_eval_context: function(eval_context) {
- this.__eval_context = eval_context;
- return this;
- },
- get_eval_context: function() {
- return this.__eval_context;
- }
-});
-};
-
-// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: