jquery-tablesorter 1.18.5 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/jquery-tablesorter/version.rb +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +68 -46
- data/vendor/assets/javascripts/jquery-tablesorter/extras/jquery.dragtable.mod.js +3 -3
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.combined.js +2383 -2100
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +2298 -2039
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +90 -66
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-month.js +45 -20
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-weekday.js +78 -20
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-globalize.js +37 -15
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +4 -4
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-chart.js +2 -2
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columnSelector.js +122 -30
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +8 -6
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +79 -58
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-grouping.js +209 -128
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-headerTitles.js +5 -4
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-lazyload.js +367 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-math.js +81 -35
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +3 -3
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +79 -53
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-print.js +25 -14
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-saveSort.js +5 -2
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +11 -7
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-sort2Hash.js +149 -50
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-sortTbodies.js +7 -7
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-staticRow.js +2 -2
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +2 -2
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-view.js +192 -0
- metadata +4 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! TableSorter (FORK) v2.
|
|
1
|
+
/*! TableSorter (FORK) v2.24.2 *//*
|
|
2
2
|
* Client-side table sorting with ease!
|
|
3
3
|
* @requires jQuery v1.2.6+
|
|
4
4
|
*
|
|
@@ -17,2159 +17,2392 @@
|
|
|
17
17
|
* @contributor Rob Garrison - https://github.com/Mottie/tablesorter
|
|
18
18
|
*/
|
|
19
19
|
/*jshint browser:true, jquery:true, unused:false, expr: true */
|
|
20
|
-
;(function($){
|
|
20
|
+
;( function( $ ) {
|
|
21
21
|
'use strict';
|
|
22
|
-
$.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
parsers: []
|
|
22
|
+
var ts = $.tablesorter = {
|
|
23
|
+
|
|
24
|
+
version : '2.24.2',
|
|
25
|
+
|
|
26
|
+
parsers : [],
|
|
27
|
+
widgets : [],
|
|
28
|
+
defaults : {
|
|
29
|
+
|
|
30
|
+
// *** appearance
|
|
31
|
+
theme : 'default', // adds tablesorter-{theme} to the table for styling
|
|
32
|
+
widthFixed : false, // adds colgroup to fix widths of columns
|
|
33
|
+
showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered.
|
|
34
|
+
|
|
35
|
+
headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> // class from cssIcon
|
|
36
|
+
onRenderTemplate : null, // function( index, template ){ return template; }, // template is a string
|
|
37
|
+
onRenderHeader : null, // function( index ){}, // nothing to return
|
|
38
|
+
|
|
39
|
+
// *** functionality
|
|
40
|
+
cancelSelection : true, // prevent text selection in the header
|
|
41
|
+
tabIndex : true, // add tabindex to header for keyboard accessibility
|
|
42
|
+
dateFormat : 'mmddyyyy', // other options: 'ddmmyyy' or 'yyyymmdd'
|
|
43
|
+
sortMultiSortKey : 'shiftKey', // key used to select additional columns
|
|
44
|
+
sortResetKey : 'ctrlKey', // key used to remove sorting on a column
|
|
45
|
+
usNumberFormat : true, // false for German '1.234.567,89' or French '1 234 567,89'
|
|
46
|
+
delayInit : false, // if false, the parsed table contents will not update until the first sort
|
|
47
|
+
serverSideSorting: false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
|
|
48
|
+
resort : true, // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed
|
|
49
|
+
|
|
50
|
+
// *** sort options
|
|
51
|
+
headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
|
|
52
|
+
ignoreCase : true, // ignore case while sorting
|
|
53
|
+
sortForce : null, // column(s) first sorted; always applied
|
|
54
|
+
sortList : [], // Initial sort order; applied initially; updated when manually sorted
|
|
55
|
+
sortAppend : null, // column(s) sorted last; always applied
|
|
56
|
+
sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained
|
|
57
|
+
|
|
58
|
+
sortInitialOrder : 'asc', // sort direction on first click
|
|
59
|
+
sortLocaleCompare: false, // replace equivalent character (accented characters)
|
|
60
|
+
sortReset : false, // third click on the header will reset column to default - unsorted
|
|
61
|
+
sortRestart : false, // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns
|
|
62
|
+
|
|
63
|
+
emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
|
|
64
|
+
stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero
|
|
65
|
+
textExtraction : 'basic', // text extraction method/function - function( node, table, cellIndex ){}
|
|
66
|
+
textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function)
|
|
67
|
+
textSorter : null, // choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]
|
|
68
|
+
numberSorter : null, // choose overall numeric sorter function( a, b, direction, maxColumnValue )
|
|
69
|
+
|
|
70
|
+
// *** widget options
|
|
71
|
+
widgets: [], // method to add widgets, e.g. widgets: ['zebra']
|
|
72
|
+
widgetOptions : {
|
|
73
|
+
zebra : [ 'even', 'odd' ] // zebra widget alternating row class names
|
|
74
|
+
},
|
|
75
|
+
initWidgets : true, // apply widgets on tablesorter initialization
|
|
76
|
+
widgetClass : 'widget-{name}', // table class name template to match to include a widget
|
|
77
|
+
|
|
78
|
+
// *** callbacks
|
|
79
|
+
initialized : null, // function( table ){},
|
|
80
|
+
|
|
81
|
+
// *** extra css class names
|
|
82
|
+
tableClass : '',
|
|
83
|
+
cssAsc : '',
|
|
84
|
+
cssDesc : '',
|
|
85
|
+
cssNone : '',
|
|
86
|
+
cssHeader : '',
|
|
87
|
+
cssHeaderRow : '',
|
|
88
|
+
cssProcessing : '', // processing icon applied to header during sort/filter
|
|
89
|
+
|
|
90
|
+
cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent
|
|
91
|
+
cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!)
|
|
92
|
+
cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort
|
|
93
|
+
cssIgnoreRow : 'tablesorter-ignoreRow', // header row to ignore; cells within this row will not be added to c.$headers
|
|
94
|
+
|
|
95
|
+
cssIcon : 'tablesorter-icon', // if this class does not exist, the {icon} will not be added from the headerTemplate
|
|
96
|
+
cssIconNone : '', // class name added to the icon when there is no column sort
|
|
97
|
+
cssIconAsc : '', // class name added to the icon when the column has an ascending sort
|
|
98
|
+
cssIconDesc : '', // class name added to the icon when the column has a descending sort
|
|
99
|
+
|
|
100
|
+
// *** events
|
|
101
|
+
pointerClick : 'click',
|
|
102
|
+
pointerDown : 'mousedown',
|
|
103
|
+
pointerUp : 'mouseup',
|
|
104
|
+
|
|
105
|
+
// *** selectors
|
|
106
|
+
selectorHeaders : '> thead th, > thead td',
|
|
107
|
+
selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort
|
|
108
|
+
selectorRemove : '.remove-me',
|
|
109
|
+
|
|
110
|
+
// *** advanced
|
|
111
|
+
debug : false,
|
|
112
|
+
|
|
113
|
+
// *** Internal variables
|
|
114
|
+
headerList: [],
|
|
115
|
+
empties: {},
|
|
116
|
+
strings: {},
|
|
117
|
+
parsers: []
|
|
118
|
+
|
|
119
|
+
// removed: widgetZebra: { css: ['even', 'odd'] }
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
},
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
// internal css classes - these will ALWAYS be added to
|
|
124
|
+
// the table and MUST only contain one class name - fixes #381
|
|
125
|
+
css : {
|
|
126
|
+
table : 'tablesorter',
|
|
127
|
+
cssHasChild: 'tablesorter-hasChildRow',
|
|
128
|
+
childRow : 'tablesorter-childRow',
|
|
129
|
+
colgroup : 'tablesorter-colgroup',
|
|
130
|
+
header : 'tablesorter-header',
|
|
131
|
+
headerRow : 'tablesorter-headerRow',
|
|
132
|
+
headerIn : 'tablesorter-header-inner',
|
|
133
|
+
icon : 'tablesorter-icon',
|
|
134
|
+
processing : 'tablesorter-processing',
|
|
135
|
+
sortAsc : 'tablesorter-headerAsc',
|
|
136
|
+
sortDesc : 'tablesorter-headerDesc',
|
|
137
|
+
sortNone : 'tablesorter-headerUnSorted'
|
|
138
|
+
},
|
|
125
139
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
headerIn : 'tablesorter-header-inner',
|
|
136
|
-
icon : 'tablesorter-icon',
|
|
137
|
-
processing : 'tablesorter-processing',
|
|
138
|
-
sortAsc : 'tablesorter-headerAsc',
|
|
139
|
-
sortDesc : 'tablesorter-headerDesc',
|
|
140
|
-
sortNone : 'tablesorter-headerUnSorted'
|
|
141
|
-
};
|
|
140
|
+
// labels applied to sortable headers for accessibility (aria) support
|
|
141
|
+
language : {
|
|
142
|
+
sortAsc : 'Ascending sort applied, ',
|
|
143
|
+
sortDesc : 'Descending sort applied, ',
|
|
144
|
+
sortNone : 'No sort applied, ',
|
|
145
|
+
nextAsc : 'activate to apply an ascending sort',
|
|
146
|
+
nextDesc : 'activate to apply a descending sort',
|
|
147
|
+
nextNone : 'activate to remove the sort'
|
|
148
|
+
},
|
|
142
149
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
nextNone : 'activate to remove the sort'
|
|
151
|
-
};
|
|
150
|
+
regex : {
|
|
151
|
+
templateContent : /\{content\}/g,
|
|
152
|
+
templateIcon : /\{icon\}/g,
|
|
153
|
+
templateName : /\{name\}/i,
|
|
154
|
+
spaces : /\s+/g,
|
|
155
|
+
nonWord : /\W/g,
|
|
156
|
+
formElements : /(input|select|button|textarea)/i,
|
|
152
157
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
// *** sort functions ***
|
|
159
|
+
// regex used in natural sort
|
|
160
|
+
// chunk/tokenize numbers & letters
|
|
161
|
+
chunk : /(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,
|
|
162
|
+
// replace chunks @ ends
|
|
163
|
+
chunks : /(^\\0|\\0$)/,
|
|
164
|
+
hex : /^0x[0-9a-f]+$/i,
|
|
165
|
+
|
|
166
|
+
// *** formatFloat ***
|
|
167
|
+
comma : /,/g,
|
|
168
|
+
digitNonUS : /[\s|\.]/g,
|
|
169
|
+
digitNegativeTest : /^\s*\([.\d]+\)/,
|
|
170
|
+
digitNegativeReplace : /^\s*\(([.\d]+)\)/,
|
|
171
|
+
|
|
172
|
+
// *** isDigit ***
|
|
173
|
+
digitTest : /^[\-+(]?\d+[)]?$/,
|
|
174
|
+
digitReplace : /[,.'"\s]/g
|
|
161
175
|
|
|
162
|
-
|
|
163
|
-
ts.instanceMethods = {};
|
|
176
|
+
},
|
|
164
177
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
// digit sort text location; keeping max+/- for backwards compatibility
|
|
179
|
+
string : {
|
|
180
|
+
max : 1,
|
|
181
|
+
min : -1,
|
|
182
|
+
emptymin : 1,
|
|
183
|
+
emptymax : -1,
|
|
184
|
+
zero : 0,
|
|
185
|
+
none : 0,
|
|
186
|
+
'null' : 0,
|
|
187
|
+
top : true,
|
|
188
|
+
bottom : false
|
|
189
|
+
},
|
|
173
190
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
var te,
|
|
177
|
-
t = c.textExtraction || '',
|
|
178
|
-
// node could be a jquery object
|
|
179
|
-
// http://jsperf.com/jquery-vs-instanceof-jquery/2
|
|
180
|
-
$node = node.jquery ? node : $(node);
|
|
181
|
-
if (typeof t === 'string') {
|
|
182
|
-
// check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
|
|
183
|
-
// http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
|
|
184
|
-
if ( t === 'basic' && typeof ( te = $node.attr(c.textAttribute) ) !== 'undefined' ) {
|
|
185
|
-
return $.trim( te );
|
|
186
|
-
}
|
|
187
|
-
return $.trim( node.textContent || $node.text() );
|
|
188
|
-
} else {
|
|
189
|
-
if (typeof t === 'function') {
|
|
190
|
-
return $.trim( t($node[0], c.table, cellIndex) );
|
|
191
|
-
} else if (typeof (te = ts.getColumnData( c.table, t, cellIndex )) === 'function') {
|
|
192
|
-
return $.trim( te($node[0], c.table, cellIndex) );
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// fallback
|
|
196
|
-
return $.trim( $node[0].textContent || $node.text() );
|
|
197
|
-
};
|
|
191
|
+
// These methods can be applied on table.config instance
|
|
192
|
+
instanceMethods : {},
|
|
198
193
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
console.log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"');
|
|
213
|
-
}
|
|
194
|
+
/*
|
|
195
|
+
▄█████ ██████ ██████ ██ ██ █████▄
|
|
196
|
+
▀█▄ ██▄▄ ██ ██ ██ ██▄▄██
|
|
197
|
+
▀█▄ ██▀▀ ██ ██ ██ ██▀▀▀
|
|
198
|
+
█████▀ ██████ ██ ▀████▀ ██
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
setup : function( table, c ) {
|
|
202
|
+
// if no thead or tbody, or tablesorter is already present, quit
|
|
203
|
+
if ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {
|
|
204
|
+
if ( c.debug ) {
|
|
205
|
+
if ( table.hasInitialized ) {
|
|
206
|
+
console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
|
|
214
207
|
} else {
|
|
215
|
-
|
|
208
|
+
console.error( 'Stopping initialization! No table, thead or tbody' );
|
|
216
209
|
}
|
|
217
210
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
var tmp = '',
|
|
215
|
+
$table = $( table ),
|
|
216
|
+
meta = $.metadata;
|
|
217
|
+
// initialization flag
|
|
218
|
+
table.hasInitialized = false;
|
|
219
|
+
// table is being processed flag
|
|
220
|
+
table.isProcessing = true;
|
|
221
|
+
// make sure to store the config object
|
|
222
|
+
table.config = c;
|
|
223
|
+
// save the settings where they read
|
|
224
|
+
$.data( table, 'tablesorter', c );
|
|
225
|
+
if ( c.debug ) {
|
|
226
|
+
console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter' );
|
|
227
|
+
$.data( table, 'startoveralltimer', new Date() );
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// removing this in version 3 (only supports jQuery 1.7+)
|
|
231
|
+
c.supportsDataObject = ( function( version ) {
|
|
232
|
+
version[ 0 ] = parseInt( version[ 0 ], 10 );
|
|
233
|
+
return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );
|
|
234
|
+
})( $.fn.jquery.split( '.' ) );
|
|
235
|
+
// ensure case insensitivity
|
|
236
|
+
c.emptyTo = c.emptyTo.toLowerCase();
|
|
237
|
+
c.stringTo = c.stringTo.toLowerCase();
|
|
238
|
+
c.last = { sortList : [], clickedIndex : -1 };
|
|
239
|
+
// add table theme class only if there isn't already one there
|
|
240
|
+
if ( !/tablesorter\-/.test( $table.attr( 'class' ) ) ) {
|
|
241
|
+
tmp = ( c.theme !== '' ? ' tablesorter-' + c.theme : '' );
|
|
242
|
+
}
|
|
243
|
+
c.table = table;
|
|
244
|
+
c.$table = $table
|
|
245
|
+
.addClass( ts.css.table + ' ' + c.tableClass + tmp )
|
|
246
|
+
.attr( 'role', 'grid' );
|
|
247
|
+
c.$headers = $table.find( c.selectorHeaders );
|
|
248
|
+
|
|
249
|
+
// give the table a unique id, which will be used in namespace binding
|
|
250
|
+
if ( !c.namespace ) {
|
|
251
|
+
c.namespace = '.tablesorter' + Math.random().toString( 16 ).slice( 2 );
|
|
252
|
+
} else {
|
|
253
|
+
// make sure namespace starts with a period & doesn't have weird characters
|
|
254
|
+
c.namespace = '.' + c.namespace.replace( ts.regex.nonWord, '' );
|
|
227
255
|
}
|
|
228
256
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
257
|
+
c.$table.children().children( 'tr' ).attr( 'role', 'row' );
|
|
258
|
+
c.$tbodies = $table.children( 'tbody:not(.' + c.cssInfoBlock + ')' ).attr({
|
|
259
|
+
'aria-live' : 'polite',
|
|
260
|
+
'aria-relevant' : 'all'
|
|
261
|
+
});
|
|
262
|
+
if ( c.$table.children( 'caption' ).length ) {
|
|
263
|
+
tmp = c.$table.children( 'caption' )[ 0 ];
|
|
264
|
+
if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + 'caption'; }
|
|
265
|
+
c.$table.attr( 'aria-labelledby', tmp.id );
|
|
266
|
+
}
|
|
267
|
+
c.widgetInit = {}; // keep a list of initialized widgets
|
|
268
|
+
// change textExtraction via data-attribute
|
|
269
|
+
c.textExtraction = c.$table.attr( 'data-text-extraction' ) || c.textExtraction || 'basic';
|
|
270
|
+
// build headers
|
|
271
|
+
ts.buildHeaders( c );
|
|
272
|
+
// fixate columns if the users supplies the fixedWidth option
|
|
273
|
+
// do this after theme has been applied
|
|
274
|
+
ts.fixColumnWidth( table );
|
|
275
|
+
// add widgets from class name
|
|
276
|
+
ts.addWidgetFromClass( table );
|
|
277
|
+
// add widget options before parsing (e.g. grouping widget has parser settings)
|
|
278
|
+
ts.applyWidgetOptions( table );
|
|
279
|
+
// try to auto detect column type, and store in tables config
|
|
280
|
+
ts.setupParsers( c );
|
|
281
|
+
// start total row count at zero
|
|
282
|
+
c.totalRows = 0;
|
|
283
|
+
// build the cache for the tbody cells
|
|
284
|
+
// delayInit will delay building the cache until the user starts a sort
|
|
285
|
+
if ( !c.delayInit ) { ts.buildCache( c ); }
|
|
286
|
+
// bind all header events and methods
|
|
287
|
+
ts.bindEvents( table, c.$headers, true );
|
|
288
|
+
ts.bindMethods( c );
|
|
289
|
+
// get sort list from jQuery data or metadata
|
|
290
|
+
// in jQuery < 1.4, an error occurs when calling $table.data()
|
|
291
|
+
if ( c.supportsDataObject && typeof $table.data().sortlist !== 'undefined' ) {
|
|
292
|
+
c.sortList = $table.data().sortlist;
|
|
293
|
+
} else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {
|
|
294
|
+
c.sortList = $table.metadata().sortlist;
|
|
295
|
+
}
|
|
296
|
+
// apply widget init code
|
|
297
|
+
ts.applyWidget( table, true );
|
|
298
|
+
// if user has supplied a sort list to constructor
|
|
299
|
+
if ( c.sortList.length > 0 ) {
|
|
300
|
+
ts.sortOn( c, c.sortList, {}, !c.initWidgets );
|
|
301
|
+
} else {
|
|
302
|
+
ts.setHeadersCss( c );
|
|
303
|
+
if ( c.initWidgets ) {
|
|
304
|
+
// apply widget format
|
|
305
|
+
ts.applyWidget( table, false );
|
|
233
306
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
parser.format( '' + txt, c.table, cell, colIndex );
|
|
248
|
-
if ( c.ignoreCase && typeof val === 'string' ) {
|
|
249
|
-
val = val.toLowerCase();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// show processesing icon
|
|
310
|
+
if ( c.showProcessing ) {
|
|
311
|
+
$table
|
|
312
|
+
.unbind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace )
|
|
313
|
+
.bind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace, function( e ) {
|
|
314
|
+
clearTimeout( c.processTimer );
|
|
315
|
+
ts.isProcessing( table );
|
|
316
|
+
if ( e.type === 'sortBegin' ) {
|
|
317
|
+
c.processTimer = setTimeout( function() {
|
|
318
|
+
ts.isProcessing( table, true );
|
|
319
|
+
}, 500 );
|
|
250
320
|
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// initialized
|
|
325
|
+
table.hasInitialized = true;
|
|
326
|
+
table.isProcessing = false;
|
|
327
|
+
if ( c.debug ) {
|
|
328
|
+
console.log( 'Overall initialization time: ' + ts.benchmark( $.data( table, 'startoveralltimer' ) ) );
|
|
329
|
+
if ( c.debug && console.groupEnd ) { console.groupEnd(); }
|
|
330
|
+
}
|
|
331
|
+
$table.trigger( 'tablesorter-initialized', table );
|
|
332
|
+
if ( typeof c.initialized === 'function' ) {
|
|
333
|
+
c.initialized( table );
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
bindMethods : function( c ) {
|
|
338
|
+
var $table = c.$table,
|
|
339
|
+
namespace = c.namespace,
|
|
340
|
+
events = ( 'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete ' +
|
|
341
|
+
'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup ' +
|
|
342
|
+
'mouseleave ' ).split( ' ' )
|
|
343
|
+
.join( namespace + ' ' );
|
|
344
|
+
// apply easy methods that trigger bound events
|
|
345
|
+
$table
|
|
346
|
+
.unbind( events.replace( ts.regex.spaces, ' ' ) )
|
|
347
|
+
.bind( 'sortReset' + namespace, function( e, callback ) {
|
|
348
|
+
e.stopPropagation();
|
|
349
|
+
// using this.config to ensure functions are getting a non-cached version of the config
|
|
350
|
+
ts.sortReset( this.config, callback );
|
|
351
|
+
})
|
|
352
|
+
.bind( 'updateAll' + namespace, function( e, resort, callback ) {
|
|
353
|
+
e.stopPropagation();
|
|
354
|
+
ts.updateAll( this.config, resort, callback );
|
|
355
|
+
})
|
|
356
|
+
.bind( 'update' + namespace + ' updateRows' + namespace, function( e, resort, callback ) {
|
|
357
|
+
e.stopPropagation();
|
|
358
|
+
ts.update( this.config, resort, callback );
|
|
359
|
+
})
|
|
360
|
+
.bind( 'updateHeaders' + namespace, function( e, callback ) {
|
|
361
|
+
e.stopPropagation();
|
|
362
|
+
ts.updateHeaders( this.config, callback );
|
|
363
|
+
})
|
|
364
|
+
.bind( 'updateCell' + namespace, function( e, cell, resort, callback ) {
|
|
365
|
+
e.stopPropagation();
|
|
366
|
+
ts.updateCell( this.config, cell, resort, callback );
|
|
367
|
+
})
|
|
368
|
+
.bind( 'addRows' + namespace, function( e, $row, resort, callback ) {
|
|
369
|
+
e.stopPropagation();
|
|
370
|
+
ts.addRows( this.config, $row, resort, callback );
|
|
371
|
+
})
|
|
372
|
+
.bind( 'updateComplete' + namespace, function() {
|
|
373
|
+
this.isUpdating = false;
|
|
374
|
+
})
|
|
375
|
+
.bind( 'sorton' + namespace, function( e, list, callback, init ) {
|
|
376
|
+
e.stopPropagation();
|
|
377
|
+
ts.sortOn( this.config, list, callback, init );
|
|
378
|
+
})
|
|
379
|
+
.bind( 'appendCache' + namespace, function( e, callback, init ) {
|
|
380
|
+
e.stopPropagation();
|
|
381
|
+
ts.appendCache( this.config, init );
|
|
382
|
+
if ( $.isFunction( callback ) ) {
|
|
383
|
+
callback( this );
|
|
384
|
+
}
|
|
385
|
+
})
|
|
386
|
+
// $tbodies variable is used by the tbody sorting widget
|
|
387
|
+
.bind( 'updateCache' + namespace, function( e, callback, $tbodies ) {
|
|
388
|
+
e.stopPropagation();
|
|
389
|
+
ts.updateCache( this.config, callback, $tbodies );
|
|
390
|
+
})
|
|
391
|
+
.bind( 'applyWidgetId' + namespace, function( e, id ) {
|
|
392
|
+
e.stopPropagation();
|
|
393
|
+
ts.getWidgetById( id ).format( this, this.config, this.config.widgetOptions );
|
|
394
|
+
})
|
|
395
|
+
.bind( 'applyWidgets' + namespace, function( e, init ) {
|
|
396
|
+
e.stopPropagation();
|
|
397
|
+
// apply widgets
|
|
398
|
+
ts.applyWidget( this, init );
|
|
399
|
+
})
|
|
400
|
+
.bind( 'refreshWidgets' + namespace, function( e, all, dontapply ) {
|
|
401
|
+
e.stopPropagation();
|
|
402
|
+
ts.refreshWidgets( this, all, dontapply );
|
|
403
|
+
})
|
|
404
|
+
.bind( 'destroy' + namespace, function( e, removeClasses, callback ) {
|
|
405
|
+
e.stopPropagation();
|
|
406
|
+
ts.destroy( this, removeClasses, callback );
|
|
407
|
+
})
|
|
408
|
+
.bind( 'resetToLoadState' + namespace, function( e ) {
|
|
409
|
+
e.stopPropagation();
|
|
410
|
+
// remove all widgets
|
|
411
|
+
ts.removeWidget( this, true, false );
|
|
412
|
+
// restore original settings; this clears out current settings, but does not clear
|
|
413
|
+
// values saved to storage.
|
|
414
|
+
c = $.extend( true, ts.defaults, c.originalSettings );
|
|
415
|
+
this.hasInitialized = false;
|
|
416
|
+
// setup the entire table again
|
|
417
|
+
ts.setup( this, c );
|
|
418
|
+
});
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
bindEvents : function( table, $headers, core ) {
|
|
422
|
+
table = $( table )[ 0 ];
|
|
423
|
+
var tmp,
|
|
424
|
+
c = table.config,
|
|
425
|
+
namespace = c.namespace,
|
|
426
|
+
downTarget = null;
|
|
427
|
+
if ( core !== true ) {
|
|
428
|
+
$headers.addClass( namespace.slice( 1 ) + '_extra_headers' );
|
|
429
|
+
tmp = $.fn.closest ? $headers.closest( 'table' )[ 0 ] : $headers.parents( 'table' )[ 0 ];
|
|
430
|
+
if ( tmp && tmp.nodeName === 'TABLE' && tmp !== table ) {
|
|
431
|
+
$( tmp ).addClass( namespace.slice( 1 ) + '_extra_table' );
|
|
251
432
|
}
|
|
252
|
-
|
|
253
|
-
|
|
433
|
+
}
|
|
434
|
+
tmp = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
|
|
435
|
+
.replace( ts.regex.spaces, ' ' )
|
|
436
|
+
.split( ' ' )
|
|
437
|
+
.join( namespace + ' ' );
|
|
438
|
+
// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
|
|
439
|
+
$headers
|
|
440
|
+
// http://stackoverflow.com/questions/5312849/jquery-find-self;
|
|
441
|
+
.find( c.selectorSort )
|
|
442
|
+
.add( $headers.filter( c.selectorSort ) )
|
|
443
|
+
.unbind( tmp )
|
|
444
|
+
.bind( tmp, function( e, external ) {
|
|
445
|
+
var $cell, cell, temp,
|
|
446
|
+
$target = $( e.target ),
|
|
447
|
+
// wrap event type in spaces, so the match doesn't trigger on inner words
|
|
448
|
+
type = ' ' + e.type + ' ';
|
|
449
|
+
// only recognize left clicks
|
|
450
|
+
if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) ||
|
|
451
|
+
// allow pressing enter
|
|
452
|
+
( type === ' keyup ' && e.which !== 13 ) ||
|
|
453
|
+
// allow triggering a click event (e.which is undefined) & ignore physical clicks
|
|
454
|
+
( type.match( ' ' + c.pointerClick + ' ' ) && typeof e.which !== 'undefined' ) ) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
// ignore mouseup if mousedown wasn't on the same target
|
|
458
|
+
if ( type.match( ' ' + c.pointerUp + ' ' ) && downTarget !== e.target && external !== true ) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
// set target on mousedown
|
|
462
|
+
if ( type.match( ' ' + c.pointerDown + ' ' ) ) {
|
|
463
|
+
downTarget = e.target;
|
|
464
|
+
// preventDefault needed or jQuery v1.3.2 and older throws an
|
|
465
|
+
// "Uncaught TypeError: handler.apply is not a function" error
|
|
466
|
+
temp = $target.jquery.split( '.' );
|
|
467
|
+
if ( temp[ 0 ] === '1' && temp[ 1 ] < 4 ) { e.preventDefault(); }
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
downTarget = null;
|
|
471
|
+
// prevent sort being triggered on form elements
|
|
472
|
+
if ( ts.regex.formElements.test( e.target.nodeName ) ||
|
|
473
|
+
// nosort class name, or elements within a nosort container
|
|
474
|
+
$target.hasClass( c.cssNoSort ) || $target.parents( '.' + c.cssNoSort ).length > 0 ||
|
|
475
|
+
// elements within a button
|
|
476
|
+
$target.parents( 'button' ).length > 0 ) {
|
|
477
|
+
return !c.cancelSelection;
|
|
478
|
+
}
|
|
479
|
+
if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
|
|
480
|
+
ts.buildCache( c );
|
|
481
|
+
}
|
|
482
|
+
// jQuery v1.2.6 doesn't have closest()
|
|
483
|
+
$cell = $.fn.closest ? $( this ).closest( 'th, td' ) :
|
|
484
|
+
/TH|TD/.test( this.nodeName ) ? $( this ) : $( this ).parents( 'th, td' );
|
|
485
|
+
// reference original table headers and find the same cell
|
|
486
|
+
// don't use $headers or IE8 throws an error - see #987
|
|
487
|
+
temp = $headers.index( $cell );
|
|
488
|
+
c.last.clickedIndex = ( temp < 0 ) ? $cell.attr( 'data-column' ) : temp;
|
|
489
|
+
// use column index if $headers is undefined
|
|
490
|
+
cell = c.$headers[ c.last.clickedIndex ];
|
|
491
|
+
if ( cell && !cell.sortDisabled ) {
|
|
492
|
+
ts.initSort( c, cell, e );
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
if ( c.cancelSelection ) {
|
|
496
|
+
// cancel selection
|
|
497
|
+
$headers
|
|
498
|
+
.attr( 'unselectable', 'on' )
|
|
499
|
+
.bind( 'selectstart', false )
|
|
500
|
+
.css({
|
|
501
|
+
'user-select' : 'none',
|
|
502
|
+
'MozUserSelect' : 'none' // not needed for jQuery 1.8+
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
},
|
|
254
506
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
507
|
+
buildHeaders : function( c ) {
|
|
508
|
+
var $temp, icon, timer, indx;
|
|
509
|
+
c.headerList = [];
|
|
510
|
+
c.headerContent = [];
|
|
511
|
+
c.sortVars = [];
|
|
512
|
+
if ( c.debug ) {
|
|
513
|
+
timer = new Date();
|
|
514
|
+
}
|
|
515
|
+
// children tr in tfoot - see issue #196 & #547
|
|
516
|
+
c.columns = ts.computeColumnIndex( c.$table.children( 'thead, tfoot' ).children( 'tr' ) );
|
|
517
|
+
// add icon if cssIcon option exists
|
|
518
|
+
icon = c.cssIcon ?
|
|
519
|
+
'<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' :
|
|
520
|
+
'';
|
|
521
|
+
// redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
|
|
522
|
+
c.$headers = $( $.map( c.$table.find( c.selectorHeaders ), function( elem, index ) {
|
|
523
|
+
var configHeaders, header, column, template, tmp,
|
|
524
|
+
$elem = $( elem );
|
|
525
|
+
// ignore cell (don't add it to c.$headers) if row has ignoreRow class
|
|
526
|
+
if ( $elem.parent().hasClass( c.cssIgnoreRow ) ) { return; }
|
|
527
|
+
// make sure to get header cell & not column indexed cell
|
|
528
|
+
configHeaders = ts.getColumnData( c.table, c.headers, index, true );
|
|
529
|
+
// save original header content
|
|
530
|
+
c.headerContent[ index ] = $elem.html();
|
|
531
|
+
// if headerTemplate is empty, don't reformat the header cell
|
|
532
|
+
if ( c.headerTemplate !== '' && !$elem.find( '.' + ts.css.headerIn ).length ) {
|
|
533
|
+
// set up header template
|
|
534
|
+
template = c.headerTemplate
|
|
535
|
+
.replace( ts.regex.templateContent, $elem.html() )
|
|
536
|
+
.replace( ts.regex.templateIcon, $elem.find( '.' + ts.css.icon ).length ? '' : icon );
|
|
537
|
+
if ( c.onRenderTemplate ) {
|
|
538
|
+
header = c.onRenderTemplate.apply( $elem, [ index, template ] );
|
|
539
|
+
// only change t if something is returned
|
|
540
|
+
if ( header && typeof header === 'string' ) {
|
|
541
|
+
template = header;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
$elem.html( '<div class="' + ts.css.headerIn + '">' + template + '</div>' ); // faster than wrapInner
|
|
545
|
+
}
|
|
546
|
+
if ( c.onRenderHeader ) {
|
|
547
|
+
c.onRenderHeader.apply( $elem, [ index, c, c.$table ] );
|
|
548
|
+
}
|
|
549
|
+
column = parseInt( $elem.attr( 'data-column' ), 10 );
|
|
550
|
+
elem.column = column;
|
|
551
|
+
tmp = ts.getData( $elem, configHeaders, 'sortInitialOrder' ) || c.sortInitialOrder;
|
|
552
|
+
// this may get updated numerous times if there are multiple rows
|
|
553
|
+
c.sortVars[ column ] = {
|
|
554
|
+
count : -1, // set to -1 because clicking on the header automatically adds one
|
|
555
|
+
order: ts.formatSortingOrder( tmp ) ?
|
|
556
|
+
[ 1, 0, 2 ] : // desc, asc, unsorted
|
|
557
|
+
[ 0, 1, 2 ], // asc, desc, unsorted
|
|
558
|
+
lockedOrder : false
|
|
273
559
|
};
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
560
|
+
tmp = ts.getData( $elem, configHeaders, 'lockedOrder' ) || false;
|
|
561
|
+
if ( typeof tmp !== 'undefined' && tmp !== false ) {
|
|
562
|
+
c.sortVars[ column ].lockedOrder = true;
|
|
563
|
+
c.sortVars[ column ].order = ts.formatSortingOrder( tmp ) ? [ 1, 1, 1 ] : [ 0, 0, 0 ];
|
|
564
|
+
}
|
|
565
|
+
// add cell to headerList
|
|
566
|
+
c.headerList[ index ] = elem;
|
|
567
|
+
// add to parent in case there are multiple rows
|
|
568
|
+
$elem
|
|
569
|
+
.addClass( ts.css.header + ' ' + c.cssHeader )
|
|
570
|
+
.parent()
|
|
571
|
+
.addClass( ts.css.headerRow + ' ' + c.cssHeaderRow )
|
|
572
|
+
.attr( 'role', 'row' );
|
|
573
|
+
// allow keyboard cursor to focus on element
|
|
574
|
+
if ( c.tabIndex ) {
|
|
575
|
+
$elem.attr( 'tabindex', 0 );
|
|
576
|
+
}
|
|
577
|
+
return elem;
|
|
578
|
+
}) );
|
|
579
|
+
// cache headers per column
|
|
580
|
+
c.$headerIndexed = [];
|
|
581
|
+
for ( indx = 0; indx < c.columns; indx++ ) {
|
|
582
|
+
// colspan in header making a column undefined
|
|
583
|
+
if ( ts.isEmptyObject( c.sortVars[ indx ] ) ) {
|
|
584
|
+
c.sortVars[ indx ] = {};
|
|
585
|
+
}
|
|
586
|
+
$temp = c.$headers.filter( '[data-column="' + indx + '"]' );
|
|
587
|
+
// target sortable column cells, unless there are none, then use non-sortable cells
|
|
588
|
+
// .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
|
|
589
|
+
c.$headerIndexed[ indx ] = $temp.length ?
|
|
590
|
+
$temp.not( '.sorter-false' ).length ?
|
|
591
|
+
$temp.not( '.sorter-false' ).filter( ':last' ) :
|
|
592
|
+
$temp.filter( ':last' ) :
|
|
593
|
+
$();
|
|
594
|
+
}
|
|
595
|
+
c.$table.find( c.selectorHeaders ).attr({
|
|
596
|
+
scope: 'col',
|
|
597
|
+
role : 'columnheader'
|
|
598
|
+
});
|
|
599
|
+
// enable/disable sorting
|
|
600
|
+
ts.updateHeader( c );
|
|
601
|
+
if ( c.debug ) {
|
|
602
|
+
console.log( 'Built headers:' + ts.benchmark( timer ) );
|
|
603
|
+
console.log( c.$headers );
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
// Use it to add a set of methods to table.config which will be available for all tables.
|
|
608
|
+
// This should be done before table initialization
|
|
609
|
+
addInstanceMethods : function( methods ) {
|
|
610
|
+
$.extend( ts.instanceMethods, methods );
|
|
611
|
+
},
|
|
612
|
+
|
|
613
|
+
/*
|
|
614
|
+
█████▄ ▄████▄ █████▄ ▄█████ ██████ █████▄ ▄█████
|
|
615
|
+
██▄▄██ ██▄▄██ ██▄▄██ ▀█▄ ██▄▄ ██▄▄██ ▀█▄
|
|
616
|
+
██▀▀▀ ██▀▀██ ██▀██ ▀█▄ ██▀▀ ██▀██ ▀█▄
|
|
617
|
+
██ ██ ██ ██ ██ █████▀ ██████ ██ ██ █████▀
|
|
618
|
+
*/
|
|
619
|
+
setupParsers : function( c, $tbodies ) {
|
|
620
|
+
var rows, list, span, max, colIndex, indx, header, configHeaders,
|
|
621
|
+
noParser, parser, extractor, time, tbody, len,
|
|
622
|
+
table = c.table,
|
|
623
|
+
tbodyIndex = 0,
|
|
624
|
+
debug = {};
|
|
625
|
+
// update table bodies in case we start with an empty table
|
|
626
|
+
c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
|
|
627
|
+
tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies;
|
|
628
|
+
len = tbody.length;
|
|
629
|
+
if ( len === 0 ) {
|
|
630
|
+
return c.debug ? console.warn( 'Warning: *Empty table!* Not building a parser cache' ) : '';
|
|
631
|
+
} else if ( c.debug ) {
|
|
632
|
+
time = new Date();
|
|
633
|
+
console[ console.group ? 'group' : 'log' ]( 'Detecting parsers for each column' );
|
|
634
|
+
}
|
|
635
|
+
list = {
|
|
636
|
+
extractors: [],
|
|
637
|
+
parsers: []
|
|
638
|
+
};
|
|
639
|
+
while ( tbodyIndex < len ) {
|
|
640
|
+
rows = tbody[ tbodyIndex ].rows;
|
|
641
|
+
if ( rows.length ) {
|
|
642
|
+
colIndex = 0;
|
|
643
|
+
max = c.columns;
|
|
644
|
+
for ( indx = 0; indx < max; indx++ ) {
|
|
645
|
+
header = c.$headerIndexed[ colIndex ];
|
|
646
|
+
if ( header && header.length ) {
|
|
280
647
|
// get column indexed table cell
|
|
281
|
-
|
|
648
|
+
configHeaders = ts.getColumnData( table, c.headers, colIndex );
|
|
282
649
|
// get column parser/extractor
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
650
|
+
extractor = ts.getParserById( ts.getData( header, configHeaders, 'extractor' ) );
|
|
651
|
+
parser = ts.getParserById( ts.getData( header, configHeaders, 'sorter' ) );
|
|
652
|
+
noParser = ts.getData( header, configHeaders, 'parser' ) === 'false';
|
|
286
653
|
// empty cells behaviour - keeping emptyToBottom for backwards compatibility
|
|
287
|
-
c.empties[
|
|
654
|
+
c.empties[colIndex] = (
|
|
655
|
+
ts.getData( header, configHeaders, 'empty' ) ||
|
|
656
|
+
c.emptyTo || ( c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase();
|
|
288
657
|
// text strings behaviour in numerical sorts
|
|
289
|
-
c.strings[
|
|
290
|
-
|
|
291
|
-
|
|
658
|
+
c.strings[colIndex] = (
|
|
659
|
+
ts.getData( header, configHeaders, 'string' ) ||
|
|
660
|
+
c.stringTo ||
|
|
661
|
+
'max' ).toLowerCase();
|
|
662
|
+
if ( noParser ) {
|
|
663
|
+
parser = ts.getParserById( 'no-parser' );
|
|
292
664
|
}
|
|
293
|
-
if (!
|
|
665
|
+
if ( !extractor ) {
|
|
294
666
|
// For now, maybe detect someday
|
|
295
|
-
|
|
667
|
+
extractor = false;
|
|
296
668
|
}
|
|
297
|
-
if (!
|
|
298
|
-
|
|
669
|
+
if ( !parser ) {
|
|
670
|
+
parser = ts.detectParserForColumn( c, rows, -1, colIndex );
|
|
299
671
|
}
|
|
300
|
-
if (c.debug) {
|
|
301
|
-
debug[ '(' +
|
|
302
|
-
parser :
|
|
303
|
-
extractor :
|
|
304
|
-
string : c.strings[
|
|
305
|
-
empty : c.empties[
|
|
672
|
+
if ( c.debug ) {
|
|
673
|
+
debug[ '(' + colIndex + ') ' + header.text() ] = {
|
|
674
|
+
parser : parser.id,
|
|
675
|
+
extractor : extractor ? extractor.id : 'none',
|
|
676
|
+
string : c.strings[ colIndex ],
|
|
677
|
+
empty : c.empties[ colIndex ]
|
|
306
678
|
};
|
|
307
679
|
}
|
|
308
|
-
list.parsers[
|
|
309
|
-
list.extractors[
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if ( c.debug ) {
|
|
315
|
-
if ( !ts.isEmptyObject( debug ) ) {
|
|
316
|
-
console[ console.table ? 'table' : 'log' ]( debug );
|
|
317
|
-
} else {
|
|
318
|
-
console.warn( ' No parsers detected!' );
|
|
319
|
-
}
|
|
320
|
-
console.log( 'Completed detecting parsers' + ts.benchmark( time ) );
|
|
321
|
-
if ( console.groupEnd ) { console.groupEnd(); }
|
|
322
|
-
}
|
|
323
|
-
c.parsers = list.parsers;
|
|
324
|
-
c.extractors = list.extractors;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/* utils */
|
|
328
|
-
function buildCache(table, callback, $tbodies) {
|
|
329
|
-
var cc, t, v, i, j, k, $tb, $row, cols, cacheTime,
|
|
330
|
-
totalRows, rowData, prevRowData, colMax,
|
|
331
|
-
c = table.config,
|
|
332
|
-
parsers = c.parsers;
|
|
333
|
-
// update tbody variable
|
|
334
|
-
c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')');
|
|
335
|
-
$tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
|
|
336
|
-
c.cache = {};
|
|
337
|
-
c.totalRows = 0;
|
|
338
|
-
// if no parsers found, return - it's an empty table.
|
|
339
|
-
if (!parsers) {
|
|
340
|
-
return c.debug ? console.warn('Warning: *Empty table!* Not building a cache') : '';
|
|
341
|
-
}
|
|
342
|
-
if (c.debug) {
|
|
343
|
-
cacheTime = new Date();
|
|
344
|
-
}
|
|
345
|
-
// processing icon
|
|
346
|
-
if (c.showProcessing) {
|
|
347
|
-
ts.isProcessing(table, true);
|
|
348
|
-
}
|
|
349
|
-
for (k = 0; k < $tb.length; k++) {
|
|
350
|
-
colMax = []; // column max value per tbody
|
|
351
|
-
cc = c.cache[k] = {
|
|
352
|
-
normalized: [] // array of normalized row data; last entry contains 'rowData' above
|
|
353
|
-
// colMax: # // added at the end
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
totalRows = ($tb[k] && $tb[k].rows.length) || 0;
|
|
357
|
-
for (i = 0; i < totalRows; ++i) {
|
|
358
|
-
rowData = {
|
|
359
|
-
// order: original row order #
|
|
360
|
-
// $row : jQuery Object[]
|
|
361
|
-
child: [], // child row text (filter widget)
|
|
362
|
-
raw: [] // original row text
|
|
363
|
-
};
|
|
364
|
-
/** Add the table data to main data array */
|
|
365
|
-
$row = $( $tb[ k ].rows[ i ] );
|
|
366
|
-
cols = [];
|
|
367
|
-
// if this is a child row, add it to the last row's children and continue to the next row
|
|
368
|
-
// ignore child row class, if it is the first row
|
|
369
|
-
if ( $row.hasClass( c.cssChildRow ) && i !== 0 ) {
|
|
370
|
-
t = cc.normalized.length - 1;
|
|
371
|
-
prevRowData = cc.normalized[ t ][ c.columns ];
|
|
372
|
-
prevRowData.$row = prevRowData.$row.add( $row );
|
|
373
|
-
// add 'hasChild' class name to parent row
|
|
374
|
-
if ( !$row.prev().hasClass( c.cssChildRow ) ) {
|
|
375
|
-
$row.prev().addClass( ts.css.cssHasChild );
|
|
376
|
-
}
|
|
377
|
-
// save child row content (un-parsed!)
|
|
378
|
-
v = $row.children( 'th, td' );
|
|
379
|
-
t = prevRowData.child.length;
|
|
380
|
-
prevRowData.child[ t ] = [];
|
|
381
|
-
// child row content does not account for colspans/rowspans; so indexing may be off
|
|
382
|
-
for ( j = 0; j < c.columns; j++ ) {
|
|
383
|
-
prevRowData.child[ t ][ j ] = ts.getParsedText( c, v[ j ], j );
|
|
384
|
-
}
|
|
385
|
-
// go to the next for loop
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
rowData.$row = $row;
|
|
389
|
-
rowData.order = i; // add original row position to rowCache
|
|
390
|
-
for ( j = 0; j < c.columns; ++j ) {
|
|
391
|
-
if (typeof parsers[ j ] === 'undefined') {
|
|
392
|
-
if ( c.debug ) {
|
|
393
|
-
console.warn( 'No parser found for cell:', $row[ 0 ].cells[ j ], 'does it have a header?' );
|
|
394
|
-
}
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
t = ts.getElementText( c, $row[ 0 ].cells[j], j );
|
|
398
|
-
rowData.raw.push( t ); // save original row text
|
|
399
|
-
v = ts.getParsedText( c, $row[ 0 ].cells[ j ], j, t );
|
|
400
|
-
cols.push( v );
|
|
401
|
-
if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
|
|
402
|
-
// determine column max value (ignore sign)
|
|
403
|
-
colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 );
|
|
680
|
+
list.parsers[ colIndex ] = parser;
|
|
681
|
+
list.extractors[ colIndex ] = extractor;
|
|
682
|
+
span = header[ 0 ].colSpan - 1;
|
|
683
|
+
if ( span > 0 ) {
|
|
684
|
+
colIndex += span;
|
|
685
|
+
max += span;
|
|
404
686
|
}
|
|
405
687
|
}
|
|
406
|
-
|
|
407
|
-
cols[ c.columns ] = rowData;
|
|
408
|
-
cc.normalized.push( cols );
|
|
688
|
+
colIndex++;
|
|
409
689
|
}
|
|
410
|
-
cc.colMax = colMax;
|
|
411
|
-
// total up rows, not including child rows
|
|
412
|
-
c.totalRows += cc.normalized.length;
|
|
413
|
-
|
|
414
690
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
if (
|
|
419
|
-
console.
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
callback( table );
|
|
691
|
+
tbodyIndex += ( list.parsers.length ) ? len : 1;
|
|
692
|
+
}
|
|
693
|
+
if ( c.debug ) {
|
|
694
|
+
if ( !ts.isEmptyObject( debug ) ) {
|
|
695
|
+
console[ console.table ? 'table' : 'log' ]( debug );
|
|
696
|
+
} else {
|
|
697
|
+
console.warn( ' No parsers detected!' );
|
|
423
698
|
}
|
|
699
|
+
console.log( 'Completed detecting parsers' + ts.benchmark( time ) );
|
|
700
|
+
if ( console.groupEnd ) { console.groupEnd(); }
|
|
424
701
|
}
|
|
702
|
+
c.parsers = list.parsers;
|
|
703
|
+
c.extractors = list.extractors;
|
|
704
|
+
},
|
|
425
705
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
c.headerList = [];
|
|
434
|
-
c.headerContent = [];
|
|
435
|
-
if (c.debug) {
|
|
436
|
-
time = new Date();
|
|
437
|
-
}
|
|
438
|
-
// children tr in tfoot - see issue #196 & #547
|
|
439
|
-
c.columns = ts.computeColumnIndex( c.$table.children('thead, tfoot').children('tr') );
|
|
440
|
-
// add icon if cssIcon option exists
|
|
441
|
-
i = c.cssIcon ? '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' : '';
|
|
442
|
-
// redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
|
|
443
|
-
c.$headers = $( $.map( c.$table.find(c.selectorHeaders), function(elem, index) {
|
|
444
|
-
$t = $(elem);
|
|
445
|
-
// ignore cell (don't add it to c.$headers) if row has ignoreRow class
|
|
446
|
-
if ($t.parent().hasClass(c.cssIgnoreRow)) { return; }
|
|
447
|
-
// make sure to get header cell & not column indexed cell
|
|
448
|
-
ch = ts.getColumnData( c.table, c.headers, index, true );
|
|
449
|
-
// save original header content
|
|
450
|
-
c.headerContent[index] = $t.html();
|
|
451
|
-
// if headerTemplate is empty, don't reformat the header cell
|
|
452
|
-
if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) {
|
|
453
|
-
// set up header template
|
|
454
|
-
t = c.headerTemplate
|
|
455
|
-
.replace(ts.regex.templateContent, $t.html())
|
|
456
|
-
.replace(ts.regex.templateIcon, $t.find('.' + ts.css.icon).length ? '' : i);
|
|
457
|
-
if (c.onRenderTemplate) {
|
|
458
|
-
h = c.onRenderTemplate.apply( $t, [ index, t ] );
|
|
459
|
-
if (h && typeof h === 'string') { t = h; } // only change t if something is returned
|
|
460
|
-
}
|
|
461
|
-
$t.html('<div class="' + ts.css.headerIn + '">' + t + '</div>'); // faster than wrapInner
|
|
462
|
-
}
|
|
463
|
-
if (c.onRenderHeader) { c.onRenderHeader.apply( $t, [ index, c, c.$table ] ); }
|
|
464
|
-
// *** remove this.column value if no conflicts found
|
|
465
|
-
elem.column = parseInt( $t.attr('data-column'), 10);
|
|
466
|
-
elem.order = formatSortingOrder( ts.getData( $t, ch, 'sortInitialOrder' ) || c.sortInitialOrder ) ?
|
|
467
|
-
[ 1, 0, 2 ] : // desc, asc, unsorted
|
|
468
|
-
[ 0, 1, 2 ]; // asc, desc, unsorted
|
|
469
|
-
elem.count = -1; // set to -1 because clicking on the header automatically adds one
|
|
470
|
-
elem.lockedOrder = false;
|
|
471
|
-
lock = ts.getData($t, ch, 'lockedOrder') || false;
|
|
472
|
-
if (typeof lock !== 'undefined' && lock !== false) {
|
|
473
|
-
elem.order = elem.lockedOrder = formatSortingOrder(lock) ? [ 1, 1, 1 ] : [ 0, 0, 0 ];
|
|
474
|
-
}
|
|
475
|
-
$t.addClass(ts.css.header + ' ' + c.cssHeader);
|
|
476
|
-
// add cell to headerList
|
|
477
|
-
c.headerList[index] = elem;
|
|
478
|
-
// add to parent in case there are multiple rows
|
|
479
|
-
$t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow).attr('role', 'row');
|
|
480
|
-
// allow keyboard cursor to focus on element
|
|
481
|
-
if (c.tabIndex) { $t.attr('tabindex', 0); }
|
|
482
|
-
return elem;
|
|
483
|
-
}));
|
|
484
|
-
// cache headers per column
|
|
485
|
-
c.$headerIndexed = [];
|
|
486
|
-
for (indx = 0; indx < c.columns; indx++) {
|
|
487
|
-
$t = c.$headers.filter('[data-column="' + indx + '"]');
|
|
488
|
-
// target sortable column cells, unless there are none, then use non-sortable cells
|
|
489
|
-
// .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
|
|
490
|
-
c.$headerIndexed[indx] = $t.not('.sorter-false').length ? $t.not('.sorter-false').filter(':last') : $t.filter(':last');
|
|
491
|
-
}
|
|
492
|
-
c.$table.find(c.selectorHeaders).attr({
|
|
493
|
-
scope: 'col',
|
|
494
|
-
role : 'columnheader'
|
|
495
|
-
});
|
|
496
|
-
// enable/disable sorting
|
|
497
|
-
updateHeader(c.table);
|
|
498
|
-
if (c.debug) {
|
|
499
|
-
console.log( 'Built headers:' + ts.benchmark( time ) );
|
|
500
|
-
console.log( c.$headers );
|
|
706
|
+
addParser : function( parser ) {
|
|
707
|
+
var indx,
|
|
708
|
+
len = ts.parsers.length,
|
|
709
|
+
add = true;
|
|
710
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
711
|
+
if ( ts.parsers[ indx ].id.toLowerCase() === parser.id.toLowerCase() ) {
|
|
712
|
+
add = false;
|
|
501
713
|
}
|
|
502
714
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
var c = table.config;
|
|
506
|
-
// remove rows/elements before update
|
|
507
|
-
c.$table.find(c.selectorRemove).remove();
|
|
508
|
-
// rebuild parsers
|
|
509
|
-
buildParserCache(c);
|
|
510
|
-
// rebuild the cache map
|
|
511
|
-
buildCache(table);
|
|
512
|
-
checkResort(c, resort, callback);
|
|
715
|
+
if ( add ) {
|
|
716
|
+
ts.parsers.push( parser );
|
|
513
717
|
}
|
|
718
|
+
},
|
|
514
719
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
isDisabled = ts.getData( $th, col, 'sorter' ) === 'false' || ts.getData( $th, col, 'parser' ) === 'false';
|
|
524
|
-
$th[0].sortDisabled = isDisabled;
|
|
525
|
-
$th[ isDisabled ? 'addClass' : 'removeClass' ]( 'sorter-false' ).attr( 'aria-disabled', '' + isDisabled );
|
|
526
|
-
// disable tab index on disabled cells
|
|
527
|
-
if ( c.tabIndex ) {
|
|
528
|
-
if ( isDisabled ) {
|
|
529
|
-
$th.removeAttr( 'tabindex' );
|
|
530
|
-
} else {
|
|
531
|
-
$th.attr( 'tabindex', '0' );
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
// aria-controls - requires table ID
|
|
535
|
-
if (table.id) {
|
|
536
|
-
if ( isDisabled ) {
|
|
537
|
-
$th.removeAttr('aria-controls');
|
|
538
|
-
} else {
|
|
539
|
-
$th.attr('aria-controls', table.id);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
720
|
+
getParserById : function( name ) {
|
|
721
|
+
/*jshint eqeqeq:false */
|
|
722
|
+
if ( name == 'false' ) { return false; }
|
|
723
|
+
var indx,
|
|
724
|
+
len = ts.parsers.length;
|
|
725
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
726
|
+
if ( ts.parsers[ indx ].id.toLowerCase() === ( name.toString() ).toLowerCase() ) {
|
|
727
|
+
return ts.parsers[ indx ];
|
|
542
728
|
}
|
|
543
729
|
}
|
|
730
|
+
return false;
|
|
731
|
+
},
|
|
544
732
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
.removeClass(css.join(' '))
|
|
561
|
-
.addClass(none).attr('aria-sort', 'none')
|
|
562
|
-
.find('.' + ts.css.icon)
|
|
563
|
-
.removeClass(cssIcon.join(' '))
|
|
564
|
-
.addClass(cssIcon[2]);
|
|
565
|
-
for (i = 0; i < len; i++) {
|
|
566
|
-
// direction = 2 means reset!
|
|
567
|
-
if (list[i][1] !== 2) {
|
|
568
|
-
// multicolumn sorting updating - see #1005
|
|
569
|
-
f = c.lastClickedIndex > 0 ? c.$headers.filter(':gt(' + ( c.lastClickedIndex - 1 ) + ')') : c.$headers;
|
|
570
|
-
// choose the :last in case there are nested columns
|
|
571
|
-
f = f.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (len === 1 ? ':last' : '') );
|
|
572
|
-
if (f.length) {
|
|
573
|
-
for (j = 0; j < f.length; j++) {
|
|
574
|
-
if (!f[j].sortDisabled) {
|
|
575
|
-
f.eq(j)
|
|
576
|
-
.removeClass(none)
|
|
577
|
-
.addClass(css[list[i][1]])
|
|
578
|
-
.attr('aria-sort', aria[list[i][1]])
|
|
579
|
-
.find('.' + ts.css.icon)
|
|
580
|
-
.removeClass(cssIcon[2])
|
|
581
|
-
.addClass(cssIcon[list[i][1]]);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
// add sorted class to footer & extra headers, if they exist
|
|
585
|
-
if ($t.length) {
|
|
586
|
-
$t.filter('[data-column="' + list[i][0] + '"]').removeClass(none).addClass(css[list[i][1]]);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
733
|
+
detectParserForColumn : function( c, rows, rowIndex, cellIndex ) {
|
|
734
|
+
var cur, $node,
|
|
735
|
+
indx = ts.parsers.length,
|
|
736
|
+
node = false,
|
|
737
|
+
nodeValue = '',
|
|
738
|
+
keepLooking = true;
|
|
739
|
+
while ( nodeValue === '' && keepLooking ) {
|
|
740
|
+
rowIndex++;
|
|
741
|
+
if ( rows[ rowIndex ] ) {
|
|
742
|
+
node = rows[ rowIndex ].cells[ cellIndex ];
|
|
743
|
+
nodeValue = ts.getElementText( c, node, cellIndex );
|
|
744
|
+
$node = $( node );
|
|
745
|
+
if ( c.debug ) {
|
|
746
|
+
console.log( 'Checking if value was empty on row ' + rowIndex + ', column: ' +
|
|
747
|
+
cellIndex + ': "' + nodeValue + '"' );
|
|
589
748
|
}
|
|
749
|
+
} else {
|
|
750
|
+
keepLooking = false;
|
|
590
751
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
h = $headers[ i ];
|
|
598
|
-
nextSort = h.order[ ( h.count + 1 ) % ( c.sortReset ? 3 : 2 ) ],
|
|
599
|
-
txt = $.trim( $h.text() ) + ': ' +
|
|
600
|
-
ts.language[ $h.hasClass( ts.css.sortAsc ) ? 'sortAsc' : $h.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone' ] +
|
|
601
|
-
ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
|
|
602
|
-
$h.attr( 'aria-label', txt );
|
|
603
|
-
}
|
|
752
|
+
}
|
|
753
|
+
while ( --indx >= 0 ) {
|
|
754
|
+
cur = ts.parsers[ indx ];
|
|
755
|
+
// ignore the default text parser because it will always be true
|
|
756
|
+
if ( cur && cur.id !== 'text' && cur.is && cur.is( nodeValue, c.table, node, $node ) ) {
|
|
757
|
+
return cur;
|
|
604
758
|
}
|
|
605
759
|
}
|
|
760
|
+
// nothing found, return the generic parser (text)
|
|
761
|
+
return ts.getParserById( 'text' );
|
|
762
|
+
},
|
|
606
763
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
case '1': case 'd': // descending
|
|
627
|
-
dir = 1;
|
|
628
|
-
break;
|
|
629
|
-
case 's': // same direction (as primary column)
|
|
630
|
-
// if primary sort is set to 's', make it ascending
|
|
631
|
-
dir = primary || 0;
|
|
632
|
-
break;
|
|
633
|
-
case 'o':
|
|
634
|
-
temp = header.order[(primary || 0) % (c.sortReset ? 3 : 2)];
|
|
635
|
-
// opposite of primary column; but resets if primary resets
|
|
636
|
-
dir = temp === 0 ? 1 : temp === 1 ? 0 : 2;
|
|
637
|
-
break;
|
|
638
|
-
case 'n':
|
|
639
|
-
header.count = header.count + 1;
|
|
640
|
-
dir = header.order[(header.count) % (c.sortReset ? 3 : 2)];
|
|
641
|
-
break;
|
|
642
|
-
default: // ascending
|
|
643
|
-
dir = 0;
|
|
644
|
-
break;
|
|
645
|
-
}
|
|
646
|
-
primary = indx === 0 ? dir : primary;
|
|
647
|
-
group = [ col, parseInt(dir, 10) || 0 ];
|
|
648
|
-
c.sortList.push(group);
|
|
649
|
-
dir = $.inArray(group[1], header.order); // fixes issue #167
|
|
650
|
-
header.count = dir >= 0 ? dir : group[1] % (c.sortReset ? 3 : 2);
|
|
651
|
-
}
|
|
764
|
+
getElementText : function( c, node, cellIndex ) {
|
|
765
|
+
if ( !node ) { return ''; }
|
|
766
|
+
var tmp,
|
|
767
|
+
extract = c.textExtraction || '',
|
|
768
|
+
// node could be a jquery object
|
|
769
|
+
// http://jsperf.com/jquery-vs-instanceof-jquery/2
|
|
770
|
+
$node = node.jquery ? node : $( node );
|
|
771
|
+
if ( typeof extract === 'string' ) {
|
|
772
|
+
// check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
|
|
773
|
+
// http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
|
|
774
|
+
if ( extract === 'basic' && typeof ( tmp = $node.attr( c.textAttribute ) ) !== 'undefined' ) {
|
|
775
|
+
return $.trim( tmp );
|
|
776
|
+
}
|
|
777
|
+
return $.trim( node.textContent || $node.text() );
|
|
778
|
+
} else {
|
|
779
|
+
if ( typeof extract === 'function' ) {
|
|
780
|
+
return $.trim( extract( $node[ 0 ], c.table, cellIndex ) );
|
|
781
|
+
} else if ( typeof ( tmp = ts.getColumnData( c.table, extract, cellIndex ) ) === 'function' ) {
|
|
782
|
+
return $.trim( tmp( $node[ 0 ], c.table, cellIndex ) );
|
|
652
783
|
}
|
|
653
784
|
}
|
|
785
|
+
// fallback
|
|
786
|
+
return $.trim( $node[ 0 ].textContent || $node.text() );
|
|
787
|
+
},
|
|
654
788
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
//
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
if (c.
|
|
675
|
-
|
|
676
|
-
for ( i = 0; i < len; i++ ) {
|
|
677
|
-
$header = c.$headers.eq( i );
|
|
678
|
-
// only reset counts on columns that weren't just clicked on and if not included in a multisort
|
|
679
|
-
if ( $header[0] !== indx && ( key || !$header.is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc) ) ) {
|
|
680
|
-
$header[0].count = -1;
|
|
681
|
-
}
|
|
682
|
-
}
|
|
789
|
+
// centralized function to extract/parse cell contents
|
|
790
|
+
getParsedText : function( c, cell, colIndex, txt ) {
|
|
791
|
+
if ( typeof txt === 'undefined' ) {
|
|
792
|
+
txt = ts.getElementText( c, cell, colIndex );
|
|
793
|
+
}
|
|
794
|
+
// if no parser, make sure to return the txt
|
|
795
|
+
var val = '' + txt,
|
|
796
|
+
parser = c.parsers[ colIndex ],
|
|
797
|
+
extractor = c.extractors[ colIndex ];
|
|
798
|
+
if ( parser ) {
|
|
799
|
+
// do extract before parsing, if there is one
|
|
800
|
+
if ( extractor && typeof extractor.format === 'function' ) {
|
|
801
|
+
txt = extractor.format( txt, c.table, cell, colIndex );
|
|
802
|
+
}
|
|
803
|
+
// allow parsing if the string is empty, previously parsing would change it to zero,
|
|
804
|
+
// in case the parser needs to extract data from the table cell attributes
|
|
805
|
+
val = parser.id === 'no-parser' ? '' :
|
|
806
|
+
// make sure txt is a string (extractor may have converted it)
|
|
807
|
+
parser.format( '' + txt, c.table, cell, colIndex );
|
|
808
|
+
if ( c.ignoreCase && typeof val === 'string' ) {
|
|
809
|
+
val = val.toLowerCase();
|
|
683
810
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
811
|
+
}
|
|
812
|
+
return val;
|
|
813
|
+
},
|
|
814
|
+
|
|
815
|
+
/*
|
|
816
|
+
▄████▄ ▄████▄ ▄████▄ ██ ██ ██████
|
|
817
|
+
██ ▀▀ ██▄▄██ ██ ▀▀ ██▄▄██ ██▄▄
|
|
818
|
+
██ ▄▄ ██▀▀██ ██ ▄▄ ██▀▀██ ██▀▀
|
|
819
|
+
▀████▀ ██ ██ ▀████▀ ██ ██ ██████
|
|
820
|
+
*/
|
|
821
|
+
buildCache : function( c, callback, $tbodies ) {
|
|
822
|
+
var cache, val, txt, rowIndex, colIndex, tbodyIndex, $tbody, $row,
|
|
823
|
+
cols, $cells, cell, cacheTime, totalRows, rowData, prevRowData,
|
|
824
|
+
colMax, span, cacheIndex, max, len,
|
|
825
|
+
table = c.table,
|
|
826
|
+
parsers = c.parsers;
|
|
827
|
+
// update tbody variable
|
|
828
|
+
c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
|
|
829
|
+
$tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
|
|
830
|
+
c.cache = {};
|
|
831
|
+
c.totalRows = 0;
|
|
832
|
+
// if no parsers found, return - it's an empty table.
|
|
833
|
+
if ( !parsers ) {
|
|
834
|
+
return c.debug ? console.warn( 'Warning: *Empty table!* Not building a cache' ) : '';
|
|
835
|
+
}
|
|
836
|
+
if ( c.debug ) {
|
|
837
|
+
cacheTime = new Date();
|
|
838
|
+
}
|
|
839
|
+
// processing icon
|
|
840
|
+
if ( c.showProcessing ) {
|
|
841
|
+
ts.isProcessing( table, true );
|
|
842
|
+
}
|
|
843
|
+
for ( tbodyIndex = 0; tbodyIndex < $tbody.length; tbodyIndex++ ) {
|
|
844
|
+
colMax = []; // column max value per tbody
|
|
845
|
+
cache = c.cache[ tbodyIndex ] = {
|
|
846
|
+
normalized: [] // array of normalized row data; last entry contains 'rowData' above
|
|
847
|
+
// colMax: # // added at the end
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
totalRows = ( $tbody[ tbodyIndex ] && $tbody[ tbodyIndex ].rows.length ) || 0;
|
|
851
|
+
for ( rowIndex = 0; rowIndex < totalRows; ++rowIndex ) {
|
|
852
|
+
rowData = {
|
|
853
|
+
// order: original row order #
|
|
854
|
+
// $row : jQuery Object[]
|
|
855
|
+
child: [], // child row text (filter widget)
|
|
856
|
+
raw: [] // original row text
|
|
857
|
+
};
|
|
858
|
+
/** Add the table data to main data array */
|
|
859
|
+
$row = $( $tbody[ tbodyIndex ].rows[ rowIndex ] );
|
|
860
|
+
cols = [];
|
|
861
|
+
// if this is a child row, add it to the last row's children and continue to the next row
|
|
862
|
+
// ignore child row class, if it is the first row
|
|
863
|
+
if ( $row.hasClass( c.cssChildRow ) && rowIndex !== 0 ) {
|
|
864
|
+
len = cache.normalized.length - 1;
|
|
865
|
+
prevRowData = cache.normalized[ len ][ c.columns ];
|
|
866
|
+
prevRowData.$row = prevRowData.$row.add( $row );
|
|
867
|
+
// add 'hasChild' class name to parent row
|
|
868
|
+
if ( !$row.prev().hasClass( c.cssChildRow ) ) {
|
|
869
|
+
$row.prev().addClass( ts.css.cssHasChild );
|
|
696
870
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
871
|
+
// save child row content (un-parsed!)
|
|
872
|
+
$cells = $row.children( 'th, td' );
|
|
873
|
+
len = prevRowData.child.length;
|
|
874
|
+
prevRowData.child[ len ] = [];
|
|
875
|
+
// child row content does not account for colspans/rowspans; so indexing may be off
|
|
876
|
+
cacheIndex = 0;
|
|
877
|
+
max = c.columns;
|
|
878
|
+
for ( colIndex = 0; colIndex < max; colIndex++ ) {
|
|
879
|
+
cell = $cells[ colIndex ];
|
|
880
|
+
if ( cell ) {
|
|
881
|
+
prevRowData.child[ len ][ colIndex ] = ts.getParsedText( c, cell, colIndex );
|
|
882
|
+
span = $cells[ colIndex ].colSpan - 1;
|
|
883
|
+
if ( span > 0 ) {
|
|
884
|
+
cacheIndex += span;
|
|
885
|
+
max += span;
|
|
886
|
+
}
|
|
706
887
|
}
|
|
888
|
+
cacheIndex++;
|
|
707
889
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
890
|
+
// go to the next for loop
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
893
|
+
rowData.$row = $row;
|
|
894
|
+
rowData.order = rowIndex; // add original row position to rowCache
|
|
895
|
+
cacheIndex = 0;
|
|
896
|
+
max = c.columns;
|
|
897
|
+
for ( colIndex = 0; colIndex < max; ++colIndex ) {
|
|
898
|
+
cell = $row[ 0 ].cells[ colIndex ];
|
|
899
|
+
if ( typeof parsers[ cacheIndex ] === 'undefined' ) {
|
|
900
|
+
if ( c.debug ) {
|
|
901
|
+
console.warn( 'No parser found for column ' + colIndex + '; cell:', cell, 'does it have a header?' );
|
|
717
902
|
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if (s[0] === indx) {
|
|
727
|
-
// order.count seems to be incorrect when compared to cell.count
|
|
728
|
-
s[1] = order.order[cell.count];
|
|
729
|
-
if (s[1] === 2) {
|
|
730
|
-
c.sortList.splice(col, 1);
|
|
731
|
-
order.count = -1;
|
|
732
|
-
}
|
|
903
|
+
} else if ( cell ) {
|
|
904
|
+
val = ts.getElementText( c, cell, cacheIndex );
|
|
905
|
+
rowData.raw[ cacheIndex ] = val; // save original row text
|
|
906
|
+
txt = ts.getParsedText( c, cell, cacheIndex, val );
|
|
907
|
+
cols[ cacheIndex ] = txt;
|
|
908
|
+
if ( ( parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
|
|
909
|
+
// determine column max value (ignore sign)
|
|
910
|
+
colMax[ cacheIndex ] = Math.max( Math.abs( txt ) || 0, colMax[ cacheIndex ] || 0 );
|
|
733
911
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
c.sortList.push([ indx, order ]);
|
|
740
|
-
// add other columns if header spans across multiple
|
|
741
|
-
if (cell.colSpan > 1) {
|
|
742
|
-
for (col = 1; col < cell.colSpan; col++) {
|
|
743
|
-
c.sortList.push([ indx + col, order ]);
|
|
744
|
-
}
|
|
912
|
+
// allow colSpan in tbody
|
|
913
|
+
span = cell.colSpan - 1;
|
|
914
|
+
if ( span > 0 ) {
|
|
915
|
+
cacheIndex += span;
|
|
916
|
+
max += span;
|
|
745
917
|
}
|
|
746
918
|
}
|
|
919
|
+
cacheIndex++;
|
|
747
920
|
}
|
|
921
|
+
// ensure rowData is always in the same location (after the last column)
|
|
922
|
+
cols[ c.columns ] = rowData;
|
|
923
|
+
cache.normalized.push( cols );
|
|
748
924
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
925
|
+
cache.colMax = colMax;
|
|
926
|
+
// total up rows, not including child rows
|
|
927
|
+
c.totalRows += cache.normalized.length;
|
|
928
|
+
|
|
929
|
+
}
|
|
930
|
+
if ( c.showProcessing ) {
|
|
931
|
+
ts.isProcessing( table ); // remove processing icon
|
|
932
|
+
}
|
|
933
|
+
if ( c.debug ) {
|
|
934
|
+
console.log( 'Building cache for ' + totalRows + ' rows' + ts.benchmark( cacheTime ) );
|
|
935
|
+
}
|
|
936
|
+
if ( $.isFunction( callback ) ) {
|
|
937
|
+
callback( table );
|
|
938
|
+
}
|
|
939
|
+
},
|
|
940
|
+
|
|
941
|
+
getColumnText : function( table, column, callback, rowFilter ) {
|
|
942
|
+
table = $( table )[0];
|
|
943
|
+
var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result,
|
|
944
|
+
hasCallback = typeof callback === 'function',
|
|
945
|
+
allColumns = column === 'all',
|
|
946
|
+
data = { raw : [], parsed: [], $cell: [] },
|
|
947
|
+
c = table.config;
|
|
948
|
+
if ( ts.isEmptyObject( c ) ) {
|
|
949
|
+
if ( c.debug ) {
|
|
950
|
+
console.warn( 'No cache found - aborting getColumnText function!' );
|
|
951
|
+
}
|
|
952
|
+
} else {
|
|
953
|
+
tbodyLen = c.$tbodies.length;
|
|
954
|
+
for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) {
|
|
955
|
+
cache = c.cache[ tbodyIndex ].normalized;
|
|
956
|
+
rowLen = cache.length;
|
|
957
|
+
for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) {
|
|
958
|
+
row = cache[ rowIndex ];
|
|
959
|
+
if ( rowFilter && !row[ c.columns ].$row.is( rowFilter ) ) {
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
962
|
+
result = true;
|
|
963
|
+
parsed = ( allColumns ) ? row.slice( 0, c.columns ) : row[ column ];
|
|
964
|
+
row = row[ c.columns ];
|
|
965
|
+
raw = ( allColumns ) ? row.raw : row.raw[ column ];
|
|
966
|
+
$cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column );
|
|
967
|
+
if ( hasCallback ) {
|
|
968
|
+
result = callback({
|
|
969
|
+
tbodyIndex : tbodyIndex,
|
|
970
|
+
rowIndex : rowIndex,
|
|
971
|
+
parsed : parsed,
|
|
972
|
+
raw : raw,
|
|
973
|
+
$row : row.$row,
|
|
974
|
+
$cell : $cell
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
if ( result !== false ) {
|
|
978
|
+
data.parsed.push( parsed );
|
|
979
|
+
data.raw.push( raw );
|
|
980
|
+
data.$cell.push( $cell );
|
|
754
981
|
}
|
|
755
982
|
}
|
|
756
983
|
}
|
|
757
|
-
//
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
// set css for headers
|
|
762
|
-
setHeadersCss(table);
|
|
763
|
-
multisort(table);
|
|
764
|
-
ts.appendCache( c );
|
|
765
|
-
$table.trigger('sortEnd', table);
|
|
766
|
-
}, 1);
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// sort multiple columns
|
|
770
|
-
function multisort(table) { /*jshint loopfunc:true */
|
|
771
|
-
var i, k, num, col, sortTime, colMax,
|
|
772
|
-
rows, order, sort, x, y,
|
|
773
|
-
dir = 0,
|
|
774
|
-
c = table.config,
|
|
775
|
-
cts = c.textSorter || '',
|
|
776
|
-
sortList = c.sortList,
|
|
777
|
-
l = sortList.length,
|
|
778
|
-
bl = c.$tbodies.length;
|
|
779
|
-
if (c.serverSideSorting || ts.isEmptyObject(c.cache)) { // empty table - fixes #206/#346
|
|
780
|
-
return;
|
|
781
|
-
}
|
|
782
|
-
if (c.debug) { sortTime = new Date(); }
|
|
783
|
-
for (k = 0; k < bl; k++) {
|
|
784
|
-
colMax = c.cache[k].colMax;
|
|
785
|
-
rows = c.cache[k].normalized;
|
|
786
|
-
|
|
787
|
-
rows.sort(function(a, b) {
|
|
788
|
-
// rows is undefined here in IE, so don't use it!
|
|
789
|
-
for (i = 0; i < l; i++) {
|
|
790
|
-
col = sortList[i][0];
|
|
791
|
-
order = sortList[i][1];
|
|
792
|
-
// sort direction, true = asc, false = desc
|
|
793
|
-
dir = order === 0;
|
|
794
|
-
|
|
795
|
-
if (c.sortStable && a[col] === b[col] && l === 1) {
|
|
796
|
-
return a[c.columns].order - b[c.columns].order;
|
|
797
|
-
}
|
|
984
|
+
// return everything
|
|
985
|
+
return data;
|
|
986
|
+
}
|
|
987
|
+
},
|
|
798
988
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
989
|
+
/*
|
|
990
|
+
██ ██ █████▄ █████▄ ▄████▄ ██████ ██████
|
|
991
|
+
██ ██ ██▄▄██ ██ ██ ██▄▄██ ██ ██▄▄
|
|
992
|
+
██ ██ ██▀▀▀ ██ ██ ██▀▀██ ██ ██▀▀
|
|
993
|
+
▀████▀ ██ █████▀ ██ ██ ██ ██████
|
|
994
|
+
*/
|
|
995
|
+
setHeadersCss : function( c ) {
|
|
996
|
+
var $sorted, header, indx, column, $header, nextSort, txt, tmp,
|
|
997
|
+
list = c.sortList,
|
|
998
|
+
len = list.length,
|
|
999
|
+
none = ts.css.sortNone + ' ' + c.cssNone,
|
|
1000
|
+
css = [ ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc ],
|
|
1001
|
+
cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ],
|
|
1002
|
+
aria = [ 'ascending', 'descending' ],
|
|
1003
|
+
// find the footer
|
|
1004
|
+
$headers = c.$table
|
|
1005
|
+
.find( 'tfoot tr' )
|
|
1006
|
+
.children()
|
|
1007
|
+
.add( $( c.namespace + '_extra_headers' ) )
|
|
1008
|
+
.removeClass( css.join( ' ' ) );
|
|
1009
|
+
// remove all header information
|
|
1010
|
+
c.$headers
|
|
1011
|
+
.removeClass( css.join( ' ' ) )
|
|
1012
|
+
.addClass( none )
|
|
1013
|
+
.attr( 'aria-sort', 'none' )
|
|
1014
|
+
.find( '.' + ts.css.icon )
|
|
1015
|
+
.removeClass( cssIcon.join( ' ' ) )
|
|
1016
|
+
.addClass( cssIcon[ 2 ] );
|
|
1017
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1018
|
+
// direction = 2 means reset!
|
|
1019
|
+
if ( list[ indx ][ 1 ] !== 2 ) {
|
|
1020
|
+
// multicolumn sorting updating - see #1005
|
|
1021
|
+
// .not(function(){}) needs jQuery 1.4
|
|
1022
|
+
$sorted = c.$headers.filter( function( i, el ) {
|
|
1023
|
+
// only include headers that are in the sortList (this includes colspans)
|
|
1024
|
+
var include = true,
|
|
1025
|
+
$el = $( el ),
|
|
1026
|
+
col = parseInt( $el.attr( 'data-column' ), 10 ),
|
|
1027
|
+
end = col + el.colSpan;
|
|
1028
|
+
for ( ; col < end; col++ ) {
|
|
1029
|
+
include = include ? ts.isValueInArray( col, c.sortList ) > -1 : false;
|
|
829
1030
|
}
|
|
830
|
-
return
|
|
1031
|
+
return include;
|
|
831
1032
|
});
|
|
832
|
-
}
|
|
833
|
-
if (c.debug) {
|
|
834
|
-
console.log( 'Sorting on ' + sortList.toString() + ' and dir ' + order + ' time' + ts.benchmark(sortTime) );
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
1033
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1034
|
+
// choose the :last in case there are nested columns
|
|
1035
|
+
$sorted = $sorted
|
|
1036
|
+
.not( '.sorter-false' )
|
|
1037
|
+
.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' + ( len === 1 ? ':last' : '' ) );
|
|
1038
|
+
if ( $sorted.length ) {
|
|
1039
|
+
for ( column = 0; column < $sorted.length; column++ ) {
|
|
1040
|
+
if ( !$sorted[ column ].sortDisabled ) {
|
|
1041
|
+
$sorted
|
|
1042
|
+
.eq( column )
|
|
1043
|
+
.removeClass( none )
|
|
1044
|
+
.addClass( css[ list[ indx ][ 1 ] ] )
|
|
1045
|
+
.attr( 'aria-sort', aria[ list[ indx ][ 1 ] ] )
|
|
1046
|
+
.find( '.' + ts.css.icon )
|
|
1047
|
+
.removeClass( cssIcon[ 2 ] )
|
|
1048
|
+
.addClass( cssIcon[ list[ indx ][ 1 ] ] );
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
// add sorted class to footer & extra headers, if they exist
|
|
1052
|
+
if ( $headers.length ) {
|
|
1053
|
+
$headers
|
|
1054
|
+
.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' )
|
|
1055
|
+
.removeClass( none )
|
|
1056
|
+
.addClass( css[ list[ indx ][ 1 ] ] );
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
841
1059
|
}
|
|
842
|
-
|
|
843
|
-
|
|
1060
|
+
}
|
|
1061
|
+
// add verbose aria labels
|
|
1062
|
+
len = c.$headers.length;
|
|
1063
|
+
$headers = c.$headers.not( '.sorter-false' );
|
|
1064
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1065
|
+
$header = $headers.eq( indx );
|
|
1066
|
+
if ( $header.length ) {
|
|
1067
|
+
header = $headers[ indx ];
|
|
1068
|
+
column = parseInt( $header.attr( 'data-column' ), 10 );
|
|
1069
|
+
nextSort = c.sortVars[ column ].order[ ( c.sortVars[ column ].count + 1 ) % ( c.sortReset ? 3 : 2 ) ];
|
|
1070
|
+
tmp = $header.hasClass( ts.css.sortAsc ) ?
|
|
1071
|
+
'sortAsc' :
|
|
1072
|
+
$header.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone';
|
|
1073
|
+
txt = $.trim( $header.text() ) + ': ' +
|
|
1074
|
+
ts.language[ tmp ] +
|
|
1075
|
+
ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
|
|
1076
|
+
$header.attr( 'aria-label', txt );
|
|
844
1077
|
}
|
|
845
1078
|
}
|
|
1079
|
+
},
|
|
846
1080
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1081
|
+
updateHeader : function( c ) {
|
|
1082
|
+
var index, isDisabled, $th, col,
|
|
1083
|
+
table = c.table,
|
|
1084
|
+
len = c.$headers.length;
|
|
1085
|
+
for ( index = 0; index < len; index++ ) {
|
|
1086
|
+
$th = c.$headers.eq( index );
|
|
1087
|
+
col = ts.getColumnData( table, c.headers, index, true );
|
|
1088
|
+
// add 'sorter-false' class if 'parser-false' is set
|
|
1089
|
+
isDisabled = ts.getData( $th, col, 'sorter' ) === 'false' || ts.getData( $th, col, 'parser' ) === 'false';
|
|
1090
|
+
$th[ 0 ].sortDisabled = isDisabled;
|
|
1091
|
+
$th[ isDisabled ? 'addClass' : 'removeClass' ]( 'sorter-false' ).attr( 'aria-disabled', '' + isDisabled );
|
|
1092
|
+
// disable tab index on disabled cells
|
|
1093
|
+
if ( c.tabIndex ) {
|
|
1094
|
+
if ( isDisabled ) {
|
|
1095
|
+
$th.removeAttr( 'tabindex' );
|
|
858
1096
|
} else {
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1097
|
+
$th.attr( 'tabindex', '0' );
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
// aria-controls - requires table ID
|
|
1101
|
+
if ( table.id ) {
|
|
1102
|
+
if ( isDisabled ) {
|
|
1103
|
+
$th.removeAttr( 'aria-controls' );
|
|
1104
|
+
} else {
|
|
1105
|
+
$th.attr( 'aria-controls', table.id );
|
|
863
1106
|
}
|
|
864
|
-
} else {
|
|
865
|
-
resortComplete(c, callback);
|
|
866
|
-
ts.applyWidget(c.table, false);
|
|
867
1107
|
}
|
|
868
1108
|
}
|
|
1109
|
+
},
|
|
869
1110
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
//
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
})
|
|
912
|
-
.bind( 'appendCache' + c.namespace, function( e, callback, init ) {
|
|
913
|
-
e.stopPropagation();
|
|
914
|
-
ts.appendCache( this.config, init );
|
|
915
|
-
if ( $.isFunction( callback ) ) {
|
|
916
|
-
callback( table );
|
|
917
|
-
}
|
|
918
|
-
})
|
|
919
|
-
// $tbodies variable is used by the tbody sorting widget
|
|
920
|
-
.bind( 'updateCache' + c.namespace, function( e, callback, $tbodies ){
|
|
921
|
-
e.stopPropagation();
|
|
922
|
-
ts.updateCache( this.config, callback, $tbodies );
|
|
923
|
-
})
|
|
924
|
-
.bind( 'applyWidgetId' + c.namespace, function( e, id ) {
|
|
925
|
-
e.stopPropagation();
|
|
926
|
-
ts.getWidgetById( id ).format( table, this.config, this.config.widgetOptions );
|
|
927
|
-
})
|
|
928
|
-
.bind( 'applyWidgets' + c.namespace, function( e, init ) {
|
|
929
|
-
e.stopPropagation();
|
|
930
|
-
// apply widgets
|
|
931
|
-
ts.applyWidget( table, init );
|
|
932
|
-
})
|
|
933
|
-
.bind( 'refreshWidgets' + c.namespace, function( e, all, dontapply ) {
|
|
934
|
-
e.stopPropagation();
|
|
935
|
-
ts.refreshWidgets( table, all, dontapply );
|
|
936
|
-
})
|
|
937
|
-
.bind( 'destroy' + c.namespace, function( e, removeClasses, callback ) {
|
|
938
|
-
e.stopPropagation();
|
|
939
|
-
ts.destroy( table, removeClasses, callback );
|
|
940
|
-
})
|
|
941
|
-
.bind( 'resetToLoadState' + c.namespace, function( e ) {
|
|
942
|
-
e.stopPropagation();
|
|
943
|
-
// remove all widgets
|
|
944
|
-
ts.removeWidget( table, true, false );
|
|
945
|
-
// restore original settings; this clears out current settings, but does not clear
|
|
946
|
-
// values saved to storage.
|
|
947
|
-
c = $.extend( true, ts.defaults, c.originalSettings );
|
|
948
|
-
table.hasInitialized = false;
|
|
949
|
-
// setup the entire table again
|
|
950
|
-
ts.setup( table, c );
|
|
951
|
-
});
|
|
1111
|
+
updateHeaderSortCount : function( c, list ) {
|
|
1112
|
+
var col, dir, group, indx, primary, temp, val, order,
|
|
1113
|
+
sortList = list || c.sortList,
|
|
1114
|
+
len = sortList.length;
|
|
1115
|
+
c.sortList = [];
|
|
1116
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1117
|
+
val = sortList[ indx ];
|
|
1118
|
+
// ensure all sortList values are numeric - fixes #127
|
|
1119
|
+
col = parseInt( val[ 0 ], 10 );
|
|
1120
|
+
// prevents error if sorton array is wrong
|
|
1121
|
+
if ( col < c.columns ) {
|
|
1122
|
+
order = c.sortVars[ col ].order;
|
|
1123
|
+
dir = ( '' + val[ 1 ] ).match( /^(1|d|s|o|n)/ );
|
|
1124
|
+
dir = dir ? dir[ 0 ] : '';
|
|
1125
|
+
// 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
|
|
1126
|
+
switch ( dir ) {
|
|
1127
|
+
case '1' : case 'd' : // descending
|
|
1128
|
+
dir = 1;
|
|
1129
|
+
break;
|
|
1130
|
+
case 's' : // same direction (as primary column)
|
|
1131
|
+
// if primary sort is set to 's', make it ascending
|
|
1132
|
+
dir = primary || 0;
|
|
1133
|
+
break;
|
|
1134
|
+
case 'o' :
|
|
1135
|
+
temp = order[ ( primary || 0 ) % ( c.sortReset ? 3 : 2 ) ];
|
|
1136
|
+
// opposite of primary column; but resets if primary resets
|
|
1137
|
+
dir = temp === 0 ? 1 : temp === 1 ? 0 : 2;
|
|
1138
|
+
break;
|
|
1139
|
+
case 'n' :
|
|
1140
|
+
dir = order[ ( ++c.sortVars[ col ].count ) % ( c.sortReset ? 3 : 2 ) ];
|
|
1141
|
+
break;
|
|
1142
|
+
default : // ascending
|
|
1143
|
+
dir = 0;
|
|
1144
|
+
break;
|
|
1145
|
+
}
|
|
1146
|
+
primary = indx === 0 ? dir : primary;
|
|
1147
|
+
group = [ col, parseInt( dir, 10 ) || 0 ];
|
|
1148
|
+
c.sortList.push( group );
|
|
1149
|
+
dir = $.inArray( group[ 1 ], order ); // fixes issue #167
|
|
1150
|
+
c.sortVars[ col ].count = dir >= 0 ? dir : group[ 1 ] % ( c.sortReset ? 3 : 2 );
|
|
1151
|
+
}
|
|
952
1152
|
}
|
|
1153
|
+
},
|
|
953
1154
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
if (!table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE') {
|
|
964
|
-
// return the table (in case the original target is the table's container)
|
|
965
|
-
ts.buildTable(table, c);
|
|
966
|
-
} else {
|
|
967
|
-
ts.setup(table, c);
|
|
968
|
-
}
|
|
969
|
-
});
|
|
970
|
-
};
|
|
1155
|
+
updateAll : function( c, resort, callback ) {
|
|
1156
|
+
var table = c.table;
|
|
1157
|
+
table.isUpdating = true;
|
|
1158
|
+
ts.refreshWidgets( table, true, true );
|
|
1159
|
+
ts.buildHeaders( c );
|
|
1160
|
+
ts.bindEvents( table, c.$headers, true );
|
|
1161
|
+
ts.bindMethods( c );
|
|
1162
|
+
ts.commonUpdate( c, resort, callback );
|
|
1163
|
+
},
|
|
971
1164
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1165
|
+
update : function( c, resort, callback ) {
|
|
1166
|
+
var table = c.table;
|
|
1167
|
+
table.isUpdating = true;
|
|
1168
|
+
// update sorting (if enabled/disabled)
|
|
1169
|
+
ts.updateHeader( c );
|
|
1170
|
+
ts.commonUpdate( c, resort, callback );
|
|
1171
|
+
},
|
|
1172
|
+
|
|
1173
|
+
// simple header update - see #989
|
|
1174
|
+
updateHeaders : function( c, callback ) {
|
|
1175
|
+
c.table.isUpdating = true;
|
|
1176
|
+
ts.buildHeaders( c );
|
|
1177
|
+
ts.bindEvents( c.table, c.$headers, true );
|
|
1178
|
+
ts.resortComplete( c, callback );
|
|
1179
|
+
},
|
|
1180
|
+
|
|
1181
|
+
updateCell : function( c, cell, resort, callback ) {
|
|
1182
|
+
c.table.isUpdating = true;
|
|
1183
|
+
c.$table.find( c.selectorRemove ).remove();
|
|
1184
|
+
// get position from the dom
|
|
1185
|
+
var tmp, indx, row, icell, cache, len,
|
|
1186
|
+
$tbodies = c.$tbodies,
|
|
1187
|
+
$cell = $( cell ),
|
|
1188
|
+
// update cache - format: function( s, table, cell, cellIndex )
|
|
1189
|
+
// no closest in jQuery v1.2.6
|
|
1190
|
+
tbodyIndex = $tbodies
|
|
1191
|
+
.index( $.fn.closest ? $cell.closest( 'tbody' ) : $cell.parents( 'tbody' ).filter( ':first' ) ),
|
|
1192
|
+
tbcache = c.cache[ tbodyIndex ],
|
|
1193
|
+
$row = $.fn.closest ? $cell.closest( 'tr' ) : $cell.parents( 'tr' ).filter( ':first' );
|
|
1194
|
+
cell = $cell[ 0 ]; // in case cell is a jQuery object
|
|
1195
|
+
// tbody may not exist if update is initialized while tbody is removed for processing
|
|
1196
|
+
if ( $tbodies.length && tbodyIndex >= 0 ) {
|
|
1197
|
+
row = $tbodies.eq( tbodyIndex ).find( 'tr' ).index( $row );
|
|
1198
|
+
cache = tbcache.normalized[ row ];
|
|
1199
|
+
len = $row[ 0 ].cells.length;
|
|
1200
|
+
if ( len !== c.columns ) {
|
|
1201
|
+
// colspan in here somewhere!
|
|
1202
|
+
icell = 0;
|
|
1203
|
+
tmp = false;
|
|
1204
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1205
|
+
if ( !tmp && $row[ 0 ].cells[ indx ] !== cell ) {
|
|
1206
|
+
icell += $row[ 0 ].cells[ indx ].colSpan;
|
|
978
1207
|
} else {
|
|
979
|
-
|
|
1208
|
+
tmp = true;
|
|
980
1209
|
}
|
|
981
1210
|
}
|
|
982
|
-
return;
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
var k = '',
|
|
986
|
-
$table = $(table),
|
|
987
|
-
m = $.metadata;
|
|
988
|
-
// initialization flag
|
|
989
|
-
table.hasInitialized = false;
|
|
990
|
-
// table is being processed flag
|
|
991
|
-
table.isProcessing = true;
|
|
992
|
-
// make sure to store the config object
|
|
993
|
-
table.config = c;
|
|
994
|
-
// save the settings where they read
|
|
995
|
-
$.data(table, 'tablesorter', c);
|
|
996
|
-
if (c.debug) {
|
|
997
|
-
console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter' );
|
|
998
|
-
$.data( table, 'startoveralltimer', new Date());
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
// removing this in version 3 (only supports jQuery 1.7+)
|
|
1002
|
-
c.supportsDataObject = (function(version) {
|
|
1003
|
-
version[0] = parseInt(version[0], 10);
|
|
1004
|
-
return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4);
|
|
1005
|
-
})($.fn.jquery.split('.'));
|
|
1006
|
-
// digit sort text location; keeping max+/- for backwards compatibility
|
|
1007
|
-
c.string = { 'max': 1, 'min': -1, 'emptymin': 1, 'emptymax': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false };
|
|
1008
|
-
// ensure case insensitivity
|
|
1009
|
-
c.emptyTo = c.emptyTo.toLowerCase();
|
|
1010
|
-
c.stringTo = c.stringTo.toLowerCase();
|
|
1011
|
-
// add table theme class only if there isn't already one there
|
|
1012
|
-
if (!/tablesorter\-/.test($table.attr('class'))) {
|
|
1013
|
-
k = (c.theme !== '' ? ' tablesorter-' + c.theme : '');
|
|
1014
|
-
}
|
|
1015
|
-
c.table = table;
|
|
1016
|
-
c.$table = $table
|
|
1017
|
-
.addClass(ts.css.table + ' ' + c.tableClass + k)
|
|
1018
|
-
.attr('role', 'grid');
|
|
1019
|
-
c.$headers = $table.find(c.selectorHeaders);
|
|
1020
|
-
|
|
1021
|
-
// give the table a unique id, which will be used in namespace binding
|
|
1022
|
-
if (!c.namespace) {
|
|
1023
|
-
c.namespace = '.tablesorter' + Math.random().toString(16).slice(2);
|
|
1024
1211
|
} else {
|
|
1025
|
-
|
|
1026
|
-
c.namespace = '.' + c.namespace.replace(ts.regex.nonWord, '');
|
|
1212
|
+
icell = $cell.index();
|
|
1027
1213
|
}
|
|
1028
|
-
|
|
1029
|
-
c
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
c.textExtraction = c.$table.attr('data-text-extraction') || c.textExtraction || 'basic';
|
|
1042
|
-
// build headers
|
|
1043
|
-
buildHeaders( c );
|
|
1044
|
-
// fixate columns if the users supplies the fixedWidth option
|
|
1045
|
-
// do this after theme has been applied
|
|
1046
|
-
ts.fixColumnWidth(table);
|
|
1047
|
-
// add widget options before parsing (e.g. grouping widget has parser settings)
|
|
1048
|
-
ts.applyWidgetOptions(table, c);
|
|
1049
|
-
// try to auto detect column type, and store in tables config
|
|
1050
|
-
buildParserCache(c);
|
|
1051
|
-
// start total row count at zero
|
|
1052
|
-
c.totalRows = 0;
|
|
1053
|
-
// build the cache for the tbody cells
|
|
1054
|
-
// delayInit will delay building the cache until the user starts a sort
|
|
1055
|
-
if (!c.delayInit) { buildCache(table); }
|
|
1056
|
-
// bind all header events and methods
|
|
1057
|
-
ts.bindEvents(table, c.$headers, true);
|
|
1058
|
-
bindMethods(table);
|
|
1059
|
-
// get sort list from jQuery data or metadata
|
|
1060
|
-
// in jQuery < 1.4, an error occurs when calling $table.data()
|
|
1061
|
-
if (c.supportsDataObject && typeof $table.data().sortlist !== 'undefined') {
|
|
1062
|
-
c.sortList = $table.data().sortlist;
|
|
1063
|
-
} else if (m && ($table.metadata() && $table.metadata().sortlist)) {
|
|
1064
|
-
c.sortList = $table.metadata().sortlist;
|
|
1065
|
-
}
|
|
1066
|
-
// apply widget init code
|
|
1067
|
-
ts.applyWidget(table, true);
|
|
1068
|
-
// if user has supplied a sort list to constructor
|
|
1069
|
-
if (c.sortList.length > 0) {
|
|
1070
|
-
$table.trigger('sorton', [ c.sortList, {}, !c.initWidgets, true ]);
|
|
1214
|
+
tmp = ts.getElementText( c, cell, icell ); // raw
|
|
1215
|
+
cache[ c.columns ].raw[ icell ] = tmp;
|
|
1216
|
+
tmp = ts.getParsedText( c, cell, icell, tmp );
|
|
1217
|
+
cache[ icell ] = tmp; // parsed
|
|
1218
|
+
cache[ c.columns ].$row = $row;
|
|
1219
|
+
if ( ( c.parsers[ icell ].type || '' ).toLowerCase() === 'numeric' ) {
|
|
1220
|
+
// update column max value (ignore sign)
|
|
1221
|
+
tbcache.colMax[ icell ] = Math.max( Math.abs( tmp ) || 0, tbcache.colMax[ icell ] || 0 );
|
|
1222
|
+
}
|
|
1223
|
+
tmp = resort !== 'undefined' ? resort : c.resort;
|
|
1224
|
+
if ( tmp !== false ) {
|
|
1225
|
+
// widgets will be reapplied
|
|
1226
|
+
ts.checkResort( c, tmp, callback );
|
|
1071
1227
|
} else {
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
ts.applyWidget(table, false);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
// show processesing icon
|
|
1080
|
-
if (c.showProcessing) {
|
|
1081
|
-
$table
|
|
1082
|
-
.unbind('sortBegin' + c.namespace + ' sortEnd' + c.namespace)
|
|
1083
|
-
.bind('sortBegin' + c.namespace + ' sortEnd' + c.namespace, function(e) {
|
|
1084
|
-
clearTimeout(c.processTimer);
|
|
1085
|
-
ts.isProcessing(table);
|
|
1086
|
-
if (e.type === 'sortBegin') {
|
|
1087
|
-
c.processTimer = setTimeout(function(){
|
|
1088
|
-
ts.isProcessing(table, true);
|
|
1089
|
-
}, 500);
|
|
1090
|
-
}
|
|
1091
|
-
});
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
// initialized
|
|
1095
|
-
table.hasInitialized = true;
|
|
1096
|
-
table.isProcessing = false;
|
|
1097
|
-
if (c.debug) {
|
|
1098
|
-
console.log( 'Overall initialization time: ' + ts.benchmark( $.data( table, 'startoveralltimer') ) );
|
|
1099
|
-
if ( c.debug && console.groupEnd ) { console.groupEnd(); }
|
|
1100
|
-
}
|
|
1101
|
-
$table.trigger('tablesorter-initialized', table);
|
|
1102
|
-
if (typeof c.initialized === 'function') { c.initialized(table); }
|
|
1103
|
-
};
|
|
1104
|
-
|
|
1105
|
-
// automatically add a colgroup with col elements set to a percentage width
|
|
1106
|
-
ts.fixColumnWidth = function(table) {
|
|
1107
|
-
table = $(table)[0];
|
|
1108
|
-
var overallWidth, percent, $tbodies, len, index,
|
|
1109
|
-
c = table.config,
|
|
1110
|
-
$colgroup = c.$table.children('colgroup');
|
|
1111
|
-
// remove plugin-added colgroup, in case we need to refresh the widths
|
|
1112
|
-
if ($colgroup.length && $colgroup.hasClass(ts.css.colgroup)) {
|
|
1113
|
-
$colgroup.remove();
|
|
1114
|
-
}
|
|
1115
|
-
if (c.widthFixed && c.$table.children('colgroup').length === 0) {
|
|
1116
|
-
$colgroup = $('<colgroup class="' + ts.css.colgroup + '">');
|
|
1117
|
-
overallWidth = c.$table.width();
|
|
1118
|
-
// only add col for visible columns - fixes #371
|
|
1119
|
-
$tbodies = c.$tbodies.find('tr:first').children(':visible'); // .each(function()
|
|
1120
|
-
len = $tbodies.length;
|
|
1121
|
-
for ( index = 0; index < len; index++ ) {
|
|
1122
|
-
percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
|
|
1123
|
-
$colgroup.append( $('<col>').css('width', percent) );
|
|
1124
|
-
}
|
|
1125
|
-
c.$table.prepend($colgroup);
|
|
1228
|
+
// don't reapply widgets is resort is false, just in case it causes
|
|
1229
|
+
// problems with element focus
|
|
1230
|
+
ts.resortComplete( c, callback );
|
|
1126
1231
|
}
|
|
1127
|
-
}
|
|
1232
|
+
}
|
|
1233
|
+
},
|
|
1128
1234
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
.add( $cell.find(k) );
|
|
1147
|
-
if ($h.length) {
|
|
1148
|
-
return obj[k];
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1235
|
+
addRows : function( c, $row, resort, callback ) {
|
|
1236
|
+
var txt, val, tbodyIndex, rowIndex, rows, cellIndex, len,
|
|
1237
|
+
cacheIndex, rowData, cells, cell, span,
|
|
1238
|
+
// allow passing a row string if only one non-info tbody exists in the table
|
|
1239
|
+
valid = typeof $row === 'string' && c.$tbodies.length === 1 && /<tr/.test( $row || '' ),
|
|
1240
|
+
table = c.table;
|
|
1241
|
+
if ( valid ) {
|
|
1242
|
+
$row = $( $row );
|
|
1243
|
+
c.$tbodies.append( $row );
|
|
1244
|
+
} else if ( !$row ||
|
|
1245
|
+
// row is a jQuery object?
|
|
1246
|
+
!( $row instanceof jQuery ) ||
|
|
1247
|
+
// row contained in the table?
|
|
1248
|
+
( $.fn.closest ? $row.closest( 'table' )[ 0 ] : $row.parents( 'table' )[ 0 ] ) !== c.table ) {
|
|
1249
|
+
if ( c.debug ) {
|
|
1250
|
+
console.error( 'addRows method requires (1) a jQuery selector reference to rows that have already ' +
|
|
1251
|
+
'been added to the table, or (2) row HTML string to be added to a table with only one tbody' );
|
|
1151
1252
|
}
|
|
1152
|
-
return;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1253
|
+
return false;
|
|
1254
|
+
}
|
|
1255
|
+
table.isUpdating = true;
|
|
1256
|
+
if ( ts.isEmptyObject( c.cache ) ) {
|
|
1257
|
+
// empty table, do an update instead - fixes #450
|
|
1258
|
+
ts.updateHeader( c );
|
|
1259
|
+
ts.commonUpdate( c, resort, callback );
|
|
1260
|
+
} else {
|
|
1261
|
+
rows = $row.filter( 'tr' ).attr( 'role', 'row' ).length;
|
|
1262
|
+
tbodyIndex = c.$tbodies.index( $row.parents( 'tbody' ).filter( ':first' ) );
|
|
1263
|
+
// fixes adding rows to an empty table - see issue #179
|
|
1264
|
+
if ( !( c.parsers && c.parsers.length ) ) {
|
|
1265
|
+
ts.setupParsers( c );
|
|
1266
|
+
}
|
|
1267
|
+
// add each row
|
|
1268
|
+
for ( rowIndex = 0; rowIndex < rows; rowIndex++ ) {
|
|
1269
|
+
cacheIndex = 0;
|
|
1270
|
+
len = $row[ rowIndex ].cells.length;
|
|
1271
|
+
cells = [];
|
|
1272
|
+
rowData = {
|
|
1273
|
+
child : [],
|
|
1274
|
+
raw : [],
|
|
1275
|
+
$row : $row.eq( rowIndex ),
|
|
1276
|
+
order : c.cache[ tbodyIndex ].normalized.length
|
|
1277
|
+
};
|
|
1278
|
+
// add each cell
|
|
1279
|
+
for ( cellIndex = 0; cellIndex < len; cellIndex++ ) {
|
|
1280
|
+
cell = $row[ rowIndex ].cells[ cellIndex ];
|
|
1281
|
+
txt = ts.getElementText( c, cell, cacheIndex );
|
|
1282
|
+
rowData.raw[ cacheIndex ] = txt;
|
|
1283
|
+
val = ts.getParsedText( c, cell, cacheIndex, txt );
|
|
1284
|
+
cells[ cacheIndex ] = val;
|
|
1285
|
+
if ( ( c.parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
|
|
1286
|
+
// update column max value (ignore sign)
|
|
1287
|
+
c.cache[ tbodyIndex ].colMax[ cacheIndex ] =
|
|
1288
|
+
Math.max( Math.abs( val ) || 0, c.cache[ tbodyIndex ].colMax[ cacheIndex ] || 0 );
|
|
1181
1289
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
for (k = rowIndex; k < rowIndex + rowSpan; k++) {
|
|
1186
|
-
if (typeof matrix[k] === 'undefined') {
|
|
1187
|
-
matrix[k] = [];
|
|
1188
|
-
}
|
|
1189
|
-
matrixrow = matrix[k];
|
|
1190
|
-
for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
|
|
1191
|
-
matrixrow[l] = 'x';
|
|
1192
|
-
}
|
|
1290
|
+
span = cell.colSpan - 1;
|
|
1291
|
+
if ( span > 0 ) {
|
|
1292
|
+
cacheIndex += span;
|
|
1193
1293
|
}
|
|
1294
|
+
cacheIndex++;
|
|
1194
1295
|
}
|
|
1296
|
+
// add the row data to the end
|
|
1297
|
+
cells[ c.columns ] = rowData;
|
|
1298
|
+
// update cache
|
|
1299
|
+
c.cache[ tbodyIndex ].normalized.push( cells );
|
|
1195
1300
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
// add processing indicator
|
|
1201
|
-
ts.isProcessing = function( $table, toggle, $ths ) {
|
|
1202
|
-
$table = $( $table );
|
|
1203
|
-
var c = $table[0].config,
|
|
1204
|
-
// default to all headers
|
|
1205
|
-
$h = $ths || $table.find('.' + ts.css.header);
|
|
1206
|
-
if (toggle) {
|
|
1207
|
-
// don't use sortList if custom $ths used
|
|
1208
|
-
if (typeof $ths !== 'undefined' && c.sortList.length > 0) {
|
|
1209
|
-
// get headers from the sortList
|
|
1210
|
-
$h = $h.filter(function(){
|
|
1211
|
-
// get data-column from attr to keep compatibility with jQuery 1.2.6
|
|
1212
|
-
return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList) >= 0;
|
|
1213
|
-
});
|
|
1214
|
-
}
|
|
1215
|
-
$table.add($h).addClass(ts.css.processing + ' ' + c.cssProcessing);
|
|
1216
|
-
} else {
|
|
1217
|
-
$table.add($h).removeClass(ts.css.processing + ' ' + c.cssProcessing);
|
|
1218
|
-
}
|
|
1219
|
-
};
|
|
1220
|
-
|
|
1221
|
-
// detach tbody but save the position
|
|
1222
|
-
// don't use tbody because there are portions that look for a tbody index (updateCell)
|
|
1223
|
-
ts.processTbody = function(table, $tb, getIt){
|
|
1224
|
-
table = $(table)[0];
|
|
1225
|
-
var holdr;
|
|
1226
|
-
if (getIt) {
|
|
1227
|
-
table.isProcessing = true;
|
|
1228
|
-
$tb.before('<colgroup class="tablesorter-savemyplace"/>');
|
|
1229
|
-
holdr = ($.fn.detach) ? $tb.detach() : $tb.remove();
|
|
1230
|
-
return holdr;
|
|
1231
|
-
}
|
|
1232
|
-
holdr = $(table).find('colgroup.tablesorter-savemyplace');
|
|
1233
|
-
$tb.insertAfter( holdr );
|
|
1234
|
-
holdr.remove();
|
|
1235
|
-
table.isProcessing = false;
|
|
1236
|
-
};
|
|
1301
|
+
// resort using current settings
|
|
1302
|
+
ts.checkResort( c, resort, callback );
|
|
1303
|
+
}
|
|
1304
|
+
},
|
|
1237
1305
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1306
|
+
updateCache : function( c, callback, $tbodies ) {
|
|
1307
|
+
// rebuild parsers
|
|
1308
|
+
if ( !( c.parsers && c.parsers.length ) ) {
|
|
1309
|
+
ts.setupParsers( c, $tbodies );
|
|
1310
|
+
}
|
|
1311
|
+
// rebuild the cache map
|
|
1312
|
+
ts.buildCache( c, callback, $tbodies );
|
|
1313
|
+
},
|
|
1241
1314
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
.
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
.
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
//
|
|
1270
|
-
(
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
// ignore mouseup if mousedown wasn't on the same target
|
|
1276
|
-
if ( type.match(' ' + c.pointerUp + ' ') && downTarget !== e.target && external !== true ) { return; }
|
|
1277
|
-
// set target on mousedown
|
|
1278
|
-
if ( type.match(' ' + c.pointerDown + ' ') ) {
|
|
1279
|
-
downTarget = e.target;
|
|
1280
|
-
// preventDefault needed or jQuery v1.3.2 and older throws an
|
|
1281
|
-
// "Uncaught TypeError: handler.apply is not a function" error
|
|
1282
|
-
temp = $target.jquery.split( '.' );
|
|
1283
|
-
if ( temp[0] === '1' && temp[1] < 4 ) { e.preventDefault(); }
|
|
1284
|
-
return;
|
|
1285
|
-
}
|
|
1286
|
-
downTarget = null;
|
|
1287
|
-
// prevent sort being triggered on form elements
|
|
1288
|
-
if ( ts.regex.formElements.test(e.target.nodeName) ||
|
|
1289
|
-
// nosort class name, or elements within a nosort container
|
|
1290
|
-
$target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 ||
|
|
1291
|
-
// elements within a button
|
|
1292
|
-
$target.parents('button').length > 0 ) {
|
|
1293
|
-
return !c.cancelSelection;
|
|
1294
|
-
}
|
|
1295
|
-
if (c.delayInit && ts.isEmptyObject(c.cache)) { buildCache(table); }
|
|
1296
|
-
// jQuery v1.2.6 doesn't have closest()
|
|
1297
|
-
$cell = $.fn.closest ? $(this).closest('th, td') : /TH|TD/.test(this.nodeName) ? $(this) : $(this).parents('th, td');
|
|
1298
|
-
// reference original table headers and find the same cell
|
|
1299
|
-
// don't use $headers or IE8 throws an error - see #987
|
|
1300
|
-
temp = $headers.index( $cell );
|
|
1301
|
-
c.lastClickedIndex = ( temp < 0 ) ? $cell.attr('data-column') : temp;
|
|
1302
|
-
// use column index if $headers is undefined
|
|
1303
|
-
cell = c.$headers[ c.lastClickedIndex ];
|
|
1304
|
-
if (cell && !cell.sortDisabled) {
|
|
1305
|
-
initSort(table, cell, e);
|
|
1315
|
+
// init flag (true) used by pager plugin to prevent widget application
|
|
1316
|
+
// renamed from appendToTable
|
|
1317
|
+
appendCache : function( c, init ) {
|
|
1318
|
+
var parsed, totalRows, $tbody, $curTbody, rowIndex, tbodyIndex, appendTime,
|
|
1319
|
+
table = c.table,
|
|
1320
|
+
wo = c.widgetOptions,
|
|
1321
|
+
$tbodies = c.$tbodies,
|
|
1322
|
+
rows = [],
|
|
1323
|
+
cache = c.cache;
|
|
1324
|
+
// empty table - fixes #206/#346
|
|
1325
|
+
if ( ts.isEmptyObject( cache ) ) {
|
|
1326
|
+
// run pager appender in case the table was just emptied
|
|
1327
|
+
return c.appender ? c.appender( table, rows ) :
|
|
1328
|
+
table.isUpdating ? c.$table.trigger( 'updateComplete', table ) : ''; // Fixes #532
|
|
1329
|
+
}
|
|
1330
|
+
if ( c.debug ) {
|
|
1331
|
+
appendTime = new Date();
|
|
1332
|
+
}
|
|
1333
|
+
for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
|
|
1334
|
+
$tbody = $tbodies.eq( tbodyIndex );
|
|
1335
|
+
if ( $tbody.length ) {
|
|
1336
|
+
// detach tbody for manipulation
|
|
1337
|
+
$curTbody = ts.processTbody( table, $tbody, true );
|
|
1338
|
+
parsed = cache[ tbodyIndex ].normalized;
|
|
1339
|
+
totalRows = parsed.length;
|
|
1340
|
+
for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
|
|
1341
|
+
rows.push( parsed[ rowIndex ][ c.columns ].$row );
|
|
1342
|
+
// removeRows used by the pager plugin; don't render if using ajax - fixes #411
|
|
1343
|
+
if ( !c.appender || ( c.pager && ( !c.pager.removeRows || !wo.pager_removeRows ) && !c.pager.ajax ) ) {
|
|
1344
|
+
$curTbody.append( parsed[ rowIndex ][ c.columns ].$row );
|
|
1345
|
+
}
|
|
1306
1346
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
// cancel selection
|
|
1310
|
-
$headers
|
|
1311
|
-
.attr('unselectable', 'on')
|
|
1312
|
-
.bind('selectstart', false)
|
|
1313
|
-
.css({
|
|
1314
|
-
'user-select': 'none',
|
|
1315
|
-
'MozUserSelect': 'none' // not needed for jQuery 1.8+
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
};
|
|
1319
|
-
|
|
1320
|
-
ts.sortReset = function( c, callback ) {
|
|
1321
|
-
var table = c.table;
|
|
1322
|
-
c.sortList = [];
|
|
1323
|
-
setHeadersCss( table );
|
|
1324
|
-
multisort( table );
|
|
1325
|
-
ts.appendCache( c );
|
|
1326
|
-
if ( $.isFunction( callback ) ) {
|
|
1327
|
-
callback( table );
|
|
1347
|
+
// restore tbody
|
|
1348
|
+
ts.processTbody( table, $curTbody, false );
|
|
1328
1349
|
}
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
// update sorting (if enabled/disabled)
|
|
1345
|
-
updateHeader( table );
|
|
1346
|
-
commonUpdate( table, resort, callback );
|
|
1347
|
-
};
|
|
1350
|
+
}
|
|
1351
|
+
if ( c.appender ) {
|
|
1352
|
+
c.appender( table, rows );
|
|
1353
|
+
}
|
|
1354
|
+
if ( c.debug ) {
|
|
1355
|
+
console.log( 'Rebuilt table' + ts.benchmark( appendTime ) );
|
|
1356
|
+
}
|
|
1357
|
+
// apply table widgets; but not before ajax completes
|
|
1358
|
+
if ( !init && !c.appender ) {
|
|
1359
|
+
ts.applyWidget( table );
|
|
1360
|
+
}
|
|
1361
|
+
if ( table.isUpdating ) {
|
|
1362
|
+
c.$table.trigger( 'updateComplete', table );
|
|
1363
|
+
}
|
|
1364
|
+
},
|
|
1348
1365
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1366
|
+
commonUpdate : function( c, resort, callback ) {
|
|
1367
|
+
// remove rows/elements before update
|
|
1368
|
+
c.$table.find( c.selectorRemove ).remove();
|
|
1369
|
+
// rebuild parsers
|
|
1370
|
+
ts.setupParsers( c );
|
|
1371
|
+
// rebuild the cache map
|
|
1372
|
+
ts.buildCache( c );
|
|
1373
|
+
ts.checkResort( c, resort, callback );
|
|
1374
|
+
},
|
|
1356
1375
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1376
|
+
/*
|
|
1377
|
+
▄█████ ▄████▄ █████▄ ██████ ██ █████▄ ▄████▄
|
|
1378
|
+
▀█▄ ██ ██ ██▄▄██ ██ ██ ██ ██ ██ ▄▄▄
|
|
1379
|
+
▀█▄ ██ ██ ██▀██ ██ ██ ██ ██ ██ ▀██
|
|
1380
|
+
█████▀ ▀████▀ ██ ██ ██ ██ ██ ██ ▀████▀
|
|
1381
|
+
*/
|
|
1382
|
+
initSort : function( c, cell, event ) {
|
|
1383
|
+
if ( c.table.isUpdating ) {
|
|
1384
|
+
// let any updates complete before initializing a sort
|
|
1385
|
+
return setTimeout( function(){
|
|
1386
|
+
ts.initSort( c, cell, event );
|
|
1387
|
+
}, 50 );
|
|
1388
|
+
}
|
|
1389
|
+
var arry, indx, headerIndx, dir, temp, tmp, $header,
|
|
1390
|
+
notMultiSort = !event[ c.sortMultiSortKey ],
|
|
1362
1391
|
table = c.table,
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
if (
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
}
|
|
1383
|
-
t = resort !== 'undefined' ? resort : c.resort;
|
|
1384
|
-
if ( t !== false ) {
|
|
1385
|
-
// widgets will be reapplied
|
|
1386
|
-
checkResort( c, t, callback );
|
|
1387
|
-
} else {
|
|
1388
|
-
// don't reapply widgets is resort is false, just in case it causes
|
|
1389
|
-
// problems with element focus
|
|
1390
|
-
resortComplete( c, callback );
|
|
1392
|
+
len = c.$headers.length,
|
|
1393
|
+
// get current column index
|
|
1394
|
+
col = parseInt( $( cell ).attr( 'data-column' ), 10 ),
|
|
1395
|
+
order = c.sortVars[ col ].order;
|
|
1396
|
+
|
|
1397
|
+
// Only call sortStart if sorting is enabled
|
|
1398
|
+
c.$table.trigger( 'sortStart', table );
|
|
1399
|
+
// get current column sort order
|
|
1400
|
+
c.sortVars[ col ].count =
|
|
1401
|
+
event[ c.sortResetKey ] ? 2 : ( c.sortVars[ col ].count + 1 ) % ( c.sortReset ? 3 : 2 );
|
|
1402
|
+
// reset all sorts on non-current column - issue #30
|
|
1403
|
+
if ( c.sortRestart ) {
|
|
1404
|
+
tmp = cell;
|
|
1405
|
+
for ( headerIndx = 0; headerIndx < len; headerIndx++ ) {
|
|
1406
|
+
$header = c.$headers.eq( headerIndx );
|
|
1407
|
+
// only reset counts on columns that weren't just clicked on and if not included in a multisort
|
|
1408
|
+
if ( $header[ 0 ] !== tmp &&
|
|
1409
|
+
( notMultiSort || !$header.is( '.' + ts.css.sortDesc + ',.' + ts.css.sortAsc ) ) ) {
|
|
1410
|
+
c.sortVars[ col ].count = -1;
|
|
1391
1411
|
}
|
|
1392
1412
|
}
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
!( $row instanceof jQuery ) ||
|
|
1406
|
-
// row contained in the table?
|
|
1407
|
-
( $.fn.closest ? $row.closest( 'table' )[ 0 ] : $row.parents( 'table' )[ 0 ] ) !== c.table ) {
|
|
1408
|
-
if ( c.debug ) {
|
|
1409
|
-
console.error( 'addRows method requires (1) a jQuery selector reference to rows that have already ' +
|
|
1410
|
-
'been added to the table, or (2) row HTML string to be added to a table with only one tbody' );
|
|
1413
|
+
}
|
|
1414
|
+
// user only wants to sort on one column
|
|
1415
|
+
if ( notMultiSort ) {
|
|
1416
|
+
// flush the sort list
|
|
1417
|
+
c.sortList = [];
|
|
1418
|
+
c.last.sortList = [];
|
|
1419
|
+
if ( c.sortForce !== null ) {
|
|
1420
|
+
arry = c.sortForce;
|
|
1421
|
+
for ( indx = 0; indx < arry.length; indx++ ) {
|
|
1422
|
+
if ( arry[ indx ][ 0 ] !== col ) {
|
|
1423
|
+
c.sortList.push( arry[ indx ] );
|
|
1424
|
+
}
|
|
1411
1425
|
}
|
|
1412
|
-
return false;
|
|
1413
1426
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1427
|
+
// add column to sort list
|
|
1428
|
+
dir = order[ c.sortVars[ col ].count ];
|
|
1429
|
+
if ( dir < 2 ) {
|
|
1430
|
+
c.sortList.push( [ col, dir ] );
|
|
1431
|
+
// add other columns if header spans across multiple
|
|
1432
|
+
if ( cell.colSpan > 1 ) {
|
|
1433
|
+
for ( indx = 1; indx < cell.colSpan; indx++ ) {
|
|
1434
|
+
c.sortList.push( [ col + indx, dir ] );
|
|
1435
|
+
// update count on columns in colSpan
|
|
1436
|
+
c.sortVars[ col + indx ].count = $.inArray( dir, order );
|
|
1437
|
+
}
|
|
1425
1438
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1439
|
+
}
|
|
1440
|
+
// multi column sorting
|
|
1441
|
+
} else {
|
|
1442
|
+
// get rid of the sortAppend before adding more - fixes issue #115 & #523
|
|
1443
|
+
c.sortList = $.extend( [], c.last.sortList );
|
|
1444
|
+
|
|
1445
|
+
// the user has clicked on an already sorted column
|
|
1446
|
+
if ( ts.isValueInArray( col, c.sortList ) >= 0 ) {
|
|
1447
|
+
// reverse the sorting direction
|
|
1448
|
+
for ( indx = 0; indx < c.sortList.length; indx++ ) {
|
|
1449
|
+
tmp = c.sortList[ indx ];
|
|
1450
|
+
if ( tmp[ 0 ] === col ) {
|
|
1451
|
+
// order.count seems to be incorrect when compared to cell.count
|
|
1452
|
+
tmp[ 1 ] = order[ c.sortVars[ col ].count ];
|
|
1453
|
+
if ( tmp[1] === 2 ) {
|
|
1454
|
+
c.sortList.splice( indx, 1 );
|
|
1455
|
+
c.sortVars[ col ].count = -1;
|
|
1441
1456
|
}
|
|
1442
1457
|
}
|
|
1443
|
-
// add the row data to the end
|
|
1444
|
-
cells.push( rowData );
|
|
1445
|
-
// update cache
|
|
1446
|
-
c.cache[ tbdy ].normalized.push( cells );
|
|
1447
1458
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
buildCache( c.table, callback, $tbodies );
|
|
1460
|
-
};
|
|
1461
|
-
|
|
1462
|
-
// init flag (true) used by pager plugin to prevent widget application
|
|
1463
|
-
// renamed from appendToTable
|
|
1464
|
-
ts.appendCache = function( c, init ) {
|
|
1465
|
-
var n, totalRows, $bk, $tb, i, k, appendTime,
|
|
1466
|
-
table = c.table,
|
|
1467
|
-
wo = c.widgetOptions,
|
|
1468
|
-
$tbodies = c.$tbodies,
|
|
1469
|
-
rows = [],
|
|
1470
|
-
cc = c.cache;
|
|
1471
|
-
// empty table - fixes #206/#346
|
|
1472
|
-
if ( ts.isEmptyObject( cc ) ) {
|
|
1473
|
-
// run pager appender in case the table was just emptied
|
|
1474
|
-
return c.appender ? c.appender( table, rows ) :
|
|
1475
|
-
table.isUpdating ? c.$table.trigger( 'updateComplete', table ) : ''; // Fixes #532
|
|
1476
|
-
}
|
|
1477
|
-
if ( c.debug ) {
|
|
1478
|
-
appendTime = new Date();
|
|
1479
|
-
}
|
|
1480
|
-
for ( k = 0; k < $tbodies.length; k++ ) {
|
|
1481
|
-
$bk = $tbodies.eq( k );
|
|
1482
|
-
if ( $bk.length ) {
|
|
1483
|
-
// get tbody
|
|
1484
|
-
$tb = ts.processTbody( table, $bk, true );
|
|
1485
|
-
n = cc[ k ].normalized;
|
|
1486
|
-
totalRows = n.length;
|
|
1487
|
-
for ( i = 0; i < totalRows; i++ ) {
|
|
1488
|
-
rows.push( n[ i ][ c.columns ].$row );
|
|
1489
|
-
// removeRows used by the pager plugin; don't render if using ajax - fixes #411
|
|
1490
|
-
if ( !c.appender || ( c.pager && ( !c.pager.removeRows || !wo.pager_removeRows ) && !c.pager.ajax ) ) {
|
|
1491
|
-
$tb.append( n[ i ][ c.columns ].$row );
|
|
1459
|
+
} else {
|
|
1460
|
+
// add column to sort list array
|
|
1461
|
+
dir = order[ c.sortVars[ col ].count ];
|
|
1462
|
+
if ( dir < 2 ) {
|
|
1463
|
+
c.sortList.push( [ col, dir ] );
|
|
1464
|
+
// add other columns if header spans across multiple
|
|
1465
|
+
if ( cell.colSpan > 1 ) {
|
|
1466
|
+
for ( indx = 1; indx < cell.colSpan; indx++ ) {
|
|
1467
|
+
c.sortList.push( [ col + indx, dir ] );
|
|
1468
|
+
// update count on columns in colSpan
|
|
1469
|
+
c.sortVars[ col + indx ].count = $.inArray( dir, order );
|
|
1492
1470
|
}
|
|
1493
1471
|
}
|
|
1494
|
-
// restore tbody
|
|
1495
|
-
ts.processTbody( table, $tb, false );
|
|
1496
1472
|
}
|
|
1497
1473
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1474
|
+
}
|
|
1475
|
+
// save sort before applying sortAppend
|
|
1476
|
+
c.last.sortList = $.extend( [], c.sortList );
|
|
1477
|
+
if ( c.sortList.length && c.sortAppend ) {
|
|
1478
|
+
arry = $.isArray( c.sortAppend ) ? c.sortAppend : c.sortAppend[ c.sortList[ 0 ][ 0 ] ];
|
|
1479
|
+
if ( !ts.isEmptyObject( arry ) ) {
|
|
1480
|
+
for ( indx = 0; indx < arry.length; indx++ ) {
|
|
1481
|
+
if ( arry[ indx ][ 0 ] !== col && ts.isValueInArray( arry[ indx ][ 0 ], c.sortList ) < 0 ) {
|
|
1482
|
+
dir = arry[ indx ][ 1 ];
|
|
1483
|
+
temp = ( '' + dir ).match( /^(a|d|s|o|n)/ );
|
|
1484
|
+
if ( temp ) {
|
|
1485
|
+
tmp = c.sortList[ 0 ][ 1 ];
|
|
1486
|
+
switch ( temp[ 0 ] ) {
|
|
1487
|
+
case 'd' :
|
|
1488
|
+
dir = 1;
|
|
1489
|
+
break;
|
|
1490
|
+
case 's' :
|
|
1491
|
+
dir = tmp;
|
|
1492
|
+
break;
|
|
1493
|
+
case 'o' :
|
|
1494
|
+
dir = tmp === 0 ? 1 : 0;
|
|
1495
|
+
break;
|
|
1496
|
+
case 'n' :
|
|
1497
|
+
dir = ( tmp + 1 ) % ( c.sortReset ? 3 : 2 );
|
|
1498
|
+
break;
|
|
1499
|
+
default:
|
|
1500
|
+
dir = 0;
|
|
1501
|
+
break;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
c.sortList.push( [ arry[ indx ][ 0 ], dir ] );
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1508
1507
|
}
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
// update header count index
|
|
1515
|
-
updateHeaderSortCount( table, list );
|
|
1508
|
+
}
|
|
1509
|
+
// sortBegin event triggered immediately before the sort
|
|
1510
|
+
c.$table.trigger( 'sortBegin', table );
|
|
1511
|
+
// setTimeout needed so the processing icon shows up
|
|
1512
|
+
setTimeout( function() {
|
|
1516
1513
|
// set css for headers
|
|
1517
|
-
setHeadersCss(
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
buildCache( table );
|
|
1521
|
-
}
|
|
1522
|
-
c.$table.trigger( 'sortBegin', table );
|
|
1523
|
-
// sort the table and append it to the dom
|
|
1524
|
-
multisort( table );
|
|
1525
|
-
ts.appendCache( c, init );
|
|
1514
|
+
ts.setHeadersCss( c );
|
|
1515
|
+
ts.multisort( c );
|
|
1516
|
+
ts.appendCache( c );
|
|
1526
1517
|
c.$table.trigger( 'sortEnd', table );
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
callback( table );
|
|
1530
|
-
}
|
|
1531
|
-
};
|
|
1518
|
+
}, 1 );
|
|
1519
|
+
},
|
|
1532
1520
|
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1521
|
+
// sort multiple columns
|
|
1522
|
+
multisort : function( c ) { /*jshint loopfunc:true */
|
|
1523
|
+
var tbodyIndex, sortTime, colMax, rows,
|
|
1524
|
+
table = c.table,
|
|
1525
|
+
dir = 0,
|
|
1526
|
+
textSorter = c.textSorter || '',
|
|
1527
|
+
sortList = c.sortList,
|
|
1528
|
+
sortLen = sortList.length,
|
|
1529
|
+
len = c.$tbodies.length;
|
|
1530
|
+
if ( c.serverSideSorting || ts.isEmptyObject( c.cache ) ) {
|
|
1531
|
+
// empty table - fixes #206/#346
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
if ( c.debug ) { sortTime = new Date(); }
|
|
1535
|
+
for ( tbodyIndex = 0; tbodyIndex < len; tbodyIndex++ ) {
|
|
1536
|
+
colMax = c.cache[ tbodyIndex ].colMax;
|
|
1537
|
+
rows = c.cache[ tbodyIndex ].normalized;
|
|
1538
|
+
|
|
1539
|
+
rows.sort( function( a, b ) {
|
|
1540
|
+
var sortIndex, num, col, order, sort, x, y;
|
|
1541
|
+
// rows is undefined here in IE, so don't use it!
|
|
1542
|
+
for ( sortIndex = 0; sortIndex < sortLen; sortIndex++ ) {
|
|
1543
|
+
col = sortList[ sortIndex ][ 0 ];
|
|
1544
|
+
order = sortList[ sortIndex ][ 1 ];
|
|
1545
|
+
// sort direction, true = asc, false = desc
|
|
1546
|
+
dir = order === 0;
|
|
1547
|
+
|
|
1548
|
+
if ( c.sortStable && a[ col ] === b[ col ] && sortLen === 1 ) {
|
|
1549
|
+
return a[ c.columns ].order - b[ c.columns ].order;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
// fallback to natural sort since it is more robust
|
|
1553
|
+
num = /n/i.test( ts.getSortType( c.parsers, col ) );
|
|
1554
|
+
if ( num && c.strings[ col ] ) {
|
|
1555
|
+
// sort strings in numerical columns
|
|
1556
|
+
if ( typeof ( ts.string[ c.strings[ col ] ] ) === 'boolean' ) {
|
|
1557
|
+
num = ( dir ? 1 : -1 ) * ( ts.string[ c.strings[ col ] ] ? -1 : 1 );
|
|
1558
|
+
} else {
|
|
1559
|
+
num = ( c.strings[ col ] ) ? ts.string[ c.strings[ col ] ] || 0 : 0;
|
|
1560
|
+
}
|
|
1561
|
+
// fall back to built-in numeric sort
|
|
1562
|
+
// var sort = $.tablesorter['sort' + s]( a[col], b[col], dir, colMax[col], table );
|
|
1563
|
+
sort = c.numberSorter ? c.numberSorter( a[ col ], b[ col ], dir, colMax[ col ], table ) :
|
|
1564
|
+
ts[ 'sortNumeric' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], num, colMax[ col ], col, c );
|
|
1565
|
+
} else {
|
|
1566
|
+
// set a & b depending on sort direction
|
|
1567
|
+
x = dir ? a : b;
|
|
1568
|
+
y = dir ? b : a;
|
|
1569
|
+
// text sort function
|
|
1570
|
+
if ( typeof textSorter === 'function' ) {
|
|
1571
|
+
// custom OVERALL text sorter
|
|
1572
|
+
sort = textSorter( x[ col ], y[ col ], dir, col, table );
|
|
1573
|
+
} else if ( typeof textSorter === 'object' && textSorter.hasOwnProperty( col ) ) {
|
|
1574
|
+
// custom text sorter for a SPECIFIC COLUMN
|
|
1575
|
+
sort = textSorter[ col ]( x[ col ], y[ col ], dir, col, table );
|
|
1576
|
+
} else {
|
|
1577
|
+
// fall back to natural sort
|
|
1578
|
+
sort = ts[ 'sortNatural' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], col, c );
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
if ( sort ) { return sort; }
|
|
1547
1582
|
}
|
|
1548
|
-
|
|
1549
|
-
|
|
1583
|
+
return a[ c.columns ].order - b[ c.columns ].order;
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
if ( c.debug ) {
|
|
1587
|
+
console.log( 'Applying sort ' + sortList.toString() + ts.benchmark( sortTime ) );
|
|
1588
|
+
}
|
|
1589
|
+
},
|
|
1550
1590
|
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
debug = c.debug,
|
|
1560
|
-
$h = $t.find('thead:first'),
|
|
1561
|
-
$r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow),
|
|
1562
|
-
$f = $t.find('tfoot:first > tr').children('th, td');
|
|
1563
|
-
if (removeClasses === false && $.inArray('uitheme', c.widgets) >= 0) {
|
|
1564
|
-
// reapply uitheme classes, in case we want to maintain appearance
|
|
1565
|
-
$t.trigger('applyWidgetId', [ 'uitheme' ]);
|
|
1566
|
-
$t.trigger('applyWidgetId', [ 'zebra' ]);
|
|
1567
|
-
}
|
|
1568
|
-
// remove widget added rows, just in case
|
|
1569
|
-
$h.find('tr').not($r).remove();
|
|
1570
|
-
// disable tablesorter
|
|
1571
|
-
events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
|
|
1572
|
-
'appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress ' +
|
|
1573
|
-
'sortBegin sortEnd resetToLoadState '.split(' ')
|
|
1574
|
-
.join(c.namespace + ' ');
|
|
1575
|
-
$t
|
|
1576
|
-
.removeData('tablesorter')
|
|
1577
|
-
.unbind( events.replace(ts.regex.spaces, ' ') );
|
|
1578
|
-
c.$headers.add($f)
|
|
1579
|
-
.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join(' ') )
|
|
1580
|
-
.removeAttr('data-column')
|
|
1581
|
-
.removeAttr('aria-label')
|
|
1582
|
-
.attr('aria-disabled', 'true');
|
|
1583
|
-
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(ts.regex.spaces, ' ') );
|
|
1584
|
-
ts.restoreHeaders(table);
|
|
1585
|
-
$t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false);
|
|
1586
|
-
// clear flag in case the plugin is initialized again
|
|
1587
|
-
table.hasInitialized = false;
|
|
1588
|
-
delete table.config.cache;
|
|
1589
|
-
if (typeof callback === 'function') {
|
|
1590
|
-
callback(table);
|
|
1591
|
-
}
|
|
1592
|
-
if (debug) {
|
|
1593
|
-
console.log( 'tablesorter has been removed' );
|
|
1594
|
-
}
|
|
1595
|
-
};
|
|
1591
|
+
resortComplete : function( c, callback ) {
|
|
1592
|
+
if ( c.table.isUpdating ) {
|
|
1593
|
+
c.$table.trigger( 'updateComplete', c.table );
|
|
1594
|
+
}
|
|
1595
|
+
if ( $.isFunction( callback ) ) {
|
|
1596
|
+
callback( c.table );
|
|
1597
|
+
}
|
|
1598
|
+
},
|
|
1596
1599
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
yN = b.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0');
|
|
1620
|
-
mx = Math.max(xN.length, yN.length);
|
|
1621
|
-
// natural sorting through split numeric strings and default strings
|
|
1622
|
-
for (i = 0; i < mx; i++) {
|
|
1623
|
-
// find floats not starting with '0', string or 0 if not defined
|
|
1624
|
-
xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0;
|
|
1625
|
-
yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0;
|
|
1626
|
-
// handle numeric vs string comparison - number < string - (Kyle Adams)
|
|
1627
|
-
if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; }
|
|
1628
|
-
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
|
|
1629
|
-
if (typeof xF !== typeof yF) {
|
|
1630
|
-
xF += '';
|
|
1631
|
-
yF += '';
|
|
1632
|
-
}
|
|
1633
|
-
if (xF < yF) { return -1; }
|
|
1634
|
-
if (xF > yF) { return 1; }
|
|
1635
|
-
}
|
|
1636
|
-
return 0;
|
|
1637
|
-
};
|
|
1600
|
+
checkResort : function( c, resort, callback ) {
|
|
1601
|
+
var sortList = $.isArray( resort ) ? resort : c.sortList,
|
|
1602
|
+
// if no resort parameter is passed, fallback to config.resort (true by default)
|
|
1603
|
+
resrt = typeof resort === 'undefined' ? c.resort : resort;
|
|
1604
|
+
// don't try to resort if the table is still processing
|
|
1605
|
+
// this will catch spamming of the updateCell method
|
|
1606
|
+
if ( resrt !== false && !c.serverSideSorting && !c.table.isProcessing ) {
|
|
1607
|
+
if ( sortList.length ) {
|
|
1608
|
+
ts.sortOn( c, sortList, function() {
|
|
1609
|
+
ts.resortComplete( c, callback );
|
|
1610
|
+
}, true );
|
|
1611
|
+
} else {
|
|
1612
|
+
ts.sortReset( c, function() {
|
|
1613
|
+
ts.resortComplete( c, callback );
|
|
1614
|
+
ts.applyWidget( c.table, false );
|
|
1615
|
+
} );
|
|
1616
|
+
}
|
|
1617
|
+
} else {
|
|
1618
|
+
ts.resortComplete( c, callback );
|
|
1619
|
+
ts.applyWidget( c.table, false );
|
|
1620
|
+
}
|
|
1621
|
+
},
|
|
1638
1622
|
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1623
|
+
sortOn : function( c, list, callback, init ) {
|
|
1624
|
+
var table = c.table;
|
|
1625
|
+
c.$table.trigger( 'sortStart', table );
|
|
1626
|
+
// update header count index
|
|
1627
|
+
ts.updateHeaderSortCount( c, list );
|
|
1628
|
+
// set css for headers
|
|
1629
|
+
ts.setHeadersCss( c );
|
|
1630
|
+
// fixes #346
|
|
1631
|
+
if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
|
|
1632
|
+
ts.buildCache( c );
|
|
1633
|
+
}
|
|
1634
|
+
c.$table.trigger( 'sortBegin', table );
|
|
1635
|
+
// sort the table and append it to the dom
|
|
1636
|
+
ts.multisort( c );
|
|
1637
|
+
ts.appendCache( c, init );
|
|
1638
|
+
c.$table.trigger( 'sortEnd', table );
|
|
1639
|
+
ts.applyWidget( table );
|
|
1640
|
+
if ( $.isFunction( callback ) ) {
|
|
1641
|
+
callback( table );
|
|
1642
|
+
}
|
|
1643
|
+
},
|
|
1646
1644
|
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1645
|
+
sortReset : function( c, callback ) {
|
|
1646
|
+
c.sortList = [];
|
|
1647
|
+
ts.setHeadersCss( c );
|
|
1648
|
+
ts.multisort( c );
|
|
1649
|
+
ts.appendCache( c );
|
|
1650
|
+
if ( $.isFunction( callback ) ) {
|
|
1651
|
+
callback( c.table );
|
|
1652
|
+
}
|
|
1653
|
+
},
|
|
1654
1654
|
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
};
|
|
1655
|
+
getSortType : function( parsers, column ) {
|
|
1656
|
+
return ( parsers && parsers[ column ] ) ? parsers[ column ].type || '' : '';
|
|
1657
|
+
},
|
|
1659
1658
|
|
|
1660
|
-
|
|
1661
|
-
//
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
if (mx) {
|
|
1665
|
-
// make sure the text value is greater than the max numerical value (mx)
|
|
1666
|
-
var i, l = a ? a.length : 0, n = mx + num;
|
|
1667
|
-
for (i = 0; i < l; i++) {
|
|
1668
|
-
n += a.charCodeAt(i);
|
|
1669
|
-
}
|
|
1670
|
-
return num * n;
|
|
1671
|
-
}
|
|
1672
|
-
return 0;
|
|
1673
|
-
};
|
|
1659
|
+
formatSortingOrder : function( val ) {
|
|
1660
|
+
// look for 'd' in 'desc' order; return true
|
|
1661
|
+
return ( /^d/i.test( val ) || val === 1 );
|
|
1662
|
+
},
|
|
1674
1663
|
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1664
|
+
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
|
|
1665
|
+
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
|
|
1666
|
+
// I could add a = a.toString(); b = b.toString(); but it'll slow down the sort overall
|
|
1667
|
+
sortNatural : function( a, b ) {
|
|
1668
|
+
if ( a === b ) { return 0; }
|
|
1669
|
+
var aNum, bNum, aFloat, bFloat, indx, max,
|
|
1670
|
+
regex = ts.regex;
|
|
1671
|
+
// first try and sort Hex codes
|
|
1672
|
+
if ( regex.hex.test( b ) ) {
|
|
1673
|
+
aNum = parseInt( a.match( regex.hex ), 16 );
|
|
1674
|
+
bNum = parseInt( b.match( regex.hex ), 16 );
|
|
1675
|
+
if ( aNum < bNum ) { return -1; }
|
|
1676
|
+
if ( aNum > bNum ) { return 1; }
|
|
1677
|
+
}
|
|
1678
|
+
// chunk/tokenize
|
|
1679
|
+
aNum = a.replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
|
|
1680
|
+
bNum = b.replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
|
|
1681
|
+
max = Math.max( aNum.length, bNum.length );
|
|
1682
|
+
// natural sorting through split numeric strings and default strings
|
|
1683
|
+
for ( indx = 0; indx < max; indx++ ) {
|
|
1684
|
+
// find floats not starting with '0', string or 0 if not defined
|
|
1685
|
+
aFloat = isNaN( aNum[ indx ] ) ? aNum[ indx ] || 0 : parseFloat( aNum[ indx ] ) || 0;
|
|
1686
|
+
bFloat = isNaN( bNum[ indx ] ) ? bNum[ indx ] || 0 : parseFloat( bNum[ indx ] ) || 0;
|
|
1687
|
+
// handle numeric vs string comparison - number < string - (Kyle Adams)
|
|
1688
|
+
if ( isNaN( aFloat ) !== isNaN( bFloat ) ) { return isNaN( aFloat ) ? 1 : -1; }
|
|
1689
|
+
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
|
|
1690
|
+
if ( typeof aFloat !== typeof bFloat ) {
|
|
1691
|
+
aFloat += '';
|
|
1692
|
+
bFloat += '';
|
|
1693
|
+
}
|
|
1694
|
+
if ( aFloat < bFloat ) { return -1; }
|
|
1695
|
+
if ( aFloat > bFloat ) { return 1; }
|
|
1696
|
+
}
|
|
1697
|
+
return 0;
|
|
1698
|
+
},
|
|
1685
1699
|
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
if (isNaN(b)) { b = ts.getTextValue(b, num, mx); }
|
|
1694
|
-
return b - a;
|
|
1695
|
-
};
|
|
1700
|
+
sortNaturalAsc : function( a, b, col, c ) {
|
|
1701
|
+
if ( a === b ) { return 0; }
|
|
1702
|
+
var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
|
|
1703
|
+
if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
|
|
1704
|
+
if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
|
|
1705
|
+
return ts.sortNatural( a, b );
|
|
1706
|
+
},
|
|
1696
1707
|
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1708
|
+
sortNaturalDesc : function( a, b, col, c ) {
|
|
1709
|
+
if ( a === b ) { return 0; }
|
|
1710
|
+
var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
|
|
1711
|
+
if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
|
|
1712
|
+
if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
|
|
1713
|
+
return ts.sortNatural( b, a );
|
|
1714
|
+
},
|
|
1700
1715
|
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
'c' : '\u00e7\u0107\u010d', // çćč
|
|
1706
|
-
'C' : '\u00c7\u0106\u010c', // ÇĆČ
|
|
1707
|
-
'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę
|
|
1708
|
-
'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
|
|
1709
|
-
'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
|
|
1710
|
-
'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
|
|
1711
|
-
'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō
|
|
1712
|
-
'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ
|
|
1713
|
-
'ss': '\u00df', // ß (s sharp)
|
|
1714
|
-
'SS': '\u1e9e', // ẞ (Capital sharp s)
|
|
1715
|
-
'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
|
|
1716
|
-
'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ
|
|
1717
|
-
};
|
|
1718
|
-
ts.replaceAccents = function(s) {
|
|
1719
|
-
var a, acc = '[', eq = ts.characterEquivalents;
|
|
1720
|
-
if (!ts.characterRegex) {
|
|
1721
|
-
ts.characterRegexArray = {};
|
|
1722
|
-
for (a in eq) {
|
|
1723
|
-
if (typeof a === 'string') {
|
|
1724
|
-
acc += eq[a];
|
|
1725
|
-
ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g');
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
ts.characterRegex = new RegExp(acc + ']');
|
|
1729
|
-
}
|
|
1730
|
-
if (ts.characterRegex.test(s)) {
|
|
1731
|
-
for (a in eq) {
|
|
1732
|
-
if (typeof a === 'string') {
|
|
1733
|
-
s = s.replace( ts.characterRegexArray[a], a );
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
return s;
|
|
1738
|
-
};
|
|
1716
|
+
// basic alphabetical sort
|
|
1717
|
+
sortText : function( a, b ) {
|
|
1718
|
+
return a > b ? 1 : ( a < b ? -1 : 0 );
|
|
1719
|
+
},
|
|
1739
1720
|
|
|
1740
|
-
|
|
1741
|
-
|
|
1721
|
+
// return text string value by adding up ascii value
|
|
1722
|
+
// so the text is somewhat sorted when using a digital sort
|
|
1723
|
+
// this is NOT an alphanumeric sort
|
|
1724
|
+
getTextValue : function( val, num, max ) {
|
|
1725
|
+
if ( max ) {
|
|
1726
|
+
// make sure the text value is greater than the max numerical value (max)
|
|
1742
1727
|
var indx,
|
|
1743
|
-
len =
|
|
1728
|
+
len = val ? val.length : 0,
|
|
1729
|
+
n = max + num;
|
|
1744
1730
|
for ( indx = 0; indx < len; indx++ ) {
|
|
1745
|
-
|
|
1746
|
-
return indx;
|
|
1747
|
-
}
|
|
1731
|
+
n += val.charCodeAt( indx );
|
|
1748
1732
|
}
|
|
1749
|
-
return
|
|
1750
|
-
}
|
|
1733
|
+
return num * n;
|
|
1734
|
+
}
|
|
1735
|
+
return 0;
|
|
1736
|
+
},
|
|
1751
1737
|
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
}
|
|
1762
|
-
};
|
|
1738
|
+
sortNumericAsc : function( a, b, num, max, col, c ) {
|
|
1739
|
+
if ( a === b ) { return 0; }
|
|
1740
|
+
var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
|
|
1741
|
+
if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
|
|
1742
|
+
if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
|
|
1743
|
+
if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
|
|
1744
|
+
if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
|
|
1745
|
+
return a - b;
|
|
1746
|
+
},
|
|
1763
1747
|
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
ts.
|
|
1767
|
-
|
|
1768
|
-
}
|
|
1748
|
+
sortNumericDesc : function( a, b, num, max, col, c ) {
|
|
1749
|
+
if ( a === b ) { return 0; }
|
|
1750
|
+
var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
|
|
1751
|
+
if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
|
|
1752
|
+
if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
|
|
1753
|
+
if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
|
|
1754
|
+
if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
|
|
1755
|
+
return b - a;
|
|
1756
|
+
},
|
|
1769
1757
|
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
var i, l = ts.parsers.length;
|
|
1774
|
-
for (i = 0; i < l; i++) {
|
|
1775
|
-
if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) {
|
|
1776
|
-
return ts.parsers[i];
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
return false;
|
|
1780
|
-
};
|
|
1758
|
+
sortNumeric : function( a, b ) {
|
|
1759
|
+
return a - b;
|
|
1760
|
+
},
|
|
1781
1761
|
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1762
|
+
/*
|
|
1763
|
+
██ ██ ██ ██ █████▄ ▄████▄ ██████ ██████ ▄█████
|
|
1764
|
+
██ ██ ██ ██ ██ ██ ██ ▄▄▄ ██▄▄ ██ ▀█▄
|
|
1765
|
+
██ ██ ██ ██ ██ ██ ██ ▀██ ██▀▀ ██ ▀█▄
|
|
1766
|
+
███████▀ ██ █████▀ ▀████▀ ██████ ██ █████▀
|
|
1767
|
+
*/
|
|
1768
|
+
addWidget : function( widget ) {
|
|
1769
|
+
ts.widgets.push( widget );
|
|
1770
|
+
},
|
|
1785
1771
|
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1772
|
+
hasWidget : function( $table, name ) {
|
|
1773
|
+
$table = $( $table );
|
|
1774
|
+
return $table.length && $table[ 0 ].config && $table[ 0 ].config.widgetInit[ name ] || false;
|
|
1775
|
+
},
|
|
1790
1776
|
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1777
|
+
getWidgetById : function( name ) {
|
|
1778
|
+
var indx, widget,
|
|
1779
|
+
len = ts.widgets.length;
|
|
1780
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1781
|
+
widget = ts.widgets[ indx ];
|
|
1782
|
+
if ( widget && widget.id && widget.id.toLowerCase() === name.toLowerCase() ) {
|
|
1783
|
+
return widget;
|
|
1798
1784
|
}
|
|
1799
|
-
}
|
|
1785
|
+
}
|
|
1786
|
+
},
|
|
1800
1787
|
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
}
|
|
1788
|
+
applyWidgetOptions : function( table ) {
|
|
1789
|
+
var indx, widget,
|
|
1790
|
+
c = table.config,
|
|
1791
|
+
len = c.widgets.length;
|
|
1792
|
+
if ( len ) {
|
|
1793
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1794
|
+
widget = ts.getWidgetById( c.widgets[ indx ] );
|
|
1795
|
+
if ( widget && widget.options ) {
|
|
1796
|
+
c.widgetOptions = $.extend( true, {}, widget.options, c.widgetOptions );
|
|
1810
1797
|
}
|
|
1811
1798
|
}
|
|
1812
|
-
}
|
|
1799
|
+
}
|
|
1800
|
+
},
|
|
1813
1801
|
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
tableClass = ' ' + c.table.className + ' ',
|
|
1819
|
-
widgets = [],
|
|
1820
|
-
time, time2, w, wd;
|
|
1821
|
-
// prevent numerous consecutive widget applications
|
|
1822
|
-
if (init !== false && table.hasInitialized && (table.isApplyingWidgets || table.isUpdating)) { return; }
|
|
1823
|
-
if (c.debug) { time = new Date(); }
|
|
1824
|
-
// look for widgets to apply from in table class
|
|
1802
|
+
addWidgetFromClass : function( table ) {
|
|
1803
|
+
var len, indx,
|
|
1804
|
+
c = table.config,
|
|
1805
|
+
// look for widgets to apply from table class
|
|
1825
1806
|
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1807
|
+
regex = '\\s' + c.widgetClass.replace( ts.regex.templateName, '([\\w-]+)' ) + '\\s',
|
|
1808
|
+
widgetClass = new RegExp( regex, 'g' ),
|
|
1809
|
+
// extract out the widget id from the table class (widget id's can include dashes)
|
|
1810
|
+
widget = ( ' ' + c.table.className + ' ' ).match( widgetClass );
|
|
1811
|
+
if ( widget ) {
|
|
1812
|
+
len = widget.length;
|
|
1813
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1814
|
+
c.widgets.push( widget[ indx ].replace( widgetClass, '$1' ) );
|
|
1836
1815
|
}
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1816
|
+
}
|
|
1817
|
+
},
|
|
1818
|
+
|
|
1819
|
+
applyWidget : function( table, init, callback ) {
|
|
1820
|
+
table = $( table )[ 0 ]; // in case this is called externally
|
|
1821
|
+
var indx, len, names, widget, name, applied, time, time2,
|
|
1822
|
+
c = table.config,
|
|
1823
|
+
widgets = [];
|
|
1824
|
+
// prevent numerous consecutive widget applications
|
|
1825
|
+
if ( init !== false && table.hasInitialized && ( table.isApplyingWidgets || table.isUpdating ) ) {
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
if ( c.debug ) { time = new Date(); }
|
|
1829
|
+
ts.addWidgetFromClass( table );
|
|
1830
|
+
if ( c.widgets.length ) {
|
|
1831
|
+
table.isApplyingWidgets = true;
|
|
1832
|
+
// ensure unique widget ids
|
|
1833
|
+
c.widgets = $.grep( c.widgets, function( val, index ) {
|
|
1834
|
+
return $.inArray( val, c.widgets ) === index;
|
|
1835
|
+
});
|
|
1836
|
+
names = c.widgets || [];
|
|
1837
|
+
len = names.length;
|
|
1838
|
+
// build widget array & add priority as needed
|
|
1839
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1840
|
+
widget = ts.getWidgetById( names[ indx ] );
|
|
1841
|
+
if ( widget && widget.id ) {
|
|
1842
|
+
// set priority to 10 if not defined
|
|
1843
|
+
if ( !widget.priority ) { widget.priority = 10; }
|
|
1844
|
+
widgets[ indx ] = widget;
|
|
1862
1845
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1846
|
+
}
|
|
1847
|
+
// sort widgets by priority
|
|
1848
|
+
widgets.sort( function( a, b ) {
|
|
1849
|
+
return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;
|
|
1850
|
+
});
|
|
1851
|
+
// add/update selected widgets
|
|
1852
|
+
len = widgets.length;
|
|
1853
|
+
if ( c.debug ) {
|
|
1854
|
+
console[ console.group ? 'group' : 'log' ]( 'Start ' + ( init ? 'initializing' : 'applying' ) + ' widgets' );
|
|
1855
|
+
}
|
|
1856
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1857
|
+
widget = widgets[ indx ];
|
|
1858
|
+
if ( widget ) {
|
|
1859
|
+
name = widget.id;
|
|
1860
|
+
applied = false;
|
|
1861
|
+
if ( c.debug ) { time2 = new Date(); }
|
|
1862
|
+
|
|
1863
|
+
if ( init || !( c.widgetInit[ name ] ) ) {
|
|
1864
|
+
// set init flag first to prevent calling init more than once (e.g. pager)
|
|
1865
|
+
c.widgetInit[ name ] = true;
|
|
1866
|
+
if ( table.hasInitialized ) {
|
|
1867
|
+
// don't reapply widget options on tablesorter init
|
|
1868
|
+
ts.applyWidgetOptions( table );
|
|
1884
1869
|
}
|
|
1885
|
-
if (
|
|
1870
|
+
if ( typeof widget.init === 'function' ) {
|
|
1886
1871
|
applied = true;
|
|
1887
|
-
if (c.debug) {
|
|
1888
|
-
console[ console.group ? 'group' : 'log' ]( '
|
|
1872
|
+
if ( c.debug ) {
|
|
1873
|
+
console[ console.group ? 'group' : 'log' ]( 'Initializing ' + name + ' widget' );
|
|
1889
1874
|
}
|
|
1890
|
-
widget.
|
|
1875
|
+
widget.init( table, widget, table.config, table.config.widgetOptions );
|
|
1891
1876
|
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1877
|
+
}
|
|
1878
|
+
if ( !init && typeof widget.format === 'function' ) {
|
|
1879
|
+
applied = true;
|
|
1880
|
+
if ( c.debug ) {
|
|
1881
|
+
console[ console.group ? 'group' : 'log' ]( 'Updating ' + name + ' widget' );
|
|
1882
|
+
}
|
|
1883
|
+
widget.format( table, table.config, table.config.widgetOptions, false );
|
|
1884
|
+
}
|
|
1885
|
+
if ( c.debug ) {
|
|
1886
|
+
if ( applied ) {
|
|
1887
|
+
console.log( 'Completed ' + ( init ? 'initializing ' : 'applying ' ) + name + ' widget' + ts.benchmark( time2 ) );
|
|
1888
|
+
if ( console.groupEnd ) { console.groupEnd(); }
|
|
1897
1889
|
}
|
|
1898
1890
|
}
|
|
1899
1891
|
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1892
|
+
}
|
|
1893
|
+
if ( c.debug && console.groupEnd ) { console.groupEnd(); }
|
|
1894
|
+
// callback executed on init only
|
|
1895
|
+
if ( !init && typeof callback === 'function' ) {
|
|
1896
|
+
callback( table );
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
setTimeout( function() {
|
|
1900
|
+
table.isApplyingWidgets = false;
|
|
1901
|
+
$.data( table, 'lastWidgetApplication', new Date() );
|
|
1902
|
+
c.$table.trigger('tablesorter-ready');
|
|
1903
|
+
}, 0 );
|
|
1904
|
+
if ( c.debug ) {
|
|
1905
|
+
widget = c.widgets.length;
|
|
1906
|
+
console.log( 'Completed ' +
|
|
1907
|
+
( init === true ? 'initializing ' : 'applying ' ) + widget +
|
|
1908
|
+
' widget' + ( widget !== 1 ? 's' : '' ) + ts.benchmark( time ) );
|
|
1909
|
+
}
|
|
1910
|
+
},
|
|
1911
|
+
|
|
1912
|
+
removeWidget : function( table, name, refreshing ) {
|
|
1913
|
+
table = $( table )[ 0 ];
|
|
1914
|
+
var index, widget, indx, len,
|
|
1915
|
+
c = table.config;
|
|
1916
|
+
// if name === true, add all widgets from $.tablesorter.widgets
|
|
1917
|
+
if ( name === true ) {
|
|
1918
|
+
name = [];
|
|
1919
|
+
len = ts.widgets.length;
|
|
1920
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1921
|
+
widget = ts.widgets[ indx ];
|
|
1922
|
+
if ( widget && widget.id ) {
|
|
1923
|
+
name.push( widget.id );
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
} else {
|
|
1927
|
+
// name can be either an array of widgets names,
|
|
1928
|
+
// or a space/comma separated list of widget names
|
|
1929
|
+
name = ( $.isArray( name ) ? name.join( ',' ) : name || '' ).toLowerCase().split( /[\s,]+/ );
|
|
1930
|
+
}
|
|
1931
|
+
len = name.length;
|
|
1932
|
+
for ( index = 0; index < len; index++ ) {
|
|
1933
|
+
widget = ts.getWidgetById( name[ index ] );
|
|
1934
|
+
indx = $.inArray( name[ index ], c.widgets );
|
|
1935
|
+
if ( widget && widget.remove ) {
|
|
1936
|
+
if ( c.debug ) {
|
|
1937
|
+
console.log( ( refreshing ? 'Refreshing' : 'Removing' ) + ' "' + name[ index ] + '" widget' );
|
|
1904
1938
|
}
|
|
1939
|
+
widget.remove( table, c, c.widgetOptions, refreshing );
|
|
1940
|
+
c.widgetInit[ name[ index ] ] = false;
|
|
1905
1941
|
}
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
}, 0);
|
|
1910
|
-
if (c.debug) {
|
|
1911
|
-
w = c.widgets.length;
|
|
1912
|
-
console.log( 'Completed ' + (init === true ? 'initializing ' : 'applying ') + w + ' widget' + (w !== 1 ? 's' : '') + ts.benchmark(time) );
|
|
1942
|
+
// don't remove the widget from config.widget if refreshing
|
|
1943
|
+
if ( indx >= 0 && refreshing !== true ) {
|
|
1944
|
+
c.widgets.splice( indx, 1 );
|
|
1913
1945
|
}
|
|
1914
|
-
}
|
|
1946
|
+
}
|
|
1947
|
+
},
|
|
1948
|
+
|
|
1949
|
+
refreshWidgets : function( table, doAll, dontapply ) {
|
|
1950
|
+
table = $( table )[ 0 ]; // see issue #243
|
|
1951
|
+
var indx, widget,
|
|
1952
|
+
c = table.config,
|
|
1953
|
+
curWidgets = c.widgets,
|
|
1954
|
+
widgets = ts.widgets,
|
|
1955
|
+
len = widgets.length,
|
|
1956
|
+
list = [],
|
|
1957
|
+
callback = function( table ) {
|
|
1958
|
+
$( table ).trigger( 'refreshComplete' );
|
|
1959
|
+
};
|
|
1960
|
+
// remove widgets not defined in config.widgets, unless doAll is true
|
|
1961
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
1962
|
+
widget = widgets[ indx ];
|
|
1963
|
+
if ( widget && widget.id && ( doAll || $.inArray( widget.id, curWidgets ) < 0 ) ) {
|
|
1964
|
+
list.push( widget.id );
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
ts.removeWidget( table, list.join( ',' ), true );
|
|
1968
|
+
if ( dontapply !== true ) {
|
|
1969
|
+
// call widget init if
|
|
1970
|
+
ts.applyWidget( table, doAll || false, callback );
|
|
1971
|
+
if ( doAll ) {
|
|
1972
|
+
// apply widget format
|
|
1973
|
+
ts.applyWidget( table, false, callback );
|
|
1974
|
+
}
|
|
1975
|
+
} else {
|
|
1976
|
+
callback( table );
|
|
1977
|
+
}
|
|
1978
|
+
},
|
|
1979
|
+
|
|
1980
|
+
/*
|
|
1981
|
+
██ ██ ██████ ██ ██ ██ ██████ ██ ██████ ▄█████
|
|
1982
|
+
██ ██ ██ ██ ██ ██ ██ ██ ██▄▄ ▀█▄
|
|
1983
|
+
██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀█▄
|
|
1984
|
+
▀████▀ ██ ██ ██████ ██ ██ ██ ██████ █████▀
|
|
1985
|
+
*/
|
|
1986
|
+
benchmark : function( diff ) {
|
|
1987
|
+
return ( ' ( ' + ( new Date().getTime() - diff.getTime() ) + 'ms )' );
|
|
1988
|
+
},
|
|
1989
|
+
// deprecated ts.log
|
|
1990
|
+
log : function() {
|
|
1991
|
+
console.log( arguments );
|
|
1992
|
+
},
|
|
1993
|
+
|
|
1994
|
+
// $.isEmptyObject from jQuery v1.4
|
|
1995
|
+
isEmptyObject : function( obj ) {
|
|
1996
|
+
/*jshint forin: false */
|
|
1997
|
+
for ( var name in obj ) {
|
|
1998
|
+
return false;
|
|
1999
|
+
}
|
|
2000
|
+
return true;
|
|
2001
|
+
},
|
|
2002
|
+
|
|
2003
|
+
isValueInArray : function( column, arry ) {
|
|
2004
|
+
var indx,
|
|
2005
|
+
len = arry && arry.length || 0;
|
|
2006
|
+
for ( indx = 0; indx < len; indx++ ) {
|
|
2007
|
+
if ( arry[ indx ][ 0 ] === column ) {
|
|
2008
|
+
return indx;
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
return -1;
|
|
2012
|
+
},
|
|
2013
|
+
|
|
2014
|
+
formatFloat : function( str, table ) {
|
|
2015
|
+
if ( typeof str !== 'string' || str === '' ) { return str; }
|
|
2016
|
+
// allow using formatFloat without a table; defaults to US number format
|
|
2017
|
+
var num,
|
|
2018
|
+
usFormat = table && table.config ? table.config.usNumberFormat !== false :
|
|
2019
|
+
typeof table !== 'undefined' ? table : true;
|
|
2020
|
+
if ( usFormat ) {
|
|
2021
|
+
// US Format - 1,234,567.89 -> 1234567.89
|
|
2022
|
+
str = str.replace( ts.regex.comma, '' );
|
|
2023
|
+
} else {
|
|
2024
|
+
// German Format = 1.234.567,89 -> 1234567.89
|
|
2025
|
+
// French Format = 1 234 567,89 -> 1234567.89
|
|
2026
|
+
str = str.replace( ts.regex.digitNonUS, '' ).replace( ts.regex.comma, '.' );
|
|
2027
|
+
}
|
|
2028
|
+
if ( ts.regex.digitNegativeTest.test( str ) ) {
|
|
2029
|
+
// make (#) into a negative number -> (10) = -10
|
|
2030
|
+
str = str.replace( ts.regex.digitNegativeReplace, '-$1' );
|
|
2031
|
+
}
|
|
2032
|
+
num = parseFloat( str );
|
|
2033
|
+
// return the text instead of zero
|
|
2034
|
+
return isNaN( num ) ? $.trim( str ) : num;
|
|
2035
|
+
},
|
|
2036
|
+
|
|
2037
|
+
isDigit : function( str ) {
|
|
2038
|
+
// replace all unwanted chars and match
|
|
2039
|
+
return isNaN( str ) ?
|
|
2040
|
+
ts.regex.digitTest.test( str.toString().replace( ts.regex.digitReplace, '' ) ) :
|
|
2041
|
+
str !== '';
|
|
2042
|
+
},
|
|
1915
2043
|
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
2044
|
+
// computeTableHeaderCellIndexes from:
|
|
2045
|
+
// http://www.javascripttoolbox.com/lib/table/examples.php
|
|
2046
|
+
// http://www.javascripttoolbox.com/temp/table_cellindex.html
|
|
2047
|
+
computeColumnIndex : function( $rows ) {
|
|
2048
|
+
var i, j, k, l, $cell, cell, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol,
|
|
2049
|
+
matrix = [],
|
|
2050
|
+
matrixrow = [];
|
|
2051
|
+
for ( i = 0; i < $rows.length; i++ ) {
|
|
2052
|
+
cells = $rows[ i ].cells;
|
|
2053
|
+
for ( j = 0; j < cells.length; j++ ) {
|
|
2054
|
+
cell = cells[ j ];
|
|
2055
|
+
$cell = $( cell );
|
|
2056
|
+
rowIndex = cell.parentNode.rowIndex;
|
|
2057
|
+
cellId = rowIndex + '-' + $cell.index();
|
|
2058
|
+
rowSpan = cell.rowSpan || 1;
|
|
2059
|
+
colSpan = cell.colSpan || 1;
|
|
2060
|
+
if ( typeof matrix[ rowIndex ] === 'undefined' ) {
|
|
2061
|
+
matrix[ rowIndex ] = [];
|
|
2062
|
+
}
|
|
2063
|
+
// Find first available column in the first row
|
|
2064
|
+
for ( k = 0; k < matrix[ rowIndex ].length + 1; k++ ) {
|
|
2065
|
+
if ( typeof matrix[ rowIndex ][ k ] === 'undefined' ) {
|
|
2066
|
+
firstAvailCol = k;
|
|
2067
|
+
break;
|
|
1928
2068
|
}
|
|
1929
2069
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
len = name.length;
|
|
1936
|
-
for (i = 0; i < len; i++) {
|
|
1937
|
-
widget = ts.getWidgetById(name[i]);
|
|
1938
|
-
indx = $.inArray( name[i], c.widgets );
|
|
1939
|
-
if ( widget && 'remove' in widget ) {
|
|
1940
|
-
if (c.debug && indx >= 0) { console.log( 'Removing "' + name[i] + '" widget' ); }
|
|
1941
|
-
if ( c.debug ) {
|
|
1942
|
-
console.log( ( refreshing ? 'Refreshing' : 'Removing' ) + ' "' + name[i] + '" widget' );
|
|
1943
|
-
}
|
|
1944
|
-
widget.remove(table, c, c.widgetOptions, refreshing);
|
|
1945
|
-
c.widgetInit[ name[i] ] = false;
|
|
2070
|
+
// add data-column (setAttribute = IE8+)
|
|
2071
|
+
if ( cell.setAttribute ) {
|
|
2072
|
+
cell.setAttribute( 'data-column', firstAvailCol );
|
|
2073
|
+
} else {
|
|
2074
|
+
$cell.attr( 'data-column', firstAvailCol );
|
|
1946
2075
|
}
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2076
|
+
for ( k = rowIndex; k < rowIndex + rowSpan; k++ ) {
|
|
2077
|
+
if ( typeof matrix[ k ] === 'undefined' ) {
|
|
2078
|
+
matrix[ k ] = [];
|
|
2079
|
+
}
|
|
2080
|
+
matrixrow = matrix[ k ];
|
|
2081
|
+
for ( l = firstAvailCol; l < firstAvailCol + colSpan; l++ ) {
|
|
2082
|
+
matrixrow[ l ] = 'x';
|
|
2083
|
+
}
|
|
1950
2084
|
}
|
|
1951
2085
|
}
|
|
1952
|
-
}
|
|
2086
|
+
}
|
|
2087
|
+
return matrixrow.length;
|
|
2088
|
+
},
|
|
1953
2089
|
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2090
|
+
// automatically add a colgroup with col elements set to a percentage width
|
|
2091
|
+
fixColumnWidth : function( table ) {
|
|
2092
|
+
table = $( table )[ 0 ];
|
|
2093
|
+
var overallWidth, percent, $tbodies, len, index,
|
|
2094
|
+
c = table.config,
|
|
2095
|
+
$colgroup = c.$table.children( 'colgroup' );
|
|
2096
|
+
// remove plugin-added colgroup, in case we need to refresh the widths
|
|
2097
|
+
if ( $colgroup.length && $colgroup.hasClass( ts.css.colgroup ) ) {
|
|
2098
|
+
$colgroup.remove();
|
|
2099
|
+
}
|
|
2100
|
+
if ( c.widthFixed && c.$table.children( 'colgroup' ).length === 0 ) {
|
|
2101
|
+
$colgroup = $( '<colgroup class="' + ts.css.colgroup + '">' );
|
|
2102
|
+
overallWidth = c.$table.width();
|
|
2103
|
+
// only add col for visible columns - fixes #371
|
|
2104
|
+
$tbodies = c.$tbodies.find( 'tr:first' ).children( ':visible' );
|
|
2105
|
+
len = $tbodies.length;
|
|
2106
|
+
for ( index = 0; index < len; index++ ) {
|
|
2107
|
+
percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
|
|
2108
|
+
$colgroup.append( $( '<col>' ).css( 'width', percent ) );
|
|
1970
2109
|
}
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2110
|
+
c.$table.prepend( $colgroup );
|
|
2111
|
+
}
|
|
2112
|
+
},
|
|
2113
|
+
|
|
2114
|
+
// get sorter, string, empty, etc options for each column from
|
|
2115
|
+
// jQuery data, metadata, header option or header class name ('sorter-false')
|
|
2116
|
+
// priority = jQuery data > meta > headers option > header class name
|
|
2117
|
+
getData : function( header, configHeader, key ) {
|
|
2118
|
+
var meta, cl4ss,
|
|
2119
|
+
val = '',
|
|
2120
|
+
$header = $( header );
|
|
2121
|
+
if ( !$header.length ) { return ''; }
|
|
2122
|
+
meta = $.metadata ? $header.metadata() : false;
|
|
2123
|
+
cl4ss = ' ' + ( $header.attr( 'class' ) || '' );
|
|
2124
|
+
if ( typeof $header.data( key ) !== 'undefined' ||
|
|
2125
|
+
typeof $header.data( key.toLowerCase() ) !== 'undefined' ) {
|
|
2126
|
+
// 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
|
|
2127
|
+
// 'data-sort-initial-order' is assigned to 'sortInitialOrder'
|
|
2128
|
+
val += $header.data( key ) || $header.data( key.toLowerCase() );
|
|
2129
|
+
} else if ( meta && typeof meta[ key ] !== 'undefined' ) {
|
|
2130
|
+
val += meta[ key ];
|
|
2131
|
+
} else if ( configHeader && typeof configHeader[ key ] !== 'undefined' ) {
|
|
2132
|
+
val += configHeader[ key ];
|
|
2133
|
+
} else if ( cl4ss !== ' ' && cl4ss.match( ' ' + key + '-' ) ) {
|
|
2134
|
+
// include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
|
|
2135
|
+
val = cl4ss.match( new RegExp( '\\s' + key + '-([\\w-]+)' ) )[ 1 ] || '';
|
|
2136
|
+
}
|
|
2137
|
+
return $.trim( val );
|
|
2138
|
+
},
|
|
2139
|
+
|
|
2140
|
+
getColumnData : function( table, obj, indx, getCell, $headers ) {
|
|
2141
|
+
if ( typeof obj === 'undefined' || obj === null ) { return; }
|
|
2142
|
+
table = $( table )[ 0 ];
|
|
2143
|
+
var $header, key,
|
|
2144
|
+
c = table.config,
|
|
2145
|
+
$cells = ( $headers || c.$headers ),
|
|
2146
|
+
// c.$headerIndexed is not defined initially
|
|
2147
|
+
$cell = c.$headerIndexed && c.$headerIndexed[ indx ] ||
|
|
2148
|
+
$cells.filter( '[data-column="' + indx + '"]:last' );
|
|
2149
|
+
if ( obj[ indx ] ) {
|
|
2150
|
+
return getCell ? obj[ indx ] : obj[ $cells.index( $cell ) ];
|
|
2151
|
+
}
|
|
2152
|
+
for ( key in obj ) {
|
|
2153
|
+
if ( typeof key === 'string' ) {
|
|
2154
|
+
$header = $cell
|
|
2155
|
+
// header cell with class/id
|
|
2156
|
+
.filter( key )
|
|
2157
|
+
// find elements within the header cell with cell/id
|
|
2158
|
+
.add( $cell.find( key ) );
|
|
2159
|
+
if ( $header.length ) {
|
|
2160
|
+
return obj[ key ];
|
|
1978
2161
|
}
|
|
1979
|
-
} else {
|
|
1980
|
-
callback(table);
|
|
1981
2162
|
}
|
|
1982
|
-
}
|
|
2163
|
+
}
|
|
2164
|
+
return;
|
|
2165
|
+
},
|
|
1983
2166
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
result = true;
|
|
2002
|
-
row = cache[ rowIndex ];
|
|
2003
|
-
parsed = ( allColumns ) ? row.slice(0, c.columns) : row[ column ];
|
|
2004
|
-
row = row[ c.columns ];
|
|
2005
|
-
raw = ( allColumns ) ? row.raw : row.raw[ column ];
|
|
2006
|
-
$cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column );
|
|
2007
|
-
if ( hasCallback ) {
|
|
2008
|
-
result = callback({
|
|
2009
|
-
tbodyIndex: tbodyIndex,
|
|
2010
|
-
rowIndex: rowIndex,
|
|
2011
|
-
parsed: parsed,
|
|
2012
|
-
raw: raw,
|
|
2013
|
-
$row: row.$row,
|
|
2014
|
-
$cell: $cell
|
|
2015
|
-
});
|
|
2016
|
-
}
|
|
2017
|
-
if ( result !== false ) {
|
|
2018
|
-
data.parsed.push( parsed );
|
|
2019
|
-
data.raw.push( raw );
|
|
2020
|
-
data.$cell.push( $cell );
|
|
2021
|
-
}
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
// return everything
|
|
2025
|
-
return data;
|
|
2167
|
+
// *** Process table ***
|
|
2168
|
+
// add processing indicator
|
|
2169
|
+
isProcessing : function( $table, toggle, $ths ) {
|
|
2170
|
+
$table = $( $table );
|
|
2171
|
+
var c = $table[ 0 ].config,
|
|
2172
|
+
// default to all headers
|
|
2173
|
+
$header = $ths || $table.find( '.' + ts.css.header );
|
|
2174
|
+
if ( toggle ) {
|
|
2175
|
+
// don't use sortList if custom $ths used
|
|
2176
|
+
if ( typeof $ths !== 'undefined' && c.sortList.length > 0 ) {
|
|
2177
|
+
// get headers from the sortList
|
|
2178
|
+
$header = $header.filter( function() {
|
|
2179
|
+
// get data-column from attr to keep compatibility with jQuery 1.2.6
|
|
2180
|
+
return this.sortDisabled ?
|
|
2181
|
+
false :
|
|
2182
|
+
ts.isValueInArray( parseFloat( $( this ).attr( 'data-column' ) ), c.sortList ) >= 0;
|
|
2183
|
+
});
|
|
2026
2184
|
}
|
|
2027
|
-
|
|
2185
|
+
$table.add( $header ).addClass( ts.css.processing + ' ' + c.cssProcessing );
|
|
2186
|
+
} else {
|
|
2187
|
+
$table.add( $header ).removeClass( ts.css.processing + ' ' + c.cssProcessing );
|
|
2188
|
+
}
|
|
2189
|
+
},
|
|
2028
2190
|
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
} else if (ch && typeof ch[key] !== 'undefined') {
|
|
2044
|
-
val += ch[key];
|
|
2045
|
-
} else if (cl !== ' ' && cl.match(' ' + key + '-')) {
|
|
2046
|
-
// include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
|
|
2047
|
-
val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || '';
|
|
2048
|
-
}
|
|
2049
|
-
return $.trim(val);
|
|
2050
|
-
};
|
|
2191
|
+
// detach tbody but save the position
|
|
2192
|
+
// don't use tbody because there are portions that look for a tbody index (updateCell)
|
|
2193
|
+
processTbody : function( table, $tb, getIt ) {
|
|
2194
|
+
table = $( table )[ 0 ];
|
|
2195
|
+
if ( getIt ) {
|
|
2196
|
+
table.isProcessing = true;
|
|
2197
|
+
$tb.before( '<colgroup class="tablesorter-savemyplace"/>' );
|
|
2198
|
+
return $.fn.detach ? $tb.detach() : $tb.remove();
|
|
2199
|
+
}
|
|
2200
|
+
var holdr = $( table ).find( 'colgroup.tablesorter-savemyplace' );
|
|
2201
|
+
$tb.insertAfter( holdr );
|
|
2202
|
+
holdr.remove();
|
|
2203
|
+
table.isProcessing = false;
|
|
2204
|
+
},
|
|
2051
2205
|
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2206
|
+
clearTableBody : function( table ) {
|
|
2207
|
+
$( table )[ 0 ].config.$tbodies.children().detach();
|
|
2208
|
+
},
|
|
2209
|
+
|
|
2210
|
+
// used when replacing accented characters during sorting
|
|
2211
|
+
characterEquivalents : {
|
|
2212
|
+
'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå
|
|
2213
|
+
'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ
|
|
2214
|
+
'c' : '\u00e7\u0107\u010d', // çćč
|
|
2215
|
+
'C' : '\u00c7\u0106\u010c', // ÇĆČ
|
|
2216
|
+
'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę
|
|
2217
|
+
'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
|
|
2218
|
+
'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
|
|
2219
|
+
'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
|
|
2220
|
+
'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō
|
|
2221
|
+
'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ
|
|
2222
|
+
'ss': '\u00df', // ß (s sharp)
|
|
2223
|
+
'SS': '\u1e9e', // ẞ (Capital sharp s)
|
|
2224
|
+
'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
|
|
2225
|
+
'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ
|
|
2226
|
+
},
|
|
2227
|
+
|
|
2228
|
+
replaceAccents : function( str ) {
|
|
2229
|
+
var chr,
|
|
2230
|
+
acc = '[',
|
|
2231
|
+
eq = ts.characterEquivalents;
|
|
2232
|
+
if ( !ts.characterRegex ) {
|
|
2233
|
+
ts.characterRegexArray = {};
|
|
2234
|
+
for ( chr in eq ) {
|
|
2235
|
+
if ( typeof chr === 'string' ) {
|
|
2236
|
+
acc += eq[ chr ];
|
|
2237
|
+
ts.characterRegexArray[ chr ] = new RegExp( '[' + eq[ chr ] + ']', 'g' );
|
|
2238
|
+
}
|
|
2069
2239
|
}
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2240
|
+
ts.characterRegex = new RegExp( acc + ']' );
|
|
2241
|
+
}
|
|
2242
|
+
if ( ts.characterRegex.test( str ) ) {
|
|
2243
|
+
for ( chr in eq ) {
|
|
2244
|
+
if ( typeof chr === 'string' ) {
|
|
2245
|
+
str = str.replace( ts.characterRegexArray[ chr ], chr );
|
|
2246
|
+
}
|
|
2073
2247
|
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
};
|
|
2248
|
+
}
|
|
2249
|
+
return str;
|
|
2250
|
+
},
|
|
2078
2251
|
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2252
|
+
// restore headers
|
|
2253
|
+
restoreHeaders : function( table ) {
|
|
2254
|
+
var index, $cell,
|
|
2255
|
+
c = $( table )[ 0 ].config,
|
|
2256
|
+
$headers = c.$table.find( c.selectorHeaders ),
|
|
2257
|
+
len = $headers.length;
|
|
2258
|
+
// don't use c.$headers here in case header cells were swapped
|
|
2259
|
+
for ( index = 0; index < len; index++ ) {
|
|
2260
|
+
$cell = $headers.eq( index );
|
|
2261
|
+
// only restore header cells if it is wrapped
|
|
2262
|
+
// because this is also used by the updateAll method
|
|
2263
|
+
if ( $cell.find( '.' + ts.css.headerIn ).length ) {
|
|
2264
|
+
$cell.html( c.headerContent[ index ] );
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
},
|
|
2087
2268
|
|
|
2088
|
-
|
|
2089
|
-
|
|
2269
|
+
destroy : function( table, removeClasses, callback ) {
|
|
2270
|
+
table = $( table )[ 0 ];
|
|
2271
|
+
if ( !table.hasInitialized ) { return; }
|
|
2272
|
+
// remove all widgets
|
|
2273
|
+
ts.removeWidget( table, true, false );
|
|
2274
|
+
var events,
|
|
2275
|
+
$t = $( table ),
|
|
2276
|
+
c = table.config,
|
|
2277
|
+
debug = c.debug,
|
|
2278
|
+
$h = $t.find( 'thead:first' ),
|
|
2279
|
+
$r = $h.find( 'tr.' + ts.css.headerRow ).removeClass( ts.css.headerRow + ' ' + c.cssHeaderRow ),
|
|
2280
|
+
$f = $t.find( 'tfoot:first > tr' ).children( 'th, td' );
|
|
2281
|
+
if ( removeClasses === false && $.inArray( 'uitheme', c.widgets ) >= 0 ) {
|
|
2282
|
+
// reapply uitheme classes, in case we want to maintain appearance
|
|
2283
|
+
$t.trigger( 'applyWidgetId', [ 'uitheme' ] );
|
|
2284
|
+
$t.trigger( 'applyWidgetId', [ 'zebra' ] );
|
|
2285
|
+
}
|
|
2286
|
+
// remove widget added rows, just in case
|
|
2287
|
+
$h.find( 'tr' ).not( $r ).remove();
|
|
2288
|
+
// disable tablesorter
|
|
2289
|
+
events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
|
|
2290
|
+
'appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress ' +
|
|
2291
|
+
'sortBegin sortEnd resetToLoadState '.split( ' ' )
|
|
2292
|
+
.join( c.namespace + ' ' );
|
|
2293
|
+
$t
|
|
2294
|
+
.removeData( 'tablesorter' )
|
|
2295
|
+
.unbind( events.replace( ts.regex.spaces, ' ' ) );
|
|
2296
|
+
c.$headers
|
|
2297
|
+
.add( $f )
|
|
2298
|
+
.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join( ' ' ) )
|
|
2299
|
+
.removeAttr( 'data-column' )
|
|
2300
|
+
.removeAttr( 'aria-label' )
|
|
2301
|
+
.attr( 'aria-disabled', 'true' );
|
|
2302
|
+
$r
|
|
2303
|
+
.find( c.selectorSort )
|
|
2304
|
+
.unbind( ( 'mousedown mouseup keypress '.split( ' ' ).join( c.namespace + ' ' ) ).replace( ts.regex.spaces, ' ' ) );
|
|
2305
|
+
ts.restoreHeaders( table );
|
|
2306
|
+
$t.toggleClass( ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false );
|
|
2307
|
+
// clear flag in case the plugin is initialized again
|
|
2308
|
+
table.hasInitialized = false;
|
|
2309
|
+
delete table.config.cache;
|
|
2310
|
+
if ( typeof callback === 'function' ) {
|
|
2311
|
+
callback( table );
|
|
2312
|
+
}
|
|
2313
|
+
if ( debug ) {
|
|
2314
|
+
console.log( 'tablesorter has been removed' );
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2090
2317
|
|
|
2091
|
-
|
|
2092
|
-
var ts = $.tablesorter;
|
|
2318
|
+
};
|
|
2093
2319
|
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2320
|
+
$.fn.tablesorter = function( settings ) {
|
|
2321
|
+
return this.each( function() {
|
|
2322
|
+
var table = this,
|
|
2323
|
+
// merge & extend config options
|
|
2324
|
+
c = $.extend( true, {}, ts.defaults, settings, ts.instanceMethods );
|
|
2325
|
+
// save initial settings
|
|
2326
|
+
c.originalSettings = settings;
|
|
2327
|
+
// create a table from data (build table widget)
|
|
2328
|
+
if ( !table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE' ) {
|
|
2329
|
+
// return the table (in case the original target is the table's container)
|
|
2330
|
+
ts.buildTable( table, c );
|
|
2331
|
+
} else {
|
|
2332
|
+
ts.setup( table, c );
|
|
2333
|
+
}
|
|
2334
|
+
});
|
|
2335
|
+
};
|
|
2098
2336
|
|
|
2099
2337
|
// set up debug logs
|
|
2100
2338
|
if ( !( window.console && window.console.log ) ) {
|
|
2339
|
+
// access $.tablesorter.logs for browsers that don't have a console...
|
|
2101
2340
|
ts.logs = [];
|
|
2102
2341
|
/*jshint -W020 */
|
|
2103
2342
|
console = {};
|
|
2104
2343
|
console.log = console.warn = console.error = console.table = function() {
|
|
2105
|
-
|
|
2344
|
+
var arg = arguments.length > 1 ? arguments : arguments[0];
|
|
2345
|
+
ts.logs.push({ date: Date.now(), log: arg });
|
|
2106
2346
|
};
|
|
2107
2347
|
}
|
|
2108
2348
|
|
|
2109
|
-
ts.log = function(){
|
|
2110
|
-
console.log( arguments );
|
|
2111
|
-
};
|
|
2112
|
-
ts.benchmark = function( diff ) {
|
|
2113
|
-
return ( ' (' + ( new Date().getTime() - diff.getTime() ) + 'ms)' );
|
|
2114
|
-
};
|
|
2115
|
-
|
|
2116
2349
|
// add default parsers
|
|
2117
2350
|
ts.addParser({
|
|
2118
|
-
id: 'no-parser',
|
|
2119
|
-
is: function() {
|
|
2351
|
+
id : 'no-parser',
|
|
2352
|
+
is : function() {
|
|
2120
2353
|
return false;
|
|
2121
2354
|
},
|
|
2122
|
-
format: function() {
|
|
2355
|
+
format : function() {
|
|
2123
2356
|
return '';
|
|
2124
2357
|
},
|
|
2125
|
-
type: 'text'
|
|
2358
|
+
type : 'text'
|
|
2126
2359
|
});
|
|
2127
2360
|
|
|
2128
2361
|
ts.addParser({
|
|
2129
|
-
id: 'text',
|
|
2130
|
-
is: function() {
|
|
2362
|
+
id : 'text',
|
|
2363
|
+
is : function() {
|
|
2131
2364
|
return true;
|
|
2132
2365
|
},
|
|
2133
|
-
format: function(
|
|
2366
|
+
format : function( str, table ) {
|
|
2134
2367
|
var c = table.config;
|
|
2135
|
-
if (
|
|
2136
|
-
|
|
2137
|
-
|
|
2368
|
+
if ( str ) {
|
|
2369
|
+
str = $.trim( c.ignoreCase ? str.toLocaleLowerCase() : str );
|
|
2370
|
+
str = c.sortLocaleCompare ? ts.replaceAccents( str ) : str;
|
|
2138
2371
|
}
|
|
2139
|
-
return
|
|
2372
|
+
return str;
|
|
2140
2373
|
},
|
|
2141
|
-
type: 'text'
|
|
2374
|
+
type : 'text'
|
|
2142
2375
|
});
|
|
2143
2376
|
|
|
2144
2377
|
ts.regex.nondigit = /[^\w,. \-()]/g;
|
|
2145
2378
|
ts.addParser({
|
|
2146
|
-
id: 'digit',
|
|
2147
|
-
is: function(
|
|
2148
|
-
return ts.isDigit(
|
|
2379
|
+
id : 'digit',
|
|
2380
|
+
is : function( str ) {
|
|
2381
|
+
return ts.isDigit( str );
|
|
2149
2382
|
},
|
|
2150
|
-
format: function(
|
|
2151
|
-
var
|
|
2152
|
-
return
|
|
2153
|
-
|
|
2383
|
+
format : function( str, table ) {
|
|
2384
|
+
var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
|
|
2385
|
+
return str && typeof num === 'number' ? num :
|
|
2386
|
+
str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
|
|
2154
2387
|
},
|
|
2155
|
-
type: 'numeric'
|
|
2388
|
+
type : 'numeric'
|
|
2156
2389
|
});
|
|
2157
2390
|
|
|
2158
2391
|
ts.regex.currencyReplace = /[+\-,. ]/g;
|
|
2159
2392
|
ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
|
|
2160
2393
|
ts.addParser({
|
|
2161
|
-
id: 'currency',
|
|
2162
|
-
is: function(
|
|
2163
|
-
|
|
2394
|
+
id : 'currency',
|
|
2395
|
+
is : function( str ) {
|
|
2396
|
+
str = ( str || '' ).replace( ts.regex.currencyReplace, '' );
|
|
2164
2397
|
// test for £$€¤¥¢
|
|
2165
|
-
return ts.regex.currencyTest.test(
|
|
2398
|
+
return ts.regex.currencyTest.test( str );
|
|
2166
2399
|
},
|
|
2167
|
-
format: function(
|
|
2168
|
-
var
|
|
2169
|
-
return
|
|
2170
|
-
|
|
2400
|
+
format : function( str, table ) {
|
|
2401
|
+
var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
|
|
2402
|
+
return str && typeof num === 'number' ? num :
|
|
2403
|
+
str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
|
|
2171
2404
|
},
|
|
2172
|
-
type: 'numeric'
|
|
2405
|
+
type : 'numeric'
|
|
2173
2406
|
});
|
|
2174
2407
|
|
|
2175
2408
|
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
|
|
@@ -2177,72 +2410,72 @@
|
|
|
2177
2410
|
ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
|
|
2178
2411
|
ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\//;
|
|
2179
2412
|
ts.addParser({
|
|
2180
|
-
id: 'url',
|
|
2181
|
-
is: function(
|
|
2182
|
-
return ts.regex.urlProtocolTest.test(
|
|
2413
|
+
id : 'url',
|
|
2414
|
+
is : function( str ) {
|
|
2415
|
+
return ts.regex.urlProtocolTest.test( str );
|
|
2183
2416
|
},
|
|
2184
|
-
format: function(
|
|
2185
|
-
return
|
|
2417
|
+
format : function( str ) {
|
|
2418
|
+
return str ? $.trim( str.replace( ts.regex.urlProtocolReplace, '' ) ) : str;
|
|
2186
2419
|
},
|
|
2187
2420
|
parsed : true, // filter widget flag
|
|
2188
|
-
type: 'text'
|
|
2421
|
+
type : 'text'
|
|
2189
2422
|
});
|
|
2190
2423
|
|
|
2191
2424
|
ts.regex.dash = /-/g;
|
|
2192
2425
|
ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
|
|
2193
2426
|
ts.addParser({
|
|
2194
|
-
id: 'isoDate',
|
|
2195
|
-
is: function(
|
|
2196
|
-
return ts.regex.isoDate.test(
|
|
2427
|
+
id : 'isoDate',
|
|
2428
|
+
is : function( str ) {
|
|
2429
|
+
return ts.regex.isoDate.test( str );
|
|
2197
2430
|
},
|
|
2198
|
-
format: function(
|
|
2199
|
-
var date =
|
|
2200
|
-
return date instanceof Date && isFinite(date) ? date.getTime() :
|
|
2431
|
+
format : function( str, table ) {
|
|
2432
|
+
var date = str ? new Date( str.replace( ts.regex.dash, '/' ) ) : str;
|
|
2433
|
+
return date instanceof Date && isFinite( date ) ? date.getTime() : str;
|
|
2201
2434
|
},
|
|
2202
|
-
type: 'numeric'
|
|
2435
|
+
type : 'numeric'
|
|
2203
2436
|
});
|
|
2204
2437
|
|
|
2205
2438
|
ts.regex.percent = /%/g;
|
|
2206
2439
|
ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
|
|
2207
2440
|
ts.addParser({
|
|
2208
|
-
id: 'percent',
|
|
2209
|
-
is: function(
|
|
2210
|
-
return ts.regex.percentTest.test(
|
|
2441
|
+
id : 'percent',
|
|
2442
|
+
is : function( str ) {
|
|
2443
|
+
return ts.regex.percentTest.test( str ) && str.length < 15;
|
|
2211
2444
|
},
|
|
2212
|
-
format: function(
|
|
2213
|
-
return
|
|
2445
|
+
format : function( str, table ) {
|
|
2446
|
+
return str ? ts.formatFloat( str.replace( ts.regex.percent, '' ), table ) : str;
|
|
2214
2447
|
},
|
|
2215
|
-
type: 'numeric'
|
|
2448
|
+
type : 'numeric'
|
|
2216
2449
|
});
|
|
2217
2450
|
|
|
2218
2451
|
// added image parser to core v2.17.9
|
|
2219
2452
|
ts.addParser({
|
|
2220
|
-
id: 'image',
|
|
2221
|
-
is: function(
|
|
2222
|
-
return $node.find('img').length > 0;
|
|
2453
|
+
id : 'image',
|
|
2454
|
+
is : function( str, table, node, $node ) {
|
|
2455
|
+
return $node.find( 'img' ).length > 0;
|
|
2223
2456
|
},
|
|
2224
|
-
format: function(
|
|
2225
|
-
return $(cell).find('img').attr(table.config.imgAttr || 'alt') ||
|
|
2457
|
+
format : function( str, table, cell ) {
|
|
2458
|
+
return $( cell ).find( 'img' ).attr( table.config.imgAttr || 'alt' ) || str;
|
|
2226
2459
|
},
|
|
2227
2460
|
parsed : true, // filter widget flag
|
|
2228
|
-
type: 'text'
|
|
2461
|
+
type : 'text'
|
|
2229
2462
|
});
|
|
2230
2463
|
|
|
2231
2464
|
ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
|
|
2232
2465
|
ts.regex.usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i;
|
|
2233
2466
|
ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
|
|
2234
2467
|
ts.addParser({
|
|
2235
|
-
id: 'usLongDate',
|
|
2236
|
-
is: function(
|
|
2468
|
+
id : 'usLongDate',
|
|
2469
|
+
is : function( str ) {
|
|
2237
2470
|
// two digit years are not allowed cross-browser
|
|
2238
2471
|
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
|
|
2239
|
-
return ts.regex.usLongDateTest1.test(
|
|
2472
|
+
return ts.regex.usLongDateTest1.test( str ) || ts.regex.usLongDateTest2.test( str );
|
|
2240
2473
|
},
|
|
2241
|
-
format: function(
|
|
2242
|
-
var date =
|
|
2243
|
-
return date instanceof Date && isFinite(date) ? date.getTime() :
|
|
2474
|
+
format : function( str, table ) {
|
|
2475
|
+
var date = str ? new Date( str.replace( ts.regex.dateReplace, '$1 $2' ) ) : str;
|
|
2476
|
+
return date instanceof Date && isFinite( date ) ? date.getTime() : str;
|
|
2244
2477
|
},
|
|
2245
|
-
type: 'numeric'
|
|
2478
|
+
type : 'numeric'
|
|
2246
2479
|
});
|
|
2247
2480
|
|
|
2248
2481
|
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
|
|
@@ -2252,100 +2485,126 @@
|
|
|
2252
2485
|
// XXY covers MDY & DMY formats
|
|
2253
2486
|
ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
|
|
2254
2487
|
ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
|
|
2488
|
+
ts.convertFormat = function( dateString, format ) {
|
|
2489
|
+
dateString = ( dateString || '' )
|
|
2490
|
+
.replace( ts.regex.spaces, ' ' )
|
|
2491
|
+
.replace( ts.regex.shortDateReplace, '/' );
|
|
2492
|
+
if ( format === 'mmddyyyy' ) {
|
|
2493
|
+
dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$1/$2' );
|
|
2494
|
+
} else if ( format === 'ddmmyyyy' ) {
|
|
2495
|
+
dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$2/$1' );
|
|
2496
|
+
} else if ( format === 'yyyymmdd' ) {
|
|
2497
|
+
dateString = dateString.replace( ts.regex.shortDateYMD, '$1/$2/$3' );
|
|
2498
|
+
}
|
|
2499
|
+
var date = new Date( dateString );
|
|
2500
|
+
return date instanceof Date && isFinite( date ) ? date.getTime() : '';
|
|
2501
|
+
};
|
|
2502
|
+
|
|
2255
2503
|
ts.addParser({
|
|
2256
|
-
id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
|
|
2257
|
-
is: function(
|
|
2258
|
-
|
|
2259
|
-
return ts.regex.shortDateTest.test(
|
|
2260
|
-
},
|
|
2261
|
-
format: function(
|
|
2262
|
-
if (
|
|
2263
|
-
var
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') ||
|
|
2504
|
+
id : 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
|
|
2505
|
+
is : function( str ) {
|
|
2506
|
+
str = ( str || '' ).replace( ts.regex.spaces, ' ' ).replace( ts.regex.shortDateReplace, '/' );
|
|
2507
|
+
return ts.regex.shortDateTest.test( str );
|
|
2508
|
+
},
|
|
2509
|
+
format : function( str, table, cell, cellIndex ) {
|
|
2510
|
+
if ( str ) {
|
|
2511
|
+
var c = table.config,
|
|
2512
|
+
$header = c.$headerIndexed[ cellIndex ],
|
|
2513
|
+
format = $header.length && $header.data( 'dateFormat' ) ||
|
|
2514
|
+
ts.getData( $header, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat' ) ||
|
|
2268
2515
|
c.dateFormat;
|
|
2269
|
-
|
|
2270
|
-
if (
|
|
2271
|
-
|
|
2272
|
-
} else if (format === 'ddmmyyyy') {
|
|
2273
|
-
d = d.replace(ts.regex.shortDateXXY, '$3/$2/$1');
|
|
2274
|
-
} else if (format === 'yyyymmdd') {
|
|
2275
|
-
d = d.replace(ts.regex.shortDateYMD, '$1/$2/$3');
|
|
2516
|
+
// save format because getData can be slow...
|
|
2517
|
+
if ( $header.length ) {
|
|
2518
|
+
$header.data( 'dateFormat', format );
|
|
2276
2519
|
}
|
|
2277
|
-
|
|
2278
|
-
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
|
2520
|
+
return ts.convertFormat( str, format ) || str;
|
|
2279
2521
|
}
|
|
2280
|
-
return
|
|
2522
|
+
return str;
|
|
2281
2523
|
},
|
|
2282
|
-
type: 'numeric'
|
|
2524
|
+
type : 'numeric'
|
|
2283
2525
|
});
|
|
2284
2526
|
|
|
2285
|
-
|
|
2527
|
+
// match 24 hour time & 12 hours time + am/pm - see http://regexr.com/3c3tk
|
|
2528
|
+
ts.regex.timeTest = /^([1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)$/i;
|
|
2529
|
+
ts.regex.timeMatch = /([1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i;
|
|
2286
2530
|
ts.addParser({
|
|
2287
|
-
id: 'time',
|
|
2288
|
-
is: function(
|
|
2289
|
-
return ts.regex.timeTest.test(
|
|
2531
|
+
id : 'time',
|
|
2532
|
+
is : function( str ) {
|
|
2533
|
+
return ts.regex.timeTest.test( str );
|
|
2290
2534
|
},
|
|
2291
|
-
format: function(
|
|
2292
|
-
|
|
2293
|
-
|
|
2535
|
+
format : function( str, table ) {
|
|
2536
|
+
// isolate time... ignore month, day and year
|
|
2537
|
+
var temp,
|
|
2538
|
+
timePart = ( str || '' ).match( ts.regex.timeMatch ),
|
|
2539
|
+
orig = new Date( str ),
|
|
2540
|
+
// no time component? default to 00:00 by leaving it out, but only if str is defined
|
|
2541
|
+
time = str && ( timePart !== null ? timePart[ 0 ] : '00:00 AM' ),
|
|
2542
|
+
date = time ? new Date( '2000/01/01 ' + time.replace( ts.regex.dateReplace, '$1 $2' ) ) : time;
|
|
2543
|
+
if ( date instanceof Date && isFinite( date ) ) {
|
|
2544
|
+
temp = orig instanceof Date && isFinite( orig ) ? orig.getTime() : 0;
|
|
2545
|
+
// if original string was a valid date, add it to the decimal so the column sorts in some kind of order
|
|
2546
|
+
// luckily new Date() ignores the decimals
|
|
2547
|
+
return temp ? parseFloat( date.getTime() + '.' + orig.getTime() ) : date.getTime();
|
|
2548
|
+
}
|
|
2549
|
+
return str;
|
|
2294
2550
|
},
|
|
2295
|
-
type: 'numeric'
|
|
2551
|
+
type : 'numeric'
|
|
2296
2552
|
});
|
|
2297
2553
|
|
|
2298
2554
|
ts.addParser({
|
|
2299
|
-
id: 'metadata',
|
|
2300
|
-
is: function() {
|
|
2555
|
+
id : 'metadata',
|
|
2556
|
+
is : function() {
|
|
2301
2557
|
return false;
|
|
2302
2558
|
},
|
|
2303
|
-
format: function(
|
|
2559
|
+
format : function( str, table, cell ) {
|
|
2304
2560
|
var c = table.config,
|
|
2305
|
-
p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
|
|
2306
|
-
return $(cell).metadata()[p];
|
|
2561
|
+
p = ( !c.parserMetadataName ) ? 'sortValue' : c.parserMetadataName;
|
|
2562
|
+
return $( cell ).metadata()[ p ];
|
|
2307
2563
|
},
|
|
2308
|
-
type: 'numeric'
|
|
2564
|
+
type : 'numeric'
|
|
2309
2565
|
});
|
|
2310
2566
|
|
|
2567
|
+
/*
|
|
2568
|
+
██████ ██████ █████▄ █████▄ ▄████▄
|
|
2569
|
+
▄█▀ ██▄▄ ██▄▄██ ██▄▄██ ██▄▄██
|
|
2570
|
+
▄█▀ ██▀▀ ██▀▀██ ██▀▀█ ██▀▀██
|
|
2571
|
+
██████ ██████ █████▀ ██ ██ ██ ██
|
|
2572
|
+
*/
|
|
2311
2573
|
// add default widgets
|
|
2312
2574
|
ts.addWidget({
|
|
2313
|
-
id: 'zebra',
|
|
2314
|
-
priority: 90,
|
|
2315
|
-
format: function(table, c, wo) {
|
|
2316
|
-
var $
|
|
2317
|
-
child = new RegExp(c.cssChildRow, 'i'),
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
time = new Date();
|
|
2321
|
-
}
|
|
2322
|
-
for (k = 0; k < b.length; k++ ) {
|
|
2575
|
+
id : 'zebra',
|
|
2576
|
+
priority : 90,
|
|
2577
|
+
format : function( table, c, wo ) {
|
|
2578
|
+
var $visibleRows, $row, count, isEven, tbodyIndex, rowIndex, len,
|
|
2579
|
+
child = new RegExp( c.cssChildRow, 'i' ),
|
|
2580
|
+
$tbodies = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) );
|
|
2581
|
+
for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
|
|
2323
2582
|
// loop through the visible rows
|
|
2324
|
-
|
|
2325
|
-
$
|
|
2326
|
-
len = $
|
|
2327
|
-
for (
|
|
2328
|
-
$
|
|
2583
|
+
count = 0;
|
|
2584
|
+
$visibleRows = $tbodies.eq( tbodyIndex ).children( 'tr:visible' ).not( c.selectorRemove );
|
|
2585
|
+
len = $visibleRows.length;
|
|
2586
|
+
for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
|
|
2587
|
+
$row = $visibleRows.eq( rowIndex );
|
|
2329
2588
|
// style child rows the same way the parent row was styled
|
|
2330
|
-
if ( !child.test( $
|
|
2331
|
-
|
|
2332
|
-
$
|
|
2333
|
-
.removeClass( wo.zebra[
|
|
2334
|
-
.addClass( wo.zebra[
|
|
2589
|
+
if ( !child.test( $row[ 0 ].className ) ) { count++; }
|
|
2590
|
+
isEven = ( count % 2 === 0 );
|
|
2591
|
+
$row
|
|
2592
|
+
.removeClass( wo.zebra[ isEven ? 1 : 0 ] )
|
|
2593
|
+
.addClass( wo.zebra[ isEven ? 0 : 1 ] );
|
|
2335
2594
|
}
|
|
2336
2595
|
}
|
|
2337
2596
|
},
|
|
2338
|
-
remove: function(table, c, wo, refreshing){
|
|
2339
|
-
if (refreshing) { return; }
|
|
2340
|
-
var
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
for (
|
|
2344
|
-
$
|
|
2345
|
-
$
|
|
2346
|
-
ts.processTbody(table, $
|
|
2597
|
+
remove : function( table, c, wo, refreshing ) {
|
|
2598
|
+
if ( refreshing ) { return; }
|
|
2599
|
+
var tbodyIndex, $tbody,
|
|
2600
|
+
$tbodies = c.$tbodies,
|
|
2601
|
+
toRemove = ( wo.zebra || [ 'even', 'odd' ] ).join( ' ' );
|
|
2602
|
+
for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ){
|
|
2603
|
+
$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
|
|
2604
|
+
$tbody.children().removeClass( toRemove );
|
|
2605
|
+
ts.processTbody( table, $tbody, false ); // restore tbody
|
|
2347
2606
|
}
|
|
2348
2607
|
}
|
|
2349
2608
|
});
|
|
2350
2609
|
|
|
2351
|
-
})(jQuery);
|
|
2610
|
+
})( jQuery );
|