enough
Version:
327 lines (300 loc) • 7.57 kB
JavaScript
/* ================================================================
* enough by xdf(xudafeng[at]126.com)
*
* first created at : Mon Nov 03 2014 19:45:18 GMT+0800 (CST)
*
* ================================================================
* Copyright xdf
*
* Licensed under the MIT License
* You may not use this file except in compliance with the License.
*
* ================================================================ */
;(function() {
'use strict';
var _guid = 0;
var slice = Array.prototype.slice;
var _ = {
create: function(o) {
if (Object.create) {
return Object.create(o);
} else {
var F = function() {};
F.prototype = o;
return new F();
}
},
slice: slice,
guid: function() {
return _guid++;
},
inherit: function(sub, sup) {
var swap = sub.prototype;
sub.prototype = this.create(sup.prototype);
this.augment(sub, swap);
sub.prototype.constructor = sub;
sub.sup = sup;
},
augment: function(r, s) {
this.merge(r.prototype, s);
return r;
},
merge: function(r, s) {
this.each(s, function(v, k) {
r[k] = v;
});
return r;
},
each: function(obj, fn) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
fn.call(this, obj[i], i);
}
}
return obj;
},
extend: function() {
var that = this;
var args = slice.call(arguments);
var r = args.shift();
this.each(args, function(s) {
that.merge(r, s);
});
return r;
},
trim: function(str) {
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
};
function Klass(obj) {
function Constructor() {
if (!(this instanceof Constructor)) {
throw new Error('Please use keyword: new, when initial a class.');
}
this._guid = _.guid();
_dataHash[this._guid] = {};
_eventHandleHash[this._guid] = {};
// inherit
Constructor.sup.call(this);
// custom constructor
var constructor = obj.hasOwnProperty('constructor') ? obj.constructor : function() {};
constructor.apply(this, arguments);
}
var sup = obj.sup;
_.extend(sup.prototype, Events, Data, {
extend: function() {
var that = this;
_.each(slice.call(arguments), function(v) {
_.merge(that, v);
});
return that;
}
});
_.inherit(Constructor, sup);
_.extend(Constructor, {
extend: function() {
return _.extend(this, arguments);
},
parent: sup.prototype,
augment: function() {
var proto = this.prototype;
_.each(slice.call(arguments), function(v) {
_.merge(proto, v);
});
return proto;
},
Klass: function(obj) {
obj = obj || {};
obj.sup = this;
return new Klass(obj);
}
});
_.each(obj, function(v, k) {
if (obj.hasOwnProperty(k) && k !== 'constructor') {
Constructor.prototype[k] = v;
}
});
return Constructor;
}
/**
* custom event
*/
var _eventHandleHash = {};
var _bindSingleEvent = function(id, handle) {
if (!_eventHandleHash[this._guid][id]) {
_eventHandleHash[this._guid][id] = [];
}
_eventHandleHash[this._guid][id].push({
id: this._guid,
handle: handle,
type: id
});
};
var _bindEvent = function(map, handle) {
var that = this;
if (typeof map === 'string') {
_bindSingleEvent.call(this, map, handle);
} else {
_.each(map, function(handle, id) {
_bindSingleEvent.call(that, id, handle);
});
}
};
var _unbindEvent = function(id) {
if (id) {
delete _eventHandleHash[this._guid][id];
} else {
_eventHandleHash[this._guid] = [];
}
};
var _triggerEvent = function(id, data) {
var _eventLoop = _eventHandleHash[this._guid][id];
if (!_eventLoop) {
return;
}
var that = this;
_.each(_eventLoop, function(e) {
e.handle.call(that, data, e.type);
});
};
var Events = {
on: function(map, handle) {
_bindEvent.call(this, map, handle);
return this;
},
detach: function(id) {
_unbindEvent.call(this, id);
return this;
},
emit: function(id, data) {
_triggerEvent.call(this, id, data);
return this;
}
};
var _dataHash = {};
var Data = {
get: function(k) {
return this.has(k) ? _dataHash[this._guid][k] : null;
},
set: function(k, v) {
var that = this;
if (typeof k === 'object') {
_.each(k, function(v, k) {
var oldValue = _dataHash[that._guid][k];
if (oldValue === v) {
return;
}
_dataHash[that._guid][k] = v;
that.emit('change:' + k, v);
that.emit('change', v);
});
} else {
var oldValue = _dataHash[that._guid][k];
if (oldValue === v) {
return;
}
_dataHash[that._guid][k] = v;
that.emit('change:' + k, v);
that.emit('change', v);
}
return this;
},
has: function(k) {
return typeof _dataHash[this._guid][k] !== 'undefined';
},
remove: function(id) {
var that = this;
if (typeof id === 'function') {
_.each(_dataHash[this._guid], function(v, k) {
if (!id(v)) {
return;
}
delete _dataHash[that._guid][k];
that.emit('change:' + k);
that.emit('change');
});
return this;
}
if (typeof id === 'undefined') {
_dataHash[this._guid] = {};
} else {
if (this.has(id)) {
delete _dataHash[this._guid][id];
}
}
that.emit('change:' + id);
this.emit('change');
return this;
},
getAll: function() {
return _dataHash[this._guid];
},
getAllAsArray: function() {
var arr = [];
var map = _dataHash[this._guid];
_.each(map, function(v) {
arr.push(v);
});
return arr;
},
size: function() {
return this.getAllAsArray().length;
},
update: function(k, fn) {
var that = this;
if (typeof k === 'function') {
_.each(_dataHash[this._guid], function(v, _k) {
k(v);
that.emit('change:' + _k, v);
});
this.emit('change');
return;
}
var v = this.get(k);
var clone = v;
if (clone.constructor === Array) {
clone = v.slice(0);
} else if (typeof clone === 'object') {
clone = _.extend({}, v);
}
if (v) {
this.set(k, fn(clone));
}
return this;
},
filter : function(fn) {
var items = [];
_.each(_dataHash[this._guid], function(v) {
if (fn(v)) {
items.push(v);
}
});
return items;
}
};
var Enough = {
_ : _,
Klass: function(obj) {
obj = obj || {};
obj.sup = function() {};
return new Klass(obj);
},
_cache: {
events: _eventHandleHash,
data: _dataHash
}
};
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = Enough;
}
exports.Enough = Enough;
} else if (typeof define === 'function' && define.amd) {
define(function() {
return Enough;
});
} else {
window.Enough = Enough;
}
})();
/* vim: set sw=2 ts=2 et tw=80 : */