Cascade.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. define( ["./DataStoreUtils.js"], function( DataStoreUtils ) {
  2. "use strict";
  3. function Control()
  4. {
  5. };
  6. Control.prototype.initialize = function( oControlHost, fnDoneInitializing )
  7. {
  8. this.m_oControlHost = oControlHost;
  9. this.m_oConfiguration = this.m_oControlHost.configuration || {};
  10. fnDoneInitializing();
  11. };
  12. Control.prototype.setData = function( oControlHost, oDataStore )
  13. {
  14. this.m_oDataStore = oDataStore;
  15. this.m_oJson = DataStoreUtils.extractData( oDataStore );
  16. this.m_aCascadingColumnsThatSetAParameter = [];
  17. this.m_aCascadingColumns = this.m_oConfiguration["cascading columns"] || this.m_oJson.columns.map( function( oColumn ) { return { "use": oColumn.name, "display": oColumn.name, "parameter": oColumn.name } } );
  18. this.m_aCascadingColumns.forEach( function( oColumn, iIndex )
  19. {
  20. oColumn.iIndex = iIndex;
  21. oColumn.use = oColumn.use || this.m_oDataStore.columnNames[iIndex];
  22. oColumn.iUseColumnIndex = this.m_oDataStore.getColumnIndex( oColumn.use );
  23. oColumn.display = oColumn.display || oColumn.use;
  24. oColumn.iDisplayColumnIndex = this.m_oDataStore.getColumnIndex( oColumn.display );
  25. oColumn.oSelectedValueIndexes = new Set();
  26. if ( oColumn.parameter )
  27. {
  28. this.m_aCascadingColumnsThatSetAParameter.push( oColumn );
  29. var oParameter = this.m_oControlHost.getParameter( oColumn.parameter );
  30. if ( oParameter )
  31. {
  32. oParameter.values.forEach( function( oValue ) { oColumn.oSelectedValueIndexes.add( this.m_oJson.columns[oColumn.iUseColumnIndex].values.indexOf( oValue.use ) ); }, this );
  33. }
  34. }
  35. }, this );
  36. this.m_aCascadingColumns[0].oCascadeJson = this.m_oJson;
  37. };
  38. Control.prototype.draw = function( oControlHost )
  39. {
  40. var bVertical = !!this.m_oConfiguration.vertical;
  41. var sId = '#' + oControlHost.container.id + ' ';
  42. var sHtml =
  43. '<style>' +
  44. sId + 'select:required:invalid { color: gray; }' +
  45. sId + 'select { box-sizing: border-box; font-family: inherit; font-size: 100%; }' +
  46. sId + 'option[value=""][disabled] { display: none; }' +
  47. sId + 'option { color: black; }' +
  48. sId + '> div { display:flex; flex-direction:' + ( bVertical ? 'column' : 'row' ) + '; }' +
  49. sId + 'div > div:not(:first-of-type) { margin-' + ( bVertical ? 'top' : 'left' ) + ':' + ( this.m_oConfiguration.spacing || '8px' ) + '; }' +
  50. sId + '> div > div { font-weight: bold; }' +
  51. '</style>';
  52. sHtml += '<div>';
  53. var sDefaultMinWidth = this.m_oConfiguration.minWidth || '150px';
  54. for ( var i = 0; i < this.m_aCascadingColumns.length; i++ )
  55. {
  56. var oCascadingColumn = this.m_aCascadingColumns[i];
  57. sHtml += '<div>';
  58. sHtml += '<div>' + this.HTMLEncode( oCascadingColumn.label || oCascadingColumn.display ) + ':</div>';
  59. sHtml += '<select disabled="true" style="min-width:' + ( oCascadingColumn.minWidth || sDefaultMinWidth ) + ';';
  60. if ( oCascadingColumn.multiple )
  61. {
  62. sHtml += 'overflow:auto;';
  63. }
  64. if ( oCascadingColumn.height || this.m_oConfiguration.height )
  65. {
  66. sHtml += 'height:' + ( oCascadingColumn.height || this.m_oConfiguration.height ) + ';';
  67. }
  68. if ( oCascadingColumn.fontSize || this.m_oConfiguration.fontSize )
  69. {
  70. sHtml += 'font-size:' + ( oCascadingColumn.fontSize || this.m_oConfiguration.fontSize ) + ';';
  71. }
  72. if ( oCascadingColumn.textAlign || this.m_oConfiguration.textAlign )
  73. {
  74. sHtml += 'text-align:' + ( oCascadingColumn.textAlign || this.m_oConfiguration.textAlign ) + ';';
  75. }
  76. sHtml += '"';
  77. if ( oCascadingColumn.required )
  78. {
  79. sHtml += ' required="true"';
  80. }
  81. if ( oCascadingColumn.multiple || ( this.m_oConfiguration.multiple && ( oCascadingColumn.multiple !== false ) ) )
  82. {
  83. sHtml += ' multiple="true"';
  84. }
  85. if ( oCascadingColumn.size || this.m_oConfiguration.size )
  86. {
  87. sHtml += ' size="' + ( oCascadingColumn.size || this.m_oConfiguration.size ) + '"';
  88. }
  89. sHtml += '></select>';
  90. sHtml += '</div>';
  91. }
  92. sHtml += "</div>";
  93. oControlHost.container.innerHTML = sHtml;
  94. this.m_nlSelects = oControlHost.container.getElementsByTagName( "SELECT" );
  95. for ( var i = 0; i < this.m_nlSelects.length; i++ )
  96. {
  97. this.populateCascadingColumn( i );
  98. this.m_nlSelects.item( i ).onchange = this.onSelectChange.bind( this, i );
  99. }
  100. };
  101. Control.prototype.onSelectChange = function( iIndex )
  102. {
  103. var oColumn = this.m_aCascadingColumns[iIndex];
  104. oColumn.oSelectedValueIndexes.clear();
  105. var sel = this.m_nlSelects.item( iIndex );
  106. for ( var i = 0; i < sel.options.length; i++ )
  107. {
  108. var elOption = sel.options[i];
  109. if ( elOption.selected )
  110. {
  111. oColumn.oSelectedValueIndexes.add( elOption.iUseValueIndex )
  112. }
  113. }
  114. for ( var i = iIndex + 1; i < this.m_aCascadingColumns.length; i++ )
  115. {
  116. var oCascadeColumn = this.m_aCascadingColumns[i];
  117. oCascadeColumn.oCascadeJson = null;
  118. oCascadeColumn.oSelectedValueIndexes.clear();
  119. var sel = this.m_nlSelects.item( i );
  120. this.removeAllHtmlSelectOptions( sel );
  121. sel.disabled = true;
  122. }
  123. this.populateCascadingColumn( iIndex + 1 );
  124. this.m_oControlHost.valueChanged();
  125. };
  126. Control.prototype.populateCascadingColumn = function( iIndex )
  127. {
  128. if ( iIndex < this.m_aCascadingColumns.length )
  129. {
  130. var oCascadingColumn = this.m_aCascadingColumns[iIndex];
  131. var oPreviousCascadeColumn = ( iIndex > 0 ) ? this.m_aCascadingColumns[iIndex - 1] : null;
  132. oCascadingColumn.oCascadeJson = oPreviousCascadeColumn ? DataStoreUtils.filterByColumnValueIndexes( oPreviousCascadeColumn.oCascadeJson, oPreviousCascadeColumn.iUseColumnIndex, oPreviousCascadeColumn.oSelectedValueIndexes ) : this.m_oJson;
  133. var oJson = DataStoreUtils.filterToUniqueRows( oCascadingColumn.oCascadeJson, oCascadingColumn.iUseColumnIndex );
  134. this.populateHtmlSelectFromColumn( this.m_nlSelects.item( iIndex ), oJson, oCascadingColumn );
  135. }
  136. };
  137. Control.prototype.populateHtmlSelectFromColumn = function( sel, oJson, oCascadingColumn )
  138. {
  139. sel.disabled = ( oCascadingColumn.iIndex > 0 ) && !this.m_aCascadingColumns[oCascadingColumn.iIndex - 1].oSelectedValueIndexes.size;
  140. this.removeAllHtmlSelectOptions( sel );
  141. var iUseColumnIndex = oCascadingColumn.iUseColumnIndex;
  142. var iDisplayColumnIndex = oCascadingColumn.iDisplayColumnIndex;
  143. var oUseColumn = oJson.columns[iUseColumnIndex];
  144. var oDisplayColumn = oJson.columns[iDisplayColumnIndex];
  145. var d = document;
  146. if ( !( oCascadingColumn.multiple || this.m_oConfiguration.multiple ) && !oCascadingColumn.oSelectedValueIndexes.size && !sel.disabled )
  147. {
  148. var elOption = d.createElement( "OPTION" );
  149. elOption.value = "";
  150. elOption.textContent = this.m_oConfiguration["choose label"] || "<Choose>";
  151. elOption.selected = oCascadingColumn.oSelectedValueIndexes.size == 0;
  152. elOption.disabled = true;
  153. sel.add( elOption );
  154. }
  155. oJson.rows.forEach( function( aRow )
  156. {
  157. var elOption = d.createElement( "OPTION" );
  158. var iUseValueIndex = aRow[iUseColumnIndex];
  159. elOption.iUseValueIndex = iUseValueIndex;
  160. elOption.iDisplayValueIndex = aRow[iDisplayColumnIndex];
  161. elOption.value = oUseColumn.values[aRow[iUseColumnIndex]];
  162. elOption.textContent = oDisplayColumn.values[aRow[iDisplayColumnIndex]];
  163. elOption.selected = oCascadingColumn.oSelectedValueIndexes.has( iUseValueIndex );
  164. sel.add( elOption );
  165. } );
  166. };
  167. Control.prototype.removeAllHtmlSelectOptions = function( sel )
  168. {
  169. while ( sel.length )
  170. {
  171. sel.remove( 0 );
  172. }
  173. };
  174. Control.prototype.getParameters = function()
  175. {
  176. return this.m_aCascadingColumnsThatSetAParameter.map( function( oColumn, i ) {
  177. return {
  178. "parameter": oColumn.parameter,
  179. "values": this.setToArray( oColumn.oSelectedValueIndexes ).map( function( iValueIndex )
  180. {
  181. return {
  182. "use" : oColumn.oCascadeJson.columns[oColumn.iUseColumnIndex].values[iValueIndex],
  183. "display" : oColumn.oCascadeJson.columns[oColumn.iDisplayColumnIndex].values[DataStoreUtils.filterByColumnValueIndex( oColumn.oCascadeJson, oColumn.iUseColumnIndex, iValueIndex ).rows[0][oColumn.iDisplayColumnIndex]]
  184. };
  185. } )
  186. };
  187. }.bind( this ) );
  188. };
  189. Control.prototype.isInValidState = function()
  190. {
  191. return this.m_aCascadingColumns.every( function( oColumn ) { return !oColumn.required || ( oColumn.oSelectedValueIndexes.size > 0 ); }, this );
  192. };
  193. Control.prototype.setToArray = function( oSet )
  194. {
  195. if ( Array.from )
  196. {
  197. return Array.from( oSet );
  198. }
  199. var a = [];
  200. oSet.forEach( function( v ) { this.push( v ); }, a );
  201. return a;
  202. };
  203. Control.prototype.HTMLEncode = function( s )
  204. {
  205. return String( s ).replace( /&/g, "&amp;" ).replace( /</g, "&lt;" ).replace( />/g, "&gt;" );
  206. };
  207. return Control;
  208. });