/** * @author Nadim Basalamah * @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 = ' '; $("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 = ''; $($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 = ' '; $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($('') .append($('').text(text)) .append($('').append($(''))) ); 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(''); }); $.each(sort_order, function(value, order) { $multiSortOrder.append(''); }); 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);