UNPKG

8.58 kBJavaScriptView Raw
1/**
2 * @author: Yura Knoxville
3 * @version: v1.1.0
4 */
5
6let initBodyCaller
7
8const groupBy = (array, f) => {
9 const tmpGroups = {}
10
11 array.forEach(o => {
12 const groups = f(o)
13
14 tmpGroups[groups] = tmpGroups[groups] || []
15 tmpGroups[groups].push(o)
16 })
17
18 return tmpGroups
19}
20
21$.extend($.fn.bootstrapTable.defaults.icons, {
22 collapseGroup: {
23 bootstrap3: 'glyphicon-chevron-up',
24 bootstrap5: 'bi-chevron-up',
25 materialize: 'arrow_drop_down'
26 }[$.fn.bootstrapTable.theme] || 'fa-angle-up',
27 expandGroup: {
28 bootstrap3: 'glyphicon-chevron-down',
29 bootstrap5: 'bi-chevron-down',
30 materialize: 'arrow_drop_up'
31 }[$.fn.bootstrapTable.theme] || 'fa-angle-down'
32})
33
34$.extend($.fn.bootstrapTable.defaults, {
35 groupBy: false,
36 groupByField: '',
37 groupByFormatter: undefined,
38 groupByToggle: false,
39 groupByShowToggleIcon: false,
40 groupByCollapsedGroups: []
41})
42
43const Utils = $.fn.bootstrapTable.utils
44const BootstrapTable = $.fn.bootstrapTable.Constructor
45const _initSort = BootstrapTable.prototype.initSort
46const _initBody = BootstrapTable.prototype.initBody
47const _updateSelected = BootstrapTable.prototype.updateSelected
48
49BootstrapTable.prototype.initSort = function (...args) {
50 _initSort.apply(this, Array.prototype.slice.apply(args))
51
52 const that = this
53
54 this.tableGroups = []
55
56 if ((this.options.groupBy) && (this.options.groupByField !== '')) {
57 if ((this.options.sortName !== this.options.groupByField)) {
58 if (this.options.customSort) {
59 Utils.calculateObjectValue(this.options, this.options.customSort, [
60 this.options.sortName,
61 this.options.sortOrder,
62 this.data
63 ])
64 } else {
65 this.options.data.sort((a, b) => {
66 const groupByFields = this.getGroupByFields()
67 const fieldValuesA = []
68 const fieldValuesB = []
69
70 $.each(groupByFields, (i, field) => {
71 fieldValuesA.push(a[field])
72 fieldValuesB.push(b[field])
73 })
74
75 a = fieldValuesA.join()
76 b = fieldValuesB.join()
77 return a.localeCompare(b, undefined, { numeric: true })
78 })
79 }
80 }
81
82 const groups = groupBy(that.data, item => {
83 const groupByFields = this.getGroupByFields()
84 const groupValues = []
85
86 $.each(groupByFields, (i, field) => {
87 groupValues.push(item[field])
88 })
89
90 return groupValues.join(', ')
91 })
92
93 let index = 0
94
95 $.each(groups, (key, value) => {
96 this.tableGroups.push({
97 id: index,
98 name: key,
99 data: value
100 })
101
102 value.forEach(item => {
103 if (!item._data) {
104 item._data = {}
105 }
106
107 if (this.isCollapsed(key, value)) {
108 item._class += ' hidden'
109 }
110
111 item._data['parent-index'] = index
112 })
113
114 index++
115 })
116 }
117}
118
119BootstrapTable.prototype.initBody = function (...args) {
120 initBodyCaller = true
121 _initBody.apply(this, Array.prototype.slice.apply(args))
122
123 if ((this.options.groupBy) && (this.options.groupByField !== '')) {
124 const that = this
125 let checkBox = false
126 let visibleColumns = 0
127
128 this.columns.forEach(column => {
129 if (column.checkbox) {
130 checkBox = true
131 } else if (column.visible) {
132 visibleColumns += 1
133 }
134 })
135
136 if (this.options.detailView && !this.options.cardView) {
137 visibleColumns += 1
138 }
139
140 this.tableGroups.forEach(item => {
141 const html = []
142
143 html.push(Utils.sprintf('<tr class="info groupBy %s" data-group-index="%s">', this.options.groupByToggle ? 'expanded' : '', item.id))
144 if (that.options.detailView && !that.options.cardView) {
145 html.push('<td class="detail"></td>')
146 }
147
148 if (checkBox) {
149 html.push('<td class="bs-checkbox">',
150 '<input name="btSelectGroup" type="checkbox" />',
151 '</td>'
152 )
153 }
154
155 let formattedValue = item.name
156
157 if (that.options.groupByFormatter !== undefined) {
158 formattedValue = Utils.calculateObjectValue(that.options, that.options.groupByFormatter, [item.name, item.id, item.data])
159 }
160 html.push('<td',
161 Utils.sprintf(' colspan="%s"', visibleColumns),
162 '>', formattedValue
163 )
164
165 let icon = this.options.icons.collapseGroup
166
167 if (this.isCollapsed(item.name, item.data)) {
168 icon = this.options.icons.expandGroup
169 }
170
171 if (this.options.groupByToggle && this.options.groupByShowToggleIcon) {
172 html.push(`<span class="float-right ${this.options.iconsPrefix} ${icon}"></span>`)
173 }
174
175 html.push('</td></tr>')
176 that.$body.find(`tr[data-parent-index=${item.id}]:first`).before($(html.join('')))
177 })
178
179 this.$selectGroup = []
180 this.$body.find('[name="btSelectGroup"]').each(function () {
181 const self = $(this)
182
183 that.$selectGroup.push({
184 group: self,
185 item: that.$selectItem.filter(function () {
186 return ($(this).closest('tr').data('parent-index') ===
187 self.closest('tr').data('group-index'))
188 })
189 })
190 })
191
192 if (this.options.groupByToggle) {
193 this.$container.off('click', '.groupBy')
194 .on('click', '.groupBy', function () {
195 const $this = $(this)
196 const groupIndex = $this.closest('tr').data('group-index')
197 const $groupRows = that.$body.find(`tr[data-parent-index=${groupIndex}]`)
198
199 $this.toggleClass('expanded collapsed')
200 $this.find('span').toggleClass(`${that.options.icons.collapseGroup} ${that.options.icons.expandGroup}`)
201 $groupRows.toggleClass('hidden')
202 $groupRows.each((i, element) => that.collapseRow($(element).data('index')))
203 })
204 }
205
206 this.$container.off('click', '[name="btSelectGroup"]')
207 .on('click', '[name="btSelectGroup"]', function (event) {
208 event.stopImmediatePropagation()
209
210 const self = $(this)
211 const checked = self.prop('checked')
212
213 that[checked ? 'checkGroup' : 'uncheckGroup']($(this).closest('tr').data('group-index'))
214 })
215 }
216
217 initBodyCaller = false
218 this.updateSelected()
219}
220
221BootstrapTable.prototype.updateSelected = function (...args) {
222 if (!initBodyCaller) {
223 _updateSelected.apply(this, Array.prototype.slice.apply(args))
224
225 if ((this.options.groupBy) && (this.options.groupByField !== '')) {
226 this.$selectGroup.forEach(item => {
227 const checkGroup = item.item.filter(':enabled').length ===
228 item.item.filter(':enabled').filter(':checked').length
229
230 item.group.prop('checked', checkGroup)
231 })
232 }
233 }
234}
235
236BootstrapTable.prototype.checkGroup = function (index) {
237 this.checkGroup_(index, true)
238}
239
240BootstrapTable.prototype.uncheckGroup = function (index) {
241 this.checkGroup_(index, false)
242}
243
244BootstrapTable.prototype.isCollapsed = function (groupKey, items) {
245 if (this.options.groupByCollapsedGroups) {
246 const collapsedGroups = Utils.calculateObjectValue(this, this.options.groupByCollapsedGroups, [groupKey, items], true)
247
248 if ($.inArray(groupKey, collapsedGroups) > -1) {
249 return true
250 }
251 }
252
253 return false
254}
255
256BootstrapTable.prototype.checkGroup_ = function (index, checked) {
257 const rowsBefore = this.getSelections()
258 const filter = function () {
259 return ($(this).closest('tr').data('parent-index') === index)
260 }
261
262 this.$selectItem.filter(filter).prop('checked', checked)
263
264 this.updateRows()
265 this.updateSelected()
266 const rowsAfter = this.getSelections()
267
268 if (checked) {
269 this.trigger('check-all', rowsAfter, rowsBefore)
270 return
271 }
272
273 this.trigger('uncheck-all', rowsAfter, rowsBefore)
274}
275
276BootstrapTable.prototype.getGroupByFields = function () {
277 let groupByFields = this.options.groupByField
278
279 if (!$.isArray(this.options.groupByField)) {
280 groupByFields = [this.options.groupByField]
281 }
282
283 return groupByFields
284}
285
286$.BootstrapTable = class extends $.BootstrapTable {
287 scrollTo (params) {
288 if (this.options.groupBy) {
289 let options = { unit: 'px', value: 0 }
290
291 if (typeof params === 'object') {
292 options = Object.assign(options, params)
293 }
294
295 if (options.unit === 'rows') {
296 let scrollTo = 0
297
298 this.$body.find(`> tr:not(.groupBy):lt(${options.value})`).each((i, el) => {
299 scrollTo += $(el).outerHeight(true)
300 })
301
302 const $targetColumn = this.$body.find(`> tr:not(.groupBy):eq(${options.value})`)
303
304 $targetColumn.prevAll('.groupBy').each((i, el) => {
305 scrollTo += $(el).outerHeight(true)
306 })
307
308 this.$tableBody.scrollTop(scrollTo)
309 return
310 }
311 }
312
313 super.scrollTo(params)
314 }
315}