| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 1 | window.angular && (function(angular) { | 
|  | 2 | 'use strict'; | 
|  | 3 |  | 
|  | 4 | /** | 
|  | 5 | * | 
| Yoshie Muranaka | bb68879 | 2019-08-12 09:31:52 -0500 | [diff] [blame] | 6 | * bmcTable Component | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 7 | * | 
|  | 8 | * To use: | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 9 | * | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 10 | * The 'data' attribute should be an array of all row objects in the table. | 
|  | 11 | * It will render each item as a <tr> in the table. | 
|  | 12 | * Each row object in the data array should also have a 'uiData' | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 13 | * property that should be an array of the properties that will render | 
|  | 14 | * as each table cell <td>. | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 15 | * Each row object in the data array can optionally have an | 
| Yoshie Muranaka | bb68879 | 2019-08-12 09:31:52 -0500 | [diff] [blame] | 16 | * 'actions' property that should be an array of actions to provide the | 
|  | 17 | * <bmc-table-actions> component. | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 18 | * Each row object can optionally have an 'expandContent' property | 
|  | 19 | * that should be a string value and can contain valid HTML. To render | 
|  | 20 | * the expanded content, set 'expandable' attribute to true. | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 21 | * | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 22 | * data = [ | 
|  | 23 | *  { uiData: ['root', 'Admin', 'enabled' ] }, | 
|  | 24 | *  { uiData: ['user1', 'User', 'disabled' ] } | 
|  | 25 | * ] | 
|  | 26 | * | 
|  | 27 | * The 'header' attribute should be an array of all header objects in the | 
|  | 28 | * table. Each object in the header array should have a 'label' property | 
|  | 29 | * that will render as a <th> in the table. | 
|  | 30 | * If the table is sortable, can optionally add 'sortable' property to header | 
|  | 31 | * row object. If a particular column is not sortable, set to false. | 
|  | 32 | * | 
|  | 33 | * header = [ | 
|  | 34 | *  { label: 'Username' }, | 
|  | 35 | *  { label: 'Privilege' } | 
|  | 36 | *  { label: 'Account Status', sortable: false } | 
|  | 37 | * ] | 
|  | 38 | * | 
|  | 39 | * The 'sortable' attribute should be a boolean value. Defaults to false. | 
|  | 40 | * The 'default-sort' attribute should be the index value of the header | 
|  | 41 | * obejct that should be sorted on inital load. | 
|  | 42 | * | 
|  | 43 | * The 'row-actions-enabled' attribute, should be a boolean value | 
|  | 44 | * Can be set to true to render table row actions. Defaults to false. | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 45 | * Row actions are defined in data.actions. | 
|  | 46 | * | 
|  | 47 | * The 'expandable' attribute should be a boolean value. If true each | 
|  | 48 | * row object in data array should contain a 'expandContent' property | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 49 | * | 
|  | 50 | * The 'size' attribute which can be set to 'small' which will | 
|  | 51 | * render a smaller font size in the table. | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 52 | * | 
|  | 53 | */ | 
| Yoshie Muranaka | bb68879 | 2019-08-12 09:31:52 -0500 | [diff] [blame] | 54 |  | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 55 | const TableController = function() { | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 56 | this.sortAscending = true; | 
|  | 57 | this.activeSort; | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 58 | this.expandedRows = new Set(); | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 59 |  | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 60 | /** | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 61 | * Sorts table data | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 62 | */ | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 63 | const sortData = () => { | 
|  | 64 | this.data.sort((a, b) => { | 
|  | 65 | const aProp = a.uiData[this.activeSort]; | 
|  | 66 | const bProp = b.uiData[this.activeSort]; | 
|  | 67 | if (aProp === bProp) { | 
|  | 68 | return 0; | 
|  | 69 | } else { | 
|  | 70 | if (this.sortAscending) { | 
|  | 71 | return aProp < bProp ? -1 : 1; | 
|  | 72 | } | 
|  | 73 | return aProp > bProp ? -1 : 1; | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 74 | } | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 75 | }) | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 76 | }; | 
|  | 77 |  | 
|  | 78 | /** | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 79 | * Prep table | 
|  | 80 | * Make adjustments to account for optional configurations | 
|  | 81 | */ | 
|  | 82 | const prepTable = () => { | 
|  | 83 | if (this.sortable) { | 
|  | 84 | // If sort is enabled, check for undefined 'sortable' | 
|  | 85 | // property for each item in header array | 
|  | 86 | this.header = this.header.map((column) => { | 
|  | 87 | column.sortable = | 
|  | 88 | column.sortable === undefined ? true : column.sortable; | 
|  | 89 | return column; | 
|  | 90 | }) | 
|  | 91 | } | 
|  | 92 | if (this.rowActionsEnabled) { | 
|  | 93 | // If table actions are enabled push an empty | 
|  | 94 | // string to the header array to account for additional | 
|  | 95 | // table actions cell | 
|  | 96 | this.header.push({label: '', sortable: false}); | 
|  | 97 | } | 
|  | 98 | if (this.expandable) { | 
|  | 99 | // If table is expandable, push an empty string to the | 
|  | 100 | // header array to account for additional expansion cell | 
|  | 101 | this.header.unshift({label: '', sortable: false}); | 
|  | 102 | } | 
|  | 103 | }; | 
|  | 104 |  | 
|  | 105 | /** | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 106 | * Callback when table row action clicked | 
|  | 107 | * Emits user desired action and associated row data to | 
|  | 108 | * parent controller | 
|  | 109 | * @param {string} action : action type | 
|  | 110 | * @param {any} row : user object | 
|  | 111 | */ | 
| Yoshie Muranaka | bb68879 | 2019-08-12 09:31:52 -0500 | [diff] [blame] | 112 | this.onEmitTableAction = (action, row) => { | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 113 | if (action !== undefined && row !== undefined) { | 
|  | 114 | const value = {action, row}; | 
|  | 115 | this.emitAction({value}); | 
|  | 116 | } | 
|  | 117 | }; | 
|  | 118 |  | 
|  | 119 | /** | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 120 | * Callback when sortable table header clicked | 
|  | 121 | * @param {number} index : index of header item | 
|  | 122 | */ | 
|  | 123 | this.onClickSort = (index) => { | 
|  | 124 | if (index === this.activeSort) { | 
|  | 125 | // If clicked header is already sorted, reverse | 
|  | 126 | // the sort direction | 
|  | 127 | this.sortAscending = !this.sortAscending; | 
|  | 128 | this.data.reverse(); | 
|  | 129 | } else { | 
|  | 130 | this.sortAscending = true; | 
|  | 131 | this.activeSort = index; | 
|  | 132 | sortData(); | 
|  | 133 | } | 
|  | 134 | }; | 
|  | 135 |  | 
|  | 136 | /** | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 137 | * Callback when expand trigger clicked | 
|  | 138 | * @param {number} row : index of expanded row | 
|  | 139 | */ | 
|  | 140 | this.onClickExpand = (row) => { | 
|  | 141 | if (this.expandedRows.has(row)) { | 
|  | 142 | this.expandedRows.delete(row) | 
|  | 143 | } else { | 
|  | 144 | this.expandedRows.add(row); | 
|  | 145 | } | 
|  | 146 | }; | 
|  | 147 |  | 
|  | 148 | /** | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 149 | * onInit Component lifecycle hook | 
|  | 150 | * Checking for undefined values | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 151 | */ | 
|  | 152 | this.$onInit = () => { | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 153 | this.header = this.header === undefined ? [] : this.header; | 
|  | 154 | this.data = this.data == undefined ? [] : this.data; | 
|  | 155 | this.sortable = this.sortable === undefined ? false : this.sortable; | 
| Yoshie Muranaka | bb68879 | 2019-08-12 09:31:52 -0500 | [diff] [blame] | 156 | this.rowActionsEnabled = | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 157 | this.rowActionsEnabled === undefined ? false : this.rowActionsEnabled; | 
|  | 158 | this.size = this.size === undefined ? '' : this.size; | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 159 | this.expandable = this.expandable === undefined ? false : this.expandable; | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 160 |  | 
|  | 161 | // Check for undefined 'uiData' property for each item in data array | 
|  | 162 | this.data = this.data.map((row) => { | 
|  | 163 | if (row.uiData === undefined) { | 
|  | 164 | row.uiData = []; | 
|  | 165 | } | 
|  | 166 | return row; | 
|  | 167 | }) | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 168 | prepTable(); | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 169 | }; | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 170 |  | 
|  | 171 | /** | 
|  | 172 | * onChanges Component lifecycle hook | 
|  | 173 | * Check for changes in the data array and apply | 
|  | 174 | * default or active sort if one is defined | 
|  | 175 | */ | 
|  | 176 | this.$onChanges = (onChangesObj) => { | 
|  | 177 | const dataChange = onChangesObj.data; | 
|  | 178 | if (dataChange) { | 
|  | 179 | if (this.activeSort !== undefined || this.defaultSort !== undefined) { | 
|  | 180 | this.activeSort = this.defaultSort !== undefined ? this.defaultSort : | 
|  | 181 | this.activeSort; | 
|  | 182 | sortData(); | 
|  | 183 | } | 
|  | 184 | } | 
|  | 185 | } | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 186 | }; | 
|  | 187 |  | 
|  | 188 | /** | 
|  | 189 | * Register bmcTable component | 
|  | 190 | */ | 
|  | 191 | angular.module('app.common.components').component('bmcTable', { | 
|  | 192 | template: require('./table.html'), | 
|  | 193 | controller: TableController, | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 194 | bindings: { | 
|  | 195 | data: '<',               // Array | 
|  | 196 | header: '<',             // Array | 
|  | 197 | rowActionsEnabled: '<',  // boolean | 
|  | 198 | size: '<',               // string | 
|  | 199 | sortable: '<',           // boolean | 
|  | 200 | defaultSort: '<',        // number (index of sort) | 
| Yoshie Muranaka | 1d83af0 | 2019-09-06 08:52:35 -0700 | [diff] [blame] | 201 | expandable: '<',         // boolean | 
| Yoshie Muranaka | b1f6424 | 2019-09-04 11:40:51 -0700 | [diff] [blame] | 202 | emitAction: '&' | 
|  | 203 | } | 
| Yoshie Muranaka | fa56273 | 2019-07-17 11:23:15 -0500 | [diff] [blame] | 204 | }) | 
|  | 205 | })(window.angular); |