Skip to content

Instantly share code, notes, and snippets.

@codeBelt
Last active January 1, 2016 21:19
Show Gist options
  • Select an option

  • Save codeBelt/8202467 to your computer and use it in GitHub Desktop.

Select an option

Save codeBelt/8202467 to your computer and use it in GitHub Desktop.
A basic view setup for require.
define(function(require) {
'use strict';
var $ = require('jquery');
var PubSubUtil = require('utils/PubSubUtil');
/**
* Function typeof value
*
* @type String
* @final
*/
var FUNCTION = 'function';
/**
* Abstract view class
*
* @class Sisley.View.AbstractView
* @extends Sisley.Util.PubSubUtil
*
* @constructor
*/
var AbstractView = function() {
// No nothing as this class should always be extended, never instantiated on its own.
};
AbstractView.prototype = new PubSubUtil();
AbstractView.prototype.constructor = AbstractView;
/**
* Initialize class
*
* @method init
* @param {jQuery|HTMLElement|String} element
* @chainable
*/
AbstractView.prototype.init = function(element) {
/**
* @property _isEnabled
* @type Boolean
* @private
*/
this._isEnabled = false;
return this
.setElement(element)
.setupHandlers()
.createChildren()
.layout()
.enable();
};
/**
* Setup event handlers
*
* @method setupHandlers
* @chainable
*/
AbstractView.prototype.setupHandlers = function() {
return this;
};
/**
* Create any child objects or references to DOM elements.
*
* @method createChildren
* @chainable
*/
AbstractView.prototype.createChildren = function() {
return this;
};
/**
* Remove any child objects or references to DOM elements.
*
* @method removeChildren
* @chainable
*/
AbstractView.prototype.removeChildren = function() {
return this;
};
/**
* Perform layout adjustments
*
* @method layout
* @chainable
*/
AbstractView.prototype.layout = function() {
return this;
};
/**
* Set view element. If class is enable, then re-enable it after setting the new element.
*
* @method setElement
* @param {jQuery|HTMLElement|String} element
* @chainable
*/
AbstractView.prototype.setElement = function(element) {
var isEnabled = this.isEnabled();
if (isEnabled) {
this.disable();
}
/**
* @property $element
* @type jQuery
*/
this.$element = element instanceof $ ? element : $(element);
/**
* @property element
* @type HTMLElement
*/
this.element = this.$element.get(0);
if (isEnabled) {
this.enable();
}
return this;
};
/**
* Determine if view is enabled right now
*
* @method isEnabled
* @return {Boolean}
*/
AbstractView.prototype.isEnabled = function() {
return this._isEnabled === true;
};
/**
* Enable event listeners
*
* @method enable
* @chainable
*/
AbstractView.prototype.enable = function() {
this._isEnabled = true;
return this;
};
/**
* Disable event listeners
*
* @method disable
* @chainable
*/
AbstractView.prototype.disable = function() {
this._isEnabled = false;
return this;
};
/**
* Add event listener to this view
*
* @method on
* @param {String} event
* @param {String|Function} selector
* @param {Function} [callback]
* @chainable
*/
AbstractView.prototype.on = function(event, selector, callback) {
if (typeof callback !== FUNCTION && typeof selector !== FUNCTION) {
throw new TypeError('selector or callback must be of type ' + FUNCTION);
}
this.$element.on(event, selector, callback);
return this;
};
/**
* Remove event listener to this view.
*
* @method off
* @param {String} [event]
* @param {String|Function} [selector]
* @param {Function} [callback]
* @chainable
*/
AbstractView.prototype.off = function(event, selector, callback) {
this.$element.off(event, selector, callback);
return this;
};
/**
* Destroy view
*
* @method destroy
* @chainable
*/
AbstractView.prototype.destroy = function() {
return this
.off()
.unsubscribe()
.remove();
};
/**
* Remove element from its parent
*
* @method remove
* @chainable
*/
AbstractView.prototype.remove = function() {
this.$element.remove();
return this;
};
/**
* Shortcut for `this.$element.find()`
*
* @method find
* @param {String} selector
* @return {jQuery}
*/
AbstractView.prototype.find = function(selector) {
return this.$element.find(selector);
};
/**
* Get view element
*
* @method getElement
* @return {HTMLElement}
*/
AbstractView.prototype.getElement = function() {
return this.element;
};
return AbstractView;
});
define(function () {
'use strict';
/**
* String type
*
* @type String
* @ignore
* @final
*/
var TYPE_STRING = 'string';
/**
* Functin type
*
* @type String
* @ignore
* @final
*/
var TYPE_FUNCTION = 'function';
/**
* Value when Array.indexOf cannot find needle
*
* @type Number
* @ignore
* @final
*/
var INDEX_NOT_FOUND = -1;
/**
* Variable name events are stored in
*
* @type String
* @private
* @ignore
*/
var _eventVariableName = '__events__';
/**
* Type error
*
* @type TypeError
* @private
* @ignore
*/
var _typeError = TypeError;
/**
* Publish/Subscribe Event stack
*
* @class Sisley.Util.PubSubUtil.Event
*
* @constructor
* @param {String} event
*/
var PubSubEvent = function(event) {
/**
* Current event's publish state
*
* @property _isPublishing
* @type Boolean
* @default false
* @ignore
* @protected TODO: unknown doc tag
*/
var _isPublishing = false;
/**
* Current publish loop index
*
* @property _i
* @type Number
* @default -1
* @ignore
* @protected TODO: unknown doc tag
*/
var _i = -1;
/**
* Callback stack
*
* @property stack
* @type Function[]
*/
var stack = this.stack = [];
/**
* Event name
*
* @property event
* @type String
*/
this.event = event;
/**
* Current length of event stack
*
* @property _length
* @type Number
* @default 0
* @ignore
* @protected TODO: unknown doc tag
*/
var _length = 0;
/**
* Add callback to event stack.
*
* @throws {TypeError} If `callback` is not of type `function`
*
* @method add
* @param {Function} callback
* @chainable
*/
this.add = function(callback) {
if (typeof callback !== TYPE_FUNCTION) {
throw new _typeError('callback should be of type ' + TYPE_FUNCTION);
}
if (stack.indexOf(callback) !== INDEX_NOT_FOUND) {
return this;
}
stack.push(callback);
_length = stack.length;
return this;
};
/**
* Remove callback from event stack.
* Will silently fail if no callback is provided, or it
* is not found in current event stack.
*
* If event stack is currently being published, index and length of publish loop are adjusted to compensate
*
* @method remove
* @param {Function} [callback]
* @chainable
*/
this.remove = function(callback) {
if (callback === void 0) {
stack.length = 0;
_length = stack.length;
return this;
}
var index = stack.indexOf(callback);
if (index === INDEX_NOT_FOUND) {
return this;
}
stack.splice(index, 1);
if (_isPublishing) {
if (index <= _i) {
_i--;
}
}
_length = stack.length;
return this;
};
/**
* Publish event by triggering all events in stack
*
* @method publish
* @param {Array|Arguments} [args]
* @chainable
*/
this.publish = function(args) {
_isPublishing = true;
_i = -1;
while (++_i < _length) {
stack[_i].apply(window, args);
}
_isPublishing = false;
return this;
};
};
/**
* Publish/Subscribe event system
*
* @class Sisley.Util.PubSubUtil
* @constructor
*/
var PubSub = function() {};
/**
* Subscribe a `callback` to a specified `event` name
*
* @throws {TypeError} If `event` is not of type `String` or `callback` is not of type `Function`
*
* @method subscribe
* @param {String} event
* @param {Function} callback
* @chainable
*/
PubSub.prototype.subscribe = function (event, callback) {
if (typeof event !== TYPE_STRING || typeof callback !== TYPE_FUNCTION) {
throw new _typeError('Invalid use of subscribe: subscribe(event, callback)');
}
if (!this[_eventVariableName]) {
this[_eventVariableName] = {};
}
/**
* Object of subscribed events names and their stacks
*
* @property __events__
* @type Object
* @private
*/
var events = this[_eventVariableName][event] || (this[_eventVariableName][event] = new PubSubEvent(event));
events.add(callback);
return this;
};
/**
* Unsubscribe a `callback` from a specified `event` stack.
* If `callback` in undefined, then all callbacks are unsubscribed from `event`.
* If `callback` and `event` are undefined, then all callbacks from all events are unsubscribed.
*
* @method unsubscribe
* @param {String} [event]
* @param {Function} [callback]
* @chainable
*/
PubSub.prototype.unsubscribe = function (event, callback) {
if (event === void 0) {
var name;
for (name in this[_eventVariableName]) {
if (this[_eventVariableName].hasOwnProperty(name)) {
this[_eventVariableName][name].remove();
}
}
this[_eventVariableName] = {};
return this;
}
if (!this[_eventVariableName]) {
return this;
}
var events = this[_eventVariableName][event];
if (events) {
events.remove(callback);
}
return this;
};
/**
* Publish an `event`. All callbacks subscribed to `event` will be triggered.
* Any additional arguments supplied will be passed to the callbacks.
* Any callbacks subscribed to the `all` event will also be triggered.
*
* @throws {TypeError} If event is not of type `String`
*
* @method publish
* @param {String} event
* @chainable
*/
PubSub.prototype.publish = function (event) {
if (typeof event !== TYPE_STRING) {
throw new _typeError('Invalid use of publish: publish(event[, ...args])');
}
if (!this[_eventVariableName]) {
return this;
}
var events = this[_eventVariableName][event];
var allEvents = this[_eventVariableName].all;
if (events) {
events.publish(arguments);
}
if (allEvents) {
allEvents.publish(arguments);
}
return this;
};
/**
* Publish/Subscribe helper. Will add `subscribe`, `unsubscribe`,
* and `publish` methods to the supplied object.
*
* @param {Object} obj
* @return {Object}
* @static
*/
PubSub.apply = function(obj) {
obj.subscribe = this.prototype.subscribe;
obj.unsubscribe = this.prototype.unsubscribe;
obj.publish = this.prototype.publish;
return obj;
};
return PubSub;
});
define(function (require, exports, module) {
'use strict';
var ${Extends} = require('./${Extends}');
/**
* @class ${NAME}
* @extends ${Extends}
*
* @constructor
*/
var ${NAME} = function(element) {
this.init(element);
};
${NAME}.prototype = new ${Extends}();
${NAME}.prototype.constructor = ${NAME};
var base = ${Extends}.prototype;
/**
* Setup event handlers
*
* @method setupHandlers
* @chainable
*/
${NAME}.prototype.setupHandlers = function() {
return this;
};
/**
* Create any child objects or references to DOM elements.
*
* @method createChildren
* @chainable
*/
${NAME}.prototype.createChildren = function() {
base.createChildren.call(this);
return this;
};
/**
* Perform layout adjustments
*
* @method layout
* @chainable
*/
${NAME}.prototype.layout = function() {
base.layout.call(this);
return this;
};
/**
* @method enable
* @chainable
*/
${NAME}.prototype.enable = function() {
return base.enable.call(this);
};
/**
* @method disable
* @chainable
*/
${NAME}.prototype.disable = function() {
return base.disable.call(this);
};
//////////////////////////////////////////////////////////////////////////////////
// EVENT HANDLERS
//////////////////////////////////////////////////////////////////////////////////
/**
* onClick handler.
*
* @method onClick
* @param event {JQueryEventObject} JavaScript event object.
* @private
*/
${NAME}.prototype.onClick = function(event) {
};
module.exports = ${NAME};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment