From db7573384800fdea71bad45cd980237eeff5cccb Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 7 Nov 2013 12:20:17 +0100 Subject: [FIX] rare race condition in BufferedDataset lp bug: https://launchpad.net/bugs/1248531 fixed bzr revid: nicolas.vanhoren@openerp.com-20131107112017-7omd01ocvnbzx9m6 --- addons/web/static/src/js/data.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index f4e1b5a9c57..fe572dffbcb 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -780,6 +780,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ this._super.apply(this, arguments); this.reset_ids([]); this.last_default_get = {}; + this.running_reads = []; }, default_get: function(fields, options) { var self = this; @@ -846,6 +847,9 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ this.to_write = []; this.cache = []; this.delete_all = false; + _.each(_.clone(this.running_reads), function(el) { + el.reject(); + }); }, read_ids: function (ids, fields, options) { var self = this; @@ -861,7 +865,6 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ to_get.push(id); } }); - var completion = $.Deferred(); var return_records = function() { var records = _.map(ids, function(id) { return _.extend({}, _.detect(self.cache, function(c) {return c.id === id;}).values, {"id": id}); @@ -896,10 +899,20 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ }, 0); }); } - completion.resolve(records); + return $.when(records); }; if(to_get.length > 0) { - var rpc_promise = this._super(to_get, fields, options).done(function(records) { + var def = $.Deferred(); + self.running_reads.push(def); + def.always(function() { + self.running_reads = _.without(self.running_reads, def); + }); + this._super(to_get, fields, options).then(function() { + def.resolve.apply(def, arguments); + }, function() { + def.reject.apply(def, arguments); + }); + return def.then(function(records) { _.each(records, function(record, index) { var id = to_get[index]; var cached = _.detect(self.cache, function(x) {return x.id === id;}); @@ -910,13 +923,11 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ cached.values = _.defaults(_.clone(cached.values), record); } }); - return_records(); + return return_records(); }); - $.when(rpc_promise).fail(function() {completion.reject();}); } else { - return_records(); + return return_records(); } - return completion.promise(); }, /** * Invalidates caching of a record in the dataset to ensure the next read -- cgit v1.2.3 From 3213ad4dddfee0333b66076b6955c7464c6421c1 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 5 Nov 2013 13:18:43 +0100 Subject: [FIX] web: instance.web.DataSetSearch.get_domain() returns the domain. lp bug: https://launchpad.net/bugs/1195631 fixed bzr revid: chs@openerp.com-20131105121843-rqplhk83fczxww0t --- addons/web/static/src/js/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index e535be294aa..bb658a27bf6 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -724,7 +724,7 @@ instance.web.DataSetSearch = instance.web.DataSet.extend({ }); }, get_domain: function (other_domain) { - this._model.domain(other_domain); + return this._model.domain(other_domain); }, alter_ids: function (ids) { this._super(ids); -- cgit v1.2.3 From 1e4b2695d59b9d51cc1e0b76f925aa4f638436f4 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 14 Nov 2013 15:26:39 +0100 Subject: [MERGE][FIX] web: fix race condition in BufferedDataset. Backport of saas-2 commit 3867 nicolas.vanhoren@openerp.com-20131107112017-7omd01ocvnbzx9m6 lp bug: https://launchpad.net/bugs/1248531 fixed bzr revid: chs@openerp.com-20131114142639-ng7wzfjwvvel2nhv --- addons/web/static/src/js/data.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index bb658a27bf6..d497cf25343 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -761,6 +761,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ this._super.apply(this, arguments); this.reset_ids([]); this.last_default_get = {}; + this.running_reads = []; }, default_get: function(fields, options) { var self = this; @@ -827,6 +828,9 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ this.to_write = []; this.cache = []; this.delete_all = false; + _.each(_.clone(this.running_reads), function(el) { + el.reject(); + }); }, read_ids: function (ids, fields, options) { var self = this; @@ -842,7 +846,6 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ to_get.push(id); } }); - var completion = $.Deferred(); var return_records = function() { var records = _.map(ids, function(id) { return _.extend({}, _.detect(self.cache, function(c) {return c.id === id;}).values, {"id": id}); @@ -877,10 +880,20 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ }, 0); }); } - completion.resolve(records); + return $.when(records); }; if(to_get.length > 0) { - var rpc_promise = this._super(to_get, fields, options).done(function(records) { + var def = $.Deferred(); + self.running_reads.push(def); + def.always(function() { + self.running_reads = _.without(self.running_reads, def); + }); + this._super(to_get, fields, options).then(function() { + def.resolve.apply(def, arguments); + }, function() { + def.reject.apply(def, arguments); + }); + return def.then(function(records) { _.each(records, function(record, index) { var id = to_get[index]; var cached = _.detect(self.cache, function(x) {return x.id === id;}); @@ -891,13 +904,11 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ cached.values = _.defaults(_.clone(cached.values), record); } }); - return_records(); + return return_records(); }); - $.when(rpc_promise).fail(function() {completion.reject();}); } else { - return_records(); + return return_records(); } - return completion.promise(); }, /** * Invalidates caching of a record in the dataset to ensure the next read -- cgit v1.2.3 From 0a76694628e0f10e4ae2a809f3a2b08d899ffa06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Fri, 22 Nov 2013 15:00:48 +0100 Subject: [IMP] webclient: Introducing SimpleIndexedDB, a key value wrapper around IndexedDB bzr revid: fva@openerp.com-20131122140048-goaplzrx26jvcmmu --- addons/web/static/src/js/data.js | 151 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 04f657d91f7..76164657d84 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -1090,6 +1090,157 @@ instance.web.DropMisordered = instance.web.Class.extend({ } }); +instance.web.SimpleIndexedDB = instance.web.Class.extend({ + /** + * A simple wrapper around IndexedDB that provides an asynchronous + * localStorage-like Key-Value api that persists between browser + * restarts. + * + * It will not work if the browser doesn't support a recent version + * of IndexedDB, and it may fail if the user refuses db access. + * + * All instances of SimpleIndexedDB will by default refer to the same + * IndexedDB database, if you want to pick another one, use the 'name' + * option on instanciation. + */ + init: function(opts){ + var self = this; + var opts = opts || {}; + + this.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; + this.db = undefined; + this._ready = new $.Deferred(); + + if(this.indexedDB && this.indexedDB.open){ + var request = this.indexedDB.open( opts.name || "SimpleIndexedDB" ,1); + + request.onerror = function(event){ + self.db = null; + self._ready.reject(event.target.error); + }; + + request.onsuccess = function(event){ + self.db = request.result; + self._ready.resolve(); + }; + + request.onupgradeneeded = function(event){ + self.db = event.target.result; + + var objectStore = self.db.createObjectStore("keyvals", { keyPath:"key" }); + self._ready.resolve(); + }; + }else{ + this.db = null; + this._ready.reject({type:'UnknownError', message:'IndexedDB is not supported by your Browser'}); + } + }, + + /** + * returns true if the browser supports the necessary IndexedDB API + * (but doesn't tell if the db can be created, check ready() for that) + */ + isSupportedByBrowser: function(){ + return this.indexedDB && this.indexedDB.open; + }, + + /** + * returns a deferred that resolves when the db has been successfully + * initialized. done/failed callbacks are optional. + */ + ready: function(done,failed){ + this._ready.then(done,failed); + return this._ready.promise(); + }, + + /** + * fetches the value associated to 'key' in the db. if the key doesn't + * exists, it returns undefined. The returned value is provided as a + * deferred, or as the first parameter of the optional 'done' callback. + */ + getItem: function(key,done,failed){ + var self = this; + var def = new $.Deferred(); + def.then(done,failed); + + this._ready.then(function(){ + var request = self.db.transaction(["keyvals"],"readwrite") + .objectStore("keyvals") + .get(key); + + request.onsuccess = function(){ + def.resolve(request.result ? request.result.value : undefined); + }; + + request.onerror = function(event){ + def.reject(event.target.error); + }; + },function(){ + def.reject({type:'UnknownError', message:'Could not initialize the IndexedDB database'}); + }); + + return def.promise(); + }, + + /** + * Associates a value to 'key' in the db, overwriting previous value if + * necessary. Contrary to localStorage, the value is not limited to strings and + * can be any javascript object, even with cyclic references ! + * + * Be sure to check for failure as the user may refuse to have data localy stored. + */ + setItem: function(key,value,done,failed){ + var self = this; + var def = new $.Deferred(); + def.then(done,failed); + + this._ready.then(function(){ + var request = self.db.transaction(["keyvals"],"readwrite") + .objectStore("keyvals") + .put( {key:key, value:value} ); + + request.onsuccess = function(){ + def.resolve(); + }; + + request.onerror = function(event){ + def.reject(event.target.error); + }; + },function(){ + def.reject({type:'UnknownError', message:'Could not initialize the IndexedDB database'}); + }); + + return def.promise(); + }, + + /** + * Removes the value associated with 'key' from the db. + */ + removeItem: function(key,done,failed){ + var self = this; + var def = new $.Deferred(); + def.then(done,failed); + + this._ready.then(function(){ + var request = self.db.transaction(["keyvals"],"readwrite") + .objectStore("keyvals") + .delete(key); + + request.onsuccess = function(){ + def.resolve(); + }; + + request.onerror = function(event){ + def.reject(event.target.error); + }; + },function(){ + def.reject({type:'UnknownError', message:'Could not initialize the IndexedDB database'}); + }); + + return def.promise(); + }, +}); + })(); // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: -- cgit v1.2.3 From b3391cd7fef94c4e82b4330db37213c08740d055 Mon Sep 17 00:00:00 2001 From: "Mohammed Shekha (OpenERP)" Date: Tue, 3 Dec 2013 18:08:56 +0530 Subject: [FIX]Web: Fixed the issue of immediate update of many2one field when many2one object name has been changed from follow button popup, reloaded the record from database forcefull to update dataaset, do not call form-blur when follow button is clicked, also do not evict record when record is still not created. bzr revid: msh@openerp.com-20131203123856-gce4li1igo9k1mak --- addons/web/static/src/js/data.js | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index d497cf25343..e1290deac02 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -920,6 +920,15 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ * @param {Object} id record to remove from the BDS's cache */ evict_record: function (id) { + // Don't evict records which haven't yet been saved: there is no more + // recent data on the server (and there potentially isn't any data), + // and this breaks the assumptions of other methods (that the data + // for new and altered records is both in the cache and in the to_write + // or to_create collection) + if (_(this.to_create.concat(this.to_write)).find(function (record) { + return record.id === id; })) { + return; + } for(var i=0, len=this.cache.length; i Date: Wed, 22 Jan 2014 13:44:49 +0100 Subject: [FIX] makes the querygroup methods compatible with the 'field:interval' format of groupbys accepted by read_group bzr revid: ged@openerp.com-20140122124449-4nodai5vkoz3eryf --- addons/web/static/src/js/data.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 10ca5d74bd9..a2e3e53db3e 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -129,11 +129,14 @@ instance.web.Query = instance.web.Class.extend({ if (_.isEmpty(grouping) && !ctx['group_by_no_leaf']) { return null; } + var raw_fields = _.map(grouping.concat(this._fields || []), function (field) { + return (_.contains(field, ':')) ? field.split(':')[0] : field; + }); var self = this; return this._model.call('read_group', { groupby: grouping, - fields: _.uniq(grouping.concat(this._fields || [])), + fields: _.uniq(raw_fields), domain: this._model.domain(this._filter), context: ctx, offset: this._offset, @@ -233,12 +236,14 @@ instance.web.QueryGroup = instance.web.Class.extend({ var group_size = fixed_group[grouping_field + '_count'] || fixed_group.__count || 0; var leaf_group = fixed_group.__context.group_by.length === 0; + var raw_field = (_.contains(grouping_field, ':')) ? grouping_field.split(':')[0] : grouping_field; + this.attributes = { folded: !!(fixed_group.__fold), grouped_on: grouping_field, // if terminal group (or no group) and group_by_no_leaf => use group.__count length: group_size, - value: fixed_group[grouping_field], + value: fixed_group[raw_field], // A group is open-able if it's not a leaf in group_by_no_leaf mode has_children: !(leaf_group && fixed_group.__context['group_by_no_leaf']), -- cgit v1.2.3 From a482809cf90f35b00f420e30829ed1c06769649d Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 29 Jan 2014 10:23:59 +0100 Subject: [FIX] correctly compute the attribute 'length' in a query_group so that the list view properly display groups when grouped by 'date:interval' (addon web) bzr revid: ged@openerp.com-20140129092359-20kw6n3sxqobiqu5 --- addons/web/static/src/js/data.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index a2e3e53db3e..4a0807a727a 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -234,9 +234,9 @@ instance.web.QueryGroup = instance.web.Class.extend({ this.model = new instance.web.Model( model, fixed_group.__context, fixed_group.__domain); - var group_size = fixed_group[grouping_field + '_count'] || fixed_group.__count || 0; + var raw_field = grouping_field && grouping_field.split(':')[0]; + var group_size = fixed_group[raw_field + '_count'] || fixed_group.__count || 0; var leaf_group = fixed_group.__context.group_by.length === 0; - var raw_field = (_.contains(grouping_field, ':')) ? grouping_field.split(':')[0] : grouping_field; this.attributes = { folded: !!(fixed_group.__fold), -- cgit v1.2.3 From 8ed584d1ac3276429bd0b108d80dcd55c89b47cd Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Thu, 30 Jan 2014 16:37:00 +0100 Subject: [FIX] simplify a computation of raw_fields to make sure it doesn't crash (_.contains expects a list, and not a string) (addon web) bzr revid: ged@openerp.com-20140130153700-2lno0uefta93ex53 --- addons/web/static/src/js/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 4a0807a727a..78e3001d746 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -130,7 +130,7 @@ instance.web.Query = instance.web.Class.extend({ return null; } var raw_fields = _.map(grouping.concat(this._fields || []), function (field) { - return (_.contains(field, ':')) ? field.split(':')[0] : field; + return field.split(':')[0]; }); var self = this; -- cgit v1.2.3 From 409c3cfe9f1cdda1b8d9672fc3c0c246ed425894 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 13 Feb 2014 09:50:08 +0100 Subject: [FIX] data: _.find (prefered to older _.detect) may return undefined if no match and would trow an error when applying .values Instead returns undefined which is handled below. This does not solve the issue when records are not loaded properly but gives a better information on the reason. bzr revid: mat@openerp.com-20140213085008-pnq4r0ebfl072u78 --- addons/web/static/src/js/data.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index e1290deac02..abfb4c15347 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -848,7 +848,8 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ }); var return_records = function() { var records = _.map(ids, function(id) { - return _.extend({}, _.detect(self.cache, function(c) {return c.id === id;}).values, {"id": id}); + var c = _.find(self.cache, function(c) {return c.id === id;}); + return _.isUndefined(c) ? c : _.extend({}, c.values, {"id": id}); }); if (self.debug_mode) { if (_.include(records, undefined)) { -- cgit v1.2.3 From 2e831ab7c377408782ab96c303f6fa50884d76e4 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 18 Feb 2014 11:14:38 +0100 Subject: [IMP] data: skip read_ids call when got no id (opw 604099). This avoids making useless calls to to read the values of o2m fields when the read on a record already told us there was no ids. bzr revid: mat@openerp.com-20140218101438-yqim33cvtg6wt4mw --- addons/web/static/src/js/data.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index abfb4c15347..04b02294463 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -428,6 +428,9 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin, * @returns {$.Deferred} */ read_ids: function (ids, fields, options) { + if (_.isEmpty(ids)) + return $.Deferred().resolve([]); + options = options || {}; // TODO: reorder results to match ids list return this._model.call('read', -- cgit v1.2.3 From f29f1e6f049428e205dcadcb613857822e24c990 Mon Sep 17 00:00:00 2001 From: "Mohammed Shekha (OpenERP)" Date: Tue, 4 Mar 2014 16:36:59 +0530 Subject: [FIX]Fixed the issue of o2m sorting by column, m2o field does not give proper result for sorting because whole value of m2o [id, value] going to compare for sorting. bzr revid: msh@openerp.com-20140304110659-4uu38feetsjj0tt5 --- addons/web/static/src/js/data.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'addons/web/static/src/js/data.js') diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index abfb4c15347..e7dc81ef787 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -877,6 +877,10 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ sign = -1; field = field.slice(1); } + //m2o should be searched based on value[1] not based whole value(i.e. [id, value]) + if(_.isArray(a[field]) && a[field].length == 2 && _.isString(a[field][1])){ + return sign * compare(a[field][1], b[field][1]); + } return sign * compare(a[field], b[field]); }, 0); }); -- cgit v1.2.3