forked from fheider/cakephp-datatables
-
Notifications
You must be signed in to change notification settings - Fork 24
/
cakephp.dataTables.js
258 lines (231 loc) · 8.75 KB
/
cakephp.dataTables.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
"use strict";
var dt = dt || {}; // initialize namespace
dt.init = dt.init || {}; // namespace for initializers
dt.render = dt.render || {}; // namespace for renderers
dt.initDataTables = function (id, options) {
/* Use text renderer by default. Escapes HTML. */
$.each(options.columns, function (i, val) {
if (!val.render) {
options.columns[i].render = $.fn.dataTable.render.text();
}
});
/* call requested initializer methods */
if (typeof(options.init) !== 'undefined') {
var initializers = options.init;
delete options.init;
$(id).on('preInit.dt', function () {
var table = $(id).dataTable(); // table jQuery object
for (var i = 0; i < initializers.length; i++) {
initializers[i](table);
}
});
}
/* create new instance */
$(id).dataTable(options);
};
/**
* Delay search trigger for DataTables input field
* @param table dataTables object
* @param minSearchCharacters minimum of characters necessary to trigger search
* @param delay milliseconds to delay search to prevent premature searches while typing
* @param selector optional, custom jQuery selector for an external search field
*/
dt.init.delayedSearch = function (table, minSearchCharacters, delay, selector) {
/* code taken from http://stackoverflow.com/a/23897722/21974 */
// Grab given or datatables input box and alter how it is bound to events
selector = selector || '#' + table.attr('id') + '_filter input';
minSearchCharacters = minSearchCharacters || 3;
delay = delay || 200;
var timer = null;
var trigger = function (value) {
table.api().search(value).draw();
};
$(selector)
.off() // Unbind previous default bindings
.on('input', function (e) { // Bind for field changes
// If enough characters, or search cleared with backspace
if (this.value.length >= minSearchCharacters || !this.value) {
window.clearTimeout(timer);
timer = window.setTimeout(trigger, delay, this.value);
}
})
.on('keydown', function (e) { // Bind for key presses
if (e.keyCode === 13) { // Enter key
window.clearTimeout(timer);
trigger(this.value);
}
});
};
/**
* Let an element change trigger a search (e.g. a custom input box)
* @param table dataTables object
* @param sender jQuery selector for the sending object
*/
dt.init.searchTrigger = function (table, sender)
{
$(document).on('change', sender, function () {
var value = table.api().search();
if (!value) // no search results displayed, need no update
return;
table.api().search(value).draw();
});
};
/**
* Add clickable behavior to table rows
* Builds upon datatables-select. As soon as a row is selected, the link fires.
* The URL is appended with the id field of the row data.
* @param table dataTables object
* @param urlbase target URL base (e.g. controller + action link)
* @param target optional: call $(target).load instead of href redirect
*/
dt.init.rowLinks = function (table, urlbase, target) {
table.api().on('select', function (e, dt, type, indexes) {
var row = table.api().rows(indexes);
var rowData = row.data();
var id = rowData[0].id;
var url = urlbase + '/' + id;
if (typeof target !== 'undefined') {
$(target).load(url);
} else {
window.location.href = url;
}
table.api().rows(indexes).deselect(); // revert selection
});
};
/**
* Add search behavior to all search fields in column footer
* @param delay Delay in ms before starting request
*/
dt.init.columnSearch = function (table, delay) {
table.api().columns().every(function () {
var index = this.index();
var lastValue = ''; // closure variable to prevent redundant AJAX calls
var timer = null; // Timer instance for delayed fetch
$('input, select', this.footer()).on('keyup change', function () {
if (this.value !== lastValue) {
lastValue = this.value;
// -- set search
table.api().column(index).search(this.value);
window.clearTimeout(timer);
timer = window.setTimeout(table.api().draw, delay);
}
});
});
};
/**
* Resize table to perfectly fit into (remainder of) window
* This works best if you set 'scrollY' to your minimum desired height
* If you do not want to use scrollY, use a fixed height on the table element
* Body margin is considered for fixed footer, body padding for fixed header
* This installs a listener for 'fullscreenToggle' on the table
* @param table dataTables object
* @param offset Offset to subtract from calculated optimal height (fine-tuning)
* @param fullscreen true to fit into whole window height (default: remaining)
*/
dt.init.fitIntoWindow = function (table, offset, fullscreen) {
var wrapper = $(table.api().table().container());
var body = wrapper.find('.dataTables_scrollBody');
if (body.length === 0) // neither scrollX / scrollY used
body = table;
// use initial height as minimum height
var minHeight = body.outerHeight();
// store fullscreen state in table
table.data('fullscreen', fullscreen);
table.on('fitIntoWindow', function () {
var bodyTag = $('body');
var total = window.innerHeight;
if (table.data('fullscreen') || (wrapper.offset().top + minHeight > total)) {
/* fit table in window minus body padding (fixed header) */
total -= bodyTag.outerHeight(false) - bodyTag.height();
} else {
/* fit table between previous content and footer (body margin) */
total -= wrapper.offset().top;
total -= bodyTag.outerHeight(true) - bodyTag.outerHeight(false);
}
/* take table decorations (e.g. info, filter elements) into account */
var self = wrapper.outerHeight(true) - body.outerHeight(false);
/* check if height changed (e.g. not on only horizontal resize) */
var height = total - self - offset;
if (body.height() === height)
return;
/* set height and propagate change */
body.css('height', height + "px");
var api = table.api();
if (typeof(api.scroller) !== 'undefined') {
api.scroller.measure(false);
}
/* note: we do not redraw as it leads to several problems. */
});
// initial call
table.trigger('fitIntoWindow');
// call on window resize
var resizeTimer;
$(window).on('resize', function (e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function () { table.trigger('fitIntoWindow') }, 250);
});
// allow toggling fullscreen mode
table.on('toggleFullscreen', function () {
table.data('fullscreen', !table.data('fullscreen'));
table.trigger('fitIntoWindow');
});
};
/**
* Render a date as localized string
* @param data The data for the cell (based on columns.data)
* @param type 'filter', 'display', 'type' or 'sort'
* @param full The full data source for the row
* @param meta Object containing additional information about the cell
* @returns Manipulated cell data
*/
dt.render.date = function (data, type, full, meta)
{
if (type === 'display') {
var date = new Date(data);
return date.toLocaleDateString(document.documentElement.lang);
}
return data;
};
/**
* Append an element property to the data send to server in a datatables request
* @param data The data object sent to the server
* @param settings DataTables settings object
* @param target Name of the object property to set
* @param source Source for target value: { selector, property, default }
* @returns The manipulated data object with new property
*/
dt.appendProperty = function (data, settings, target, source)
{
var value = $(source.selector).prop(source.property);
data[target] = (typeof(value) === 'undefined' ? source.default : value);
return data;
};
/**
* Escapes HTML characters
* Inspired by dataTable.render.text()
* Should be used in all render functions!
*/
dt.h = function (d)
{
return typeof d === 'string' ?
d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') :
d;
};
/**
* Function reset
*
*/
dt.resetColumnSearch = function (table) {
var needRedraw = false; // redraw when a filter is dis-applied
table.api().columns().every(function () {
// always clean up
$(this.footer()).children('input, select').val('');
if (!this.search())
return;
// remove the filter
this.search('');
needRedraw = true;
});
if (needRedraw)
table.api().draw();
};