"use strict"; (function($) { $(document).ready(function() { console.log('ws: init UI parts'); /** * Initialize an empty object to be populated as follows: * - key is an UI element's id * - value associated is an obj containing: tmpl (the template) and $elem (jQueried target element) */ _ws.ui = {}; /** * Generic template-based rendering function */ function viewDefaultRender(data) { if(! data) { console.log('WARNING! You should provide data for #' + elemId + "'s render()"); } this.$elem.empty(); this.$elem.html( Mustache.render( this.tmpl, data ) ); this.$elem.show(); this.bindEvents(); } /** * Wrapper around provided render function (show elem after render) */ function viewRenderWrapper(data) { this._render(data); this.$elem.show(); } /** * Bind events */ function viewBindEvents() { var events = this.props.events; for(var descriptor in events) { var handler = events[descriptor]; var bits = descriptor.split(' '); var evtName = bits.shift(); var selector = bits.join(' '); var target = selector === '' ? this.$elem : this.$elem.find(selector); console.log('#### bind', descriptor, 'e:' + evtName, 's:[' + selector + '], target:', target); target.on(evtName, handler.bind(this)); } } /** * Bind events: nop */ function viewBindEventsNop() { console.log(this.partName, 'bindEvents:nop'); } /** * Show view element */ function viewElemShow() { this.$elem.show(); } /** * Hide view element */ function hideElemShow() { this.$elem.hide(); } /** * Build a view */ _ws.makeView = function(elemId, props) { var v = {}; v.props = props || {}; v.$elem = $('#' + elemId); v.partName = _.camelCase(elemId); _ws.ui[v.partName] = v; // Bind the provided render function if(typeof v.props.render === 'function') { v._render = props.render.bind(v); v.render = viewRenderWrapper.bind(v); } // Otherwise assign the default render function else { var $tmplEl = $('script[data-tmpl-for="' + elemId + '"]'); v.tmpl = $tmplEl.html(); v.render = viewDefaultRender.bind(v); } // Set event handlers if(v.props.events) { v.bindEvents = viewBindEvents.bind(v); v.bindEvents(); } else { v.bindEvents = viewBindEventsNop.bind(v); } // Pass arbitrary properties for(var p in props) { if(['render', 'events', 'init'].indexOf(p) !== -1) { // console.log('pass props: ignore', p); continue; } v[p] = props[p]; } v.show = viewElemShow.bind(v); v.hide = hideElemShow.bind(v); // Init if an init function was provided if(typeof v.props.init === 'function') { var initFunc = v.props.init.bind(v); initFunc(); } }; }); })(jQuery);