CompoundColumns.js 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. define([
  2. "dojo/_base/lang",
  3. "dojo/_base/declare",
  4. "dgrid/util/misc",
  5. "xstyle/css!../css/extensions/CompoundColumns.css"
  6. ], function(lang, declare, miscUtil){
  7. return declare(null, {
  8. // summary:
  9. // Extension allowing for specification of columns with additional
  10. // header rows spanning multiple columns for strictly display purposes.
  11. // Only works on `columns` arrays, not `columns` objects or `subRows`
  12. // (nor ColumnSets).
  13. // description:
  14. // CompoundColumns allows nested header cell configurations, wherein the
  15. // higher-level headers may span multiple columns and are for
  16. // display purposes only.
  17. // These nested header cells are configured using a special recursive
  18. // `children` property in the column definition, where only the deepest
  19. // children are ultimately rendered in the grid as actual columns.
  20. // In addition, the deepest child columns may be rendered without
  21. // individual headers by specifying `showChildHeaders: false` on the parent.
  22. configStructure: function(){
  23. // create a set of sub rows for the header row so we can do compound columns
  24. // the first row is a special spacer row
  25. var columns = (this.subRows && this.subRows[0]) || this.columns,
  26. headerRows = [[]],
  27. contentColumns = [];
  28. // This first row is spacer row that will be made invisible (zero height)
  29. // with CSS, but it must be rendered as the first row since that is what
  30. // the table layout is driven by.
  31. headerRows[0].className = "dgrid-spacer-row";
  32. function processColumns(columns, level, hasLabel){
  33. var numColumns = 0,
  34. noop = function(){},
  35. column, children, hasChildLabels;
  36. function processColumn(column, i){
  37. children = column.children;
  38. hasChildLabels = column.children && (column.showChildHeaders !== false);
  39. if(children){
  40. // it has children, recursively process the children
  41. numColumns += (column.colSpan = processColumns(children, level + 1, hasChildLabels));
  42. }else{
  43. // it has no children, it is a normal header, add it to the content columns
  44. contentColumns.push(column);
  45. // add each one to the first spacer header row for proper layout of the header cells
  46. headerRows[0].push(lang.delegate(column, {renderHeaderCell: noop}));
  47. numColumns++;
  48. }
  49. if(!hasChildLabels){
  50. // create a header version of the column where we can define a specific rowSpan
  51. // we define the rowSpan as a negative, the number of levels less than the total number of rows, which we don't know yet
  52. column = lang.delegate(column, {rowSpan: -level});
  53. }
  54. // add the column to the header rows at the appropriate level
  55. if(hasLabel){
  56. (headerRows[level] || (headerRows[level] = [])).push(column);
  57. }
  58. }
  59. miscUtil.each(columns, processColumn, this);
  60. return numColumns;
  61. }
  62. processColumns(columns, 1, true);
  63. var numHeaderRows = headerRows.length,
  64. i, j, headerRow, headerColumn;
  65. // Now go back through and increase the rowSpans of the headers to be
  66. // total rows minus the number of levels they are at.
  67. for(i = 0; i < numHeaderRows; i++){
  68. headerRow = headerRows[i];
  69. for(j = 0; j < headerRow.length; j++){
  70. headerColumn = headerRow[j];
  71. if(headerColumn.rowSpan < 1){
  72. headerColumn.rowSpan += numHeaderRows;
  73. }
  74. }
  75. }
  76. // we need to set this to be used for subRows, so we make it a single row
  77. contentColumns = [contentColumns];
  78. // set our header rows so that the grid will use the alternate header row
  79. // configuration for rendering the headers
  80. contentColumns.headerRows = headerRows;
  81. this.subRows = contentColumns;
  82. this.inherited(arguments);
  83. }
  84. });
  85. });