/** * @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' }, 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 showSortModal = function(that) { if (!$("#sortModal").hasClass("modal")) { var sModal = ' '; $("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 = ''; $($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 }]; } } 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 = ' '; $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 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 $sortModal = $("#sortModal"), text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy(); $sortModal.find('tbody') .append($('') .append($('').text(text)) .append($('').append($(''))) ); 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(''); }); $.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').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);