footable_rails 0.0.1

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.
@@ -0,0 +1,373 @@
1
+ (function($, w, undefined) {
2
+ if (w.footable === undefined || w.foobox === null) throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
3
+ var defaults = {
4
+ grid: {
5
+ enabled: true,
6
+ data: null,
7
+ template: null, //row html template, use for make a row.
8
+ cols: null, //column define
9
+ items: null, //data items
10
+ url: null, //get data from url
11
+ ajax: null, //paramater for $.ajax
12
+ activeClass: 'active', //add to row selected
13
+ multiSelect: false, //allow select multiple row
14
+ showIndex: false, //show row index
15
+ showCheckbox: false, //show checkbox for select
16
+ showEmptyInfo: false, //when that is not data in table, show a info to notify user
17
+ emptyInfo: '<p class="text-center text-warning">No Data</p>',
18
+ pagination: {
19
+ "page-size": 20,
20
+ "pagination-class": "pagination pagination-centered"
21
+ },
22
+ indexFormatter: function(val, $td, index) {
23
+ return index + 1;
24
+ },
25
+ checkboxFormatter: function(isTop) {
26
+ return '<input type="checkbox" class="' + (isTop ? 'checkAll' : 'check') + '">';
27
+ },
28
+ events: {
29
+ loaded: 'footable_grid_loaded',
30
+ created: 'footable_grid_created',
31
+ removed: 'footable_grid_removed',
32
+ updated: 'footable_grid_updated'
33
+ }
34
+ }
35
+ };
36
+
37
+ function makeTh(col) {
38
+ var $th = $('<th>' + col.title + '</th>');
39
+ if ($.isPlainObject(col.data)) {
40
+ $th.data(col.data);
41
+ }
42
+ if ($.isPlainObject(col.style)) {
43
+ $th.css(col.style);
44
+ }
45
+ if (col.className) {
46
+ $th.addClass(col.className);
47
+ }
48
+ return $th;
49
+ }
50
+
51
+ function initThead($table, options) {
52
+ var $thead = $table.find('thead');
53
+ if ($thead.size() === 0) {
54
+ $thead = $('<thead>').appendTo($table);
55
+ }
56
+ var $row = $('<tr>').appendTo($thead);
57
+ for (var i = 0, len = options.cols.length; i < len; i++) {
58
+ $row.append(makeTh(options.cols[i]));
59
+ }
60
+ }
61
+
62
+ function initTBody($table) {
63
+ var $tbody = $table.find('tbody');
64
+ if ($tbody.size() === 0) {
65
+ $tbody = $('<tbody>').appendTo($table);
66
+ }
67
+ }
68
+
69
+ function initPagination($table, cols, options) {
70
+ if (options) {
71
+ $table.attr("data-page-size", options['page-size']);
72
+ var $tfoot = $table.find('tfoot');
73
+ if ($tfoot.size() === 0) {
74
+ $tfoot = $('<tfoot class="hide-if-no-paging"></tfoot>').appendTo($table);
75
+ }
76
+ $tfoot.append('<tr><td colspan=' + cols.length + '></td></tr>');
77
+ var $pagination = $("<div>").appendTo($tfoot.find("tr:last-child td"));
78
+ $pagination.addClass(options['pagination-class']);
79
+ }
80
+ }
81
+
82
+ function setToggleColumn(cols) {
83
+ var toggleColumn = cols[0];
84
+ for (var i = 0, len = cols.length; i < len; i++) {
85
+ var col = cols[i];
86
+ if (col.data && (col.data.toggle === true || col.data.toggle === "true")) {
87
+ return;
88
+ }
89
+ }
90
+ toggleColumn.data = $.extend(toggleColumn.data, {
91
+ toggle: true
92
+ });
93
+ }
94
+
95
+ function makeEmptyInfo($table, cols, emptyInfo) {
96
+ if ($table.find("tr.emptyInfo").size() === 0) {
97
+ $table.find('tbody').append('<tr class="emptyInfo"><td colspan="' + cols.length + '">' + emptyInfo + '</td></tr>');
98
+ }
99
+ }
100
+
101
+ function updateRowIndex($tbody, $newRow, detailClass, offset) {
102
+ //update rows index
103
+ $tbody.find('tr:not(.' + detailClass + ')').each(function() {
104
+ var $row = $(this),
105
+ index = $newRow.data('index'),
106
+ oldIndex = parseInt($row.data('index'), 0),
107
+ newIndex = oldIndex + offset;
108
+ if (oldIndex >= index && this !== $newRow.get(0)) {
109
+ $row.attr('data-index', newIndex).data('index', newIndex);
110
+ }
111
+ });
112
+ }
113
+
114
+ function Grid() {
115
+ var grid = this;
116
+ grid.name = 'Footable Grid';
117
+ grid.init = function(ft) {
118
+ var toggleClass = ft.options.classes.toggle;
119
+ var detailClass = ft.options.classes.detail;
120
+ var options = ft.options.grid;
121
+ if (!options.cols) return;
122
+ grid.footable = ft;
123
+ var $table = $(ft.table);
124
+ $table.data('grid', grid);
125
+ if ($.isPlainObject(options.data)) {
126
+ $table.data(options.data);
127
+ }
128
+ grid._items = [];
129
+ setToggleColumn(options.cols);
130
+ if (options.showCheckbox) {
131
+ options.multiSelect = true;
132
+ options.cols.unshift({
133
+ title: options.checkboxFormatter(true),
134
+ name: '',
135
+ data: {
136
+ "sort-ignore": true
137
+ },
138
+ formatter: options.checkboxFormatter
139
+ });
140
+ }
141
+ if (options.showIndex) {
142
+ options.cols.unshift({
143
+ title: '#',
144
+ name: 'index',
145
+ data: {
146
+ "sort-ignore": true
147
+ },
148
+ formatter: options.indexFormatter
149
+ });
150
+ }
151
+ initThead($table, options);
152
+ initTBody($table);
153
+ initPagination($table, options.cols, options.pagination);
154
+ $table.off('.grid').on({
155
+ 'footable_initialized.grid': function(e) {
156
+ if (options.url || options.ajax) {
157
+ $.ajax(options.ajax || {
158
+ url: options.url
159
+ }).then(function(resp) {
160
+ grid.newItem(resp);
161
+ ft.raise(options.events.loaded);
162
+ }, function(jqXHR) {
163
+ throw 'load data from ' + (options.url || options.ajax.url) + ' fail';
164
+ });
165
+ } else {
166
+ grid.newItem(options.items || []);
167
+ ft.raise(options.events.loaded);
168
+ }
169
+ },
170
+ 'footable_sorted.grid footable_grid_created.grid footable_grid_removed.grid': function(event) {
171
+ if (options.showIndex && grid.getItem().length > 0) {
172
+ $table.find('tbody tr:not(.' + detailClass + ')').each(function(index) {
173
+ var $td = $(this).find('td:first');
174
+ $td.html(options.indexFormatter(null, $td, index));
175
+ });
176
+ }
177
+ },
178
+ 'footable_redrawn.grid footable_row_removed.grid': function(event) {
179
+ if (grid.getItem().length === 0 && options.showEmptyInfo) {
180
+ makeEmptyInfo($table, options.cols, options.emptyInfo);
181
+ }
182
+ }
183
+ }).on({
184
+ 'click.grid': function(event) {
185
+ if ($(event.target).closest('td').find('>.' + toggleClass).size() > 0) {
186
+ return true;
187
+ }
188
+ var $tr = $(event.currentTarget);
189
+ if ($tr.hasClass(detailClass)) {
190
+ return true;
191
+ }
192
+ if (!options.multiSelect && !$tr.hasClass(options.activeClass)) {
193
+ $table.find('tbody tr.' + options.activeClass).removeClass(options.activeClass);
194
+ }
195
+ $tr.toggleClass(options.activeClass);
196
+ if (options.showCheckbox) {
197
+ $tr.find('input:checkbox.check').prop('checked', function(index, val) {
198
+ if (event.target === this) {
199
+ return val;
200
+ }
201
+ return !val;
202
+ });
203
+ }
204
+ ft.toggleDetail($tr);
205
+ }
206
+ }, 'tbody tr').on('click.grid', 'thead input:checkbox.checkAll', function(event) {
207
+ var checked = !! event.currentTarget.checked;
208
+ if (checked) {
209
+ $table.find('tbody tr').addClass(options.activeClass);
210
+ } else {
211
+ $table.find('tbody tr').removeClass(options.activeClass);
212
+ }
213
+ $table.find('tbody input:checkbox.check').prop('checked', checked);
214
+ });
215
+ };
216
+ /**
217
+ * get selected rows index;
218
+ */
219
+ grid.getSelected = function() {
220
+ var options = grid.footable.options.grid,
221
+ $selected = $(grid.footable.table).find('tbody>tr.' + options.activeClass);
222
+ return $selected.map(function() {
223
+ return $(this).data('index');
224
+ });
225
+ };
226
+ /**
227
+ * get row's data by index
228
+ */
229
+ grid.getItem = function(index) {
230
+ if (index !== undefined) {
231
+ if ($.isArray(index)) {
232
+ return $.map(index, function(item) {
233
+ return grid._items[item];
234
+ });
235
+ }
236
+ return grid._items[index];
237
+ }
238
+ return grid._items;
239
+ };
240
+
241
+ function makeCell(col, value, index) {
242
+ var $td = $('<td>');
243
+ if (col.formatter) {
244
+ $td.html(col.formatter(value, $td, index));
245
+ } else {
246
+ $td.html(value || '');
247
+ }
248
+ return $td;
249
+ }
250
+ grid._makeRow = function(item, index) {
251
+ var options = grid.footable.options.grid;
252
+ var $row;
253
+ if ($.isFunction(options.template)) {
254
+ $row = $(options.template($.extend({}, {
255
+ __index: index
256
+ }, item)));
257
+ } else {
258
+ $row = $('<tr>');
259
+ for (var i = 0, len = options.cols.length; i < len; i++) {
260
+ var col = options.cols[i];
261
+ $row.append(makeCell(col, item[col.name] || '', index));
262
+ }
263
+ }
264
+ $row.attr('data-index', index);
265
+ return $row;
266
+ };
267
+ /**
268
+ * create rows by js object
269
+ */
270
+ grid.newItem = function(item, index, wait) {
271
+ var $tbody = $(grid.footable.table).find('tbody');
272
+ var detailClass = grid.footable.options.classes.detail;
273
+ $tbody.find('tr.emptyInfo').remove();
274
+ if ($.isArray(item)) {
275
+ for (var atom;
276
+ (atom = item.pop());) {
277
+ grid.newItem(atom, index, true);
278
+ }
279
+ grid.footable.redraw();
280
+ grid.footable.raise(grid.footable.options.grid.events.created, {
281
+ item: item,
282
+ index: index
283
+ });
284
+ return;
285
+ }
286
+ if (!$.isPlainObject(item)) {
287
+ return;
288
+ }
289
+ var $tr, len = grid._items.length;
290
+ if (index === undefined || index < 0 || index > len) {
291
+ $tr = grid._makeRow(item, len++);
292
+ grid._items.push(item);
293
+ $tbody.append($tr);
294
+ } else {
295
+ $tr = grid._makeRow(item, index);
296
+ if (index === 0) {
297
+ grid._items.unshift(item);
298
+ $tbody.prepend($tr);
299
+ } else {
300
+ var $before = $tbody.find('tr[data-index=' + (index - 1) + ']');
301
+ grid._items.splice(index, 0, item);
302
+ if ($before.data('detail_created') === true) {
303
+ $before = $before.next();
304
+ }
305
+ $before.after($tr);
306
+ }
307
+ updateRowIndex($tbody, $tr, detailClass, 1);
308
+ }
309
+ if (!wait) {
310
+ grid.footable.redraw();
311
+ grid.footable.raise(grid.footable.options.grid.events.created, {
312
+ item: item,
313
+ index: index
314
+ });
315
+ }
316
+ };
317
+ /**
318
+ * update row by js object
319
+ */
320
+ grid.setItem = function(item, index) {
321
+ if (!$.isPlainObject(item)) {
322
+ return;
323
+ }
324
+ var $tbody = $(grid.footable.table).find('tbody'),
325
+ $newTr = grid._makeRow(item, index);
326
+ $.extend(grid._items[index], item);
327
+ var $tr = $tbody.find('tr').eq(index);
328
+ $tr.html($newTr.html());
329
+ grid.footable.redraw();
330
+ grid.footable.raise(grid.footable.options.grid.events.updated, {
331
+ item: item,
332
+ index: index
333
+ });
334
+ };
335
+ /**
336
+ * remove rows by index
337
+ */
338
+ grid.removeItem = function(index) {
339
+ var $tbody = $(grid.footable.table).find('tbody');
340
+ var detailClass = grid.footable.options.classes.detail;
341
+ var result = [];
342
+ if ($.isArray(index)) {
343
+ for (var i;
344
+ (i = index.pop());) {
345
+ result.push(grid.removeItem(i));
346
+ }
347
+ grid.footable.raise(grid.footable.options.grid.events.removed, {
348
+ item: result,
349
+ index: index
350
+ });
351
+ return result;
352
+ }
353
+ if (index === undefined) {
354
+ $tbody.find('tr').each(function() {
355
+ result.push(grid._items.shift());
356
+ grid.footable.removeRow(this);
357
+ });
358
+ } else {
359
+ var $tr = $tbody.find('tr[data-index=' + index + ']');
360
+ result = grid._items.splice(index, 1)[0];
361
+ grid.footable.removeRow($tr);
362
+ //update rows index
363
+ updateRowIndex($tbody, $tr, detailClass, -1);
364
+ }
365
+ grid.footable.raise(grid.footable.options.grid.events.removed, {
366
+ item: result,
367
+ index: index
368
+ });
369
+ return result;
370
+ };
371
+ }
372
+ w.footable.plugins.register(Grid, defaults);
373
+ })(jQuery, window);
@@ -0,0 +1,827 @@
1
+ /*!
2
+ * FooTable - Awesome Responsive Tables
3
+ * Version : 2.0.3
4
+ * http://fooplugins.com/plugins/footable-jquery/
5
+ *
6
+ * Requires jQuery - http://jquery.com/
7
+ *
8
+ * Copyright 2014 Steven Usher & Brad Vincent
9
+ * Released under the MIT license
10
+ * You are free to use FooTable in commercial projects as long as this copyright header is left intact.
11
+ *
12
+ * Date: 11 Nov 2014
13
+ */
14
+ (function ($, w, undefined) {
15
+ w.footable = {
16
+ options: {
17
+ delay: 100, // The number of millseconds to wait before triggering the react event
18
+ breakpoints: { // The different screen resolution breakpoints
19
+ phone: 480,
20
+ tablet: 1024
21
+ },
22
+ parsers: { // The default parser to parse the value out of a cell (values are used in building up row detail)
23
+ alpha: function (cell) {
24
+ return $(cell).data('value') || $.trim($(cell).text());
25
+ },
26
+ numeric: function (cell) {
27
+ var val = $(cell).data('value') || $(cell).text().replace(/[^0-9.\-]/g, '');
28
+ val = parseFloat(val);
29
+ if (isNaN(val)) val = 0;
30
+ return val;
31
+ }
32
+ },
33
+ addRowToggle: true,
34
+ calculateWidthOverride: null,
35
+ toggleSelector: ' > tbody > tr:not(.footable-row-detail)', //the selector to show/hide the detail row
36
+ columnDataSelector: '> thead > tr:last-child > th, > thead > tr:last-child > td', //the selector used to find the column data in the thead
37
+ detailSeparator: ':', //the separator character used when building up the detail row
38
+ toggleHTMLElement: '<span />', // override this if you want to insert a click target rather than use a background image.
39
+ createGroupedDetail: function (data) {
40
+ var groups = { '_none': { 'name': null, 'data': [] } };
41
+ for (var i = 0; i < data.length; i++) {
42
+ var groupid = data[i].group;
43
+ if (groupid !== null) {
44
+ if (!(groupid in groups))
45
+ groups[groupid] = { 'name': data[i].groupName || data[i].group, 'data': [] };
46
+
47
+ groups[groupid].data.push(data[i]);
48
+ } else {
49
+ groups._none.data.push(data[i]);
50
+ }
51
+ }
52
+ return groups;
53
+ },
54
+ createDetail: function (element, data, createGroupedDetail, separatorChar, classes) {
55
+ /// <summary>This function is used by FooTable to generate the detail view seen when expanding a collapsed row.</summary>
56
+ /// <param name="element">This is the div that contains all the detail row information, anything could be added to it.</param>
57
+ /// <param name="data">
58
+ /// This is an array of objects containing the cell information for the current row.
59
+ /// These objects look like the below:
60
+ /// obj = {
61
+ /// 'name': String, // The name of the column
62
+ /// 'value': Object, // The value parsed from the cell using the parsers. This could be a string, a number or whatever the parser outputs.
63
+ /// 'display': String, // This is the actual HTML from the cell, so if you have images etc you want moved this is the one to use and is the default value used.
64
+ /// 'group': String, // This is the identifier used in the data-group attribute of the column.
65
+ /// 'groupName': String // This is the actual name of the group the column belongs to.
66
+ /// }
67
+ /// </param>
68
+ /// <param name="createGroupedDetail">The grouping function to group the data</param>
69
+ /// <param name="separatorChar">The separator charactor used</param>
70
+ /// <param name="classes">The array of class names used to build up the detail row</param>
71
+
72
+ var groups = createGroupedDetail(data);
73
+ for (var group in groups) {
74
+ if (groups[group].data.length === 0) continue;
75
+ if (group !== '_none') element.append('<div class="' + classes.detailInnerGroup + '">' + groups[group].name + '</div>');
76
+
77
+ for (var j = 0; j < groups[group].data.length; j++) {
78
+ var separator = (groups[group].data[j].name) ? separatorChar : '';
79
+ element.append($('<div></div>').addClass(classes.detailInnerRow).append($('<div></div>').addClass(classes.detailInnerName)
80
+ .append(groups[group].data[j].name + separator)).append($('<div></div>').addClass(classes.detailInnerValue)
81
+ .attr('data-bind-value', groups[group].data[j].bindName).append(groups[group].data[j].display)));
82
+ }
83
+ }
84
+ },
85
+ classes: {
86
+ main: 'footable',
87
+ loading: 'footable-loading',
88
+ loaded: 'footable-loaded',
89
+ toggle: 'footable-toggle',
90
+ disabled: 'footable-disabled',
91
+ detail: 'footable-row-detail',
92
+ detailCell: 'footable-row-detail-cell',
93
+ detailInner: 'footable-row-detail-inner',
94
+ detailInnerRow: 'footable-row-detail-row',
95
+ detailInnerGroup: 'footable-row-detail-group',
96
+ detailInnerName: 'footable-row-detail-name',
97
+ detailInnerValue: 'footable-row-detail-value',
98
+ detailShow: 'footable-detail-show'
99
+ },
100
+ triggers: {
101
+ initialize: 'footable_initialize', //trigger this event to force FooTable to reinitialize
102
+ resize: 'footable_resize', //trigger this event to force FooTable to resize
103
+ redraw: 'footable_redraw', //trigger this event to force FooTable to redraw
104
+ toggleRow: 'footable_toggle_row', //trigger this event to force FooTable to toggle a row
105
+ expandFirstRow: 'footable_expand_first_row', //trigger this event to force FooTable to expand the first row
106
+ expandAll: 'footable_expand_all', //trigger this event to force FooTable to expand all rows
107
+ collapseAll: 'footable_collapse_all' //trigger this event to force FooTable to collapse all rows
108
+ },
109
+ events: {
110
+ alreadyInitialized: 'footable_already_initialized', //fires when the FooTable has already been initialized
111
+ initializing: 'footable_initializing', //fires before FooTable starts initializing
112
+ initialized: 'footable_initialized', //fires after FooTable has finished initializing
113
+ resizing: 'footable_resizing', //fires before FooTable resizes
114
+ resized: 'footable_resized', //fires after FooTable has resized
115
+ redrawn: 'footable_redrawn', //fires after FooTable has redrawn
116
+ breakpoint: 'footable_breakpoint', //fires inside the resize function, when a breakpoint is hit
117
+ columnData: 'footable_column_data', //fires when setting up column data. Plugins should use this event to capture their own info about a column
118
+ rowDetailUpdating: 'footable_row_detail_updating', //fires before a detail row is updated
119
+ rowDetailUpdated: 'footable_row_detail_updated', //fires when a detail row is being updated
120
+ rowCollapsed: 'footable_row_collapsed', //fires when a row is collapsed
121
+ rowExpanded: 'footable_row_expanded', //fires when a row is expanded
122
+ rowRemoved: 'footable_row_removed', //fires when a row is removed
123
+ reset: 'footable_reset' //fires when FooTable is reset
124
+ },
125
+ debug: false, // Whether or not to log information to the console.
126
+ log: null
127
+ },
128
+
129
+ version: {
130
+ major: 0, minor: 5,
131
+ toString: function () {
132
+ return w.footable.version.major + '.' + w.footable.version.minor;
133
+ },
134
+ parse: function (str) {
135
+ var version = /(\d+)\.?(\d+)?\.?(\d+)?/.exec(str);
136
+ return {
137
+ major: parseInt(version[1], 10) || 0,
138
+ minor: parseInt(version[2], 10) || 0,
139
+ patch: parseInt(version[3], 10) || 0
140
+ };
141
+ }
142
+ },
143
+
144
+ plugins: {
145
+ _validate: function (plugin) {
146
+ ///<summary>Simple validation of the <paramref name="plugin"/> to make sure any members called by FooTable actually exist.</summary>
147
+ ///<param name="plugin">The object defining the plugin, this should implement a string property called "name" and a function called "init".</param>
148
+
149
+ if (!$.isFunction(plugin)) {
150
+ if (w.footable.options.debug === true) console.error('Validation failed, expected type "function", received type "{0}".', typeof plugin);
151
+ return false;
152
+ }
153
+ var p = new plugin();
154
+ if (typeof p['name'] !== 'string') {
155
+ if (w.footable.options.debug === true) console.error('Validation failed, plugin does not implement a string property called "name".', p);
156
+ return false;
157
+ }
158
+ if (!$.isFunction(p['init'])) {
159
+ if (w.footable.options.debug === true) console.error('Validation failed, plugin "' + p['name'] + '" does not implement a function called "init".', p);
160
+ return false;
161
+ }
162
+ if (w.footable.options.debug === true) console.log('Validation succeeded for plugin "' + p['name'] + '".', p);
163
+ return true;
164
+ },
165
+ registered: [], // An array containing all registered plugins.
166
+ register: function (plugin, options) {
167
+ ///<summary>Registers a <paramref name="plugin"/> and its default <paramref name="options"/> with FooTable.</summary>
168
+ ///<param name="plugin">The plugin that should implement a string property called "name" and a function called "init".</param>
169
+ ///<param name="options">The default options to merge with the FooTable's base options.</param>
170
+
171
+ if (w.footable.plugins._validate(plugin)) {
172
+ w.footable.plugins.registered.push(plugin);
173
+ if (typeof options === 'object') $.extend(true, w.footable.options, options);
174
+ }
175
+ },
176
+ load: function(instance){
177
+ var loaded = [], registered, i;
178
+ for(i = 0; i < w.footable.plugins.registered.length; i++){
179
+ try {
180
+ registered = w.footable.plugins.registered[i];
181
+ loaded.push(new registered(instance));
182
+ } catch (err) {
183
+ if (w.footable.options.debug === true) console.error(err);
184
+ }
185
+ }
186
+ return loaded;
187
+ },
188
+ init: function (instance) {
189
+ ///<summary>Loops through all registered plugins and calls the "init" method supplying the current <paramref name="instance"/> of the FooTable as the first parameter.</summary>
190
+ ///<param name="instance">The current instance of the FooTable that the plugin is being initialized for.</param>
191
+
192
+ for (var i = 0; i < instance.plugins.length; i++) {
193
+ try {
194
+ instance.plugins[i]['init'](instance);
195
+ } catch (err) {
196
+ if (w.footable.options.debug === true) console.error(err);
197
+ }
198
+ }
199
+ }
200
+ }
201
+ };
202
+
203
+ var instanceCount = 0;
204
+
205
+ $.fn.footable = function (options) {
206
+ ///<summary>The main constructor call to initialize the plugin using the supplied <paramref name="options"/>.</summary>
207
+ ///<param name="options">
208
+ ///<para>A JSON object containing user defined options for the plugin to use. Any options not supplied will have a default value assigned.</para>
209
+ ///<para>Check the documentation or the default options object above for more information on available options.</para>
210
+ ///</param>
211
+
212
+ options = options || {};
213
+ if (options.breakpoints) { // clear the default breakpoints if the user specifies one
214
+ w.footable.options.breakpoints = {};
215
+ }
216
+ var o = $.extend(true, {}, w.footable.options, options); //merge user and default options
217
+ return this.each(function () {
218
+ instanceCount++;
219
+ var footable = new Footable(this, o, instanceCount);
220
+ $(this).data('footable', footable);
221
+ });
222
+ };
223
+
224
+ //helper for using timeouts
225
+ function Timer() {
226
+ ///<summary>Simple timer object created around a timeout.</summary>
227
+ var t = this;
228
+ t.id = null;
229
+ t.busy = false;
230
+ t.start = function (code, milliseconds) {
231
+ ///<summary>Starts the timer and waits the specified amount of <paramref name="milliseconds"/> before executing the supplied <paramref name="code"/>.</summary>
232
+ ///<param name="code">The code to execute once the timer runs out.</param>
233
+ ///<param name="milliseconds">The time in milliseconds to wait before executing the supplied <paramref name="code"/>.</param>
234
+
235
+ if (t.busy) {
236
+ return;
237
+ }
238
+ t.stop();
239
+ t.id = setTimeout(function () {
240
+ code();
241
+ t.id = null;
242
+ t.busy = false;
243
+ }, milliseconds);
244
+ t.busy = true;
245
+ };
246
+ t.stop = function () {
247
+ ///<summary>Stops the timer if its runnning and resets it back to its starting state.</summary>
248
+
249
+ if (t.id !== null) {
250
+ clearTimeout(t.id);
251
+ t.id = null;
252
+ t.busy = false;
253
+ }
254
+ };
255
+ }
256
+
257
+ function Footable(t, o, id) {
258
+ ///<summary>Inits a new instance of the plugin.</summary>
259
+ ///<param name="t">The main table element to apply this plugin to.</param>
260
+ ///<param name="o">The options supplied to the plugin. Check the defaults object to see all available options.</param>
261
+ ///<param name="id">The id to assign to this instance of the plugin.</param>
262
+
263
+ var ft = this;
264
+ ft.id = id;
265
+ ft.table = t;
266
+ ft.options = o;
267
+ ft.breakpoints = [];
268
+ ft.breakpointNames = '';
269
+ ft.columns = {};
270
+ ft.plugins = w.footable.plugins.load(ft);
271
+
272
+ var opt = ft.options,
273
+ cls = opt.classes,
274
+ evt = opt.events,
275
+ trg = opt.triggers,
276
+ indexOffset = 0;
277
+
278
+ // This object simply houses all the timers used in the FooTable.
279
+ ft.timers = {
280
+ resize: new Timer(),
281
+ register: function (name) {
282
+ ft.timers[name] = new Timer();
283
+ return ft.timers[name];
284
+ }
285
+ };
286
+
287
+ ft.init = function () {
288
+ var $window = $(w), $table = $(ft.table);
289
+
290
+ w.footable.plugins.init(ft);
291
+
292
+ if ($table.hasClass(cls.loaded)) {
293
+ //already loaded FooTable for the table, so don't init again
294
+ ft.raise(evt.alreadyInitialized);
295
+ return;
296
+ }
297
+
298
+ //raise the initializing event
299
+ ft.raise(evt.initializing);
300
+
301
+ $table.addClass(cls.loading);
302
+
303
+ // Get the column data once for the life time of the plugin
304
+ $table.find(opt.columnDataSelector).each(function () {
305
+ var data = ft.getColumnData(this);
306
+ ft.columns[data.index] = data;
307
+ });
308
+
309
+ // Create a nice friendly array to work with out of the breakpoints object.
310
+ for (var name in opt.breakpoints) {
311
+ ft.breakpoints.push({ 'name': name, 'width': opt.breakpoints[name] });
312
+ ft.breakpointNames += (name + ' ');
313
+ }
314
+
315
+ // Sort the breakpoints so the smallest is checked first
316
+ ft.breakpoints.sort(function (a, b) {
317
+ return a['width'] - b['width'];
318
+ });
319
+
320
+ $table
321
+ .unbind(trg.initialize)
322
+ //bind to FooTable initialize trigger
323
+ .bind(trg.initialize, function () {
324
+ //remove previous "state" (to "force" a resize)
325
+ $table.removeData('footable_info');
326
+ $table.data('breakpoint', '');
327
+
328
+ //trigger the FooTable resize
329
+ $table.trigger(trg.resize);
330
+
331
+ //remove the loading class
332
+ $table.removeClass(cls.loading);
333
+
334
+ //add the FooTable and loaded class
335
+ $table.addClass(cls.loaded).addClass(cls.main);
336
+
337
+ //raise the initialized event
338
+ ft.raise(evt.initialized);
339
+ })
340
+ .unbind(trg.redraw)
341
+ //bind to FooTable redraw trigger
342
+ .bind(trg.redraw, function () {
343
+ ft.redraw();
344
+ })
345
+ .unbind(trg.resize)
346
+ //bind to FooTable resize trigger
347
+ .bind(trg.resize, function () {
348
+ ft.resize();
349
+ })
350
+ .unbind(trg.expandFirstRow)
351
+ //bind to FooTable expandFirstRow trigger
352
+ .bind(trg.expandFirstRow, function () {
353
+ $table.find(opt.toggleSelector).first().not('.' + cls.detailShow).trigger(trg.toggleRow);
354
+ })
355
+ .unbind(trg.expandAll)
356
+ //bind to FooTable expandFirstRow trigger
357
+ .bind(trg.expandAll, function () {
358
+ $table.find(opt.toggleSelector).not('.' + cls.detailShow).trigger(trg.toggleRow);
359
+ })
360
+ .unbind(trg.collapseAll)
361
+ //bind to FooTable expandFirstRow trigger
362
+ .bind(trg.collapseAll, function () {
363
+ $table.find('.' + cls.detailShow).trigger(trg.toggleRow);
364
+ });
365
+
366
+ //trigger a FooTable initialize
367
+ $table.trigger(trg.initialize);
368
+
369
+ //bind to window resize
370
+ $window
371
+ .bind('resize.footable', function () {
372
+ ft.timers.resize.stop();
373
+ ft.timers.resize.start(function () {
374
+ ft.raise(trg.resize);
375
+ }, opt.delay);
376
+ });
377
+ };
378
+
379
+ ft.addRowToggle = function () {
380
+ if (!opt.addRowToggle) return;
381
+
382
+ var $table = $(ft.table),
383
+ hasToggleColumn = false;
384
+
385
+ //first remove all toggle spans
386
+ $table.find('span.' + cls.toggle).remove();
387
+
388
+ for (var c in ft.columns) {
389
+ var col = ft.columns[c];
390
+ if (col.toggle) {
391
+ hasToggleColumn = true;
392
+ var selector = '> tbody > tr:not(.' + cls.detail + ',.' + cls.disabled + ') > td:nth-child(' + (parseInt(col.index, 10) + 1) + '),' +
393
+ '> tbody > tr:not(.' + cls.detail + ',.' + cls.disabled + ') > th:nth-child(' + (parseInt(col.index, 10) + 1) + ')';
394
+ $table.find(selector).not('.' + cls.detailCell).prepend($(opt.toggleHTMLElement).addClass(cls.toggle));
395
+ return;
396
+ }
397
+ }
398
+ //check if we have an toggle column. If not then add it to the first column just to be safe
399
+ if (!hasToggleColumn) {
400
+ $table
401
+ .find('> tbody > tr:not(.' + cls.detail + ',.' + cls.disabled + ') > td:first-child')
402
+ .add('> tbody > tr:not(.' + cls.detail + ',.' + cls.disabled + ') > th:first-child')
403
+ .not('.' + cls.detailCell)
404
+ .prepend($(opt.toggleHTMLElement).addClass(cls.toggle));
405
+ }
406
+ };
407
+
408
+ ft.setColumnClasses = function () {
409
+ var $table = $(ft.table);
410
+ for (var c in ft.columns) {
411
+ var col = ft.columns[c];
412
+ if (col.className !== null) {
413
+ var selector = '', first = true;
414
+ $.each(col.matches, function (m, match) { //support for colspans
415
+ if (!first) selector += ', ';
416
+ selector += '> tbody > tr:not(.' + cls.detail + ') > td:nth-child(' + (parseInt(match, 10) + 1) + ')';
417
+ first = false;
418
+ });
419
+ //add the className to the cells specified by data-class="blah"
420
+ $table.find(selector).not('.' + cls.detailCell).addClass(col.className);
421
+ }
422
+ }
423
+ };
424
+
425
+ //moved this out into it's own function so that it can be called from other add-ons
426
+ ft.bindToggleSelectors = function () {
427
+ var $table = $(ft.table);
428
+
429
+ if (!ft.hasAnyBreakpointColumn()) return;
430
+
431
+ $table.find(opt.toggleSelector).unbind(trg.toggleRow).bind(trg.toggleRow, function (e) {
432
+ var $row = $(this).is('tr') ? $(this) : $(this).parents('tr:first');
433
+ ft.toggleDetail($row);
434
+ });
435
+
436
+ $table.find(opt.toggleSelector).unbind('click.footable').bind('click.footable', function (e) {
437
+ if ($table.is('.breakpoint') && $(e.target).is('td,th,.'+ cls.toggle)) {
438
+ $(this).trigger(trg.toggleRow);
439
+ }
440
+ });
441
+ };
442
+
443
+ ft.parse = function (cell, column) {
444
+ var parser = opt.parsers[column.type] || opt.parsers.alpha;
445
+ return parser(cell);
446
+ };
447
+
448
+ ft.getColumnData = function (th) {
449
+ var $th = $(th), hide = $th.data('hide'), index = $th.index();
450
+ hide = hide || '';
451
+ hide = jQuery.map(hide.split(','), function (a) {
452
+ return jQuery.trim(a);
453
+ });
454
+ var data = {
455
+ 'index': index,
456
+ 'hide': { },
457
+ 'type': $th.data('type') || 'alpha',
458
+ 'name': $th.data('name') || $.trim($th.text()),
459
+ 'ignore': $th.data('ignore') || false,
460
+ 'toggle': $th.data('toggle') || false,
461
+ 'className': $th.data('class') || null,
462
+ 'matches': [],
463
+ 'names': { },
464
+ 'group': $th.data('group') || null,
465
+ 'groupName': null,
466
+ 'isEditable': $th.data('editable')
467
+ };
468
+
469
+ if (data.group !== null) {
470
+ var $group = $(ft.table).find('> thead > tr.footable-group-row > th[data-group="' + data.group + '"], > thead > tr.footable-group-row > td[data-group="' + data.group + '"]').first();
471
+ data.groupName = ft.parse($group, { 'type': 'alpha' });
472
+ }
473
+
474
+ var pcolspan = parseInt($th.prev().attr('colspan') || 0, 10);
475
+ indexOffset += pcolspan > 1 ? pcolspan - 1 : 0;
476
+ var colspan = parseInt($th.attr('colspan') || 0, 10), curindex = data.index + indexOffset;
477
+ if (colspan > 1) {
478
+ var names = $th.data('names');
479
+ names = names || '';
480
+ names = names.split(',');
481
+ for (var i = 0; i < colspan; i++) {
482
+ data.matches.push(i + curindex);
483
+ if (i < names.length) data.names[i + curindex] = names[i];
484
+ }
485
+ } else {
486
+ data.matches.push(curindex);
487
+ }
488
+
489
+ data.hide['default'] = ($th.data('hide') === "all") || ($.inArray('default', hide) >= 0);
490
+
491
+ var hasBreakpoint = false;
492
+ for (var name in opt.breakpoints) {
493
+ data.hide[name] = ($th.data('hide') === "all") || ($.inArray(name, hide) >= 0);
494
+ hasBreakpoint = hasBreakpoint || data.hide[name];
495
+ }
496
+ data.hasBreakpoint = hasBreakpoint;
497
+ var e = ft.raise(evt.columnData, { 'column': { 'data': data, 'th': th } });
498
+ return e.column.data;
499
+ };
500
+
501
+ ft.getViewportWidth = function () {
502
+ return window.innerWidth || (document.body ? document.body.offsetWidth : 0);
503
+ };
504
+
505
+ ft.calculateWidth = function ($table, info) {
506
+ if (jQuery.isFunction(opt.calculateWidthOverride)) {
507
+ return opt.calculateWidthOverride($table, info);
508
+ }
509
+ if (info.viewportWidth < info.width) info.width = info.viewportWidth;
510
+ if (info.parentWidth < info.width) info.width = info.parentWidth;
511
+ return info;
512
+ };
513
+
514
+ ft.hasBreakpointColumn = function (breakpoint) {
515
+ for (var c in ft.columns) {
516
+ if (ft.columns[c].hide[breakpoint]) {
517
+ if (ft.columns[c].ignore) {
518
+ continue;
519
+ }
520
+ return true;
521
+ }
522
+ }
523
+ return false;
524
+ };
525
+
526
+ ft.hasAnyBreakpointColumn = function () {
527
+ for (var c in ft.columns) {
528
+ if (ft.columns[c].hasBreakpoint) {
529
+ return true;
530
+ }
531
+ }
532
+ return false;
533
+ };
534
+
535
+ ft.resize = function () {
536
+ var $table = $(ft.table);
537
+
538
+ if (!$table.is(':visible')) {
539
+ return;
540
+ } //we only care about FooTables that are visible
541
+
542
+ if (!ft.hasAnyBreakpointColumn()) {
543
+ $table.trigger(trg.redraw);
544
+ return;
545
+ } //we only care about FooTables that have breakpoints
546
+
547
+ var info = {
548
+ 'width': $table.width(), //the table width
549
+ 'viewportWidth': ft.getViewportWidth(), //the width of the viewport
550
+ 'parentWidth': $table.parent().width() //the width of the parent
551
+ };
552
+
553
+ info = ft.calculateWidth($table, info);
554
+
555
+ var pinfo = $table.data('footable_info');
556
+ $table.data('footable_info', info);
557
+ ft.raise(evt.resizing, { 'old': pinfo, 'info': info });
558
+
559
+ // This (if) statement is here purely to make sure events aren't raised twice as mobile safari seems to do
560
+ if (!pinfo || (pinfo && pinfo.width && pinfo.width !== info.width)) {
561
+
562
+ var current = null, breakpoint;
563
+ for (var i = 0; i < ft.breakpoints.length; i++) {
564
+ breakpoint = ft.breakpoints[i];
565
+ if (breakpoint && breakpoint.width && info.width <= breakpoint.width) {
566
+ current = breakpoint;
567
+ break;
568
+ }
569
+ }
570
+
571
+ var breakpointName = (current === null ? 'default' : current['name']),
572
+ hasBreakpointFired = ft.hasBreakpointColumn(breakpointName),
573
+ previousBreakpoint = $table.data('breakpoint');
574
+
575
+ $table
576
+ .data('breakpoint', breakpointName)
577
+ .removeClass('default breakpoint').removeClass(ft.breakpointNames)
578
+ .addClass(breakpointName + (hasBreakpointFired ? ' breakpoint' : ''));
579
+
580
+ //only do something if the breakpoint has changed
581
+ if (breakpointName !== previousBreakpoint) {
582
+ //trigger a redraw
583
+ $table.trigger(trg.redraw);
584
+ //raise a breakpoint event
585
+ ft.raise(evt.breakpoint, { 'breakpoint': breakpointName, 'info': info });
586
+ }
587
+ }
588
+
589
+ ft.raise(evt.resized, { 'old': pinfo, 'info': info });
590
+ };
591
+
592
+ ft.redraw = function () {
593
+ //add the toggler to each row
594
+ ft.addRowToggle();
595
+
596
+ //bind the toggle selector click events
597
+ ft.bindToggleSelectors();
598
+
599
+ //set any cell classes defined for the columns
600
+ ft.setColumnClasses();
601
+
602
+ var $table = $(ft.table),
603
+ breakpointName = $table.data('breakpoint'),
604
+ hasBreakpointFired = ft.hasBreakpointColumn(breakpointName);
605
+
606
+ $table
607
+ .find('> tbody > tr:not(.' + cls.detail + ')').data('detail_created', false).end()
608
+ .find('> thead > tr:last-child > th')
609
+ .each(function () {
610
+ var data = ft.columns[$(this).index()], selector = '', first = true;
611
+ $.each(data.matches, function (m, match) {
612
+ if (!first) {
613
+ selector += ', ';
614
+ }
615
+ var count = match + 1;
616
+ selector += '> tbody > tr:not(.' + cls.detail + ') > td:nth-child(' + count + ')';
617
+ selector += ', > tfoot > tr:not(.' + cls.detail + ') > td:nth-child(' + count + ')';
618
+ selector += ', > colgroup > col:nth-child(' + count + ')';
619
+ first = false;
620
+ });
621
+
622
+ selector += ', > thead > tr[data-group-row="true"] > th[data-group="' + data.group + '"]';
623
+ var $column = $table.find(selector).add(this);
624
+ if (breakpointName !== '') {
625
+ if (data.hide[breakpointName] === false) $column.addClass('footable-visible').show();
626
+ else $column.removeClass('footable-visible').hide();
627
+ }
628
+
629
+ if ($table.find('> thead > tr.footable-group-row').length === 1) {
630
+ var $groupcols = $table.find('> thead > tr:last-child > th[data-group="' + data.group + '"]:visible, > thead > tr:last-child > th[data-group="' + data.group + '"]:visible'),
631
+ $group = $table.find('> thead > tr.footable-group-row > th[data-group="' + data.group + '"], > thead > tr.footable-group-row > td[data-group="' + data.group + '"]'),
632
+ groupspan = 0;
633
+
634
+ $.each($groupcols, function () {
635
+ groupspan += parseInt($(this).attr('colspan') || 1, 10);
636
+ });
637
+
638
+ if (groupspan > 0) $group.attr('colspan', groupspan).show();
639
+ else $group.hide();
640
+ }
641
+ })
642
+ .end()
643
+ .find('> tbody > tr.' + cls.detailShow).each(function () {
644
+ ft.createOrUpdateDetailRow(this);
645
+ });
646
+
647
+ $table.find("[data-bind-name]").each(function () {
648
+ ft.toggleInput(this);
649
+ });
650
+
651
+ $table.find('> tbody > tr.' + cls.detailShow + ':visible').each(function () {
652
+ var $next = $(this).next();
653
+ if ($next.hasClass(cls.detail)) {
654
+ if (!hasBreakpointFired) $next.hide();
655
+ else $next.show();
656
+ }
657
+ });
658
+
659
+ // adding .footable-first-column and .footable-last-column to the first and last th and td of each row in order to allow
660
+ // for styling if the first or last column is hidden (which won't work using :first-child or :last-child)
661
+ $table.find('> thead > tr > th.footable-last-column, > tbody > tr > td.footable-last-column').removeClass('footable-last-column');
662
+ $table.find('> thead > tr > th.footable-first-column, > tbody > tr > td.footable-first-column').removeClass('footable-first-column');
663
+ $table.find('> thead > tr, > tbody > tr')
664
+ .find('> th.footable-visible:last, > td.footable-visible:last')
665
+ .addClass('footable-last-column')
666
+ .end()
667
+ .find('> th.footable-visible:first, > td.footable-visible:first')
668
+ .addClass('footable-first-column');
669
+
670
+ ft.raise(evt.redrawn);
671
+ };
672
+
673
+ ft.toggleDetail = function (row) {
674
+ var $row = (row.jquery) ? row : $(row),
675
+ $next = $row.next();
676
+
677
+ //check if the row is already expanded
678
+ if ($row.hasClass(cls.detailShow)) {
679
+ $row.removeClass(cls.detailShow);
680
+
681
+ //only hide the next row if it's a detail row
682
+ if ($next.hasClass(cls.detail)) $next.hide();
683
+
684
+ ft.raise(evt.rowCollapsed, { 'row': $row[0] });
685
+
686
+ } else {
687
+ ft.createOrUpdateDetailRow($row[0]);
688
+ $row.addClass(cls.detailShow)
689
+ .next().show();
690
+
691
+ ft.raise(evt.rowExpanded, { 'row': $row[0] });
692
+ }
693
+ };
694
+
695
+ ft.removeRow = function (row) {
696
+ var $row = (row.jquery) ? row : $(row);
697
+ if ($row.hasClass(cls.detail)) {
698
+ $row = $row.prev();
699
+ }
700
+ var $next = $row.next();
701
+ if ($row.data('detail_created') === true) {
702
+ //remove the detail row
703
+ $next.remove();
704
+ }
705
+ $row.remove();
706
+
707
+ //raise event
708
+ ft.raise(evt.rowRemoved);
709
+ };
710
+
711
+ ft.appendRow = function (row) {
712
+ var $row = (row.jquery) ? row : $(row);
713
+ $(ft.table).find('tbody').append($row);
714
+
715
+ //redraw the table
716
+ ft.redraw();
717
+ };
718
+
719
+ ft.getColumnFromTdIndex = function (index) {
720
+ /// <summary>Returns the correct column data for the supplied index taking into account colspans.</summary>
721
+ /// <param name="index">The index to retrieve the column data for.</param>
722
+ /// <returns type="json">A JSON object containing the column data for the supplied index.</returns>
723
+ var result = null;
724
+ for (var column in ft.columns) {
725
+ if ($.inArray(index, ft.columns[column].matches) >= 0) {
726
+ result = ft.columns[column];
727
+ break;
728
+ }
729
+ }
730
+ return result;
731
+ };
732
+
733
+ ft.createOrUpdateDetailRow = function (actualRow) {
734
+ var $row = $(actualRow), $next = $row.next(), $detail, values = [];
735
+ if ($row.data('detail_created') === true) return true;
736
+
737
+ if ($row.is(':hidden')) return false; //if the row is hidden for some reason (perhaps filtered) then get out of here
738
+ ft.raise(evt.rowDetailUpdating, { 'row': $row, 'detail': $next });
739
+ $row.find('> td:hidden').each(function () {
740
+ var index = $(this).index(), column = ft.getColumnFromTdIndex(index), name = column.name;
741
+ if (column.ignore === true) return true;
742
+
743
+ if (index in column.names) name = column.names[index];
744
+
745
+ var bindName = $(this).attr("data-bind-name");
746
+ if (bindName != null && $(this).is(':empty')) {
747
+ var bindValue = $('.' + cls.detailInnerValue + '[' + 'data-bind-value="' + bindName + '"]');
748
+ $(this).html($(bindValue).contents().detach());
749
+ }
750
+ var display;
751
+ if (column.isEditable !== false && (column.isEditable || $(this).find(":input").length > 0)) {
752
+ if(bindName == null) {
753
+ bindName = "bind-" + $.now() + "-" + index;
754
+ $(this).attr("data-bind-name", bindName);
755
+ }
756
+ display = $(this).contents().detach();
757
+ }
758
+ if (!display) display = $(this).contents().clone(true, true);
759
+ values.push({ 'name': name, 'value': ft.parse(this, column), 'display': display, 'group': column.group, 'groupName': column.groupName, 'bindName': bindName });
760
+ return true;
761
+ });
762
+ if (values.length === 0) return false; //return if we don't have any data to show
763
+ var colspan = $row.find('> td:visible').length;
764
+ var exists = $next.hasClass(cls.detail);
765
+ if (!exists) { // Create
766
+ $next = $('<tr class="' + cls.detail + '"><td class="' + cls.detailCell + '"><div class="' + cls.detailInner + '"></div></td></tr>');
767
+ $row.after($next);
768
+ }
769
+ $next.find('> td:first').attr('colspan', colspan);
770
+ $detail = $next.find('.' + cls.detailInner).empty();
771
+ opt.createDetail($detail, values, opt.createGroupedDetail, opt.detailSeparator, cls);
772
+ $row.data('detail_created', true);
773
+ ft.raise(evt.rowDetailUpdated, { 'row': $row, 'detail': $next });
774
+ return !exists;
775
+ };
776
+
777
+ ft.raise = function (eventName, args) {
778
+
779
+ if (ft.options.debug === true && $.isFunction(ft.options.log)) ft.options.log(eventName, 'event');
780
+
781
+ args = args || { };
782
+ var def = { 'ft': ft };
783
+ $.extend(true, def, args);
784
+ var e = $.Event(eventName, def);
785
+ if (!e.ft) {
786
+ $.extend(true, e, def);
787
+ } //pre jQuery 1.6 which did not allow data to be passed to event object constructor
788
+ $(ft.table).trigger(e);
789
+ return e;
790
+ };
791
+
792
+ //reset the state of FooTable
793
+ ft.reset = function() {
794
+ var $table = $(ft.table);
795
+ $table.removeData('footable_info')
796
+ .data('breakpoint', '')
797
+ .removeClass(cls.loading)
798
+ .removeClass(cls.loaded);
799
+
800
+ $table.find(opt.toggleSelector).unbind(trg.toggleRow).unbind('click.footable');
801
+
802
+ $table.find('> tbody > tr').removeClass(cls.detailShow);
803
+
804
+ $table.find('> tbody > tr.' + cls.detail).remove();
805
+
806
+ ft.raise(evt.reset);
807
+ };
808
+
809
+ //Switch between row-detail and detail-show.
810
+ ft.toggleInput = function (column) {
811
+ var bindName = $(column).attr("data-bind-name");
812
+ if(bindName != null) {
813
+ var bindValue = $('.' + cls.detailInnerValue + '[' + 'data-bind-value="' + bindName + '"]');
814
+ if(bindValue != null) {
815
+ if($(column).is(":visible")) {
816
+ if(!$(bindValue).is(':empty')) $(column).html($(bindValue).contents().detach());
817
+ } else if(!$(column).is(':empty')) {
818
+ $(bindValue).html($(column).contents().detach());
819
+ }
820
+ }
821
+ }
822
+ };
823
+
824
+ ft.init();
825
+ return ft;
826
+ }
827
+ })(jQuery, window);