[ADD] basics for smarter collections to back the listview and its components
bzr revid: xmo@openerp.com-20110817085532-4chvix1odshuebvc
This commit is contained in:
parent
ed9db7c2c7
commit
4ce473b8dc
|
@ -10,6 +10,9 @@ openerp.base.core = function(openerp) {
|
|||
var initializing = false,
|
||||
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
// The base Class implementation (does nothing)
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
openerp.base.Class = function(){};
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
|
|
|
@ -1179,7 +1179,164 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @extends openerp.base.Class
|
||||
*/
|
||||
var Events = {
|
||||
/**
|
||||
* @param {String} event event to listen to on the current object, null for all events
|
||||
* @param {Function} handler event handler to bind to the relevant event
|
||||
* @returns this
|
||||
*/
|
||||
bind: function (event, handler) {
|
||||
var calls = this['_callbacks'] || (this._callbacks = {});
|
||||
|
||||
if (event in calls) {
|
||||
calls[event].push(handler);
|
||||
} else {
|
||||
calls[event] = [handler];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* @param {String} event
|
||||
* @returns this
|
||||
*/
|
||||
trigger: function (event) {
|
||||
var calls;
|
||||
if (!(calls = this._callbacks)) { return this; }
|
||||
var callbacks = (calls[event] || []).concat(calls[null] || []);
|
||||
for(var i=0, length=callbacks.length; i<length; ++i) {
|
||||
callbacks[i].apply(this, arguments);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
};
|
||||
var Record = openerp.base.Class.extend(/** @lends Record# */{
|
||||
/**
|
||||
* @constructs
|
||||
* @extends openerp.base.Class
|
||||
* @borrows Events#bind as this.bind
|
||||
* @borrows Events#trigger as this.trigger
|
||||
* @param {Object} [data]
|
||||
*/
|
||||
init: function (data) {
|
||||
this.data = data || {};
|
||||
},
|
||||
/**
|
||||
* @param {String} key
|
||||
* @returns {Object}
|
||||
*/
|
||||
get: function (key) {
|
||||
return this.data[key];
|
||||
},
|
||||
/**
|
||||
* @param key
|
||||
* @param value
|
||||
* @returns {Record}
|
||||
*/
|
||||
set: function (key, value) {
|
||||
this.data[key] = value;
|
||||
this.trigger('change:' + key, this, value);
|
||||
this.trigger('change', this);
|
||||
return this;
|
||||
}
|
||||
});
|
||||
Record.include(Events);
|
||||
var Collection = openerp.base.Class.extend(/** @lends Collection# */{
|
||||
/**
|
||||
* @constructs
|
||||
* @extends openerp.base.Class
|
||||
* @borrows Events#bind as this.bind
|
||||
* @borrows Events#trigger as this.trigger
|
||||
* @param {Array} [records] records to initialize the collection with
|
||||
* @param {Object} [options]
|
||||
*/
|
||||
init: function (records, options) {
|
||||
options = options || {};
|
||||
_.bindAll(this, '_onRecordEvent');
|
||||
this.records = [];
|
||||
this._byId = {};
|
||||
this._proxies = {};
|
||||
this._key = options.key;
|
||||
this._parent = options.parent;
|
||||
|
||||
if (records) {
|
||||
this.add(records);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {Object|Array} record
|
||||
* @returns this
|
||||
*/
|
||||
add: function (record) {
|
||||
var records = record instanceof Array ? record : [record];
|
||||
|
||||
for(var i=0, length=records.length; i<length; ++i) {
|
||||
var instance = (records[i] instanceof Record) ? records[i] : new Record(records[i]);
|
||||
instance.bind(null, this._onRecordEvent);
|
||||
this._byId[instance.get('id')] = instance;
|
||||
this.records.push(instance);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a record by its index in the collection, can also take a group if
|
||||
* the collection is not degenerate
|
||||
*
|
||||
* @param {Number} index
|
||||
* @param {String} [group]
|
||||
* @returns {Record|undefined}
|
||||
*/
|
||||
at: function (index, group) {
|
||||
if (group) {
|
||||
var groups = group.split('.');
|
||||
return this._proxies[groups[0]].at(index, groups.join('.'));
|
||||
}
|
||||
return this.records[index];
|
||||
},
|
||||
/**
|
||||
* Get a record by its database id
|
||||
*
|
||||
* @param {Number} id
|
||||
* @returns {Record|undefined}
|
||||
*/
|
||||
get: function (id) {
|
||||
if (!_(this._proxies).isEmpty()) {
|
||||
var record = null;
|
||||
_(this._proxies).detect(function (proxy) {
|
||||
return record = proxy.get(id);
|
||||
});
|
||||
return record;
|
||||
}
|
||||
return this._byId[id];
|
||||
},
|
||||
/**
|
||||
* Builds a proxy (insert/retrieve) to a subtree of the collection, by
|
||||
* the subtree's group
|
||||
*
|
||||
* @param {String} section group path section
|
||||
* @returns {Collection}
|
||||
*/
|
||||
proxy: function (section) {
|
||||
return this._proxies[section] = new Collection(null, {
|
||||
parent: this,
|
||||
key: section
|
||||
}).bind(null, this._onRecordEvent);
|
||||
},
|
||||
|
||||
_onRecordEvent: function (event, record, options) {
|
||||
this.trigger.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
Collection.include(Events);
|
||||
openerp.base.list = {
|
||||
Events: Events,
|
||||
Record: Record,
|
||||
Collection: Collection
|
||||
}
|
||||
};
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
$(document).ready(function () {
|
||||
var openerp,
|
||||
create = function (o) {
|
||||
if (typeof Object.create === 'function') {
|
||||
return Object.create(o);
|
||||
}
|
||||
function Cls() {}
|
||||
Cls.prototype = o;
|
||||
return new Cls;
|
||||
};
|
||||
module('list-events', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init();
|
||||
window.openerp.base.list(openerp);
|
||||
}
|
||||
});
|
||||
test('Simple event triggering', function () {
|
||||
var e = create(openerp.base.list.Events), passed = false;
|
||||
e.bind('foo', function () { passed = true; });
|
||||
e.trigger('foo');
|
||||
ok(passed);
|
||||
});
|
||||
test('Bind all', function () {
|
||||
var e = create(openerp.base.list.Events), event = null;
|
||||
e.bind(null, function (ev) { event = ev; });
|
||||
e.trigger('foo');
|
||||
strictEqual(event, 'foo');
|
||||
});
|
||||
test('Propagate trigger params', function () {
|
||||
var e = create(openerp.base.list.Events), p = false;
|
||||
e.bind(null, function (_, param) { p = param });
|
||||
e.trigger('foo', true);
|
||||
strictEqual(p, true)
|
||||
});
|
||||
test('Bind multiple callbacks', function () {
|
||||
var e = create(openerp.base.list.Events), count;
|
||||
e.bind('foo', function () { count++; })
|
||||
.bind('bar', function () { count++; })
|
||||
.bind(null, function () { count++; })
|
||||
.bind('foo', function () { count++; })
|
||||
.bind(null, function () { count++; })
|
||||
.bind(null, function () { count++; });
|
||||
|
||||
count = 0;
|
||||
e.trigger('foo');
|
||||
strictEqual(count, 5);
|
||||
|
||||
count = 0;
|
||||
e.trigger('bar');
|
||||
strictEqual(count, 4);
|
||||
|
||||
count = 0;
|
||||
e.trigger('baz');
|
||||
strictEqual(count, 3);
|
||||
});
|
||||
test('Mixin events', function () {
|
||||
var cls = openerp.base.Class.extend({
|
||||
method: function () { this.trigger('e'); }
|
||||
});
|
||||
cls.include(openerp.base.list.Events);
|
||||
var instance = new cls, triggered = false;
|
||||
|
||||
instance.bind('e', function () { triggered = true; });
|
||||
instance.method();
|
||||
|
||||
ok(triggered);
|
||||
});
|
||||
|
||||
module('list-records', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init();
|
||||
window.openerp.base.list(openerp);
|
||||
}
|
||||
});
|
||||
test('Basic record initialization', function () {
|
||||
var r = new openerp.base.list.Record({qux: 3});
|
||||
r.set('foo', 1);
|
||||
r.set('bar', 2);
|
||||
strictEqual(r.get('foo'), 1);
|
||||
strictEqual(r.get('bar'), 2);
|
||||
strictEqual(r.get('qux'), 3);
|
||||
});
|
||||
test('Change all the things', function () {
|
||||
var r = new openerp.base.list.Record(), changed = false, field;
|
||||
r.bind('change', function () { changed = true; });
|
||||
r.bind(null, function (e) { field = field || e.split(':')[1]});
|
||||
r.set('foo', 1);
|
||||
strictEqual(r.get('foo'), 1);
|
||||
ok(changed);
|
||||
strictEqual(field, 'foo');
|
||||
});
|
||||
test('Change single field', function () {
|
||||
var r = new openerp.base.list.Record(), changed = 0;
|
||||
r.bind('change:foo', function () { changed++; });
|
||||
r.set('foo', 1);
|
||||
r.set('bar', 1);
|
||||
strictEqual(r.get('foo'), 1);
|
||||
strictEqual(r.get('bar'), 1);
|
||||
strictEqual(changed, 1);
|
||||
});
|
||||
|
||||
module('list-collections-degenerate', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init();
|
||||
window.openerp.base.list(openerp);
|
||||
}
|
||||
});
|
||||
test('Fetch from collection', function () {
|
||||
var c = new openerp.base.list.Collection();
|
||||
c.add({id: 1, value: 2});
|
||||
c.add({id: 2, value: 3});
|
||||
c.add({id: 3, value: 5});
|
||||
c.add({id: 4, value: 7});
|
||||
var r = c.at(2), r2 = c.get(1);
|
||||
|
||||
ok(r instanceof openerp.base.list.Record);
|
||||
strictEqual(r.get('id'), 3);
|
||||
strictEqual(r.get('value'), 5);
|
||||
|
||||
ok(r2 instanceof openerp.base.list.Record);
|
||||
strictEqual(r2.get('id'), 1);
|
||||
strictEqual(r2.get('value'), 2);
|
||||
});
|
||||
test('Events propagation', function () {
|
||||
var values = [];
|
||||
var c = new openerp.base.list.Collection([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
{id: 3, value: 20}
|
||||
]);
|
||||
c.bind('change:value', function (e, record, value) {
|
||||
values.push(value);
|
||||
});
|
||||
c.get(1).set('value', 6);
|
||||
c.get(2).set('value', 11);
|
||||
c.get(3).set('value', 21);
|
||||
deepEqual(values, [6, 11, 21]);
|
||||
});
|
||||
test('BTree', function () {
|
||||
var root = new openerp.base.list.Collection(),
|
||||
c = root.proxy('admin'),
|
||||
total = 0;
|
||||
c.add({id: 1, name: "Administrator", login: 'admin'});
|
||||
c.add({id: 3, name: "Demo", login: 'demo'});
|
||||
root.bind('change:wealth', function () {
|
||||
total = (root.get(1).get('wealth') || 0) + (root.get(3).get('wealth') || 0);
|
||||
});
|
||||
|
||||
strictEqual(total, 0);
|
||||
c.at(0).set('wealth', 42);
|
||||
strictEqual(total, 42);
|
||||
c.at(1).set('wealth', 5);
|
||||
strictEqual(total, 47);
|
||||
});
|
||||
});
|
|
@ -40,4 +40,5 @@
|
|||
<script type="text/javascript" src="/base/static/test/class.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/registry.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/form.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/list-utils.js"></script>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue