footable-on-rails 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/FooTable-On-Rails.gemspec +23 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +34 -0
  7. data/Rakefile +1 -0
  8. data/lib/footable-on-rails.rb +12 -0
  9. data/lib/footable-on-rails/engine.rb +6 -0
  10. data/lib/footable-on-rails/railtie.rb +5 -0
  11. data/lib/footable-on-rails/version.rb +5 -0
  12. data/vendor/assets/images/footable-on-rails/minus.png +0 -0
  13. data/vendor/assets/images/footable-on-rails/plus.png +0 -0
  14. data/vendor/assets/javascripts/footable-on-rails/footable.js +784 -0
  15. data/vendor/assets/javascripts/footable-on-rails/index.js +2 -0
  16. data/vendor/assets/javascripts/footable-on-rails/plugins/footable.filter.js +144 -0
  17. data/vendor/assets/javascripts/footable-on-rails/plugins/footable.paginate.js +241 -0
  18. data/vendor/assets/javascripts/footable-on-rails/plugins/footable.sort.js +190 -0
  19. data/vendor/assets/javascripts/footable-on-rails/plugins/footable.striping.js +57 -0
  20. data/vendor/assets/stylesheets/footable-on-rails/fonts/footable.eot +0 -0
  21. data/vendor/assets/stylesheets/footable-on-rails/fonts/footable.svg +78 -0
  22. data/vendor/assets/stylesheets/footable-on-rails/fonts/footable.ttf +0 -0
  23. data/vendor/assets/stylesheets/footable-on-rails/fonts/footable.woff +0 -0
  24. data/vendor/assets/stylesheets/footable-on-rails/footable.core.css +178 -0
  25. data/vendor/assets/stylesheets/footable-on-rails/footable.core.min.css +1 -0
  26. data/vendor/assets/stylesheets/footable-on-rails/footable.metro.css +152 -0
  27. data/vendor/assets/stylesheets/footable-on-rails/footable.metro.min.css +1 -0
  28. data/vendor/assets/stylesheets/footable-on-rails/footable.standalone.css +181 -0
  29. data/vendor/assets/stylesheets/footable-on-rails/footable.standalone.min.css +1 -0
  30. data/vendor/assets/stylesheets/footable-on-rails/index.css +9 -0
  31. metadata +101 -0
@@ -0,0 +1,2 @@
1
+ //= require ./footable.js
2
+ //= require_tree ./plugins/
@@ -0,0 +1,144 @@
1
+ (function ($, w, undefined) {
2
+ if (w.footable === undefined || w.footable === null)
3
+ throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
4
+
5
+ var defaults = {
6
+ filter: {
7
+ enabled: true,
8
+ input: '.footable-filter',
9
+ timeout: 300,
10
+ minimum: 2,
11
+ disableEnter: false,
12
+ filterFunction: function(index) {
13
+ var $t = $(this),
14
+ $table = $t.parents('table:first'),
15
+ filter = $table.data('current-filter').toUpperCase(),
16
+ text = $t.find('td').text();
17
+ if (!$table.data('filter-text-only')) {
18
+ $t.find('td[data-value]').each(function () {
19
+ text += $(this).data('value');
20
+ });
21
+ }
22
+ return text.toUpperCase().indexOf(filter) >= 0;
23
+ }
24
+ }
25
+ };
26
+
27
+ function Filter() {
28
+ var p = this;
29
+ p.name = 'Footable Filter';
30
+ p.init = function (ft) {
31
+ p.footable = ft;
32
+ if (ft.options.filter.enabled === true) {
33
+ if ($(ft.table).data('filter') === false) return;
34
+ ft.timers.register('filter');
35
+ $(ft.table)
36
+ .unbind('.filtering')
37
+ .bind({
38
+ 'footable_initialized.filtering': function (e) {
39
+ var $table = $(ft.table);
40
+ var data = {
41
+ 'input': $table.data('filter') || ft.options.filter.input,
42
+ 'timeout': $table.data('filter-timeout') || ft.options.filter.timeout,
43
+ 'minimum': $table.data('filter-minimum') || ft.options.filter.minimum,
44
+ 'disableEnter': $table.data('filter-disable-enter') || ft.options.filter.disableEnter
45
+ };
46
+ if (data.disableEnter) {
47
+ $(data.input).keypress(function (event) {
48
+ if (window.event)
49
+ return (window.event.keyCode !== 13);
50
+ else
51
+ return (event.which !== 13);
52
+ });
53
+ }
54
+ $table.bind('footable_clear_filter', function () {
55
+ $(data.input).val('');
56
+ p.clearFilter();
57
+ });
58
+ $table.bind('footable_filter', function (event, args) {
59
+ p.filter(args.filter);
60
+ });
61
+ $(data.input).keyup(function (eve) {
62
+ ft.timers.filter.stop();
63
+ if (eve.which === 27) {
64
+ $(data.input).val('');
65
+ }
66
+ ft.timers.filter.start(function () {
67
+ var val = $(data.input).val() || '';
68
+ p.filter(val);
69
+ }, data.timeout);
70
+ });
71
+ },
72
+ 'footable_redrawn.filtering': function (e) {
73
+ var $table = $(ft.table),
74
+ filter = $table.data('filter-string');
75
+ if (filter) {
76
+ p.filter(filter);
77
+ }
78
+ }
79
+ })
80
+ //save the filter object onto the table so we can access it later
81
+ .data('footable-filter', p);
82
+ }
83
+ };
84
+
85
+ p.filter = function (filterString) {
86
+ var ft = p.footable,
87
+ $table = $(ft.table),
88
+ minimum = $table.data('filter-minimum') || ft.options.filter.minimum,
89
+ clear = !filterString;
90
+
91
+ //raise a pre-filter event so that we can cancel the filtering if needed
92
+ var event = ft.raise('footable_filtering', { filter: filterString, clear: clear });
93
+ if (event && event.result === false) return;
94
+ if (event.filter && event.filter.length < minimum) {
95
+ return; //if we do not have the minimum chars then do nothing
96
+ }
97
+
98
+ if (event.clear) {
99
+ p.clearFilter();
100
+ } else {
101
+ var filters = event.filter.split(' ');
102
+
103
+ $table.find('> tbody > tr').hide().addClass('footable-filtered');
104
+ var rows = $table.find('> tbody > tr:not(.footable-row-detail)');
105
+ $.each(filters, function (i, f) {
106
+ if (f && f.length > 0) {
107
+ $table.data('current-filter', f);
108
+ rows = rows.filter(ft.options.filter.filterFunction);
109
+ }
110
+ });
111
+ rows.each(function () {
112
+ p.showRow(this, ft);
113
+ $(this).removeClass('footable-filtered');
114
+ });
115
+ $table.data('filter-string', event.filter);
116
+ ft.raise('footable_filtered', { filter: event.filter, clear: false });
117
+ }
118
+ };
119
+
120
+ p.clearFilter = function () {
121
+ var ft = p.footable,
122
+ $table = $(ft.table);
123
+
124
+ $table.find('> tbody > tr:not(.footable-row-detail)').removeClass('footable-filtered').each(function () {
125
+ p.showRow(this, ft);
126
+ });
127
+ $table.removeData('filter-string');
128
+ ft.raise('footable_filtered', { clear: true });
129
+ };
130
+
131
+ p.showRow = function (row, ft) {
132
+ var $row = $(row), $next = $row.next(), $table = $(ft.table);
133
+ if ($row.is(':visible')) return; //already visible - do nothing
134
+ if ($table.hasClass('breakpoint') && $row.hasClass('footable-detail-show') && $next.hasClass('footable-row-detail')) {
135
+ $row.add($next).show();
136
+ ft.createOrUpdateDetailRow(row);
137
+ }
138
+ else $row.show();
139
+ };
140
+ }
141
+
142
+ w.footable.plugins.register(Filter, defaults);
143
+
144
+ })(jQuery, window);
@@ -0,0 +1,241 @@
1
+ (function ($, w, undefined) {
2
+ if (w.footable === undefined || w.footable === null)
3
+ throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
4
+
5
+ var defaults = {
6
+ paginate: true,
7
+ pageSize: 10,
8
+ pageNavigation: '.pagination',
9
+ firstText: '&laquo;',
10
+ previousText: '&lsaquo;',
11
+ nextText: '&rsaquo;',
12
+ lastText: '&raquo;',
13
+ limitNavigation: 0,
14
+ limitPreviousText: '...',
15
+ limitNextText: '...'
16
+ };
17
+
18
+ function pageInfo(ft) {
19
+ var $table = $(ft.table), data = $table.data();
20
+ this.pageNavigation = data.pageNavigation || ft.options.pageNavigation;
21
+ this.pageSize = data.pageSize || ft.options.pageSize;
22
+ this.firstText = data.firstText || ft.options.firstText;
23
+ this.previousText = data.previousText || ft.options.previousText;
24
+ this.nextText = data.nextText || ft.options.nextText;
25
+ this.lastText = data.lastText || ft.options.lastText;
26
+ this.limitNavigation = parseInt(data.limitNavigation || ft.options.limitNavigation || defaults.limitNavigation, 10);
27
+ this.limitPreviousText = data.limitPreviousText || ft.options.limitPreviousText;
28
+ this.limitNextText = data.limitNextText || ft.options.limitNextText;
29
+ this.limit = this.limitNavigation > 0;
30
+ this.currentPage = data.currentPage || 0;
31
+ this.pages = [];
32
+ this.control = false;
33
+ }
34
+
35
+ function Paginate() {
36
+ var p = this;
37
+ p.name = 'Footable Paginate';
38
+
39
+ p.init = function (ft) {
40
+ if (ft.options.paginate === true) {
41
+ if ($(ft.table).data('page') === false) return;
42
+ p.footable = ft;
43
+ $(ft.table)
44
+ .unbind('.paging')
45
+ .bind({
46
+ 'footable_initialized.paging footable_row_removed.paging footable_redrawn.paging footable_sorted.paging footable_filtered.paging': function () {
47
+ p.setupPaging();
48
+ }
49
+ })
50
+ //save the filter object onto the table so we can access it later
51
+ .data('footable-paging', p);
52
+ }
53
+ };
54
+
55
+ p.setupPaging = function () {
56
+ var ft = p.footable,
57
+ $tbody = $(ft.table).find('> tbody');
58
+
59
+ ft.pageInfo = new pageInfo(ft);
60
+
61
+ p.createPages(ft, $tbody);
62
+ p.createNavigation(ft, $tbody);
63
+ p.fillPage(ft, $tbody, ft.pageInfo.currentPage);
64
+ };
65
+
66
+ p.createPages = function (ft, tbody) {
67
+ var pages = 1;
68
+ var info = ft.pageInfo;
69
+ var pageCount = pages * info.pageSize;
70
+ var page = [];
71
+ var lastPage = [];
72
+ info.pages = [];
73
+ var rows = tbody.find('> tr:not(.footable-filtered,.footable-row-detail)');
74
+ rows.each(function (i, row) {
75
+ page.push(row);
76
+ if (i === pageCount - 1) {
77
+ info.pages.push(page);
78
+ pages++;
79
+ pageCount = pages * info.pageSize;
80
+ page = [];
81
+ } else if (i >= rows.length - (rows.length % info.pageSize)) {
82
+ lastPage.push(row);
83
+ }
84
+ });
85
+ if (lastPage.length > 0) info.pages.push(lastPage);
86
+ if (info.currentPage >= info.pages.length) info.currentPage = info.pages.length - 1;
87
+ if (info.currentPage < 0) info.currentPage = 0;
88
+ if (info.pages.length === 1) {
89
+ //we only have a single page
90
+ $(ft.table).addClass('no-paging');
91
+ } else {
92
+ $(ft.table).removeClass('no-paging');
93
+ }
94
+ };
95
+
96
+ p.createNavigation = function (ft, tbody) {
97
+ var $nav = $(ft.table).find(ft.pageInfo.pageNavigation);
98
+ //if we cannot find the navigation control within the table, then try find it outside
99
+ if ($nav.length === 0) {
100
+ $nav = $(ft.pageInfo.pageNavigation);
101
+ //if the navigation control is inside another table, then get out
102
+ if ($nav.parents('table:first').length > 0 && $nav.parents('table:first') !== $(ft.table)) return;
103
+ //if we found more than one navigation control, write error to console
104
+ if ($nav.length > 1 && ft.options.debug === true) console.error('More than one pagination control was found!');
105
+ }
106
+ //if we still cannot find the control, then don't do anything
107
+ if ($nav.length === 0) return;
108
+ //if the nav is not a UL, then find or create a UL
109
+ if (!$nav.is('ul')) {
110
+ if ($nav.find('ul:first').length === 0) {
111
+ $nav.append('<ul />');
112
+ }
113
+ $nav = $nav.find('ul');
114
+ }
115
+ $nav.find('li').remove();
116
+ var info = ft.pageInfo;
117
+ info.control = $nav;
118
+ if (info.pages.length > 0) {
119
+ $nav.append('<li class="footable-page-arrow"><a data-page="first" href="#first">' + ft.pageInfo.firstText + '</a>');
120
+ $nav.append('<li class="footable-page-arrow"><a data-page="prev" href="#prev">' + ft.pageInfo.previousText + '</a></li>');
121
+ if (info.limit){
122
+ $nav.append('<li class="footable-page-arrow"><a data-page="limit-prev" href="#limit-prev">' + ft.pageInfo.limitPreviousText + '</a></li>');
123
+ }
124
+ if (!info.limit){
125
+ $.each(info.pages, function (i, page) {
126
+ if (page.length > 0) {
127
+ $nav.append('<li class="footable-page"><a data-page="' + i + '" href="#">' + (i + 1) + '</a></li>');
128
+ }
129
+ });
130
+ }
131
+ if (info.limit){
132
+ $nav.append('<li class="footable-page-arrow"><a data-page="limit-next" href="#limit-next">' + ft.pageInfo.limitNextText + '</a></li>');
133
+ p.createLimited($nav, info, 0);
134
+ }
135
+ $nav.append('<li class="footable-page-arrow"><a data-page="next" href="#next">' + ft.pageInfo.nextText + '</a></li>');
136
+ $nav.append('<li class="footable-page-arrow"><a data-page="last" href="#last">' + ft.pageInfo.lastText + '</a></li>');
137
+ }
138
+ $nav.off('click', 'a[data-page]').on('click', 'a[data-page]', function (e) {
139
+ e.preventDefault();
140
+ var page = $(this).data('page');
141
+ var newPage = info.currentPage;
142
+ if (page === 'first') {
143
+ newPage = 0;
144
+ } else if (page === 'prev') {
145
+ if (newPage > 0) newPage--;
146
+ } else if (page === 'next') {
147
+ if (newPage < info.pages.length - 1) newPage++;
148
+ } else if (page === 'last') {
149
+ newPage = info.pages.length - 1;
150
+ } else if (page === 'limit-prev') {
151
+ newPage = -1;
152
+ var first = $nav.find('.footable-page:first a').data('page');
153
+ p.createLimited($nav, info, first - info.limitNavigation);
154
+ p.setPagingClasses($nav, info.currentPage, info.pages.length);
155
+ } else if (page === 'limit-next') {
156
+ newPage = -1;
157
+ var last = $nav.find('.footable-page:last a').data('page');
158
+ p.createLimited($nav, info, last + 1);
159
+ p.setPagingClasses($nav, info.currentPage, info.pages.length);
160
+ } else {
161
+ newPage = page;
162
+ }
163
+ if (newPage >= 0){
164
+ if (info.limit && info.currentPage != newPage){
165
+ var start = newPage;
166
+ while (start % info.limitNavigation !== 0){ start -= 1; }
167
+ p.createLimited($nav, info, start);
168
+ }
169
+ p.paginate(ft, newPage);
170
+ }
171
+ });
172
+ p.setPagingClasses($nav, info.currentPage, info.pages.length);
173
+ };
174
+
175
+ p.createLimited = function(nav, info, start){
176
+ start = start || 0;
177
+ nav.find('li.footable-page').remove();
178
+ var i, page,
179
+ $prev = nav.find('li.footable-page-arrow > a[data-page="limit-prev"]').parent(),
180
+ $next = nav.find('li.footable-page-arrow > a[data-page="limit-next"]').parent();
181
+ for (i = info.pages.length - 1; i >=0 ; i--){
182
+ page = info.pages[i];
183
+ if (i >= start && i < start + info.limitNavigation && page.length > 0) {
184
+ $prev.after('<li class="footable-page"><a data-page="' + i + '" href="#">' + (i + 1) + '</a></li>');
185
+ }
186
+ }
187
+ if (start === 0){ $prev.hide(); }
188
+ else { $prev.show(); }
189
+ if (start + info.limitNavigation >= info.pages.length){ $next.hide(); }
190
+ else { $next.show(); }
191
+ };
192
+
193
+ p.paginate = function (ft, newPage) {
194
+ var info = ft.pageInfo;
195
+ if (info.currentPage !== newPage) {
196
+ var $tbody = $(ft.table).find('> tbody');
197
+
198
+ //raise a pre-pagin event so that we can cancel the paging if needed
199
+ var event = ft.raise('footable_paging', { page: newPage, size: info.pageSize });
200
+ if (event && event.result === false) return;
201
+
202
+ p.fillPage(ft, $tbody, newPage);
203
+ info.control.find('li').removeClass('active disabled');
204
+ p.setPagingClasses(info.control, info.currentPage, info.pages.length);
205
+ }
206
+ };
207
+
208
+ p.setPagingClasses = function (nav, currentPage, pageCount) {
209
+ nav.find('li.footable-page > a[data-page=' + currentPage + ']').parent().addClass('active');
210
+ if (currentPage >= pageCount - 1) {
211
+ nav.find('li.footable-page-arrow > a[data-page="next"]').parent().addClass('disabled');
212
+ nav.find('li.footable-page-arrow > a[data-page="last"]').parent().addClass('disabled');
213
+ }
214
+ if (currentPage < 1) {
215
+ nav.find('li.footable-page-arrow > a[data-page="first"]').parent().addClass('disabled');
216
+ nav.find('li.footable-page-arrow > a[data-page="prev"]').parent().addClass('disabled');
217
+ }
218
+ };
219
+
220
+ p.fillPage = function (ft, tbody, pageNumber) {
221
+ ft.pageInfo.currentPage = pageNumber;
222
+ $(ft.table).data('currentPage', pageNumber);
223
+ tbody.find('> tr').hide();
224
+ $(ft.pageInfo.pages[pageNumber]).each(function () {
225
+ p.showRow(this, ft);
226
+ });
227
+ };
228
+
229
+ p.showRow = function (row, ft) {
230
+ var $row = $(row), $next = $row.next(), $table = $(ft.table);
231
+ if ($table.hasClass('breakpoint') && $row.hasClass('footable-detail-show') && $next.hasClass('footable-row-detail')) {
232
+ $row.add($next).show();
233
+ ft.createOrUpdateDetailRow(row);
234
+ }
235
+ else $row.show();
236
+ };
237
+ }
238
+
239
+ w.footable.plugins.register(Paginate, defaults);
240
+
241
+ })(jQuery, window);
@@ -0,0 +1,190 @@
1
+ (function ($, w, undefined) {
2
+ if (w.footable === undefined || w.footable === null)
3
+ throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
4
+
5
+ var defaults = {
6
+ sort: true,
7
+ sorters: {
8
+ alpha: function (a, b) {
9
+ if (typeof(a) === 'string') { a = a.toLowerCase(); }
10
+ if (typeof(b) === 'string') { b = b.toLowerCase(); }
11
+ if (a === b) return 0;
12
+ if (a < b) return -1;
13
+ return 1;
14
+ },
15
+ numeric: function (a, b) {
16
+ return a - b;
17
+ }
18
+ },
19
+ classes: {
20
+ sort: {
21
+ sortable: 'footable-sortable',
22
+ sorted: 'footable-sorted',
23
+ descending: 'footable-sorted-desc',
24
+ indicator: 'footable-sort-indicator'
25
+ }
26
+ },
27
+ events: {
28
+ sort: {
29
+ sorting: 'footable_sorting',
30
+ sorted: 'footable_sorted'
31
+ }
32
+ }
33
+ };
34
+
35
+ function Sort() {
36
+ var p = this;
37
+ p.name = 'Footable Sortable';
38
+ p.init = function (ft) {
39
+ p.footable = ft;
40
+ if (ft.options.sort === true) {
41
+ $(ft.table)
42
+ .unbind('.sorting')
43
+ .bind({
44
+ 'footable_initialized.sorting': function (e) {
45
+ var $table = $(ft.table),
46
+ $tbody = $table.find('> tbody'),
47
+ cls = ft.options.classes.sort,
48
+ column, $th;
49
+
50
+ if ($table.data('sort') === false) return;
51
+
52
+ $table.find('> thead > tr:last-child > th, > thead > tr:last-child > td').each(function (ec) {
53
+ $th = $(this), column = ft.columns[$th.index()];
54
+ if (column.sort.ignore !== true && !$th.hasClass(cls.sortable)) {
55
+ $th.addClass(cls.sortable);
56
+ $('<span />').addClass(cls.indicator).appendTo($th);
57
+ }
58
+ });
59
+
60
+ $table.find('> thead > tr:last-child > th.' + cls.sortable + ', > thead > tr:last-child > td.' + cls.sortable).unbind('click.footable').bind('click.footable', function (ec) {
61
+ ec.preventDefault();
62
+ $th = $(this);
63
+ var ascending = !$th.hasClass(cls.sorted);
64
+ p.doSort($th.index(), ascending);
65
+ return false;
66
+ });
67
+
68
+ var didSomeSorting = false;
69
+ for (var c in ft.columns) {
70
+ column = ft.columns[c];
71
+ if (column.sort.initial) {
72
+ var ascending = (column.sort.initial !== 'descending');
73
+ p.doSort(column.index, ascending);
74
+ break;
75
+ }
76
+ }
77
+ if (didSomeSorting) {
78
+ ft.bindToggleSelectors();
79
+ }
80
+ },
81
+ 'footable_redrawn.sorting': function(e) {
82
+ var $table = $(ft.table),
83
+ cls = ft.options.classes.sort;
84
+ if ($table.data('sorted') >= 0) {
85
+ $table.find('> thead > tr:last-child > th').each(function(i){
86
+ var $th = $(this);
87
+ if ($th.hasClass(cls.sorted) || $th.hasClass(cls.descending)) {
88
+ p.doSort(i);
89
+ return;
90
+ }
91
+ });
92
+ }
93
+ },
94
+ 'footable_column_data.sorting': function (e) {
95
+ var $th = $(e.column.th);
96
+ e.column.data.sort = e.column.data.sort || {};
97
+ e.column.data.sort.initial = $th.data('sort-initial') || false;
98
+ e.column.data.sort.ignore = $th.data('sort-ignore') || false;
99
+ e.column.data.sort.selector = $th.data('sort-selector') || null;
100
+
101
+ var match = $th.data('sort-match') || 0;
102
+ if (match >= e.column.data.matches.length) match = 0;
103
+ e.column.data.sort.match = e.column.data.matches[match];
104
+ }
105
+ })
106
+ //save the sort object onto the table so we can access it later
107
+ .data('footable-sort', p);
108
+ }
109
+ };
110
+
111
+ p.doSort = function(columnIndex, ascending) {
112
+ var ft = p.footable;
113
+ if ($(ft.table).data('sort') === false) return;
114
+
115
+ var $table = $(ft.table),
116
+ $tbody = $table.find('> tbody'),
117
+ column = ft.columns[columnIndex],
118
+ $th = $table.find('> thead > tr:last-child > th:eq(' + columnIndex + ')'),
119
+ cls = ft.options.classes.sort,
120
+ evt = ft.options.events.sort;
121
+
122
+ ascending = (ascending === undefined) ? $th.hasClass(cls.sorted) :
123
+ (ascending === 'toggle') ? !$th.hasClass(cls.sorted) : ascending;
124
+
125
+ if (column.sort.ignore === true) return true;
126
+
127
+ //raise a pre-sorting event so that we can cancel the sorting if needed
128
+ var event = ft.raise(evt.sorting, { column: column, direction: ascending ? 'ASC' : 'DESC' });
129
+ if (event && event.result === false) return;
130
+
131
+ $table.data('sorted', column.index);
132
+
133
+ $table.find('> thead > tr:last-child > th, > thead > tr:last-child > td').not($th).removeClass(cls.sorted + ' ' + cls.descending);
134
+
135
+ if (ascending === undefined) {
136
+ ascending = $th.hasClass(cls.sorted);
137
+ }
138
+
139
+ if (ascending) {
140
+ $th.removeClass(cls.descending).addClass(cls.sorted);
141
+ } else {
142
+ $th.removeClass(cls.sorted).addClass(cls.descending);
143
+ }
144
+
145
+ p.sort(ft, $tbody, column, ascending);
146
+
147
+ ft.bindToggleSelectors();
148
+ ft.raise(evt.sorted, { column: column, direction: ascending ? 'ASC' : 'DESC' });
149
+ };
150
+
151
+ p.rows = function (ft, tbody, column) {
152
+ var rows = [];
153
+ tbody.find('> tr').each(function () {
154
+ var $row = $(this), $next = null;
155
+ if ($row.hasClass(ft.options.classes.detail)) return true;
156
+ if ($row.next().hasClass(ft.options.classes.detail)) {
157
+ $next = $row.next().get(0);
158
+ }
159
+ var row = { 'row': $row, 'detail': $next };
160
+ if (column !== undefined) {
161
+ row.value = ft.parse(this.cells[column.sort.match], column);
162
+ }
163
+ rows.push(row);
164
+ return true;
165
+ }).detach();
166
+ return rows;
167
+ };
168
+
169
+ p.sort = function (ft, tbody, column, ascending) {
170
+ var rows = p.rows(ft, tbody, column);
171
+ var sorter = ft.options.sorters[column.type] || ft.options.sorters.alpha;
172
+ rows.sort(function (a, b) {
173
+ if (ascending) {
174
+ return sorter(a.value, b.value);
175
+ } else {
176
+ return sorter(b.value, a.value);
177
+ }
178
+ });
179
+ for (var j = 0; j < rows.length; j++) {
180
+ tbody.append(rows[j].row);
181
+ if (rows[j].detail !== null) {
182
+ tbody.append(rows[j].detail);
183
+ }
184
+ }
185
+ };
186
+ }
187
+
188
+ w.footable.plugins.register(Sort, defaults);
189
+
190
+ })(jQuery, window);