ソースを参照

Merge pull request #993 from djhvscf/master

Improve filter-control, cookie, multiple-sort and flat-json extensions
文翼 10 年 前
コミット
9b0443f323

+ 22 - 4
src/extensions/cookie/README.md

@@ -10,20 +10,38 @@ Use Plugin: [bootstrap-table-cookie](https://github.com/wenzhixin/bootstrap-tabl
 
 ## Options
 
-### stateSave
+### cookie
 
 * type: Boolean
 * description: Set true to save the state of a table (its paging position, ordering state, records per page).
 * default: `false`
 
-### stateSaveExpire
+### cookieExpire
 
 * type: String
-* description: You must set this property if stateSave is enable to know when will expire the cookie created. Must use this format: 'number{letter}' like '2h', in the letter position
+* description: You must set this property if cookie option is enable to know when will expire the cookie created. Must use this format: 'number{letter}' like '2h', in the letter position
                		you can use: 's','mi','h','d','m','y', these means: 'seconds', 'minutes', 'hours', 'days', 'months', 'years'.
 * default: `2h`
 
-### stateSaveIdTable
+### cookiePath
+
+* type: String
+* description: you can tell the browser what path the cookie belongs to. By default, the cookie belongs to the current page.
+* default: `null`
+
+### cookieDomain
+
+* type: String
+* description: This is the website domain, with the www. prefix removed.
+* default: `null`
+
+### cookieSecure
+
+* type: Boolean
+* description: This property keep cookie communication limited to encrypted transmission, directing browsers to use cookies only via secure/encrypted connections.
+* default: `null`
+
+### cookieIdTable
 
 * type: String
 * description: You must set this property if stateSave is enable to sets an unique cookie with an identifier for each table in your page or project. You must set this property because we need create cookies with an identifier.

+ 62 - 73
src/extensions/cookie/bootstrap-table-cookie.js

@@ -1,7 +1,7 @@
 /**
  * @author: Dennis Hernández
  * @webSite: http://djhvscf.github.io/Blog
- * @version: v1.1.0
+ * @version: v1.2.0
  *
  * @update zhixin wen <wenzhixin2010@gmail.com>
  */
@@ -9,7 +9,7 @@
 (function ($) {
     'use strict';
 
-    var idsStateSaveList = {
+    var cookieIds = {
         sortOrder: 'bs.table.sortOrder',
         sortName: 'bs.table.sortName',
         pageNumber: 'bs.table.pageNumber',
@@ -22,20 +22,17 @@
         return (navigator.cookieEnabled) ? true : false;
     };
 
-    var setCookie = function (that, cookieName, sValue, sPath, sDomain, bSecure) {
-        if ((!that.options.stateSave) || (!cookieEnabled()) || (that.options.stateSaveIdTable === '')) {
+    var setCookie = function (that, cookieName, sValue) {
+        if ((!that.options.stateSave) || (!cookieEnabled()) || (that.options.cookieIdTable === '')) {
             return;
         }
 
-        var tableName = that.options.stateSaveIdTable,
-            vEnd = that.options.stateSaveExpire;
-
-        cookieName = tableName + '.' + cookieName;
+        cookieName = that.options.cookieIdTable + '.' + cookieName;
         if (!cookieName || /^(?:expires|max\-age|path|domain|secure)$/i.test(cookieName)) {
             return false;
         }
 
-        document.cookie = encodeURIComponent(cookieName) + '=' + encodeURIComponent(sValue) + calculateExpiration(vEnd) + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '') + (bSecure ? '; secure' : '');
+        document.cookie = encodeURIComponent(cookieName) + '=' + encodeURIComponent(sValue) + calculateExpiration(that.options.cookieExpire) + (that.options.cookieDomain ? '; domain=' + that.options.cookieDomain : '') + (that.options.cookiePath ? '; path=' + that.options.cookiePath : '') + (that.cookieSecure ? '; secure' : '');
         return true;
     };
 
@@ -63,41 +60,44 @@
         return true;
     };
 
-    var calculateExpiration = function(vEnd) {
-        var time = vEnd.replace(/[0-9]/, ''); //s,mi,h,d,m,y
-        vEnd = vEnd.replace(/[A-Za-z]/, ''); //number
+    var calculateExpiration = function(cookieExpire) {
+        var time = cookieExpire.replace(/[0-9]/, ''); //s,mi,h,d,m,y
+        cookieExpire = cookieExpire.replace(/[A-Za-z]/, ''); //number
 
         switch (time.toLowerCase()) {
             case 's':
-                vEnd = +vEnd;
+                cookieExpire = +cookieExpire;
                 break;
             case 'mi':
-                vEnd = vEnd * 60;
+                cookieExpire = cookieExpire * 60;
                 break;
             case 'h':
-                vEnd = vEnd * 60 * 60;
+                cookieExpire = cookieExpire * 60 * 60;
                 break;
             case 'd':
-                vEnd = vEnd * 24 * 60 * 60;
+                cookieExpire = cookieExpire * 24 * 60 * 60;
                 break;
             case 'm':
-                vEnd = vEnd * 30 * 24 * 60 * 60;
+                cookieExpire = cookieExpire * 30 * 24 * 60 * 60;
                 break;
             case 'y':
-                vEnd = vEnd * 365 * 30 * 24 * 60 * 60;
+                cookieExpire = cookieExpire * 365 * 30 * 24 * 60 * 60;
                 break;
             default:
-                vEnd = undefined;
+                cookieExpire = undefined;
                 break;
         }
 
-        return vEnd === undefined ? '' : '; max-age=' + vEnd;
-    }
+        return cookieExpire === undefined ? '' : '; max-age=' + cookieExpire;
+    };
 
     $.extend($.fn.bootstrapTable.defaults, {
-        stateSave: false,
-        stateSaveExpire: '2h',
-        stateSaveIdTable: ''
+        cookie: false,
+        cookieExpire: '2h',
+        cookiePath: null,
+        cookieDomain: null,
+        cookieSecure: null,
+        cookieIdTable: ''
     });
 
     $.fn.bootstrapTable.methods.push('deleteCookie');
@@ -117,11 +117,11 @@
     // init save data after initTable function
     BootstrapTable.prototype.initTable = function () {
         _initTable.apply(this, Array.prototype.slice.apply(arguments));
-        this.initStateSave();
+        this.initCookie();
     };
 
-    BootstrapTable.prototype.initStateSave = function () {
-        if (!this.options.stateSave) {
+    BootstrapTable.prototype.initCookie = function () {
+        if (!this.options.cookie) {
             return;
         }
 
@@ -129,79 +129,69 @@
             return;
         }
 
-        if (this.options.stateSaveIdTable === '') {
+        if (this.options.cookieIdTable === '' || this.options.cookieExpire === '') {
             return;
         }
 
-        var sortOrderStateSave = getCookie(this.options.stateSaveIdTable, idsStateSaveList.sortOrder),
-            sortOrderStateName = getCookie(this.options.stateSaveIdTable, idsStateSaveList.sortName),
-            pageNumberStateSave = getCookie(this.options.stateSaveIdTable, idsStateSaveList.pageNumber),
-            pageListStateSave = getCookie(this.options.stateSaveIdTable, idsStateSaveList.pageList),
-            columnsStateSave = JSON.parse(getCookie(this.options.stateSaveIdTable, idsStateSaveList.columns)),
-            searchStateSave = getCookie(this.options.stateSaveIdTable, idsStateSaveList.searchText);
-
-        if (sortOrderStateSave) {
-            this.options.sortOrder = sortOrderStateSave;
-            this.options.sortName = sortOrderStateName;
-        }
-
-        if (pageNumberStateSave) {
-            this.options.pageNumber = +pageNumberStateSave;
-        }
-
-        if (pageListStateSave) {
-            this.options.pageSize = pageListStateSave ===
-                this.options.formatAllRows() ? pageListStateSave : +pageListStateSave;
-        }
-
-        if (columnsStateSave) {
+        var sortOrderCookie = getCookie(this.options.cookieIdTable, cookieIds.sortOrder),
+            sortOrderNameCookie = getCookie(this.options.cookieIdTable, cookieIds.sortName),
+            pageNumberCookie = getCookie(this.options.cookieIdTable, cookieIds.pageNumber),
+            pageListCookie = getCookie(this.options.cookieIdTable, cookieIds.pageList),
+            columnsCookie = JSON.parse(getCookie(this.options.cookieIdTable, cookieIds.columns)),
+            searchTextCookie = getCookie(this.options.cookieIdTable, cookieIds.searchText);
+
+        //sortOrder
+        this.options.sortOrder = sortOrderCookie ? sortOrderCookie : 'asc';
+        //sortName
+        this.options.sortName = sortOrderNameCookie ? sortOrderNameCookie : undefined;
+        //pageNumber
+        this.options.pageNumber = pageNumberCookie ? +pageNumberCookie : 1;
+        //pageSize
+        this.options.pageSize = pageListCookie ? pageListCookie === this.options.formatAllRows() ? pageListCookie : +pageListCookie : 10;
+        //searchText
+        this.options.searchText = searchTextCookie ? searchTextCookie : '';
+
+        if (columnsCookie) {
             $.each(this.options.columns, function (i, column) {
-                column.visible = columnsStateSave.indexOf(column.field) !== -1;
+                column.visible = columnsCookie.indexOf(column.field) !== -1;
             });
         }
-
-        if (searchStateSave) {
-            this.options.searchText = searchStateSave;
-        }
     };
 
     BootstrapTable.prototype.onSort = function () {
         _onSort.apply(this, Array.prototype.slice.apply(arguments));
-
-        setCookie(this, idsStateSaveList.sortOrder, this.options.sortOrder);
-        setCookie(this, idsStateSaveList.sortName, this.options.sortName);
+        setCookie(this, cookieIds.sortOrder, this.options.sortOrder);
+        setCookie(this, cookieIds.sortName, this.options.sortName);
     };
 
     BootstrapTable.prototype.onPageNumber = function () {
         _onPageNumber.apply(this, Array.prototype.slice.apply(arguments));
-
-        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+        setCookie(this, cookieIds.pageNumber, this.options.pageNumber);
     };
 
     BootstrapTable.prototype.onPageListChange = function () {
         _onPageListChange.apply(this, Array.prototype.slice.apply(arguments));
-
-        setCookie(this, idsStateSaveList.pageList, this.options.pageSize);
+        setCookie(this, cookieIds.pageList, this.options.pageSize);
     };
 
     BootstrapTable.prototype.onPageFirst = function () {
         _onPageFirst.apply(this, Array.prototype.slice.apply(arguments));
-        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+        setCookie(this, cookieIds.pageNumber, this.options.pageNumber);
     };
 
     BootstrapTable.prototype.onPagePre = function () {
         _onPagePre.apply(this, Array.prototype.slice.apply(arguments));
-        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+        setCookie(this, cookieIds.pageNumber, this.options.pageNumber);
     };
 
     BootstrapTable.prototype.onPageNext = function () {
         _onPageNext.apply(this, Array.prototype.slice.apply(arguments));
-        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+        setCookie(this, cookieIds.pageNumber, this.options.pageNumber);
     };
 
     BootstrapTable.prototype.onPageLast = function () {
         _onPageLast.apply(this, Array.prototype.slice.apply(arguments));
-        setCookie(this, idsStateSaveList.pageNumber, this.options.pageNumber);
+        setCookie(this, cookieIds.pageNumber, this.options.pageNumber);
     };
 
     BootstrapTable.prototype.toggleColumn = function () {
@@ -209,19 +199,18 @@
 
         var visibleColumns = [];
 
-        $.each(this.options.columns, function (i) {
-            if (this.visible) {
-                visibleColumns.push(this.field);
+        $.each(this.options.columns, function (i, column) {
+            if (column.visible) {
+                visibleColumns.push(column.field);
             }
         });
 
-        setCookie(this, idsStateSaveList.columns, JSON.stringify(visibleColumns));
+        setCookie(this, cookieIds.columns, JSON.stringify(visibleColumns));
     };
 
     BootstrapTable.prototype.onSearch = function () {
         _onSearch.apply(this, Array.prototype.slice.apply(arguments));
-
-        setCookie(this, idsStateSaveList.searchText, this.searchText);
+        setCookie(this, cookieIds.searchText, this.searchText);
     };
 
     BootstrapTable.prototype.deleteCookie = function (cookieName) {
@@ -229,6 +218,6 @@
             return;
         }
 
-        deleteCookie(idsStateSaveList[cookieName]);
+        deleteCookie(cookieIds[cookieName], this.options.cookiePath, this.options.cookieDomain);
     };
 })(jQuery);

+ 34 - 22
src/extensions/filter-control/bootstrap-table-filter-control.js

@@ -61,15 +61,16 @@
         return defaultValue;
     };
 
-    var addValueToSelectControl = function (selectControl, value, text) {
-        if (existsValueInSelectControl(selectControl, value)) {
+    var addOptionToSelectControl = function (selectControl, value, text) {
+        //selectControl = $(selectControl.get(0));
+        if (existsOptionInSelectControl(selectControl, value)) {
             selectControl.append($("<option></option>")
                 .attr("value", value)
                 .text(text));
         }
     };
 
-    var existsValueInSelectControl = function (selectControl, value) {
+    var existsOptionInSelectControl = function (selectControl, value) {
         var options = selectControl.get(0).options,
             iOpt = 0;
 
@@ -91,13 +92,26 @@
     var copyValues = function (that) {
         that.options.values = [];
         that.$tableHeader.find('table select, table input').each(function () {
-            that.options.values.push($(this).val());
+            that.options.values.push(
+                {
+                    field: $(this).parent().parent().parent().data('field'),
+                    value: $(this).val()
+                });
         });
     };
 
     var setValues = function(that) {
+        var field = null;
         that.$tableHeader.find('table select, table input').each(function (index, ele) {
-            $(this).val(that.options.values[index]);
+            if (that.options.values.length > 0) {
+                field = $(this).parent().parent().parent().data('field');
+                for (var i = 0; i < that.options.values.length; i++) {
+                    if (field === that.options.values[i].field) {
+                        $(this).val(that.options.values[i].value);
+                        break;
+                    }
+                }
+            }
         });
     };
 
@@ -150,7 +164,7 @@
                 var filterDataType = column.filterData.substring(0, 3);
                 var filterDataSource = column.filterData.substring(4, column.filterData.length);
                 var selectControl = $('.' + column.field);
-                addValueToSelectControl(selectControl, '', '');
+                addOptionToSelectControl(selectControl, '', '');
 
                 switch (filterDataType) {
                     case 'url':
@@ -159,7 +173,7 @@
                             dataType: 'json',
                             success: function (data) {
                                 $.each(data, function (key, value) {
-                                    addValueToSelectControl(selectControl, key, value);
+                                    addOptionToSelectControl(selectControl, key, value);
                                 });
                             }
                         });
@@ -167,7 +181,7 @@
                     case 'var':
                         var variableValues = window[filterDataSource];
                         for (var key in variableValues) {
-                            addValueToSelectControl(selectControl, key, variableValues[key]);
+                            addOptionToSelectControl(selectControl, key, variableValues[key]);
                         }
                         break;
                 }
@@ -189,14 +203,10 @@
                 }, that.options.searchTimeOut);
             });
 
-            var datepickers = that.$header.find('.date-filter-control');
+            var datepickers = header.find('.date-filter-control');
             if (datepickers.length > 0) {
                 $.each(that.options.columns, function (i, column) {
                     if (column.filterControl !== undefined && column.filterControl.toLowerCase() === 'datepicker') {
-                        column.filterDatepickerOptions = $.extend(column.filterDatepickerOptions, {
-                            calendarWeeks: true
-                        });
-
                         header.find('.date-filter-control.' + column.field).datepicker(column.filterDatepickerOptions)
                             .on('changeDate', function (e) {
                                 //Fired the keyup event
@@ -215,7 +225,8 @@
         onColumnSearch: function (field, text) {
             return false;
         },
-        values: [] //internal variables
+        //internal variables
+        values: []
     });
 
     $.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
@@ -238,8 +249,10 @@
         //Make sure that the filtercontrol option is set
         if (this.options.filterControl) {
             var that = this;
-            this.$el.on('reset-view.bs.table', function () {
+            //Make sure that the internal variables are set correctly
+            this.options.values = [];
 
+            this.$el.on('reset-view.bs.table', function () {
                 //Create controls on $tableHeader if the height is set
                 if (!that.options.height) {
                     return;
@@ -253,9 +266,7 @@
                 createControls(that, that.$tableHeader);
             }).on('post-header.bs.table', function () {
                 setValues(that);
-            });
-
-            this.$el.on('post-body.bs.table', function () {
+            }).on('post-body.bs.table', function () {
                 if (that.options.height) {
                     fixHeaderCSS(that);
                 }
@@ -277,9 +288,10 @@
         _initBody.apply(this, Array.prototype.slice.apply(arguments));
 
         var that = this,
-            data = this.getData();
+            data = this.options.data,
+            pageTo = this.pageTo < this.options.data.length ? this.options.data.length : this.pageTo;
 
-        for (var i = this.pageFrom - 1; i < this.pageTo; i++) {
+        for (var i = this.pageFrom - 1; i < pageTo; i++) {
             var key,
                 item = data[i];
 
@@ -299,11 +311,11 @@
                             if (selectControl !== undefined && selectControl.length > 0) {
                                 if (selectControl.get(0).options.length === 0) {
                                     //Added the default option
-                                    addValueToSelectControl(selectControl, '', '');
+                                    addOptionToSelectControl(selectControl, '', '');
                                 }
 
                                 //Added a new value
-                                addValueToSelectControl(selectControl, value, value);
+                                addOptionToSelectControl(selectControl, value, value);
                             }
                         }
                     }

+ 6 - 0
src/extensions/flat-json/README.md

@@ -15,3 +15,9 @@ Use Plugin: [bootstrap-table-flat-json](https://github.com/djhvscf/bootstrap-tab
 * type: Boolean
 * description: Set true to flat the JSON object.
 * default: `false`
+
+### flatSeparator
+
+* type: String
+* description: Set the default separator between object levels.
+* default: `.`

+ 43 - 51
src/extensions/flat-json/bootstrap-table-flat-json.js

@@ -1,70 +1,62 @@
 /**
  * @author: Dennis Hernández
  * @webSite: http://djhvscf.github.io/Blog
- * @version: v1.2.0
+ * @version: v1.3.0
  */
 
-
 (function ($) {
     'use strict';
 
+    var flat = function (element, that) {
+        var result = {};
+
+        function recurse(cur, prop) {
+            if (Object(cur) !== cur) {
+                result[prop] = cur;
+            } else if ($.isArray(cur)) {
+                for (var i = 0, l = cur.length; i < l; i++) {
+                    recurse(cur[i], prop ? prop + that.options.flatSeparator + i : "" + i);
+                    if (l == 0) {
+                        result[prop] = [];
+                    }
+                }
+            } else {
+                var isEmpty = true;
+                for (var p in cur) {
+                    isEmpty = false;
+                    recurse(cur[p], prop ? prop + that.options.flatSeparator + p : p);
+                }
+                if (isEmpty) {
+                    result[prop] = {};
+                }
+            }
+        }
+
+        recurse(element, "");
+        return result;
+    };
+
+    var flatHelper = function (data, that) {
+        var flatArray = [];
+
+        $.each(!$.isArray(data) ? [data] : data, function (i, element) {
+            flatArray.push(flat(element, that));
+        });
+        return flatArray;
+    };
+
     $.extend($.fn.bootstrapTable.defaults, {
-        flat: false
+        flat: false,
+        flatSeparator: '.'
     });
 
     var BootstrapTable = $.fn.bootstrapTable.Constructor,
         _initData = BootstrapTable.prototype.initData;
 
     BootstrapTable.prototype.initData = function (data, type) {
-        if( this.options.flat ){
-            data = data === undefined ? this.options.data : data;
-            data = sd.flatHelper(data);
+        if (this.options.flat) {
+            data = flatHelper(data ? data : this.options.data, this);
         }
         _initData.apply(this, [data, type]);
     };
-
-    //Main functions
-    var sd = {
-        flat: function (element) {
-            var result = {};
-
-            function recurse(cur, prop) {
-                if (Object(cur) !== cur) {
-                    result[prop] = cur;
-                } else if ($.isArray(cur)) {
-                    for (var i = 0, l = cur.length; i < l; i++) {
-                        recurse(cur[i], prop ? prop + "." + i : "" + i);
-                        if (l == 0) {
-                            result[prop] = [];
-                        }
-                    }
-                } else {
-                    var isEmpty = true;
-                    for (var p in cur) {
-                        isEmpty = false;
-                        recurse(cur[p], prop ? prop + "." + p : p);
-                    }
-                    if (isEmpty) {
-                        result[prop] = {};
-                    }
-                }
-            }
-
-            recurse(element, "");
-            return result;
-        },
-
-        flatHelper: function (data) {
-            var flatArray = [],
-                arrayHelper = [];
-            if (!$.isArray(data)) {
-                arrayHelper.push(data);
-                data = arrayHelper;
-            }
-            $.each(data, function (i, element) {
-                flatArray.push(sd.flat(element));
-            });
-            return flatArray;
-        }
-    };
 })(jQuery);

+ 0 - 1
src/extensions/key-events/bootstrap-table-key-events.js

@@ -19,7 +19,6 @@
 
     BootstrapTable.prototype.init = function () {
         _init.apply(this, Array.prototype.slice.apply(arguments));
-
         this.initKeyEvents();
     };
 

+ 42 - 37
src/extensions/multiple-sort/bootstrap-table-multiple-sort.js

@@ -15,13 +15,16 @@
     };
 
     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">';
+        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">&times;</span></button>';
-            sModal += '                     <h4 class="modal-title" id="sortModalLabel">' + that.options.formatMultipleSort() + '</h4>';
+            sModal += '                     <h4 class="modal-title" id="' + _id + 'Label">' + that.options.formatMultipleSort() + '</h4>';
             sModal += '                 </div>';
             sModal += '                 <div class="modal-body">';
             sModal += '                     <div class="bootstrap-table">';
@@ -57,12 +60,12 @@
 
             $("body").append($(sModal));
 
-            var $sortModal = $('#sortModal'),
-                $rows = $sortModal.find("tbody > tr");
+            that.$sortModal = $(_selector);
+            var $rows = that.$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;
+            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++;
@@ -71,20 +74,20 @@
                 }
             });
 
-            $sortModal.off('click', '#delete').on('click', '#delete', function() {
-                var total = $sortModal.find('.multi-sort-name:first option').length,
-                    current = $sortModal.find('tbody tr').length;
+            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--;
-                    $sortModal.find('tbody tr:last').remove();
+                    that.$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'),
+            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 = [];
 
@@ -113,7 +116,7 @@
                 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'));
+                        $($alert).insertBefore(that.$sortModal.find('.bars'));
                     }
                 } else {
                     if ($alert.length === 1) {
@@ -122,7 +125,7 @@
 
                     that.options.sortName = "";
                     that.onMultipleSort();
-                    $sortModal.modal('hide');
+                    that.$sortModal.modal('hide');
                 }
             });
 
@@ -210,7 +213,9 @@
 
     BootstrapTable.prototype.initToolbar = function() {
         this.showToolbar = true;
-        var that = this;
+        var that = this,
+            sortModalId = '#sortModal_' + this.$el.attr('id');
+        this.$sortModal = $(sortModalId);
 
         _initToolbar.apply(this, Array.prototype.slice.apply(arguments));
 
@@ -219,7 +224,7 @@
                 $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 = '  <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>';
 
@@ -228,7 +233,7 @@
                 showSortModal(that);
             }
 
-            this.$el.one('sort.bs.table', function() {
+            this.$el.on('sort.bs.table', function() {
                 isSingleSort = true;
             });
 
@@ -250,12 +255,14 @@
                 }
 
                 that.assignSortableArrows();
-                $('#sortModal').remove();
+                that.$sortModal.remove();
                 showSortModal(that);
             });
 
             this.$el.on('reset-view.bs.table', function() {
-                that.assignSortableArrows();
+                if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object') {
+                    that.assignSortableArrows();
+                }
             });
         }
     };
@@ -309,18 +316,17 @@
     };
 
     BootstrapTable.prototype.addLevel = function(index, sortPriority) {
-        var $sortModal = $("#sortModal"),
-            text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy();
+        var text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy();
 
-        $sortModal.find('tbody')
+        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 = $sortModal.find('.multi-sort-name').last(),
-            $multiSortOrder = $sortModal.find('.multi-sort-order').last();
+        var $multiSortName = this.$sortModal.find('.multi-sort-name').last(),
+            $multiSortOrder = this.$sortModal.find('.multi-sort-order').last();
 
         this.options.columns.forEach(function(column) {
             if (column.sortable === false || column.visible === false) {
@@ -346,28 +352,27 @@
         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').addClass(that.options.sortPriority[c].sortOrder);
+                    $(headers[i]).find('.sortable').removeClass('desc asc').addClass(that.options.sortPriority[c].sortOrder);
                 }
             }
         }
     };
 
     BootstrapTable.prototype.setButtonStates = function() {
-        var $sortModal = $('#sortModal'),
-            total = $sortModal.find('.multi-sort-name:first option').length,
-            current = $sortModal.find('tbody tr').length;
+        var total = this.$sortModal.find('.multi-sort-name:first option').length,
+            current = this.$sortModal.find('tbody tr').length;
 
         if (current == total) {
-            $sortModal.find('#add').attr('disabled', 'disabled');
+            this.$sortModal.find('#add').attr('disabled', 'disabled');
         }
         if (current > 1) {
-            $sortModal.find('#delete').removeAttr('disabled');
+            this.$sortModal.find('#delete').removeAttr('disabled');
         }
         if (current < total) {
-            $sortModal.find('#add').removeAttr('disabled');
+            this.$sortModal.find('#add').removeAttr('disabled');
         }
         if (current == 1) {
-            $sortModal.find('#delete').attr('disabled', 'disabled');
+            this.$sortModal.find('#delete').attr('disabled', 'disabled');
         }
     };
-})(jQuery);
+})(jQuery);