jquery-tablesorter 0.0.5 → 1.0.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.
- data/README.markdown +25 -31
- data/Rakefile +2 -35
- data/lib/jquery-tablesorter/version.rb +1 -1
- data/lib/tasks/jquery-tablesorter_tasks.rake +24 -0
- data/vendor/assets/javascripts/jquery-tablesorter.js +1 -2
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.metadata.js +148 -0
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +1138 -0
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +450 -0
- data/vendor/assets/stylesheets/jquery-tablesorter/blue.css +3 -0
- data/vendor/assets/stylesheets/jquery-tablesorter/blue/style.css +110 -0
- data/vendor/assets/stylesheets/jquery-tablesorter/ui.css +4 -0
- data/vendor/assets/stylesheets/jquery-tablesorter/ui/style.css +60 -0
- metadata +23 -15
- data/vendor/assets/images/jquery-tablesorter/blue/asc.gif +0 -0
- data/vendor/assets/images/jquery-tablesorter/blue/bg.gif +0 -0
- data/vendor/assets/images/jquery-tablesorter/blue/desc.gif +0 -0
- data/vendor/assets/images/jquery-tablesorter/green/asc.png +0 -0
- data/vendor/assets/images/jquery-tablesorter/green/bg.png +0 -0
- data/vendor/assets/images/jquery-tablesorter/green/desc.png +0 -0
- data/vendor/assets/javascripts/jquery-tablesorter/jquery-tablesorter.js +0 -1031
- data/vendor/assets/javascripts/jquery-tablesorter/pager.js +0 -184
- data/vendor/assets/stylesheets/jquery-tablesorter/blue.css.scss +0 -39
- data/vendor/assets/stylesheets/jquery-tablesorter/green.css.scss +0 -39
data/README.markdown
CHANGED
@@ -3,7 +3,13 @@ jQuery Table Sorter plugin for Rails
|
|
3
3
|
|
4
4
|
Simple integration of jquery-tablesorter into the asset pipeline.
|
5
5
|
|
6
|
-
|
6
|
+
Current version: 2.3.4
|
7
|
+
|
8
|
+
NOTICE:
|
9
|
+
---
|
10
|
+
|
11
|
+
v0.0.5 users, from v1.0.0, the tablesorter's version will change
|
12
|
+
to [Mottie's fork] :smile:.
|
7
13
|
|
8
14
|
Install
|
9
15
|
---
|
@@ -21,52 +27,40 @@ Rails 3.1 and higher
|
|
21
27
|
Usage
|
22
28
|
---
|
23
29
|
|
24
|
-
In your
|
30
|
+
### In your `application.js`
|
25
31
|
|
26
32
|
```
|
27
33
|
require jquery-tablesorter
|
28
34
|
```
|
29
35
|
|
30
|
-
|
36
|
+
this will require `jquery.metadata`, `jquery.tablesorter`,
|
37
|
+
`jquery.tablesorter.widgets`
|
38
|
+
|
39
|
+
Or you can include single file with:
|
31
40
|
|
32
41
|
```
|
33
|
-
require jquery-tablesorter
|
42
|
+
require jquery-tablesorter/jquery.metadata
|
43
|
+
require jquery-tablesorter/jquery.tablesorter
|
44
|
+
require jquery-tablesorter/jquery.tablesorter.widgets
|
34
45
|
```
|
35
46
|
|
36
|
-
Avaliable theme names:
|
37
|
-
|
38
|
-
* green
|
39
|
-
* blue
|
40
47
|
|
41
|
-
In
|
48
|
+
### In your `application.css`
|
42
49
|
|
43
50
|
```
|
44
|
-
|
51
|
+
require jquery-tablesorter/<theme name>
|
45
52
|
```
|
46
53
|
|
47
|
-
|
48
|
-
---
|
49
|
-
|
50
|
-
#### v0.0.5
|
51
|
-
|
52
|
-
* FIX: now require pager plugin as default.
|
53
|
-
* FIX: move assets files from app to vendor & cleanup.
|
54
|
-
* FIX: remove dependency on `jquery-rails`
|
55
|
-
* FIX: remove development dependency on `sqlite3`
|
56
|
-
|
57
|
-
#### v0.0.4
|
58
|
-
|
59
|
-
* FIX: update gemspec to be compatible with Rails 3.2, Thanks to [derekprior](https://github.com/derekprior).
|
60
|
-
|
61
|
-
#### v0.0.3
|
54
|
+
Avaliable theme names:
|
62
55
|
|
63
|
-
*
|
64
|
-
*
|
56
|
+
* blue
|
57
|
+
* ui
|
65
58
|
|
66
|
-
|
59
|
+
### In CoffeeScript file:
|
67
60
|
|
68
|
-
|
61
|
+
```
|
62
|
+
$('table.tablesorter').tablesorter()
|
63
|
+
```
|
69
64
|
|
70
|
-
|
65
|
+
[Mottie's fork]: https://github.com/Mottie/tablesorter
|
71
66
|
|
72
|
-
* NEW: added jquery-tablesorter plugin, use `require jquery-tablesorter/jquery-tablesorter` to require javascript and `require jquery-tablesorter/<theme name>` to require stylesheet.
|
data/Rakefile
CHANGED
@@ -1,39 +1,6 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
begin
|
3
|
-
require 'bundler/setup'
|
4
|
-
rescue LoadError
|
5
|
-
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
-
end
|
7
|
-
begin
|
8
|
-
require 'rdoc/task'
|
9
|
-
rescue LoadError
|
10
|
-
require 'rdoc/rdoc'
|
11
|
-
require 'rake/rdoctask'
|
12
|
-
RDoc::Task = Rake::RDocTask
|
13
|
-
end
|
14
|
-
|
15
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
-
rdoc.rdoc_dir = 'rdoc'
|
17
|
-
rdoc.title = 'JqueryTablesorter'
|
18
|
-
rdoc.options << '--line-numbers'
|
19
|
-
rdoc.rdoc_files.include('README.rdoc')
|
20
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
-
end
|
22
|
-
|
23
|
-
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
24
|
-
load 'rails/tasks/engine.rake'
|
25
|
-
|
26
2
|
|
3
|
+
require 'bundler'
|
27
4
|
Bundler::GemHelper.install_tasks
|
28
5
|
|
29
|
-
|
30
|
-
|
31
|
-
Rake::TestTask.new(:test) do |t|
|
32
|
-
t.libs << 'lib'
|
33
|
-
t.libs << 'test'
|
34
|
-
t.pattern = 'test/**/*_test.rb'
|
35
|
-
t.verbose = false
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
task :default => :test
|
6
|
+
load 'lib/tasks/jquery-tablesorter_tasks.rake'
|
@@ -2,3 +2,27 @@
|
|
2
2
|
# task :jquery-tablesorter do
|
3
3
|
# # Task goes here
|
4
4
|
# end
|
5
|
+
#
|
6
|
+
namespace :jquery_tablesorter do
|
7
|
+
desc 'update tablesorter'
|
8
|
+
task :update do
|
9
|
+
# js files
|
10
|
+
javascript_files = [
|
11
|
+
'tablesorter/js/jquery.metadata.js',
|
12
|
+
'tablesorter/js/jquery.tablesorter.js',
|
13
|
+
'tablesorter/js/jquery.tablesorter.widgets.js'
|
14
|
+
]
|
15
|
+
FileUtils.cp javascript_files,
|
16
|
+
'vendor/assets/javascripts/jquery-tablesorter/',
|
17
|
+
:verbose => true
|
18
|
+
|
19
|
+
# stylesheets
|
20
|
+
FileUtils.cp 'tablesorter/css/blue/style.css',
|
21
|
+
'vendor/assets/stylesheets/jquery-tablesorter/blue',
|
22
|
+
:verbose => true
|
23
|
+
FileUtils.cp 'tablesorter/css/ui/style.css',
|
24
|
+
'vendor/assets/stylesheets/jquery-tablesorter/ui',
|
25
|
+
:verbose => true
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -1,2 +1 @@
|
|
1
|
-
//=
|
2
|
-
//= require jquery-tablesorter/pager
|
1
|
+
//= require_tree ./jquery-tablesorter
|
@@ -0,0 +1,148 @@
|
|
1
|
+
/*
|
2
|
+
* Metadata - jQuery plugin for parsing metadata from elements
|
3
|
+
*
|
4
|
+
* Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan
|
5
|
+
*
|
6
|
+
* Dual licensed under the MIT and GPL licenses:
|
7
|
+
* http://www.opensource.org/licenses/mit-license.php
|
8
|
+
* http://www.gnu.org/licenses/gpl.html
|
9
|
+
*
|
10
|
+
* Revision: $Id: jquery.metadata.js 3640 2007-10-11 18:34:38Z pmclanahan $
|
11
|
+
*
|
12
|
+
*/
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
|
16
|
+
* in the JSON will become a property of the element itself.
|
17
|
+
*
|
18
|
+
* There are four supported types of metadata storage:
|
19
|
+
*
|
20
|
+
* attr: Inside an attribute. The name parameter indicates *which* attribute.
|
21
|
+
*
|
22
|
+
* class: Inside the class attribute, wrapped in curly braces: { }
|
23
|
+
*
|
24
|
+
* elem: Inside a child element (e.g. a script tag). The
|
25
|
+
* name parameter indicates *which* element.
|
26
|
+
* html5: Values are stored in data-* attributes.
|
27
|
+
*
|
28
|
+
* The metadata for an element is loaded the first time the element is accessed via jQuery.
|
29
|
+
*
|
30
|
+
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
|
31
|
+
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
|
32
|
+
*
|
33
|
+
* @name $.metadata.setType
|
34
|
+
*
|
35
|
+
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
|
36
|
+
* @before $.metadata.setType("class")
|
37
|
+
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
38
|
+
* @desc Reads metadata from the class attribute
|
39
|
+
*
|
40
|
+
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
|
41
|
+
* @before $.metadata.setType("attr", "data")
|
42
|
+
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
43
|
+
* @desc Reads metadata from a "data" attribute
|
44
|
+
*
|
45
|
+
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
|
46
|
+
* @before $.metadata.setType("elem", "script")
|
47
|
+
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
48
|
+
* @desc Reads metadata from a nested script element
|
49
|
+
*
|
50
|
+
* @example <p id="one" class="some_class" data-item_id="1" data-item_label="Label">This is a p</p>
|
51
|
+
* @before $.metadata.setType("html5")
|
52
|
+
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
53
|
+
* @desc Reads metadata from a series of data-* attributes
|
54
|
+
*
|
55
|
+
* @param String type The encoding type
|
56
|
+
* @param String name The name of the attribute to be used to get metadata (optional)
|
57
|
+
* @cat Plugins/Metadata
|
58
|
+
* @descr Sets the type of encoding to be used when loading metadata for the first time
|
59
|
+
* @type undefined
|
60
|
+
* @see metadata()
|
61
|
+
*/
|
62
|
+
|
63
|
+
(function($) {
|
64
|
+
|
65
|
+
$.extend({
|
66
|
+
metadata : {
|
67
|
+
defaults : {
|
68
|
+
type: 'class',
|
69
|
+
name: 'metadata',
|
70
|
+
cre: /({.*})/,
|
71
|
+
single: 'metadata'
|
72
|
+
},
|
73
|
+
setType: function( type, name ){
|
74
|
+
this.defaults.type = type;
|
75
|
+
this.defaults.name = name;
|
76
|
+
},
|
77
|
+
get: function( elem, opts ){
|
78
|
+
var settings = $.extend({},this.defaults,opts);
|
79
|
+
// check for empty string in single property
|
80
|
+
if ( !settings.single.length ) settings.single = 'metadata';
|
81
|
+
|
82
|
+
var data = $.data(elem, settings.single);
|
83
|
+
// returned cached data if it already exists
|
84
|
+
if ( data ) return data;
|
85
|
+
|
86
|
+
data = "{}";
|
87
|
+
|
88
|
+
var getData = function(data) {
|
89
|
+
if(typeof data != "string") return data;
|
90
|
+
|
91
|
+
if( data.indexOf('{') < 0 ) {
|
92
|
+
data = eval("(" + data + ")");
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
var getObject = function(data) {
|
97
|
+
if(typeof data != "string") return data;
|
98
|
+
|
99
|
+
data = eval("(" + data + ")");
|
100
|
+
return data;
|
101
|
+
}
|
102
|
+
|
103
|
+
if ( settings.type == "html5" ) {
|
104
|
+
var object = {};
|
105
|
+
$( elem.attributes ).each(function() {
|
106
|
+
var name = this.nodeName;
|
107
|
+
if(name.match(/^data-/)) name = name.replace(/^data-/, '');
|
108
|
+
else return true;
|
109
|
+
object[name] = getObject(this.nodeValue);
|
110
|
+
});
|
111
|
+
} else {
|
112
|
+
if ( settings.type == "class" ) {
|
113
|
+
var m = settings.cre.exec( elem.className );
|
114
|
+
if ( m )
|
115
|
+
data = m[1];
|
116
|
+
} else if ( settings.type == "elem" ) {
|
117
|
+
if( !elem.getElementsByTagName ) return;
|
118
|
+
var e = elem.getElementsByTagName(settings.name);
|
119
|
+
if ( e.length )
|
120
|
+
data = $.trim(e[0].innerHTML);
|
121
|
+
} else if ( elem.getAttribute != undefined ) {
|
122
|
+
var attr = elem.getAttribute( settings.name );
|
123
|
+
if ( attr )
|
124
|
+
data = attr;
|
125
|
+
}
|
126
|
+
object = getObject(data.indexOf("{") < 0 ? "{" + data + "}" : data);
|
127
|
+
}
|
128
|
+
|
129
|
+
$.data( elem, settings.single, object );
|
130
|
+
return object;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
});
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Returns the metadata object for the first member of the jQuery object.
|
137
|
+
*
|
138
|
+
* @name metadata
|
139
|
+
* @descr Returns element's metadata object
|
140
|
+
* @param Object opts An object contianing settings to override the defaults
|
141
|
+
* @type jQuery
|
142
|
+
* @cat Plugins/Metadata
|
143
|
+
*/
|
144
|
+
$.fn.metadata = function( opts ){
|
145
|
+
return $.metadata.get( this[0], opts );
|
146
|
+
};
|
147
|
+
|
148
|
+
})(jQuery);
|
@@ -0,0 +1,1138 @@
|
|
1
|
+
/*!
|
2
|
+
* TableSorter 2.3.4 - Client-side table sorting with ease!
|
3
|
+
* @requires jQuery v1.2.6+
|
4
|
+
*
|
5
|
+
* Copyright (c) 2007 Christian Bach
|
6
|
+
* Examples and docs at: http://tablesorter.com
|
7
|
+
* Dual licensed under the MIT and GPL licenses:
|
8
|
+
* http://www.opensource.org/licenses/mit-license.php
|
9
|
+
* http://www.gnu.org/licenses/gpl.html
|
10
|
+
*
|
11
|
+
* @type jQuery
|
12
|
+
* @name tablesorter
|
13
|
+
* @cat Plugins/Tablesorter
|
14
|
+
* @author Christian Bach/christian.bach@polyester.se
|
15
|
+
* @contributor Rob Garrison/https://github.com/Mottie/tablesorter
|
16
|
+
*/
|
17
|
+
!(function($) {
|
18
|
+
$.extend({
|
19
|
+
tablesorter: new function() {
|
20
|
+
|
21
|
+
this.version = "2.3.4";
|
22
|
+
|
23
|
+
var parsers = [], widgets = [];
|
24
|
+
this.defaults = {
|
25
|
+
|
26
|
+
// appearance
|
27
|
+
widthFixed : false,
|
28
|
+
|
29
|
+
// functionality
|
30
|
+
cancelSelection : true, // prevent text selection in the header
|
31
|
+
dateFormat : "mmddyyyy", // other options: "ddmmyyy" or "yyyymmdd"
|
32
|
+
sortMultiSortKey : "shiftKey", // key used to select additional columns
|
33
|
+
usNumberFormat : true, // false for German "1.234.567,89" or French "1 234 567,89"
|
34
|
+
delayInit : false, // if false, the parsed table contents will not update until the first sort.
|
35
|
+
|
36
|
+
// sort options
|
37
|
+
headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
|
38
|
+
ignoreCase : true, // ignore case while sorting
|
39
|
+
sortForce : null, // column(s) first sorted; always applied
|
40
|
+
sortList : [], // Initial sort order; applied initially; updated when manually sorted
|
41
|
+
sortAppend : null, // column(s) sorted last; always applied
|
42
|
+
|
43
|
+
sortInitialOrder : "asc", // sort direction on first click
|
44
|
+
sortLocaleCompare: false, // replace equivalent character (accented characters)
|
45
|
+
sortReset : false, // third click on the header will reset column to default - unsorted
|
46
|
+
sortRestart : false, // restart sort to "sortInitialOrder" when clicking on previously unsorted columns
|
47
|
+
|
48
|
+
emptyTo : "bottom", // sort empty cell to bottom, top, none, zero
|
49
|
+
stringTo : "max", // sort strings in numerical column as max, min, top, bottom, zero
|
50
|
+
textExtraction : "simple", // text extraction method/function - function(node, table, cellIndex){}
|
51
|
+
textSorter : null, // use custom text sorter - function(a,b){ return a.sort(b); } // basic sort
|
52
|
+
|
53
|
+
// widget options
|
54
|
+
widgetOptions : {
|
55
|
+
zebra : [ "even", "odd" ] // zebra widget alternating row class names
|
56
|
+
},
|
57
|
+
|
58
|
+
// callbacks
|
59
|
+
initialized : null, // function(table){},
|
60
|
+
onRenderHeader : null, // function(index){},
|
61
|
+
|
62
|
+
// css class names
|
63
|
+
tableClass : 'tablesorter',
|
64
|
+
cssAsc : "tablesorter-headerSortUp",
|
65
|
+
cssChildRow : "expand-child",
|
66
|
+
cssDesc : "tablesorter-headerSortDown",
|
67
|
+
cssHeader : "tablesorter-header",
|
68
|
+
cssInfoBlock : "tablesorter-infoOnly", // don't sort tbody with this class name
|
69
|
+
|
70
|
+
// selectors
|
71
|
+
selectorHeaders : '> thead th',
|
72
|
+
selectorRemove : "tr.remove-me",
|
73
|
+
|
74
|
+
// advanced
|
75
|
+
debug : false,
|
76
|
+
|
77
|
+
// Internal variables
|
78
|
+
headerList: [],
|
79
|
+
empties: {},
|
80
|
+
strings: {},
|
81
|
+
parsers: [],
|
82
|
+
widgets: []
|
83
|
+
|
84
|
+
// deprecated; but retained for backwards compatibility
|
85
|
+
// widgetZebra: { css: ["even", "odd"] }
|
86
|
+
|
87
|
+
};
|
88
|
+
|
89
|
+
/* debuging utils */
|
90
|
+
function log(s) {
|
91
|
+
if (typeof console !== "undefined" && typeof console.log !== "undefined") {
|
92
|
+
console.log(s);
|
93
|
+
} else {
|
94
|
+
alert(s);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
function benchmark(s, d) {
|
99
|
+
log(s + " (" + (new Date().getTime() - d.getTime()) + "ms)");
|
100
|
+
}
|
101
|
+
|
102
|
+
this.benchmark = benchmark;
|
103
|
+
this.hasInitialized = false;
|
104
|
+
|
105
|
+
function getElementText(table, node, cellIndex) {
|
106
|
+
var text = "", t = table.config.textExtraction;
|
107
|
+
if (!node) { return ""; }
|
108
|
+
if (t === "simple") {
|
109
|
+
text = $(node).text();
|
110
|
+
} else {
|
111
|
+
if (typeof(t) === "function") {
|
112
|
+
text = t(node, table, cellIndex);
|
113
|
+
} else if (typeof(t) === "object" && t.hasOwnProperty(cellIndex)) {
|
114
|
+
text = t[cellIndex](node, table, cellIndex);
|
115
|
+
} else {
|
116
|
+
text = $(node).text();
|
117
|
+
}
|
118
|
+
}
|
119
|
+
return $.trim(text);
|
120
|
+
}
|
121
|
+
|
122
|
+
/* parsers utils */
|
123
|
+
function getParserById(name) {
|
124
|
+
var i, l = parsers.length;
|
125
|
+
for (i = 0; i < l; i++) {
|
126
|
+
if (parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) {
|
127
|
+
return parsers[i];
|
128
|
+
}
|
129
|
+
}
|
130
|
+
return false;
|
131
|
+
}
|
132
|
+
|
133
|
+
function detectParserForColumn(table, rows, rowIndex, cellIndex) {
|
134
|
+
var i, l = parsers.length,
|
135
|
+
node = false,
|
136
|
+
nodeValue = '',
|
137
|
+
keepLooking = true;
|
138
|
+
while (nodeValue === '' && keepLooking) {
|
139
|
+
rowIndex++;
|
140
|
+
if (rows[rowIndex]) {
|
141
|
+
node = rows[rowIndex].cells[cellIndex];
|
142
|
+
nodeValue = getElementText(table, node, cellIndex);
|
143
|
+
if (table.config.debug) {
|
144
|
+
log('Checking if value was empty on row ' + rowIndex + ', column:' + cellIndex + ": " + nodeValue);
|
145
|
+
}
|
146
|
+
} else {
|
147
|
+
keepLooking = false;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
for (i = 1; i < l; i++) {
|
151
|
+
if (parsers[i].is(nodeValue, table, node)) {
|
152
|
+
return parsers[i];
|
153
|
+
}
|
154
|
+
}
|
155
|
+
// 0 is always the generic parser (text)
|
156
|
+
return parsers[0];
|
157
|
+
}
|
158
|
+
|
159
|
+
function buildParserCache(table, $headers) {
|
160
|
+
var c = table.config, tb = $(table.tBodies).filter(':not(.' + c.cssInfoBlock + ')'),
|
161
|
+
ts = $.tablesorter, rows, list, l, i, h, m, ch, cl, p, parsersDebug = "";
|
162
|
+
if ( tb.length === 0) { return; } // In the case of empty tables
|
163
|
+
rows = tb[0].rows;
|
164
|
+
if (rows[0]) {
|
165
|
+
list = [];
|
166
|
+
l = rows[0].cells.length;
|
167
|
+
for (i = 0; i < l; i++) {
|
168
|
+
// tons of thanks to AnthonyM1229 for working out the following selector (issue #74) to make this work in IE8!
|
169
|
+
h = $headers.filter(':not([colspan])[data-column="'+i+'"]:last,[colspan="1"][data-column="'+i+'"]:last');
|
170
|
+
ch = c.headers[i];
|
171
|
+
// get column parser
|
172
|
+
p = getParserById( ts.getData(h, ch, 'sorter') );
|
173
|
+
// empty cells behaviour - keeping emptyToBottom for backwards compatibility.
|
174
|
+
c.empties[i] = ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' );
|
175
|
+
// text strings behaviour in numerical sorts
|
176
|
+
c.strings[i] = ts.getData(h, ch, 'string') || c.stringTo || 'max';
|
177
|
+
if (!p) {
|
178
|
+
p = detectParserForColumn(table, rows, -1, i);
|
179
|
+
}
|
180
|
+
if (c.debug) {
|
181
|
+
parsersDebug += "column:" + i + "; parser:" + p.id + "; string:" + c.strings[i] + '; empty: ' + c.empties[i] + "\n";
|
182
|
+
}
|
183
|
+
list.push(p);
|
184
|
+
}
|
185
|
+
}
|
186
|
+
if (c.debug) {
|
187
|
+
log(parsersDebug);
|
188
|
+
}
|
189
|
+
return list;
|
190
|
+
}
|
191
|
+
|
192
|
+
/* utils */
|
193
|
+
function buildRegex(){
|
194
|
+
var a, acc = '[', t = $.tablesorter,
|
195
|
+
reg = t.characterEquivalents;
|
196
|
+
t.characterRegexArray = {};
|
197
|
+
for (a in reg) {
|
198
|
+
if (typeof a === 'string') {
|
199
|
+
acc += reg[a];
|
200
|
+
t.characterRegexArray[a] = new RegExp('[' + reg[a] + ']', 'g');
|
201
|
+
}
|
202
|
+
}
|
203
|
+
t.characterRegex = new RegExp(acc + ']');
|
204
|
+
}
|
205
|
+
|
206
|
+
function buildCache(table) {
|
207
|
+
var b = table.tBodies,
|
208
|
+
tc = table.config,
|
209
|
+
totalRows,
|
210
|
+
totalCells,
|
211
|
+
parsers = tc.parsers,
|
212
|
+
t, i, j, k, c, cols, cacheTime;
|
213
|
+
tc.cache = {};
|
214
|
+
if (tc.debug) {
|
215
|
+
cacheTime = new Date();
|
216
|
+
}
|
217
|
+
for (k = 0; k < b.length; k++) {
|
218
|
+
tc.cache[k] = { row: [], normalized: [] };
|
219
|
+
// ignore tbodies with class name from css.cssInfoBlock
|
220
|
+
if (!$(b[k]).hasClass(tc.cssInfoBlock)) {
|
221
|
+
totalRows = (b[k] && b[k].rows.length) || 0;
|
222
|
+
totalCells = (b[k].rows[0] && b[k].rows[0].cells.length) || 0;
|
223
|
+
for (i = 0; i < totalRows; ++i) {
|
224
|
+
/** Add the table data to main data array */
|
225
|
+
c = $(b[k].rows[i]);
|
226
|
+
cols = [];
|
227
|
+
// if this is a child row, add it to the last row's children and continue to the next row
|
228
|
+
if (c.hasClass(tc.cssChildRow)) {
|
229
|
+
tc.cache[k].row[tc.cache[k].row.length - 1] = tc.cache[k].row[tc.cache[k].row.length - 1].add(c);
|
230
|
+
// go to the next for loop
|
231
|
+
continue;
|
232
|
+
}
|
233
|
+
tc.cache[k].row.push(c);
|
234
|
+
for (j = 0; j < totalCells; ++j) {
|
235
|
+
t = getElementText(table, c[0].cells[j], j);
|
236
|
+
// allow parsing if the string is empty, previously parsing would change it to zero,
|
237
|
+
// in case the parser needs to extract data from the table cell attributes
|
238
|
+
cols.push( parsers[j].format(t, table, c[0].cells[j], j) );
|
239
|
+
}
|
240
|
+
cols.push(tc.cache[k].normalized.length); // add position for rowCache
|
241
|
+
tc.cache[k].normalized.push(cols);
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
if (tc.debug) {
|
246
|
+
benchmark("Building cache for " + totalRows + " rows", cacheTime);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
function getWidgetById(name) {
|
251
|
+
var i, w, l = widgets.length;
|
252
|
+
for (i = 0; i < l; i++) {
|
253
|
+
w = widgets[i];
|
254
|
+
if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) {
|
255
|
+
return w;
|
256
|
+
}
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
function applyWidget(table, init) {
|
261
|
+
var c = table.config.widgets,
|
262
|
+
i, w, l = c.length;
|
263
|
+
for (i = 0; i < l; i++) {
|
264
|
+
w = getWidgetById(c[i]);
|
265
|
+
if ( w ) {
|
266
|
+
if (init && w.hasOwnProperty('init')) {
|
267
|
+
w.init(table, widgets, w);
|
268
|
+
} else if (!init && w.hasOwnProperty('format')) {
|
269
|
+
w.format(table);
|
270
|
+
}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
function appendToTable(table) {
|
276
|
+
var c = table.config,
|
277
|
+
b = table.tBodies,
|
278
|
+
rows = [],
|
279
|
+
r, n, totalRows, checkCell, c2 = c.cache,
|
280
|
+
f, i, j, k, l, pos, appendTime;
|
281
|
+
if (c.debug) {
|
282
|
+
appendTime = new Date();
|
283
|
+
}
|
284
|
+
for (k = 0; k < b.length; k++) {
|
285
|
+
if (!$(b[k]).hasClass(c.cssInfoBlock)){
|
286
|
+
f = document.createDocumentFragment();
|
287
|
+
r = c2[k].row;
|
288
|
+
n = c2[k].normalized;
|
289
|
+
totalRows = n.length;
|
290
|
+
checkCell = totalRows ? (n[0].length - 1) : 0;
|
291
|
+
for (i = 0; i < totalRows; i++) {
|
292
|
+
pos = n[i][checkCell];
|
293
|
+
rows.push(r[pos]);
|
294
|
+
// removeRows used by the pager plugin
|
295
|
+
if (!c.appender || !c.removeRows) {
|
296
|
+
l = r[pos].length;
|
297
|
+
for (j = 0; j < l; j++) {
|
298
|
+
f.appendChild(r[pos][j]);
|
299
|
+
}
|
300
|
+
}
|
301
|
+
}
|
302
|
+
table.tBodies[k].appendChild(f);
|
303
|
+
}
|
304
|
+
}
|
305
|
+
if (c.appender) {
|
306
|
+
c.appender(table, rows);
|
307
|
+
}
|
308
|
+
if (c.debug) {
|
309
|
+
benchmark("Rebuilt table", appendTime);
|
310
|
+
}
|
311
|
+
// apply table widgets
|
312
|
+
applyWidget(table);
|
313
|
+
// trigger sortend
|
314
|
+
$(table).trigger("sortEnd", table);
|
315
|
+
}
|
316
|
+
|
317
|
+
// from:
|
318
|
+
// http://www.javascripttoolbox.com/lib/table/examples.php
|
319
|
+
// http://www.javascripttoolbox.com/temp/table_cellindex.html
|
320
|
+
function computeTableHeaderCellIndexes(t) {
|
321
|
+
var matrix = [],
|
322
|
+
lookup = {},
|
323
|
+
trs = $(t).find('thead:eq(0) tr'),
|
324
|
+
i, j, k, l, c, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, matrixrow;
|
325
|
+
for (i = 0; i < trs.length; i++) {
|
326
|
+
cells = trs[i].cells;
|
327
|
+
for (j = 0; j < cells.length; j++) {
|
328
|
+
c = cells[j];
|
329
|
+
rowIndex = c.parentNode.rowIndex;
|
330
|
+
cellId = rowIndex + "-" + c.cellIndex;
|
331
|
+
rowSpan = c.rowSpan || 1;
|
332
|
+
colSpan = c.colSpan || 1;
|
333
|
+
if (typeof(matrix[rowIndex]) === "undefined") {
|
334
|
+
matrix[rowIndex] = [];
|
335
|
+
}
|
336
|
+
// Find first available column in the first row
|
337
|
+
for (k = 0; k < matrix[rowIndex].length + 1; k++) {
|
338
|
+
if (typeof(matrix[rowIndex][k]) === "undefined") {
|
339
|
+
firstAvailCol = k;
|
340
|
+
break;
|
341
|
+
}
|
342
|
+
}
|
343
|
+
lookup[cellId] = firstAvailCol;
|
344
|
+
// add data-column
|
345
|
+
$(c).attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex
|
346
|
+
for (k = rowIndex; k < rowIndex + rowSpan; k++) {
|
347
|
+
if (typeof(matrix[k]) === "undefined") {
|
348
|
+
matrix[k] = [];
|
349
|
+
}
|
350
|
+
matrixrow = matrix[k];
|
351
|
+
for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
|
352
|
+
matrixrow[l] = "x";
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}
|
356
|
+
}
|
357
|
+
return lookup;
|
358
|
+
}
|
359
|
+
|
360
|
+
function formatSortingOrder(v) {
|
361
|
+
// look for "d" in "desc" order; return true
|
362
|
+
return (/^d/i.test(v) || v === 1);
|
363
|
+
}
|
364
|
+
|
365
|
+
function buildHeaders(table) {
|
366
|
+
var meta = ($.metadata) ? true : false,
|
367
|
+
header_index = computeTableHeaderCellIndexes(table), ch, $t,
|
368
|
+
$th, lock, time, $tableHeaders, c = table.config, ts = $.tablesorter;
|
369
|
+
c.headerList = [];
|
370
|
+
if (c.debug) {
|
371
|
+
time = new Date();
|
372
|
+
}
|
373
|
+
$tableHeaders = $(c.selectorHeaders, table)
|
374
|
+
.wrapInner("<div class='tablesorter-header-inner' />")
|
375
|
+
.each(function(index) {
|
376
|
+
$t = $(this);
|
377
|
+
ch = c.headers[index];
|
378
|
+
this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
|
379
|
+
this.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2];
|
380
|
+
this.count = -1; // set to -1 because clicking on the header automatically adds one
|
381
|
+
if (ts.getData($t, ch, 'sorter') === 'false') { this.sortDisabled = true; }
|
382
|
+
this.lockedOrder = false;
|
383
|
+
lock = ts.getData($t, ch, 'lockedOrder') || false;
|
384
|
+
if (typeof(lock) !== 'undefined' && lock !== false) {
|
385
|
+
this.order = this.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0];
|
386
|
+
}
|
387
|
+
if (!this.sortDisabled) {
|
388
|
+
$th = $t.addClass(c.cssHeader);
|
389
|
+
if (c.onRenderHeader) { c.onRenderHeader.apply($th, [index]); }
|
390
|
+
}
|
391
|
+
// add cell to headerList
|
392
|
+
c.headerList[index] = this;
|
393
|
+
// add to parent in case there are multiple rows
|
394
|
+
$t.parent().addClass(c.cssHeader);
|
395
|
+
});
|
396
|
+
if (c.debug) {
|
397
|
+
benchmark("Built headers", time);
|
398
|
+
log($tableHeaders);
|
399
|
+
}
|
400
|
+
return $tableHeaders;
|
401
|
+
}
|
402
|
+
|
403
|
+
function isValueInArray(v, a) {
|
404
|
+
var i, l = a.length;
|
405
|
+
for (i = 0; i < l; i++) {
|
406
|
+
if (a[i][0] === v) {
|
407
|
+
return true;
|
408
|
+
}
|
409
|
+
}
|
410
|
+
return false;
|
411
|
+
}
|
412
|
+
|
413
|
+
function setHeadersCss(table, $headers, list) {
|
414
|
+
var f, h = [], i, j, l, css = [table.config.cssDesc, table.config.cssAsc];
|
415
|
+
// remove all header information
|
416
|
+
$headers
|
417
|
+
.removeClass(css.join(' '))
|
418
|
+
.each(function() {
|
419
|
+
if (!this.sortDisabled) {
|
420
|
+
h[this.column] = $(this);
|
421
|
+
}
|
422
|
+
});
|
423
|
+
l = list.length;
|
424
|
+
for (i = 0; i < l; i++) {
|
425
|
+
if (list[i][1] === 2) { continue; } // direction = 2 means reset!
|
426
|
+
h[list[i][0]].addClass(css[list[i][1]]);
|
427
|
+
// multicolumn sorting updating
|
428
|
+
f = $headers.filter('[data-column="' + list[i][0] + '"]');
|
429
|
+
if (l > 1 && f.length) {
|
430
|
+
for (j = 0; j < f.length; j++) {
|
431
|
+
if (!f[j].sortDisabled) {
|
432
|
+
$(f[j]).addClass(css[list[i][1]]);
|
433
|
+
}
|
434
|
+
}
|
435
|
+
}
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
function fixColumnWidth(table) {
|
440
|
+
if (table.config.widthFixed) {
|
441
|
+
var colgroup = $('<colgroup>');
|
442
|
+
$("tr:first td", table.tBodies[0]).each(function() {
|
443
|
+
colgroup.append($('<col>').css('width', $(this).width()));
|
444
|
+
});
|
445
|
+
$(table).prepend(colgroup);
|
446
|
+
}
|
447
|
+
}
|
448
|
+
|
449
|
+
function updateHeaderSortCount(table, sortList) {
|
450
|
+
var i, s, o, c = table.config,
|
451
|
+
l = sortList.length;
|
452
|
+
for (i = 0; i < l; i++) {
|
453
|
+
s = sortList[i];
|
454
|
+
o = c.headerList[s[0]];
|
455
|
+
o.count = s[1] % (c.sortReset ? 3 : 2);
|
456
|
+
}
|
457
|
+
}
|
458
|
+
|
459
|
+
function getCachedSortType(parsers, i) {
|
460
|
+
return (parsers) ? parsers[i].type : '';
|
461
|
+
}
|
462
|
+
|
463
|
+
/* sorting methods - reverted sorting method back to version 2.0.3 */
|
464
|
+
function multisort(table, sortList) {
|
465
|
+
var dynamicExp, col, mx = 0, dir = 0, tc = table.config,
|
466
|
+
l = sortList.length, bl = table.tBodies.length,
|
467
|
+
sortTime, i, j, k, c, cache, lc, s, e, order, orgOrderCol;
|
468
|
+
if (tc.debug) { sortTime = new Date(); }
|
469
|
+
for (k = 0; k < bl; k++) {
|
470
|
+
dynamicExp = "var sortWrapper = function(a,b) {";
|
471
|
+
cache = tc.cache[k];
|
472
|
+
lc = cache.normalized.length;
|
473
|
+
for (i = 0; i < l; i++) {
|
474
|
+
c = sortList[i][0];
|
475
|
+
order = sortList[i][1];
|
476
|
+
// fallback to natural sort since it is more robust
|
477
|
+
s = /n/i.test(getCachedSortType(tc.parsers, c)) ? "Numeric" : "Text";
|
478
|
+
s += order === 0 ? "" : "Desc";
|
479
|
+
e = "e" + i;
|
480
|
+
// get max column value (ignore sign)
|
481
|
+
if (/Numeric/.test(s) && tc.strings[c]) {
|
482
|
+
for (j = 0; j < lc; j++) {
|
483
|
+
col = Math.abs(parseFloat(cache.normalized[j][c]));
|
484
|
+
mx = Math.max( mx, isNaN(col) ? 0 : col );
|
485
|
+
}
|
486
|
+
// sort strings in numerical columns
|
487
|
+
if (typeof(tc.string[tc.strings[c]]) === 'boolean') {
|
488
|
+
dir = (order === 0 ? 1 : -1) * (tc.string[tc.strings[c]] ? -1 : 1);
|
489
|
+
} else {
|
490
|
+
dir = (tc.strings[c]) ? tc.string[tc.strings[c]] || 0 : 0;
|
491
|
+
}
|
492
|
+
}
|
493
|
+
dynamicExp += "var " + e + " = sort" + s + "(table, a[" + c + "],b[" + c + "]," + c + "," + mx + "," + dir + "); ";
|
494
|
+
dynamicExp += "if (" + e + ") { return " + e + "; } ";
|
495
|
+
dynamicExp += "else { ";
|
496
|
+
}
|
497
|
+
// if value is the same keep orignal order
|
498
|
+
orgOrderCol = (cache.normalized && cache.normalized[0]) ? cache.normalized[0].length - 1 : 0;
|
499
|
+
dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
|
500
|
+
for (i=0; i < l; i++) {
|
501
|
+
dynamicExp += "}; ";
|
502
|
+
}
|
503
|
+
dynamicExp += "return 0; ";
|
504
|
+
dynamicExp += "}; ";
|
505
|
+
eval(dynamicExp);
|
506
|
+
cache.normalized.sort(sortWrapper); // sort using eval expression
|
507
|
+
}
|
508
|
+
if (tc.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time", sortTime); }
|
509
|
+
}
|
510
|
+
|
511
|
+
// Natural sort - https://github.com/overset/javascript-natural-sort
|
512
|
+
function sortText(table, a, b, col) {
|
513
|
+
if (a === b) { return 0; }
|
514
|
+
var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ],
|
515
|
+
r = $.tablesorter.regex, xN, xD, yN, yD, xF, yF, i, mx;
|
516
|
+
if (a === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? -1 : 1) : -e || -1; }
|
517
|
+
if (b === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? 1 : -1) : e || 1; }
|
518
|
+
if (typeof c.textSorter === 'function') { return c.textSorter(a, b, table, col); }
|
519
|
+
// chunk/tokenize
|
520
|
+
xN = a.replace(r[0], '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
|
521
|
+
yN = b.replace(r[0], '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
|
522
|
+
// numeric, hex or date detection
|
523
|
+
xD = parseInt(a.match(r[2])) || (xN.length !== 1 && a.match(r[1]) && Date.parse(a));
|
524
|
+
yD = parseInt(b.match(r[2])) || (xD && b.match(r[1]) && Date.parse(b)) || null;
|
525
|
+
// first try and sort Hex codes or Dates
|
526
|
+
if (yD) {
|
527
|
+
if ( xD < yD ) { return -1; }
|
528
|
+
if ( xD > yD ) { return 1; }
|
529
|
+
}
|
530
|
+
mx = Math.max(xN.length, yN.length);
|
531
|
+
// natural sorting through split numeric strings and default strings
|
532
|
+
for (i = 0; i < mx; i++) {
|
533
|
+
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
|
534
|
+
xF = (!(xN[i] || '').match(r[3]) && parseFloat(xN[i])) || xN[i] || 0;
|
535
|
+
yF = (!(yN[i] || '').match(r[3]) && parseFloat(yN[i])) || yN[i] || 0;
|
536
|
+
// handle numeric vs string comparison - number < string - (Kyle Adams)
|
537
|
+
if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; }
|
538
|
+
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
|
539
|
+
if (typeof xF !== typeof yF) {
|
540
|
+
xF += '';
|
541
|
+
yF += '';
|
542
|
+
}
|
543
|
+
if (xF < yF) { return -1; }
|
544
|
+
if (xF > yF) { return 1; }
|
545
|
+
}
|
546
|
+
return 0;
|
547
|
+
}
|
548
|
+
|
549
|
+
function sortTextDesc(table, a, b, col) {
|
550
|
+
if (a === b) { return 0; }
|
551
|
+
var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ];
|
552
|
+
if (a === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? -1 : 1) : e || 1; }
|
553
|
+
if (b === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? 1 : -1) : -e || -1; }
|
554
|
+
if (typeof c.textSorter === 'function') { return c.textSorter(b, a, table, col); }
|
555
|
+
return sortText(table, b, a);
|
556
|
+
}
|
557
|
+
|
558
|
+
// return text string value by adding up ascii value
|
559
|
+
// so the text is somewhat sorted when using a digital sort
|
560
|
+
// this is NOT an alphanumeric sort
|
561
|
+
function getTextValue(a, mx, d) {
|
562
|
+
if (mx) {
|
563
|
+
// make sure the text value is greater than the max numerical value (mx)
|
564
|
+
var i, l = a.length, n = mx + d;
|
565
|
+
for (i = 0; i < l; i++) {
|
566
|
+
n += a.charCodeAt(i);
|
567
|
+
}
|
568
|
+
return d * n;
|
569
|
+
}
|
570
|
+
return 0;
|
571
|
+
}
|
572
|
+
|
573
|
+
function sortNumeric(table, a, b, col, mx, d) {
|
574
|
+
if (a === b) { return 0; }
|
575
|
+
var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ];
|
576
|
+
if (a === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? -1 : 1) : -e || -1; }
|
577
|
+
if (b === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? 1 : -1) : e || 1; }
|
578
|
+
if (isNaN(a)) { a = getTextValue(a, mx, d); }
|
579
|
+
if (isNaN(b)) { b = getTextValue(b, mx, d); }
|
580
|
+
return a - b;
|
581
|
+
}
|
582
|
+
|
583
|
+
function sortNumericDesc(table, a, b, col, mx, d) {
|
584
|
+
if (a === b) { return 0; }
|
585
|
+
var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ];
|
586
|
+
if (a === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? -1 : 1) : e || 1; }
|
587
|
+
if (b === '' && e !== 0) { return (typeof(e) === 'boolean') ? (e ? 1 : -1) : -e || -1; }
|
588
|
+
if (isNaN(a)) { a = getTextValue(a, mx, d); }
|
589
|
+
if (isNaN(b)) { b = getTextValue(b, mx, d); }
|
590
|
+
return b - a;
|
591
|
+
}
|
592
|
+
|
593
|
+
/* public methods */
|
594
|
+
this.construct = function(settings) {
|
595
|
+
return this.each(function() {
|
596
|
+
// if no thead or tbody quit.
|
597
|
+
if (!this.tHead || this.tBodies.length === 0) { return; }
|
598
|
+
// declare
|
599
|
+
var $headers, $cell, totalRows, $this,
|
600
|
+
config, c, i, j, k, a, s, o,
|
601
|
+
m = $.metadata;
|
602
|
+
// new blank config object
|
603
|
+
this.config = {};
|
604
|
+
// merge and extend.
|
605
|
+
c = config = $.extend(true, this.config, $.tablesorter.defaults, settings);
|
606
|
+
|
607
|
+
if (c.debug) { $.data( this, 'startoveralltimer', new Date()); }
|
608
|
+
// store common expression for speed
|
609
|
+
$this = $(this).addClass(c.tableClass);
|
610
|
+
// save the settings where they read
|
611
|
+
$.data(this, "tablesorter", c);
|
612
|
+
// build up character equivalent cross-reference
|
613
|
+
buildRegex();
|
614
|
+
// digit sort text location; keeping max+/- for backwards compatibility
|
615
|
+
c.string = { 'max': 1, 'min': -1, 'max+': 1, 'max-': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false };
|
616
|
+
// build headers
|
617
|
+
$headers = buildHeaders(this);
|
618
|
+
// try to auto detect column type, and store in tables config
|
619
|
+
c.parsers = buildParserCache(this, $headers);
|
620
|
+
// build the cache for the tbody cells
|
621
|
+
// delayInit will delay building the cache until the user starts a sort
|
622
|
+
if (!c.delayInit) { buildCache(this); }
|
623
|
+
// fixate columns if the users supplies the fixedWidth option
|
624
|
+
fixColumnWidth(this);
|
625
|
+
// apply event handling to headers
|
626
|
+
// this is to big, perhaps break it out?
|
627
|
+
$headers
|
628
|
+
.click(function(e) {
|
629
|
+
if (c.delayInit && !c.cache) { buildCache($this[0]); }
|
630
|
+
if (!this.sortDisabled) {
|
631
|
+
// Only call sortStart if sorting is enabled.
|
632
|
+
$this.trigger("sortStart", $this[0]);
|
633
|
+
// store exp, for speed
|
634
|
+
$cell = $(this);
|
635
|
+
k = !e[c.sortMultiSortKey];
|
636
|
+
// get current column sort order
|
637
|
+
this.count = (this.count + 1) % (c.sortReset ? 3 : 2);
|
638
|
+
// reset all sorts on non-current column - issue #30
|
639
|
+
if (c.sortRestart) {
|
640
|
+
i = this;
|
641
|
+
$headers.each(function() {
|
642
|
+
// only reset counts on columns that weren't just clicked on and if not included in a multisort
|
643
|
+
if (this !== i && (k || !$(this).is('.' + c.cssDesc + ',.' + c.cssAsc))) {
|
644
|
+
this.count = -1;
|
645
|
+
}
|
646
|
+
});
|
647
|
+
}
|
648
|
+
// get current column index
|
649
|
+
i = this.column;
|
650
|
+
// user only wants to sort on one column
|
651
|
+
if (k) {
|
652
|
+
// flush the sort list
|
653
|
+
c.sortList = [];
|
654
|
+
if (c.sortForce !== null) {
|
655
|
+
a = c.sortForce;
|
656
|
+
for (j = 0; j < a.length; j++) {
|
657
|
+
if (a[j][0] !== i) {
|
658
|
+
c.sortList.push(a[j]);
|
659
|
+
}
|
660
|
+
}
|
661
|
+
}
|
662
|
+
// add column to sort list
|
663
|
+
o = this.order[this.count];
|
664
|
+
if (o < 2) {
|
665
|
+
c.sortList.push([i, o]);
|
666
|
+
// add other columns if header spans across multiple
|
667
|
+
if (this.colSpan > 1) {
|
668
|
+
for (j = 1; j < this.colSpan; j++) {
|
669
|
+
c.sortList.push([i+j, o]);
|
670
|
+
}
|
671
|
+
}
|
672
|
+
}
|
673
|
+
// multi column sorting
|
674
|
+
} else {
|
675
|
+
// the user has clicked on an already sorted column.
|
676
|
+
if (isValueInArray(i, c.sortList)) {
|
677
|
+
// reverse the sorting direction for all tables.
|
678
|
+
for (j = 0; j < c.sortList.length; j++) {
|
679
|
+
s = c.sortList[j];
|
680
|
+
o = c.headerList[s[0]];
|
681
|
+
if (s[0] === i) {
|
682
|
+
s[1] = o.order[o.count];
|
683
|
+
if (s[1] === 2) {
|
684
|
+
c.sortList.splice(j,1);
|
685
|
+
o.count = -1;
|
686
|
+
}
|
687
|
+
}
|
688
|
+
}
|
689
|
+
} else {
|
690
|
+
// add column to sort list array
|
691
|
+
o = this.order[this.count];
|
692
|
+
if (o < 2) {
|
693
|
+
c.sortList.push([i, o]);
|
694
|
+
// add other columns if header spans across multiple
|
695
|
+
if (this.colSpan > 1) {
|
696
|
+
for (j = 1; j < this.colSpan; j++) {
|
697
|
+
c.sortList.push([i+j, o]);
|
698
|
+
}
|
699
|
+
}
|
700
|
+
}
|
701
|
+
}
|
702
|
+
}
|
703
|
+
if (c.sortAppend !== null) {
|
704
|
+
a = c.sortAppend;
|
705
|
+
for (j = 0; j < a.length; j++) {
|
706
|
+
if (a[j][0] !== i) {
|
707
|
+
c.sortList.push(a[j]);
|
708
|
+
}
|
709
|
+
}
|
710
|
+
}
|
711
|
+
// sortBegin event triggered immediately before the sort
|
712
|
+
$this.trigger("sortBegin", $this[0]);
|
713
|
+
// set css for headers
|
714
|
+
setHeadersCss($this[0], $headers, c.sortList);
|
715
|
+
appendToTable($this[0], multisort($this[0], c.sortList));
|
716
|
+
// stop normal event by returning false
|
717
|
+
return false;
|
718
|
+
}
|
719
|
+
// cancel selection
|
720
|
+
})
|
721
|
+
.mousedown(function() {
|
722
|
+
if (c.cancelSelection) {
|
723
|
+
this.onselectstart = function() {
|
724
|
+
return false;
|
725
|
+
};
|
726
|
+
return false;
|
727
|
+
}
|
728
|
+
});
|
729
|
+
// apply easy methods that trigger binded events
|
730
|
+
$this
|
731
|
+
.bind("update", function(e, resort) {
|
732
|
+
// remove rows/elements before update
|
733
|
+
$(c.selectorRemove, this).remove();
|
734
|
+
// rebuild parsers.
|
735
|
+
c.parsers = buildParserCache(this, $headers);
|
736
|
+
// rebuild the cache map
|
737
|
+
buildCache(this);
|
738
|
+
if (resort !== false) { $(this).trigger("sorton", [c.sortList]); }
|
739
|
+
})
|
740
|
+
.bind("updateCell", function(e, cell, resort) {
|
741
|
+
// get position from the dom.
|
742
|
+
var t = this, pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex],
|
743
|
+
// update cache - format: function(s, table, cell, cellIndex)
|
744
|
+
tbdy = $(this).find('tbody').index( $(cell).closest('tbody') );
|
745
|
+
t.config.cache[tbdy].normalized[pos[0]][pos[1]] = c.parsers[pos[1]].format( getElementText(t, cell, pos[1]), t, cell, pos[1] );
|
746
|
+
if (resort !== false) { $(this).trigger("sorton", [c.sortList]); }
|
747
|
+
})
|
748
|
+
.bind("addRows", function(e, $row, resort) {
|
749
|
+
var i, rows = $row.filter('tr').length,
|
750
|
+
dat = [], l = $row[0].cells.length, t = this,
|
751
|
+
tbdy = $(this).find('tbody').index( $row.closest('tbody') );
|
752
|
+
// add each row
|
753
|
+
for (i = 0; i < rows; i++) {
|
754
|
+
// add each cell
|
755
|
+
for (j = 0; j < l; j++) {
|
756
|
+
dat[j] = c.parsers[j].format( getElementText(t, $row[i].cells[j], j), t, $row[i].cells[j], j );
|
757
|
+
}
|
758
|
+
// add the row index to the end
|
759
|
+
dat.push(c.cache[tbdy].row.length);
|
760
|
+
// update cache
|
761
|
+
c.cache[tbdy].row.push([$row[i]]);
|
762
|
+
c.cache[tbdy].normalized.push(dat);
|
763
|
+
dat = [];
|
764
|
+
}
|
765
|
+
// resort using current settings
|
766
|
+
if (resort !== false) { $(this).trigger("sorton", [c.sortList]); }
|
767
|
+
})
|
768
|
+
.bind("sorton", function(e, list) {
|
769
|
+
$(this).trigger("sortStart", this);
|
770
|
+
// update and store the sortlist
|
771
|
+
c.sortList = list;
|
772
|
+
// update header count index
|
773
|
+
updateHeaderSortCount(this, c.sortList);
|
774
|
+
// set css for headers
|
775
|
+
setHeadersCss(this, $headers, c.sortList);
|
776
|
+
// sort the table and append it to the dom
|
777
|
+
appendToTable(this, multisort(this, c.sortList));
|
778
|
+
})
|
779
|
+
.bind("appendCache", function() {
|
780
|
+
appendToTable(this);
|
781
|
+
})
|
782
|
+
.bind("applyWidgetId", function(e, id) {
|
783
|
+
getWidgetById(id).format(this);
|
784
|
+
})
|
785
|
+
.bind("applyWidgets", function() {
|
786
|
+
// apply widgets
|
787
|
+
applyWidget(this);
|
788
|
+
})
|
789
|
+
.bind("destroy", function(e,c){
|
790
|
+
$.tablesorter.destroy(this, c);
|
791
|
+
});
|
792
|
+
|
793
|
+
// get sort list from jQuery data or metadata
|
794
|
+
if ($this.data() && typeof $this.data().sortlist !== 'undefined') {
|
795
|
+
c.sortList = $this.data().sortlist;
|
796
|
+
} else if (m && ($this.metadata() && $this.metadata().sortlist)) {
|
797
|
+
c.sortList = $this.metadata().sortlist;
|
798
|
+
}
|
799
|
+
// apply widget init code
|
800
|
+
applyWidget(this, true);
|
801
|
+
// if user has supplied a sort list to constructor.
|
802
|
+
if (c.sortList.length > 0) {
|
803
|
+
$this.trigger("sorton", [c.sortList]);
|
804
|
+
} else {
|
805
|
+
// apply widget format
|
806
|
+
applyWidget(this);
|
807
|
+
}
|
808
|
+
|
809
|
+
// initialized
|
810
|
+
this.hasInitialized = true;
|
811
|
+
if (c.debug) {
|
812
|
+
$.tablesorter.benchmark("Overall initialization time", $.data( this, 'startoveralltimer'));
|
813
|
+
}
|
814
|
+
$this.trigger('tablesorter-initialized', this);
|
815
|
+
if (typeof c.initialized === 'function') { c.initialized(this); }
|
816
|
+
});
|
817
|
+
};
|
818
|
+
|
819
|
+
this.destroy = function(table, removeClasses){
|
820
|
+
var $t = $(table), c = table.config;
|
821
|
+
// remove widget added rows
|
822
|
+
$t.find('thead:first tr:not(.' + c.cssHeader + ')').remove();
|
823
|
+
// remove resizer widget stuff
|
824
|
+
$t.find('thead:first .tablesorter-resizer').remove();
|
825
|
+
// disable tablesorter
|
826
|
+
$t
|
827
|
+
.unbind('update updateCell addRows sorton appendCache applyWidgetId applyWidgets destroy mouseup mouseleave')
|
828
|
+
.find(c.selectorHeaders)
|
829
|
+
.unbind('click mousedown mousemove mouseup')
|
830
|
+
.removeClass(c.cssHeader + ' ' + c.cssAsc + ' ' + c.cssDesc);
|
831
|
+
if (removeClasses !== false) {
|
832
|
+
$t.removeClass(c.tableClass);
|
833
|
+
}
|
834
|
+
};
|
835
|
+
|
836
|
+
this.addParser = function(parser) {
|
837
|
+
var i, l = parsers.length, a = true;
|
838
|
+
for (i = 0; i < l; i++) {
|
839
|
+
if (parsers[i].id.toLowerCase() === parser.id.toLowerCase()) {
|
840
|
+
a = false;
|
841
|
+
}
|
842
|
+
}
|
843
|
+
if (a) {
|
844
|
+
parsers.push(parser);
|
845
|
+
}
|
846
|
+
};
|
847
|
+
this.addWidget = function(widget) {
|
848
|
+
widgets.push(widget);
|
849
|
+
};
|
850
|
+
|
851
|
+
this.formatFloat = function(s, table) {
|
852
|
+
if (typeof(s) !== 'string' || s === '') { return s; }
|
853
|
+
if (table.config.usNumberFormat !== false) {
|
854
|
+
// US Format - 1,234,567.89 -> 1234567.89
|
855
|
+
s = s.replace(/,/g,'');
|
856
|
+
} else {
|
857
|
+
// German Format = 1.234.567,89 -> 1234567.89
|
858
|
+
// French Format = 1 234 567,89 -> 1234567.89
|
859
|
+
s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.');
|
860
|
+
}
|
861
|
+
if(/^\s*\([.\d]+\)/.test(s)) {
|
862
|
+
s = s.replace(/^\s*\(/,'-').replace(/\)/,'');
|
863
|
+
}
|
864
|
+
var i = parseFloat(s);
|
865
|
+
// return the text instead of zero
|
866
|
+
return isNaN(i) ? $.trim(s) : i;
|
867
|
+
};
|
868
|
+
this.isDigit = function(s) {
|
869
|
+
// replace all unwanted chars and match.
|
870
|
+
return (/^[\-+(]?\d*[)]?$/).test(s.replace(/[,.'\s]/g, ''));
|
871
|
+
};
|
872
|
+
|
873
|
+
// regex used in natural sort
|
874
|
+
this.regex = [
|
875
|
+
/(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi, // chunk/tokenize numbers & letters
|
876
|
+
/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, //date
|
877
|
+
/^0x[0-9a-f]+$/i, // hex
|
878
|
+
/^0/ // leading zeros
|
879
|
+
];
|
880
|
+
// used when replacing accented characters during sorting
|
881
|
+
this.characterEquivalents = {
|
882
|
+
"a" : "\u00e1\u00e0\u00e2\u00e3\u00e4", // áàâãä
|
883
|
+
"A" : "\u00c1\u00c0\u00c2\u00c3\u00c4", // ÁÀÂÃÄ
|
884
|
+
"c" : "\u00e7", // ç
|
885
|
+
"C" : "\u00c7", // Ç
|
886
|
+
"e" : "\u00e9\u00e8\u00ea\u00eb", // éèêë
|
887
|
+
"E" : "\u00c9\u00c8\u00ca\u00cb", // ÉÈÊË
|
888
|
+
"i" : "\u00ed\u00ec\u0130\u00ee\u00ef", // íìİîï
|
889
|
+
"I" : "\u00cd\u00cc\u0130\u00ce\u00cf", // ÍÌİÎÏ
|
890
|
+
"o" : "\u00f3\u00f2\u00f4\u00f5\u00f6", // óòôõö
|
891
|
+
"O" : "\u00d3\u00d2\u00d4\u00d5\u00d6", // ÓÒÔÕÖ
|
892
|
+
"S" : "\u00df", // ß
|
893
|
+
"u" : "\u00fa\u00f9\u00fb\u00fc", // úùûü
|
894
|
+
"U" : "\u00da\u00d9\u00db\u00dc" // ÚÙÛÜ
|
895
|
+
};
|
896
|
+
this.replaceAccents = function(s) {
|
897
|
+
if (this.characterRegex.test(s)) {
|
898
|
+
var a, eq = this.characterEquivalents;
|
899
|
+
for (a in eq) {
|
900
|
+
if (typeof a === 'string') {
|
901
|
+
s = s.replace( this.characterRegexArray[a], a );
|
902
|
+
}
|
903
|
+
}
|
904
|
+
}
|
905
|
+
return s;
|
906
|
+
};
|
907
|
+
|
908
|
+
// get sorter, string, empty, etc options for each column from
|
909
|
+
// metadata, header option or header class name ("sorter-false")
|
910
|
+
// priority = jQuery data > meta > headers option > header class name
|
911
|
+
this.getData = function(h, ch, key) {
|
912
|
+
var val = '', $h = $(h),
|
913
|
+
m = $.metadata ? $h.metadata() : false,
|
914
|
+
cl = ' ' + ($h.length ? $h.attr('class') || '' : '');
|
915
|
+
if ($h.length && $h.data() && ( typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined') ){
|
916
|
+
// "data-lockedOrder" is assigned to "lockedorder"; but "data-locked-order" is assigned to "lockedOrder"
|
917
|
+
// "data-sort-initial-order" is assigned to "sortInitialOrder"
|
918
|
+
val += $h.data(key) || $h.data(key.toLowerCase());
|
919
|
+
} else if (m && typeof m[key] !== 'undefined') {
|
920
|
+
val += m[key];
|
921
|
+
} else if (ch && typeof ch[key] !== 'undefined') {
|
922
|
+
val += ch[key];
|
923
|
+
} else if (cl && cl.match(' ' + key + '-')) {
|
924
|
+
// include sorter class name "sorter-text", etc
|
925
|
+
val = cl.match( new RegExp(' ' + key + '-(\\w+)') )[1] || '';
|
926
|
+
}
|
927
|
+
return $.trim(val);
|
928
|
+
};
|
929
|
+
|
930
|
+
this.clearTableBody = function(table) {
|
931
|
+
$(table.tBodies).filter(':not(.' + table.config.cssInfoBlock + ')').empty();
|
932
|
+
};
|
933
|
+
|
934
|
+
}
|
935
|
+
})();
|
936
|
+
|
937
|
+
// make shortcut
|
938
|
+
var ts = $.tablesorter;
|
939
|
+
|
940
|
+
// extend plugin scope
|
941
|
+
$.fn.extend({
|
942
|
+
tablesorter: ts.construct
|
943
|
+
});
|
944
|
+
|
945
|
+
// add default parsers
|
946
|
+
ts.addParser({
|
947
|
+
id: "text",
|
948
|
+
is: function(s, table, node) {
|
949
|
+
return true;
|
950
|
+
},
|
951
|
+
format: function(s, table, cell, cellIndex) {
|
952
|
+
var c = table.config;
|
953
|
+
s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s );
|
954
|
+
return c.sortLocaleCompare ? ts.replaceAccents(s) : s;
|
955
|
+
},
|
956
|
+
type: "text"
|
957
|
+
});
|
958
|
+
|
959
|
+
ts.addParser({
|
960
|
+
id: "currency",
|
961
|
+
is: function(s) {
|
962
|
+
return (/^\(?[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+/).test(s); // £$€¤¥¢
|
963
|
+
},
|
964
|
+
format: function(s, table) {
|
965
|
+
return ts.formatFloat(s.replace(/[^\w,. \-()]/g, ""), table);
|
966
|
+
},
|
967
|
+
type: "numeric"
|
968
|
+
});
|
969
|
+
|
970
|
+
ts.addParser({
|
971
|
+
id: "ipAddress",
|
972
|
+
is: function(s) {
|
973
|
+
return (/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/).test(s);
|
974
|
+
},
|
975
|
+
format: function(s, table) {
|
976
|
+
var i, item, a = s.split("."),
|
977
|
+
r = "",
|
978
|
+
l = a.length;
|
979
|
+
for (i = 0; i < l; i++) {
|
980
|
+
item = a[i];
|
981
|
+
if (item.length === 2) {
|
982
|
+
r += "0" + item;
|
983
|
+
} else {
|
984
|
+
r += item;
|
985
|
+
}
|
986
|
+
}
|
987
|
+
return ts.formatFloat(r, table);
|
988
|
+
},
|
989
|
+
type: "numeric"
|
990
|
+
});
|
991
|
+
|
992
|
+
ts.addParser({
|
993
|
+
id: "url",
|
994
|
+
is: function(s) {
|
995
|
+
return (/^(https?|ftp|file):\/\/$/).test(s);
|
996
|
+
},
|
997
|
+
format: function(s) {
|
998
|
+
return $.trim(s.replace(/(https?|ftp|file):\/\//, ''));
|
999
|
+
},
|
1000
|
+
type: "text"
|
1001
|
+
});
|
1002
|
+
|
1003
|
+
ts.addParser({
|
1004
|
+
id: "isoDate",
|
1005
|
+
is: function(s) {
|
1006
|
+
return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/).test(s);
|
1007
|
+
},
|
1008
|
+
format: function(s, table) {
|
1009
|
+
return ts.formatFloat((s !== "") ? (new Date(s.replace(/-/g, "/")).getTime() || "") : "", table);
|
1010
|
+
},
|
1011
|
+
type: "numeric"
|
1012
|
+
});
|
1013
|
+
|
1014
|
+
ts.addParser({
|
1015
|
+
id: "percent",
|
1016
|
+
is: function(s) {
|
1017
|
+
return (/\d%\)?$/).test(s);
|
1018
|
+
},
|
1019
|
+
format: function(s, table) {
|
1020
|
+
return ts.formatFloat(s.replace(/%/g, ""), table);
|
1021
|
+
},
|
1022
|
+
type: "numeric"
|
1023
|
+
});
|
1024
|
+
|
1025
|
+
ts.addParser({
|
1026
|
+
id: "usLongDate",
|
1027
|
+
is: function(s) {
|
1028
|
+
return s.match(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/);
|
1029
|
+
},
|
1030
|
+
format: function(s, table) {
|
1031
|
+
return ts.formatFloat( (new Date(s).getTime() || ''), table);
|
1032
|
+
},
|
1033
|
+
type: "numeric"
|
1034
|
+
});
|
1035
|
+
|
1036
|
+
ts.addParser({
|
1037
|
+
id: "shortDate", // "mmddyyyy", "ddmmyyyy" or "yyyymmdd"
|
1038
|
+
is: function(s) {
|
1039
|
+
// testing for ####-####-#### - so it's not perfect
|
1040
|
+
return (/\d{1,4}[\/\-\,\.\s+]\d{1,4}[\/\-\.\,\s+]\d{1,4}/).test(s);
|
1041
|
+
},
|
1042
|
+
format: function(s, table, cell, cellIndex) {
|
1043
|
+
var c = table.config, ci = c.headerList[cellIndex],
|
1044
|
+
format = ci.shortDateFormat;
|
1045
|
+
if (typeof format === 'undefined') {
|
1046
|
+
// cache header formatting so it doesn't getData for every cell in the column
|
1047
|
+
format = ci.shortDateFormat = ts.getData( ci, c.headers[cellIndex], 'dateFormat') || c.dateFormat;
|
1048
|
+
}
|
1049
|
+
s = s.replace(/\s+/g," ").replace(/[\-|\.|\,]/g, "/");
|
1050
|
+
if (format === "mmddyyyy") {
|
1051
|
+
s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$1/$2");
|
1052
|
+
} else if (format === "ddmmyyyy") {
|
1053
|
+
s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$2/$1");
|
1054
|
+
} else if (format === "yyyymmdd") {
|
1055
|
+
s = s.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, "$1/$2/$3");
|
1056
|
+
}
|
1057
|
+
return ts.formatFloat( (new Date(s).getTime() || ''), table);
|
1058
|
+
},
|
1059
|
+
type: "numeric"
|
1060
|
+
});
|
1061
|
+
|
1062
|
+
ts.addParser({
|
1063
|
+
id: "time",
|
1064
|
+
is: function(s) {
|
1065
|
+
return (/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/).test(s);
|
1066
|
+
},
|
1067
|
+
format: function(s, table) {
|
1068
|
+
return ts.formatFloat( (new Date("2000/01/01 " + s).getTime() || ''), table);
|
1069
|
+
},
|
1070
|
+
type: "numeric"
|
1071
|
+
});
|
1072
|
+
|
1073
|
+
ts.addParser({
|
1074
|
+
id: "digit",
|
1075
|
+
is: function(s) {
|
1076
|
+
return ts.isDigit(s);
|
1077
|
+
},
|
1078
|
+
format: function(s, table) {
|
1079
|
+
return ts.formatFloat(s.replace(/[^\w,. \-()]/g, ""), table);
|
1080
|
+
},
|
1081
|
+
type: "numeric"
|
1082
|
+
});
|
1083
|
+
|
1084
|
+
ts.addParser({
|
1085
|
+
id: "metadata",
|
1086
|
+
is: function(s) {
|
1087
|
+
return false;
|
1088
|
+
},
|
1089
|
+
format: function(s, table, cell) {
|
1090
|
+
var c = table.config,
|
1091
|
+
p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
|
1092
|
+
return $(cell).metadata()[p];
|
1093
|
+
},
|
1094
|
+
type: "numeric"
|
1095
|
+
});
|
1096
|
+
|
1097
|
+
// add default widgets
|
1098
|
+
ts.addWidget({
|
1099
|
+
id: "zebra",
|
1100
|
+
format: function(table) {
|
1101
|
+
var $tb, $tr, $f, row, even, time, k, j, l, n,
|
1102
|
+
c = table.config,
|
1103
|
+
child = new RegExp(c.cssChildRow, 'i'),
|
1104
|
+
b = $(table).children('tbody:not(.' + c.cssInfoBlock + ')'),
|
1105
|
+
css = [ "even", "odd" ];
|
1106
|
+
// maintain backwards compatibility
|
1107
|
+
css = c.widgetZebra && c.hasOwnProperty('css') ? c.widgetZebra.css :
|
1108
|
+
(c.widgetOptions && c.widgetOptions.hasOwnProperty('zebra')) ? c.widgetOptions.zebra : css;
|
1109
|
+
if (c.debug) {
|
1110
|
+
time = new Date();
|
1111
|
+
}
|
1112
|
+
for (k = 0; k < b.length; k++ ) {
|
1113
|
+
row = 0;
|
1114
|
+
// loop through the visible rows
|
1115
|
+
$tb = $(b[k]);
|
1116
|
+
l = $tb.children('tr').length;
|
1117
|
+
if (l > 1) {
|
1118
|
+
$f = $(document.createDocumentFragment());
|
1119
|
+
$tr = $tb.children('tr').appendTo($f);
|
1120
|
+
for (j = 0; j < l; j++) {
|
1121
|
+
if ($tr[j].style.display !== 'none') {
|
1122
|
+
n = $tr[j].className;
|
1123
|
+
// style children rows the same way the parent row was styled
|
1124
|
+
if (!child.test(n)) { row++; }
|
1125
|
+
even = (row % 2 === 0);
|
1126
|
+
$tr[j].className = n.replace(/\s+/g,'').replace(css[0],'').replace(css[1],'') + ' ' + css[even ? 0 : 1];
|
1127
|
+
}
|
1128
|
+
}
|
1129
|
+
}
|
1130
|
+
$tb.append($tr);
|
1131
|
+
}
|
1132
|
+
if (c.debug) {
|
1133
|
+
ts.benchmark("Applying Zebra widget", time);
|
1134
|
+
}
|
1135
|
+
}
|
1136
|
+
});
|
1137
|
+
|
1138
|
+
})(jQuery);
|