/* vanilla-lib */
function VanillaLibScope( ) {
this.mapFlat = ( array,func ) => array.map( x => func(x) ).reduce( (a,b) => a.concat(b) );
this.parenth = ( elem,nth ) => traverse(elem, this.ifndef(nth, 1), 0);
this.ifndef = ( expr,value ) => ( this.ndef(expr) ? value : expr );
this.ispojo = expr => this.isobj(expr, Object);
this.export = ( source,target,members ) => ( Object.keys(source).filter( key => ! members || members.includes(key) )
.forEach( key => target[ key ] = source[ key ] ) );
this.ifnan = ( expr,value ) => ( isNaN(expr) ? value : expr );
this.isobj = ( expr,type ) => ( 'object' === typeof expr && ( ! type || this.isfn(expr.constructor)
&& type === ( this.isfn(type) ? expr.constructor : expr.constructor.name ) ) );
this.isarr = expr => this.isobj(expr, Array);
this.isstr = expr => ( 'string' === typeof expr );
this.isfn = expr => ( 'function' === typeof expr );
this.ndef = expr => ( 'undefined' === typeof expr );
this.test = ( expr,func,other ) => ( !! expr ? func(expr) : this.isfn(other) ? other(expr) : other );
this.fire = ( elem,event,args ) => elem.dispatchEvent( this.isobj(event) ? even
: new Event( event, this.ifndef(args, { 'bubbles':true, 'cancelable':true }) ) );
this.warn = console.warn;
this.log = console.debug;
this.on = ( elem,event,func ) => elem.addEventListener(event, func);
this.$$ = ( sel,elem ) => Array.slice((elem || document).querySelectorAll(sel));
this.$ = ( sel,elem ) => (elem || document).querySelector(sel);
this.aggRate = ( amount,rate,periods ) => ( ! periods ? amount : this.aggRate(amount * rate, rate, periods - 1) ),
this.toDec = expr => ( Math.round(parseFloat((expr +'').replace(/\$|,/g, '')) * 100) / 100 );
this.appendTo = function( element, parent, reference ) {
if ( !! reference ) {
parent = reference.parentNode;
reference = reference.nextSibling;
}
if ( !! reference ) {
return this.prependTo(element, parent, reference);
} else if ( !! parent ) {
parent.append(element);
} else {
this.warn('*** appendTo() could not add element: No parent or reference element provided');
}
return element;
};
this.attr = function( elem, name, value ) {
if ( this.isarr(elem) ) {
return elem.map( el => this.attr(el, name, value) );
}
this.keysAndValues(name, value, ( n,v ) => ( null === v ? elem.removeAttribute(n) : elem.setAttribute(n, v) ) );
return elem;
};
this.create = function( html, containerType ) {
let container = null,
result = null,
attrs, style;
if ( this.isobj(containerType) ) {
attrs = containerType.attrs;
style = containerType.style;
containerType = containerType.container;
}
containerType = containerType || 'div';
create[ containerType ] =
container = create[ containerType ] || document.createElement(containerType);
container.innerHTML = html;
result = Array.slice(container.childNodes)
.map( elem => (elem.remove(), elem) );
if ( !! attrs ) {
this.attr(result, attrs);
}
if ( !! style ) {
this.css(result, style);
}
if ( 1 == result.length ) {
result = result[ 0 ];
}
return result;
};
this.css = function( element, key, value ) {
if ( isarr(element) ) {
return element.map( el => css(el, key, value) );
}
keysAndValues(key, value, ( k,v ) => element.style[ k ] = v );
return element;
};
this.keysAndValues = function( key, value, action ) {
// Case 1: key is an object (and there is no value)
if ( this.isobj(key) && ! value ) {
return Object.keys(key)
.map( k => action(k, key[ k ]) );
// Case 2: key is an array
} else if ( this.isarr(key) ) {
// Case 1.a: value is an array of the same length
if ( this.isarr(value) && key.length === value.length ) {
return key.map( ( k,i ) => action(k, value[ i ]) );
// Case 1.b: value is considered a simple, plain value
} else {
return key.map( k => action(k, value) );
}
// Default Case: key and value considered as simple, plain values
} else {
return action(key, value);
}
};
this.prependTo = function( element, parent, reference ) {
if ( ! reference && !! parent ) {
reference = parent.childNodes[ 0 ];
}
if ( !! reference ) {
reference.parentNode.insertBefore(element, reference);
} else if ( !! parent ) {
parent.append(element);
} else {
this.warn('*** prependTo() could not add element: No parent or reference element provided');
}
return element;
};
this.toDec2 = function( amount ) {
amount = this.toDec(amount);
if ( isNaN(amount) ) {
return null;
}
let segs = (amount +'').split('.');
return segs[ 0 ] +'.'+ ((segs[ 1 ] || 0) +'0').slice(0, 2);
};
this.toMoney = function( amount ) {
let dec2 = this.toDec2(amount);
return ( isNaN(dec2) ? null : dec2 < 0 ? '-$ '+ (-dec2) : '$ '+ dec2 );
};
this.traverse = function( elem, up, sideways, elementsOnly, lastIfNull ) {
let last = elem;
while ( !! elem && up -- > 0 ) elem = (last = elem, elem.parentNode);
let prop = ( elementsOnly ? 'Element' : '' ) +'Sibling';
if ( sideways < 0 ) {
while ( !! elem && sideways ++ < 0 ) elem = (last = elem, elem[ 'previous'+ prop ]);
} else if ( sideways > 0 ) {
while ( !! elem && sideways -- > 0 ) elem = (last = elem, elem[ 'next'+ prop ]);
}
return ( ! lastIfNull ? elem : elem || last );
};
this.copyMembers = function( source, target, members, preserve ) {
//this.log('* Copying from', source, '\n\tto', target, '\n\t'+ members, preserve);
if ( ! this.isobj(source) || ! this.isobj(target) ) {
this.warn('=> Cannot copy from/to non-objects');
return false;
}
let names = Object.keys(source);
preserve = ( this.isobj(preserve) ? preserve : false );
//this.log('- Full list of members:', names);
if ( this.isstr(members) ) {
members = members.split(',').map( nm => nm.trim() );
}
if ( this.isarr(members) ) {
//this.log('* Member filter:', members);
names = names.filter( nm => members.includes(nm) );
} else if ( this.isfn(members) ) {
names = names.filter(members);
}
//this.log('- Filtered list of members:', names);
names.forEach( nm => {
if ( !! target[ nm ] && !! preserve ) {
preserve[ nm ] = target[ nm ];
}
target[ nm ] = source[ nm ];
//this.log('- Target members', nm, target[ nm ]);
} );
//this.log('=>', target);
return (preserve || target);
};
this.export = function( scope, members, overwriten ) {
if ( ! scope ) {
return false;
}
return this.copyMembers(this, scope, members, overwriten);
};
}