--- /dev/null
+'use strict';
+
+Class("UnlimitedPizza").inherits(Widget)({
+
+ /**
+ * Gets instance, creates it if not available.
+ */
+ instance : function getInstance(config) {
+ if (!this._mainInstance) {
+ this._mainInstance = new this(config);
+ }
+ return this._mainInstance;
+ },
+
+ prototype : {
+ _loaded : false,
+
+ init : function (config) {
+ Widget.prototype.init.call(this, config)
+
+ this._bindInternalEvents();
+ },
+
+ _bindInternalEvents : function bindInternalEvents() {
+ this.bind('activate', this._onActivate.bind(this));
+ },
+
+ _onActivate : function _activate() {
+ // If this is the first time activating it... then load
+ if (!this._loaded) {
+ this._load();
+ }
+ },
+
+ /*
+ * Loads everything.
+ */
+ _load : function _load() {
+
+ // Melty cheese is our header image widget.
+ this._loadMeltyCheese();
+ },
+
+ _loadMeltyCheese : function() {
+ this.element.find('.post-image').each(function (i, headerElement) {
+
+ // Create and activate
+ this.appendChild(new UnlimitedPizza.MeltyCheese({
+ element : $(headerElement),
+ name : 'header-' + i
+ }));
+ this['header-' + i].activate();
+ }.bind(this));
+ }
+ }
+});
--- /dev/null
+'use strict';
+
+Class(UnlimitedPizza, "MeltyCheese").inherits(Widget)({
+ prototype : {
+ min : 60, // min height of the element
+ max : 480, // max height of the element
+ minThreshold : 200, // distance from bottom before we start
+ maxThreshold : 500, // distance from bottom before we stop
+ _loaded : false,
+
+ init : function (config) {
+ Widget.prototype.init.call(this, config)
+
+ this._bindInternalEvents();
+ },
+
+ _bindInternalEvents : function bindInternalEvents() {
+ this.bind('activate', this._onActivate.bind(this));
+ this.bind('deactivate', this._onDeactivate.bind(this));
+ },
+
+ _onActivate : function _activate() {
+ // If this is the first time activating it... then load
+ if (!this._loaded) {
+ this._load();
+ }
+ },
+
+ _onDeactivate : function _deactivate() {
+ this._unload();
+ },
+
+ /*
+ * Loads everything.
+ */
+ _load : function _load() {
+ this._bindEvents();
+
+ this.image = this.element.find('img')
+ },
+
+ _unload : function _unload() {
+ this._loaded = false;
+ this._unbindEvents();
+ },
+
+ _bindEvents : function bindEvents() {
+ $(window).on('scroll', this._onScroll.bind(this));
+ $(window).on('resize', this._onScroll.bind(this));
+ },
+
+ _unbindEvents : function unbindEvents() {
+ $(window).off('scroll');
+ $(window).off('resize');
+ },
+
+ /* Listeners beyond */
+
+ _onScroll : function onScroll() {
+ var documentTop, documentBottom, elementTop, diff, height;
+
+
+ documentTop = $(window).scrollTop();
+ documentBottom = documentTop + $(window).height();
+ elementTop = this.element.offset().top;
+ diff = documentBottom - elementTop;
+
+ this.max = this.image.height();
+ this.min = this.max / 10;
+
+ diff -= this.minThreshold;
+
+ height = diff * this.max / this.maxThreshold;
+
+ if (height < this.min) {
+ height = this.min;
+ }
+
+ if (height > this.max) {
+ height = this.max;
+ }
+
+ console.log("I, ", this.name, "should be ", height);
+
+ this.element.height(height);
+ },
+
+ }
+});
--- /dev/null
+Class("Unlimitedpizza").inherits(Widget)({
+ prototype : {
+ _loaded : false,
+
+ init : function (config) {
+ Widget.constructor.prototype.init.call(this, config)
+
+ this._bindInternalEvents();
+ },
+
+ _bindInternalEvents : function bindInternalEvents() {
+ this.bind('activate', this._onActivate.bind(this));
+ this.bind('deactivate', this._onDeactivate.bind(this));
+ },
+
+ _onActivate : function _activate() {
+ if (!this._loaded) {
+ this._load();
+ }
+ },
+
+ _load : function _load() {
+ var meltyCheese;
+
+ meltyCheese = new Unlimitedpizza.MeltyCheese
+ }
+ }
+});
--- /dev/null
+
+if (typeof global === "undefined") {
+ global = window;
+}
+
+global.Interface = function Interface(nameOrNameSpace, name) {
+ var nameSpace, interfaceName, factory;
+ nameSpace = (nameOrNameSpace && name) ? nameOrNameSpace : this;
+ interfaceName = (nameOrNameSpace && name) ? name :
+ (nameOrNameSpace) ? nameOrNameSpace : 'interface' + Math.random().toString();
+ factory = function(definition) {
+ definition.isInterface = true;
+ definition.name = interfaceName;
+ nameSpace[interfaceName] = definition;
+ return nameSpace[interfaceName];
+ };
+ return factory;
+};
+
+global.Module = function Module(nameOrNameSpace, name) {
+ var nameSpace, moduleName, factory, newModule;
+
+ nameSpace = (nameOrNameSpace && name) ? nameOrNameSpace : this;
+ moduleName = (nameOrNameSpace && name) ? name :
+ (nameOrNameSpace) ? nameOrNameSpace : 'module' + Math.random().toString();
+
+ newModule = {
+ moduleName : moduleName,
+ prototype : {},
+ __includedModules : [],
+ include : function(module) {
+ var property;
+ for (property in module) {
+ if (module.hasOwnProperty(property)
+ && property !== 'prototype'
+ && property !== 'isModule'
+ && property !== '__includedModules'
+ && property !== 'include'
+ && property !== 'moduleName') {
+ newModule[property] = module[property];
+ }
+ }
+
+ if (module.hasOwnProperty('prototype') && module.prototype) {
+ for (property in module.prototype) {
+ if (module.prototype.hasOwnProperty(property)) {
+ newModule.prototype[property] = module.prototype[property];
+ }
+ }
+ }
+ else {
+ module.prototype = {};
+ }
+
+ this.__includedModules.push(module);
+
+ return this;
+ }
+ }
+
+ factory = function(definition){
+ var property;
+
+ newModule.isModule = true;
+
+ for (property in definition) {
+ if (definition.hasOwnProperty(property)
+ && property !== 'prototype'
+ && property !== 'isModule'
+ && property !== '__includedModules'
+ && property !== 'include'
+ && property !== 'moduleName') {
+ newModule[property] = definition[property];
+ }
+ }
+
+ if (definition.hasOwnProperty('prototype') && definition.prototype) {
+ for (property in definition.prototype) {
+ if (definition.prototype.hasOwnProperty(property)) {
+ newModule.prototype[property] = definition.prototype[property];
+ }
+ }
+ }
+
+ nameSpace[moduleName] = newModule;
+
+ return nameSpace[moduleName];
+ };
+
+ factory.includes = function () {
+ for(var i = 0; i < arguments.length; i++){
+ newModule.include(arguments[i]);
+ }
+ return factory;
+ };
+
+ return factory;
+};
+
+global.Class = function Class(classNameOrNameSpace, className) {
+ var nameSpace, newClass, classFactory;
+ nameSpace = (classNameOrNameSpace && className) ? classNameOrNameSpace : global;
+ className = (classNameOrNameSpace && className) ? className :
+ (classNameOrNameSpace) ? classNameOrNameSpace : 'class' + Math.random().toString();
+
+ newClass = function() {
+ if (this.init) {
+ this.init.apply(this, arguments);
+ }
+ };
+
+ newClass.__descendants = [];
+ newClass.__implementedInterfaces = [];
+ newClass.__includedModules = [];
+ newClass.className = className;
+ newClass.include = function(module) {
+ var property;
+ for (property in module) {
+ if (module.hasOwnProperty(property)
+ && property != 'prototype'
+ && property != 'constructor'
+ && property != 'isModule'
+ && property != 'superClass'
+ && property != 'include') {
+ newClass[property] = module[property];
+ }
+ }
+
+ if (module.hasOwnProperty('prototype') && module.prototype) {
+ for (property in module.prototype) {
+ if (module.prototype.hasOwnProperty(property)) {
+ newClass.prototype[property] = module.prototype[property];
+ }
+ }
+ } else {
+ module.prototype = {};
+ }
+
+ newClass.__includedModules.push(module);
+ return this;
+ };
+
+ classFactory = function(classDefinition) {
+ var i, il, j, jl, property, classPrototype = classDefinition.prototype;
+ if (classPrototype) {
+ for (property in classPrototype) {
+ if (classPrototype.hasOwnProperty(property)) {
+ newClass.prototype[property] = classPrototype[property];
+ }
+ }
+ delete classDefinition.prototype;
+ }
+ for (property in classDefinition) {
+ if (classDefinition.hasOwnProperty(property)) {
+ newClass[property] = classDefinition[property];
+ }
+ }
+
+ for (i = 0, il = newClass.__implementedInterfaces.length; i < il; i++) {
+ for (j = 0, jl = newClass.__implementedInterfaces[i].constructor.length; j < jl; j++) {
+ if (!newClass[ newClass.__implementedInterfaces[i].constructor[j] ]) {
+ console.log('must implement static ' + newClass.__implementedInterfaces[i].name);
+ break;
+ }
+ }
+
+ if (newClass.__implementedInterfaces[i].hasOwnProperty('prototype')
+ && newClass.__implementedInterfaces[i].prototype) {
+ for (j = 0, jl = newClass.__implementedInterfaces[i].prototype.length; j < jl; j++) {
+ if (!newClass.prototype[newClass.__implementedInterfaces[i].prototype[j]]) {
+ console.log('must implement prototype ' + newClass.__implementedInterfaces[i].name);
+ break;
+ }
+ }
+ }
+ }
+
+ try {
+ if (Li && Li.ObjectSpy && Li.Spy) {
+ newClass.__objectSpy = new Li.ObjectSpy();
+ newClass.__objectSpy.spy(newClass);
+ newClass.__objectSpy.spy(newClass.prototype);
+ }
+ } catch (error) {}
+
+ nameSpace[className] = newClass;
+ return newClass;
+ };
+
+ classFactory.inherits = function(superClass) {
+ var i, inheritedClass;
+ newClass.superClass = superClass;
+ if (superClass.hasOwnProperty('__descendants')) {
+ superClass.__descendants.push(newClass);
+ }
+ inheritedClass = function() {
+ };
+ inheritedClass.prototype = superClass.prototype;
+ newClass.prototype = new inheritedClass();
+ newClass.prototype.constructor = newClass;
+
+ for (i in superClass) {
+ if (superClass.hasOwnProperty(i)
+ && i != 'prototype'
+ && i !== 'className'
+ && i !== 'superClass'
+ && i !== 'include'
+ && i != '__descendants') {
+ newClass[i] = superClass[i];
+ }
+ }
+
+ delete this.inherits;
+ return this;
+ };
+
+ classFactory.ensures = function(interfaces) {
+ for (var i = 0; i < arguments.length; i++) {
+ newClass.__implementedInterfaces.push(arguments[i]);
+ }
+ delete this.ensures;
+ return classFactory;
+ };
+
+ classFactory.includes = function() {
+ for (var i = 0; i < arguments.length; i++) {
+ newClass.include(arguments[i]);
+ }
+ return classFactory;
+ };
+
+ return classFactory;
+
+};
--- /dev/null
+Module('BubblingSupport')({
+ dispatch : function (type, data) {
+ data = data || {};
+ var event = CustomEventSupport.prototype.dispatch.call(this, type, data);
+ if (event.isPropagationStopped === false) {
+ if (this.parent && this.parent.dispatch) {
+ data.target = event.target;
+ data.currentTarget = this.parent;
+ this.parent.dispatch(event.type, data);
+ }
+ }
+ return event;
+ },
+
+ prototype : {
+ dispatch : function (type, data) {
+ data = data || {};
+
+ var event = CustomEventSupport.prototype.dispatch.call(this, type, data);
+
+ if (event.isPropagationStopped === false && event.bubbles === true) {
+ if (this.parent && this.parent.dispatch) {
+ data.target = event.target;
+ data.currentTarget = this.parent;
+ this.parent.dispatch(event.type, data);
+ }
+ }
+
+ return event;
+ }
+ }
+ });
--- /dev/null
+Class('CustomEvent')({
+ prototype : {
+ bubbles : true,
+ cancelable : true,
+ currentTarget : null,
+ timeStamp : 0,
+ target : null,
+ type : '',
+ isPropagationStopped : false,
+ isDefaultPrevented : false,
+ isImmediatePropagationStopped : false,
+ areImmediateHandlersPrevented : false,
+ init : function init(type, data) {
+ this.type = type;
+ if (typeof data !== 'undefined') {
+ for(var property in data) {
+ if (data.hasOwnProperty(property)) {
+ this[property] = data[property];
+ }
+ }
+ }
+ },
+ stopPropagation : function stopPropagation() {
+ this.isPropagationStopped = true;
+ },
+ preventDefault : function preventDefault() {
+ this.isDefaultPrevented = true;
+ },
+ stopImmediatePropagation : function stopImmediatePropagation() {
+ this.preventImmediateHandlers();
+ this.stopPropagation();
+ },
+ preventImmediateHandlers : function preventImmediateHandlers() {
+ this.areImmediateHandlersPrevented = true;
+ }
+ }
+});
--- /dev/null
+Module('CustomEventSupport')({
+
+ eventListeners : null,
+
+ bind : function(type, eventHandler) {
+ var found, i, listeners;
+
+ if(!this.eventListeners) {
+ this.eventListeners = {};
+ }
+
+ if(!this.eventListeners[type]) {
+ this.eventListeners[type] = [];
+ }
+
+ found = false;
+
+ listeners = this.eventListeners[type];
+ for (i = 0; i < listeners.length; i++) {
+ if (listeners[i] === eventHandler) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found) {
+ this.eventListeners[type].push(eventHandler);
+ }
+
+ return this;
+ },
+
+ unbind : function(type, eventHandler) {
+ var i, found, listeners;
+
+ found = false;
+
+ if(!this.eventListeners) {
+ this.eventListeners = {};
+ }
+
+ if(typeof eventHandler == 'undefined') {
+ this.eventListeners[type] = [];
+ }
+
+ listeners = this.eventListeners[type];
+ for (i = 0; i < listeners.length; i++) {
+ if(listeners[i] === eventHandler) {
+ found = true;
+ break;
+ }
+ }
+
+ if(found) {
+ this.eventListeners[type].splice(i, 1);
+ }
+
+ return this;
+ },
+
+ dispatch : function(type, data) {
+ var event, listeners, instance, i;
+
+ if (this.eventListeners === null) {
+ this.eventListeners = {};
+ }
+
+ if (typeof data === 'undefined') {
+ data = {};
+ }
+
+ if (data.hasOwnProperty('target') === false) {
+ data.target = this;
+ }
+
+ event = new CustomEvent(type, data);
+ listeners = this.eventListeners[type] || [];
+ instance = this;
+
+ for (i = 0; i < listeners.length; i = i + 1) {
+ listeners[i].call(instance, event);
+ if (event.areImmediateHandlersPrevented === true) {
+ break;
+ }
+ }
+
+ return event;
+ },
+
+ prototype : {
+
+ eventListeners : null,
+
+ bind : function(type, eventHandler) {
+ var found, i, listeners;
+
+ if(!this.eventListeners) {
+ this.eventListeners = {};
+ }
+
+ if(!this.eventListeners[type]) {
+ this.eventListeners[type] = [];
+ }
+
+ found = false;
+
+ listeners = this.eventListeners[type];
+ for (i = 0; i < listeners.length; i++) {
+ if(listeners[i] === eventHandler) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found) {
+ this.eventListeners[type].push(eventHandler);
+ }
+
+ return this;
+ },
+
+ unbind : function(type, eventHandler) {
+ var i, found, listeners;
+
+ found = false;
+ i = 0;
+
+ if(!this.eventListeners) {
+ this.eventListeners = {};
+ }
+
+ if(typeof eventHandler == 'undefined') {
+ this.eventListeners[type] = [];
+ }
+
+ listeners = this.eventListeners[type];
+ for (i = 0; i < listeners.length; i++) {
+ if(listeners[i] == eventHandler) {
+ found = true;
+ break;
+ }
+ }
+
+ if(found) {
+ this.eventListeners[type].splice(i, 1);
+ }
+
+ return this;
+ },
+
+ dispatch : function(type, data) {
+ var event, listeners, instance, i;
+
+ if (this.eventListeners === null) {
+ this.eventListeners = {};
+ }
+
+ if (typeof data === 'undefined') {
+ data = {};
+ }
+
+ if (data.hasOwnProperty('target') === false) {
+ data.target = this;
+ }
+
+ event = new CustomEvent(type, data);
+ listeners = this.eventListeners[type] || [];
+ instance = this;
+
+ for (i = 0; i < listeners.length; i = i + 1) {
+ listeners[i].call(instance, event);
+ if (event.areImmediateHandlersPrevented === true) {
+ break;
+ }
+ }
+
+ return event;
+ }
+ }
+});
--- /dev/null
+// This file is node only
+if(typeof require !== 'undefined'){
+ require('./custom_event');
+ require('./custom_event_support');
+ require('./node_support');
+ require('./bubbling_support');
+}
--- /dev/null
+Module('NodeSupport')({
+ prototype : {
+ parent : null,
+
+ children : [],
+
+ appendChild : function(child) {
+ if(child.parent) {
+ child.parent.removeChild(child);
+ }
+
+ if(!this.hasOwnProperty('children')) {
+ this.children = [];
+ }
+
+ this.children.push(child);
+ this[child.name] = child;
+ child.setParent(this);
+ return child;
+ },
+
+ insertBefore : function (child, beforeChild) {
+ var position;
+
+ if (child.parent) {
+ child.parent.removeChild(child);
+ }
+
+ if (!this.hasOwnProperty('children')) {
+ this.children = [];
+ }
+
+ if (typeof beforeChild === 'undefined') {
+ this.appendChild(child);
+ } else {
+ position = this.children.indexOf(beforeChild);
+ this.children.splice(position, 0, child);
+
+ this[child.name] = child;
+ child.setParent(this);
+ }
+
+ return child;
+
+ },
+
+ insertChild : function(child, position) {
+ console.warn('NodeSupport insertChild method is deprecated, try insertBefore');
+
+ if (child.parent) {
+ child.parent.removeChild(child);
+ }
+
+ if (!this.hasOwnProperty('children')) {
+ this.children = [];
+ }
+
+ if (typeof position == 'undefined') {
+ this.children.push(child);
+ this[child.name] = child;
+ child.setParent(this);
+ return child;
+ }
+
+ this.children.splice(position, 0, child);
+ this[child.name] = child;
+ child.setParent(this);
+ return child;
+ },
+
+ removeChild : function (child) {
+ var position = this.children.indexOf(child);
+
+ if (position !== -1) {
+ this.children.splice(position, 1);
+ delete this[child.name];
+ child.parent = null;
+ }
+
+ return child;
+ },
+
+ setParent : function (parent) {
+ this.parent = parent;
+ return this;
+ },
+
+ getDescendants : function () {
+ var nodes = [];
+ this.children.forEach(function (node) {
+ nodes.push(node);
+ });
+ this.children.forEach(function (node) {
+ nodes = nodes.concat(node.getDescendants());
+ });
+ return nodes;
+ },
+
+ getPreviousSibling : function () {
+ if (typeof this.parent === 'undefined') {
+ return;
+ }
+
+ if (this.parent.children[0] === this) {
+ return;
+ }
+
+ return this.parent.children[ this.parent.children.indexOf(this) - 1 ];
+ },
+
+ getNextSibling : function () {
+ if (typeof this.parent === 'undefined') {
+ return;
+ }
+
+ if (this.parent.children[ this.parent.children.length - 1 ] === this) {
+ return;
+ }
+
+ return this.parent.children[ this.parent.children.indexOf(this) + 1 ];
+ }
+ }
+});
--- /dev/null
+/**
+Base Class from which almost all widgets are based overall the project
+
+The main idea behind constructing a new widget toolkit instead of using one of the many high quality widget
+toolkits avaliable is that we considered that currently, no widget system provides all the features that where
+required for this project.
+
+Features of the widget system
+* A custom and easy to handle event binding, dispatching and manipulation, with some sort of bubbling support
+* A module system which we can use to include specific behaviour to any widget and reuse the code where needed
+* A tree structure support for the widgets that the event system could bubble, and that also serves as
+* A navigation system.
+* The widgets must be able to be grouped to form more complex widgets
+* Remove the complexity of DOM manipulation and handling
+* A way to wrap widgets at our convenience to reuse widgets avaliable and make them comly to our needs
+without the need to hack those widgets, that would force us to maintain the new versions of those widgets
+and that is a very complex task when widgets become so complex.
+* A widget system that would allow us to start wrapping some widgets for a fast start and later code our own widgets
+at will.
+* expose a consistent API that allow us to choose the use of widgets by API calls and user interaction at will and with the same
+clearance and capacity
+* an easy way to allow subclasing widgets
+* an easy way to provide new html, class, and css for a specific instance of a widget that would remove us the need
+to create complex inheritance structures that are hard to maintain.
+
+Usage Example.
+
+The most basic usage of a widget is to simply create an instance and render it at a target element
+in this case body
+var myWidgetInstance = new Breezi.Widget();
+myWidgetInstance.render(document.body);
+
+like this widget does renders does not display anything so lets give it something to display first
+var myWidgetInstance = new Breezi.Widget();
+myWidgetInstance.element.html('Im a simple widget');
+myWidgetInstance.render(document.body);
+
+this reveals that internally every widget has an element property that is initialized by default to a jQuery Instance
+this allow easy DOM manipulation, animation and operations handled by a high quality third party library.
+@class Widget
+@namespace Breezi
+@inlcudes CustomEventSupport
+@includes NodeSupport
+@dependency Neon
+@dependency CustomEventSupport
+@dependency NodeSupport
+**/
+Class('Widget').includes(CustomEventSupport, NodeSupport)({
+
+ /**
+ The default html for the widget, at the most simple case this is just a div.
+ @name HTML
+ @attribute_type CONSTANT
+ @type String
+ */
+ HTML : '<div></div>',
+
+ /**
+ the widget container default class for all widgets is widget
+ @name ELEMENT_CLASS
+ @constant
+ @type String
+ **/
+ ELEMENT_CLASS : 'widget',
+
+ /**
+ @property prototype
+ @type Object
+ **/
+ prototype : {
+ /**
+ Holds the active status of the widget
+ By default all widgets are deactivated waiting
+ for an action to activate it.
+ @property active <public> [Boolean] (false)
+ **/
+ active : false,
+
+ /**
+ Holds the disabled status of the widget
+ By default all widgets are enabled and only by
+ API could be disabled.
+ @property disabled <public> [Boolean] (false)
+ **/
+ disabled : false,
+
+ __destroyed : false,
+
+ init : function init(config) {
+ var property;
+
+ Object.keys(config || {}).forEach(function (propertyName) {
+ this[propertyName] = config[propertyName];
+ }, this);
+
+ if (this.element == null) {
+ this.element = $(this.constructor.HTML.replace(/\s\s+/g, ''));
+ this.element.addClass(this.constructor.ELEMENT_CLASS);
+ }
+
+ if (this.hasOwnProperty('className') === true) {
+ this.element.addClass(this.className);
+ }
+ },
+
+ /**
+ implementation of the activate method, when you need an override, do it
+ over this method instead of doing it on activate
+ @property _activate <private> [Function]
+ @return undefined [undefined]
+ **/
+ _activate : function _activate() {
+ this.active = true;
+ this.element.addClass('active');
+ },
+
+ /**
+ Public activation method for widget, you can listen to this event
+ to take some other actions, but the most important part of this
+ method is that it runs its default action, (its activation)
+ this method uses _activate as its implementation to maintain
+ the events order intact.
+ @property activate <public> [Function]
+ @method
+ @dispatch beforeActivate
+ @dispatch activate
+ @return this [Widget]
+ **/
+ activate : function activate() {
+ if (this.__destroyed === true) {
+ console.warn('calling on destroyed object');
+ }
+ this.dispatch('beforeActivate');
+ this._activate();
+ this.dispatch('activate');
+ return this;
+ },
+
+ /**
+ deactivation implementation
+ this is the oposite of activation method and as such it must be
+ treated as important as that.
+ @property _deactivate <private> [Function]
+ @method
+ @return undefined [undefined]
+ **/
+ _deactivate : function _deactivate() {
+ this.active = false;
+ this.element.removeClass('active');
+ },
+
+ /**
+ Public deactivation method for widget, you can listen to this event
+ to take some other actions, but the most important part of this
+ method is that it runs its default action, (its activation)
+ this method uses _deactivate as its implementation to maintain
+ the events order intact.
+ @property activate <public> [Function]
+ @method
+ @dispatch beforeDeactivatee
+ @dispatch deactivate
+ @return this [Widget]
+ **/
+ deactivate : function deactivate() {
+ if (this.__destroyed === true) {
+ console.warn('calling on destroyed object');
+ }
+ this.dispatch('beforeDeactivate');
+ this._deactivate();
+ this.dispatch('deactivate');
+ return this;
+ },
+
+ /**
+ Enable implementation method
+ if you need to provide a different procedure for enable
+ you must override this method and call "super"
+ @property _enable <private> [Function]
+ @method
+ @return undefined [undefined]
+ **/
+ _enable : function _enable() {
+ this.disabled = false;
+ this.element.removeClass('disable');
+ },
+
+ /**
+ Public enable method, this method should not be
+ overriden.
+ @property enable <public> [Function]
+ @method
+ @return this [Widget]
+ **/
+ enable : function enable() {
+ if (this.__destroyed === true) {
+ console.warn('calling on destroyed object');
+ }
+ this.dispatch('beforeEnable');
+ this._enable();
+ this.dispatch('enable');
+
+ return this;
+ },
+
+ /**
+ Disable implementation
+ @property _disable <private> [Function]
+ @return undefined [undefined]
+ **/
+ _disable : function _disable() {
+ this.disabled = true;
+ this.element.addClass('disable');
+ },
+
+ /**
+ Disables the widget, the idea behind disabling a widget
+ comes from DOM form elements. so following this idea
+ all widgets can be disabled and queried for its disabled
+ state via the disabled property.
+ Same as DOM form elements there is feedback and that is why
+ the default implementation sets the "disable" class
+ on the element so proper visual feedback can be provided
+ to the user.
+ @property disable <public> [Function]
+ @method
+ @return this [Widget]
+ **/
+ disable : function disable() {
+ if (this.__destroyed === true) {
+ console.warn('calling on destroyed object');
+ }
+ this.dispatch('beforeDisable');
+ this._disable();
+ this.dispatch('disable');
+
+ return this;
+ },
+
+ /**
+ Destroy implementation. Its main responsabilities are cleaning
+ all references to other objects so garbage collector can collect
+ the memory used by this and the other objects
+ @property _destroy <private> [Function]
+ @method
+ @return undefined [undefined]
+ **/
+ _destroy : function _destroy() {
+ var childrenLength;
+
+ if (this.element) {
+ this.element.remove();
+ }
+
+ if (this.children !== null){
+ childrenLength = this.children.length;
+ while(childrenLength > 0){
+ this.children[0].destroy();
+ if (this.children.length === childrenLength) {
+ this.children.shift();
+ }
+ childrenLength--;
+ }
+ }
+
+ if (this.parent) {
+ this.parent.removeChild(this);
+ }
+
+ this.children = null;
+ this.element = null;
+ },
+
+ /**
+ Destroy public method, this one should not be replaced
+ @property destroy <public> [Function]
+ @method
+ @return null [null]
+ **/
+ destroy : function destroy() {
+ if (this.__destroyed === true) {
+ console.warn('calling on destroyed object');
+ }
+
+ this.dispatch('beforeDestroy');
+ this._destroy();
+ this.dispatch('destroy');
+
+ this.eventListeners = null;
+ this.__destroyed = true;
+
+ return null;
+ },
+
+ /**
+ The render method is the mechanism by which you pass a widget from
+ living only on memory to get into the DOM and with this into the
+ application flow. The recomendation is that render is the last method
+ of the setup of a widget, including appending its children. this is
+ because once a widget gets renderer, further operations cause browser
+ reflows, and DOM operations are slower than memory operations.
+ This method shoudl not be replaced by its children.
+ @property render <public> [Function]
+ @method
+ @argument element <required> [JQuery] (undefined) This is the element
+ into which the widget will be appended.
+ @argument beforeElement <optional> [jQuery] (undefined) this is the element
+ that will be used as a reference to insert the widgets element. this argument
+ must be a child of the "element" argument.
+ @return this [Widget]
+ **/
+ render : function render(element, beforeElement) {
+ if (this.__destroyed === true) {
+ console.warn('calling on destroyed object');
+ }
+ this.dispatch('beforeRender', {
+ element : element,
+ beforeElement : beforeElement
+ });
+ if (beforeElement) {
+ this.element.insertBefore(beforeElement);
+ } else {
+ this.element.appendTo(element);
+ }
+ this.dispatch('render');
+ return this;
+ }
+ }
+});