DetailPanel.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. module INSPECTOR {
  2. export interface SortDirection {
  3. [property: string]: number;
  4. }
  5. export class DetailPanel extends BasicElement {
  6. // The header row
  7. private _headerRow : HTMLElement;
  8. // Contains all details rows that belongs to the item above
  9. private _detailRows : Array<PropertyLine> = [];
  10. // Store the sort direction of each header column
  11. private _sortDirection : SortDirection = {};
  12. constructor(dr? : Array<PropertyLine>) {
  13. super();
  14. this._build();
  15. if (dr) {
  16. this._detailRows = dr;
  17. this.update();
  18. }
  19. }
  20. set details(detailsRow : Array<PropertyLine>) {
  21. this.clean();
  22. this._detailRows = detailsRow;
  23. // Refresh HTML
  24. this.update();
  25. }
  26. protected _build() {
  27. this._div.className = 'insp-details';
  28. this._div.id = 'insp-details';
  29. // Create header row
  30. this._createHeaderRow();
  31. this._div.appendChild(this._headerRow);
  32. }
  33. /** Updates the HTML of the detail panel */
  34. public update() {
  35. this._sortDetails('name', 1);
  36. this._addDetails();
  37. }
  38. /** Add all lines in the html div. Does not sort them! */
  39. private _addDetails() {
  40. let details = Helpers.CreateDiv('details', this._div);
  41. for (let row of this._detailRows) {
  42. details.appendChild(row.toHtml());
  43. }
  44. }
  45. /**
  46. * Sort the details row by comparing the given property of each row
  47. */
  48. private _sortDetails(property:string, _direction?:number) {
  49. // Clean header
  50. let elems = Inspector.DOCUMENT.querySelectorAll('.sort-direction');
  51. for (let e=0; e<elems.length; e++) {
  52. elems[e].classList.remove('fa-chevron-up');
  53. elems[e].classList.remove('fa-chevron-down');
  54. }
  55. if (_direction || !this._sortDirection[property]) {
  56. this._sortDirection[property] = _direction || 1;
  57. } else {
  58. this._sortDirection[property] *= -1;
  59. }
  60. let direction = this._sortDirection[property];
  61. if (direction == 1) {
  62. this._headerRow.querySelector(`#sort-direction-${property}`).classList.remove('fa-chevron-down');
  63. this._headerRow.querySelector(`#sort-direction-${property}`).classList.add('fa-chevron-up');
  64. } else {
  65. this._headerRow.querySelector(`#sort-direction-${property}`).classList.remove('fa-chevron-up');
  66. this._headerRow.querySelector(`#sort-direction-${property}`).classList.add('fa-chevron-down');
  67. }
  68. let isString = (s: any) => {
  69. return typeof(s) === 'string' || s instanceof String;
  70. };
  71. this._detailRows.forEach((property) => {
  72. property.closeDetails();
  73. })
  74. this._detailRows.sort((detail1: any, detail2: any) : number => {
  75. let str1 = String(detail1[property]);
  76. let str2 = String(detail2[property]);
  77. if (!isString(str1)) {
  78. str1 = detail1[property].toString();
  79. }
  80. if (!isString(str2)) {
  81. str2 = detail2[property].toString();
  82. }
  83. // Compare numbers as numbers and string as string with 'numeric=true'
  84. return str1.localeCompare(str2, [], {numeric:true}) * direction;
  85. });
  86. }
  87. /**
  88. * Removes all data in the detail panel but keep the header row
  89. */
  90. public clean() {
  91. // Delete all details row
  92. for (let pline of this._detailRows) {
  93. pline.dispose();
  94. }
  95. Helpers.CleanDiv(this._div);
  96. // Header row
  97. this._div.appendChild(this._headerRow);
  98. }
  99. /** Overrides basicelement.dispose */
  100. public dispose() {
  101. // Delete all details row
  102. for (let pline of this._detailRows) {
  103. pline.dispose();
  104. }
  105. }
  106. /**
  107. * Creates the header row : name, value, id
  108. */
  109. private _createHeaderRow() {
  110. this._headerRow = Helpers.CreateDiv('header-row');
  111. let createDiv = (name:string, cssClass:string) : HTMLElement => {
  112. let div = Helpers.CreateDiv(cssClass+' header-col');
  113. // Column title - first letter in uppercase
  114. let spanName = Inspector.DOCUMENT.createElement('span');
  115. spanName.textContent = name.charAt(0).toUpperCase() + name.slice(1);
  116. // sort direction
  117. let spanDirection = Inspector.DOCUMENT.createElement('i');
  118. spanDirection.className = 'sort-direction fa';
  119. spanDirection.id = 'sort-direction-'+name;
  120. div.appendChild(spanName);
  121. div.appendChild(spanDirection);
  122. div.addEventListener('click', (e) => {
  123. this._sortDetails(name);
  124. this._addDetails();
  125. });
  126. return div;
  127. };
  128. this._headerRow.appendChild(createDiv('name', 'prop-name'));
  129. this._headerRow.appendChild(createDiv('value', 'prop-value'));
  130. }
  131. }
  132. }