DetailPanel.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. let query = this._headerRow.querySelector(`#sort-direction-${property}`);
  62. if (query) {
  63. if (direction == 1) {
  64. query.classList.remove('fa-chevron-down');
  65. query.classList.add('fa-chevron-up');
  66. } else {
  67. query.classList.remove('fa-chevron-up');
  68. query.classList.add('fa-chevron-down');
  69. }
  70. }
  71. let isString = (s: any) => {
  72. return typeof(s) === 'string' || s instanceof String;
  73. };
  74. this._detailRows.forEach((property) => {
  75. property.closeDetails();
  76. })
  77. this._detailRows.sort((detail1: any, detail2: any) : number => {
  78. let str1 = String(detail1[property]);
  79. let str2 = String(detail2[property]);
  80. if (!isString(str1)) {
  81. str1 = detail1[property].toString();
  82. }
  83. if (!isString(str2)) {
  84. str2 = detail2[property].toString();
  85. }
  86. // Compare numbers as numbers and string as string with 'numeric=true'
  87. return str1.localeCompare(str2, [], {numeric:true}) * direction;
  88. });
  89. }
  90. /**
  91. * Removes all data in the detail panel but keep the header row
  92. */
  93. public clean() {
  94. // Delete all details row
  95. for (let pline of this._detailRows) {
  96. pline.dispose();
  97. }
  98. Helpers.CleanDiv(this._div);
  99. // Header row
  100. this._div.appendChild(this._headerRow);
  101. }
  102. /** Overrides basicelement.dispose */
  103. public dispose() {
  104. // Delete all details row
  105. for (let pline of this._detailRows) {
  106. pline.dispose();
  107. }
  108. }
  109. /**
  110. * Creates the header row : name, value, id
  111. */
  112. private _createHeaderRow() {
  113. this._headerRow = Helpers.CreateDiv('header-row');
  114. let createDiv = (name:string, cssClass:string) : HTMLElement => {
  115. let div = Helpers.CreateDiv(cssClass+' header-col');
  116. // Column title - first letter in uppercase
  117. let spanName = Inspector.DOCUMENT.createElement('span');
  118. spanName.textContent = name.charAt(0).toUpperCase() + name.slice(1);
  119. // sort direction
  120. let spanDirection = Inspector.DOCUMENT.createElement('i');
  121. spanDirection.className = 'sort-direction fa';
  122. spanDirection.id = 'sort-direction-'+name;
  123. div.appendChild(spanName);
  124. div.appendChild(spanDirection);
  125. div.addEventListener('click', (e) => {
  126. this._sortDetails(name);
  127. this._addDetails();
  128. });
  129. return div;
  130. };
  131. this._headerRow.appendChild(createDiv('name', 'prop-name'));
  132. this._headerRow.appendChild(createDiv('value', 'prop-value'));
  133. }
  134. }
  135. }