foundation.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /**
  2. * @license
  3. * Copyright 2019 Google Inc.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. */
  23. import { __assign, __awaiter, __extends, __generator } from "tslib";
  24. import { MDCFoundation } from '@material/base/foundation';
  25. import { cssClasses, SortValue, attributes } from './constants';
  26. /**
  27. * The Foundation of data table component containing pure business logic, any
  28. * logic requiring DOM manipulation are delegated to adapter methods.
  29. */
  30. var MDCDataTableFoundation = /** @class */ (function (_super) {
  31. __extends(MDCDataTableFoundation, _super);
  32. function MDCDataTableFoundation(adapter) {
  33. return _super.call(this, __assign(__assign({}, MDCDataTableFoundation.defaultAdapter), adapter)) || this;
  34. }
  35. Object.defineProperty(MDCDataTableFoundation, "defaultAdapter", {
  36. get: function () {
  37. return {
  38. addClass: function () { return undefined; },
  39. addClassAtRowIndex: function () { return undefined; },
  40. getAttributeByHeaderCellIndex: function () { return ''; },
  41. getHeaderCellCount: function () { return 0; },
  42. getHeaderCellElements: function () { return []; },
  43. getRowCount: function () { return 0; },
  44. getRowElements: function () { return []; },
  45. getRowIdAtIndex: function () { return ''; },
  46. getRowIndexByChildElement: function () { return 0; },
  47. getSelectedRowCount: function () { return 0; },
  48. getTableContainerHeight: function () { return 0; },
  49. getTableHeaderHeight: function () { return 0; },
  50. isCheckboxAtRowIndexChecked: function () { return false; },
  51. isHeaderRowCheckboxChecked: function () { return false; },
  52. isRowsSelectable: function () { return false; },
  53. notifyRowSelectionChanged: function () { return undefined; },
  54. notifySelectedAll: function () { return undefined; },
  55. notifySortAction: function () { return undefined; },
  56. notifyUnselectedAll: function () { return undefined; },
  57. notifyRowClick: function () { return undefined; },
  58. registerHeaderRowCheckbox: function () { return undefined; },
  59. registerRowCheckboxes: function () { return undefined; },
  60. removeClass: function () { return undefined; },
  61. removeClassAtRowIndex: function () { return undefined; },
  62. removeClassNameByHeaderCellIndex: function () { return undefined; },
  63. setAttributeAtRowIndex: function () { return undefined; },
  64. setAttributeByHeaderCellIndex: function () { return undefined; },
  65. setClassNameByHeaderCellIndex: function () { return undefined; },
  66. setHeaderRowCheckboxChecked: function () { return undefined; },
  67. setHeaderRowCheckboxIndeterminate: function () { return undefined; },
  68. setProgressIndicatorStyles: function () { return undefined; },
  69. setRowCheckboxCheckedAtIndex: function () { return undefined; },
  70. setSortStatusLabelByHeaderCellIndex: function () { return undefined; },
  71. };
  72. },
  73. enumerable: false,
  74. configurable: true
  75. });
  76. /**
  77. * Re-initializes header row checkbox and row checkboxes when selectable rows
  78. * are added or removed from table. Use this if registering checkbox is
  79. * synchronous.
  80. */
  81. MDCDataTableFoundation.prototype.layout = function () {
  82. if (this.adapter.isRowsSelectable()) {
  83. this.adapter.registerHeaderRowCheckbox();
  84. this.adapter.registerRowCheckboxes();
  85. this.setHeaderRowCheckboxState();
  86. }
  87. };
  88. /**
  89. * Re-initializes header row checkbox and row checkboxes when selectable rows
  90. * are added or removed from table. Use this if registering checkbox is
  91. * asynchronous.
  92. */
  93. MDCDataTableFoundation.prototype.layoutAsync = function () {
  94. return __awaiter(this, void 0, void 0, function () {
  95. return __generator(this, function (_a) {
  96. switch (_a.label) {
  97. case 0:
  98. if (!this.adapter.isRowsSelectable()) return [3 /*break*/, 3];
  99. return [4 /*yield*/, this.adapter.registerHeaderRowCheckbox()];
  100. case 1:
  101. _a.sent();
  102. return [4 /*yield*/, this.adapter.registerRowCheckboxes()];
  103. case 2:
  104. _a.sent();
  105. this.setHeaderRowCheckboxState();
  106. _a.label = 3;
  107. case 3: return [2 /*return*/];
  108. }
  109. });
  110. });
  111. };
  112. /**
  113. * @return Returns array of row elements.
  114. */
  115. MDCDataTableFoundation.prototype.getRows = function () {
  116. return this.adapter.getRowElements();
  117. };
  118. /**
  119. * @return Array of header cell elements.
  120. */
  121. MDCDataTableFoundation.prototype.getHeaderCells = function () {
  122. return this.adapter.getHeaderCellElements();
  123. };
  124. /**
  125. * Sets selected row ids. Overwrites previously selected rows.
  126. * @param rowIds Array of row ids that needs to be selected.
  127. */
  128. MDCDataTableFoundation.prototype.setSelectedRowIds = function (rowIds) {
  129. for (var rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
  130. var rowId = this.adapter.getRowIdAtIndex(rowIndex);
  131. var isSelected = false;
  132. if (rowId && rowIds.indexOf(rowId) >= 0) {
  133. isSelected = true;
  134. }
  135. this.adapter.setRowCheckboxCheckedAtIndex(rowIndex, isSelected);
  136. this.selectRowAtIndex(rowIndex, isSelected);
  137. }
  138. this.setHeaderRowCheckboxState();
  139. };
  140. /**
  141. * @return Returns array of all row ids.
  142. */
  143. MDCDataTableFoundation.prototype.getRowIds = function () {
  144. var rowIds = [];
  145. for (var rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
  146. rowIds.push(this.adapter.getRowIdAtIndex(rowIndex));
  147. }
  148. return rowIds;
  149. };
  150. /**
  151. * @return Returns array of selected row ids.
  152. */
  153. MDCDataTableFoundation.prototype.getSelectedRowIds = function () {
  154. var selectedRowIds = [];
  155. for (var rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
  156. if (this.adapter.isCheckboxAtRowIndexChecked(rowIndex)) {
  157. selectedRowIds.push(this.adapter.getRowIdAtIndex(rowIndex));
  158. }
  159. }
  160. return selectedRowIds;
  161. };
  162. /**
  163. * Handles header row checkbox change event.
  164. */
  165. MDCDataTableFoundation.prototype.handleHeaderRowCheckboxChange = function () {
  166. var isHeaderChecked = this.adapter.isHeaderRowCheckboxChecked();
  167. for (var rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
  168. this.adapter.setRowCheckboxCheckedAtIndex(rowIndex, isHeaderChecked);
  169. this.selectRowAtIndex(rowIndex, isHeaderChecked);
  170. }
  171. if (isHeaderChecked) {
  172. this.adapter.notifySelectedAll();
  173. }
  174. else {
  175. this.adapter.notifyUnselectedAll();
  176. }
  177. };
  178. /**
  179. * Handles change event originated from row checkboxes.
  180. */
  181. MDCDataTableFoundation.prototype.handleRowCheckboxChange = function (event) {
  182. var rowIndex = this.adapter.getRowIndexByChildElement(event.target);
  183. if (rowIndex === -1) {
  184. return;
  185. }
  186. var selected = this.adapter.isCheckboxAtRowIndexChecked(rowIndex);
  187. this.selectRowAtIndex(rowIndex, selected);
  188. this.setHeaderRowCheckboxState();
  189. var rowId = this.adapter.getRowIdAtIndex(rowIndex);
  190. this.adapter.notifyRowSelectionChanged({ rowId: rowId, rowIndex: rowIndex, selected: selected });
  191. };
  192. /**
  193. * Handles sort action on sortable header cell.
  194. */
  195. MDCDataTableFoundation.prototype.handleSortAction = function (eventData) {
  196. var columnId = eventData.columnId, columnIndex = eventData.columnIndex, headerCell = eventData.headerCell;
  197. // Reset sort attributes / classes on other header cells.
  198. for (var index = 0; index < this.adapter.getHeaderCellCount(); index++) {
  199. if (index === columnIndex) {
  200. continue;
  201. }
  202. this.adapter.removeClassNameByHeaderCellIndex(index, cssClasses.HEADER_CELL_SORTED);
  203. this.adapter.removeClassNameByHeaderCellIndex(index, cssClasses.HEADER_CELL_SORTED_DESCENDING);
  204. this.adapter.setAttributeByHeaderCellIndex(index, attributes.ARIA_SORT, SortValue.NONE);
  205. this.adapter.setSortStatusLabelByHeaderCellIndex(index, SortValue.NONE);
  206. }
  207. // Set appropriate sort attributes / classes on target header cell.
  208. this.adapter.setClassNameByHeaderCellIndex(columnIndex, cssClasses.HEADER_CELL_SORTED);
  209. var currentSortValue = this.adapter.getAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT);
  210. var sortValue = SortValue.NONE;
  211. // Set to descending if sorted on ascending order.
  212. if (currentSortValue === SortValue.ASCENDING) {
  213. this.adapter.setClassNameByHeaderCellIndex(columnIndex, cssClasses.HEADER_CELL_SORTED_DESCENDING);
  214. this.adapter.setAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT, SortValue.DESCENDING);
  215. sortValue = SortValue.DESCENDING;
  216. // Set to ascending if sorted on descending order.
  217. }
  218. else if (currentSortValue === SortValue.DESCENDING) {
  219. this.adapter.removeClassNameByHeaderCellIndex(columnIndex, cssClasses.HEADER_CELL_SORTED_DESCENDING);
  220. this.adapter.setAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT, SortValue.ASCENDING);
  221. sortValue = SortValue.ASCENDING;
  222. }
  223. else {
  224. // Set to ascending by default when not sorted.
  225. this.adapter.setAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT, SortValue.ASCENDING);
  226. sortValue = SortValue.ASCENDING;
  227. }
  228. this.adapter.setSortStatusLabelByHeaderCellIndex(columnIndex, sortValue);
  229. this.adapter.notifySortAction({
  230. columnId: columnId,
  231. columnIndex: columnIndex,
  232. headerCell: headerCell,
  233. sortValue: sortValue,
  234. });
  235. };
  236. /**
  237. * Handles data table row click event.
  238. */
  239. MDCDataTableFoundation.prototype.handleRowClick = function (_a) {
  240. var rowId = _a.rowId, row = _a.row, altKey = _a.altKey, ctrlKey = _a.ctrlKey, metaKey = _a.metaKey, shiftKey = _a.shiftKey;
  241. this.adapter.notifyRowClick({
  242. rowId: rowId,
  243. row: row,
  244. altKey: altKey,
  245. ctrlKey: ctrlKey,
  246. metaKey: metaKey,
  247. shiftKey: shiftKey,
  248. });
  249. };
  250. /**
  251. * Shows progress indicator blocking only the table body content when in
  252. * loading state.
  253. */
  254. MDCDataTableFoundation.prototype.showProgress = function () {
  255. var tableHeaderHeight = this.adapter.getTableHeaderHeight();
  256. // Calculate the height of table content (Not scroll content) excluding
  257. // header row height.
  258. var height = this.adapter.getTableContainerHeight() - tableHeaderHeight;
  259. var top = tableHeaderHeight;
  260. this.adapter.setProgressIndicatorStyles({
  261. height: height + "px",
  262. top: top + "px",
  263. });
  264. this.adapter.addClass(cssClasses.IN_PROGRESS);
  265. };
  266. /**
  267. * Hides progress indicator when data table is finished loading.
  268. */
  269. MDCDataTableFoundation.prototype.hideProgress = function () {
  270. this.adapter.removeClass(cssClasses.IN_PROGRESS);
  271. };
  272. /**
  273. * Updates header row checkbox state based on number of rows selected.
  274. */
  275. MDCDataTableFoundation.prototype.setHeaderRowCheckboxState = function () {
  276. if (this.adapter.getSelectedRowCount() === 0) {
  277. this.adapter.setHeaderRowCheckboxChecked(false);
  278. this.adapter.setHeaderRowCheckboxIndeterminate(false);
  279. }
  280. else if (this.adapter.getSelectedRowCount() === this.adapter.getRowCount()) {
  281. this.adapter.setHeaderRowCheckboxChecked(true);
  282. this.adapter.setHeaderRowCheckboxIndeterminate(false);
  283. }
  284. else {
  285. this.adapter.setHeaderRowCheckboxIndeterminate(true);
  286. this.adapter.setHeaderRowCheckboxChecked(false);
  287. }
  288. };
  289. /**
  290. * Sets the attributes of row element based on selection state.
  291. */
  292. MDCDataTableFoundation.prototype.selectRowAtIndex = function (rowIndex, selected) {
  293. if (selected) {
  294. this.adapter.addClassAtRowIndex(rowIndex, cssClasses.ROW_SELECTED);
  295. this.adapter.setAttributeAtRowIndex(rowIndex, attributes.ARIA_SELECTED, 'true');
  296. }
  297. else {
  298. this.adapter.removeClassAtRowIndex(rowIndex, cssClasses.ROW_SELECTED);
  299. this.adapter.setAttributeAtRowIndex(rowIndex, attributes.ARIA_SELECTED, 'false');
  300. }
  301. };
  302. return MDCDataTableFoundation;
  303. }(MDCFoundation));
  304. export { MDCDataTableFoundation };
  305. //# sourceMappingURL=foundation.js.map