Skip to content

Instantly share code, notes, and snippets.

@skamenetskiy
Created March 26, 2015 17:02
Show Gist options
  • Save skamenetskiy/330bc48971116593863f to your computer and use it in GitHub Desktop.
Save skamenetskiy/330bc48971116593863f to your computer and use it in GitHub Desktop.
/**
* @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