Browse Source

Bootstrap Table Multiple Sort

Initial release of Bootstrap Table Multiple Sort.
dimbslmh 10 years ago
parent
commit
0349210531
1 changed files with 367 additions and 0 deletions
  1. 367 0
      src/extensions/multiple-sort/bootstrap-table-multiple-sort.js

+ 367 - 0
src/extensions/multiple-sort/bootstrap-table-multiple-sort.js

@@ -0,0 +1,367 @@
+/**
+ * @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'
+        },
+        arrowAsc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ' +
+        '0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBd' +
+        'qEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVo' +
+        'AADeemwtPcZI2wAAAABJRU5ErkJggg==',
+        arrowDesc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWj' +
+        'YBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJ' +
+        'zcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ';
+
+    var cmp = function(x, y) {
+        return x > y ? 1 : x < y ? -1 : 0;
+    };
+
+    var showSortModal = function(that) {
+        if (!$("#sortModal").hasClass("modal")) {
+            var sModal = '  <div class="modal fade" id="sortModal" tabindex="-1" role="dialog" aria-labelledby="sortModalLabel" 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">&times;</span></button>';
+            sModal += '                     <h4 class="modal-title" id="sortModalLabel">' + 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));
+
+            var $sortModal = $('#sortModal'),
+                $rows = $sortModal.find("tbody > tr");
+
+            $sortModal.off('click', '#add').on('click', '#add', function() {
+                var total = $sortModal.find('.multi-sort-name:first option').length,
+                    current = $sortModal.find('tbody tr').length;
+
+                if (current < total) {
+                    current++;
+                    that.addLevel();
+                    that.setButtonStates();
+                }
+            });
+
+            $sortModal.off('click', '#delete').on('click', '#delete', function() {
+                var total = $sortModal.find('.multi-sort-name:first option').length,
+                    current = $sortModal.find('tbody tr').length;
+
+                if (current > 1 && current <= total) {
+                    current--;
+                    $sortModal.find('tbody tr:last').remove();
+                    that.setButtonStates();
+                }
+            });
+
+            $sortModal.off('click', '.btn-primary').on('click', '.btn-primary', function() {
+                var $rows = $sortModal.find("tbody > tr"),
+                    $alert = $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($sortModal.find('.bars'));
+                    }
+                } else {
+                    if ($alert.length === 1) {
+                        $($alert).remove();
+                    }
+
+                    that.onMultipleSort();
+                    $sortModal.modal('hide');
+                }
+            });
+
+            if (that.options.sortPriority === null) {
+                if (that.options.sortName) {
+                    that.options.sortPriority = [{
+                        sortName: that.options.sortName,
+                        sortOrder: that.options.sortOrder
+                    }];
+                } else {
+                    that.addLevel(0);
+                }
+            } else 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;
+
+        _initToolbar.apply(this, Array.prototype.slice.apply(arguments));
+
+        if (this.options.showMultiSort) {
+            var $btnGroup = this.$toolbar.find('>.btn-group'),
+                $multiSortBtn = $btnGroup.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="#sortModal" title="' + this.options.formatMultipleSort() + '">';
+                $multiSortBtn += '     <i class="' + this.options.iconsPrefix + ' ' + this.options.icons.sort + '"></i>';
+                $multiSortBtn += '</button>';
+
+                $btnGroup.append($multiSortBtn);
+
+                showSortModal(that);
+            }
+
+            this.$el.one('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() {
+                that.options.sortPriority = null;
+                $('#sortModal').remove();
+                showSortModal(that);
+            });
+        }
+    };
+
+    BootstrapTable.prototype.onMultipleSort = function() {
+        var that = this;
+
+        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 $sortModal = $("#sortModal"),
+            text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy();
+
+        $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 = $sortModal.find('.multi-sort-name').last(),
+            $multiSortOrder = $sortModal.find('.multi-sort-order').last();
+
+        this.options.columns.forEach(function(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').css('background-image', 'url(' + (that.options.sortPriority[c].sortOrder === 'desc' ? arrowDesc : arrowAsc) + ')');
+                }
+            }
+        }
+    };
+
+    BootstrapTable.prototype.setButtonStates = function() {
+        var $sortModal = $('#sortModal'),
+            total = $sortModal.find('.multi-sort-name:first option').length,
+            current = $sortModal.find('tbody tr').length;
+
+        if (current == total) {
+            $sortModal.find('#add').attr('disabled', 'disabled');
+        }
+        if (current > 1) {
+            $sortModal.find('#delete').removeAttr('disabled');
+        }
+        if (current < total) {
+            $sortModal.find('#add').removeAttr('disabled');
+        }
+        if (current == 1) {
+            $sortModal.find('#delete').attr('disabled', 'disabled');
+        }
+    };
+})(jQuery);