ws-ui-parts.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. console.log('this is default render on', this, 'with data', data);
  17. if(! data) {
  18. throw new Error('WARNING! You should provide data for #' + elemId + "'s render()");
  19. }
  20. this.$elem.empty();
  21. this.$elem.html( Mustache.render( this.tmpl, data ) );
  22. this.$elem.show();
  23. this.bindEvents();
  24. }
  25. }
  26. /**
  27. * Wrapper around provided render function (show elem after render)
  28. */
  29. function viewRenderWrapper(data) {
  30. this._render(data);
  31. this.$elem.show();
  32. }
  33. /**
  34. * Bind events
  35. */
  36. function viewBindEvents() {
  37. var events = this.props.events;
  38. for(var descriptor in events) {
  39. var handler = events[descriptor];
  40. var bits = descriptor.split(' ');
  41. var evtName = bits.shift();
  42. var selector = bits.join(' ');
  43. var target = selector === '' ? this.$elem : this.$elem.find(selector);
  44. // console.log('#### bind', descriptor, 'e:' + evtName, 's:[' + selector + '], target:', target);
  45. target.on(evtName, handler.bind(this));
  46. }
  47. }
  48. /**
  49. * Bind events: nop
  50. */
  51. function viewBindEventsNop() {
  52. console.log(this.partName, 'bindEvents:nop');
  53. }
  54. /**
  55. * Show view element
  56. */
  57. function viewElemShow() {
  58. this.$elem.show();
  59. }
  60. /**
  61. * Hide view element
  62. */
  63. function hideElemShow() {
  64. this.$elem.hide();
  65. }
  66. /**
  67. * Build a view
  68. */
  69. _ws.makeView = function(elemId, props) {
  70. var v = {};
  71. v.props = props || {};
  72. v.$elem = $('#' + elemId);
  73. v.partName = _.camelCase(elemId);
  74. _ws.ui[v.partName] = v;
  75. // Bind the provided render function
  76. if(typeof v.props.render === 'function') {
  77. v._render = props.render.bind(v);
  78. v.render = viewRenderWrapper.bind(v);
  79. }
  80. // Otherwise assign the default render function
  81. else {
  82. var $tmplEl = $('script[data-tmpl-for="' + elemId + '"]');
  83. v.tmpl = $tmplEl.html();
  84. v.render = (viewDefaultRender(elemId)).bind(v);
  85. }
  86. // Set event handlers
  87. if(v.props.events) {
  88. v.bindEvents = viewBindEvents.bind(v);
  89. v.bindEvents();
  90. }
  91. else {
  92. v.bindEvents = viewBindEventsNop.bind(v);
  93. }
  94. // Pass arbitrary properties
  95. for(var p in props) {
  96. if(['render', 'events', 'init'].indexOf(p) !== -1) {
  97. // console.log('pass props: ignore', p);
  98. continue;
  99. }
  100. v[p] = props[p];
  101. }
  102. v.show = viewElemShow.bind(v);
  103. v.hide = hideElemShow.bind(v);
  104. // Init if an init function was provided
  105. if(typeof v.props.init === 'function') {
  106. var initFunc = v.props.init.bind(v);
  107. initFunc();
  108. }
  109. };
  110. });
  111. })(jQuery);