HtmlTemplates.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. 'use strict';
  2. /**
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2014, 2020
  5. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  6. *
  7. * @module /com/ibm/common/templates/HtmlTemplates
  8. * @see HtmlTemplates
  9. */
  10. /*globals module*/
  11. define(['../../lib/@waca/core-client/js/core-client/ui/core/Class', '../../lib/@waca/dashboard-common/dist/utils/HtmlXSSUtils', 'underscore'], function (BaseClass, HtmlXSSUtils, _) {
  12. /*
  13. * TODO: These strings should be loaded from template files... but the 'text!'
  14. * AMD loader module is not currently supported in our NodeJS server so for the
  15. * time being, they are still hard-coded strings.
  16. */
  17. var sDefaultHtml = '<div id="{{id}}" tabindex="-1" class="page page{{type}}{{extraCSS}}"{{style}}>{{items}}</div>';
  18. var gridDefaultHtml = '<div id="{{id}}" tabindex="-1" class="page page{{type}} gridCapable{{extraCSS}}"{{style}}>{{items}}</div>';
  19. var sDefaultItems = '{{item}}';
  20. var sWidgetHtml = '<div id="{{id}}" role="application" aria-label="{{title}}" class="widget {{widgetType}}Widget{{extraCSS}}"{{style}} tabIndex="0"><div class="widgetContentWrapper" style="height:100%;width:100%"></div></div>';
  21. var sWidgetItems = ''; // Yes, empty!
  22. var sColumnHtml = '<table id="{{id}}" class="page page{{type}}{{extraCSS}}"{{style}}>' + '<tbody>' + '<tr>{{items}}</tr>' + '</tbody>' + '</table>';
  23. var sColumnItems = '<td>{{item}}</td>';
  24. var sFlowHtml = '<div id="{{id}}" class="page page{{type}}{{extraCSS}}"{{style}}>' + '<div class="pageflowcolumn">{{items}}</div>' + '</div>';
  25. var sFlowItems = '{{item}}';
  26. var sTabHtml = '<div id="{{id}}" class="page page{{type}}{{extraCSS}}"{{style}}>' + '<div class="tabCntr"></div>' + '<div class="tabPageHolder">{{items}}</div>' + '</div>';
  27. var sTabItems = '<div id="{{item.id}}_tab" class="pageTabContent">{{item}}</div>';
  28. var sHubHtml = '<div id="{{id}}" class="page page{{type}}{{extraCSS}}"{{style}}>' + '<div class="tabLabelCntr">{{labels}}</div>' + '<div class="tabCntr">{{items}}</div>' + '</div>';
  29. var sHubItems = '<div id="{{id}}_{{counter}}" class="pageTabContent" style="display:none">{{item}}</div>';
  30. var sHubLabels = '<div id="{{id}}_{{counter}}_label" class="tabLabel" tabIndex="0" role="tab">{{label}}</div>';
  31. var sLongScrollHtml = '<div id="{{id}}" class="page page{{type}}{{extraCSS}}"{{style}}>' + '<div class="tabLabelCntr">{{labels}}</div>' + '<div class="tabCntr">{{items}}</div>' + '</div>';
  32. var sLongScrollItems = '<div id="{{id}}_{{counter}}" class="pageTabContent" style="display:none">{{item}}</div>';
  33. var sLongScrollLabels = '<div id="{{id}}_{{counter}}_label" class="tabLabel" tabIndex="0" role="tab">{{label}}</div>';
  34. var _idCounter = 0;
  35. var Templates = BaseClass.extend({
  36. init: function init(options) {
  37. options = options || {};
  38. // Use arrays for templates:
  39. // [0] is for the page.
  40. // [1] is the HTML wrapping the sub items.
  41. // [2] is for labels (Tab layout)
  42. this._defaultHtml = [sDefaultHtml, sDefaultItems];
  43. this._htmlTemplates = {
  44. absolute: [gridDefaultHtml, sDefaultItems],
  45. scalingAbsolute: [gridDefaultHtml, sDefaultItems],
  46. genericPage: [gridDefaultHtml, sDefaultItems],
  47. widget: [sWidgetHtml, sWidgetItems],
  48. column: [sColumnHtml, sColumnItems],
  49. flow: [sFlowHtml, sFlowItems],
  50. tab: [sTabHtml, sTabItems],
  51. cardtab: [sTabHtml, sTabItems],
  52. hub: [sHubHtml, sHubItems, sHubLabels],
  53. longscroll: [sLongScrollHtml, sLongScrollItems, sLongScrollLabels]
  54. };
  55. if (options.layoutExtensionsTemplates) {
  56. // used to remove the copyright notice
  57. var matchComment = /<!--[\s\S]*?-->/m;
  58. Object.keys(options.layoutExtensionsTemplates).forEach(function (key) {
  59. var templates = options.layoutExtensionsTemplates[key]();
  60. this._htmlTemplates[key] = templates.map(function (template) {
  61. return (template || '').replace(matchComment, '');
  62. });
  63. }.bind(this));
  64. }
  65. },
  66. // Used by unit-tests...
  67. reset: function reset() {
  68. _idCounter = 0;
  69. },
  70. getStyleValue: function getStyleValue(s) {
  71. var a = [];
  72. if (s) {
  73. if (typeof s === 'string') {
  74. a.push(s);
  75. } else {
  76. var allStyles = [];
  77. for (var i in s) {
  78. if (s.hasOwnProperty(i)) {
  79. allStyles.push(i + ':' + s[i]);
  80. }
  81. }
  82. a.push(allStyles.join(';'));
  83. }
  84. }
  85. return a.join('');
  86. },
  87. getStyle: function getStyle(s) {
  88. var styleValue = this.getStyleValue(s);
  89. var a = [];
  90. if (styleValue) {
  91. a.push(' style="');
  92. a.push(_.escape(styleValue));
  93. a.push('"');
  94. }
  95. return a.join('');
  96. },
  97. getHtml: function getHtml(spec, widgetMap) {
  98. // page
  99. if (!spec.id) {
  100. var newId = 'page' + _idCounter++;
  101. if (spec.setId) {
  102. spec.setId(newId); //ideally getters should not mutate input
  103. } else {
  104. spec.id = newId;
  105. }
  106. }
  107. var type = spec.type;
  108. var template = this.getTemplate(type);
  109. var sMainTemplate = template[0];
  110. var aItemsHtml = [];
  111. var aLabelsHtml = [];
  112. _.each(spec.items, function (item, idx) {
  113. this._loadLabelHtml(aLabelsHtml, type, widgetMap, item, idx);
  114. this._loadItemHtml(aItemsHtml, type, widgetMap, item);
  115. }.bind(this));
  116. var sHtml = sMainTemplate.replace(/\{\{items\}\}/g, aItemsHtml.join('')).replace(/\{\{labels\}\}/g, aLabelsHtml.join(''));
  117. // Replace widget attributes
  118. sHtml = this.replaceWidgetValues(sHtml, widgetMap ? widgetMap[spec.id] : null);
  119. sHtml = this.replaceLayoutValues(sHtml, spec);
  120. return sHtml;
  121. },
  122. _loadLabelHtml: function _loadLabelHtml(aLabelsHtml, type, widgetMap, item, idx) {
  123. var label = this.getLabel(item, widgetMap) || 'Tab ' + (idx + 1);
  124. var sHtml = this.getLabelTemplate(type, label, item);
  125. if (sHtml) {
  126. aLabelsHtml.push(sHtml);
  127. }
  128. },
  129. _loadItemHtml: function _loadItemHtml(aItemsHtml, type, widgetMap, item) {
  130. var label = this.getLabel(item, widgetMap) || '';
  131. var sHtml = this.getItemTemplate(type, this.getHtml(item, widgetMap), item, label);
  132. if (sHtml) {
  133. aItemsHtml.push(sHtml);
  134. }
  135. },
  136. getTemplate: function getTemplate(type) {
  137. return this._htmlTemplates[type] || this._defaultHtml;
  138. },
  139. getLabelTemplate: function getLabelTemplate(type, label, item) {
  140. var result = null;
  141. var sLabelTemplate = this.getTemplate(type)[2];
  142. if (sLabelTemplate) {
  143. item.id = item.id || 'page' + _idCounter++;
  144. result = sLabelTemplate.replace(/\{\{item.id\}\}/g, _.escape(item.id)).replace(/\{\{label\}\}/g, _.escape(label));
  145. }
  146. return result;
  147. },
  148. getItemTemplate: function getItemTemplate(type, itemContent, item, label) {
  149. var data = item.data || {};
  150. var style = item.style || {};
  151. var sLabel = label || '';
  152. var result = null;
  153. var sItemTemplate = this.getTemplate(type)[1];
  154. if (sItemTemplate) {
  155. result = sItemTemplate.replace(/\{\{item.id\}\}/g, _.escape(item.id)).replace(/\{\{item\}\}/g, itemContent).replace(/\{\{label\}\}/g, _.escape(sLabel)).replace(/\{\{dx\}\}/g, _.escape('' + (data.x || 0))).replace(/\{\{dy\}\}/g, _.escape('' + (data.y || 0))).replace(/\{\{dscale\}\}/g, _.escape('' + (data.scale || 1))).replace(/\{\{style\}\}/g, this.getStyle(style));
  156. }
  157. return result;
  158. },
  159. replaceLayoutValues: function replaceLayoutValues(sHtml, spec) {
  160. var data = spec.data || {};
  161. var fill = spec.fillColor;
  162. if (fill) {
  163. var fillCss = 'fill-' + fill;
  164. if (spec.css && spec.css.indexOf(fillCss) === -1) {
  165. spec.css += ' ' + fillCss;
  166. } else {
  167. spec.css = fillCss;
  168. }
  169. }
  170. return sHtml.replace(/\{\{id\}\}/g, _.escape(spec.id)).replace(/\{\{type\}\}/g, _.escape(spec.type)).replace(/\{\{style\}\}/g, this.getStyle(spec.style)).replace(/\{\{extraCSS\}\}/g, spec.css ? ' ' + _.escape(spec.css) : '').replace(/\{\{extraCSSTabLabels\}\}/g, spec.cssTabLabels ? ' ' + _.escape(spec.cssTabLabels) : '').replace(/\{\{dx\}\}/g, _.escape('' + (data.x || 0))).replace(/\{\{dy\}\}/g, _.escape('' + (data.y || 0))).replace(/\{\{dscale\}\}/g, _.escape('' + (data.scale || 1)));
  171. },
  172. replaceWidgetValues: function replaceWidgetValues(html, widgetSpec) {
  173. // Replace widget attributes
  174. var widgetType = widgetSpec && widgetSpec.type ? widgetSpec.type : '';
  175. var title = null;
  176. if (widgetSpec) {
  177. // TODO: this is ugly.. widgets should use common property for the title/label
  178. title = widgetSpec.get('name') || widgetSpec.get('title') || widgetSpec.get('altText');
  179. }
  180. title = HtmlXSSUtils.sanitizeHtml(title);
  181. return html.replace(/\{\{widgetType\}\}/g, _.escape(widgetType)).replace(/\{\{title\}\}/g, _.escape(title));
  182. },
  183. getLabel: function getLabel(model, widgetMap) {
  184. var s = '';
  185. var title;
  186. if (model && model.title) {
  187. title = model.get ? model.get('title') : model.title;
  188. }
  189. if (typeof title === 'string') {
  190. s = title;
  191. } else if (title) {
  192. s = this.getHtml(title, widgetMap);
  193. }
  194. return s;
  195. }
  196. });
  197. return Templates;
  198. });
  199. //# sourceMappingURL=HtmlTemplates.js.map