| /** | 
|  * @author: Yura Knoxville | 
|  * @version: v1.0.0 | 
|  */ | 
|   | 
| !function ($) { | 
|   | 
|     'use strict'; | 
|   | 
|     var initBodyCaller, | 
|         tableGroups; | 
|   | 
|     // it only does '%s', and return '' when arguments are undefined | 
|     var sprintf = function (str) { | 
|         var args = arguments, | 
|             flag = true, | 
|             i = 1; | 
|   | 
|         str = str.replace(/%s/g, function () { | 
|             var arg = args[i++]; | 
|   | 
|             if (typeof arg === 'undefined') { | 
|                 flag = false; | 
|                 return ''; | 
|             } | 
|             return arg; | 
|         }); | 
|         return flag ? str : ''; | 
|     }; | 
|   | 
|     var groupBy = function (array , f) { | 
|         var groups = {}; | 
|         array.forEach(function(o) { | 
|             var group = f(o); | 
|             groups[group] = groups[group] || []; | 
|             groups[group].push(o); | 
|         }); | 
|   | 
|         return groups; | 
|     }; | 
|   | 
|     $.extend($.fn.bootstrapTable.defaults, { | 
|         groupBy: false, | 
|         groupByField: '' | 
|     }); | 
|   | 
|     var BootstrapTable = $.fn.bootstrapTable.Constructor, | 
|         _initSort = BootstrapTable.prototype.initSort, | 
|         _initBody = BootstrapTable.prototype.initBody, | 
|         _updateSelected = BootstrapTable.prototype.updateSelected; | 
|   | 
|     BootstrapTable.prototype.initSort = function () { | 
|         _initSort.apply(this, Array.prototype.slice.apply(arguments)); | 
|   | 
|         var that = this; | 
|         tableGroups = []; | 
|   | 
|         if ((this.options.groupBy) && (this.options.groupByField !== '')) { | 
|   | 
|             if ((this.options.sortName != this.options.groupByField)) { | 
|                 this.data.sort(function(a, b) { | 
|                     return a[that.options.groupByField].localeCompare(b[that.options.groupByField]); | 
|                 }); | 
|             } | 
|   | 
|             var that = this; | 
|             var groups = groupBy(that.data, function (item) { | 
|                 return [item[that.options.groupByField]]; | 
|             }); | 
|   | 
|             var index = 0; | 
|             $.each(groups, function(key, value) { | 
|                 tableGroups.push({ | 
|                     id: index, | 
|                     name: key | 
|                 }); | 
|   | 
|                 value.forEach(function(item) { | 
|                     if (!item._data) { | 
|                         item._data = {}; | 
|                     } | 
|   | 
|                     item._data['parent-index'] = index; | 
|                 }); | 
|   | 
|                 index++; | 
|             }); | 
|         } | 
|     } | 
|   | 
|     BootstrapTable.prototype.initBody = function () { | 
|         initBodyCaller = true; | 
|   | 
|         _initBody.apply(this, Array.prototype.slice.apply(arguments)); | 
|   | 
|         if ((this.options.groupBy) && (this.options.groupByField !== '')) { | 
|             var that = this, | 
|                 checkBox = false, | 
|                 visibleColumns = 0; | 
|   | 
|             this.columns.forEach(function(column) { | 
|                 if (column.checkbox) { | 
|                     checkBox = true; | 
|                 } else { | 
|                     if (column.visible) { | 
|                         visibleColumns += 1; | 
|                     } | 
|                 } | 
|             }); | 
|   | 
|             if (this.options.detailView && !this.options.cardView) { | 
|                 visibleColumns += 1; | 
|             } | 
|   | 
|             tableGroups.forEach(function(item){ | 
|                 var html = []; | 
|   | 
|                 html.push(sprintf('<tr class="info groupBy expanded" data-group-index="%s">', item.id)); | 
|   | 
|                 if (that.options.detailView && !that.options.cardView) { | 
|                     html.push('<td class="detail"></td>'); | 
|                 } | 
|   | 
|                 if (checkBox) { | 
|                     html.push('<td class="bs-checkbox">', | 
|                         '<input  name="btSelectGroup" type="checkbox" />', | 
|                         '</td>' | 
|                     ); | 
|                 } | 
|   | 
|                 html.push('<td', | 
|                     sprintf(' colspan="%s"', visibleColumns), | 
|                     '>', item.name, '</td>' | 
|                 ); | 
|   | 
|                 html.push('</tr>'); | 
|   | 
|                 that.$body.find('tr[data-parent-index='+item.id+']:first').before($(html.join(''))); | 
|             }); | 
|   | 
|             this.$selectGroup = []; | 
|             this.$body.find('[name="btSelectGroup"]').each(function() { | 
|                 var self = $(this); | 
|   | 
|                 that.$selectGroup.push({ | 
|                     group: self, | 
|                     item: that.$selectItem.filter(function () { | 
|                         return ($(this).closest('tr').data('parent-index') === | 
|                         self.closest('tr').data('group-index')); | 
|                     }) | 
|                 }); | 
|             }); | 
|   | 
|             this.$container.off('click', '.groupBy') | 
|                 .on('click', '.groupBy', function() { | 
|                     $(this).toggleClass('expanded'); | 
|                     that.$body.find('tr[data-parent-index='+$(this).closest('tr').data('group-index')+']').toggleClass('hidden'); | 
|                 }); | 
|   | 
|             this.$container.off('click', '[name="btSelectGroup"]') | 
|                 .on('click', '[name="btSelectGroup"]', function (event) { | 
|                     event.stopImmediatePropagation(); | 
|   | 
|                     var self = $(this); | 
|                     var checked = self.prop('checked'); | 
|                     that[checked ? 'checkGroup' : 'uncheckGroup']($(this).closest('tr').data('group-index')); | 
|                 }); | 
|         } | 
|   | 
|         initBodyCaller = false; | 
|         this.updateSelected(); | 
|     }; | 
|   | 
|     BootstrapTable.prototype.updateSelected = function () { | 
|         if (!initBodyCaller) { | 
|             _updateSelected.apply(this, Array.prototype.slice.apply(arguments)); | 
|   | 
|             if ((this.options.groupBy) && (this.options.groupByField !== '')) { | 
|                 this.$selectGroup.forEach(function (item) { | 
|                     var checkGroup = item.item.filter(':enabled').length === | 
|                         item.item.filter(':enabled').filter(':checked').length; | 
|   | 
|                     item.group.prop('checked', checkGroup); | 
|                 }); | 
|             } | 
|         } | 
|     }; | 
|   | 
|     BootstrapTable.prototype.getGroupSelections = function (index) { | 
|         var that = this; | 
|   | 
|         return $.grep(this.data, function (row) { | 
|             return (row[that.header.stateField] && (row._data['parent-index'] === index)); | 
|         }); | 
|     }; | 
|   | 
|     BootstrapTable.prototype.checkGroup = function (index) { | 
|         this.checkGroup_(index, true); | 
|     }; | 
|   | 
|     BootstrapTable.prototype.uncheckGroup = function (index) { | 
|         this.checkGroup_(index, false); | 
|     }; | 
|   | 
|     BootstrapTable.prototype.checkGroup_ = function (index, checked) { | 
|         var rows; | 
|         var filter = function() { | 
|             return ($(this).closest('tr').data('parent-index') === index); | 
|         }; | 
|   | 
|         if (!checked) { | 
|             rows = this.getGroupSelections(index); | 
|         } | 
|   | 
|         this.$selectItem.filter(filter).prop('checked', checked); | 
|   | 
|   | 
|         this.updateRows(); | 
|         this.updateSelected(); | 
|         if (checked) { | 
|             rows = this.getGroupSelections(index); | 
|         } | 
|         this.trigger(checked ? 'check-all' : 'uncheck-all', rows); | 
|     }; | 
|   | 
| }(jQuery); |