/**
* Created by z on 27.11.2015.
*/
'use strict';
/**
* This class implements renderable interface.
* Renderable is an object that can have child Renderable elements. Renderable.render method
* creates DOM element with child elements according to domAttributes property. Any renderable
* can have on<Eventname> method that will be called when DOM element event with corresponding
* name is triggered e.g. renderable.onClick willbe called on $(element).trigger('click').
*
* @param domAttributes - json object e.g. :
* id: 'element-id',
* class: ["class1","class2"],
* element: '<div/>',
* attributes: {src:"url"}
*
* @constructor
*/
SUXESS.Renderable = function ( domAttributes ) {
domAttributes = domAttributes || {};
this._domAttributes = {
id: undefined,
class: [],
element: '<div/>',
attributes: {}
};
this._lastRender = null;
this._children = [];
this._domCallbacks = [];
for( var prop in domAttributes){
this._domAttributes[prop] = domAttributes[prop];
}
};
/**
* Adds renderable to children renderables
* @param {SUXESS.Renderable} c
*/
SUXESS.Renderable.prototype.addChild = function (c) {
this._children.push(c);
};
/**
* Returns array of children elements.
* @return {Array} - Array of SUXESS.Renderable
*/
SUXESS.Renderable.prototype.getChildren = function () {
return this._children;
};
/**
* Returns DOM element with child elements according to domAttributes with proper callbacks bound.
* @return {DOM} - DOM element
*/
SUXESS.Renderable.prototype.render = function () {
var children = this.getChildren();
var childElems = [];
for( var i = 0; i < children.length; i++ ) {
childElems.push( children[i].render() );
}
var element = $( this._domAttributes.element )[0];
this._addCssId(element);
this._addCssClasses(element);
this._addJsCallbacks(element);
this._addHtmlAttributes(element);
for( i = 0; i < this._domCallbacks.length; i++) {
$(element).on(this._domCallbacks[i].event, this._domCallbacks[i].fn );
}
for( i = 0; i < childElems.length; i++ ) {
$(element).append( childElems[i] );
}
$(element).data('renderable', this);
this._lastRender = element;
return element;
};
/**
* Returns last rendered dom element.
* @return {element}
*/
SUXESS.Renderable.prototype.getRender = function () {
return this._lastRender;
};
/**
* Adds callback to last render and any future renders.
* Basically same as $(render).on(event,fn)
* @param event
* @param fn
*/
SUXESS.Renderable.prototype.addDomCallback = function (event, fn) {
this._domCallbacks.push({event:event, fn:fn});
if ( this._lastRender !== null ) {
$(this._lastRender).on(event,fn);
}
};
/**
* Adds id to element being created.
* @param e
* @private
*/
SUXESS.Renderable.prototype._addCssId = function (e) {
$(e).attr( 'id', this._domAttributes.id );
};
/**
* Adds css classes to element being created.
* @param e
* @private
*/
SUXESS.Renderable.prototype._addCssClasses = function (e) {
var classes = this._domAttributes.class;
for( var i = 0; i < classes.length; i++ ) {
$(e).addClass( classes[i] );
}
};
/**
* Adds event callbacks using on<Eventname> methods to element being created.
* Any method that matches ^on[A-Z].* will be added to event callbacks.
* @param e
* @private
*/
SUXESS.Renderable.prototype._addJsCallbacks = function (e) {
// PROPERTIES
var callbacks = Object.getOwnPropertyNames(this).filter(
function( property ) {
if( typeof this[property] !== 'function' )
return false;
if( !property.match(/^on[A-Z].*/) )
return false;
return true;
},
this
);
var name;
for( var i = 0; i < callbacks.length; i++ ){
name = callbacks[i].substring( 2 );
name = name.charAt(0).toLowerCase() + name.slice(1);
$(e).on(name, this[ callbacks[i] ].bind(this) );
}
// PROTOTYPE METHODS
callbacks = [];
var proto = Object.getPrototypeOf(this);
for( var f in proto ){
if( f.match(/^on[A-Z].*/) ){
name = f.substring( 2 );
name = name.charAt(0).toLowerCase() + name.slice(1);
$(e).on(name, proto[ f ].bind(this) );
}
}
};
/**
* Adds html attributes to element being created.
* @param e
* @private
*/
SUXESS.Renderable.prototype._addHtmlAttributes = function (e) {
$(e).attr( this._domAttributes.attributes );
};