diff --git a/README.md b/README.md index 97de5023..b789869a 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,28 @@ If you would like to contribute, please... View the [complete change log here](https://github.com/Mottie/tablesorter/wiki/Changes). +#### Version 2.29.1 (12/13/2017) + +* Core: + * Fix non-typical use of selectorHeaders. See [issue #1459](https://github.com/Mottie/tablesorter/issues/1459). + * Update external header icons on sort. Fixes [issue #1483](https://github.com/Mottie/tablesorter/issues/1483). + * Remove an empty block. +* Filter: + * Select exact matches ignore "and" and "or" keywords. Fixes [issue #1486](https://github.com/Mottie/tablesorter/issues/1486). +* Resizable: + * `addLastColumn` stops adding handles to hidden columns. Fixes [issue #1485](https://github.com/Mottie/tablesorter/issues/1485). +* Scroller: + * Adjust columns on `filterInit`. See [issue #1468](https://github.com/Mottie/tablesorter/issues/1468). +* Vertical Group: + * New widget added. See [demo](https://mottie.github.io/tablesorter/docs/example-widget-vertical-group.html). + * Thanks to [aavmurphy](https://github.com/aavmurphy) for sharing the code. See [issue #1469](https://github.com/Mottie/tablesorter/issues/1469) and [PR #1470](https://github.com/Mottie/tablesorter/pull/1470). +* Docs: + * Fix pager example. + * List all contained IP parsers. Fixes [issue #1484](https://github.com/Mottie/tablesorter/issues/1484). + * Fix Bootstrap v2 demo; restored gyphs images. +* Meta: + * Update authors. + #### Version 2.29.0 (9/27/2017) * Core: @@ -164,15 +186,3 @@ View the [complete change log here](https://github.com/Mottie/tablesorter/wiki/C * Use src files in filter formatter demo for testing. * Meta: * Include `js` & `css` folders with bower installs. - -#### Version 2.28.14 (6/8/2017) - -* Core: - * Show console error for mismatched column count. See [issue #1415](https://github.com/Mottie/tablesorter/issues/1415). -* Pager: - * (addon) Ensure ajax is called after filter widget init. Fixes [issue #1389](https://github.com/Mottie/tablesorter/issues/1389). - * (addon) Fix height issues for certain browsers (border-spacing). See [pull #1418](https://github.com/Mottie/tablesorter/pull/1418); thanks [@DoctorWhite](https://github.com/DoctorWhite) - * (widget) Apply height adjustment code to pager widget. - * Use selectorRemove to remove error rows. Removes error rows with dynamically changed class names. -* Meta: - * Added [AUTHORS](https://github.com/Mottie/tablesorter/blob/master/AUTHORS) file. diff --git a/dist/js/jquery.tablesorter.combined.js b/dist/js/jquery.tablesorter.combined.js index 457b76fb..c7bfeaa9 100644 --- a/dist/js/jquery.tablesorter.combined.js +++ b/dist/js/jquery.tablesorter.combined.js @@ -1,4 +1,4 @@ -/*! tablesorter (FORK) - updated 09-27-2017 (v2.29.0)*/ +/*! tablesorter (FORK) - updated 12-13-2017 (v2.29.1)*/ /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */ (function(factory) { if (typeof define === 'function' && define.amd) { @@ -10,7 +10,7 @@ } }(function(jQuery) { -/*! TableSorter (FORK) v2.29.0 *//* +/*! TableSorter (FORK) v2.29.1 *//* * Client-side table sorting with ease! * @requires jQuery v1.2.6+ * @@ -34,7 +34,7 @@ 'use strict'; var ts = $.tablesorter = { - version : '2.29.0', + version : '2.29.1', parsers : [], widgets : [], @@ -526,8 +526,7 @@ if ( c.delayInit && ts.isEmptyObject( c.cache ) ) { ts.buildCache( c ); } - // jQuery v1.2.6 doesn't have closest() - $cell = ts.getHeaderCell( $( this ) ); + $cell = ts.getClosest( $( this ), '.' + ts.css.header ); // reference original table headers and find the same cell // don't use $headers or IE8 throws an error - see #987 temp = $headers.index( $cell ); @@ -567,10 +566,15 @@ ''; // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683 c.$headers = $( $.map( c.$table.find( c.selectorHeaders ), function( elem, index ) { - var configHeaders, header, column, template, tmp, $th, + var configHeaders, header, column, template, tmp, $elem = $( elem ); // ignore cell (don't add it to c.$headers) if row has ignoreRow class - if ( $elem.parent().hasClass( c.cssIgnoreRow ) ) { return; } + if ( ts.getClosest( $elem, 'tr' ).hasClass( c.cssIgnoreRow ) ) { return; } + // transfer data-column to element if not th/td - #1459 + if ( !/(th|td)/i.test( elem.nodeName ) ) { + tmp = ts.getClosest( $elem, 'th, td' ); + $elem.attr( 'data-column', tmp.attr( 'data-column' ) ); + } // make sure to get header cell & not column indexed cell configHeaders = ts.getColumnData( c.table, c.headers, index, true ); // save original header content @@ -593,9 +597,7 @@ if ( c.onRenderHeader ) { c.onRenderHeader.apply( $elem, [ index, c, c.$table ] ); } - // data-column stored on th or td only - $th = ts.getHeaderCell( $elem ); - column = parseInt( $th.attr( 'data-column' ), 10 ); + column = parseInt( $elem.attr( 'data-column' ), 10 ); elem.column = column; tmp = ts.getOrder( ts.getData( $elem, configHeaders, 'sortInitialOrder' ) || c.sortInitialOrder ); // this may get updated numerous times if there are multiple rows @@ -631,6 +633,7 @@ if ( ts.isEmptyObject( c.sortVars[ indx ] ) ) { c.sortVars[ indx ] = {}; } + // Use c.$headers.parent() in case selectorHeaders doesn't point to the th/td $temp = c.$headers.filter( '[data-column="' + indx + '"]' ); // target sortable column cells, unless there are none, then use non-sortable cells // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6 @@ -1094,6 +1097,15 @@ css = [ ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc ], cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ], aria = [ 'ascending', 'descending' ], + updateColumnSort = function($el, index) { + $el + .removeClass( none ) + .addClass( css[ index ] ) + .attr( 'aria-sort', aria[ index ] ) + .find( '.' + ts.css.icon ) + .removeClass( cssIcon[ 2 ] ) + .addClass( cssIcon[ index ] ); + }, // find the footer $extras = c.$table .find( 'tfoot tr' ) @@ -1132,7 +1144,7 @@ var include = true, $el = c.$headers.eq( i ), col = parseInt( $el.attr( 'data-column' ), 10 ), - end = col + c.$headers[ i ].colSpan; + end = col + ts.getClosest( $el, 'th, td' )[0].colSpan; for ( ; col < end; col++ ) { include = include ? include || ts.isValueInArray( col, c.sortList ) > -1 : false; } @@ -1146,23 +1158,13 @@ if ( $sorted.length ) { for ( column = 0; column < $sorted.length; column++ ) { if ( !$sorted[ column ].sortDisabled ) { - $sorted - .eq( column ) - .removeClass( none ) - .addClass( css[ list[ indx ][ 1 ] ] ) - .attr( 'aria-sort', aria[ list[ indx ][ 1 ] ] ) - .find( '.' + ts.css.icon ) - .removeClass( cssIcon[ 2 ] ) - .addClass( cssIcon[ list[ indx ][ 1 ] ] ); + updateColumnSort( $sorted.eq( column ) , list[ indx ][ 1 ] ); } } - // add sorted class to footer & extra headers, if they exist - if ( $extras.length ) { - $extras - .filter( '[data-column="' + list[ indx ][ 0 ] + '"]' ) - .removeClass( none ) - .addClass( css[ list[ indx ][ 1 ] ] ); - } + } + // add sorted class to footer & extra headers, if they exist + if ( $extras.length ) { + updateColumnSort( $extras.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' ), list[ indx ][ 1 ] ); } } } @@ -1173,29 +1175,20 @@ } }, - // This function does NOT return closest if the $el matches the selector getClosest : function( $el, selector ) { - return $.fn.closest ? - $el.closest( selector ) : - $el.parents( selector ).filter( ':first' ); - }, - - getHeaderCell : function( $el ) { // jQuery v1.2.6 doesn't have closest() if ( $.fn.closest ) { - return $el.closest( 'th, td' ); + return $el.closest( selector ); } - return /TH|TD/.test( $el[0].nodeName ) ? + return $el.is( selector ) ? $el : - $el.parents( 'th, td' ).filter( ':first' ); + $el.parents( selector ).filter( ':first' ); }, // nextSort (optional), lets you disable next sort text setColumnAriaLabel : function( c, $header, nextSort ) { if ( $header.length ) { - var $th = ts.getHeaderCell( $header ), - // data-column always stored on the th/td - column = parseInt( $th.attr( 'data-column' ), 10 ), + var column = parseInt( $header.attr( 'data-column' ), 10 ), vars = c.sortVars[ column ], tmp = $header.hasClass( ts.css.sortAsc ) ? 'sortAsc' : @@ -1563,10 +1556,10 @@ notMultiSort = !event[ c.sortMultiSortKey ], table = c.table, len = c.$headers.length, - // get current column index; *always* stored on th/td - $th = ts.getHeaderCell( $( cell ) ), - col = parseInt( $th.attr( 'data-column' ), 10 ), + th = ts.getClosest( $( cell ), 'th, td' ), + col = parseInt( th.attr( 'data-column' ), 10 ), order = c.sortVars[ col ].order; + th = th[0]; // Only call sortStart if sorting is enabled c.$table.triggerHandler( 'sortStart', table ); // get current column sort order @@ -1601,8 +1594,8 @@ if ( dir < 2 ) { c.sortList[ c.sortList.length ] = [ col, dir ]; // add other columns if header spans across multiple - if ( cell.colSpan > 1 ) { - for ( indx = 1; indx < cell.colSpan; indx++ ) { + if ( th.colSpan > 1 ) { + for ( indx = 1; indx < th.colSpan; indx++ ) { c.sortList[ c.sortList.length ] = [ col + indx, dir ]; // update count on columns in colSpan c.sortVars[ col + indx ].count = $.inArray( dir, order ); @@ -1634,8 +1627,8 @@ if ( dir < 2 ) { c.sortList[ c.sortList.length ] = [ col, dir ]; // add other columns if header spans across multiple - if ( cell.colSpan > 1 ) { - for ( indx = 1; indx < cell.colSpan; indx++ ) { + if ( th.colSpan > 1 ) { + for ( indx = 1; indx < th.colSpan; indx++ ) { c.sortList[ c.sortList.length ] = [ col + indx, dir ]; // update count on columns in colSpan c.sortVars[ col + indx ].count = $.inArray( dir, order ); @@ -2404,7 +2397,7 @@ $cells = ( $headers || c.$headers ), // c.$headerIndexed is not defined initially $cell = c.$headerIndexed && c.$headerIndexed[ indx ] || - $cells.filter( '[data-column="' + indx + '"]:last' ); + $cells.find( '[data-column="' + indx + '"]:last' ); if ( typeof obj[ indx ] !== 'undefined' ) { return getCell ? obj[ indx ] : obj[ $cells.index( $cell ) ]; } @@ -4406,6 +4399,7 @@ if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) { matches = tsf.types[ffxn]( c, data, vars ); if ( matches !== null ) { + data.matchedOn = ffxn; filterMatched = matches; } } @@ -4453,6 +4447,7 @@ tsf.multipleColumns( c, wo.filter_$anyMatch ) : []; data.$cells = data.$row.children(); + data.matchedOn = null; if ( data.anyMatchFlag && columnIndex.length > 1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) { data.anyMatch = true; data.isMatch = true; @@ -4554,7 +4549,9 @@ // cycle through the different filters // filters return a boolean or null if nothing matches filterMatched = tsf.processTypes( c, data, vars ); - if ( filterMatched !== null ) { + // select with exact match; ignore "and" or "or" within the text; fixes #1486 + txt = fxn === true && (data.matchedOn === 'and' || data.matchedOn === 'or'); + if ( filterMatched !== null && !txt) { result = filterMatched; // Look for match, and add child row data for matching } else { @@ -5713,7 +5710,10 @@ columns = c.columns - 1, $header = $this.data( 'header' ); if ( !$header ) { return; } // see #859 - if ( !$header.is(':visible') ) { + if ( + !$header.is(':visible') || + ( !wo.resizable_addLastColumn && ts.resizable.checkVisibleColumns(c, column) ) + ) { $this.hide(); } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) { $this.css({ @@ -5725,6 +5725,16 @@ }); }, + // Fixes #1485 + checkVisibleColumns: function( c, column ) { + var i, + len = 0; + for ( i = column + 1; i < c.columns; i++ ) { + len += c.$headerIndexed[i].is( ':visible' ) ? 1 : 0; + } + return len === 0; + }, + // prevent text selection while dragging resize bar toggleTextSelection : function( c, wo, toggle ) { var namespace = c.namespace + 'tsresize'; diff --git a/dist/js/jquery.tablesorter.combined.min.js b/dist/js/jquery.tablesorter.combined.min.js index 19672e32..14f9b767 100644 --- a/dist/js/jquery.tablesorter.combined.min.js +++ b/dist/js/jquery.tablesorter.combined.min.js @@ -1,2 +1,2 @@ -/*! tablesorter (FORK) - updated 09-27-2017 (v2.29.0)*/ -!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(t){"use strict";var r=t.tablesorter={version:"2.29.0",parsers:[],widgets:[],defaults:{theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,resort:!0,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",duplicateSpan:!0,textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,initWidgets:!0,widgetClass:"widget-{name}",widgets:[],widgetOptions:{zebra:["even","odd"]},initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssIconDisabled:"",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[],globalize:0,imgAttr:0},css:{table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",colgroup:"tablesorter-colgroup",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"},language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",sortDisabled:"sorting is disabled",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},regex:{templateContent:/\{content\}/g,templateIcon:/\{icon\}/g,templateName:/\{name\}/i,spaces:/\s+/g,nonWord:/\W/g,formElements:/(input|select|button|textarea)/i,chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},keyCodes:{enter:13},dates:{},instanceMethods:{},setup:function(e,a){if(e&&e.tHead&&0!==e.tBodies.length&&!0!==e.hasInitialized){var i="",s=t(e),o=t.metadata;e.hasInitialized=!1,e.isProcessing=!0,e.config=a,t.data(e,"tablesorter",a),a.debug&&(console[console.group?"group":"log"]("Initializing tablesorter v"+r.version),t.data(e,"startoveralltimer",new Date)),a.supportsDataObject=function(e){return e[0]=parseInt(e[0],10),e[0]>1||1===e[0]&&parseInt(e[1],10)>=4}(t.fn.jquery.split(".")),a.emptyTo=a.emptyTo.toLowerCase(),a.stringTo=a.stringTo.toLowerCase(),a.last={sortList:[],clickedIndex:-1},/tablesorter\-/.test(s.attr("class"))||(i=""!==a.theme?" tablesorter-"+a.theme:""),a.namespace?a.namespace="."+a.namespace.replace(r.regex.nonWord,""):a.namespace=".tablesorter"+Math.random().toString(16).slice(2),a.table=e,a.$table=s.addClass(r.css.table+" "+a.tableClass+i+" "+a.namespace.slice(1)).attr("role","grid"),a.$headers=s.find(a.selectorHeaders),a.$table.children().children("tr").attr("role","row"),a.$tbodies=s.children("tbody:not(."+a.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),a.$table.children("caption").length&&((i=a.$table.children("caption")[0]).id||(i.id=a.namespace.slice(1)+"caption"),a.$table.attr("aria-labelledby",i.id)),a.widgetInit={},a.textExtraction=a.$table.attr("data-text-extraction")||a.textExtraction||"basic",r.buildHeaders(a),r.fixColumnWidth(e),r.addWidgetFromClass(e),r.applyWidgetOptions(e),r.setupParsers(a),a.totalRows=0,r.validateOptions(a),a.delayInit||r.buildCache(a),r.bindEvents(e,a.$headers,!0),r.bindMethods(a),a.supportsDataObject&&void 0!==s.data().sortlist?a.sortList=s.data().sortlist:o&&s.metadata()&&s.metadata().sortlist&&(a.sortList=s.metadata().sortlist),r.applyWidget(e,!0),a.sortList.length>0?r.sortOn(a,a.sortList,{},!a.initWidgets):(r.setHeadersCss(a),a.initWidgets&&r.applyWidget(e,!1)),a.showProcessing&&s.unbind("sortBegin"+a.namespace+" sortEnd"+a.namespace).bind("sortBegin"+a.namespace+" sortEnd"+a.namespace,function(t){clearTimeout(a.timerProcessing),r.isProcessing(e),"sortBegin"===t.type&&(a.timerProcessing=setTimeout(function(){r.isProcessing(e,!0)},500))}),e.hasInitialized=!0,e.isProcessing=!1,a.debug&&(console.log("Overall initialization time:"+r.benchmark(t.data(e,"startoveralltimer"))),a.debug&&console.groupEnd&&console.groupEnd()),s.triggerHandler("tablesorter-initialized",e),"function"==typeof a.initialized&&a.initialized(e)}else a.debug&&(e.hasInitialized?console.warn("Stopping initialization. Tablesorter has already been initialized"):console.error("Stopping initialization! No table, thead or tbody",e))},bindMethods:function(e){var a=e.$table,i=e.namespace,s="sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(i+" ");a.unbind(s.replace(r.regex.spaces," ")).bind("sortReset"+i,function(e,t){e.stopPropagation(),r.sortReset(this.config,function(e){e.isApplyingWidgets?setTimeout(function(){r.applyWidget(e,"",t)},100):r.applyWidget(e,"",t)})}).bind("updateAll"+i,function(e,t,a){e.stopPropagation(),r.updateAll(this.config,t,a)}).bind("update"+i+" updateRows"+i,function(e,t,a){e.stopPropagation(),r.update(this.config,t,a)}).bind("updateHeaders"+i,function(e,t){e.stopPropagation(),r.updateHeaders(this.config,t)}).bind("updateCell"+i,function(e,t,a,i){e.stopPropagation(),r.updateCell(this.config,t,a,i)}).bind("addRows"+i,function(e,t,a,i){e.stopPropagation(),r.addRows(this.config,t,a,i)}).bind("updateComplete"+i,function(){this.isUpdating=!1}).bind("sorton"+i,function(e,t,a,i){e.stopPropagation(),r.sortOn(this.config,t,a,i)}).bind("appendCache"+i,function(e,a,i){e.stopPropagation(),r.appendCache(this.config,i),t.isFunction(a)&&a(this)}).bind("updateCache"+i,function(e,t,a){e.stopPropagation(),r.updateCache(this.config,t,a)}).bind("applyWidgetId"+i,function(e,t){e.stopPropagation(),r.applyWidgetId(this,t)}).bind("applyWidgets"+i,function(e,t){e.stopPropagation(),r.applyWidget(this,!1,t)}).bind("refreshWidgets"+i,function(e,t,a){e.stopPropagation(),r.refreshWidgets(this,t,a)}).bind("removeWidget"+i,function(e,t,a){e.stopPropagation(),r.removeWidget(this,t,a)}).bind("destroy"+i,function(e,t,a){e.stopPropagation(),r.destroy(this,t,a)}).bind("resetToLoadState"+i,function(a){a.stopPropagation(),r.removeWidget(this,!0,!1);var i=t.extend(!0,{},e.originalSettings);(e=t.extend(!0,{},r.defaults,i)).originalSettings=i,this.hasInitialized=!1,r.setup(this,e)})},bindEvents:function(e,a,i){var s,o=(e=t(e)[0]).config,n=o.namespace,l=null;!0!==i&&(a.addClass(n.slice(1)+"_extra_headers"),(s=r.getClosest(a,"table")).length&&"TABLE"===s[0].nodeName&&s[0]!==e&&t(s[0]).addClass(n.slice(1)+"_extra_table")),s=(o.pointerDown+" "+o.pointerUp+" "+o.pointerClick+" sort keyup ").replace(r.regex.spaces," ").split(" ").join(n+" "),a.find(o.selectorSort).add(a.filter(o.selectorSort)).unbind(s).bind(s,function(e,i){var s,n,d,c=t(e.target),f=" "+e.type+" ";if(!(1!==(e.which||e.button)&&!f.match(" "+o.pointerClick+" | sort | keyup ")||" keyup "===f&&e.which!==r.keyCodes.enter||f.match(" "+o.pointerClick+" ")&&void 0!==e.which||f.match(" "+o.pointerUp+" ")&&l!==e.target&&!0!==i)){if(f.match(" "+o.pointerDown+" "))return l=e.target,void("1"===(d=c.jquery.split("."))[0]&&d[1]<4&&e.preventDefault());if(l=null,r.regex.formElements.test(e.target.nodeName)||c.hasClass(o.cssNoSort)||c.parents("."+o.cssNoSort).length>0||c.parents("button").length>0)return!o.cancelSelection;o.delayInit&&r.isEmptyObject(o.cache)&&r.buildCache(o),s=r.getHeaderCell(t(this)),d=a.index(s),o.last.clickedIndex=d<0?s.attr("data-column"):d,(n=o.$headers[o.last.clickedIndex])&&!n.sortDisabled&&r.initSort(o,n,e)}}),o.cancelSelection&&a.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},buildHeaders:function(e){var a,i,s,o;for(e.headerList=[],e.headerContent=[],e.sortVars=[],e.debug&&(s=new Date),e.columns=r.computeColumnIndex(e.$table.children("thead, tfoot").children("tr")),i=e.cssIcon?'':"",e.$headers=t(t.map(e.$table.find(e.selectorHeaders),function(a,s){var o,n,l,d,c,f,u=t(a);if(!u.parent().hasClass(e.cssIgnoreRow))return o=r.getColumnData(e.table,e.headers,s,!0),e.headerContent[s]=u.html(),""===e.headerTemplate||u.find("."+r.css.headerIn).length||(d=e.headerTemplate.replace(r.regex.templateContent,u.html()).replace(r.regex.templateIcon,u.find("."+r.css.icon).length?"":i),e.onRenderTemplate&&(n=e.onRenderTemplate.apply(u,[s,d]))&&"string"==typeof n&&(d=n),u.html('