Commit 8c1c32e6 by Иван Кубота

build it all up

parent 299cebbf
...@@ -25,11 +25,15 @@ Store MUST notify all subscribers on each change ...@@ -25,11 +25,15 @@ Store MUST notify all subscribers on each change
Store MUST NOT notify subscribers if it does not change Store MUST NOT notify subscribers if it does not change
*/ */
const Store = function(cfg) { const Store = function(cfg, key) {
Observable.call(this); Observable.call(this);
this.events = new Observable(); this.events = new Observable();
this._props = cfg || {}; this._props = cfg || {};
}, this._key = key;
// SINGLETONS
this.arrays = {};
this.items = new WeakMap();
},
isObject = function(obj) { isObject = function(obj) {
// null is not an object. treat Date as primitive // null is not an object. treat Date as primitive
return typeof obj === 'object' && obj !== null && !(obj instanceof Date); return typeof obj === 'object' && obj !== null && !(obj instanceof Date);
...@@ -103,9 +107,13 @@ StoreParent.prototype = { ...@@ -103,9 +107,13 @@ StoreParent.prototype = {
}else{ }else{
return this.key; return this.key;
} }
},
getPointer: function() {
return this.parent._props[this.getKey()];
} }
}; };
Store.prototype = { Store.prototype = {
_key: null,
parent: null, parent: null,
setParent: function(parent, key, item){ setParent: function(parent, key, item){
this.parent = new StoreParent(parent, key, item); this.parent = new StoreParent(parent, key, item);
...@@ -117,15 +125,30 @@ Store.prototype = { ...@@ -117,15 +125,30 @@ Store.prototype = {
} }
return out; return out;
}, },
item: function(key, item){ item: function(key, refItem) {
let subStore = new Store(item?item:key); var item = refItem ? refItem : this.get(key);
var subStore = typeof item === 'object' ? this.items.get(item) : void 0;
if(subStore === void 0){
this.items.set(item, subStore = new Store(null, key));
subStore.setParent(this, key, item);
}
return subStore;
},
// TODO: TEST item in real project and remove this
item2: function(key, item){
let subStore = item ? new Store(item) : new Store(null, key);
subStore.setParent(this, key, item); subStore.setParent(this, key, item);
return subStore; return subStore;
}, },
array: function(key){ array: function(key){
// singletons
if(key in this.arrays)
return this.arrays[key];
let arrayStore = new ArrayStore(this.get(key)); let arrayStore = new ArrayStore(this.get(key));
arrayStore.setParent(this, key); arrayStore.setParent(this, key);
return arrayStore; return this.arrays[key] = arrayStore;
}, },
experimental: false, experimental: false,
_set: function(keys, val, pointer, changeList) { _set: function(keys, val, pointer, changeList) {
...@@ -173,7 +196,9 @@ Store.prototype = { ...@@ -173,7 +196,9 @@ Store.prototype = {
return this; return this;
} }
var _key;
var _key = key;
if(type === 'string') { if(type === 'string') {
_key = key.split('.'); _key = key.split('.');
}else if(type === 'number'){ }else if(type === 'number'){
...@@ -182,10 +207,10 @@ Store.prototype = { ...@@ -182,10 +207,10 @@ Store.prototype = {
} }
this._set( this._set(
_key, _key,
val, val,
this._props, this.parent ? this.parent.getPointer() : this._props,
changeList changeList
); );
if(!isChangeList) if(!isChangeList)
this._notify(changeList); this._notify(changeList);
...@@ -198,28 +223,56 @@ Store.prototype = { ...@@ -198,28 +223,56 @@ Store.prototype = {
return this; return this;
return this.set(key, val, changeList); return this.set(key, val, changeList);
}, },
_notify: function(changeList, prefix) { _notifyBubble: function(changeListBubbled, prefix, additional){
prefix = prefix || '';
var item, changeList = [], list = [], i, key;
for( i = changeListBubbled.length; i;){
item = changeListBubbled[--i];
list.push(item);
key = list.join('.');
changeList.push([key, this.get(key)]);
}
this._notify(changeList, '', additional)
if(this.parent){
changeListBubbled.push(this.parent.getKey());
if(prefix) {
this.parent.parent._notifyBubble(changeListBubbled, this.parent.getKey() + '.' + prefix, additional);
}else{
this.parent.parent._notifyBubble(changeListBubbled, this.parent.getKey(), additional);
}
}
//debugger
},
_notify: function(changeList, prefix, additional) {
prefix = prefix || ''; prefix = prefix || '';
for( let i = changeList.length; i; ){ for( let i = changeList.length; i; ){
const changeListElement = changeList[ --i ]; const changeListElement = changeList[ --i ];
var key = changeListElement[0], val = changeListElement[1], var key = changeListElement[0], val = changeListElement[1],
fullKey = prefix+(key===''?'':(prefix===''?'':'.')+key); fullKey = prefix+(key===''?'':(prefix===''?'':'.')+key);
this.events.fire('change', fullKey, changeListElement[1]); this.events.fire('change', fullKey, changeListElement[1], additional);
this.fire(fullKey, changeListElement[1]); this.fire(fullKey, changeListElement[1], additional);
} }
if(this.parent){ if(this.parent){
if(prefix) { if(prefix) {
this.parent.parent._notify(changeList, this.parent.getKey() + '.' + prefix); this.parent.parent._notify(changeList, this.parent.getKey() + '.' + prefix, additional);
}else{ }else{
this.parent.parent._notify(changeList, this.parent.getKey()); this.parent.parent._notify(changeList, this.parent.getKey(), additional);
} }
} }
}, },
get: function(key, returnLastStore) { get: function(key, returnLastStore) {
if(key === void 0)
if(key === void 0){
if(this.parent)
return this.parent.parent.get(this.parent.getKey())
return this._props; return this._props;
}
let type = typeof key; let type = typeof key;
if(type === 'string') { if(type === 'string') {
...@@ -229,8 +282,8 @@ Store.prototype = { ...@@ -229,8 +282,8 @@ Store.prototype = {
key = [key]; key = [key];
} }
let ref = this, let ref = this.parent ? this.parent.parent.get(this.parent.getKey()) : this,
lastStore = ref, i, _i; lastStore = ref, i, _i;
for( i = 0, _i = key.length; i < _i; i++ ){ for( i = 0, _i = key.length; i < _i; i++ ){
if( ref instanceof Store ){ if( ref instanceof Store ){
...@@ -250,7 +303,7 @@ Store.prototype = { ...@@ -250,7 +303,7 @@ Store.prototype = {
return ref; return ref;
}, },
sub: function(key, fn, suppresFirstCall) { sub: function(key, fn, suppressFirstCall) {
var un; var un;
if(Array.isArray(key)){ if(Array.isArray(key)){
var _self = this; var _self = this;
...@@ -261,20 +314,23 @@ Store.prototype = { ...@@ -261,20 +314,23 @@ Store.prototype = {
return fn.apply(_self, args); return fn.apply(_self, args);
}; };
var wrap = function(i){ var wrap = function(i){
return function(val) { return function(val, force) {
args[i] = val; if(args[i] !== val || force){
return caller(); args[ i ] = val;
return caller();
}
}; };
}; };
var uns = []; var uns = [];
for( var i = 0, _i = key.length; i < _i; i++ ){ for( var i = 0, _i = key.length; i < _i; i++ ){
if(key[i] instanceof StoreBinding){ if(key[i] instanceof StoreBinding){
// TODO add suppresFirstCall // TODO add suppressFirstCall
uns.push(key[i].sub(wrap(i))); uns.push(key[i].sub(wrap(i)));
args[i] = key[i].get(); args[i] = key[i].get();
}else if(key[i] instanceof HookPrototype){ }else if(key[i] instanceof HookPrototype){
uns.push(key[i].hook(wrap(i), suppresFirstCall)); uns.push(key[i].hook(wrap(i), suppressFirstCall));
args[i] = key[i].get(); args[i] = key[i].get();
}else{ }else{
uns.push(this.on( key[ i ], wrap(i) )); uns.push(this.on( key[ i ], wrap(i) ));
...@@ -283,7 +339,7 @@ Store.prototype = { ...@@ -283,7 +339,7 @@ Store.prototype = {
} }
!suppresFirstCall && caller(); !suppressFirstCall && caller();
return function() { return function() {
for( var i = 0, _i = uns.length; i < _i; i++ ){ for( var i = 0, _i = uns.length; i < _i; i++ ){
uns[ i ](); uns[ i ]();
...@@ -291,7 +347,7 @@ Store.prototype = { ...@@ -291,7 +347,7 @@ Store.prototype = {
}; };
}else{ }else{
un = this.on( key, fn ); un = this.on( key, fn );
!suppresFirstCall && fn( this.get( key ) ); !suppressFirstCall && fn( this.get( key ) );
return un; return un;
} }
...@@ -379,9 +435,9 @@ StoreBinding.prototype = { ...@@ -379,9 +435,9 @@ StoreBinding.prototype = {
return new StoreBinding(this.store, this.key+'.'+key); return new StoreBinding(this.store, this.key+'.'+key);
}, },
hook: function(draw) { hook: function(draw) {
return this.sub(function(val){ return this.sub(function(val){
draw(val); draw(val);
}); });
}, },
array: function() { array: function() {
return this.store.array(this.key); return this.store.array(this.key);
...@@ -456,14 +512,14 @@ Store.IF = function(cfg, children){ ...@@ -456,14 +512,14 @@ Store.IF = function(cfg, children){
var hook = function( cond ){ var hook = function( cond ){
update( cond ? holders.true : holders.false ); update( cond ? holders.true : holders.false );
}; };
if(cfg.condition instanceof HookPrototype){ if(cfg.condition instanceof HookPrototype){
cfg.condition.hook( hook ); cfg.condition.hook( hook );
}else if(typeof cfg.condition === 'function'){ }else if(typeof cfg.condition === 'function'){
cfg.condition( hook ); cfg.condition( hook );
}else{ }else{
// TODO other hooklikes // TODO other hooklikes
hook(cfg.condition) hook(cfg.condition)
} }
} }
}; };
Store.NOT = Store.AGGREGATE(function(values, length) { Store.NOT = Store.AGGREGATE(function(values, length) {
...@@ -508,9 +564,9 @@ HookPrototype.prototype = { ...@@ -508,9 +564,9 @@ HookPrototype.prototype = {
x.sub = (fn)=> this.hook(fn); x.sub = (fn)=> this.hook(fn);
return x; return x;
}, },
hook: function(fn, suppresFirstCall) { hook: function(fn, suppressFirstCall) {
this.subscribers.push(fn); this.subscribers.push(fn);
!suppresFirstCall && fn(this.get()); !suppressFirstCall && fn(this.get());
var _self = this; var _self = this;
return function() { return function() {
var index = _self.subscribers.indexOf(fn); var index = _self.subscribers.indexOf(fn);
...@@ -562,6 +618,7 @@ Store.Value = { ...@@ -562,6 +618,7 @@ Store.Value = {
setter: function(val) { return val|0; } setter: function(val) { return val|0; }
}), }),
Any: new HookFactory(), Any: new HookFactory(),
Array: new HookFactory(),
Function: new HookFactory() Function: new HookFactory()
}; };
Store.HookPrototype = HookPrototype; Store.HookPrototype = HookPrototype;
...@@ -590,7 +647,15 @@ const ArrayStore = function(cfg) { ...@@ -590,7 +647,15 @@ const ArrayStore = function(cfg) {
ArrayStore.prototype = { ArrayStore.prototype = {
length: 0, length: 0,
indexOf: function (a) { indexOf: function (a) {
return this._props.indexOf(a); if(typeof a === 'function'){
for( var i = 0, _i = this._props.length; i < _i; i++ ){
if(a(this._props[ i ]))
break;
}
return i < _i ? i : -1;
}else{
return this._props.indexOf(a);
}
}, },
toArray: function () { toArray: function () {
return this._props; return this._props;
...@@ -598,10 +663,12 @@ ArrayStore.prototype = { ...@@ -598,10 +663,12 @@ ArrayStore.prototype = {
_fireAdd: function (item, pos) { _fireAdd: function (item, pos) {
var arr = this._props; var arr = this._props;
this.fire('add', item, pos > 0 ? arr.get(pos-1) : null, pos < this.length - 1 ? arr.get(pos+1) : null, pos) this.fire('add', item, pos > 0 ? arr.get(pos-1) : null, pos < this.length - 1 ? arr.get(pos+1) : null, pos)
this._notifyBubble([pos], '', true);
}, },
_fireRemove: function (item, pos) { _fireRemove: function (item, pos) {
var arr = this._props; var arr = this._props;
this.fire('remove', item, pos > 0 ? arr.get(pos-1) : null, pos < this.length ? arr.get(pos) : null, pos) this.fire('remove', item, pos > 0 ? arr.get(pos-1) : null, pos < this.length ? arr.get(pos) : null, pos)
this._notifyBubble([], '', true);
}, },
push: function (item) { push: function (item) {
// single item push only // single item push only
...@@ -649,16 +716,36 @@ ArrayStore.prototype = { ...@@ -649,16 +716,36 @@ ArrayStore.prototype = {
@return element that was in that position before @return element that was in that position before
*/ */
set: function(pos, item){ set: function(key, item){
if(pos === this.length){ var _key = key, type = typeof key;
if(type === 'string') {
_key = key.split('.');
}else if(type === 'number'){
_key = [key];
}
if(_key.length === 1){
if( Array.isArray( key ) && arguments.length === 1 ){
this.splice.apply( this, [ 0, this.length ].concat( key ) )
return this;
}else if( key === this.length ){
this.push( item ); this.push( item );
return void 0; // for same behavior we return empty array return void 0; // for same behavior we return empty array
} }
return this.splice(pos, 1, item)[0]; return this.splice( key, 1, item )[ 0 ];
}else{
return this.item(_key[0]).set(_key.slice(1), item);
}
}, },
iterator: function(start){ iterator: function(start){
return new Iterator(this, start); return new Iterator(this, start);
}, },
removeItem: function(item){
var index = this._props.indexOf(item);
if(index > -1){
this.remove(index);
}
return item;
},
remove: function(pos){ remove: function(pos){
var item = this._props.splice(pos,1)[0]; var item = this._props.splice(pos,1)[0];
this.length--; this.length--;
...@@ -672,60 +759,27 @@ ArrayStore.prototype = { ...@@ -672,60 +759,27 @@ ArrayStore.prototype = {
}, },
forEach: function (fn) { forEach: function (fn) {
return this._props.forEach(fn); return this._props.forEach(fn);
}
};
ArrayStore.prototype = Object.assign(new Store(), ArrayStore.prototype);
/*
const ArrayStore = function (cfg) {
Store.call(this, cfg);
};
ArrayStore.prototype = {
push: function (val) {
var changeList = [];
changeList.push(['', this._props])
this.set(this.getLength(), val, changeList);
this._notify(changeList);
return this;
}, },
pop: function () { map: function (fn) {
var changeList = []; return this._props.map(fn);
changeList.push(['', this._props]);
var out = this.get(this.getLength()-1);
this.set(this.getLength()-1, void 0, changeList);
this._props.pop();
this._notify(changeList);
return out;
}, },
remove: function(item) { filter: function(fn) {
var idx = this._props.indexOf(item); return this._props.filter(fn);
if(idx>-1){
var changeList = [];
changeList.push(['', this._props]);
this._props.splice(idx,1);
//this.set(this.getLength()-1, void 0, changeList);
this._notify(changeList);
}
return this;
},
slice: function () {},
splice: function () {},
getLength: function () {
return this._props.length;
}, },
update: function() { items: function() {
var changeList = []; //return this.item()
changeList.push(['', this._props]);
this._notify(changeList);
return this;
}, },
'~destructor': function() { sub: function(fn, suppressFirstCall) {
this._listeners = this.events = this._props = null; var changed = () => {
fn.call(this, this._props);
}
this.on('add', changed);
this.on('remove', changed);
!suppressFirstCall && changed();
} }
}; };
ArrayStore.prototype = Object.assign(new Store(), ArrayStore.prototype);
ArrayStore.prototype = Object.assign(new Store(), ArrayStore.prototype);*/ Store.ArrayStore = ArrayStore;
typeof module === 'object' && (module.exports = Store); typeof module === 'object' && (module.exports = Store);
(typeof window === 'object') && (window.Store = Store); (typeof window === 'object') && (window.Store = Store);
\ No newline at end of file
const {minify} = require("terser"),
fs = require('fs'),
path = require( 'path'),
DOM = ['DOM.js'],
rDOM = DOM.concat('Observer.js', 'Store.js', 'Transform.js'),
dir = 'build',
header = `/* Vanilla.js Reactivity by Ivan Kubota.
* ©Form.dev 2012—${(new Date()).getFullYear()}
* License: MPL-2.0 for not commercial use and all projects that involves me
*/
`;
build = {
DOM,
rDOM
},
hash = {};
Object
.values(build)
.forEach(files =>
files.forEach(fileName =>
hash[fileName] = hash[fileName] || fs.readFileSync(fileName).toString('utf-8')
)
);
(async function(){
for( let outFileName in build ){
let
dest = path.join( dir, outFileName ),
source = header +
(await minify(
build[ outFileName ].map( fileName => hash[ fileName ] ).join( ';' )
)).code;
fs.writeFileSync( dest, source );
console.log( `Build ${dest} ${( source.length / 1024 ).toFixed( 2 )}K` )
}
})();
\ No newline at end of file
{
"name": "react-vanilla",
"version": "1.0.0",
"description": "",
"main": "DOM.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@gitlab.quokka.pub:Zibx/react-vanilla.git"
},
"keywords": [],
"author": "",
"license": "MPL-2.0",
"dependencies": {
"terser": "^5.4.0"
}
}
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
source-map-support@~0.5.19:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@~0.7.2:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
terser@^5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.4.0.tgz#9815c0839072d5c894e22c6fc508fbe9f5e7d7e8"
integrity sha512-3dZunFLbCJis9TAF2VnX+VrQLctRUmt1p3W2kCsJuZE4ZgWqh//+1MZ62EanewrqKoUf4zIaDGZAvml4UDc0OQ==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.19"
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