From 03492105310a63d64377f649ac395c998cef949c Mon Sep 17 00:00:00 2001 From: dimbslmh Date: Mon, 25 May 2015 19:55:23 +0700 Subject: [PATCH 1/4] Bootstrap Table Multiple Sort Initial release of Bootstrap Table Multiple Sort. --- .../bootstrap-table-multiple-sort.js | 367 ++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 src/extensions/multiple-sort/bootstrap-table-multiple-sort.js diff --git a/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js b/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js new file mode 100644 index 0000000000..e5b447eaf2 --- /dev/null +++ b/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js @@ -0,0 +1,367 @@ +/** + * @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 cmp = function(x, y) { + return x > y ? 1 : x < y ? -1 : 0; + }; + + 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 + }]; + } 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 = ' '; + + $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($('') + .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); From b467eba7cfd1d049460e44955ba756b067afe5c1 Mon Sep 17 00:00:00 2001 From: dimbslmh Date: Mon, 25 May 2015 20:20:28 +0700 Subject: [PATCH 2/4] Bootstrap Table Multiple Sort extension README.md Initial release of README for Bootstrap Table Multiple Sort extension. --- src/extensions/multiple-sort/README.md | 91 ++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/extensions/multiple-sort/README.md diff --git a/src/extensions/multiple-sort/README.md b/src/extensions/multiple-sort/README.md new file mode 100644 index 0000000000..fc51b21d7d --- /dev/null +++ b/src/extensions/multiple-sort/README.md @@ -0,0 +1,91 @@ +# Table Multiple Sort + +Use Plugin: [bootstrap-table-multiple-sort](https://github.com/dimbslmh/bootstrap-table/tree/master/src/extensions/multiple-sort) + +## Usage + +```html + +``` + +## Options + +### showMultiSort + +* type: Boolean +* description: Set true to allow the multiple sort. +* default: `false` + +### sortPriority + +* type: Object +* description: Set one or multiple sort priority. Example: '[{"sortName": "forks_count","sortOrder":"desc"},{"sortName":"stargazers_count","sortOrder":"desc"}]' +* default: null + +### Icons +* sort: `glyphicon-sort` +* plus: `glyphicon-plus` +* minus: `glyphicon-minus` + +## Locales + +### formatMultipleSort + +* description: Title of the advanced search modal +* default: `Multiple Sort` + +### formatAddLevel + +* description: Text of the add level button +* default: `Add Level` + +### formatDeleteLevel + +* description: Text of the delete level button +* default: `Delete Level` + +### formatColumn + +* description: Text of Column header +* default: `Column` + +### formatOrder + +* description: Text of the delete level button +* default: `Order` + +### formatSortBy + +* description: Text of the delete level button +* default: `Sort by` + +### formatThenBy + +* description: Text of the delete level button +* default: `Then by` + +### formatSort + +* description: Text of the delete level button +* default: `Sort` + +### formatCancel + +* description: Text of the delete level button +* default: `Cancel` + +### formatDuplicateAlertTitle + +* description: Title of the duplicate alert +* default: `Duplicate(s) detected!` + +### formatDuplicateAlertDescription + +* description: Text of the duplicate alert +* default: `Please remove or change any duplicate column.` + +## Events + +### onMultipleSort(multiple-sort.bs.table) + +* Fires when sorting with one or multiple Sort Priority. From 1eda790db641f2783e101d8c92deaf74d0349bb0 Mon Sep 17 00:00:00 2001 From: dimbslmh Date: Mon, 25 May 2015 21:22:02 +0700 Subject: [PATCH 3/4] Fix condition to add levels in showSortModal Fix condition for initial adding of rows inside showSortModal. --- .../multiple-sort/bootstrap-table-multiple-sort.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js b/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js index e5b447eaf2..6b5ce3a571 100644 --- a/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js +++ b/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js @@ -21,10 +21,6 @@ '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 = '