/** 
 | 
 * @author Nadim Basalamah <dimbslmh@gmail.com> 
 | 
 * @version: v1.0.0 
 | 
 * https://github.com/dimbslmh/bootstrap-table/tree/master/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js 
 | 
 */ 
 | 
  
 | 
(function($) { 
 | 
    'use strict'; 
 | 
  
 | 
    var isSingleSort = false; 
 | 
  
 | 
    var sort_order = { 
 | 
        asc: 'Ascending', 
 | 
        desc: 'Descending' 
 | 
    }; 
 | 
  
 | 
    var showSortModal = function(that) { 
 | 
        var _selector = that.$sortModal.selector, 
 | 
            _id = _selector.substr(1); 
 | 
  
 | 
        if (!$(_id).hasClass("modal")) { 
 | 
            var sModal = '  <div class="modal fade" id="' + _id + '" tabindex="-1" role="dialog" aria-labelledby="' + _id + 'Label" aria-hidden="true">'; 
 | 
            sModal += '         <div class="modal-dialog">'; 
 | 
            sModal += '             <div class="modal-content">'; 
 | 
            sModal += '                 <div class="modal-header">'; 
 | 
            sModal += '                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>'; 
 | 
            sModal += '                     <h4 class="modal-title" id="' + _id + 'Label">' + that.options.formatMultipleSort() + '</h4>'; 
 | 
            sModal += '                 </div>'; 
 | 
            sModal += '                 <div class="modal-body">'; 
 | 
            sModal += '                     <div class="bootstrap-table">'; 
 | 
            sModal += '                         <div class="fixed-table-toolbar">'; 
 | 
            sModal += '                             <div class="bars">'; 
 | 
            sModal += '                                 <div id="toolbar">'; 
 | 
            sModal += '                                     <button id="add" type="button" class="btn btn-default"><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.plus + '"></i> ' + that.options.formatAddLevel() + '</button>'; 
 | 
            sModal += '                                     <button id="delete" type="button" class="btn btn-default" disabled><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.minus + '"></i> ' + that.options.formatDeleteLevel() + '</button>'; 
 | 
            sModal += '                                 </div>'; 
 | 
            sModal += '                             </div>'; 
 | 
            sModal += '                         </div>'; 
 | 
            sModal += '                         <div class="fixed-table-container">'; 
 | 
            sModal += '                             <table id="multi-sort" class="table">'; 
 | 
            sModal += '                                 <thead>'; 
 | 
            sModal += '                                     <tr>'; 
 | 
            sModal += '                                         <th></th>'; 
 | 
            sModal += '                                         <th><div class="th-inner">' + that.options.formatColumn() + '</div></th>'; 
 | 
            sModal += '                                         <th><div class="th-inner">' + that.options.formatOrder() + '</div></th>'; 
 | 
            sModal += '                                     </tr>'; 
 | 
            sModal += '                                 </thead>'; 
 | 
            sModal += '                                 <tbody></tbody>'; 
 | 
            sModal += '                             </table>'; 
 | 
            sModal += '                         </div>'; 
 | 
            sModal += '                     </div>'; 
 | 
            sModal += '                 </div>'; 
 | 
            sModal += '                 <div class="modal-footer">'; 
 | 
            sModal += '                     <button type="button" class="btn btn-default" data-dismiss="modal">' + that.options.formatCancel() + '</button>'; 
 | 
            sModal += '                     <button type="button" class="btn btn-primary">' + that.options.formatSort() + '</button>'; 
 | 
            sModal += '                 </div>'; 
 | 
            sModal += '             </div>'; 
 | 
            sModal += '         </div>'; 
 | 
            sModal += '     </div>'; 
 | 
  
 | 
            $("body").append($(sModal)); 
 | 
  
 | 
            that.$sortModal = $(_selector); 
 | 
            var $rows = that.$sortModal.find("tbody > tr"); 
 | 
  
 | 
            that.$sortModal.off('click', '#add').on('click', '#add', function() { 
 | 
                var total = that.$sortModal.find('.multi-sort-name:first option').length, 
 | 
                    current = that.$sortModal.find('tbody tr').length; 
 | 
  
 | 
                if (current < total) { 
 | 
                    current++; 
 | 
                    that.addLevel(); 
 | 
                    that.setButtonStates(); 
 | 
                } 
 | 
            }); 
 | 
  
 | 
            that.$sortModal.off('click', '#delete').on('click', '#delete', function() { 
 | 
                var total = that.$sortModal.find('.multi-sort-name:first option').length, 
 | 
                    current = that.$sortModal.find('tbody tr').length; 
 | 
  
 | 
                if (current > 1 && current <= total) { 
 | 
                    current--; 
 | 
                    that.$sortModal.find('tbody tr:last').remove(); 
 | 
                    that.setButtonStates(); 
 | 
                } 
 | 
            }); 
 | 
  
 | 
            that.$sortModal.off('click', '.btn-primary').on('click', '.btn-primary', function() { 
 | 
                var $rows = that.$sortModal.find("tbody > tr"), 
 | 
                    $alert = that.$sortModal.find('div.alert'), 
 | 
                    fields = [], 
 | 
                    results = []; 
 | 
  
 | 
  
 | 
                that.options.sortPriority = $.map($rows, function(row) { 
 | 
                    var $row = $(row), 
 | 
                        name = $row.find('.multi-sort-name').val(), 
 | 
                        order = $row.find('.multi-sort-order').val(); 
 | 
  
 | 
                    fields.push(name); 
 | 
  
 | 
                    return { 
 | 
                        sortName: name, 
 | 
                        sortOrder: order 
 | 
                    }; 
 | 
                }); 
 | 
  
 | 
                var sorted_fields = fields.sort(); 
 | 
  
 | 
                for (var i = 0; i < fields.length - 1; i++) { 
 | 
                    if (sorted_fields[i + 1] == sorted_fields[i]) { 
 | 
                        results.push(sorted_fields[i]); 
 | 
                    } 
 | 
                } 
 | 
  
 | 
                if (results.length > 0) { 
 | 
                    if ($alert.length === 0) { 
 | 
                        $alert = '<div class="alert alert-danger" role="alert"><strong>' + that.options.formatDuplicateAlertTitle() + '</strong> ' + that.options.formatDuplicateAlertDescription() + '</div>'; 
 | 
                        $($alert).insertBefore(that.$sortModal.find('.bars')); 
 | 
                    } 
 | 
                } else { 
 | 
                    if ($alert.length === 1) { 
 | 
                        $($alert).remove(); 
 | 
                    } 
 | 
  
 | 
                    that.options.sortName = ""; 
 | 
                    that.onMultipleSort(); 
 | 
                    that.$sortModal.modal('hide'); 
 | 
                } 
 | 
            }); 
 | 
  
 | 
            if (that.options.sortPriority === null || that.options.sortPriority.length === 0) { 
 | 
                if (that.options.sortName) { 
 | 
                    that.options.sortPriority = [{ 
 | 
                        sortName: that.options.sortName, 
 | 
                        sortOrder: that.options.sortOrder 
 | 
                    }]; 
 | 
                } 
 | 
            } 
 | 
  
 | 
            if (that.options.sortPriority !== null && that.options.sortPriority.length > 0) { 
 | 
                if ($rows.length < that.options.sortPriority.length && typeof that.options.sortPriority === 'object') { 
 | 
                    for (var i = 0; i < that.options.sortPriority.length; i++) { 
 | 
                        that.addLevel(i, that.options.sortPriority[i]); 
 | 
                    } 
 | 
                } 
 | 
            } else { 
 | 
                that.addLevel(0); 
 | 
            } 
 | 
  
 | 
            that.setButtonStates(); 
 | 
        } 
 | 
    }; 
 | 
  
 | 
    $.extend($.fn.bootstrapTable.defaults, { 
 | 
        showMultiSort: false, 
 | 
        sortPriority: null, 
 | 
        onMultipleSort: function() { 
 | 
            return false; 
 | 
        } 
 | 
    }); 
 | 
  
 | 
    $.extend($.fn.bootstrapTable.defaults.icons, { 
 | 
        sort: 'glyphicon-sort', 
 | 
        plus: 'glyphicon-plus', 
 | 
        minus: 'glyphicon-minus' 
 | 
    }); 
 | 
  
 | 
    $.extend($.fn.bootstrapTable.Constructor.EVENTS, { 
 | 
        'multiple-sort.bs.table': 'onMultipleSort' 
 | 
    }); 
 | 
  
 | 
    $.extend($.fn.bootstrapTable.locales, { 
 | 
        formatMultipleSort: function() { 
 | 
            return 'Multiple Sort'; 
 | 
        }, 
 | 
        formatAddLevel: function() { 
 | 
            return "Add Level"; 
 | 
        }, 
 | 
        formatDeleteLevel: function() { 
 | 
            return "Delete Level"; 
 | 
        }, 
 | 
        formatColumn: function() { 
 | 
            return "Column"; 
 | 
        }, 
 | 
        formatOrder: function() { 
 | 
            return "Order"; 
 | 
        }, 
 | 
        formatSortBy: function() { 
 | 
            return "Sort by"; 
 | 
        }, 
 | 
        formatThenBy: function() { 
 | 
            return "Then by"; 
 | 
        }, 
 | 
        formatSort: function() { 
 | 
            return "Sort"; 
 | 
        }, 
 | 
        formatCancel: function() { 
 | 
            return "Cancel"; 
 | 
        }, 
 | 
        formatDuplicateAlertTitle: function() { 
 | 
            return "Duplicate(s) detected!"; 
 | 
        }, 
 | 
        formatDuplicateAlertDescription: function() { 
 | 
            return "Please remove or change any duplicate column."; 
 | 
        } 
 | 
    }); 
 | 
  
 | 
    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales); 
 | 
  
 | 
    var BootstrapTable = $.fn.bootstrapTable.Constructor, 
 | 
        _initToolbar = BootstrapTable.prototype.initToolbar; 
 | 
  
 | 
    BootstrapTable.prototype.initToolbar = function() { 
 | 
        this.showToolbar = true; 
 | 
        var that = this, 
 | 
            sortModalId = '#sortModal_' + this.$el.attr('id'); 
 | 
        this.$sortModal = $(sortModalId); 
 | 
  
 | 
        _initToolbar.apply(this, Array.prototype.slice.apply(arguments)); 
 | 
  
 | 
        if (this.options.showMultiSort) { 
 | 
            var $btnGroup = this.$toolbar.find('>.btn-group').first(), 
 | 
                $multiSortBtn = this.$toolbar.find('div.multi-sort'); 
 | 
  
 | 
            if (!$multiSortBtn.length) { 
 | 
                $multiSortBtn = '  <button class="multi-sort btn btn-default' + (this.options.iconSize === undefined ? '' : ' btn-' + this.options.iconSize) + '" type="button" data-toggle="modal" data-target="' + sortModalId + '" title="' + this.options.formatMultipleSort() + '">'; 
 | 
                $multiSortBtn += '     <i class="' + this.options.iconsPrefix + ' ' + this.options.icons.sort + '"></i>'; 
 | 
                $multiSortBtn += '</button>'; 
 | 
  
 | 
                $btnGroup.append($multiSortBtn); 
 | 
  
 | 
                showSortModal(that); 
 | 
            } 
 | 
  
 | 
            this.$el.on('sort.bs.table', function() { 
 | 
                isSingleSort = true; 
 | 
            }); 
 | 
  
 | 
            this.$el.on('multiple-sort.bs.table', function() { 
 | 
                isSingleSort = false; 
 | 
            }); 
 | 
  
 | 
            this.$el.on('load-success.bs.table', function() { 
 | 
                if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object') { 
 | 
                    that.onMultipleSort(); 
 | 
                } 
 | 
            }); 
 | 
  
 | 
            this.$el.on('column-switch.bs.table', function(field, checked) { 
 | 
                for (var i = 0; i < that.options.sortPriority.length; i++) { 
 | 
                    if (that.options.sortPriority[i].sortName === checked) { 
 | 
                        that.options.sortPriority.splice(i, 1); 
 | 
                    } 
 | 
                } 
 | 
  
 | 
                that.assignSortableArrows(); 
 | 
                that.$sortModal.remove(); 
 | 
                showSortModal(that); 
 | 
            }); 
 | 
  
 | 
            this.$el.on('reset-view.bs.table', function() { 
 | 
                if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object') { 
 | 
                    that.assignSortableArrows(); 
 | 
                } 
 | 
            }); 
 | 
        } 
 | 
    }; 
 | 
  
 | 
    BootstrapTable.prototype.onMultipleSort = function() { 
 | 
        var that = this; 
 | 
  
 | 
        var cmp = function(x, y) { 
 | 
            return x > y ? 1 : x < y ? -1 : 0; 
 | 
        }; 
 | 
  
 | 
        var arrayCmp = function(a, b) { 
 | 
            var arr1 = [], 
 | 
                arr2 = []; 
 | 
  
 | 
            for (var i = 0; i < that.options.sortPriority.length; i++) { 
 | 
                var order = that.options.sortPriority[i].sortOrder === 'desc' ? -1 : 1, 
 | 
                    aa = a[that.options.sortPriority[i].sortName], 
 | 
                    bb = b[that.options.sortPriority[i].sortName]; 
 | 
  
 | 
                if (aa === undefined || aa === null) { 
 | 
                    aa = ''; 
 | 
                } 
 | 
                if (bb === undefined || bb === null) { 
 | 
                    bb = ''; 
 | 
                } 
 | 
                if ($.isNumeric(aa) && $.isNumeric(bb)) { 
 | 
                    aa = parseFloat(aa); 
 | 
                    bb = parseFloat(bb); 
 | 
                } 
 | 
                if (typeof aa !== 'string') { 
 | 
                    aa = aa.toString(); 
 | 
                } 
 | 
  
 | 
                arr1.push( 
 | 
                    order * cmp(aa, bb)); 
 | 
                arr2.push( 
 | 
                    order * cmp(bb, aa)); 
 | 
            } 
 | 
  
 | 
            return cmp(arr1, arr2); 
 | 
        }; 
 | 
  
 | 
        this.data.sort(function(a, b) { 
 | 
            return arrayCmp(a, b); 
 | 
        }); 
 | 
  
 | 
        this.initBody(); 
 | 
        this.assignSortableArrows(); 
 | 
        this.trigger('multiple-sort'); 
 | 
    }; 
 | 
  
 | 
    BootstrapTable.prototype.addLevel = function(index, sortPriority) { 
 | 
        var text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy(); 
 | 
  
 | 
        this.$sortModal.find('tbody') 
 | 
            .append($('<tr>') 
 | 
                .append($('<td>').text(text)) 
 | 
                .append($('<td>').append($('<select class="form-control multi-sort-name">'))) 
 | 
                .append($('<td>').append($('<select class="form-control multi-sort-order">'))) 
 | 
        ); 
 | 
  
 | 
        var $multiSortName = this.$sortModal.find('.multi-sort-name').last(), 
 | 
            $multiSortOrder = this.$sortModal.find('.multi-sort-order').last(); 
 | 
  
 | 
        $.each(this.columns, function (i, column) { 
 | 
            if (column.sortable === false || column.visible === false) { 
 | 
                return true; 
 | 
            } 
 | 
            $multiSortName.append('<option value="' + column.field + '">' + column.title + '</option>'); 
 | 
        }); 
 | 
  
 | 
        $.each(sort_order, function(value, order) { 
 | 
            $multiSortOrder.append('<option value="' + value + '">' + order + '</option>'); 
 | 
        }); 
 | 
  
 | 
        if (sortPriority !== undefined) { 
 | 
            $multiSortName.find('option[value="' + sortPriority.sortName + '"]').attr("selected", true); 
 | 
            $multiSortOrder.find('option[value="' + sortPriority.sortOrder + '"]').attr("selected", true); 
 | 
        } 
 | 
    }; 
 | 
  
 | 
    BootstrapTable.prototype.assignSortableArrows = function() { 
 | 
        var that = this, 
 | 
            headers = that.$header.find('th'); 
 | 
  
 | 
        for (var i = 0; i < headers.length; i++) { 
 | 
            for (var c = 0; c < that.options.sortPriority.length; c++) { 
 | 
                if ($(headers[i]).data('field') === that.options.sortPriority[c].sortName) { 
 | 
                    $(headers[i]).find('.sortable').removeClass('desc asc').addClass(that.options.sortPriority[c].sortOrder); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
    }; 
 | 
  
 | 
    BootstrapTable.prototype.setButtonStates = function() { 
 | 
        var total = this.$sortModal.find('.multi-sort-name:first option').length, 
 | 
            current = this.$sortModal.find('tbody tr').length; 
 | 
  
 | 
        if (current == total) { 
 | 
            this.$sortModal.find('#add').attr('disabled', 'disabled'); 
 | 
        } 
 | 
        if (current > 1) { 
 | 
            this.$sortModal.find('#delete').removeAttr('disabled'); 
 | 
        } 
 | 
        if (current < total) { 
 | 
            this.$sortModal.find('#add').removeAttr('disabled'); 
 | 
        } 
 | 
        if (current == 1) { 
 | 
            this.$sortModal.find('#delete').attr('disabled', 'disabled'); 
 | 
        } 
 | 
    }; 
 | 
})(jQuery); 
 |