Created
March 26, 2015 17:02
-
-
Save skamenetskiy/330bc48971116593863f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @copyright Semen Kamenetskiy <[email protected]> | |
*/ | |
(function (global, undefined) { | |
'use strict'; | |
/** | |
* Foreach loop | |
* @param object | |
* @param callback | |
* @returns {boolean} | |
*/ | |
function forEach(object, callback) { | |
for (var a in object) { | |
if (object.hasOwnProperty(a)) { | |
callback.call(object, object[a], a, object) | |
} | |
} | |
return true; | |
} | |
/** | |
* | |
* @param [NewObject] - the constructor | |
* @param [parameters] - additional methods and parameters | |
* @returns {*|Function} | |
*/ | |
function extend(NewObject, parameters) { | |
parameters = parameters || {}; | |
NewObject = NewObject || function () { | |
}; | |
// Append an extend method | |
NewObject.extend = this.extend; | |
// Append parent object params | |
NewObject.prototype = this.prototype; | |
// Append additional params | |
forEach(parameters, function (value, key) { | |
NewObject.prototype[key] = value | |
}); | |
// Return new object | |
return NewObject | |
} | |
/** | |
* Custom event | |
* @constructor | |
*/ | |
function MVCEvent() { | |
} | |
/** | |
* Global MVC event prototype | |
* @type {{type: null, timeStamp: null, data: {}}} | |
*/ | |
MVCEvent.prototype = { | |
type: null, | |
timeStamp: null, | |
data: {} | |
}; | |
/** | |
* Global application constructor | |
* @constructor | |
*/ | |
function Application() { | |
this.__models__ = new ModelCollection; | |
this.__views__ = new ViewCollection; | |
this.__controllers__ = new ControllerCollection; | |
} | |
/** | |
* Add an extend method to collection | |
* @type {extend} | |
*/ | |
Application.extend = extend; | |
/** | |
* Registers a new model in collection | |
* @param model | |
* @returns {Number} | |
*/ | |
Application.prototype.registerModel = function (model) { | |
return this.__models__.add(model) | |
}; | |
/** | |
* Registers a new view in collection | |
* @param model | |
* @returns {Number} | |
*/ | |
Application.prototype.registerView = function (model) { | |
return this.__views__.add(model) | |
}; | |
/** | |
* Registers a new controller in collection | |
* @param model | |
* @returns {Number} | |
*/ | |
Application.prototype.registerController = function (model) { | |
return this.__controllers__.add(model) | |
}; | |
/** | |
* | |
* @param index | |
* @returns {ModelCollection|AbstractCollection} | |
*/ | |
Application.prototype.models = function (index) { | |
if (undefined !== index) { | |
return this.__models__.get(index) | |
} | |
return this.__models__ | |
}; | |
/** | |
* | |
* @param index | |
* @returns {ModelCollection|AbstractCollection} | |
*/ | |
Application.prototype.views = function (index) { | |
if (undefined !== index) { | |
return this.__views__.get(index) | |
} | |
return this.__views__ | |
}; | |
/** | |
* | |
* @param index | |
* @returns {ModelCollection|AbstractCollection} | |
*/ | |
Application.prototype.controllers = function (index) { | |
if (undefined !== index) { | |
return this.__controllers__.get(index) | |
} | |
return this.__controllers__ | |
}; | |
/** | |
* Global Model constructor | |
* @constructor | |
*/ | |
function Model() { | |
/** | |
* Model vars container | |
* @type {{}} | |
* @private | |
*/ | |
this.__vars__ = {}; | |
/** | |
* Model events container | |
* @type {{}} | |
* @private | |
*/ | |
this.__events__ = {}; | |
} | |
/** | |
* Add extend method | |
* @type {extend} | |
*/ | |
Model.extend = extend; | |
/** | |
* Sets an event listener | |
* @param eventType | |
* @param eventHandler | |
* @returns {Model} | |
*/ | |
Model.prototype.bind = function (eventType, eventHandler) { | |
if (arguments.length == 2) { | |
if (!this.__events__[eventType]) { | |
this.__events__[eventType] = [] | |
} | |
this.__events__[eventType] | |
.push(eventHandler); | |
} | |
return this | |
}; | |
/** | |
* Unsets an event listener | |
* @param eventType | |
* @param eventHandler | |
* @returns {Object} | |
*/ | |
Model.prototype.unbind = function (eventType, eventHandler) { | |
if (arguments.length == 0) { | |
this.__events__ = {}; | |
return this | |
} | |
if (undefined === eventHandler) { | |
delete this.__events__[eventType] | |
} else { | |
if (eventType in this.__events__) { | |
var self = this; | |
this.__events__[eventType].forEach(function (handler, index) { | |
if (handler === eventHandler) { | |
delete self.__events__[eventType][index] | |
} | |
}) | |
} | |
} | |
return this | |
}; | |
/** | |
* Triggers an event | |
* @param event | |
*/ | |
Model.prototype.trigger = function (event) { | |
if (!(event instanceof MVCEvent)) { | |
throw new TypeError('event is not a valid event') | |
} | |
var self = this; | |
if (event.type in this.__events__) { | |
forEach(this.__events__, function (eventsList) { | |
eventsList.forEach(function (handler) { | |
handler.call(self, event) | |
}) | |
}) | |
} | |
return this | |
}; | |
/** | |
* Model setter | |
* @param key | |
* @param value | |
* @returns {Model} | |
*/ | |
Model.prototype.set = function (key, value) { | |
this.__vars__[key] = value; | |
return this | |
}; | |
/** | |
* Model getter | |
* @param key | |
* @returns {*} | |
*/ | |
Model.prototype.get = function (key) { | |
if (key in this.__vars__) { | |
return this.__vars__[key] | |
} | |
return undefined | |
}; | |
/** | |
* Custom event for Model | |
* @param eventType | |
* @constructor | |
*/ | |
function ModelEvent(eventType) { | |
if ('string' !== typeof(eventType)) { | |
throw new TypeError('eventType is not a string') | |
} | |
this.type = eventType; | |
this.timeStamp = (new Date).getTime() | |
} | |
/** | |
* Model event prototype | |
* @type {{type: null, timeStamp: null}} | |
*/ | |
ModelEvent.prototype = MVCEvent.prototype; | |
/** | |
* Global view constructor | |
* @constructor | |
*/ | |
function View() { | |
} | |
/** | |
* Add extend method to view | |
* @type {extend} | |
*/ | |
View.extend = extend; | |
/** | |
* Custom event for Model | |
* @param eventType | |
* @constructor | |
*/ | |
function ViewEvent(eventType) { | |
if ('string' !== typeof(eventType)) { | |
throw new TypeError('eventType is not a string') | |
} | |
this.type = eventType; | |
this.timeStamp = (new Date).getTime() | |
} | |
/** | |
* Model event prototype | |
* @type {{type: null, timeStamp: null}} | |
*/ | |
ViewEvent.prototype = MVCEvent.prototype; | |
/** | |
* Global controller constructor | |
* @constructor | |
*/ | |
function Controller() { | |
this.__routes__ = {}; | |
this.__useHistory__ = !!history.pushState; | |
} | |
/** | |
* Adding extend method to controller | |
* @type {extend} | |
*/ | |
Controller.extend = extend; | |
/** | |
* | |
* @param route | |
* @param listener | |
* @returns {Controller} | |
*/ | |
Controller.prototype.addRouteListener = function (route, listener) { | |
if (!(route in this.__routes__)) { | |
this.__routes__[route] = []; | |
} | |
this.__routes__[route].push(listener); | |
return this | |
}; | |
Controller.prototype.navigate = function (route) { | |
}; | |
Controller.prototype.listen = function () { | |
return this; | |
}; | |
/** | |
* Custom event for Model | |
* @param eventType | |
* @constructor | |
*/ | |
function ControllerEvent(eventType) { | |
if ('string' !== typeof(eventType)) { | |
throw new TypeError('eventType is not a string') | |
} | |
this.type = eventType; | |
this.timeStamp = (new Date).getTime() | |
} | |
/** | |
* Model event prototype | |
* @type {{type: null, timeStamp: null}} | |
*/ | |
ControllerEvent.prototype = MVCEvent.prototype; | |
/** | |
* | |
* @constructor | |
*/ | |
function AbstractCollection() { | |
this.__collection__ = []; | |
} | |
/** | |
* Add an extend method | |
* @type {extend} | |
*/ | |
AbstractCollection.extend = extend; | |
/** | |
* Add a model to collection | |
* @param model | |
* @returns {Number} | |
*/ | |
AbstractCollection.prototype.add = function (model) { | |
if (!(model instanceof this.__type__)) { | |
throw new TypeError('model is not an instance of Model') | |
} | |
return this.__collection__.push(model); | |
}; | |
/** | |
* Retrieve an element from collection | |
* @param index | |
* @returns {*} | |
*/ | |
AbstractCollection.prototype.retrieve = function (index) { | |
if (index in this.__collection__) { | |
return this.__collection__[index] | |
} | |
return undefined | |
}; | |
/** | |
* Remove a model from collection | |
* @param model | |
* @returns {AbstractCollection} | |
*/ | |
AbstractCollection.prototype.remove = function (model) { | |
this.__collection__.forEach(function (savedModel, index, collection) { | |
if (model === savedModel) { | |
collection.splice(index, 1) | |
} | |
}); | |
return this | |
}; | |
/** | |
* | |
* @param method | |
* @param args | |
* @returns {AbstractCollection} | |
*/ | |
AbstractCollection.prototype.apply = function (method, args) { | |
this.__collection__.forEach(function (model) { | |
if (method in model) { | |
model[method].apply(model, args) | |
} | |
}); | |
return this | |
}; | |
/** | |
* A shortcut for set method | |
* @returns {AbstractCollection} | |
*/ | |
AbstractCollection.prototype.set = function () { | |
return this.apply('set', arguments); | |
}; | |
AbstractCollection.prototype.get = function (index) { | |
}; | |
/** | |
* A shortcut for bind method | |
* @returns {AbstractCollection} | |
*/ | |
AbstractCollection.prototype.bind = function () { | |
return this.apply('bind', arguments) | |
}; | |
/** | |
* A shortcut for unbind method | |
* @returns {AbstractCollection} | |
*/ | |
AbstractCollection.prototype.unbind = function () { | |
return this.apply('unbind', arguments) | |
}; | |
/** | |
* A shortcut for bind method | |
* @returns {AbstractCollection} | |
*/ | |
AbstractCollection.prototype.trigger = function () { | |
return this.apply('trigger', arguments) | |
}; | |
/** | |
* Model collection constructor | |
* @constructor | |
*/ | |
function ModelCollection() { | |
this.__type__ = Model; | |
this.__collection__ = []; | |
} | |
/** | |
* View collection constructor | |
* @constructor | |
*/ | |
function ViewCollection() { | |
this.__type__ = View; | |
this.__collection__ = []; | |
} | |
/** | |
* Controller collection constructor | |
* @constructor | |
*/ | |
function ControllerCollection() { | |
this.__type__ = Controller; | |
this.__collection__ = []; | |
} | |
/** | |
* Generate model globals | |
*/ | |
global.Model = Model.extend(Model); | |
global.ModelCollection = AbstractCollection.extend(ModelCollection); | |
global.ModelEvent = ModelEvent; | |
/** | |
* Generate view globals | |
*/ | |
global.View = View.extend(View); | |
global.ViewCollection = AbstractCollection.extend(ViewCollection); | |
global.ViewEvent = ViewEvent; | |
/** | |
* Generate controller collection | |
*/ | |
global.Controller = Controller.extend(Controller); | |
global.ControllerCollection = AbstractCollection.extend(ControllerCollection); | |
global.ControllerEvent = ControllerEvent; | |
/** | |
* Generate abstract globals | |
*/ | |
global.AbstractCollection = AbstractCollection; | |
})( | |
// Global object | |
window | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment