ws-ui-parts.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. "use strict";
  2. (function($) {
  3. $(document).ready(function() {
  4. // console.log('ws: init UI parts');
  5. /**
  6. * Initialize an empty object to be populated as follows:
  7. * - key is an UI element's id
  8. * - value associated is an obj containing: tmpl (the template) and $elem (jQueried target element)
  9. */
  10. _ws.ui = {};
  11. /**
  12. * Generic template-based rendering function
  13. */
  14. function viewDefaultRender(elemId) {
  15. return function(data) {
  16. if(! data) {
  17. throw new Error('WARNING! You should provide data for #' + elemId + "'s render()");
  18. }
  19. this.$elem.empty();
  20. this.$elem.html( Mustache.render( this.tmpl, data ) );
  21. this.$elem.removeClass('hidden');
  22. this.$elem.show();
  23. this.bindEvents();
  24. // call if an afterRender function was provided
  25. if(typeof this.afterRender === 'function') {
  26. this.afterRender();
  27. }
  28. }
  29. }
  30. /**
  31. * Wrapper around provided render function (show elem after render)
  32. */
  33. function viewRenderWrapper(data) {
  34. this._render(data);
  35. this.$elem.show();
  36. }
  37. /**
  38. * Bind events
  39. */
  40. function viewBindEvents() {
  41. var events = this.props.events;
  42. for(var descriptor in events) {
  43. var handler = events[descriptor];
  44. var bits = descriptor.split(' ');
  45. var evtName = bits.shift();
  46. var selector = bits.join(' ');
  47. var target = selector === '' ? this.$elem : this.$elem.find(selector);
  48. target.on(evtName, handler.bind(this));
  49. }
  50. }
  51. /**
  52. * Bind events: nop
  53. */
  54. function viewBindEventsNop() {}
  55. /**
  56. * Show view element
  57. */
  58. function viewElemShow() {
  59. this.$elem.removeClass('hidden');
  60. this.$elem.show();
  61. }
  62. /**
  63. * Hide view element
  64. */
  65. function hideElemShow() {
  66. this.$elem.addClass('hidden');
  67. this.$elem.hide();
  68. }
  69. /**
  70. * Build a view
  71. */
  72. _ws.makeView = function(elemId, props) {
  73. var v = {};
  74. v.props = props || {};
  75. v.$elem = $('#' + elemId);
  76. v.partName = _.camelCase(elemId);
  77. _ws.ui[v.partName] = v;
  78. // Bind the provided render function
  79. if(typeof v.props.render === 'function') {
  80. v._render = props.render.bind(v);
  81. v.render = viewRenderWrapper.bind(v);
  82. }
  83. // Otherwise assign the default render function
  84. else {
  85. var $tmplEl = $('script[data-tmpl-for="' + elemId + '"]');
  86. v.tmpl = $tmplEl.html();
  87. v.render = (viewDefaultRender(elemId)).bind(v);
  88. }
  89. // Set event handlers
  90. if(v.props.events) {
  91. v.bindEvents = viewBindEvents.bind(v);
  92. v.bindEvents();
  93. }
  94. else {
  95. v.bindEvents = viewBindEventsNop.bind(v);
  96. }
  97. // Pass arbitrary properties
  98. for(var p in props) {
  99. if(['render', 'events', 'init'].indexOf(p) !== -1) {
  100. continue;
  101. }
  102. var prop = props[p];
  103. v[p] = typeof prop !== 'function' ? prop : prop.bind(v);
  104. }
  105. v.show = viewElemShow.bind(v);
  106. v.hide = hideElemShow.bind(v);
  107. // Init if an init function was provided
  108. if(typeof v.props.init === 'function') {
  109. (v.props.init.bind(v))();
  110. }
  111. };
  112. });
  113. })(jQuery);