instance-js
Version:
437 lines (341 loc) • 9.41 kB
JavaScript
(function(root) {
function Inst(obj, opt) {
return new Instance(obj, opt);
}
function Instance(obj, opt) {
if( isString(obj) ) {
if( isFunction(Inst.classStringHandler) ) {
return Inst.classStringHandler.call(this, obj, opt)
}
}
else if(obj != null ) {
if( isArrayLike(obj) && !isElement(obj) && !isWindow(obj) ) {
for( var i=0; i < obj.length; i++ ) {
this[i] = obj[ i ];
}
this.length = obj.length;
}
else {
this[0] = obj;
this.length = 1;
}
}
}
Inst.classStringHandler = function(obj, opt) {
var nodes;
if( /</.test(obj) ) {
nodes = nodeFromString(obj, opt);
}
else {
nodes = (opt || document).querySelectorAll(obj);
}
for(var i=0; i<nodes.length; i++) {
this[i] = nodes[i];
}
this.length = nodes.length;
}
// #Extensions
// jQuery.extend + overwrite
Inst.extend = (Inst.proto = Instance.prototype).extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ],
i = 1,
length = arguments.length,
deep = false,
overwrite = true;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i++ ];
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !isFunction( target ) ) {
target = {};
}
// Extend this if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
if( typeof arguments[ length - 1] === "boolean" ) {
overwrite = arguments[ --length ];
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( ( options = arguments[ i ] ) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent overwrite
if( !overwrite && name in target ) {
continue;
}
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( isPlainObject( copy ) ||
( copyIsArray = isArray( copy ) ) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && isArray( src ) ? src : [];
} else {
clone = src && isPlainObject( src ) ? src : {};
}
// Never move original objects, clone them
target[ name ] = Inst.extend( deep, clone, copy, overwrite );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
}
// #Wire Event Emitter
var wire = {
events: {},
add: function(name, fn) {
if( !Array.isArray(this.events[name]) ) {
this.events[name] = [];
}
if( !~this.events[name].indexOf(fn) && typeof fn === "function" ) {
this.events[name] = this.events[name].concat(fn);
}
},
remove: function(name, fn) {
var fns = this.events[name];
if( !fns ) {
return;
}
if( fn ) {
var index = fns.indexOf(fn);
if( ~index ) {
this.events[name] = fns.slice(0, index).concat( fns.slice(index + 1) );
}
}
else {
this.events[name] = [];
}
},
send: function(name, data, scope) {
var fns = this.events[name];
data = 1 in arguments ? [data] : [];
if( !fns ) {
throw new ReferenceError(name + " event was not found.");
}
for(var i=0; i<fns.length; i++) {
fns[i].apply(scope, data);
}
},
check: function(name) {
return !!this.events[name];
}
};
Inst.extend({
on: wire.add.bind(wire),
off: wire.remove.bind(wire),
emit: wire.send.bind(wire),
emitterCheck: wire.check.bind(wire)
});
var hangFire = (function() {
var hang = {};
var defaultWait = 300;
return function hangFire(callback, wait, callbackId) {
// identifies functions by string
callbackId = callbackId ? callbackId : callback.toString();
if( hang[ callbackId ] !== undefined ) {
clearTimeout( hang[callbackId] );
}
return hang[callbackId] = setTimeout(callback, typeof wait === "number" ? wait : defaultWait);
}
})();
Inst.hangFire = hangFire;
// #Math
Inst.random = function random(min, max, ignr) {
ignr = 2 in arguments ? Array.isArray(ignr) ? ignr : [ignr] : []
if( max == null ) {
max = min == null ? 1 : min;
min = 0;
}
if( max < min ) {
var tempMax = max;
max = min;
min = tempMax;
}
var rand;
while( (rand = Math.round(Math.random() * max)) < min || ~ignr.indexOf(rand) );
return rand;
}
// #Ajax
Inst.ajax = (function() {
var requests = {};
return function ajax( a ) {
var req = new XMLHttpRequest;
a.method = a.method ? a.method.toUpperCase() : "POST";
a.url = a.url ? a.url : "";
req.open(a.method, a.url, !a.sync);
req.onreadystatechange = function() {
if( this.readyState === 4 ) {
if( this.status === 200 ) {
a.success&&a.success.call(this, JSON.parse(this.responseText));
}
else {
a.failure&&a.failure.call(this, {code: this.status, text: this.statusText})
}
}
}
req.onerror = a.error||null
if( a.progress ) {
if( a.method === "POST" ) {
a.upload.addEventListener('progress', a.progress);
}
else {
req.onprogress = a.progress;
}
}
req.onloadstart = a.start || null;
req.onloadend = a.end || null;
req.onabort = a.abort || null;
if( a.header ) {
for( var header in a.header ) {
req.setRequestHeader(header, a.header[ header ]);
}
}
var contentType = a.contentType != null ? a.contentType : "application/x-www-form-urlencoded";
if( contentType ) {
req.setRequestHeader("Content-Type", contentType);
}
if( a.restart && ( a.name || a.url ) && requests[ a.name || a.url ] ) {
requests[ a.name || a.url ].abort();
}
requests[ a.name || a.url ] = req;
req.send( a.data );
return req;
}
})();
// #Promise
Inst.promise = (function() {
function sendReq(type, url, data) {
return new Promise(function(rs, rj) {
Inst.ajax({
url: url,
data: data||null,
method: type||null,
success: function(response) {
rs(response)
},
failure: function(status) {
rj(Error("statusCode: " + status.code + ", statusText: '" + status.text + "'"))
},
error: function(e) {
rj(e)
}
})
})
}
var P = {
toPost: function(url, data) {
return sendReq("post", url, data)
},
toGet: function(url) {
return sendReq("get", url)
},
toPut: function(url, data) {
return sendReq("put", url, data)
},
toDelete: function(url) {
return sendReq("delete", url)
},
}
P.toUpdate = P.toPut;
// #alias
Inst.post = P.toPost;
Inst.get = P.toGet;
Inst.update = P.toUpdate;
Inst.delete = P.delete;
return P;
})();
// #Native
Inst.proto.extend({
splice: Array.prototype.splice,
push: Array.prototype.push,
});
// #Abstract
var nodeFromString = (function() {
var wrapper = document.createElement('div'),
placeholders = /(.?)(?:\@)([\w-]+)((?:\.[\w-]+|\[\s*\d+\s*])*)/g,
bracketNotations = /\[\s*(\d+)\s*]/g;
function placeData(str, vo) {
var obj, chainList;
return str.replace(placeholders, function(m, charbefore, ph, chain) {
if( charbefore === "\\" ) {
return "@" + ph + chain;
}
if( !vo ) {
return m;
}
obj = vo[ ph ];
chainList = str.replace(bracketNotations, ".$1").split(".").slice(1);
for( var i=0; i<chainList.length; i++ ) {
obj = obj[ chainList[i] ];
if( obj == null ) {
obj = "";
break;
}
}
return charbefore + (obj || "");
});
}
return function(HTMLString, valuesObject) {
var nodes = [];
wrapper.innerHTML = placeData(HTMLString, valuesObject);
while( wrapper.firstChild ) {
nodes.push( wrapper.removeChild( wrapper.firstChild ) );
}
return nodes;
}
})();
// #Predicates
function isString(obj) {
return obj != null && (typeof obj === "string" || obj.constructor === String);
}
function isFunction(obj) {
return obj != null && (typeof obj === "function" || obj.constructor === Function);
}
function isArrayLike( obj ) {
if( isString(obj) ) return true;
return (
obj != null &&
typeof obj === "object" &&
"length" in obj &&
+obj.length + 1 > 0 &&
(
obj.length - 1 in obj ||
obj.length === 0
)
);
}
function isWindow( obj ) {
return obj === window;
}
function isElement( obj ) {
return !!(
typeof HTMLElement === "object" ?
obj instanceof HTMLElement :
// for the heck of it
obj && obj.nodeType === 1 && obj.removeChild && obj.nodeName
)
}
if(typeof module !== 'undefined' && module.exports) {
module.exports.Instance = module.exports.Inst = module.exports.I = Inst;
}
else {
root.Instance = root.Inst = root.I = Inst;
}
})(this);