Commit c476fa75 by Иван Кубота

set\get subproperties of store

parent 221fb797
......@@ -6,44 +6,98 @@ const isEqual = function(original, fn) {
const Store = function(cfg) {
Observable.call(this);
this._props = cfg || {};
};
},
isObject = function(obj) {
return typeof obj === 'object' && obj !== null;
};
const recursiveWalk = function(path, pointer, key, list) {
if(typeof pointer[key] === 'object'){
for(let subKey in pointer[key]){
if(typeof pointer[key][subKey] === 'object'){
list.push( [ path.concat( key, subKey ).join('.'), void 0 ] );
}
recursiveWalk(path.concat(key), pointer[key], subKey, list);
}
}else{
list.push( [ path.concat( key ).join('.'), void 0 ] );
}
},
recursiveSet = function(path, pointer, key, val, list){
let subKey,i;
if( isObject(val) ){
if(Array.isArray(val)){
if(!Array.isArray(pointer[key])){
pointer[ key ] = [];
list.push([path.concat(key).join( '.' ), pointer[ key ]])
}
}else{
if(!isObject(pointer[ key ])){
pointer[ key ] = {};
list.push([path.concat(key).join( '.' ), pointer[ key ]])
}
}
for(subKey in val){
recursiveSet( path.concat( key ), pointer[ key ], subKey, val[subKey], list );
}
for( subKey in pointer[ key ] ){
if( !val.hasOwnProperty( subKey ) ){
// remove
recursiveWalk( path.concat( key ), pointer[key], subKey, list );
delete pointer[ key ][ subKey ];
}
}
}else{
if( val !== pointer[ key ] ){
pointer[ key ] = val;
list.push( [ path.concat(key).join( '.' ), pointer[ key ] ] );
}
}
};
Store.prototype = {
experimental: false,
_set: function(keys, val, pointer, path){
let i, _i;
let key = keys[path.length];
_set: function(keys, val, pointer, changeList) {
changeList = changeList || [];
let parent, i, _i;
for(i=0, _i = keys.length - 1; i < _i; i++){
let key = keys[i];
parent = pointer;
if(pointer[key] !== val){
// TODO make it work
if(typeof val === 'object' && key in pointer){
this._set(keys, val[key], pointer[key], path.concat(key));
if(key in pointer){
pointer = parent[key];
if(!isObject(pointer)){
pointer = parent[key] = {};
changeList.push([keys.slice(0, i).join( '.' ), parent[key]]);
}
}else{
pointer = parent[key] = {};
changeList.push([keys.slice(0, i+1).join( '.' ), parent[key]]);
}
pointer[ key ] = val;
this.fire( 'change', key, val );
this.fire( key, val );
}
let key = keys[i];
recursiveSet(keys.slice(0, keys.length - 1), pointer, key, val, changeList);
},
set: function(key, val) {
if(!this.experimental)
if(this._props[key] !== val){
this._props[ key ] = val;
this.fire( 'change', key, val );
this.fire( key, val );
}
return this._set(
set: function(key, val) {
let changeList = [];
this._set(
typeof key === 'string' ? key.split('.') : key,
val,
this._props,
[]
changeList
);
for( let i = changeList.length; i; ){
const changeListElement = changeList[ --i ];
this.fire('change', changeListElement[0], changeListElement[1]);
this.fire(changeListElement[0], changeListElement[1]);
}
return;
},
get: function(key, returnLastStore) {
if(!this.experimental)
return this._props[key];
key = typeof key === 'string' ? key.split('.') : key;
let ref = this,
......
......@@ -3,7 +3,7 @@ export default D.declare('view.page.Account', ()=>
<div>
Account Page
<div>
Hello, {_=>store.sub('account', account=> _(account.name))}
Hello, {_=>store.sub('account.name', account=> _(account))}
</div>
</div>
)
......@@ -23,6 +23,158 @@ describe('store', function() {
assert.equal(s.get('a.b.d'), 20);
s.set('a.b', null);
assert.equal(s.get('a.b.d'), void 0);
});
it('should fire changes for simple values', function () {
const s = new Store({a:4, b: 5, c: 6});
let list;
s.on('change', function(path, val) {
list.push({path, val})
});
list = [];
s.set('a', 4);
assert.equal(list.length, 0);
list = [];
s.set('b', 4);
assert.equal(list.length, 1);
assert.equal(list[0].path, 'b');
assert.equal(list[0].val, 4);
list = [];
s.set('c', {kk: 2});
assert.equal(list.length, 2);
assert.equal(list[0].path, 'c.kk');
assert.equal(list[0].val, 2);
assert.equal(list[1].path, 'c');
assert.deepEqual(list[1].val, {kk: 2});
});
const logList = function(list) {
console.log(list.map(({path, val})=>`${path} > ${JSON.stringify(val)}`).join('\n'))
};
const fixList = function(list) {
console.log(`assert.equal(list.length, ${list.length});`);
console.log(list.map(
({path, val}, n)=>
`assert.equal(list[${n}].path, ${JSON.stringify(path)});
assert.deepEqual(list[${n}].val, ${JSON.stringify(val)});
`).join('\n')
)
};
it('should fire changes for complex values', function () {
const s = new Store({});
let list;
s.on('change', function(path, val) {
list.push({path, val})
});
list = [];
s.set('a.b.c', 33);
assert.equal(list.length, 3);
assert.equal(list[0].path, "a.b.c");
assert.deepEqual(list[0].val, 33);
assert.equal(list[1].path, "a.b");
assert.deepEqual(list[1].val, {"c":33});
assert.equal(list[2].path, "a");
assert.deepEqual(list[2].val, {"b":{"c":33}});
list = [];
s.set('a.b', {c:12, d: 20});
assert.equal(list.length, 2);
assert.equal(list[0].path, "a.b.d");
assert.deepEqual(list[0].val, 20);
assert.equal(list[1].path, "a.b.c");
assert.deepEqual(list[1].val, 12);
list = [];
s.set('a.b', null);
assert.equal(list.length, 1);
assert.equal(list[0].path, "a.b");
assert.deepEqual(list[0].val, null);
list = [];
s.set('a.b', {c:12, d: 20});
assert.equal(list.length, 3);
assert.equal(list[0].path, "a.b.d");
assert.deepEqual(list[0].val, 20);
assert.equal(list[1].path, "a.b.c");
assert.deepEqual(list[1].val, 12);
assert.equal(list[2].path, "a.b");
assert.deepEqual(list[2].val, {"c":12,"d":20});
list = [];
s.set('a.b', {x: {y:3}});
assert.equal(list.length, 4);
assert.equal(list[0].path, "a.b.d");
assert.deepEqual(list[0].val, undefined);
assert.equal(list[1].path, "a.b.c");
assert.deepEqual(list[1].val, undefined);
assert.equal(list[2].path, "a.b.x.y");
assert.deepEqual(list[2].val, 3);
assert.equal(list[3].path, "a.b.x");
assert.deepEqual(list[3].val, {"y":3});
//fixList(list)
});
it('should fire changes for even more complex values', function () {
const s = new Store({});
let list = [];
s.on('change', function(path, val) {
list.push({path, val})
});
let startVal;
s.set('a.b', startVal = {c:12, d: {e:1, f: 2, g: [3, 4, {h: 5}]}});
assert.deepEqual(s._props, {a:{b: startVal}})
list = [];
s.set('a.b', {c: 12, f: 22});
assert.equal(list.length, 8);
assert.equal(list[0].path, "a.b.d.g.2.h");
assert.deepEqual(list[0].val, undefined);
assert.equal(list[1].path, "a.b.d.g.2");
assert.deepEqual(list[1].val, undefined);
assert.equal(list[2].path, "a.b.d.g.1");
assert.deepEqual(list[2].val, undefined);
assert.equal(list[3].path, "a.b.d.g.0");
assert.deepEqual(list[3].val, undefined);
assert.equal(list[4].path, "a.b.d.g");
assert.deepEqual(list[4].val, undefined);
assert.equal(list[5].path, "a.b.d.f");
assert.deepEqual(list[5].val, undefined);
assert.equal(list[6].path, "a.b.d.e");
assert.deepEqual(list[6].val, undefined);
assert.equal(list[7].path, "a.b.f");
assert.deepEqual(list[7].val, 22);
console.log(JSON.stringify(s._props))
})
});
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment