1 /** |
|
2 * @summary DataTables |
|
3 * @description Paginate, search and sort HTML tables |
|
4 * @version 1.9.4 |
|
5 * @file jquery.dataTables.js |
|
6 * @author Allan Jardine (www.sprymedia.co.uk) |
|
7 * @contact www.sprymedia.co.uk/contact |
|
8 * |
|
9 * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved. |
|
10 * |
|
11 * This source file is free software, under either the GPL v2 license or a |
|
12 * BSD style license, available at: |
|
13 * http://datatables.net/license_gpl2 |
|
14 * http://datatables.net/license_bsd |
|
15 * |
|
16 * This source file is distributed in the hope that it will be useful, but |
|
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. |
|
19 * |
|
20 * For details please refer to: http://www.datatables.net |
|
21 */ |
|
22 |
|
23 |
|
24 (function ($) { |
|
25 |
|
26 "use strict"; |
|
27 |
|
28 /** |
|
29 * DataTables is a plug-in for the jQuery Javascript library. It is a |
|
30 * highly flexible tool, based upon the foundations of progressive |
|
31 * enhancement, which will add advanced interaction controls to any |
|
32 * HTML table. For a full list of features please refer to |
|
33 * <a href="http://datatables.net">DataTables.net</a>. |
|
34 * |
|
35 * Note that the <i>DataTable</i> object is not a global variable but is |
|
36 * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which |
|
37 * it may be accessed. |
|
38 * |
|
39 * @class |
|
40 * @param {object} [oInit={}] Configuration object for DataTables. Options |
|
41 * are defined by {@link DataTable.defaults} |
|
42 * @requires jQuery 1.3+ |
|
43 * |
|
44 * @example |
|
45 * // Basic initialisation |
|
46 * $(document).ready( function { |
|
47 * $('#example').dataTable(); |
|
48 * } ); |
|
49 * |
|
50 * @example |
|
51 * // Initialisation with configuration options - in this case, disable |
|
52 * // pagination and sorting. |
|
53 * $(document).ready( function { |
|
54 * $('#example').dataTable( { |
|
55 * "bPaginate": false, |
|
56 * "bSort": false |
|
57 * } ); |
|
58 * } ); |
|
59 */ |
|
60 var DataTable = function (oInit) { |
|
61 |
|
62 |
|
63 /** |
|
64 * Add a column to the list used for the table with default values |
|
65 * @param {object} oSettings dataTables settings object |
|
66 * @param {node} nTh The th element for this column |
|
67 * @memberof DataTable#oApi |
|
68 */ |
|
69 function _fnAddColumn(oSettings, nTh) { |
|
70 var oDefaults = DataTable.defaults.columns; |
|
71 var iCol = oSettings.aoColumns.length; |
|
72 var oCol = $.extend({}, DataTable.models.oColumn, oDefaults, { |
|
73 "sSortingClass": oSettings.oClasses.sSortable, |
|
74 "sSortingClassJUI": oSettings.oClasses.sSortJUI, |
|
75 "nTh": nTh ? nTh : document.createElement('th'), |
|
76 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', |
|
77 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], |
|
78 "mData": oDefaults.mData ? oDefaults.oDefaults : iCol |
|
79 }); |
|
80 oSettings.aoColumns.push(oCol); |
|
81 |
|
82 /* Add a column specific filter */ |
|
83 if (oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null) { |
|
84 oSettings.aoPreSearchCols[ iCol ] = $.extend({}, DataTable.models.oSearch); |
|
85 } |
|
86 else { |
|
87 var oPre = oSettings.aoPreSearchCols[ iCol ]; |
|
88 |
|
89 /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */ |
|
90 if (oPre.bRegex === undefined) { |
|
91 oPre.bRegex = true; |
|
92 } |
|
93 |
|
94 if (oPre.bSmart === undefined) { |
|
95 oPre.bSmart = true; |
|
96 } |
|
97 |
|
98 if (oPre.bCaseInsensitive === undefined) { |
|
99 oPre.bCaseInsensitive = true; |
|
100 } |
|
101 } |
|
102 |
|
103 /* Use the column options function to initialise classes etc */ |
|
104 _fnColumnOptions(oSettings, iCol, null); |
|
105 } |
|
106 |
|
107 |
|
108 /** |
|
109 * Apply options for a column |
|
110 * @param {object} oSettings dataTables settings object |
|
111 * @param {int} iCol column index to consider |
|
112 * @param {object} oOptions object with sType, bVisible and bSearchable etc |
|
113 * @memberof DataTable#oApi |
|
114 */ |
|
115 function _fnColumnOptions(oSettings, iCol, oOptions) { |
|
116 var oCol = oSettings.aoColumns[ iCol ]; |
|
117 |
|
118 /* User specified column options */ |
|
119 if (oOptions !== undefined && oOptions !== null) { |
|
120 /* Backwards compatibility for mDataProp */ |
|
121 if (oOptions.mDataProp && !oOptions.mData) { |
|
122 oOptions.mData = oOptions.mDataProp; |
|
123 } |
|
124 |
|
125 if (oOptions.sType !== undefined) { |
|
126 oCol.sType = oOptions.sType; |
|
127 oCol._bAutoType = false; |
|
128 } |
|
129 |
|
130 $.extend(oCol, oOptions); |
|
131 _fnMap(oCol, oOptions, "sWidth", "sWidthOrig"); |
|
132 |
|
133 /* iDataSort to be applied (backwards compatibility), but aDataSort will take |
|
134 * priority if defined |
|
135 */ |
|
136 if (oOptions.iDataSort !== undefined) { |
|
137 oCol.aDataSort = [ oOptions.iDataSort ]; |
|
138 } |
|
139 _fnMap(oCol, oOptions, "aDataSort"); |
|
140 } |
|
141 |
|
142 /* Cache the data get and set functions for speed */ |
|
143 var mRender = oCol.mRender ? _fnGetObjectDataFn(oCol.mRender) : null; |
|
144 var mData = _fnGetObjectDataFn(oCol.mData); |
|
145 |
|
146 oCol.fnGetData = function (oData, sSpecific) { |
|
147 var innerData = mData(oData, sSpecific); |
|
148 |
|
149 if (oCol.mRender && (sSpecific && sSpecific !== '')) { |
|
150 return mRender(innerData, sSpecific, oData); |
|
151 } |
|
152 return innerData; |
|
153 }; |
|
154 oCol.fnSetData = _fnSetObjectDataFn(oCol.mData); |
|
155 |
|
156 /* Feature sorting overrides column specific when off */ |
|
157 if (!oSettings.oFeatures.bSort) { |
|
158 oCol.bSortable = false; |
|
159 } |
|
160 |
|
161 /* Check that the class assignment is correct for sorting */ |
|
162 if (!oCol.bSortable || |
|
163 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1)) { |
|
164 oCol.sSortingClass = oSettings.oClasses.sSortableNone; |
|
165 oCol.sSortingClassJUI = ""; |
|
166 } |
|
167 else if ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) { |
|
168 oCol.sSortingClass = oSettings.oClasses.sSortable; |
|
169 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI; |
|
170 } |
|
171 else if ($.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1) { |
|
172 oCol.sSortingClass = oSettings.oClasses.sSortableAsc; |
|
173 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed; |
|
174 } |
|
175 else if ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1) { |
|
176 oCol.sSortingClass = oSettings.oClasses.sSortableDesc; |
|
177 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed; |
|
178 } |
|
179 } |
|
180 |
|
181 |
|
182 /** |
|
183 * Adjust the table column widths for new data. Note: you would probably want to |
|
184 * do a redraw after calling this function! |
|
185 * @param {object} oSettings dataTables settings object |
|
186 * @memberof DataTable#oApi |
|
187 */ |
|
188 function _fnAdjustColumnSizing(oSettings) { |
|
189 /* Not interested in doing column width calculation if auto-width is disabled */ |
|
190 if (oSettings.oFeatures.bAutoWidth === false) { |
|
191 return false; |
|
192 } |
|
193 |
|
194 _fnCalculateColumnWidths(oSettings); |
|
195 for (var i = 0 , iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
196 oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth; |
|
197 } |
|
198 } |
|
199 |
|
200 |
|
201 /** |
|
202 * Covert the index of a visible column to the index in the data array (take account |
|
203 * of hidden columns) |
|
204 * @param {object} oSettings dataTables settings object |
|
205 * @param {int} iMatch Visible column index to lookup |
|
206 * @returns {int} i the data index |
|
207 * @memberof DataTable#oApi |
|
208 */ |
|
209 function _fnVisibleToColumnIndex(oSettings, iMatch) { |
|
210 var aiVis = _fnGetColumns(oSettings, 'bVisible'); |
|
211 |
|
212 return typeof aiVis[iMatch] === 'number' ? |
|
213 aiVis[iMatch] : |
|
214 null; |
|
215 } |
|
216 |
|
217 |
|
218 /** |
|
219 * Covert the index of an index in the data array and convert it to the visible |
|
220 * column index (take account of hidden columns) |
|
221 * @param {int} iMatch Column index to lookup |
|
222 * @param {object} oSettings dataTables settings object |
|
223 * @returns {int} i the data index |
|
224 * @memberof DataTable#oApi |
|
225 */ |
|
226 function _fnColumnIndexToVisible(oSettings, iMatch) { |
|
227 var aiVis = _fnGetColumns(oSettings, 'bVisible'); |
|
228 var iPos = $.inArray(iMatch, aiVis); |
|
229 |
|
230 return iPos !== -1 ? iPos : null; |
|
231 } |
|
232 |
|
233 |
|
234 /** |
|
235 * Get the number of visible columns |
|
236 * @param {object} oSettings dataTables settings object |
|
237 * @returns {int} i the number of visible columns |
|
238 * @memberof DataTable#oApi |
|
239 */ |
|
240 function _fnVisbleColumns(oSettings) { |
|
241 return _fnGetColumns(oSettings, 'bVisible').length; |
|
242 } |
|
243 |
|
244 |
|
245 /** |
|
246 * Get an array of column indexes that match a given property |
|
247 * @param {object} oSettings dataTables settings object |
|
248 * @param {string} sParam Parameter in aoColumns to look for - typically |
|
249 * bVisible or bSearchable |
|
250 * @returns {array} Array of indexes with matched properties |
|
251 * @memberof DataTable#oApi |
|
252 */ |
|
253 function _fnGetColumns(oSettings, sParam) { |
|
254 var a = []; |
|
255 |
|
256 $.map(oSettings.aoColumns, function (val, i) { |
|
257 if (val[sParam]) { |
|
258 a.push(i); |
|
259 } |
|
260 }); |
|
261 |
|
262 return a; |
|
263 } |
|
264 |
|
265 |
|
266 /** |
|
267 * Get the sort type based on an input string |
|
268 * @param {string} sData data we wish to know the type of |
|
269 * @returns {string} type (defaults to 'string' if no type can be detected) |
|
270 * @memberof DataTable#oApi |
|
271 */ |
|
272 function _fnDetectType(sData) { |
|
273 var aTypes = DataTable.ext.aTypes; |
|
274 var iLen = aTypes.length; |
|
275 |
|
276 for (var i = 0; i < iLen; i++) { |
|
277 var sType = aTypes[i](sData); |
|
278 if (sType !== null) { |
|
279 return sType; |
|
280 } |
|
281 } |
|
282 |
|
283 return 'string'; |
|
284 } |
|
285 |
|
286 |
|
287 /** |
|
288 * Figure out how to reorder a display list |
|
289 * @param {object} oSettings dataTables settings object |
|
290 * @returns array {int} aiReturn index list for reordering |
|
291 * @memberof DataTable#oApi |
|
292 */ |
|
293 function _fnReOrderIndex(oSettings, sColumns) { |
|
294 var aColumns = sColumns.split(','); |
|
295 var aiReturn = []; |
|
296 |
|
297 for (var i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
298 for (var j = 0; j < iLen; j++) { |
|
299 if (oSettings.aoColumns[i].sName == aColumns[j]) { |
|
300 aiReturn.push(j); |
|
301 break; |
|
302 } |
|
303 } |
|
304 } |
|
305 |
|
306 return aiReturn; |
|
307 } |
|
308 |
|
309 |
|
310 /** |
|
311 * Get the column ordering that DataTables expects |
|
312 * @param {object} oSettings dataTables settings object |
|
313 * @returns {string} comma separated list of names |
|
314 * @memberof DataTable#oApi |
|
315 */ |
|
316 function _fnColumnOrdering(oSettings) { |
|
317 var sNames = ''; |
|
318 for (var i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
319 sNames += oSettings.aoColumns[i].sName + ','; |
|
320 } |
|
321 if (sNames.length == iLen) { |
|
322 return ""; |
|
323 } |
|
324 return sNames.slice(0, -1); |
|
325 } |
|
326 |
|
327 |
|
328 /** |
|
329 * Take the column definitions and static columns arrays and calculate how |
|
330 * they relate to column indexes. The callback function will then apply the |
|
331 * definition found for a column to a suitable configuration object. |
|
332 * @param {object} oSettings dataTables settings object |
|
333 * @param {array} aoColDefs The aoColumnDefs array that is to be applied |
|
334 * @param {array} aoCols The aoColumns array that defines columns individually |
|
335 * @param {function} fn Callback function - takes two parameters, the calculated |
|
336 * column index and the definition for that column. |
|
337 * @memberof DataTable#oApi |
|
338 */ |
|
339 function _fnApplyColumnDefs(oSettings, aoColDefs, aoCols, fn) { |
|
340 var i, iLen, j, jLen, k, kLen; |
|
341 |
|
342 // Column definitions with aTargets |
|
343 if (aoColDefs) { |
|
344 /* Loop over the definitions array - loop in reverse so first instance has priority */ |
|
345 for (i = aoColDefs.length - 1; i >= 0; i--) { |
|
346 /* Each definition can target multiple columns, as it is an array */ |
|
347 var aTargets = aoColDefs[i].aTargets; |
|
348 if (!$.isArray(aTargets)) { |
|
349 _fnLog(oSettings, 1, 'aTargets must be an array of targets, not a ' + (typeof aTargets)); |
|
350 } |
|
351 |
|
352 for (j = 0, jLen = aTargets.length; j < jLen; j++) { |
|
353 if (typeof aTargets[j] === 'number' && aTargets[j] >= 0) { |
|
354 /* Add columns that we don't yet know about */ |
|
355 while (oSettings.aoColumns.length <= aTargets[j]) { |
|
356 _fnAddColumn(oSettings); |
|
357 } |
|
358 |
|
359 /* Integer, basic index */ |
|
360 fn(aTargets[j], aoColDefs[i]); |
|
361 } |
|
362 else if (typeof aTargets[j] === 'number' && aTargets[j] < 0) { |
|
363 /* Negative integer, right to left column counting */ |
|
364 fn(oSettings.aoColumns.length + aTargets[j], aoColDefs[i]); |
|
365 } |
|
366 else if (typeof aTargets[j] === 'string') { |
|
367 /* Class name matching on TH element */ |
|
368 for (k = 0, kLen = oSettings.aoColumns.length; k < kLen; k++) { |
|
369 if (aTargets[j] == "_all" || |
|
370 $(oSettings.aoColumns[k].nTh).hasClass(aTargets[j])) { |
|
371 fn(k, aoColDefs[i]); |
|
372 } |
|
373 } |
|
374 } |
|
375 } |
|
376 } |
|
377 } |
|
378 |
|
379 // Statically defined columns array |
|
380 if (aoCols) { |
|
381 for (i = 0, iLen = aoCols.length; i < iLen; i++) { |
|
382 fn(i, aoCols[i]); |
|
383 } |
|
384 } |
|
385 } |
|
386 |
|
387 /** |
|
388 * Add a data array to the table, creating DOM node etc. This is the parallel to |
|
389 * _fnGatherData, but for adding rows from a Javascript source, rather than a |
|
390 * DOM source. |
|
391 * @param {object} oSettings dataTables settings object |
|
392 * @param {array} aData data array to be added |
|
393 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed |
|
394 * @memberof DataTable#oApi |
|
395 */ |
|
396 function _fnAddData(oSettings, aDataSupplied) { |
|
397 var oCol; |
|
398 |
|
399 /* Take an independent copy of the data source so we can bash it about as we wish */ |
|
400 var aDataIn = ($.isArray(aDataSupplied)) ? |
|
401 aDataSupplied.slice() : |
|
402 $.extend(true, {}, aDataSupplied); |
|
403 |
|
404 /* Create the object for storing information about this new row */ |
|
405 var iRow = oSettings.aoData.length; |
|
406 var oData = $.extend(true, {}, DataTable.models.oRow); |
|
407 oData._aData = aDataIn; |
|
408 oSettings.aoData.push(oData); |
|
409 |
|
410 /* Create the cells */ |
|
411 var nTd, sThisType; |
|
412 for (var i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
413 oCol = oSettings.aoColumns[i]; |
|
414 |
|
415 /* Use rendered data for filtering / sorting */ |
|
416 if (typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null) { |
|
417 _fnSetCellData(oSettings, iRow, i, _fnRender(oSettings, iRow, i)); |
|
418 } |
|
419 else { |
|
420 _fnSetCellData(oSettings, iRow, i, _fnGetCellData(oSettings, iRow, i)); |
|
421 } |
|
422 |
|
423 /* See if we should auto-detect the column type */ |
|
424 if (oCol._bAutoType && oCol.sType != 'string') { |
|
425 /* Attempt to auto detect the type - same as _fnGatherData() */ |
|
426 var sVarType = _fnGetCellData(oSettings, iRow, i, 'type'); |
|
427 if (sVarType !== null && sVarType !== '') { |
|
428 sThisType = _fnDetectType(sVarType); |
|
429 if (oCol.sType === null) { |
|
430 oCol.sType = sThisType; |
|
431 } |
|
432 else if (oCol.sType != sThisType && oCol.sType != "html") { |
|
433 /* String is always the 'fallback' option */ |
|
434 oCol.sType = 'string'; |
|
435 } |
|
436 } |
|
437 } |
|
438 } |
|
439 |
|
440 /* Add to the display array */ |
|
441 oSettings.aiDisplayMaster.push(iRow); |
|
442 |
|
443 /* Create the DOM information */ |
|
444 if (!oSettings.oFeatures.bDeferRender) { |
|
445 _fnCreateTr(oSettings, iRow); |
|
446 } |
|
447 |
|
448 return iRow; |
|
449 } |
|
450 |
|
451 |
|
452 /** |
|
453 * Read in the data from the target table from the DOM |
|
454 * @param {object} oSettings dataTables settings object |
|
455 * @memberof DataTable#oApi |
|
456 */ |
|
457 function _fnGatherData(oSettings) { |
|
458 var iLoop, i, iLen, j, jLen, jInner, |
|
459 nTds, nTrs, nTd, nTr, aLocalData, iThisIndex, |
|
460 iRow, iRows, iColumn, iColumns, sNodeName, |
|
461 oCol, oData; |
|
462 |
|
463 /* |
|
464 * Process by row first |
|
465 * Add the data object for the whole table - storing the tr node. Note - no point in getting |
|
466 * DOM based data if we are going to go and replace it with Ajax source data. |
|
467 */ |
|
468 if (oSettings.bDeferLoading || oSettings.sAjaxSource === null) { |
|
469 nTr = oSettings.nTBody.firstChild; |
|
470 while (nTr) { |
|
471 if (nTr.nodeName.toUpperCase() == "TR") { |
|
472 iThisIndex = oSettings.aoData.length; |
|
473 nTr._DT_RowIndex = iThisIndex; |
|
474 oSettings.aoData.push($.extend(true, {}, DataTable.models.oRow, { |
|
475 "nTr": nTr |
|
476 })); |
|
477 |
|
478 oSettings.aiDisplayMaster.push(iThisIndex); |
|
479 nTd = nTr.firstChild; |
|
480 jInner = 0; |
|
481 while (nTd) { |
|
482 sNodeName = nTd.nodeName.toUpperCase(); |
|
483 if (sNodeName == "TD" || sNodeName == "TH") { |
|
484 _fnSetCellData(oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML)); |
|
485 jInner++; |
|
486 } |
|
487 nTd = nTd.nextSibling; |
|
488 } |
|
489 } |
|
490 nTr = nTr.nextSibling; |
|
491 } |
|
492 } |
|
493 |
|
494 /* Gather in the TD elements of the Table - note that this is basically the same as |
|
495 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet |
|
496 * setup! |
|
497 */ |
|
498 nTrs = _fnGetTrNodes(oSettings); |
|
499 nTds = []; |
|
500 for (i = 0, iLen = nTrs.length; i < iLen; i++) { |
|
501 nTd = nTrs[i].firstChild; |
|
502 while (nTd) { |
|
503 sNodeName = nTd.nodeName.toUpperCase(); |
|
504 if (sNodeName == "TD" || sNodeName == "TH") { |
|
505 nTds.push(nTd); |
|
506 } |
|
507 nTd = nTd.nextSibling; |
|
508 } |
|
509 } |
|
510 |
|
511 /* Now process by column */ |
|
512 for (iColumn = 0, iColumns = oSettings.aoColumns.length; iColumn < iColumns; iColumn++) { |
|
513 oCol = oSettings.aoColumns[iColumn]; |
|
514 |
|
515 /* Get the title of the column - unless there is a user set one */ |
|
516 if (oCol.sTitle === null) { |
|
517 oCol.sTitle = oCol.nTh.innerHTML; |
|
518 } |
|
519 |
|
520 var |
|
521 bAutoType = oCol._bAutoType, |
|
522 bRender = typeof oCol.fnRender === 'function', |
|
523 bClass = oCol.sClass !== null, |
|
524 bVisible = oCol.bVisible, |
|
525 nCell, sThisType, sRendered, sValType; |
|
526 |
|
527 /* A single loop to rule them all (and be more efficient) */ |
|
528 if (bAutoType || bRender || bClass || !bVisible) { |
|
529 for (iRow = 0, iRows = oSettings.aoData.length; iRow < iRows; iRow++) { |
|
530 oData = oSettings.aoData[iRow]; |
|
531 nCell = nTds[ (iRow * iColumns) + iColumn ]; |
|
532 |
|
533 /* Type detection */ |
|
534 if (bAutoType && oCol.sType != 'string') { |
|
535 sValType = _fnGetCellData(oSettings, iRow, iColumn, 'type'); |
|
536 if (sValType !== '') { |
|
537 sThisType = _fnDetectType(sValType); |
|
538 if (oCol.sType === null) { |
|
539 oCol.sType = sThisType; |
|
540 } |
|
541 else if (oCol.sType != sThisType && |
|
542 oCol.sType != "html") { |
|
543 /* String is always the 'fallback' option */ |
|
544 oCol.sType = 'string'; |
|
545 } |
|
546 } |
|
547 } |
|
548 |
|
549 if (oCol.mRender) { |
|
550 // mRender has been defined, so we need to get the value and set it |
|
551 nCell.innerHTML = _fnGetCellData(oSettings, iRow, iColumn, 'display'); |
|
552 } |
|
553 else if (oCol.mData !== iColumn) { |
|
554 // If mData is not the same as the column number, then we need to |
|
555 // get the dev set value. If it is the column, no point in wasting |
|
556 // time setting the value that is already there! |
|
557 nCell.innerHTML = _fnGetCellData(oSettings, iRow, iColumn, 'display'); |
|
558 } |
|
559 |
|
560 /* Rendering */ |
|
561 if (bRender) { |
|
562 sRendered = _fnRender(oSettings, iRow, iColumn); |
|
563 nCell.innerHTML = sRendered; |
|
564 if (oCol.bUseRendered) { |
|
565 /* Use the rendered data for filtering / sorting */ |
|
566 _fnSetCellData(oSettings, iRow, iColumn, sRendered); |
|
567 } |
|
568 } |
|
569 |
|
570 /* Classes */ |
|
571 if (bClass) { |
|
572 nCell.className += ' ' + oCol.sClass; |
|
573 } |
|
574 |
|
575 /* Column visibility */ |
|
576 if (!bVisible) { |
|
577 oData._anHidden[iColumn] = nCell; |
|
578 nCell.parentNode.removeChild(nCell); |
|
579 } |
|
580 else { |
|
581 oData._anHidden[iColumn] = null; |
|
582 } |
|
583 |
|
584 if (oCol.fnCreatedCell) { |
|
585 oCol.fnCreatedCell.call(oSettings.oInstance, |
|
586 nCell, _fnGetCellData(oSettings, iRow, iColumn, 'display'), oData._aData, iRow, iColumn |
|
587 ); |
|
588 } |
|
589 } |
|
590 } |
|
591 } |
|
592 |
|
593 /* Row created callbacks */ |
|
594 if (oSettings.aoRowCreatedCallback.length !== 0) { |
|
595 for (i = 0, iLen = oSettings.aoData.length; i < iLen; i++) { |
|
596 oData = oSettings.aoData[i]; |
|
597 _fnCallbackFire(oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i]); |
|
598 } |
|
599 } |
|
600 } |
|
601 |
|
602 |
|
603 /** |
|
604 * Take a TR element and convert it to an index in aoData |
|
605 * @param {object} oSettings dataTables settings object |
|
606 * @param {node} n the TR element to find |
|
607 * @returns {int} index if the node is found, null if not |
|
608 * @memberof DataTable#oApi |
|
609 */ |
|
610 function _fnNodeToDataIndex(oSettings, n) { |
|
611 return (n._DT_RowIndex !== undefined) ? n._DT_RowIndex : null; |
|
612 } |
|
613 |
|
614 |
|
615 /** |
|
616 * Take a TD element and convert it into a column data index (not the visible index) |
|
617 * @param {object} oSettings dataTables settings object |
|
618 * @param {int} iRow The row number the TD/TH can be found in |
|
619 * @param {node} n The TD/TH element to find |
|
620 * @returns {int} index if the node is found, -1 if not |
|
621 * @memberof DataTable#oApi |
|
622 */ |
|
623 function _fnNodeToColumnIndex(oSettings, iRow, n) { |
|
624 var anCells = _fnGetTdNodes(oSettings, iRow); |
|
625 |
|
626 for (var i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
627 if (anCells[i] === n) { |
|
628 return i; |
|
629 } |
|
630 } |
|
631 return -1; |
|
632 } |
|
633 |
|
634 |
|
635 /** |
|
636 * Get an array of data for a given row from the internal data cache |
|
637 * @param {object} oSettings dataTables settings object |
|
638 * @param {int} iRow aoData row id |
|
639 * @param {string} sSpecific data get type ('type' 'filter' 'sort') |
|
640 * @param {array} aiColumns Array of column indexes to get data from |
|
641 * @returns {array} Data array |
|
642 * @memberof DataTable#oApi |
|
643 */ |
|
644 function _fnGetRowData(oSettings, iRow, sSpecific, aiColumns) { |
|
645 var out = []; |
|
646 for (var i = 0, iLen = aiColumns.length; i < iLen; i++) { |
|
647 out.push(_fnGetCellData(oSettings, iRow, aiColumns[i], sSpecific)); |
|
648 } |
|
649 return out; |
|
650 } |
|
651 |
|
652 |
|
653 /** |
|
654 * Get the data for a given cell from the internal cache, taking into account data mapping |
|
655 * @param {object} oSettings dataTables settings object |
|
656 * @param {int} iRow aoData row id |
|
657 * @param {int} iCol Column index |
|
658 * @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort') |
|
659 * @returns {*} Cell data |
|
660 * @memberof DataTable#oApi |
|
661 */ |
|
662 function _fnGetCellData(oSettings, iRow, iCol, sSpecific) { |
|
663 var sData; |
|
664 var oCol = oSettings.aoColumns[iCol]; |
|
665 var oData = oSettings.aoData[iRow]._aData; |
|
666 |
|
667 if ((sData = oCol.fnGetData(oData, sSpecific)) === undefined) { |
|
668 if (oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null) { |
|
669 _fnLog(oSettings, 0, "Requested unknown parameter " + |
|
670 (typeof oCol.mData == 'function' ? '{mData function}' : "'" + oCol.mData + "'") + |
|
671 " from the data source for row " + iRow); |
|
672 oSettings.iDrawError = oSettings.iDraw; |
|
673 } |
|
674 return oCol.sDefaultContent; |
|
675 } |
|
676 |
|
677 /* When the data source is null, we can use default column data */ |
|
678 if (sData === null && oCol.sDefaultContent !== null) { |
|
679 sData = oCol.sDefaultContent; |
|
680 } |
|
681 else if (typeof sData === 'function') { |
|
682 /* If the data source is a function, then we run it and use the return */ |
|
683 return sData(); |
|
684 } |
|
685 |
|
686 if (sSpecific == 'display' && sData === null) { |
|
687 return ''; |
|
688 } |
|
689 return sData; |
|
690 } |
|
691 |
|
692 |
|
693 /** |
|
694 * Set the value for a specific cell, into the internal data cache |
|
695 * @param {object} oSettings dataTables settings object |
|
696 * @param {int} iRow aoData row id |
|
697 * @param {int} iCol Column index |
|
698 * @param {*} val Value to set |
|
699 * @memberof DataTable#oApi |
|
700 */ |
|
701 function _fnSetCellData(oSettings, iRow, iCol, val) { |
|
702 var oCol = oSettings.aoColumns[iCol]; |
|
703 var oData = oSettings.aoData[iRow]._aData; |
|
704 |
|
705 oCol.fnSetData(oData, val); |
|
706 } |
|
707 |
|
708 |
|
709 // Private variable that is used to match array syntax in the data property object |
|
710 var __reArray = /\[.*?\]$/; |
|
711 |
|
712 /** |
|
713 * Return a function that can be used to get data from a source object, taking |
|
714 * into account the ability to use nested objects as a source |
|
715 * @param {string|int|function} mSource The data source for the object |
|
716 * @returns {function} Data get function |
|
717 * @memberof DataTable#oApi |
|
718 */ |
|
719 function _fnGetObjectDataFn(mSource) { |
|
720 if (mSource === null) { |
|
721 /* Give an empty string for rendering / sorting etc */ |
|
722 return function (data, type) { |
|
723 return null; |
|
724 }; |
|
725 } |
|
726 else if (typeof mSource === 'function') { |
|
727 return function (data, type, extra) { |
|
728 return mSource(data, type, extra); |
|
729 }; |
|
730 } |
|
731 else if (typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1)) { |
|
732 /* If there is a . in the source string then the data source is in a |
|
733 * nested object so we loop over the data for each level to get the next |
|
734 * level down. On each loop we test for undefined, and if found immediately |
|
735 * return. This allows entire objects to be missing and sDefaultContent to |
|
736 * be used if defined, rather than throwing an error |
|
737 */ |
|
738 var fetchData = function (data, type, src) { |
|
739 var a = src.split('.'); |
|
740 var arrayNotation, out, innerSrc; |
|
741 |
|
742 if (src !== "") { |
|
743 for (var i = 0, iLen = a.length; i < iLen; i++) { |
|
744 // Check if we are dealing with an array notation request |
|
745 arrayNotation = a[i].match(__reArray); |
|
746 |
|
747 if (arrayNotation) { |
|
748 a[i] = a[i].replace(__reArray, ''); |
|
749 |
|
750 // Condition allows simply [] to be passed in |
|
751 if (a[i] !== "") { |
|
752 data = data[ a[i] ]; |
|
753 } |
|
754 out = []; |
|
755 |
|
756 // Get the remainder of the nested object to get |
|
757 a.splice(0, i + 1); |
|
758 innerSrc = a.join('.'); |
|
759 |
|
760 // Traverse each entry in the array getting the properties requested |
|
761 for (var j = 0, jLen = data.length; j < jLen; j++) { |
|
762 out.push(fetchData(data[j], type, innerSrc)); |
|
763 } |
|
764 |
|
765 // If a string is given in between the array notation indicators, that |
|
766 // is used to join the strings together, otherwise an array is returned |
|
767 var join = arrayNotation[0].substring(1, arrayNotation[0].length - 1); |
|
768 data = (join === "") ? out : out.join(join); |
|
769 |
|
770 // The inner call to fetchData has already traversed through the remainder |
|
771 // of the source requested, so we exit from the loop |
|
772 break; |
|
773 } |
|
774 |
|
775 if (data === null || data[ a[i] ] === undefined) { |
|
776 return undefined; |
|
777 } |
|
778 data = data[ a[i] ]; |
|
779 } |
|
780 } |
|
781 |
|
782 return data; |
|
783 }; |
|
784 |
|
785 return function (data, type) { |
|
786 return fetchData(data, type, mSource); |
|
787 }; |
|
788 } |
|
789 else { |
|
790 /* Array or flat object mapping */ |
|
791 return function (data, type) { |
|
792 return data[mSource]; |
|
793 }; |
|
794 } |
|
795 } |
|
796 |
|
797 |
|
798 /** |
|
799 * Return a function that can be used to set data from a source object, taking |
|
800 * into account the ability to use nested objects as a source |
|
801 * @param {string|int|function} mSource The data source for the object |
|
802 * @returns {function} Data set function |
|
803 * @memberof DataTable#oApi |
|
804 */ |
|
805 function _fnSetObjectDataFn(mSource) { |
|
806 if (mSource === null) { |
|
807 /* Nothing to do when the data source is null */ |
|
808 return function (data, val) { |
|
809 }; |
|
810 } |
|
811 else if (typeof mSource === 'function') { |
|
812 return function (data, val) { |
|
813 mSource(data, 'set', val); |
|
814 }; |
|
815 } |
|
816 else if (typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1)) { |
|
817 /* Like the get, we need to get data from a nested object */ |
|
818 var setData = function (data, val, src) { |
|
819 var a = src.split('.'), b; |
|
820 var arrayNotation, o, innerSrc; |
|
821 |
|
822 for (var i = 0, iLen = a.length - 1; i < iLen; i++) { |
|
823 // Check if we are dealing with an array notation request |
|
824 arrayNotation = a[i].match(__reArray); |
|
825 |
|
826 if (arrayNotation) { |
|
827 a[i] = a[i].replace(__reArray, ''); |
|
828 data[ a[i] ] = []; |
|
829 |
|
830 // Get the remainder of the nested object to set so we can recurse |
|
831 b = a.slice(); |
|
832 b.splice(0, i + 1); |
|
833 innerSrc = b.join('.'); |
|
834 |
|
835 // Traverse each entry in the array setting the properties requested |
|
836 for (var j = 0, jLen = val.length; j < jLen; j++) { |
|
837 o = {}; |
|
838 setData(o, val[j], innerSrc); |
|
839 data[ a[i] ].push(o); |
|
840 } |
|
841 |
|
842 // The inner call to setData has already traversed through the remainder |
|
843 // of the source and has set the data, thus we can exit here |
|
844 return; |
|
845 } |
|
846 |
|
847 // If the nested object doesn't currently exist - since we are |
|
848 // trying to set the value - create it |
|
849 if (data[ a[i] ] === null || data[ a[i] ] === undefined) { |
|
850 data[ a[i] ] = {}; |
|
851 } |
|
852 data = data[ a[i] ]; |
|
853 } |
|
854 |
|
855 // If array notation is used, we just want to strip it and use the property name |
|
856 // and assign the value. If it isn't used, then we get the result we want anyway |
|
857 data[ a[a.length - 1].replace(__reArray, '') ] = val; |
|
858 }; |
|
859 |
|
860 return function (data, val) { |
|
861 return setData(data, val, mSource); |
|
862 }; |
|
863 } |
|
864 else { |
|
865 /* Array or flat object mapping */ |
|
866 return function (data, val) { |
|
867 data[mSource] = val; |
|
868 }; |
|
869 } |
|
870 } |
|
871 |
|
872 |
|
873 /** |
|
874 * Return an array with the full table data |
|
875 * @param {object} oSettings dataTables settings object |
|
876 * @returns array {array} aData Master data array |
|
877 * @memberof DataTable#oApi |
|
878 */ |
|
879 function _fnGetDataMaster(oSettings) { |
|
880 var aData = []; |
|
881 var iLen = oSettings.aoData.length; |
|
882 for (var i = 0; i < iLen; i++) { |
|
883 aData.push(oSettings.aoData[i]._aData); |
|
884 } |
|
885 return aData; |
|
886 } |
|
887 |
|
888 |
|
889 /** |
|
890 * Nuke the table |
|
891 * @param {object} oSettings dataTables settings object |
|
892 * @memberof DataTable#oApi |
|
893 */ |
|
894 function _fnClearTable(oSettings) { |
|
895 oSettings.aoData.splice(0, oSettings.aoData.length); |
|
896 oSettings.aiDisplayMaster.splice(0, oSettings.aiDisplayMaster.length); |
|
897 oSettings.aiDisplay.splice(0, oSettings.aiDisplay.length); |
|
898 _fnCalculateEnd(oSettings); |
|
899 } |
|
900 |
|
901 |
|
902 /** |
|
903 * Take an array of integers (index array) and remove a target integer (value - not |
|
904 * the key!) |
|
905 * @param {array} a Index array to target |
|
906 * @param {int} iTarget value to find |
|
907 * @memberof DataTable#oApi |
|
908 */ |
|
909 function _fnDeleteIndex(a, iTarget) { |
|
910 var iTargetIndex = -1; |
|
911 |
|
912 for (var i = 0, iLen = a.length; i < iLen; i++) { |
|
913 if (a[i] == iTarget) { |
|
914 iTargetIndex = i; |
|
915 } |
|
916 else if (a[i] > iTarget) { |
|
917 a[i]--; |
|
918 } |
|
919 } |
|
920 |
|
921 if (iTargetIndex != -1) { |
|
922 a.splice(iTargetIndex, 1); |
|
923 } |
|
924 } |
|
925 |
|
926 |
|
927 /** |
|
928 * Call the developer defined fnRender function for a given cell (row/column) with |
|
929 * the required parameters and return the result. |
|
930 * @param {object} oSettings dataTables settings object |
|
931 * @param {int} iRow aoData index for the row |
|
932 * @param {int} iCol aoColumns index for the column |
|
933 * @returns {*} Return of the developer's fnRender function |
|
934 * @memberof DataTable#oApi |
|
935 */ |
|
936 function _fnRender(oSettings, iRow, iCol) { |
|
937 var oCol = oSettings.aoColumns[iCol]; |
|
938 |
|
939 return oCol.fnRender({ |
|
940 "iDataRow": iRow, |
|
941 "iDataColumn": iCol, |
|
942 "oSettings": oSettings, |
|
943 "aData": oSettings.aoData[iRow]._aData, |
|
944 "mDataProp": oCol.mData |
|
945 }, _fnGetCellData(oSettings, iRow, iCol, 'display')); |
|
946 } |
|
947 |
|
948 /** |
|
949 * Create a new TR element (and it's TD children) for a row |
|
950 * @param {object} oSettings dataTables settings object |
|
951 * @param {int} iRow Row to consider |
|
952 * @memberof DataTable#oApi |
|
953 */ |
|
954 function _fnCreateTr(oSettings, iRow) { |
|
955 var oData = oSettings.aoData[iRow]; |
|
956 var nTd; |
|
957 |
|
958 if (oData.nTr === null) { |
|
959 oData.nTr = document.createElement('tr'); |
|
960 |
|
961 /* Use a private property on the node to allow reserve mapping from the node |
|
962 * to the aoData array for fast look up |
|
963 */ |
|
964 oData.nTr._DT_RowIndex = iRow; |
|
965 |
|
966 /* Special parameters can be given by the data source to be used on the row */ |
|
967 if (oData._aData.DT_RowId) { |
|
968 oData.nTr.id = oData._aData.DT_RowId; |
|
969 } |
|
970 |
|
971 if (oData._aData.DT_RowClass) { |
|
972 oData.nTr.className = oData._aData.DT_RowClass; |
|
973 } |
|
974 |
|
975 /* Process each column */ |
|
976 for (var i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
977 var oCol = oSettings.aoColumns[i]; |
|
978 nTd = document.createElement(oCol.sCellType); |
|
979 |
|
980 /* Render if needed - if bUseRendered is true then we already have the rendered |
|
981 * value in the data source - so can just use that |
|
982 */ |
|
983 nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ? |
|
984 _fnRender(oSettings, iRow, i) : |
|
985 _fnGetCellData(oSettings, iRow, i, 'display'); |
|
986 |
|
987 /* Add user defined class */ |
|
988 if (oCol.sClass !== null) { |
|
989 nTd.className = oCol.sClass; |
|
990 } |
|
991 |
|
992 if (oCol.bVisible) { |
|
993 oData.nTr.appendChild(nTd); |
|
994 oData._anHidden[i] = null; |
|
995 } |
|
996 else { |
|
997 oData._anHidden[i] = nTd; |
|
998 } |
|
999 |
|
1000 if (oCol.fnCreatedCell) { |
|
1001 oCol.fnCreatedCell.call(oSettings.oInstance, |
|
1002 nTd, _fnGetCellData(oSettings, iRow, i, 'display'), oData._aData, iRow, i |
|
1003 ); |
|
1004 } |
|
1005 } |
|
1006 |
|
1007 _fnCallbackFire(oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow]); |
|
1008 } |
|
1009 } |
|
1010 |
|
1011 |
|
1012 /** |
|
1013 * Create the HTML header for the table |
|
1014 * @param {object} oSettings dataTables settings object |
|
1015 * @memberof DataTable#oApi |
|
1016 */ |
|
1017 function _fnBuildHead(oSettings) { |
|
1018 var i, nTh, iLen, j, jLen; |
|
1019 var iThs = $('th, td', oSettings.nTHead).length; |
|
1020 var iCorrector = 0; |
|
1021 var jqChildren; |
|
1022 |
|
1023 /* If there is a header in place - then use it - otherwise it's going to get nuked... */ |
|
1024 if (iThs !== 0) { |
|
1025 /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */ |
|
1026 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
1027 nTh = oSettings.aoColumns[i].nTh; |
|
1028 nTh.setAttribute('role', 'columnheader'); |
|
1029 if (oSettings.aoColumns[i].bSortable) { |
|
1030 nTh.setAttribute('tabindex', oSettings.iTabIndex); |
|
1031 nTh.setAttribute('aria-controls', oSettings.sTableId); |
|
1032 } |
|
1033 |
|
1034 if (oSettings.aoColumns[i].sClass !== null) { |
|
1035 $(nTh).addClass(oSettings.aoColumns[i].sClass); |
|
1036 } |
|
1037 |
|
1038 /* Set the title of the column if it is user defined (not what was auto detected) */ |
|
1039 if (oSettings.aoColumns[i].sTitle != nTh.innerHTML) { |
|
1040 nTh.innerHTML = oSettings.aoColumns[i].sTitle; |
|
1041 } |
|
1042 } |
|
1043 } |
|
1044 else { |
|
1045 /* We don't have a header in the DOM - so we are going to have to create one */ |
|
1046 var nTr = document.createElement("tr"); |
|
1047 |
|
1048 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
1049 nTh = oSettings.aoColumns[i].nTh; |
|
1050 nTh.innerHTML = oSettings.aoColumns[i].sTitle; |
|
1051 nTh.setAttribute('tabindex', '0'); |
|
1052 |
|
1053 if (oSettings.aoColumns[i].sClass !== null) { |
|
1054 $(nTh).addClass(oSettings.aoColumns[i].sClass); |
|
1055 } |
|
1056 |
|
1057 nTr.appendChild(nTh); |
|
1058 } |
|
1059 $(oSettings.nTHead).html('')[0].appendChild(nTr); |
|
1060 _fnDetectHeader(oSettings.aoHeader, oSettings.nTHead); |
|
1061 } |
|
1062 |
|
1063 /* ARIA role for the rows */ |
|
1064 $(oSettings.nTHead).children('tr').attr('role', 'row'); |
|
1065 |
|
1066 /* Add the extra markup needed by jQuery UI's themes */ |
|
1067 if (oSettings.bJUI) { |
|
1068 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
1069 nTh = oSettings.aoColumns[i].nTh; |
|
1070 |
|
1071 var nDiv = document.createElement('div'); |
|
1072 nDiv.className = oSettings.oClasses.sSortJUIWrapper; |
|
1073 $(nTh).contents().appendTo(nDiv); |
|
1074 |
|
1075 var nSpan = document.createElement('span'); |
|
1076 nSpan.className = oSettings.oClasses.sSortIcon; |
|
1077 nDiv.appendChild(nSpan); |
|
1078 nTh.appendChild(nDiv); |
|
1079 } |
|
1080 } |
|
1081 |
|
1082 if (oSettings.oFeatures.bSort) { |
|
1083 for (i = 0; i < oSettings.aoColumns.length; i++) { |
|
1084 if (oSettings.aoColumns[i].bSortable !== false) { |
|
1085 _fnSortAttachListener(oSettings, oSettings.aoColumns[i].nTh, i); |
|
1086 } |
|
1087 else { |
|
1088 $(oSettings.aoColumns[i].nTh).addClass(oSettings.oClasses.sSortableNone); |
|
1089 } |
|
1090 } |
|
1091 } |
|
1092 |
|
1093 /* Deal with the footer - add classes if required */ |
|
1094 if (oSettings.oClasses.sFooterTH !== "") { |
|
1095 $(oSettings.nTFoot).children('tr').children('th').addClass(oSettings.oClasses.sFooterTH); |
|
1096 } |
|
1097 |
|
1098 /* Cache the footer elements */ |
|
1099 if (oSettings.nTFoot !== null) { |
|
1100 var anCells = _fnGetUniqueThs(oSettings, null, oSettings.aoFooter); |
|
1101 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
1102 if (anCells[i]) { |
|
1103 oSettings.aoColumns[i].nTf = anCells[i]; |
|
1104 if (oSettings.aoColumns[i].sClass) { |
|
1105 $(anCells[i]).addClass(oSettings.aoColumns[i].sClass); |
|
1106 } |
|
1107 } |
|
1108 } |
|
1109 } |
|
1110 } |
|
1111 |
|
1112 |
|
1113 /** |
|
1114 * Draw the header (or footer) element based on the column visibility states. The |
|
1115 * methodology here is to use the layout array from _fnDetectHeader, modified for |
|
1116 * the instantaneous column visibility, to construct the new layout. The grid is |
|
1117 * traversed over cell at a time in a rows x columns grid fashion, although each |
|
1118 * cell insert can cover multiple elements in the grid - which is tracks using the |
|
1119 * aApplied array. Cell inserts in the grid will only occur where there isn't |
|
1120 * already a cell in that position. |
|
1121 * @param {object} oSettings dataTables settings object |
|
1122 * @param array {objects} aoSource Layout array from _fnDetectHeader |
|
1123 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, |
|
1124 * @memberof DataTable#oApi |
|
1125 */ |
|
1126 function _fnDrawHead(oSettings, aoSource, bIncludeHidden) { |
|
1127 var i, iLen, j, jLen, k, kLen, n, nLocalTr; |
|
1128 var aoLocal = []; |
|
1129 var aApplied = []; |
|
1130 var iColumns = oSettings.aoColumns.length; |
|
1131 var iRowspan, iColspan; |
|
1132 |
|
1133 if (bIncludeHidden === undefined) { |
|
1134 bIncludeHidden = false; |
|
1135 } |
|
1136 |
|
1137 /* Make a copy of the master layout array, but without the visible columns in it */ |
|
1138 for (i = 0, iLen = aoSource.length; i < iLen; i++) { |
|
1139 aoLocal[i] = aoSource[i].slice(); |
|
1140 aoLocal[i].nTr = aoSource[i].nTr; |
|
1141 |
|
1142 /* Remove any columns which are currently hidden */ |
|
1143 for (j = iColumns - 1; j >= 0; j--) { |
|
1144 if (!oSettings.aoColumns[j].bVisible && !bIncludeHidden) { |
|
1145 aoLocal[i].splice(j, 1); |
|
1146 } |
|
1147 } |
|
1148 |
|
1149 /* Prep the applied array - it needs an element for each row */ |
|
1150 aApplied.push([]); |
|
1151 } |
|
1152 |
|
1153 for (i = 0, iLen = aoLocal.length; i < iLen; i++) { |
|
1154 nLocalTr = aoLocal[i].nTr; |
|
1155 |
|
1156 /* All cells are going to be replaced, so empty out the row */ |
|
1157 if (nLocalTr) { |
|
1158 while ((n = nLocalTr.firstChild)) { |
|
1159 nLocalTr.removeChild(n); |
|
1160 } |
|
1161 } |
|
1162 |
|
1163 for (j = 0, jLen = aoLocal[i].length; j < jLen; j++) { |
|
1164 iRowspan = 1; |
|
1165 iColspan = 1; |
|
1166 |
|
1167 /* Check to see if there is already a cell (row/colspan) covering our target |
|
1168 * insert point. If there is, then there is nothing to do. |
|
1169 */ |
|
1170 if (aApplied[i][j] === undefined) { |
|
1171 nLocalTr.appendChild(aoLocal[i][j].cell); |
|
1172 aApplied[i][j] = 1; |
|
1173 |
|
1174 /* Expand the cell to cover as many rows as needed */ |
|
1175 while (aoLocal[i + iRowspan] !== undefined && |
|
1176 aoLocal[i][j].cell == aoLocal[i + iRowspan][j].cell) { |
|
1177 aApplied[i + iRowspan][j] = 1; |
|
1178 iRowspan++; |
|
1179 } |
|
1180 |
|
1181 /* Expand the cell to cover as many columns as needed */ |
|
1182 while (aoLocal[i][j + iColspan] !== undefined && |
|
1183 aoLocal[i][j].cell == aoLocal[i][j + iColspan].cell) { |
|
1184 /* Must update the applied array over the rows for the columns */ |
|
1185 for (k = 0; k < iRowspan; k++) { |
|
1186 aApplied[i + k][j + iColspan] = 1; |
|
1187 } |
|
1188 iColspan++; |
|
1189 } |
|
1190 |
|
1191 /* Do the actual expansion in the DOM */ |
|
1192 aoLocal[i][j].cell.rowSpan = iRowspan; |
|
1193 aoLocal[i][j].cell.colSpan = iColspan; |
|
1194 } |
|
1195 } |
|
1196 } |
|
1197 } |
|
1198 |
|
1199 |
|
1200 /** |
|
1201 * Insert the required TR nodes into the table for display |
|
1202 * @param {object} oSettings dataTables settings object |
|
1203 * @memberof DataTable#oApi |
|
1204 */ |
|
1205 function _fnDraw(oSettings) { |
|
1206 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ |
|
1207 var aPreDraw = _fnCallbackFire(oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings]); |
|
1208 if ($.inArray(false, aPreDraw) !== -1) { |
|
1209 _fnProcessingDisplay(oSettings, false); |
|
1210 return; |
|
1211 } |
|
1212 |
|
1213 var i, iLen, n; |
|
1214 var anRows = []; |
|
1215 var iRowCount = 0; |
|
1216 var iStripes = oSettings.asStripeClasses.length; |
|
1217 var iOpenRows = oSettings.aoOpenRows.length; |
|
1218 |
|
1219 oSettings.bDrawing = true; |
|
1220 |
|
1221 /* Check and see if we have an initial draw position from state saving */ |
|
1222 if (oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1) { |
|
1223 if (oSettings.oFeatures.bServerSide) { |
|
1224 oSettings._iDisplayStart = oSettings.iInitDisplayStart; |
|
1225 } |
|
1226 else { |
|
1227 oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ? |
|
1228 0 : oSettings.iInitDisplayStart; |
|
1229 } |
|
1230 oSettings.iInitDisplayStart = -1; |
|
1231 _fnCalculateEnd(oSettings); |
|
1232 } |
|
1233 |
|
1234 /* Server-side processing draw intercept */ |
|
1235 if (oSettings.bDeferLoading) { |
|
1236 oSettings.bDeferLoading = false; |
|
1237 oSettings.iDraw++; |
|
1238 } |
|
1239 else if (!oSettings.oFeatures.bServerSide) { |
|
1240 oSettings.iDraw++; |
|
1241 } |
|
1242 else if (!oSettings.bDestroying && !_fnAjaxUpdate(oSettings)) { |
|
1243 return; |
|
1244 } |
|
1245 |
|
1246 if (oSettings.aiDisplay.length !== 0) { |
|
1247 var iStart = oSettings._iDisplayStart; |
|
1248 var iEnd = oSettings._iDisplayEnd; |
|
1249 |
|
1250 if (oSettings.oFeatures.bServerSide) { |
|
1251 iStart = 0; |
|
1252 iEnd = oSettings.aoData.length; |
|
1253 } |
|
1254 |
|
1255 for (var j = iStart; j < iEnd; j++) { |
|
1256 var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ]; |
|
1257 if (aoData.nTr === null) { |
|
1258 _fnCreateTr(oSettings, oSettings.aiDisplay[j]); |
|
1259 } |
|
1260 |
|
1261 var nRow = aoData.nTr; |
|
1262 |
|
1263 /* Remove the old striping classes and then add the new one */ |
|
1264 if (iStripes !== 0) { |
|
1265 var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ]; |
|
1266 if (aoData._sRowStripe != sStripe) { |
|
1267 $(nRow).removeClass(aoData._sRowStripe).addClass(sStripe); |
|
1268 aoData._sRowStripe = sStripe; |
|
1269 } |
|
1270 } |
|
1271 |
|
1272 /* Row callback functions - might want to manipulate the row */ |
|
1273 _fnCallbackFire(oSettings, 'aoRowCallback', null, |
|
1274 [nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j]); |
|
1275 |
|
1276 anRows.push(nRow); |
|
1277 iRowCount++; |
|
1278 |
|
1279 /* If there is an open row - and it is attached to this parent - attach it on redraw */ |
|
1280 if (iOpenRows !== 0) { |
|
1281 for (var k = 0; k < iOpenRows; k++) { |
|
1282 if (nRow == oSettings.aoOpenRows[k].nParent) { |
|
1283 anRows.push(oSettings.aoOpenRows[k].nTr); |
|
1284 break; |
|
1285 } |
|
1286 } |
|
1287 } |
|
1288 } |
|
1289 } |
|
1290 else { |
|
1291 /* Table is empty - create a row with an empty message in it */ |
|
1292 anRows[ 0 ] = document.createElement('tr'); |
|
1293 |
|
1294 if (oSettings.asStripeClasses[0]) { |
|
1295 anRows[ 0 ].className = oSettings.asStripeClasses[0]; |
|
1296 } |
|
1297 |
|
1298 var oLang = oSettings.oLanguage; |
|
1299 var sZero = oLang.sZeroRecords; |
|
1300 if (oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide) { |
|
1301 sZero = oLang.sLoadingRecords; |
|
1302 } |
|
1303 else if (oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0) { |
|
1304 sZero = oLang.sEmptyTable; |
|
1305 } |
|
1306 |
|
1307 var nTd = document.createElement('td'); |
|
1308 nTd.setAttribute('valign', "top"); |
|
1309 nTd.colSpan = _fnVisbleColumns(oSettings); |
|
1310 nTd.className = oSettings.oClasses.sRowEmpty; |
|
1311 nTd.innerHTML = _fnInfoMacros(oSettings, sZero); |
|
1312 |
|
1313 anRows[ iRowCount ].appendChild(nTd); |
|
1314 } |
|
1315 |
|
1316 /* Header and footer callbacks */ |
|
1317 _fnCallbackFire(oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], |
|
1318 _fnGetDataMaster(oSettings), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ]); |
|
1319 |
|
1320 _fnCallbackFire(oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], |
|
1321 _fnGetDataMaster(oSettings), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ]); |
|
1322 |
|
1323 /* |
|
1324 * Need to remove any old row from the display - note we can't just empty the tbody using |
|
1325 * $().html('') since this will unbind the jQuery event handlers (even although the node |
|
1326 * still exists!) - equally we can't use innerHTML, since IE throws an exception. |
|
1327 */ |
|
1328 var |
|
1329 nAddFrag = document.createDocumentFragment(), |
|
1330 nRemoveFrag = document.createDocumentFragment(), |
|
1331 nBodyPar, nTrs; |
|
1332 |
|
1333 if (oSettings.nTBody) { |
|
1334 nBodyPar = oSettings.nTBody.parentNode; |
|
1335 nRemoveFrag.appendChild(oSettings.nTBody); |
|
1336 |
|
1337 /* When doing infinite scrolling, only remove child rows when sorting, filtering or start |
|
1338 * up. When not infinite scroll, always do it. |
|
1339 */ |
|
1340 if (!oSettings.oScroll.bInfinite || !oSettings._bInitComplete || |
|
1341 oSettings.bSorted || oSettings.bFiltered) { |
|
1342 while ((n = oSettings.nTBody.firstChild)) { |
|
1343 oSettings.nTBody.removeChild(n); |
|
1344 } |
|
1345 } |
|
1346 |
|
1347 /* Put the draw table into the dom */ |
|
1348 for (i = 0, iLen = anRows.length; i < iLen; i++) { |
|
1349 nAddFrag.appendChild(anRows[i]); |
|
1350 } |
|
1351 |
|
1352 oSettings.nTBody.appendChild(nAddFrag); |
|
1353 if (nBodyPar !== null) { |
|
1354 nBodyPar.appendChild(oSettings.nTBody); |
|
1355 } |
|
1356 } |
|
1357 |
|
1358 /* Call all required callback functions for the end of a draw */ |
|
1359 _fnCallbackFire(oSettings, 'aoDrawCallback', 'draw', [oSettings]); |
|
1360 |
|
1361 /* Draw is complete, sorting and filtering must be as well */ |
|
1362 oSettings.bSorted = false; |
|
1363 oSettings.bFiltered = false; |
|
1364 oSettings.bDrawing = false; |
|
1365 |
|
1366 if (oSettings.oFeatures.bServerSide) { |
|
1367 _fnProcessingDisplay(oSettings, false); |
|
1368 if (!oSettings._bInitComplete) { |
|
1369 _fnInitComplete(oSettings); |
|
1370 } |
|
1371 } |
|
1372 } |
|
1373 |
|
1374 |
|
1375 /** |
|
1376 * Redraw the table - taking account of the various features which are enabled |
|
1377 * @param {object} oSettings dataTables settings object |
|
1378 * @memberof DataTable#oApi |
|
1379 */ |
|
1380 function _fnReDraw(oSettings) { |
|
1381 if (oSettings.oFeatures.bSort) { |
|
1382 /* Sorting will refilter and draw for us */ |
|
1383 _fnSort(oSettings, oSettings.oPreviousSearch); |
|
1384 } |
|
1385 else if (oSettings.oFeatures.bFilter) { |
|
1386 /* Filtering will redraw for us */ |
|
1387 _fnFilterComplete(oSettings, oSettings.oPreviousSearch); |
|
1388 } |
|
1389 else { |
|
1390 _fnCalculateEnd(oSettings); |
|
1391 _fnDraw(oSettings); |
|
1392 } |
|
1393 } |
|
1394 |
|
1395 |
|
1396 /** |
|
1397 * Add the options to the page HTML for the table |
|
1398 * @param {object} oSettings dataTables settings object |
|
1399 * @memberof DataTable#oApi |
|
1400 */ |
|
1401 function _fnAddOptionsHtml(oSettings) { |
|
1402 /* |
|
1403 * Create a temporary, empty, div which we can later on replace with what we have generated |
|
1404 * we do it this way to rendering the 'options' html offline - speed :-) |
|
1405 */ |
|
1406 var nHolding = $('<div></div>')[0]; |
|
1407 oSettings.nTable.parentNode.insertBefore(nHolding, oSettings.nTable); |
|
1408 |
|
1409 /* |
|
1410 * All DataTables are wrapped in a div |
|
1411 */ |
|
1412 oSettings.nTableWrapper = $('<div id="' + oSettings.sTableId + '_wrapper" class="' + oSettings.oClasses.sWrapper + '" role="grid"></div>')[0]; |
|
1413 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; |
|
1414 |
|
1415 /* Track where we want to insert the option */ |
|
1416 var nInsertNode = oSettings.nTableWrapper; |
|
1417 |
|
1418 /* Loop over the user set positioning and place the elements as needed */ |
|
1419 var aDom = oSettings.sDom.split(''); |
|
1420 var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j; |
|
1421 for (var i = 0; i < aDom.length; i++) { |
|
1422 iPushFeature = 0; |
|
1423 cOption = aDom[i]; |
|
1424 |
|
1425 if (cOption == '<') { |
|
1426 /* New container div */ |
|
1427 nNewNode = $('<div></div>')[0]; |
|
1428 |
|
1429 /* Check to see if we should append an id and/or a class name to the container */ |
|
1430 cNext = aDom[i + 1]; |
|
1431 if (cNext == "'" || cNext == '"') { |
|
1432 sAttr = ""; |
|
1433 j = 2; |
|
1434 while (aDom[i + j] != cNext) { |
|
1435 sAttr += aDom[i + j]; |
|
1436 j++; |
|
1437 } |
|
1438 |
|
1439 /* Replace jQuery UI constants */ |
|
1440 if (sAttr == "H") { |
|
1441 sAttr = oSettings.oClasses.sJUIHeader; |
|
1442 } |
|
1443 else if (sAttr == "F") { |
|
1444 sAttr = oSettings.oClasses.sJUIFooter; |
|
1445 } |
|
1446 |
|
1447 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic |
|
1448 * breaks the string into parts and applies them as needed |
|
1449 */ |
|
1450 if (sAttr.indexOf('.') != -1) { |
|
1451 var aSplit = sAttr.split('.'); |
|
1452 nNewNode.id = aSplit[0].substr(1, aSplit[0].length - 1); |
|
1453 nNewNode.className = aSplit[1]; |
|
1454 } |
|
1455 else if (sAttr.charAt(0) == "#") { |
|
1456 nNewNode.id = sAttr.substr(1, sAttr.length - 1); |
|
1457 } |
|
1458 else { |
|
1459 nNewNode.className = sAttr; |
|
1460 } |
|
1461 |
|
1462 i += j; |
|
1463 /* Move along the position array */ |
|
1464 } |
|
1465 |
|
1466 nInsertNode.appendChild(nNewNode); |
|
1467 nInsertNode = nNewNode; |
|
1468 } |
|
1469 else if (cOption == '>') { |
|
1470 /* End container div */ |
|
1471 nInsertNode = nInsertNode.parentNode; |
|
1472 } |
|
1473 else if (cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange) { |
|
1474 /* Length */ |
|
1475 nTmp = _fnFeatureHtmlLength(oSettings); |
|
1476 iPushFeature = 1; |
|
1477 } |
|
1478 else if (cOption == 'f' && oSettings.oFeatures.bFilter) { |
|
1479 /* Filter */ |
|
1480 nTmp = _fnFeatureHtmlFilter(oSettings); |
|
1481 iPushFeature = 1; |
|
1482 } |
|
1483 else if (cOption == 'r' && oSettings.oFeatures.bProcessing) { |
|
1484 /* pRocessing */ |
|
1485 nTmp = _fnFeatureHtmlProcessing(oSettings); |
|
1486 iPushFeature = 1; |
|
1487 } |
|
1488 else if (cOption == 't') { |
|
1489 /* Table */ |
|
1490 nTmp = _fnFeatureHtmlTable(oSettings); |
|
1491 iPushFeature = 1; |
|
1492 } |
|
1493 else if (cOption == 'i' && oSettings.oFeatures.bInfo) { |
|
1494 /* Info */ |
|
1495 nTmp = _fnFeatureHtmlInfo(oSettings); |
|
1496 iPushFeature = 1; |
|
1497 } |
|
1498 else if (cOption == 'p' && oSettings.oFeatures.bPaginate) { |
|
1499 /* Pagination */ |
|
1500 nTmp = _fnFeatureHtmlPaginate(oSettings); |
|
1501 iPushFeature = 1; |
|
1502 } |
|
1503 else if (DataTable.ext.aoFeatures.length !== 0) { |
|
1504 /* Plug-in features */ |
|
1505 var aoFeatures = DataTable.ext.aoFeatures; |
|
1506 for (var k = 0, kLen = aoFeatures.length; k < kLen; k++) { |
|
1507 if (cOption == aoFeatures[k].cFeature) { |
|
1508 nTmp = aoFeatures[k].fnInit(oSettings); |
|
1509 if (nTmp) { |
|
1510 iPushFeature = 1; |
|
1511 } |
|
1512 break; |
|
1513 } |
|
1514 } |
|
1515 } |
|
1516 |
|
1517 /* Add to the 2D features array */ |
|
1518 if (iPushFeature == 1 && nTmp !== null) { |
|
1519 if (typeof oSettings.aanFeatures[cOption] !== 'object') { |
|
1520 oSettings.aanFeatures[cOption] = []; |
|
1521 } |
|
1522 oSettings.aanFeatures[cOption].push(nTmp); |
|
1523 nInsertNode.appendChild(nTmp); |
|
1524 } |
|
1525 } |
|
1526 |
|
1527 /* Built our DOM structure - replace the holding div with what we want */ |
|
1528 nHolding.parentNode.replaceChild(oSettings.nTableWrapper, nHolding); |
|
1529 } |
|
1530 |
|
1531 |
|
1532 /** |
|
1533 * Use the DOM source to create up an array of header cells. The idea here is to |
|
1534 * create a layout grid (array) of rows x columns, which contains a reference |
|
1535 * to the cell that that point in the grid (regardless of col/rowspan), such that |
|
1536 * any column / row could be removed and the new grid constructed |
|
1537 * @param array {object} aLayout Array to store the calculated layout in |
|
1538 * @param {node} nThead The header/footer element for the table |
|
1539 * @memberof DataTable#oApi |
|
1540 */ |
|
1541 function _fnDetectHeader(aLayout, nThead) { |
|
1542 var nTrs = $(nThead).children('tr'); |
|
1543 var nTr, nCell; |
|
1544 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; |
|
1545 var bUnique; |
|
1546 var fnShiftCol = function (a, i, j) { |
|
1547 var k = a[i]; |
|
1548 while (k[j]) { |
|
1549 j++; |
|
1550 } |
|
1551 return j; |
|
1552 }; |
|
1553 |
|
1554 aLayout.splice(0, aLayout.length); |
|
1555 |
|
1556 /* We know how many rows there are in the layout - so prep it */ |
|
1557 for (i = 0, iLen = nTrs.length; i < iLen; i++) { |
|
1558 aLayout.push([]); |
|
1559 } |
|
1560 |
|
1561 /* Calculate a layout array */ |
|
1562 for (i = 0, iLen = nTrs.length; i < iLen; i++) { |
|
1563 nTr = nTrs[i]; |
|
1564 iColumn = 0; |
|
1565 |
|
1566 /* For every cell in the row... */ |
|
1567 nCell = nTr.firstChild; |
|
1568 while (nCell) { |
|
1569 if (nCell.nodeName.toUpperCase() == "TD" || |
|
1570 nCell.nodeName.toUpperCase() == "TH") { |
|
1571 /* Get the col and rowspan attributes from the DOM and sanitise them */ |
|
1572 iColspan = nCell.getAttribute('colspan') * 1; |
|
1573 iRowspan = nCell.getAttribute('rowspan') * 1; |
|
1574 iColspan = (!iColspan || iColspan === 0 || iColspan === 1) ? 1 : iColspan; |
|
1575 iRowspan = (!iRowspan || iRowspan === 0 || iRowspan === 1) ? 1 : iRowspan; |
|
1576 |
|
1577 /* There might be colspan cells already in this row, so shift our target |
|
1578 * accordingly |
|
1579 */ |
|
1580 iColShifted = fnShiftCol(aLayout, i, iColumn); |
|
1581 |
|
1582 /* Cache calculation for unique columns */ |
|
1583 bUnique = iColspan === 1 ? true : false; |
|
1584 |
|
1585 /* If there is col / rowspan, copy the information into the layout grid */ |
|
1586 for (l = 0; l < iColspan; l++) { |
|
1587 for (k = 0; k < iRowspan; k++) { |
|
1588 aLayout[i + k][iColShifted + l] = { |
|
1589 "cell": nCell, |
|
1590 "unique": bUnique |
|
1591 }; |
|
1592 aLayout[i + k].nTr = nTr; |
|
1593 } |
|
1594 } |
|
1595 } |
|
1596 nCell = nCell.nextSibling; |
|
1597 } |
|
1598 } |
|
1599 } |
|
1600 |
|
1601 |
|
1602 /** |
|
1603 * Get an array of unique th elements, one for each column |
|
1604 * @param {object} oSettings dataTables settings object |
|
1605 * @param {node} nHeader automatically detect the layout from this node - optional |
|
1606 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional |
|
1607 * @returns array {node} aReturn list of unique th's |
|
1608 * @memberof DataTable#oApi |
|
1609 */ |
|
1610 function _fnGetUniqueThs(oSettings, nHeader, aLayout) { |
|
1611 var aReturn = []; |
|
1612 if (!aLayout) { |
|
1613 aLayout = oSettings.aoHeader; |
|
1614 if (nHeader) { |
|
1615 aLayout = []; |
|
1616 _fnDetectHeader(aLayout, nHeader); |
|
1617 } |
|
1618 } |
|
1619 |
|
1620 for (var i = 0, iLen = aLayout.length; i < iLen; i++) { |
|
1621 for (var j = 0, jLen = aLayout[i].length; j < jLen; j++) { |
|
1622 if (aLayout[i][j].unique && |
|
1623 (!aReturn[j] || !oSettings.bSortCellsTop)) { |
|
1624 aReturn[j] = aLayout[i][j].cell; |
|
1625 } |
|
1626 } |
|
1627 } |
|
1628 |
|
1629 return aReturn; |
|
1630 } |
|
1631 |
|
1632 |
|
1633 /** |
|
1634 * Update the table using an Ajax call |
|
1635 * @param {object} oSettings dataTables settings object |
|
1636 * @returns {boolean} Block the table drawing or not |
|
1637 * @memberof DataTable#oApi |
|
1638 */ |
|
1639 function _fnAjaxUpdate(oSettings) { |
|
1640 if (oSettings.bAjaxDataGet) { |
|
1641 oSettings.iDraw++; |
|
1642 _fnProcessingDisplay(oSettings, true); |
|
1643 var iColumns = oSettings.aoColumns.length; |
|
1644 var aoData = _fnAjaxParameters(oSettings); |
|
1645 _fnServerParams(oSettings, aoData); |
|
1646 |
|
1647 oSettings.fnServerData.call(oSettings.oInstance, oSettings.sAjaxSource, aoData, |
|
1648 function (json) { |
|
1649 _fnAjaxUpdateDraw(oSettings, json); |
|
1650 }, oSettings); |
|
1651 return false; |
|
1652 } |
|
1653 else { |
|
1654 return true; |
|
1655 } |
|
1656 } |
|
1657 |
|
1658 |
|
1659 /** |
|
1660 * Build up the parameters in an object needed for a server-side processing request |
|
1661 * @param {object} oSettings dataTables settings object |
|
1662 * @returns {bool} block the table drawing or not |
|
1663 * @memberof DataTable#oApi |
|
1664 */ |
|
1665 function _fnAjaxParameters(oSettings) { |
|
1666 var iColumns = oSettings.aoColumns.length; |
|
1667 var aoData = [], mDataProp, aaSort, aDataSort; |
|
1668 var i, j; |
|
1669 |
|
1670 aoData.push({ "name": "sEcho", "value": oSettings.iDraw }); |
|
1671 aoData.push({ "name": "iColumns", "value": iColumns }); |
|
1672 aoData.push({ "name": "sColumns", "value": _fnColumnOrdering(oSettings) }); |
|
1673 aoData.push({ "name": "iDisplayStart", "value": oSettings._iDisplayStart }); |
|
1674 aoData.push({ "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ? |
|
1675 oSettings._iDisplayLength : -1 }); |
|
1676 |
|
1677 for (i = 0; i < iColumns; i++) { |
|
1678 mDataProp = oSettings.aoColumns[i].mData; |
|
1679 aoData.push({ "name": "mDataProp_" + i, "value": typeof(mDataProp) === "function" ? 'function' : mDataProp }); |
|
1680 } |
|
1681 |
|
1682 /* Filtering */ |
|
1683 if (oSettings.oFeatures.bFilter !== false) { |
|
1684 aoData.push({ "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch }); |
|
1685 aoData.push({ "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex }); |
|
1686 for (i = 0; i < iColumns; i++) { |
|
1687 aoData.push({ "name": "sSearch_" + i, "value": oSettings.aoPreSearchCols[i].sSearch }); |
|
1688 aoData.push({ "name": "bRegex_" + i, "value": oSettings.aoPreSearchCols[i].bRegex }); |
|
1689 aoData.push({ "name": "bSearchable_" + i, "value": oSettings.aoColumns[i].bSearchable }); |
|
1690 } |
|
1691 } |
|
1692 |
|
1693 /* Sorting */ |
|
1694 if (oSettings.oFeatures.bSort !== false) { |
|
1695 var iCounter = 0; |
|
1696 |
|
1697 aaSort = ( oSettings.aaSortingFixed !== null ) ? |
|
1698 oSettings.aaSortingFixed.concat(oSettings.aaSorting) : |
|
1699 oSettings.aaSorting.slice(); |
|
1700 |
|
1701 for (i = 0; i < aaSort.length; i++) { |
|
1702 aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort; |
|
1703 |
|
1704 for (j = 0; j < aDataSort.length; j++) { |
|
1705 aoData.push({ "name": "iSortCol_" + iCounter, "value": aDataSort[j] }); |
|
1706 aoData.push({ "name": "sSortDir_" + iCounter, "value": aaSort[i][1] }); |
|
1707 iCounter++; |
|
1708 } |
|
1709 } |
|
1710 aoData.push({ "name": "iSortingCols", "value": iCounter }); |
|
1711 |
|
1712 for (i = 0; i < iColumns; i++) { |
|
1713 aoData.push({ "name": "bSortable_" + i, "value": oSettings.aoColumns[i].bSortable }); |
|
1714 } |
|
1715 } |
|
1716 |
|
1717 return aoData; |
|
1718 } |
|
1719 |
|
1720 |
|
1721 /** |
|
1722 * Add Ajax parameters from plug-ins |
|
1723 * @param {object} oSettings dataTables settings object |
|
1724 * @param array {objects} aoData name/value pairs to send to the server |
|
1725 * @memberof DataTable#oApi |
|
1726 */ |
|
1727 function _fnServerParams(oSettings, aoData) { |
|
1728 _fnCallbackFire(oSettings, 'aoServerParams', 'serverParams', [aoData]); |
|
1729 } |
|
1730 |
|
1731 |
|
1732 /** |
|
1733 * Data the data from the server (nuking the old) and redraw the table |
|
1734 * @param {object} oSettings dataTables settings object |
|
1735 * @param {object} json json data return from the server. |
|
1736 * @param {string} json.sEcho Tracking flag for DataTables to match requests |
|
1737 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering |
|
1738 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering |
|
1739 * @param {array} json.aaData The data to display on this page |
|
1740 * @param {string} [json.sColumns] Column ordering (sName, comma separated) |
|
1741 * @memberof DataTable#oApi |
|
1742 */ |
|
1743 function _fnAjaxUpdateDraw(oSettings, json) { |
|
1744 if (json.sEcho !== undefined) { |
|
1745 /* Protect against old returns over-writing a new one. Possible when you get |
|
1746 * very fast interaction, and later queries are completed much faster |
|
1747 */ |
|
1748 if (json.sEcho * 1 < oSettings.iDraw) { |
|
1749 return; |
|
1750 } |
|
1751 else { |
|
1752 oSettings.iDraw = json.sEcho * 1; |
|
1753 } |
|
1754 } |
|
1755 |
|
1756 if (!oSettings.oScroll.bInfinite || |
|
1757 (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered))) { |
|
1758 _fnClearTable(oSettings); |
|
1759 } |
|
1760 oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10); |
|
1761 oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10); |
|
1762 |
|
1763 /* Determine if reordering is required */ |
|
1764 var sOrdering = _fnColumnOrdering(oSettings); |
|
1765 var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering ); |
|
1766 var aiIndex; |
|
1767 if (bReOrder) { |
|
1768 aiIndex = _fnReOrderIndex(oSettings, json.sColumns); |
|
1769 } |
|
1770 |
|
1771 var aData = _fnGetObjectDataFn(oSettings.sAjaxDataProp)(json); |
|
1772 for (var i = 0, iLen = aData.length; i < iLen; i++) { |
|
1773 if (bReOrder) { |
|
1774 /* If we need to re-order, then create a new array with the correct order and add it */ |
|
1775 var aDataSorted = []; |
|
1776 for (var j = 0, jLen = oSettings.aoColumns.length; j < jLen; j++) { |
|
1777 aDataSorted.push(aData[i][ aiIndex[j] ]); |
|
1778 } |
|
1779 _fnAddData(oSettings, aDataSorted); |
|
1780 } |
|
1781 else { |
|
1782 /* No re-order required, sever got it "right" - just straight add */ |
|
1783 _fnAddData(oSettings, aData[i]); |
|
1784 } |
|
1785 } |
|
1786 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
|
1787 |
|
1788 oSettings.bAjaxDataGet = false; |
|
1789 _fnDraw(oSettings); |
|
1790 oSettings.bAjaxDataGet = true; |
|
1791 _fnProcessingDisplay(oSettings, false); |
|
1792 } |
|
1793 |
|
1794 |
|
1795 /** |
|
1796 * Generate the node required for filtering text |
|
1797 * @returns {node} Filter control element |
|
1798 * @param {object} oSettings dataTables settings object |
|
1799 * @memberof DataTable#oApi |
|
1800 */ |
|
1801 function _fnFeatureHtmlFilter(oSettings) { |
|
1802 var oPreviousSearch = oSettings.oPreviousSearch; |
|
1803 |
|
1804 var sSearchStr = oSettings.oLanguage.sSearch; |
|
1805 sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ? |
|
1806 sSearchStr.replace('_INPUT_', '<input type="text" />') : |
|
1807 sSearchStr === "" ? '<input type="text" />' : sSearchStr + ' <input type="text" />'; |
|
1808 |
|
1809 var nFilter = document.createElement('div'); |
|
1810 nFilter.className = oSettings.oClasses.sFilter; |
|
1811 nFilter.innerHTML = '<label>' + sSearchStr + '</label>'; |
|
1812 //nFilter.innerHTML = '<div class="input-group"><span class="input-group-addon"><i class="fa fa-search"></i></span>' + sSearchStr + '</div>'; |
|
1813 if (!oSettings.aanFeatures.f) { |
|
1814 nFilter.id = oSettings.sTableId + '_filter'; |
|
1815 } |
|
1816 |
|
1817 var jqFilter = $('input[type="text"]', nFilter); |
|
1818 |
|
1819 // Store a reference to the input element, so other input elements could be |
|
1820 // added to the filter wrapper if needed (submit button for example) |
|
1821 nFilter._DT_Input = jqFilter[0]; |
|
1822 |
|
1823 jqFilter.val(oPreviousSearch.sSearch.replace('"', '"')); |
|
1824 jqFilter.bind('keyup.DT', function (e) { |
|
1825 /* Update all other filter input elements for the new display */ |
|
1826 var n = oSettings.aanFeatures.f; |
|
1827 var val = this.value === "" ? "" : this.value; // mental IE8 fix :-( |
|
1828 |
|
1829 for (var i = 0, iLen = n.length; i < iLen; i++) { |
|
1830 if (n[i] != $(this).parents('div.dataTables_filter')[0]) { |
|
1831 $(n[i]._DT_Input).val(val); |
|
1832 } |
|
1833 } |
|
1834 |
|
1835 /* Now do the filter */ |
|
1836 if (val != oPreviousSearch.sSearch) { |
|
1837 _fnFilterComplete(oSettings, { |
|
1838 "sSearch": val, |
|
1839 "bRegex": oPreviousSearch.bRegex, |
|
1840 "bSmart": oPreviousSearch.bSmart, |
|
1841 "bCaseInsensitive": oPreviousSearch.bCaseInsensitive |
|
1842 }); |
|
1843 } |
|
1844 }); |
|
1845 |
|
1846 jqFilter |
|
1847 .attr('aria-controls', oSettings.sTableId) |
|
1848 .bind('keypress.DT', function (e) { |
|
1849 /* Prevent form submission */ |
|
1850 if (e.keyCode == 13) { |
|
1851 return false; |
|
1852 } |
|
1853 } |
|
1854 ); |
|
1855 |
|
1856 return nFilter; |
|
1857 } |
|
1858 |
|
1859 |
|
1860 /** |
|
1861 * Filter the table using both the global filter and column based filtering |
|
1862 * @param {object} oSettings dataTables settings object |
|
1863 * @param {object} oSearch search information |
|
1864 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) |
|
1865 * @memberof DataTable#oApi |
|
1866 */ |
|
1867 function _fnFilterComplete(oSettings, oInput, iForce) { |
|
1868 var oPrevSearch = oSettings.oPreviousSearch; |
|
1869 var aoPrevSearch = oSettings.aoPreSearchCols; |
|
1870 var fnSaveFilter = function (oFilter) { |
|
1871 /* Save the filtering values */ |
|
1872 oPrevSearch.sSearch = oFilter.sSearch; |
|
1873 oPrevSearch.bRegex = oFilter.bRegex; |
|
1874 oPrevSearch.bSmart = oFilter.bSmart; |
|
1875 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; |
|
1876 }; |
|
1877 |
|
1878 /* In server-side processing all filtering is done by the server, so no point hanging around here */ |
|
1879 if (!oSettings.oFeatures.bServerSide) { |
|
1880 /* Global filter */ |
|
1881 _fnFilter(oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive); |
|
1882 fnSaveFilter(oInput); |
|
1883 |
|
1884 /* Now do the individual column filter */ |
|
1885 for (var i = 0; i < oSettings.aoPreSearchCols.length; i++) { |
|
1886 _fnFilterColumn(oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex, |
|
1887 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive); |
|
1888 } |
|
1889 |
|
1890 /* Custom filtering */ |
|
1891 _fnFilterCustom(oSettings); |
|
1892 } |
|
1893 else { |
|
1894 fnSaveFilter(oInput); |
|
1895 } |
|
1896 |
|
1897 /* Tell the draw function we have been filtering */ |
|
1898 oSettings.bFiltered = true; |
|
1899 $(oSettings.oInstance).trigger('filter', oSettings); |
|
1900 |
|
1901 /* Redraw the table */ |
|
1902 oSettings._iDisplayStart = 0; |
|
1903 _fnCalculateEnd(oSettings); |
|
1904 _fnDraw(oSettings); |
|
1905 |
|
1906 /* Rebuild search array 'offline' */ |
|
1907 _fnBuildSearchArray(oSettings, 0); |
|
1908 } |
|
1909 |
|
1910 |
|
1911 /** |
|
1912 * Apply custom filtering functions |
|
1913 * @param {object} oSettings dataTables settings object |
|
1914 * @memberof DataTable#oApi |
|
1915 */ |
|
1916 function _fnFilterCustom(oSettings) { |
|
1917 var afnFilters = DataTable.ext.afnFiltering; |
|
1918 var aiFilterColumns = _fnGetColumns(oSettings, 'bSearchable'); |
|
1919 |
|
1920 for (var i = 0, iLen = afnFilters.length; i < iLen; i++) { |
|
1921 var iCorrector = 0; |
|
1922 for (var j = 0, jLen = oSettings.aiDisplay.length; j < jLen; j++) { |
|
1923 var iDisIndex = oSettings.aiDisplay[j - iCorrector]; |
|
1924 var bTest = afnFilters[i]( |
|
1925 oSettings, |
|
1926 _fnGetRowData(oSettings, iDisIndex, 'filter', aiFilterColumns), |
|
1927 iDisIndex |
|
1928 ); |
|
1929 |
|
1930 /* Check if we should use this row based on the filtering function */ |
|
1931 if (!bTest) { |
|
1932 oSettings.aiDisplay.splice(j - iCorrector, 1); |
|
1933 iCorrector++; |
|
1934 } |
|
1935 } |
|
1936 } |
|
1937 } |
|
1938 |
|
1939 |
|
1940 /** |
|
1941 * Filter the table on a per-column basis |
|
1942 * @param {object} oSettings dataTables settings object |
|
1943 * @param {string} sInput string to filter on |
|
1944 * @param {int} iColumn column to filter |
|
1945 * @param {bool} bRegex treat search string as a regular expression or not |
|
1946 * @param {bool} bSmart use smart filtering or not |
|
1947 * @param {bool} bCaseInsensitive Do case insenstive matching or not |
|
1948 * @memberof DataTable#oApi |
|
1949 */ |
|
1950 function _fnFilterColumn(oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive) { |
|
1951 if (sInput === "") { |
|
1952 return; |
|
1953 } |
|
1954 |
|
1955 var iIndexCorrector = 0; |
|
1956 var rpSearch = _fnFilterCreateSearch(sInput, bRegex, bSmart, bCaseInsensitive); |
|
1957 |
|
1958 for (var i = oSettings.aiDisplay.length - 1; i >= 0; i--) { |
|
1959 var sData = _fnDataToSearch(_fnGetCellData(oSettings, oSettings.aiDisplay[i], iColumn, 'filter'), |
|
1960 oSettings.aoColumns[iColumn].sType); |
|
1961 if (!rpSearch.test(sData)) { |
|
1962 oSettings.aiDisplay.splice(i, 1); |
|
1963 iIndexCorrector++; |
|
1964 } |
|
1965 } |
|
1966 } |
|
1967 |
|
1968 |
|
1969 /** |
|
1970 * Filter the data table based on user input and draw the table |
|
1971 * @param {object} oSettings dataTables settings object |
|
1972 * @param {string} sInput string to filter on |
|
1973 * @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0) |
|
1974 * @param {bool} bRegex treat as a regular expression or not |
|
1975 * @param {bool} bSmart perform smart filtering or not |
|
1976 * @param {bool} bCaseInsensitive Do case insenstive matching or not |
|
1977 * @memberof DataTable#oApi |
|
1978 */ |
|
1979 function _fnFilter(oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive) { |
|
1980 var i; |
|
1981 var rpSearch = _fnFilterCreateSearch(sInput, bRegex, bSmart, bCaseInsensitive); |
|
1982 var oPrevSearch = oSettings.oPreviousSearch; |
|
1983 |
|
1984 /* Check if we are forcing or not - optional parameter */ |
|
1985 if (!iForce) { |
|
1986 iForce = 0; |
|
1987 } |
|
1988 |
|
1989 /* Need to take account of custom filtering functions - always filter */ |
|
1990 if (DataTable.ext.afnFiltering.length !== 0) { |
|
1991 iForce = 1; |
|
1992 } |
|
1993 |
|
1994 /* |
|
1995 * If the input is blank - we want the full data set |
|
1996 */ |
|
1997 if (sInput.length <= 0) { |
|
1998 oSettings.aiDisplay.splice(0, oSettings.aiDisplay.length); |
|
1999 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
|
2000 } |
|
2001 else { |
|
2002 /* |
|
2003 * We are starting a new search or the new search string is smaller |
|
2004 * then the old one (i.e. delete). Search from the master array |
|
2005 */ |
|
2006 if (oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length || |
|
2007 oPrevSearch.sSearch.length > sInput.length || iForce == 1 || |
|
2008 sInput.indexOf(oPrevSearch.sSearch) !== 0) { |
|
2009 /* Nuke the old display array - we are going to rebuild it */ |
|
2010 oSettings.aiDisplay.splice(0, oSettings.aiDisplay.length); |
|
2011 |
|
2012 /* Force a rebuild of the search array */ |
|
2013 _fnBuildSearchArray(oSettings, 1); |
|
2014 |
|
2015 /* Search through all records to populate the search array |
|
2016 * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 |
|
2017 * mapping |
|
2018 */ |
|
2019 for (i = 0; i < oSettings.aiDisplayMaster.length; i++) { |
|
2020 if (rpSearch.test(oSettings.asDataSearch[i])) { |
|
2021 oSettings.aiDisplay.push(oSettings.aiDisplayMaster[i]); |
|
2022 } |
|
2023 } |
|
2024 } |
|
2025 else { |
|
2026 /* Using old search array - refine it - do it this way for speed |
|
2027 * Don't have to search the whole master array again |
|
2028 */ |
|
2029 var iIndexCorrector = 0; |
|
2030 |
|
2031 /* Search the current results */ |
|
2032 for (i = 0; i < oSettings.asDataSearch.length; i++) { |
|
2033 if (!rpSearch.test(oSettings.asDataSearch[i])) { |
|
2034 oSettings.aiDisplay.splice(i - iIndexCorrector, 1); |
|
2035 iIndexCorrector++; |
|
2036 } |
|
2037 } |
|
2038 } |
|
2039 } |
|
2040 } |
|
2041 |
|
2042 |
|
2043 /** |
|
2044 * Create an array which can be quickly search through |
|
2045 * @param {object} oSettings dataTables settings object |
|
2046 * @param {int} iMaster use the master data array - optional |
|
2047 * @memberof DataTable#oApi |
|
2048 */ |
|
2049 function _fnBuildSearchArray(oSettings, iMaster) { |
|
2050 if (!oSettings.oFeatures.bServerSide) { |
|
2051 /* Clear out the old data */ |
|
2052 oSettings.asDataSearch = []; |
|
2053 |
|
2054 var aiFilterColumns = _fnGetColumns(oSettings, 'bSearchable'); |
|
2055 var aiIndex = (iMaster === 1) ? |
|
2056 oSettings.aiDisplayMaster : |
|
2057 oSettings.aiDisplay; |
|
2058 |
|
2059 for (var i = 0, iLen = aiIndex.length; i < iLen; i++) { |
|
2060 oSettings.asDataSearch[i] = _fnBuildSearchRow( |
|
2061 oSettings, |
|
2062 _fnGetRowData(oSettings, aiIndex[i], 'filter', aiFilterColumns) |
|
2063 ); |
|
2064 } |
|
2065 } |
|
2066 } |
|
2067 |
|
2068 |
|
2069 /** |
|
2070 * Create a searchable string from a single data row |
|
2071 * @param {object} oSettings dataTables settings object |
|
2072 * @param {array} aData Row data array to use for the data to search |
|
2073 * @memberof DataTable#oApi |
|
2074 */ |
|
2075 function _fnBuildSearchRow(oSettings, aData) { |
|
2076 var sSearch = aData.join(' '); |
|
2077 |
|
2078 /* If it looks like there is an HTML entity in the string, attempt to decode it */ |
|
2079 if (sSearch.indexOf('&') !== -1) { |
|
2080 sSearch = $('<div>').html(sSearch).text(); |
|
2081 } |
|
2082 |
|
2083 // Strip newline characters |
|
2084 return sSearch.replace(/[\n\r]/g, " "); |
|
2085 } |
|
2086 |
|
2087 /** |
|
2088 * Build a regular expression object suitable for searching a table |
|
2089 * @param {string} sSearch string to search for |
|
2090 * @param {bool} bRegex treat as a regular expression or not |
|
2091 * @param {bool} bSmart perform smart filtering or not |
|
2092 * @param {bool} bCaseInsensitive Do case insensitive matching or not |
|
2093 * @returns {RegExp} constructed object |
|
2094 * @memberof DataTable#oApi |
|
2095 */ |
|
2096 function _fnFilterCreateSearch(sSearch, bRegex, bSmart, bCaseInsensitive) { |
|
2097 var asSearch, sRegExpString; |
|
2098 |
|
2099 if (bSmart) { |
|
2100 /* Generate the regular expression to use. Something along the lines of: |
|
2101 * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$ |
|
2102 */ |
|
2103 asSearch = bRegex ? sSearch.split(' ') : _fnEscapeRegex(sSearch).split(' '); |
|
2104 sRegExpString = '^(?=.*?' + asSearch.join(')(?=.*?') + ').*$'; |
|
2105 return new RegExp(sRegExpString, bCaseInsensitive ? "i" : ""); |
|
2106 } |
|
2107 else { |
|
2108 sSearch = bRegex ? sSearch : _fnEscapeRegex(sSearch); |
|
2109 return new RegExp(sSearch, bCaseInsensitive ? "i" : ""); |
|
2110 } |
|
2111 } |
|
2112 |
|
2113 |
|
2114 /** |
|
2115 * Convert raw data into something that the user can search on |
|
2116 * @param {string} sData data to be modified |
|
2117 * @param {string} sType data type |
|
2118 * @returns {string} search string |
|
2119 * @memberof DataTable#oApi |
|
2120 */ |
|
2121 function _fnDataToSearch(sData, sType) { |
|
2122 if (typeof DataTable.ext.ofnSearch[sType] === "function") { |
|
2123 return DataTable.ext.ofnSearch[sType](sData); |
|
2124 } |
|
2125 else if (sData === null) { |
|
2126 return ''; |
|
2127 } |
|
2128 else if (sType == "html") { |
|
2129 return sData.replace(/[\r\n]/g, " ").replace(/<.*?>/g, ""); |
|
2130 } |
|
2131 else if (typeof sData === "string") { |
|
2132 return sData.replace(/[\r\n]/g, " "); |
|
2133 } |
|
2134 return sData; |
|
2135 } |
|
2136 |
|
2137 |
|
2138 /** |
|
2139 * scape a string such that it can be used in a regular expression |
|
2140 * @param {string} sVal string to escape |
|
2141 * @returns {string} escaped string |
|
2142 * @memberof DataTable#oApi |
|
2143 */ |
|
2144 function _fnEscapeRegex(sVal) { |
|
2145 var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ]; |
|
2146 var reReplace = new RegExp('(\\' + acEscape.join('|\\') + ')', 'g'); |
|
2147 return sVal.replace(reReplace, '\\$1'); |
|
2148 } |
|
2149 |
|
2150 |
|
2151 /** |
|
2152 * Generate the node required for the info display |
|
2153 * @param {object} oSettings dataTables settings object |
|
2154 * @returns {node} Information element |
|
2155 * @memberof DataTable#oApi |
|
2156 */ |
|
2157 function _fnFeatureHtmlInfo(oSettings) { |
|
2158 var nInfo = document.createElement('div'); |
|
2159 nInfo.className = oSettings.oClasses.sInfo; |
|
2160 |
|
2161 /* Actions that are to be taken once only for this feature */ |
|
2162 if (!oSettings.aanFeatures.i) { |
|
2163 /* Add draw callback */ |
|
2164 oSettings.aoDrawCallback.push({ |
|
2165 "fn": _fnUpdateInfo, |
|
2166 "sName": "information" |
|
2167 }); |
|
2168 |
|
2169 /* Add id */ |
|
2170 nInfo.id = oSettings.sTableId + '_info'; |
|
2171 } |
|
2172 oSettings.nTable.setAttribute('aria-describedby', oSettings.sTableId + '_info'); |
|
2173 |
|
2174 return nInfo; |
|
2175 } |
|
2176 |
|
2177 |
|
2178 /** |
|
2179 * Update the information elements in the display |
|
2180 * @param {object} oSettings dataTables settings object |
|
2181 * @memberof DataTable#oApi |
|
2182 */ |
|
2183 function _fnUpdateInfo(oSettings) { |
|
2184 /* Show information about the table */ |
|
2185 if (!oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0) { |
|
2186 return; |
|
2187 } |
|
2188 |
|
2189 var |
|
2190 oLang = oSettings.oLanguage, |
|
2191 iStart = oSettings._iDisplayStart + 1, |
|
2192 iEnd = oSettings.fnDisplayEnd(), |
|
2193 iMax = oSettings.fnRecordsTotal(), |
|
2194 iTotal = oSettings.fnRecordsDisplay(), |
|
2195 sOut; |
|
2196 |
|
2197 if (iTotal === 0) { |
|
2198 /* Empty record set */ |
|
2199 sOut = oLang.sInfoEmpty; |
|
2200 } |
|
2201 else { |
|
2202 /* Normal record set */ |
|
2203 sOut = oLang.sInfo; |
|
2204 } |
|
2205 |
|
2206 if (iTotal != iMax) { |
|
2207 /* Record set after filtering */ |
|
2208 sOut += ' ' + oLang.sInfoFiltered; |
|
2209 } |
|
2210 |
|
2211 // Convert the macros |
|
2212 sOut += oLang.sInfoPostFix; |
|
2213 sOut = _fnInfoMacros(oSettings, sOut); |
|
2214 |
|
2215 if (oLang.fnInfoCallback !== null) { |
|
2216 sOut = oLang.fnInfoCallback.call(oSettings.oInstance, |
|
2217 oSettings, iStart, iEnd, iMax, iTotal, sOut); |
|
2218 } |
|
2219 |
|
2220 var n = oSettings.aanFeatures.i; |
|
2221 for (var i = 0, iLen = n.length; i < iLen; i++) { |
|
2222 $(n[i]).html(sOut); |
|
2223 } |
|
2224 } |
|
2225 |
|
2226 |
|
2227 function _fnInfoMacros(oSettings, str) { |
|
2228 var |
|
2229 iStart = oSettings._iDisplayStart + 1, |
|
2230 sStart = oSettings.fnFormatNumber(iStart), |
|
2231 iEnd = oSettings.fnDisplayEnd(), |
|
2232 sEnd = oSettings.fnFormatNumber(iEnd), |
|
2233 iTotal = oSettings.fnRecordsDisplay(), |
|
2234 sTotal = oSettings.fnFormatNumber(iTotal), |
|
2235 iMax = oSettings.fnRecordsTotal(), |
|
2236 sMax = oSettings.fnFormatNumber(iMax); |
|
2237 |
|
2238 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only |
|
2239 // internally |
|
2240 if (oSettings.oScroll.bInfinite) { |
|
2241 sStart = oSettings.fnFormatNumber(1); |
|
2242 } |
|
2243 |
|
2244 return str. |
|
2245 replace(/_START_/g, sStart). |
|
2246 replace(/_END_/g, sEnd). |
|
2247 replace(/_TOTAL_/g, sTotal). |
|
2248 replace(/_MAX_/g, sMax); |
|
2249 } |
|
2250 |
|
2251 |
|
2252 /** |
|
2253 * Draw the table for the first time, adding all required features |
|
2254 * @param {object} oSettings dataTables settings object |
|
2255 * @memberof DataTable#oApi |
|
2256 */ |
|
2257 function _fnInitialise(oSettings) { |
|
2258 var i, iLen, iAjaxStart = oSettings.iInitDisplayStart; |
|
2259 |
|
2260 /* Ensure that the table data is fully initialised */ |
|
2261 if (oSettings.bInitialised === false) { |
|
2262 setTimeout(function () { |
|
2263 _fnInitialise(oSettings); |
|
2264 }, 200); |
|
2265 return; |
|
2266 } |
|
2267 |
|
2268 /* Show the display HTML options */ |
|
2269 _fnAddOptionsHtml(oSettings); |
|
2270 |
|
2271 /* Build and draw the header / footer for the table */ |
|
2272 _fnBuildHead(oSettings); |
|
2273 _fnDrawHead(oSettings, oSettings.aoHeader); |
|
2274 if (oSettings.nTFoot) { |
|
2275 _fnDrawHead(oSettings, oSettings.aoFooter); |
|
2276 } |
|
2277 |
|
2278 /* Okay to show that something is going on now */ |
|
2279 _fnProcessingDisplay(oSettings, true); |
|
2280 |
|
2281 /* Calculate sizes for columns */ |
|
2282 if (oSettings.oFeatures.bAutoWidth) { |
|
2283 _fnCalculateColumnWidths(oSettings); |
|
2284 } |
|
2285 |
|
2286 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
2287 if (oSettings.aoColumns[i].sWidth !== null) { |
|
2288 oSettings.aoColumns[i].nTh.style.width = _fnStringToCss(oSettings.aoColumns[i].sWidth); |
|
2289 } |
|
2290 } |
|
2291 |
|
2292 /* If there is default sorting required - let's do it. The sort function will do the |
|
2293 * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows |
|
2294 * the table to look initialised for Ajax sourcing data (show 'loading' message possibly) |
|
2295 */ |
|
2296 if (oSettings.oFeatures.bSort) { |
|
2297 _fnSort(oSettings); |
|
2298 } |
|
2299 else if (oSettings.oFeatures.bFilter) { |
|
2300 _fnFilterComplete(oSettings, oSettings.oPreviousSearch); |
|
2301 } |
|
2302 else { |
|
2303 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
|
2304 _fnCalculateEnd(oSettings); |
|
2305 _fnDraw(oSettings); |
|
2306 } |
|
2307 |
|
2308 /* if there is an ajax source load the data */ |
|
2309 if (oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide) { |
|
2310 var aoData = []; |
|
2311 _fnServerParams(oSettings, aoData); |
|
2312 oSettings.fnServerData.call(oSettings.oInstance, oSettings.sAjaxSource, aoData, function (json) { |
|
2313 var aData = (oSettings.sAjaxDataProp !== "") ? |
|
2314 _fnGetObjectDataFn(oSettings.sAjaxDataProp)(json) : json; |
|
2315 |
|
2316 /* Got the data - add it to the table */ |
|
2317 for (i = 0; i < aData.length; i++) { |
|
2318 _fnAddData(oSettings, aData[i]); |
|
2319 } |
|
2320 |
|
2321 /* Reset the init display for cookie saving. We've already done a filter, and |
|
2322 * therefore cleared it before. So we need to make it appear 'fresh' |
|
2323 */ |
|
2324 oSettings.iInitDisplayStart = iAjaxStart; |
|
2325 |
|
2326 if (oSettings.oFeatures.bSort) { |
|
2327 _fnSort(oSettings); |
|
2328 } |
|
2329 else { |
|
2330 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
|
2331 _fnCalculateEnd(oSettings); |
|
2332 _fnDraw(oSettings); |
|
2333 } |
|
2334 |
|
2335 _fnProcessingDisplay(oSettings, false); |
|
2336 _fnInitComplete(oSettings, json); |
|
2337 }, oSettings); |
|
2338 return; |
|
2339 } |
|
2340 |
|
2341 /* Server-side processing initialisation complete is done at the end of _fnDraw */ |
|
2342 if (!oSettings.oFeatures.bServerSide) { |
|
2343 _fnProcessingDisplay(oSettings, false); |
|
2344 _fnInitComplete(oSettings); |
|
2345 } |
|
2346 } |
|
2347 |
|
2348 |
|
2349 /** |
|
2350 * Draw the table for the first time, adding all required features |
|
2351 * @param {object} oSettings dataTables settings object |
|
2352 * @param {object} [json] JSON from the server that completed the table, if using Ajax source |
|
2353 * with client-side processing (optional) |
|
2354 * @memberof DataTable#oApi |
|
2355 */ |
|
2356 function _fnInitComplete(oSettings, json) { |
|
2357 oSettings._bInitComplete = true; |
|
2358 _fnCallbackFire(oSettings, 'aoInitComplete', 'init', [oSettings, json]); |
|
2359 } |
|
2360 |
|
2361 |
|
2362 /** |
|
2363 * Language compatibility - when certain options are given, and others aren't, we |
|
2364 * need to duplicate the values over, in order to provide backwards compatibility |
|
2365 * with older language files. |
|
2366 * @param {object} oSettings dataTables settings object |
|
2367 * @memberof DataTable#oApi |
|
2368 */ |
|
2369 function _fnLanguageCompat(oLanguage) { |
|
2370 var oDefaults = DataTable.defaults.oLanguage; |
|
2371 |
|
2372 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as |
|
2373 * sZeroRecords - assuming that is given. |
|
2374 */ |
|
2375 if (!oLanguage.sEmptyTable && oLanguage.sZeroRecords && |
|
2376 oDefaults.sEmptyTable === "No data available in table") { |
|
2377 _fnMap(oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable'); |
|
2378 } |
|
2379 |
|
2380 /* Likewise with loading records */ |
|
2381 if (!oLanguage.sLoadingRecords && oLanguage.sZeroRecords && |
|
2382 oDefaults.sLoadingRecords === "Loading...") { |
|
2383 _fnMap(oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords'); |
|
2384 } |
|
2385 } |
|
2386 |
|
2387 |
|
2388 /** |
|
2389 * Generate the node required for user display length changing |
|
2390 * @param {object} oSettings dataTables settings object |
|
2391 * @returns {node} Display length feature node |
|
2392 * @memberof DataTable#oApi |
|
2393 */ |
|
2394 function _fnFeatureHtmlLength(oSettings) { |
|
2395 if (oSettings.oScroll.bInfinite) { |
|
2396 return null; |
|
2397 } |
|
2398 |
|
2399 /* This can be overruled by not using the _MENU_ var/macro in the language variable */ |
|
2400 var sName = 'name="' + oSettings.sTableId + '_length"'; |
|
2401 var sStdMenu = '<select size="1" ' + sName + '>'; |
|
2402 var i, iLen; |
|
2403 var aLengthMenu = oSettings.aLengthMenu; |
|
2404 |
|
2405 if (aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && |
|
2406 typeof aLengthMenu[1] === 'object') { |
|
2407 for (i = 0, iLen = aLengthMenu[0].length; i < iLen; i++) { |
|
2408 sStdMenu += '<option value="' + aLengthMenu[0][i] + '">' + aLengthMenu[1][i] + '</option>'; |
|
2409 } |
|
2410 } |
|
2411 else { |
|
2412 for (i = 0, iLen = aLengthMenu.length; i < iLen; i++) { |
|
2413 sStdMenu += '<option value="' + aLengthMenu[i] + '">' + aLengthMenu[i] + '</option>'; |
|
2414 } |
|
2415 } |
|
2416 sStdMenu += '</select>'; |
|
2417 |
|
2418 var nLength = document.createElement('div'); |
|
2419 if (!oSettings.aanFeatures.l) { |
|
2420 nLength.id = oSettings.sTableId + '_length'; |
|
2421 } |
|
2422 nLength.className = oSettings.oClasses.sLength; |
|
2423 nLength.innerHTML = '<label>' + oSettings.oLanguage.sLengthMenu.replace('_MENU_', sStdMenu) + '</label>'; |
|
2424 |
|
2425 /* |
|
2426 * Set the length to the current display length - thanks to Andrea Pavlovic for this fix, |
|
2427 * and Stefan Skopnik for fixing the fix! |
|
2428 */ |
|
2429 $('select option[value="' + oSettings._iDisplayLength + '"]', nLength).attr("selected", true); |
|
2430 |
|
2431 $('select', nLength).bind('change.DT', function (e) { |
|
2432 var iVal = $(this).val(); |
|
2433 |
|
2434 /* Update all other length options for the new display */ |
|
2435 var n = oSettings.aanFeatures.l; |
|
2436 for (i = 0, iLen = n.length; i < iLen; i++) { |
|
2437 if (n[i] != this.parentNode) { |
|
2438 $('select', n[i]).val(iVal); |
|
2439 } |
|
2440 } |
|
2441 |
|
2442 /* Redraw the table */ |
|
2443 oSettings._iDisplayLength = parseInt(iVal, 10); |
|
2444 _fnCalculateEnd(oSettings); |
|
2445 |
|
2446 /* If we have space to show extra rows (backing up from the end point - then do so */ |
|
2447 if (oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay()) { |
|
2448 oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength; |
|
2449 if (oSettings._iDisplayStart < 0) { |
|
2450 oSettings._iDisplayStart = 0; |
|
2451 } |
|
2452 } |
|
2453 |
|
2454 if (oSettings._iDisplayLength == -1) { |
|
2455 oSettings._iDisplayStart = 0; |
|
2456 } |
|
2457 |
|
2458 _fnDraw(oSettings); |
|
2459 }); |
|
2460 |
|
2461 |
|
2462 $('select', nLength).attr('aria-controls', oSettings.sTableId); |
|
2463 |
|
2464 return nLength; |
|
2465 } |
|
2466 |
|
2467 |
|
2468 /** |
|
2469 * Recalculate the end point based on the start point |
|
2470 * @param {object} oSettings dataTables settings object |
|
2471 * @memberof DataTable#oApi |
|
2472 */ |
|
2473 function _fnCalculateEnd(oSettings) { |
|
2474 if (oSettings.oFeatures.bPaginate === false) { |
|
2475 oSettings._iDisplayEnd = oSettings.aiDisplay.length; |
|
2476 } |
|
2477 else { |
|
2478 /* Set the end point of the display - based on how many elements there are |
|
2479 * still to display |
|
2480 */ |
|
2481 if (oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length || |
|
2482 oSettings._iDisplayLength == -1) { |
|
2483 oSettings._iDisplayEnd = oSettings.aiDisplay.length; |
|
2484 } |
|
2485 else { |
|
2486 oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength; |
|
2487 } |
|
2488 } |
|
2489 } |
|
2490 |
|
2491 |
|
2492 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
2493 * Note that most of the paging logic is done in |
|
2494 * DataTable.ext.oPagination |
|
2495 */ |
|
2496 |
|
2497 /** |
|
2498 * Generate the node required for default pagination |
|
2499 * @param {object} oSettings dataTables settings object |
|
2500 * @returns {node} Pagination feature node |
|
2501 * @memberof DataTable#oApi |
|
2502 */ |
|
2503 function _fnFeatureHtmlPaginate(oSettings) { |
|
2504 if (oSettings.oScroll.bInfinite) { |
|
2505 return null; |
|
2506 } |
|
2507 |
|
2508 var nPaginate = document.createElement('div'); |
|
2509 nPaginate.className = oSettings.oClasses.sPaging + oSettings.sPaginationType; |
|
2510 |
|
2511 DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit(oSettings, nPaginate, |
|
2512 function (oSettings) { |
|
2513 _fnCalculateEnd(oSettings); |
|
2514 _fnDraw(oSettings); |
|
2515 } |
|
2516 ); |
|
2517 |
|
2518 /* Add a draw callback for the pagination on first instance, to update the paging display */ |
|
2519 if (!oSettings.aanFeatures.p) { |
|
2520 oSettings.aoDrawCallback.push({ |
|
2521 "fn": function (oSettings) { |
|
2522 DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate(oSettings, function (oSettings) { |
|
2523 _fnCalculateEnd(oSettings); |
|
2524 _fnDraw(oSettings); |
|
2525 }); |
|
2526 }, |
|
2527 "sName": "pagination" |
|
2528 }); |
|
2529 } |
|
2530 return nPaginate; |
|
2531 } |
|
2532 |
|
2533 |
|
2534 /** |
|
2535 * Alter the display settings to change the page |
|
2536 * @param {object} oSettings dataTables settings object |
|
2537 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" |
|
2538 * or page number to jump to (integer) |
|
2539 * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1 |
|
2540 * @memberof DataTable#oApi |
|
2541 */ |
|
2542 function _fnPageChange(oSettings, mAction) { |
|
2543 var iOldStart = oSettings._iDisplayStart; |
|
2544 |
|
2545 if (typeof mAction === "number") { |
|
2546 oSettings._iDisplayStart = mAction * oSettings._iDisplayLength; |
|
2547 if (oSettings._iDisplayStart > oSettings.fnRecordsDisplay()) { |
|
2548 oSettings._iDisplayStart = 0; |
|
2549 } |
|
2550 } |
|
2551 else if (mAction == "first") { |
|
2552 oSettings._iDisplayStart = 0; |
|
2553 } |
|
2554 else if (mAction == "previous") { |
|
2555 oSettings._iDisplayStart = oSettings._iDisplayLength >= 0 ? |
|
2556 oSettings._iDisplayStart - oSettings._iDisplayLength : |
|
2557 0; |
|
2558 |
|
2559 /* Correct for under-run */ |
|
2560 if (oSettings._iDisplayStart < 0) { |
|
2561 oSettings._iDisplayStart = 0; |
|
2562 } |
|
2563 } |
|
2564 else if (mAction == "next") { |
|
2565 if (oSettings._iDisplayLength >= 0) { |
|
2566 /* Make sure we are not over running the display array */ |
|
2567 if (oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay()) { |
|
2568 oSettings._iDisplayStart += oSettings._iDisplayLength; |
|
2569 } |
|
2570 } |
|
2571 else { |
|
2572 oSettings._iDisplayStart = 0; |
|
2573 } |
|
2574 } |
|
2575 else if (mAction == "last") { |
|
2576 if (oSettings._iDisplayLength >= 0) { |
|
2577 var iPages = parseInt((oSettings.fnRecordsDisplay() - 1) / oSettings._iDisplayLength, 10) + 1; |
|
2578 oSettings._iDisplayStart = (iPages - 1) * oSettings._iDisplayLength; |
|
2579 } |
|
2580 else { |
|
2581 oSettings._iDisplayStart = 0; |
|
2582 } |
|
2583 } |
|
2584 else { |
|
2585 _fnLog(oSettings, 0, "Unknown paging action: " + mAction); |
|
2586 } |
|
2587 $(oSettings.oInstance).trigger('page', oSettings); |
|
2588 |
|
2589 return iOldStart != oSettings._iDisplayStart; |
|
2590 } |
|
2591 |
|
2592 |
|
2593 /** |
|
2594 * Generate the node required for the processing node |
|
2595 * @param {object} oSettings dataTables settings object |
|
2596 * @returns {node} Processing element |
|
2597 * @memberof DataTable#oApi |
|
2598 */ |
|
2599 function _fnFeatureHtmlProcessing(oSettings) { |
|
2600 var nProcessing = document.createElement('div'); |
|
2601 |
|
2602 if (!oSettings.aanFeatures.r) { |
|
2603 nProcessing.id = oSettings.sTableId + '_processing'; |
|
2604 } |
|
2605 nProcessing.innerHTML = oSettings.oLanguage.sProcessing; |
|
2606 nProcessing.className = oSettings.oClasses.sProcessing; |
|
2607 oSettings.nTable.parentNode.insertBefore(nProcessing, oSettings.nTable); |
|
2608 |
|
2609 return nProcessing; |
|
2610 } |
|
2611 |
|
2612 |
|
2613 /** |
|
2614 * Display or hide the processing indicator |
|
2615 * @param {object} oSettings dataTables settings object |
|
2616 * @param {bool} bShow Show the processing indicator (true) or not (false) |
|
2617 * @memberof DataTable#oApi |
|
2618 */ |
|
2619 function _fnProcessingDisplay(oSettings, bShow) { |
|
2620 if (oSettings.oFeatures.bProcessing) { |
|
2621 var an = oSettings.aanFeatures.r; |
|
2622 for (var i = 0, iLen = an.length; i < iLen; i++) { |
|
2623 an[i].style.visibility = bShow ? "visible" : "hidden"; |
|
2624 } |
|
2625 } |
|
2626 |
|
2627 $(oSettings.oInstance).trigger('processing', [oSettings, bShow]); |
|
2628 } |
|
2629 |
|
2630 /** |
|
2631 * Add any control elements for the table - specifically scrolling |
|
2632 * @param {object} oSettings dataTables settings object |
|
2633 * @returns {node} Node to add to the DOM |
|
2634 * @memberof DataTable#oApi |
|
2635 */ |
|
2636 function _fnFeatureHtmlTable(oSettings) { |
|
2637 /* Check if scrolling is enabled or not - if not then leave the DOM unaltered */ |
|
2638 if (oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "") { |
|
2639 return oSettings.nTable; |
|
2640 } |
|
2641 |
|
2642 /* |
|
2643 * The HTML structure that we want to generate in this function is: |
|
2644 * div - nScroller |
|
2645 * div - nScrollHead |
|
2646 * div - nScrollHeadInner |
|
2647 * table - nScrollHeadTable |
|
2648 * thead - nThead |
|
2649 * div - nScrollBody |
|
2650 * table - oSettings.nTable |
|
2651 * thead - nTheadSize |
|
2652 * tbody - nTbody |
|
2653 * div - nScrollFoot |
|
2654 * div - nScrollFootInner |
|
2655 * table - nScrollFootTable |
|
2656 * tfoot - nTfoot |
|
2657 */ |
|
2658 var |
|
2659 nScroller = document.createElement('div'), |
|
2660 nScrollHead = document.createElement('div'), |
|
2661 nScrollHeadInner = document.createElement('div'), |
|
2662 nScrollBody = document.createElement('div'), |
|
2663 nScrollFoot = document.createElement('div'), |
|
2664 nScrollFootInner = document.createElement('div'), |
|
2665 nScrollHeadTable = oSettings.nTable.cloneNode(false), |
|
2666 nScrollFootTable = oSettings.nTable.cloneNode(false), |
|
2667 nThead = oSettings.nTable.getElementsByTagName('thead')[0], |
|
2668 nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : |
|
2669 oSettings.nTable.getElementsByTagName('tfoot')[0], |
|
2670 oClasses = oSettings.oClasses; |
|
2671 |
|
2672 nScrollHead.appendChild(nScrollHeadInner); |
|
2673 nScrollFoot.appendChild(nScrollFootInner); |
|
2674 nScrollBody.appendChild(oSettings.nTable); |
|
2675 nScroller.appendChild(nScrollHead); |
|
2676 nScroller.appendChild(nScrollBody); |
|
2677 nScrollHeadInner.appendChild(nScrollHeadTable); |
|
2678 nScrollHeadTable.appendChild(nThead); |
|
2679 if (nTfoot !== null) { |
|
2680 nScroller.appendChild(nScrollFoot); |
|
2681 nScrollFootInner.appendChild(nScrollFootTable); |
|
2682 nScrollFootTable.appendChild(nTfoot); |
|
2683 } |
|
2684 |
|
2685 nScroller.className = oClasses.sScrollWrapper; |
|
2686 nScrollHead.className = oClasses.sScrollHead; |
|
2687 nScrollHeadInner.className = oClasses.sScrollHeadInner; |
|
2688 nScrollBody.className = oClasses.sScrollBody; |
|
2689 nScrollFoot.className = oClasses.sScrollFoot; |
|
2690 nScrollFootInner.className = oClasses.sScrollFootInner; |
|
2691 |
|
2692 if (oSettings.oScroll.bAutoCss) { |
|
2693 nScrollHead.style.overflow = "hidden"; |
|
2694 nScrollHead.style.position = "relative"; |
|
2695 nScrollFoot.style.overflow = "hidden"; |
|
2696 nScrollBody.style.overflow = "auto"; |
|
2697 } |
|
2698 |
|
2699 nScrollHead.style.border = "0"; |
|
2700 nScrollHead.style.width = "100%"; |
|
2701 nScrollFoot.style.border = "0"; |
|
2702 nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ? |
|
2703 oSettings.oScroll.sXInner : "100%"; |
|
2704 /* will be overwritten */ |
|
2705 |
|
2706 /* Modify attributes to respect the clones */ |
|
2707 nScrollHeadTable.removeAttribute('id'); |
|
2708 nScrollHeadTable.style.marginLeft = "0"; |
|
2709 oSettings.nTable.style.marginLeft = "0"; |
|
2710 if (nTfoot !== null) { |
|
2711 nScrollFootTable.removeAttribute('id'); |
|
2712 nScrollFootTable.style.marginLeft = "0"; |
|
2713 } |
|
2714 |
|
2715 /* Move caption elements from the body to the header, footer or leave where it is |
|
2716 * depending on the configuration. Note that the DTD says there can be only one caption */ |
|
2717 var nCaption = $(oSettings.nTable).children('caption'); |
|
2718 if (nCaption.length > 0) { |
|
2719 nCaption = nCaption[0]; |
|
2720 if (nCaption._captionSide === "top") { |
|
2721 nScrollHeadTable.appendChild(nCaption); |
|
2722 } |
|
2723 else if (nCaption._captionSide === "bottom" && nTfoot) { |
|
2724 nScrollFootTable.appendChild(nCaption); |
|
2725 } |
|
2726 } |
|
2727 |
|
2728 /* |
|
2729 * Sizing |
|
2730 */ |
|
2731 /* When x-scrolling add the width and a scroller to move the header with the body */ |
|
2732 if (oSettings.oScroll.sX !== "") { |
|
2733 nScrollHead.style.width = _fnStringToCss(oSettings.oScroll.sX); |
|
2734 nScrollBody.style.width = _fnStringToCss(oSettings.oScroll.sX); |
|
2735 |
|
2736 if (nTfoot !== null) { |
|
2737 nScrollFoot.style.width = _fnStringToCss(oSettings.oScroll.sX); |
|
2738 } |
|
2739 |
|
2740 /* When the body is scrolled, then we also want to scroll the headers */ |
|
2741 $(nScrollBody).scroll(function (e) { |
|
2742 nScrollHead.scrollLeft = this.scrollLeft; |
|
2743 |
|
2744 if (nTfoot !== null) { |
|
2745 nScrollFoot.scrollLeft = this.scrollLeft; |
|
2746 } |
|
2747 }); |
|
2748 } |
|
2749 |
|
2750 /* When yscrolling, add the height */ |
|
2751 if (oSettings.oScroll.sY !== "") { |
|
2752 nScrollBody.style.height = _fnStringToCss(oSettings.oScroll.sY); |
|
2753 } |
|
2754 |
|
2755 /* Redraw - align columns across the tables */ |
|
2756 oSettings.aoDrawCallback.push({ |
|
2757 "fn": _fnScrollDraw, |
|
2758 "sName": "scrolling" |
|
2759 }); |
|
2760 |
|
2761 /* Infinite scrolling event handlers */ |
|
2762 if (oSettings.oScroll.bInfinite) { |
|
2763 $(nScrollBody).scroll(function () { |
|
2764 /* Use a blocker to stop scrolling from loading more data while other data is still loading */ |
|
2765 if (!oSettings.bDrawing && $(this).scrollTop() !== 0) { |
|
2766 /* Check if we should load the next data set */ |
|
2767 if ($(this).scrollTop() + $(this).height() > |
|
2768 $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap) { |
|
2769 /* Only do the redraw if we have to - we might be at the end of the data */ |
|
2770 if (oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay()) { |
|
2771 _fnPageChange(oSettings, 'next'); |
|
2772 _fnCalculateEnd(oSettings); |
|
2773 _fnDraw(oSettings); |
|
2774 } |
|
2775 } |
|
2776 } |
|
2777 }); |
|
2778 } |
|
2779 |
|
2780 oSettings.nScrollHead = nScrollHead; |
|
2781 oSettings.nScrollFoot = nScrollFoot; |
|
2782 |
|
2783 return nScroller; |
|
2784 } |
|
2785 |
|
2786 |
|
2787 /** |
|
2788 * Update the various tables for resizing. It's a bit of a pig this function, but |
|
2789 * basically the idea to: |
|
2790 * 1. Re-create the table inside the scrolling div |
|
2791 * 2. Take live measurements from the DOM |
|
2792 * 3. Apply the measurements |
|
2793 * 4. Clean up |
|
2794 * @param {object} o dataTables settings object |
|
2795 * @returns {node} Node to add to the DOM |
|
2796 * @memberof DataTable#oApi |
|
2797 */ |
|
2798 function _fnScrollDraw(o) { |
|
2799 var |
|
2800 nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0], |
|
2801 nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], |
|
2802 nScrollBody = o.nTable.parentNode, |
|
2803 i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis, |
|
2804 nTheadSize, nTfootSize, |
|
2805 iWidth, aApplied = [], aAppliedFooter = [], iSanityWidth, |
|
2806 nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null, |
|
2807 nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null, |
|
2808 ie67 = o.oBrowser.bScrollOversize, |
|
2809 zeroOut = function (nSizer) { |
|
2810 oStyle = nSizer.style; |
|
2811 oStyle.paddingTop = "0"; |
|
2812 oStyle.paddingBottom = "0"; |
|
2813 oStyle.borderTopWidth = "0"; |
|
2814 oStyle.borderBottomWidth = "0"; |
|
2815 oStyle.height = 0; |
|
2816 }; |
|
2817 |
|
2818 /* |
|
2819 * 1. Re-create the table inside the scrolling div |
|
2820 */ |
|
2821 |
|
2822 /* Remove the old minimised thead and tfoot elements in the inner table */ |
|
2823 $(o.nTable).children('thead, tfoot').remove(); |
|
2824 |
|
2825 /* Clone the current header and footer elements and then place it into the inner table */ |
|
2826 nTheadSize = $(o.nTHead).clone()[0]; |
|
2827 o.nTable.insertBefore(nTheadSize, o.nTable.childNodes[0]); |
|
2828 anHeadToSize = o.nTHead.getElementsByTagName('tr'); |
|
2829 anHeadSizers = nTheadSize.getElementsByTagName('tr'); |
|
2830 |
|
2831 if (o.nTFoot !== null) { |
|
2832 nTfootSize = $(o.nTFoot).clone()[0]; |
|
2833 o.nTable.insertBefore(nTfootSize, o.nTable.childNodes[1]); |
|
2834 anFootToSize = o.nTFoot.getElementsByTagName('tr'); |
|
2835 anFootSizers = nTfootSize.getElementsByTagName('tr'); |
|
2836 } |
|
2837 |
|
2838 /* |
|
2839 * 2. Take live measurements from the DOM - do not alter the DOM itself! |
|
2840 */ |
|
2841 |
|
2842 /* Remove old sizing and apply the calculated column widths |
|
2843 * Get the unique column headers in the newly created (cloned) header. We want to apply the |
|
2844 * calculated sizes to this header |
|
2845 */ |
|
2846 if (o.oScroll.sX === "") { |
|
2847 nScrollBody.style.width = '100%'; |
|
2848 nScrollHeadInner.parentNode.style.width = '100%'; |
|
2849 } |
|
2850 |
|
2851 var nThs = _fnGetUniqueThs(o, nTheadSize); |
|
2852 for (i = 0, iLen = nThs.length; i < iLen; i++) { |
|
2853 iVis = _fnVisibleToColumnIndex(o, i); |
|
2854 nThs[i].style.width = o.aoColumns[iVis].sWidth; |
|
2855 } |
|
2856 |
|
2857 if (o.nTFoot !== null) { |
|
2858 _fnApplyToChildren(function (n) { |
|
2859 n.style.width = ""; |
|
2860 }, anFootSizers); |
|
2861 } |
|
2862 |
|
2863 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we |
|
2864 // will end up forcing the scrollbar to appear, making our measurements wrong for when we |
|
2865 // then hide it (end of this function), so add the header height to the body scroller. |
|
2866 if (o.oScroll.bCollapse && o.oScroll.sY !== "") { |
|
2867 nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight) + "px"; |
|
2868 } |
|
2869 |
|
2870 /* Size the table as a whole */ |
|
2871 iSanityWidth = $(o.nTable).outerWidth(); |
|
2872 if (o.oScroll.sX === "") { |
|
2873 /* No x scrolling */ |
|
2874 o.nTable.style.width = "100%"; |
|
2875 |
|
2876 /* I know this is rubbish - but IE7 will make the width of the table when 100% include |
|
2877 * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this |
|
2878 * into account. |
|
2879 */ |
|
2880 if (ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || |
|
2881 $(nScrollBody).css('overflow-y') == "scroll")) { |
|
2882 o.nTable.style.width = _fnStringToCss($(o.nTable).outerWidth() - o.oScroll.iBarWidth); |
|
2883 } |
|
2884 } |
|
2885 else { |
|
2886 if (o.oScroll.sXInner !== "") { |
|
2887 /* x scroll inner has been given - use it */ |
|
2888 o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner); |
|
2889 } |
|
2890 else if (iSanityWidth == $(nScrollBody).width() && |
|
2891 $(nScrollBody).height() < $(o.nTable).height()) { |
|
2892 /* There is y-scrolling - try to take account of the y scroll bar */ |
|
2893 o.nTable.style.width = _fnStringToCss(iSanityWidth - o.oScroll.iBarWidth); |
|
2894 if ($(o.nTable).outerWidth() > iSanityWidth - o.oScroll.iBarWidth) { |
|
2895 /* Not possible to take account of it */ |
|
2896 o.nTable.style.width = _fnStringToCss(iSanityWidth); |
|
2897 } |
|
2898 } |
|
2899 else { |
|
2900 /* All else fails */ |
|
2901 o.nTable.style.width = _fnStringToCss(iSanityWidth); |
|
2902 } |
|
2903 } |
|
2904 |
|
2905 /* Recalculate the sanity width - now that we've applied the required width, before it was |
|
2906 * a temporary variable. This is required because the column width calculation is done |
|
2907 * before this table DOM is created. |
|
2908 */ |
|
2909 iSanityWidth = $(o.nTable).outerWidth(); |
|
2910 |
|
2911 /* We want the hidden header to have zero height, so remove padding and borders. Then |
|
2912 * set the width based on the real headers |
|
2913 */ |
|
2914 |
|
2915 // Apply all styles in one pass. Invalidates layout only once because we don't read any |
|
2916 // DOM properties. |
|
2917 _fnApplyToChildren(zeroOut, anHeadSizers); |
|
2918 |
|
2919 // Read all widths in next pass. Forces layout only once because we do not change |
|
2920 // any DOM properties. |
|
2921 _fnApplyToChildren(function (nSizer) { |
|
2922 aApplied.push(_fnStringToCss($(nSizer).width())); |
|
2923 }, anHeadSizers); |
|
2924 |
|
2925 // Apply all widths in final pass. Invalidates layout only once because we do not |
|
2926 // read any DOM properties. |
|
2927 _fnApplyToChildren(function (nToSize, i) { |
|
2928 nToSize.style.width = aApplied[i]; |
|
2929 }, anHeadToSize); |
|
2930 |
|
2931 $(anHeadSizers).height(0); |
|
2932 |
|
2933 /* Same again with the footer if we have one */ |
|
2934 if (o.nTFoot !== null) { |
|
2935 _fnApplyToChildren(zeroOut, anFootSizers); |
|
2936 |
|
2937 _fnApplyToChildren(function (nSizer) { |
|
2938 aAppliedFooter.push(_fnStringToCss($(nSizer).width())); |
|
2939 }, anFootSizers); |
|
2940 |
|
2941 _fnApplyToChildren(function (nToSize, i) { |
|
2942 nToSize.style.width = aAppliedFooter[i]; |
|
2943 }, anFootToSize); |
|
2944 |
|
2945 $(anFootSizers).height(0); |
|
2946 } |
|
2947 |
|
2948 /* |
|
2949 * 3. Apply the measurements |
|
2950 */ |
|
2951 |
|
2952 /* "Hide" the header and footer that we used for the sizing. We want to also fix their width |
|
2953 * to what they currently are |
|
2954 */ |
|
2955 _fnApplyToChildren(function (nSizer, i) { |
|
2956 nSizer.innerHTML = ""; |
|
2957 nSizer.style.width = aApplied[i]; |
|
2958 }, anHeadSizers); |
|
2959 |
|
2960 if (o.nTFoot !== null) { |
|
2961 _fnApplyToChildren(function (nSizer, i) { |
|
2962 nSizer.innerHTML = ""; |
|
2963 nSizer.style.width = aAppliedFooter[i]; |
|
2964 }, anFootSizers); |
|
2965 } |
|
2966 |
|
2967 /* Sanity check that the table is of a sensible width. If not then we are going to get |
|
2968 * misalignment - try to prevent this by not allowing the table to shrink below its min width |
|
2969 */ |
|
2970 if ($(o.nTable).outerWidth() < iSanityWidth) { |
|
2971 /* The min width depends upon if we have a vertical scrollbar visible or not */ |
|
2972 var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || |
|
2973 $(nScrollBody).css('overflow-y') == "scroll")) ? |
|
2974 iSanityWidth + o.oScroll.iBarWidth : iSanityWidth; |
|
2975 |
|
2976 /* IE6/7 are a law unto themselves... */ |
|
2977 if (ie67 && (nScrollBody.scrollHeight > |
|
2978 nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll")) { |
|
2979 o.nTable.style.width = _fnStringToCss(iCorrection - o.oScroll.iBarWidth); |
|
2980 } |
|
2981 |
|
2982 /* Apply the calculated minimum width to the table wrappers */ |
|
2983 nScrollBody.style.width = _fnStringToCss(iCorrection); |
|
2984 o.nScrollHead.style.width = _fnStringToCss(iCorrection); |
|
2985 |
|
2986 if (o.nTFoot !== null) { |
|
2987 o.nScrollFoot.style.width = _fnStringToCss(iCorrection); |
|
2988 } |
|
2989 |
|
2990 /* And give the user a warning that we've stopped the table getting too small */ |
|
2991 if (o.oScroll.sX === "") { |
|
2992 _fnLog(o, 1, "The table cannot fit into the current element which will cause column" + |
|
2993 " misalignment. The table has been drawn at its minimum possible width."); |
|
2994 } |
|
2995 else if (o.oScroll.sXInner !== "") { |
|
2996 _fnLog(o, 1, "The table cannot fit into the current element which will cause column" + |
|
2997 " misalignment. Increase the sScrollXInner value or remove it to allow automatic" + |
|
2998 " calculation"); |
|
2999 } |
|
3000 } |
|
3001 else { |
|
3002 nScrollBody.style.width = _fnStringToCss('100%'); |
|
3003 o.nScrollHead.style.width = _fnStringToCss('100%'); |
|
3004 |
|
3005 if (o.nTFoot !== null) { |
|
3006 o.nScrollFoot.style.width = _fnStringToCss('100%'); |
|
3007 } |
|
3008 } |
|
3009 |
|
3010 |
|
3011 /* |
|
3012 * 4. Clean up |
|
3013 */ |
|
3014 if (o.oScroll.sY === "") { |
|
3015 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting |
|
3016 * the scrollbar height from the visible display, rather than adding it on. We need to |
|
3017 * set the height in order to sort this. Don't want to do it in any other browsers. |
|
3018 */ |
|
3019 if (ie67) { |
|
3020 nScrollBody.style.height = _fnStringToCss(o.nTable.offsetHeight + o.oScroll.iBarWidth); |
|
3021 } |
|
3022 } |
|
3023 |
|
3024 if (o.oScroll.sY !== "" && o.oScroll.bCollapse) { |
|
3025 nScrollBody.style.height = _fnStringToCss(o.oScroll.sY); |
|
3026 |
|
3027 var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ? |
|
3028 o.oScroll.iBarWidth : 0; |
|
3029 if (o.nTable.offsetHeight < nScrollBody.offsetHeight) { |
|
3030 nScrollBody.style.height = _fnStringToCss(o.nTable.offsetHeight + iExtra); |
|
3031 } |
|
3032 } |
|
3033 |
|
3034 /* Finally set the width's of the header and footer tables */ |
|
3035 var iOuterWidth = $(o.nTable).outerWidth(); |
|
3036 nScrollHeadTable.style.width = _fnStringToCss(iOuterWidth); |
|
3037 nScrollHeadInner.style.width = _fnStringToCss(iOuterWidth); |
|
3038 |
|
3039 // Figure out if there are scrollbar present - if so then we need a the header and footer to |
|
3040 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) |
|
3041 var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll"; |
|
3042 nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth + "px" : "0px"; |
|
3043 |
|
3044 if (o.nTFoot !== null) { |
|
3045 nScrollFootTable.style.width = _fnStringToCss(iOuterWidth); |
|
3046 nScrollFootInner.style.width = _fnStringToCss(iOuterWidth); |
|
3047 nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth + "px" : "0px"; |
|
3048 } |
|
3049 |
|
3050 /* Adjust the position of the header in case we loose the y-scrollbar */ |
|
3051 $(nScrollBody).scroll(); |
|
3052 |
|
3053 /* If sorting or filtering has occurred, jump the scrolling back to the top */ |
|
3054 if (o.bSorted || o.bFiltered) { |
|
3055 nScrollBody.scrollTop = 0; |
|
3056 } |
|
3057 } |
|
3058 |
|
3059 |
|
3060 /** |
|
3061 * Apply a given function to the display child nodes of an element array (typically |
|
3062 * TD children of TR rows |
|
3063 * @param {function} fn Method to apply to the objects |
|
3064 * @param array {nodes} an1 List of elements to look through for display children |
|
3065 * @param array {nodes} an2 Another list (identical structure to the first) - optional |
|
3066 * @memberof DataTable#oApi |
|
3067 */ |
|
3068 function _fnApplyToChildren(fn, an1, an2) { |
|
3069 var index = 0, i = 0, iLen = an1.length; |
|
3070 var nNode1, nNode2; |
|
3071 |
|
3072 while (i < iLen) { |
|
3073 nNode1 = an1[i].firstChild; |
|
3074 nNode2 = an2 ? an2[i].firstChild : null; |
|
3075 while (nNode1) { |
|
3076 if (nNode1.nodeType === 1) { |
|
3077 if (an2) { |
|
3078 fn(nNode1, nNode2, index); |
|
3079 } |
|
3080 else { |
|
3081 fn(nNode1, index); |
|
3082 } |
|
3083 index++; |
|
3084 } |
|
3085 nNode1 = nNode1.nextSibling; |
|
3086 nNode2 = an2 ? nNode2.nextSibling : null; |
|
3087 } |
|
3088 i++; |
|
3089 } |
|
3090 } |
|
3091 |
|
3092 /** |
|
3093 * Convert a CSS unit width to pixels (e.g. 2em) |
|
3094 * @param {string} sWidth width to be converted |
|
3095 * @param {node} nParent parent to get the with for (required for relative widths) - optional |
|
3096 * @returns {int} iWidth width in pixels |
|
3097 * @memberof DataTable#oApi |
|
3098 */ |
|
3099 function _fnConvertToWidth(sWidth, nParent) { |
|
3100 if (!sWidth || sWidth === null || sWidth === '') { |
|
3101 return 0; |
|
3102 } |
|
3103 |
|
3104 if (!nParent) { |
|
3105 nParent = document.body; |
|
3106 } |
|
3107 |
|
3108 var iWidth; |
|
3109 var nTmp = document.createElement("div"); |
|
3110 nTmp.style.width = _fnStringToCss(sWidth); |
|
3111 |
|
3112 nParent.appendChild(nTmp); |
|
3113 iWidth = nTmp.offsetWidth; |
|
3114 nParent.removeChild(nTmp); |
|
3115 |
|
3116 return ( iWidth ); |
|
3117 } |
|
3118 |
|
3119 |
|
3120 /** |
|
3121 * Calculate the width of columns for the table |
|
3122 * @param {object} oSettings dataTables settings object |
|
3123 * @memberof DataTable#oApi |
|
3124 */ |
|
3125 function _fnCalculateColumnWidths(oSettings) { |
|
3126 var iTableWidth = oSettings.nTable.offsetWidth; |
|
3127 var iUserInputs = 0; |
|
3128 var iTmpWidth; |
|
3129 var iVisibleColumns = 0; |
|
3130 var iColums = oSettings.aoColumns.length; |
|
3131 var i, iIndex, iCorrector, iWidth; |
|
3132 var oHeaders = $('th', oSettings.nTHead); |
|
3133 var widthAttr = oSettings.nTable.getAttribute('width'); |
|
3134 var nWrapper = oSettings.nTable.parentNode; |
|
3135 |
|
3136 /* Convert any user input sizes into pixel sizes */ |
|
3137 for (i = 0; i < iColums; i++) { |
|
3138 if (oSettings.aoColumns[i].bVisible) { |
|
3139 iVisibleColumns++; |
|
3140 |
|
3141 if (oSettings.aoColumns[i].sWidth !== null) { |
|
3142 iTmpWidth = _fnConvertToWidth(oSettings.aoColumns[i].sWidthOrig, |
|
3143 nWrapper); |
|
3144 if (iTmpWidth !== null) { |
|
3145 oSettings.aoColumns[i].sWidth = _fnStringToCss(iTmpWidth); |
|
3146 } |
|
3147 |
|
3148 iUserInputs++; |
|
3149 } |
|
3150 } |
|
3151 } |
|
3152 |
|
3153 /* If the number of columns in the DOM equals the number that we have to process in |
|
3154 * DataTables, then we can use the offsets that are created by the web-browser. No custom |
|
3155 * sizes can be set in order for this to happen, nor scrolling used |
|
3156 */ |
|
3157 if (iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums && |
|
3158 oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "") { |
|
3159 for (i = 0; i < oSettings.aoColumns.length; i++) { |
|
3160 iTmpWidth = $(oHeaders[i]).width(); |
|
3161 if (iTmpWidth !== null) { |
|
3162 oSettings.aoColumns[i].sWidth = _fnStringToCss(iTmpWidth); |
|
3163 } |
|
3164 } |
|
3165 } |
|
3166 else { |
|
3167 /* Otherwise we are going to have to do some calculations to get the width of each column. |
|
3168 * Construct a 1 row table with the widest node in the data, and any user defined widths, |
|
3169 * then insert it into the DOM and allow the browser to do all the hard work of |
|
3170 * calculating table widths. |
|
3171 */ |
|
3172 var |
|
3173 nCalcTmp = oSettings.nTable.cloneNode(false), |
|
3174 nTheadClone = oSettings.nTHead.cloneNode(true), |
|
3175 nBody = document.createElement('tbody'), |
|
3176 nTr = document.createElement('tr'), |
|
3177 nDivSizing; |
|
3178 |
|
3179 nCalcTmp.removeAttribute("id"); |
|
3180 nCalcTmp.appendChild(nTheadClone); |
|
3181 if (oSettings.nTFoot !== null) { |
|
3182 nCalcTmp.appendChild(oSettings.nTFoot.cloneNode(true)); |
|
3183 _fnApplyToChildren(function (n) { |
|
3184 n.style.width = ""; |
|
3185 }, nCalcTmp.getElementsByTagName('tr')); |
|
3186 } |
|
3187 |
|
3188 nCalcTmp.appendChild(nBody); |
|
3189 nBody.appendChild(nTr); |
|
3190 |
|
3191 /* Remove any sizing that was previously applied by the styles */ |
|
3192 var jqColSizing = $('thead th', nCalcTmp); |
|
3193 if (jqColSizing.length === 0) { |
|
3194 jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp); |
|
3195 } |
|
3196 |
|
3197 /* Apply custom sizing to the cloned header */ |
|
3198 var nThs = _fnGetUniqueThs(oSettings, nTheadClone); |
|
3199 iCorrector = 0; |
|
3200 for (i = 0; i < iColums; i++) { |
|
3201 var oColumn = oSettings.aoColumns[i]; |
|
3202 if (oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "") { |
|
3203 nThs[i - iCorrector].style.width = _fnStringToCss(oColumn.sWidthOrig); |
|
3204 } |
|
3205 else if (oColumn.bVisible) { |
|
3206 nThs[i - iCorrector].style.width = ""; |
|
3207 } |
|
3208 else { |
|
3209 iCorrector++; |
|
3210 } |
|
3211 } |
|
3212 |
|
3213 /* Find the biggest td for each column and put it into the table */ |
|
3214 for (i = 0; i < iColums; i++) { |
|
3215 if (oSettings.aoColumns[i].bVisible) { |
|
3216 var nTd = _fnGetWidestNode(oSettings, i); |
|
3217 if (nTd !== null) { |
|
3218 nTd = nTd.cloneNode(true); |
|
3219 if (oSettings.aoColumns[i].sContentPadding !== "") { |
|
3220 nTd.innerHTML += oSettings.aoColumns[i].sContentPadding; |
|
3221 } |
|
3222 nTr.appendChild(nTd); |
|
3223 } |
|
3224 } |
|
3225 } |
|
3226 |
|
3227 /* Build the table and 'display' it */ |
|
3228 nWrapper.appendChild(nCalcTmp); |
|
3229 |
|
3230 /* When scrolling (X or Y) we want to set the width of the table as appropriate. However, |
|
3231 * when not scrolling leave the table width as it is. This results in slightly different, |
|
3232 * but I think correct behaviour |
|
3233 */ |
|
3234 if (oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "") { |
|
3235 nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner); |
|
3236 } |
|
3237 else if (oSettings.oScroll.sX !== "") { |
|
3238 nCalcTmp.style.width = ""; |
|
3239 if ($(nCalcTmp).width() < nWrapper.offsetWidth) { |
|
3240 nCalcTmp.style.width = _fnStringToCss(nWrapper.offsetWidth); |
|
3241 } |
|
3242 } |
|
3243 else if (oSettings.oScroll.sY !== "") { |
|
3244 nCalcTmp.style.width = _fnStringToCss(nWrapper.offsetWidth); |
|
3245 } |
|
3246 else if (widthAttr) { |
|
3247 nCalcTmp.style.width = _fnStringToCss(widthAttr); |
|
3248 } |
|
3249 nCalcTmp.style.visibility = "hidden"; |
|
3250 |
|
3251 /* Scrolling considerations */ |
|
3252 _fnScrollingWidthAdjust(oSettings, nCalcTmp); |
|
3253 |
|
3254 /* Read the width's calculated by the browser and store them for use by the caller. We |
|
3255 * first of all try to use the elements in the body, but it is possible that there are |
|
3256 * no elements there, under which circumstances we use the header elements |
|
3257 */ |
|
3258 var oNodes = $("tbody tr:eq(0)", nCalcTmp).children(); |
|
3259 if (oNodes.length === 0) { |
|
3260 oNodes = _fnGetUniqueThs(oSettings, $('thead', nCalcTmp)[0]); |
|
3261 } |
|
3262 |
|
3263 /* Browsers need a bit of a hand when a width is assigned to any columns when |
|
3264 * x-scrolling as they tend to collapse the table to the min-width, even if |
|
3265 * we sent the column widths. So we need to keep track of what the table width |
|
3266 * should be by summing the user given values, and the automatic values |
|
3267 */ |
|
3268 if (oSettings.oScroll.sX !== "") { |
|
3269 var iTotal = 0; |
|
3270 iCorrector = 0; |
|
3271 for (i = 0; i < oSettings.aoColumns.length; i++) { |
|
3272 if (oSettings.aoColumns[i].bVisible) { |
|
3273 if (oSettings.aoColumns[i].sWidthOrig === null) { |
|
3274 iTotal += $(oNodes[iCorrector]).outerWidth(); |
|
3275 } |
|
3276 else { |
|
3277 iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px', ''), 10) + |
|
3278 ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width()); |
|
3279 } |
|
3280 iCorrector++; |
|
3281 } |
|
3282 } |
|
3283 |
|
3284 nCalcTmp.style.width = _fnStringToCss(iTotal); |
|
3285 oSettings.nTable.style.width = _fnStringToCss(iTotal); |
|
3286 } |
|
3287 |
|
3288 iCorrector = 0; |
|
3289 for (i = 0; i < oSettings.aoColumns.length; i++) { |
|
3290 if (oSettings.aoColumns[i].bVisible) { |
|
3291 iWidth = $(oNodes[iCorrector]).width(); |
|
3292 if (iWidth !== null && iWidth > 0) { |
|
3293 oSettings.aoColumns[i].sWidth = _fnStringToCss(iWidth); |
|
3294 } |
|
3295 iCorrector++; |
|
3296 } |
|
3297 } |
|
3298 |
|
3299 var cssWidth = $(nCalcTmp).css('width'); |
|
3300 oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ? |
|
3301 cssWidth : _fnStringToCss($(nCalcTmp).outerWidth()); |
|
3302 nCalcTmp.parentNode.removeChild(nCalcTmp); |
|
3303 } |
|
3304 |
|
3305 if (widthAttr) { |
|
3306 oSettings.nTable.style.width = _fnStringToCss(widthAttr); |
|
3307 } |
|
3308 } |
|
3309 |
|
3310 |
|
3311 /** |
|
3312 * Adjust a table's width to take account of scrolling |
|
3313 * @param {object} oSettings dataTables settings object |
|
3314 * @param {node} n table node |
|
3315 * @memberof DataTable#oApi |
|
3316 */ |
|
3317 function _fnScrollingWidthAdjust(oSettings, n) { |
|
3318 if (oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "") { |
|
3319 /* When y-scrolling only, we want to remove the width of the scroll bar so the table |
|
3320 * + scroll bar will fit into the area avaialble. |
|
3321 */ |
|
3322 var iOrigWidth = $(n).width(); |
|
3323 n.style.width = _fnStringToCss($(n).outerWidth() - oSettings.oScroll.iBarWidth); |
|
3324 } |
|
3325 else if (oSettings.oScroll.sX !== "") { |
|
3326 /* When x-scrolling both ways, fix the table at it's current size, without adjusting */ |
|
3327 n.style.width = _fnStringToCss($(n).outerWidth()); |
|
3328 } |
|
3329 } |
|
3330 |
|
3331 |
|
3332 /** |
|
3333 * Get the widest node |
|
3334 * @param {object} oSettings dataTables settings object |
|
3335 * @param {int} iCol column of interest |
|
3336 * @returns {node} widest table node |
|
3337 * @memberof DataTable#oApi |
|
3338 */ |
|
3339 function _fnGetWidestNode(oSettings, iCol) { |
|
3340 var iMaxIndex = _fnGetMaxLenString(oSettings, iCol); |
|
3341 if (iMaxIndex < 0) { |
|
3342 return null; |
|
3343 } |
|
3344 |
|
3345 if (oSettings.aoData[iMaxIndex].nTr === null) { |
|
3346 var n = document.createElement('td'); |
|
3347 n.innerHTML = _fnGetCellData(oSettings, iMaxIndex, iCol, ''); |
|
3348 return n; |
|
3349 } |
|
3350 return _fnGetTdNodes(oSettings, iMaxIndex)[iCol]; |
|
3351 } |
|
3352 |
|
3353 |
|
3354 /** |
|
3355 * Get the maximum strlen for each data column |
|
3356 * @param {object} oSettings dataTables settings object |
|
3357 * @param {int} iCol column of interest |
|
3358 * @returns {string} max string length for each column |
|
3359 * @memberof DataTable#oApi |
|
3360 */ |
|
3361 function _fnGetMaxLenString(oSettings, iCol) { |
|
3362 var iMax = -1; |
|
3363 var iMaxIndex = -1; |
|
3364 |
|
3365 for (var i = 0; i < oSettings.aoData.length; i++) { |
|
3366 var s = _fnGetCellData(oSettings, i, iCol, 'display') + ""; |
|
3367 s = s.replace(/<.*?>/g, ""); |
|
3368 if (s.length > iMax) { |
|
3369 iMax = s.length; |
|
3370 iMaxIndex = i; |
|
3371 } |
|
3372 } |
|
3373 |
|
3374 return iMaxIndex; |
|
3375 } |
|
3376 |
|
3377 |
|
3378 /** |
|
3379 * Append a CSS unit (only if required) to a string |
|
3380 * @param {array} aArray1 first array |
|
3381 * @param {array} aArray2 second array |
|
3382 * @returns {int} 0 if match, 1 if length is different, 2 if no match |
|
3383 * @memberof DataTable#oApi |
|
3384 */ |
|
3385 function _fnStringToCss(s) { |
|
3386 if (s === null) { |
|
3387 return "0px"; |
|
3388 } |
|
3389 |
|
3390 if (typeof s == 'number') { |
|
3391 if (s < 0) { |
|
3392 return "0px"; |
|
3393 } |
|
3394 return s + "px"; |
|
3395 } |
|
3396 |
|
3397 /* Check if the last character is not 0-9 */ |
|
3398 var c = s.charCodeAt(s.length - 1); |
|
3399 if (c < 0x30 || c > 0x39) { |
|
3400 return s; |
|
3401 } |
|
3402 return s + "px"; |
|
3403 } |
|
3404 |
|
3405 |
|
3406 /** |
|
3407 * Get the width of a scroll bar in this browser being used |
|
3408 * @returns {int} width in pixels |
|
3409 * @memberof DataTable#oApi |
|
3410 */ |
|
3411 function _fnScrollBarWidth() { |
|
3412 var inner = document.createElement('p'); |
|
3413 var style = inner.style; |
|
3414 style.width = "100%"; |
|
3415 style.height = "200px"; |
|
3416 style.padding = "0px"; |
|
3417 |
|
3418 var outer = document.createElement('div'); |
|
3419 style = outer.style; |
|
3420 style.position = "absolute"; |
|
3421 style.top = "0px"; |
|
3422 style.left = "0px"; |
|
3423 style.visibility = "hidden"; |
|
3424 style.width = "200px"; |
|
3425 style.height = "150px"; |
|
3426 style.padding = "0px"; |
|
3427 style.overflow = "hidden"; |
|
3428 outer.appendChild(inner); |
|
3429 |
|
3430 document.body.appendChild(outer); |
|
3431 var w1 = inner.offsetWidth; |
|
3432 outer.style.overflow = 'scroll'; |
|
3433 var w2 = inner.offsetWidth; |
|
3434 if (w1 == w2) { |
|
3435 w2 = outer.clientWidth; |
|
3436 } |
|
3437 |
|
3438 document.body.removeChild(outer); |
|
3439 return (w1 - w2); |
|
3440 } |
|
3441 |
|
3442 /** |
|
3443 * Change the order of the table |
|
3444 * @param {object} oSettings dataTables settings object |
|
3445 * @param {bool} bApplyClasses optional - should we apply classes or not |
|
3446 * @memberof DataTable#oApi |
|
3447 */ |
|
3448 function _fnSort(oSettings, bApplyClasses) { |
|
3449 var |
|
3450 i, iLen, j, jLen, k, kLen, |
|
3451 sDataType, nTh, |
|
3452 aaSort = [], |
|
3453 aiOrig = [], |
|
3454 oSort = DataTable.ext.oSort, |
|
3455 aoData = oSettings.aoData, |
|
3456 aoColumns = oSettings.aoColumns, |
|
3457 oAria = oSettings.oLanguage.oAria; |
|
3458 |
|
3459 /* No sorting required if server-side or no sorting array */ |
|
3460 if (!oSettings.oFeatures.bServerSide && |
|
3461 (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null)) { |
|
3462 aaSort = ( oSettings.aaSortingFixed !== null ) ? |
|
3463 oSettings.aaSortingFixed.concat(oSettings.aaSorting) : |
|
3464 oSettings.aaSorting.slice(); |
|
3465 |
|
3466 /* If there is a sorting data type, and a function belonging to it, then we need to |
|
3467 * get the data from the developer's function and apply it for this column |
|
3468 */ |
|
3469 for (i = 0; i < aaSort.length; i++) { |
|
3470 var iColumn = aaSort[i][0]; |
|
3471 var iVisColumn = _fnColumnIndexToVisible(oSettings, iColumn); |
|
3472 sDataType = oSettings.aoColumns[ iColumn ].sSortDataType; |
|
3473 if (DataTable.ext.afnSortData[sDataType]) { |
|
3474 var aData = DataTable.ext.afnSortData[sDataType].call( |
|
3475 oSettings.oInstance, oSettings, iColumn, iVisColumn |
|
3476 ); |
|
3477 if (aData.length === aoData.length) { |
|
3478 for (j = 0, jLen = aoData.length; j < jLen; j++) { |
|
3479 _fnSetCellData(oSettings, j, iColumn, aData[j]); |
|
3480 } |
|
3481 } |
|
3482 else { |
|
3483 _fnLog(oSettings, 0, "Returned data sort array (col " + iColumn + ") is the wrong length"); |
|
3484 } |
|
3485 } |
|
3486 } |
|
3487 |
|
3488 /* Create a value - key array of the current row positions such that we can use their |
|
3489 * current position during the sort, if values match, in order to perform stable sorting |
|
3490 */ |
|
3491 for (i = 0, iLen = oSettings.aiDisplayMaster.length; i < iLen; i++) { |
|
3492 aiOrig[ oSettings.aiDisplayMaster[i] ] = i; |
|
3493 } |
|
3494 |
|
3495 /* Build an internal data array which is specific to the sort, so we can get and prep |
|
3496 * the data to be sorted only once, rather than needing to do it every time the sorting |
|
3497 * function runs. This make the sorting function a very simple comparison |
|
3498 */ |
|
3499 var iSortLen = aaSort.length; |
|
3500 var fnSortFormat, aDataSort; |
|
3501 for (i = 0, iLen = aoData.length; i < iLen; i++) { |
|
3502 for (j = 0; j < iSortLen; j++) { |
|
3503 aDataSort = aoColumns[ aaSort[j][0] ].aDataSort; |
|
3504 |
|
3505 for (k = 0, kLen = aDataSort.length; k < kLen; k++) { |
|
3506 sDataType = aoColumns[ aDataSort[k] ].sType; |
|
3507 fnSortFormat = oSort[ (sDataType ? sDataType : 'string') + "-pre" ]; |
|
3508 |
|
3509 aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ? |
|
3510 fnSortFormat(_fnGetCellData(oSettings, i, aDataSort[k], 'sort')) : |
|
3511 _fnGetCellData(oSettings, i, aDataSort[k], 'sort'); |
|
3512 } |
|
3513 } |
|
3514 } |
|
3515 |
|
3516 /* Do the sort - here we want multi-column sorting based on a given data source (column) |
|
3517 * and sorting function (from oSort) in a certain direction. It's reasonably complex to |
|
3518 * follow on it's own, but this is what we want (example two column sorting): |
|
3519 * fnLocalSorting = function(a,b){ |
|
3520 * var iTest; |
|
3521 * iTest = oSort['string-asc']('data11', 'data12'); |
|
3522 * if (iTest !== 0) |
|
3523 * return iTest; |
|
3524 * iTest = oSort['numeric-desc']('data21', 'data22'); |
|
3525 * if (iTest !== 0) |
|
3526 * return iTest; |
|
3527 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); |
|
3528 * } |
|
3529 * Basically we have a test for each sorting column, if the data in that column is equal, |
|
3530 * test the next column. If all columns match, then we use a numeric sort on the row |
|
3531 * positions in the original data array to provide a stable sort. |
|
3532 */ |
|
3533 oSettings.aiDisplayMaster.sort(function (a, b) { |
|
3534 var k, l, lLen, iTest, aDataSort, sDataType; |
|
3535 for (k = 0; k < iSortLen; k++) { |
|
3536 aDataSort = aoColumns[ aaSort[k][0] ].aDataSort; |
|
3537 |
|
3538 for (l = 0, lLen = aDataSort.length; l < lLen; l++) { |
|
3539 sDataType = aoColumns[ aDataSort[l] ].sType; |
|
3540 |
|
3541 iTest = oSort[ (sDataType ? sDataType : 'string') + "-" + aaSort[k][1] ]( |
|
3542 aoData[a]._aSortData[ aDataSort[l] ], |
|
3543 aoData[b]._aSortData[ aDataSort[l] ] |
|
3544 ); |
|
3545 |
|
3546 if (iTest !== 0) { |
|
3547 return iTest; |
|
3548 } |
|
3549 } |
|
3550 } |
|
3551 |
|
3552 return oSort['numeric-asc'](aiOrig[a], aiOrig[b]); |
|
3553 }); |
|
3554 } |
|
3555 |
|
3556 /* Alter the sorting classes to take account of the changes */ |
|
3557 if ((bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender) { |
|
3558 _fnSortingClasses(oSettings); |
|
3559 } |
|
3560 |
|
3561 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
3562 var sTitle = aoColumns[i].sTitle.replace(/<.*?>/g, ""); |
|
3563 nTh = aoColumns[i].nTh; |
|
3564 nTh.removeAttribute('aria-sort'); |
|
3565 nTh.removeAttribute('aria-label'); |
|
3566 |
|
3567 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ |
|
3568 if (aoColumns[i].bSortable) { |
|
3569 if (aaSort.length > 0 && aaSort[0][0] == i) { |
|
3570 nTh.setAttribute('aria-sort', aaSort[0][1] == "asc" ? "ascending" : "descending"); |
|
3571 |
|
3572 var nextSort = (aoColumns[i].asSorting[ aaSort[0][2] + 1 ]) ? |
|
3573 aoColumns[i].asSorting[ aaSort[0][2] + 1 ] : aoColumns[i].asSorting[0]; |
|
3574 nTh.setAttribute('aria-label', sTitle + |
|
3575 (nextSort == "asc" ? oAria.sSortAscending : oAria.sSortDescending)); |
|
3576 } |
|
3577 else { |
|
3578 nTh.setAttribute('aria-label', sTitle + |
|
3579 (aoColumns[i].asSorting[0] == "asc" ? oAria.sSortAscending : oAria.sSortDescending)); |
|
3580 } |
|
3581 } |
|
3582 else { |
|
3583 nTh.setAttribute('aria-label', sTitle); |
|
3584 } |
|
3585 } |
|
3586 |
|
3587 /* Tell the draw function that we have sorted the data */ |
|
3588 oSettings.bSorted = true; |
|
3589 $(oSettings.oInstance).trigger('sort', oSettings); |
|
3590 |
|
3591 /* Copy the master data into the draw array and re-draw */ |
|
3592 if (oSettings.oFeatures.bFilter) { |
|
3593 /* _fnFilter() will redraw the table for us */ |
|
3594 _fnFilterComplete(oSettings, oSettings.oPreviousSearch, 1); |
|
3595 } |
|
3596 else { |
|
3597 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
|
3598 oSettings._iDisplayStart = 0; |
|
3599 /* reset display back to page 0 */ |
|
3600 _fnCalculateEnd(oSettings); |
|
3601 _fnDraw(oSettings); |
|
3602 } |
|
3603 } |
|
3604 |
|
3605 |
|
3606 /** |
|
3607 * Attach a sort handler (click) to a node |
|
3608 * @param {object} oSettings dataTables settings object |
|
3609 * @param {node} nNode node to attach the handler to |
|
3610 * @param {int} iDataIndex column sorting index |
|
3611 * @param {function} [fnCallback] callback function |
|
3612 * @memberof DataTable#oApi |
|
3613 */ |
|
3614 function _fnSortAttachListener(oSettings, nNode, iDataIndex, fnCallback) { |
|
3615 _fnBindAction(nNode, {}, function (e) { |
|
3616 /* If the column is not sortable - don't to anything */ |
|
3617 if (oSettings.aoColumns[iDataIndex].bSortable === false) { |
|
3618 return; |
|
3619 } |
|
3620 |
|
3621 /* |
|
3622 * This is a little bit odd I admit... I declare a temporary function inside the scope of |
|
3623 * _fnBuildHead and the click handler in order that the code presented here can be used |
|
3624 * twice - once for when bProcessing is enabled, and another time for when it is |
|
3625 * disabled, as we need to perform slightly different actions. |
|
3626 * Basically the issue here is that the Javascript engine in modern browsers don't |
|
3627 * appear to allow the rendering engine to update the display while it is still executing |
|
3628 * it's thread (well - it does but only after long intervals). This means that the |
|
3629 * 'processing' display doesn't appear for a table sort. To break the js thread up a bit |
|
3630 * I force an execution break by using setTimeout - but this breaks the expected |
|
3631 * thread continuation for the end-developer's point of view (their code would execute |
|
3632 * too early), so we only do it when we absolutely have to. |
|
3633 */ |
|
3634 var fnInnerSorting = function () { |
|
3635 var iColumn, iNextSort; |
|
3636 |
|
3637 /* If the shift key is pressed then we are multiple column sorting */ |
|
3638 if (e.shiftKey) { |
|
3639 /* Are we already doing some kind of sort on this column? */ |
|
3640 var bFound = false; |
|
3641 for (var i = 0; i < oSettings.aaSorting.length; i++) { |
|
3642 if (oSettings.aaSorting[i][0] == iDataIndex) { |
|
3643 bFound = true; |
|
3644 iColumn = oSettings.aaSorting[i][0]; |
|
3645 iNextSort = oSettings.aaSorting[i][2] + 1; |
|
3646 |
|
3647 if (!oSettings.aoColumns[iColumn].asSorting[iNextSort]) { |
|
3648 /* Reached the end of the sorting options, remove from multi-col sort */ |
|
3649 oSettings.aaSorting.splice(i, 1); |
|
3650 } |
|
3651 else { |
|
3652 /* Move onto next sorting direction */ |
|
3653 oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort]; |
|
3654 oSettings.aaSorting[i][2] = iNextSort; |
|
3655 } |
|
3656 break; |
|
3657 } |
|
3658 } |
|
3659 |
|
3660 /* No sort yet - add it in */ |
|
3661 if (bFound === false) { |
|
3662 oSettings.aaSorting.push([ iDataIndex, |
|
3663 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ]); |
|
3664 } |
|
3665 } |
|
3666 else { |
|
3667 /* If no shift key then single column sort */ |
|
3668 if (oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex) { |
|
3669 iColumn = oSettings.aaSorting[0][0]; |
|
3670 iNextSort = oSettings.aaSorting[0][2] + 1; |
|
3671 if (!oSettings.aoColumns[iColumn].asSorting[iNextSort]) { |
|
3672 iNextSort = 0; |
|
3673 } |
|
3674 oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort]; |
|
3675 oSettings.aaSorting[0][2] = iNextSort; |
|
3676 } |
|
3677 else { |
|
3678 oSettings.aaSorting.splice(0, oSettings.aaSorting.length); |
|
3679 oSettings.aaSorting.push([ iDataIndex, |
|
3680 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ]); |
|
3681 } |
|
3682 } |
|
3683 |
|
3684 /* Run the sort */ |
|
3685 _fnSort(oSettings); |
|
3686 }; |
|
3687 /* /fnInnerSorting */ |
|
3688 |
|
3689 if (!oSettings.oFeatures.bProcessing) { |
|
3690 fnInnerSorting(); |
|
3691 } |
|
3692 else { |
|
3693 _fnProcessingDisplay(oSettings, true); |
|
3694 setTimeout(function () { |
|
3695 fnInnerSorting(); |
|
3696 if (!oSettings.oFeatures.bServerSide) { |
|
3697 _fnProcessingDisplay(oSettings, false); |
|
3698 } |
|
3699 }, 0); |
|
3700 } |
|
3701 |
|
3702 /* Call the user specified callback function - used for async user interaction */ |
|
3703 if (typeof fnCallback == 'function') { |
|
3704 fnCallback(oSettings); |
|
3705 } |
|
3706 }); |
|
3707 } |
|
3708 |
|
3709 |
|
3710 /** |
|
3711 * Set the sorting classes on the header, Note: it is safe to call this function |
|
3712 * when bSort and bSortClasses are false |
|
3713 * @param {object} oSettings dataTables settings object |
|
3714 * @memberof DataTable#oApi |
|
3715 */ |
|
3716 function _fnSortingClasses(oSettings) { |
|
3717 var i, iLen, j, jLen, iFound; |
|
3718 var aaSort, sClass; |
|
3719 var iColumns = oSettings.aoColumns.length; |
|
3720 var oClasses = oSettings.oClasses; |
|
3721 |
|
3722 for (i = 0; i < iColumns; i++) { |
|
3723 if (oSettings.aoColumns[i].bSortable) { |
|
3724 $(oSettings.aoColumns[i].nTh).removeClass(oClasses.sSortAsc + " " + oClasses.sSortDesc + |
|
3725 " " + oSettings.aoColumns[i].sSortingClass); |
|
3726 } |
|
3727 } |
|
3728 |
|
3729 if (oSettings.aaSortingFixed !== null) { |
|
3730 aaSort = oSettings.aaSortingFixed.concat(oSettings.aaSorting); |
|
3731 } |
|
3732 else { |
|
3733 aaSort = oSettings.aaSorting.slice(); |
|
3734 } |
|
3735 |
|
3736 /* Apply the required classes to the header */ |
|
3737 for (i = 0; i < oSettings.aoColumns.length; i++) { |
|
3738 if (oSettings.aoColumns[i].bSortable) { |
|
3739 sClass = oSettings.aoColumns[i].sSortingClass; |
|
3740 iFound = -1; |
|
3741 for (j = 0; j < aaSort.length; j++) { |
|
3742 if (aaSort[j][0] == i) { |
|
3743 sClass = ( aaSort[j][1] == "asc" ) ? |
|
3744 oClasses.sSortAsc : oClasses.sSortDesc; |
|
3745 iFound = j; |
|
3746 break; |
|
3747 } |
|
3748 } |
|
3749 $(oSettings.aoColumns[i].nTh).addClass(sClass); |
|
3750 |
|
3751 if (oSettings.bJUI) { |
|
3752 /* jQuery UI uses extra markup */ |
|
3753 var jqSpan = $("span." + oClasses.sSortIcon, oSettings.aoColumns[i].nTh); |
|
3754 jqSpan.removeClass(oClasses.sSortJUIAsc + " " + oClasses.sSortJUIDesc + " " + |
|
3755 oClasses.sSortJUI + " " + oClasses.sSortJUIAscAllowed + " " + oClasses.sSortJUIDescAllowed); |
|
3756 |
|
3757 var sSpanClass; |
|
3758 if (iFound == -1) { |
|
3759 sSpanClass = oSettings.aoColumns[i].sSortingClassJUI; |
|
3760 } |
|
3761 else if (aaSort[iFound][1] == "asc") { |
|
3762 sSpanClass = oClasses.sSortJUIAsc; |
|
3763 } |
|
3764 else { |
|
3765 sSpanClass = oClasses.sSortJUIDesc; |
|
3766 } |
|
3767 |
|
3768 jqSpan.addClass(sSpanClass); |
|
3769 } |
|
3770 } |
|
3771 else { |
|
3772 /* No sorting on this column, so add the base class. This will have been assigned by |
|
3773 * _fnAddColumn |
|
3774 */ |
|
3775 $(oSettings.aoColumns[i].nTh).addClass(oSettings.aoColumns[i].sSortingClass); |
|
3776 } |
|
3777 } |
|
3778 |
|
3779 /* |
|
3780 * Apply the required classes to the table body |
|
3781 * Note that this is given as a feature switch since it can significantly slow down a sort |
|
3782 * on large data sets (adding and removing of classes is always slow at the best of times..) |
|
3783 * Further to this, note that this code is admittedly fairly ugly. It could be made a lot |
|
3784 * simpler using jQuery selectors and add/removeClass, but that is significantly slower |
|
3785 * (on the order of 5 times slower) - hence the direct DOM manipulation here. |
|
3786 * Note that for deferred drawing we do use jQuery - the reason being that taking the first |
|
3787 * row found to see if the whole column needs processed can miss classes since the first |
|
3788 * column might be new. |
|
3789 */ |
|
3790 sClass = oClasses.sSortColumn; |
|
3791 |
|
3792 if (oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses) { |
|
3793 var nTds = _fnGetTdNodes(oSettings); |
|
3794 |
|
3795 /* Determine what the sorting class for each column should be */ |
|
3796 var iClass, iTargetCol; |
|
3797 var asClasses = []; |
|
3798 for (i = 0; i < iColumns; i++) { |
|
3799 asClasses.push(""); |
|
3800 } |
|
3801 for (i = 0, iClass = 1; i < aaSort.length; i++) { |
|
3802 iTargetCol = parseInt(aaSort[i][0], 10); |
|
3803 asClasses[iTargetCol] = sClass + iClass; |
|
3804 |
|
3805 if (iClass < 3) { |
|
3806 iClass++; |
|
3807 } |
|
3808 } |
|
3809 |
|
3810 /* Make changes to the classes for each cell as needed */ |
|
3811 var reClass = new RegExp(sClass + "[123]"); |
|
3812 var sTmpClass, sCurrentClass, sNewClass; |
|
3813 for (i = 0, iLen = nTds.length; i < iLen; i++) { |
|
3814 /* Determine which column we're looking at */ |
|
3815 iTargetCol = i % iColumns; |
|
3816 |
|
3817 /* What is the full list of classes now */ |
|
3818 sCurrentClass = nTds[i].className; |
|
3819 /* What sorting class should be applied? */ |
|
3820 sNewClass = asClasses[iTargetCol]; |
|
3821 /* What would the new full list be if we did a replacement? */ |
|
3822 sTmpClass = sCurrentClass.replace(reClass, sNewClass); |
|
3823 |
|
3824 if (sTmpClass != sCurrentClass) { |
|
3825 /* We changed something */ |
|
3826 nTds[i].className = $.trim(sTmpClass); |
|
3827 } |
|
3828 else if (sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1) { |
|
3829 /* We need to add a class */ |
|
3830 nTds[i].className = sCurrentClass + " " + sNewClass; |
|
3831 } |
|
3832 } |
|
3833 } |
|
3834 } |
|
3835 |
|
3836 |
|
3837 /** |
|
3838 * Save the state of a table in a cookie such that the page can be reloaded |
|
3839 * @param {object} oSettings dataTables settings object |
|
3840 * @memberof DataTable#oApi |
|
3841 */ |
|
3842 function _fnSaveState(oSettings) { |
|
3843 if (!oSettings.oFeatures.bStateSave || oSettings.bDestroying) { |
|
3844 return; |
|
3845 } |
|
3846 |
|
3847 /* Store the interesting variables */ |
|
3848 var i, iLen, bInfinite = oSettings.oScroll.bInfinite; |
|
3849 var oState = { |
|
3850 "iCreate": new Date().getTime(), |
|
3851 "iStart": (bInfinite ? 0 : oSettings._iDisplayStart), |
|
3852 "iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd), |
|
3853 "iLength": oSettings._iDisplayLength, |
|
3854 "aaSorting": $.extend(true, [], oSettings.aaSorting), |
|
3855 "oSearch": $.extend(true, {}, oSettings.oPreviousSearch), |
|
3856 "aoSearchCols": $.extend(true, [], oSettings.aoPreSearchCols), |
|
3857 "abVisCols": [] |
|
3858 }; |
|
3859 |
|
3860 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
3861 oState.abVisCols.push(oSettings.aoColumns[i].bVisible); |
|
3862 } |
|
3863 |
|
3864 _fnCallbackFire(oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState]); |
|
3865 |
|
3866 oSettings.fnStateSave.call(oSettings.oInstance, oSettings, oState); |
|
3867 } |
|
3868 |
|
3869 |
|
3870 /** |
|
3871 * Attempt to load a saved table state from a cookie |
|
3872 * @param {object} oSettings dataTables settings object |
|
3873 * @param {object} oInit DataTables init object so we can override settings |
|
3874 * @memberof DataTable#oApi |
|
3875 */ |
|
3876 function _fnLoadState(oSettings, oInit) { |
|
3877 if (!oSettings.oFeatures.bStateSave) { |
|
3878 return; |
|
3879 } |
|
3880 |
|
3881 var oData = oSettings.fnStateLoad.call(oSettings.oInstance, oSettings); |
|
3882 if (!oData) { |
|
3883 return; |
|
3884 } |
|
3885 |
|
3886 /* Allow custom and plug-in manipulation functions to alter the saved data set and |
|
3887 * cancelling of loading by returning false |
|
3888 */ |
|
3889 var abStateLoad = _fnCallbackFire(oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData]); |
|
3890 if ($.inArray(false, abStateLoad) !== -1) { |
|
3891 return; |
|
3892 } |
|
3893 |
|
3894 /* Store the saved state so it might be accessed at any time */ |
|
3895 oSettings.oLoadedState = $.extend(true, {}, oData); |
|
3896 |
|
3897 /* Restore key features */ |
|
3898 oSettings._iDisplayStart = oData.iStart; |
|
3899 oSettings.iInitDisplayStart = oData.iStart; |
|
3900 oSettings._iDisplayEnd = oData.iEnd; |
|
3901 oSettings._iDisplayLength = oData.iLength; |
|
3902 oSettings.aaSorting = oData.aaSorting.slice(); |
|
3903 oSettings.saved_aaSorting = oData.aaSorting.slice(); |
|
3904 |
|
3905 /* Search filtering */ |
|
3906 $.extend(oSettings.oPreviousSearch, oData.oSearch); |
|
3907 $.extend(true, oSettings.aoPreSearchCols, oData.aoSearchCols); |
|
3908 |
|
3909 /* Column visibility state |
|
3910 * Pass back visibility settings to the init handler, but to do not here override |
|
3911 * the init object that the user might have passed in |
|
3912 */ |
|
3913 oInit.saved_aoColumns = []; |
|
3914 for (var i = 0; i < oData.abVisCols.length; i++) { |
|
3915 oInit.saved_aoColumns[i] = {}; |
|
3916 oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i]; |
|
3917 } |
|
3918 |
|
3919 _fnCallbackFire(oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData]); |
|
3920 } |
|
3921 |
|
3922 |
|
3923 /** |
|
3924 * Create a new cookie with a value to store the state of a table |
|
3925 * @param {string} sName name of the cookie to create |
|
3926 * @param {string} sValue the value the cookie should take |
|
3927 * @param {int} iSecs duration of the cookie |
|
3928 * @param {string} sBaseName sName is made up of the base + file name - this is the base |
|
3929 * @param {function} fnCallback User definable function to modify the cookie |
|
3930 * @memberof DataTable#oApi |
|
3931 */ |
|
3932 function _fnCreateCookie(sName, sValue, iSecs, sBaseName, fnCallback) { |
|
3933 var date = new Date(); |
|
3934 date.setTime(date.getTime() + (iSecs * 1000)); |
|
3935 |
|
3936 /* |
|
3937 * Shocking but true - it would appear IE has major issues with having the path not having |
|
3938 * a trailing slash on it. We need the cookie to be available based on the path, so we |
|
3939 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the |
|
3940 * patch to use at least some of the path |
|
3941 */ |
|
3942 var aParts = window.location.pathname.split('/'); |
|
3943 var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g, "").toLowerCase(); |
|
3944 var sFullCookie, oData; |
|
3945 |
|
3946 if (fnCallback !== null) { |
|
3947 oData = (typeof $.parseJSON === 'function') ? |
|
3948 $.parseJSON(sValue) : eval('(' + sValue + ')'); |
|
3949 sFullCookie = fnCallback(sNameFile, oData, date.toGMTString(), |
|
3950 aParts.join('/') + "/"); |
|
3951 } |
|
3952 else { |
|
3953 sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) + |
|
3954 "; expires=" + date.toGMTString() + "; path=" + aParts.join('/') + "/"; |
|
3955 } |
|
3956 |
|
3957 /* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies |
|
3958 * belonging to DataTables. |
|
3959 */ |
|
3960 var |
|
3961 aCookies = document.cookie.split(';'), |
|
3962 iNewCookieLen = sFullCookie.split(';')[0].length, |
|
3963 aOldCookies = []; |
|
3964 |
|
3965 if (iNewCookieLen + document.cookie.length + 10 > 4096) /* Magic 10 for padding */ |
|
3966 { |
|
3967 for (var i = 0, iLen = aCookies.length; i < iLen; i++) { |
|
3968 if (aCookies[i].indexOf(sBaseName) != -1) { |
|
3969 /* It's a DataTables cookie, so eval it and check the time stamp */ |
|
3970 var aSplitCookie = aCookies[i].split('='); |
|
3971 try { |
|
3972 oData = eval('(' + decodeURIComponent(aSplitCookie[1]) + ')'); |
|
3973 |
|
3974 if (oData && oData.iCreate) { |
|
3975 aOldCookies.push({ |
|
3976 "name": aSplitCookie[0], |
|
3977 "time": oData.iCreate |
|
3978 }); |
|
3979 } |
|
3980 } |
|
3981 catch (e) { |
|
3982 } |
|
3983 } |
|
3984 } |
|
3985 |
|
3986 // Make sure we delete the oldest ones first |
|
3987 aOldCookies.sort(function (a, b) { |
|
3988 return b.time - a.time; |
|
3989 }); |
|
3990 |
|
3991 // Eliminate as many old DataTables cookies as we need to |
|
3992 while (iNewCookieLen + document.cookie.length + 10 > 4096) { |
|
3993 if (aOldCookies.length === 0) { |
|
3994 // Deleted all DT cookies and still not enough space. Can't state save |
|
3995 return; |
|
3996 } |
|
3997 |
|
3998 var old = aOldCookies.pop(); |
|
3999 document.cookie = old.name + "=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=" + |
|
4000 aParts.join('/') + "/"; |
|
4001 } |
|
4002 } |
|
4003 |
|
4004 document.cookie = sFullCookie; |
|
4005 } |
|
4006 |
|
4007 |
|
4008 /** |
|
4009 * Read an old cookie to get a cookie with an old table state |
|
4010 * @param {string} sName name of the cookie to read |
|
4011 * @returns {string} contents of the cookie - or null if no cookie with that name found |
|
4012 * @memberof DataTable#oApi |
|
4013 */ |
|
4014 function _fnReadCookie(sName) { |
|
4015 var |
|
4016 aParts = window.location.pathname.split('/'), |
|
4017 sNameEQ = sName + '_' + aParts[aParts.length - 1].replace(/[\/:]/g, "").toLowerCase() + '=', |
|
4018 sCookieContents = document.cookie.split(';'); |
|
4019 |
|
4020 for (var i = 0; i < sCookieContents.length; i++) { |
|
4021 var c = sCookieContents[i]; |
|
4022 |
|
4023 while (c.charAt(0) == ' ') { |
|
4024 c = c.substring(1, c.length); |
|
4025 } |
|
4026 |
|
4027 if (c.indexOf(sNameEQ) === 0) { |
|
4028 return decodeURIComponent(c.substring(sNameEQ.length, c.length)); |
|
4029 } |
|
4030 } |
|
4031 return null; |
|
4032 } |
|
4033 |
|
4034 |
|
4035 /** |
|
4036 * Return the settings object for a particular table |
|
4037 * @param {node} nTable table we are using as a dataTable |
|
4038 * @returns {object} Settings object - or null if not found |
|
4039 * @memberof DataTable#oApi |
|
4040 */ |
|
4041 function _fnSettingsFromNode(nTable) { |
|
4042 for (var i = 0; i < DataTable.settings.length; i++) { |
|
4043 if (DataTable.settings[i].nTable === nTable) { |
|
4044 return DataTable.settings[i]; |
|
4045 } |
|
4046 } |
|
4047 |
|
4048 return null; |
|
4049 } |
|
4050 |
|
4051 |
|
4052 /** |
|
4053 * Return an array with the TR nodes for the table |
|
4054 * @param {object} oSettings dataTables settings object |
|
4055 * @returns {array} TR array |
|
4056 * @memberof DataTable#oApi |
|
4057 */ |
|
4058 function _fnGetTrNodes(oSettings) { |
|
4059 var aNodes = []; |
|
4060 var aoData = oSettings.aoData; |
|
4061 for (var i = 0, iLen = aoData.length; i < iLen; i++) { |
|
4062 if (aoData[i].nTr !== null) { |
|
4063 aNodes.push(aoData[i].nTr); |
|
4064 } |
|
4065 } |
|
4066 return aNodes; |
|
4067 } |
|
4068 |
|
4069 |
|
4070 /** |
|
4071 * Return an flat array with all TD nodes for the table, or row |
|
4072 * @param {object} oSettings dataTables settings object |
|
4073 * @param {int} [iIndividualRow] aoData index to get the nodes for - optional |
|
4074 * if not given then the return array will contain all nodes for the table |
|
4075 * @returns {array} TD array |
|
4076 * @memberof DataTable#oApi |
|
4077 */ |
|
4078 function _fnGetTdNodes(oSettings, iIndividualRow) { |
|
4079 var anReturn = []; |
|
4080 var iCorrector; |
|
4081 var anTds, nTd; |
|
4082 var iRow, iRows = oSettings.aoData.length, |
|
4083 iColumn, iColumns, oData, sNodeName, iStart = 0, iEnd = iRows; |
|
4084 |
|
4085 /* Allow the collection to be limited to just one row */ |
|
4086 if (iIndividualRow !== undefined) { |
|
4087 iStart = iIndividualRow; |
|
4088 iEnd = iIndividualRow + 1; |
|
4089 } |
|
4090 |
|
4091 for (iRow = iStart; iRow < iEnd; iRow++) { |
|
4092 oData = oSettings.aoData[iRow]; |
|
4093 if (oData.nTr !== null) { |
|
4094 /* get the TD child nodes - taking into account text etc nodes */ |
|
4095 anTds = []; |
|
4096 nTd = oData.nTr.firstChild; |
|
4097 while (nTd) { |
|
4098 sNodeName = nTd.nodeName.toLowerCase(); |
|
4099 if (sNodeName == 'td' || sNodeName == 'th') { |
|
4100 anTds.push(nTd); |
|
4101 } |
|
4102 nTd = nTd.nextSibling; |
|
4103 } |
|
4104 |
|
4105 iCorrector = 0; |
|
4106 for (iColumn = 0, iColumns = oSettings.aoColumns.length; iColumn < iColumns; iColumn++) { |
|
4107 if (oSettings.aoColumns[iColumn].bVisible) { |
|
4108 anReturn.push(anTds[iColumn - iCorrector]); |
|
4109 } |
|
4110 else { |
|
4111 anReturn.push(oData._anHidden[iColumn]); |
|
4112 iCorrector++; |
|
4113 } |
|
4114 } |
|
4115 } |
|
4116 } |
|
4117 |
|
4118 return anReturn; |
|
4119 } |
|
4120 |
|
4121 |
|
4122 /** |
|
4123 * Log an error message |
|
4124 * @param {object} oSettings dataTables settings object |
|
4125 * @param {int} iLevel log error messages, or display them to the user |
|
4126 * @param {string} sMesg error message |
|
4127 * @memberof DataTable#oApi |
|
4128 */ |
|
4129 function _fnLog(oSettings, iLevel, sMesg) { |
|
4130 var sAlert = (oSettings === null) ? |
|
4131 "DataTables warning: " + sMesg : |
|
4132 "DataTables warning (table id = '" + oSettings.sTableId + "'): " + sMesg; |
|
4133 |
|
4134 if (iLevel === 0) { |
|
4135 if (DataTable.ext.sErrMode == 'alert') { |
|
4136 alert(sAlert); |
|
4137 } |
|
4138 else { |
|
4139 throw new Error(sAlert); |
|
4140 } |
|
4141 return; |
|
4142 } |
|
4143 else if (window.console && console.log) { |
|
4144 console.log(sAlert); |
|
4145 } |
|
4146 } |
|
4147 |
|
4148 |
|
4149 /** |
|
4150 * See if a property is defined on one object, if so assign it to the other object |
|
4151 * @param {object} oRet target object |
|
4152 * @param {object} oSrc source object |
|
4153 * @param {string} sName property |
|
4154 * @param {string} [sMappedName] name to map too - optional, sName used if not given |
|
4155 * @memberof DataTable#oApi |
|
4156 */ |
|
4157 function _fnMap(oRet, oSrc, sName, sMappedName) { |
|
4158 if (sMappedName === undefined) { |
|
4159 sMappedName = sName; |
|
4160 } |
|
4161 if (oSrc[sName] !== undefined) { |
|
4162 oRet[sMappedName] = oSrc[sName]; |
|
4163 } |
|
4164 } |
|
4165 |
|
4166 |
|
4167 /** |
|
4168 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow |
|
4169 * copy arrays. The reason we need to do this, is that we don't want to deep copy array |
|
4170 * init values (such as aaSorting) since the dev wouldn't be able to override them, but |
|
4171 * we do want to deep copy arrays. |
|
4172 * @param {object} oOut Object to extend |
|
4173 * @param {object} oExtender Object from which the properties will be applied to oOut |
|
4174 * @returns {object} oOut Reference, just for convenience - oOut === the return. |
|
4175 * @memberof DataTable#oApi |
|
4176 * @todo This doesn't take account of arrays inside the deep copied objects. |
|
4177 */ |
|
4178 function _fnExtend(oOut, oExtender) { |
|
4179 var val; |
|
4180 |
|
4181 for (var prop in oExtender) { |
|
4182 if (oExtender.hasOwnProperty(prop)) { |
|
4183 val = oExtender[prop]; |
|
4184 |
|
4185 if (typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false) { |
|
4186 $.extend(true, oOut[prop], val); |
|
4187 } |
|
4188 else { |
|
4189 oOut[prop] = val; |
|
4190 } |
|
4191 } |
|
4192 } |
|
4193 |
|
4194 return oOut; |
|
4195 } |
|
4196 |
|
4197 |
|
4198 /** |
|
4199 * Bind an event handers to allow a click or return key to activate the callback. |
|
4200 * This is good for accessibility since a return on the keyboard will have the |
|
4201 * same effect as a click, if the element has focus. |
|
4202 * @param {element} n Element to bind the action to |
|
4203 * @param {object} oData Data object to pass to the triggered function |
|
4204 * @param {function} fn Callback function for when the event is triggered |
|
4205 * @memberof DataTable#oApi |
|
4206 */ |
|
4207 function _fnBindAction(n, oData, fn) { |
|
4208 $(n) |
|
4209 .bind('click.DT', oData, function (e) { |
|
4210 n.blur(); // Remove focus outline for mouse users |
|
4211 fn(e); |
|
4212 }) |
|
4213 .bind('keypress.DT', oData, function (e) { |
|
4214 if (e.which === 13) { |
|
4215 fn(e); |
|
4216 } |
|
4217 }) |
|
4218 .bind('selectstart.DT', function () { |
|
4219 /* Take the brutal approach to cancelling text selection */ |
|
4220 return false; |
|
4221 }); |
|
4222 } |
|
4223 |
|
4224 |
|
4225 /** |
|
4226 * Register a callback function. Easily allows a callback function to be added to |
|
4227 * an array store of callback functions that can then all be called together. |
|
4228 * @param {object} oSettings dataTables settings object |
|
4229 * @param {string} sStore Name of the array storage for the callbacks in oSettings |
|
4230 * @param {function} fn Function to be called back |
|
4231 * @param {string} sName Identifying name for the callback (i.e. a label) |
|
4232 * @memberof DataTable#oApi |
|
4233 */ |
|
4234 function _fnCallbackReg(oSettings, sStore, fn, sName) { |
|
4235 if (fn) { |
|
4236 oSettings[sStore].push({ |
|
4237 "fn": fn, |
|
4238 "sName": sName |
|
4239 }); |
|
4240 } |
|
4241 } |
|
4242 |
|
4243 |
|
4244 /** |
|
4245 * Fire callback functions and trigger events. Note that the loop over the callback |
|
4246 * array store is done backwards! Further note that you do not want to fire off triggers |
|
4247 * in time sensitive applications (for example cell creation) as its slow. |
|
4248 * @param {object} oSettings dataTables settings object |
|
4249 * @param {string} sStore Name of the array storage for the callbacks in oSettings |
|
4250 * @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger |
|
4251 * is fired |
|
4252 * @param {array} aArgs Array of arguments to pass to the callback function / trigger |
|
4253 * @memberof DataTable#oApi |
|
4254 */ |
|
4255 function _fnCallbackFire(oSettings, sStore, sTrigger, aArgs) { |
|
4256 var aoStore = oSettings[sStore]; |
|
4257 var aRet = []; |
|
4258 |
|
4259 for (var i = aoStore.length - 1; i >= 0; i--) { |
|
4260 aRet.push(aoStore[i].fn.apply(oSettings.oInstance, aArgs)); |
|
4261 } |
|
4262 |
|
4263 if (sTrigger !== null) { |
|
4264 $(oSettings.oInstance).trigger(sTrigger, aArgs); |
|
4265 } |
|
4266 |
|
4267 return aRet; |
|
4268 } |
|
4269 |
|
4270 |
|
4271 /** |
|
4272 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other |
|
4273 * library, then we use that as it is fast, safe and accurate. If the function isn't |
|
4274 * available then we need to built it ourselves - the inspiration for this function comes |
|
4275 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is |
|
4276 * not perfect and absolutely should not be used as a replacement to json2.js - but it does |
|
4277 * do what we need, without requiring a dependency for DataTables. |
|
4278 * @param {object} o JSON object to be converted |
|
4279 * @returns {string} JSON string |
|
4280 * @memberof DataTable#oApi |
|
4281 */ |
|
4282 var _fnJsonString = (window.JSON) ? JSON.stringify : function (o) { |
|
4283 /* Not an object or array */ |
|
4284 var sType = typeof o; |
|
4285 if (sType !== "object" || o === null) { |
|
4286 // simple data type |
|
4287 if (sType === "string") { |
|
4288 o = '"' + o + '"'; |
|
4289 } |
|
4290 return o + ""; |
|
4291 } |
|
4292 |
|
4293 /* If object or array, need to recurse over it */ |
|
4294 var |
|
4295 sProp, mValue, |
|
4296 json = [], |
|
4297 bArr = $.isArray(o); |
|
4298 |
|
4299 for (sProp in o) { |
|
4300 mValue = o[sProp]; |
|
4301 sType = typeof mValue; |
|
4302 |
|
4303 if (sType === "string") { |
|
4304 mValue = '"' + mValue + '"'; |
|
4305 } |
|
4306 else if (sType === "object" && mValue !== null) { |
|
4307 mValue = _fnJsonString(mValue); |
|
4308 } |
|
4309 |
|
4310 json.push((bArr ? "" : '"' + sProp + '":') + mValue); |
|
4311 } |
|
4312 |
|
4313 return (bArr ? "[" : "{") + json + (bArr ? "]" : "}"); |
|
4314 }; |
|
4315 |
|
4316 |
|
4317 /** |
|
4318 * From some browsers (specifically IE6/7) we need special handling to work around browser |
|
4319 * bugs - this function is used to detect when these workarounds are needed. |
|
4320 * @param {object} oSettings dataTables settings object |
|
4321 * @memberof DataTable#oApi |
|
4322 */ |
|
4323 function _fnBrowserDetect(oSettings) { |
|
4324 /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the |
|
4325 * width of the scrollbar, while other browsers ensure the inner element is contained |
|
4326 * without forcing scrolling |
|
4327 */ |
|
4328 var n = $( |
|
4329 '<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">' + |
|
4330 '<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">' + |
|
4331 '<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>' + |
|
4332 '</div>' + |
|
4333 '</div>')[0]; |
|
4334 |
|
4335 document.body.appendChild(n); |
|
4336 oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false; |
|
4337 document.body.removeChild(n); |
|
4338 } |
|
4339 |
|
4340 |
|
4341 /** |
|
4342 * Perform a jQuery selector action on the table's TR elements (from the tbody) and |
|
4343 * return the resulting jQuery object. |
|
4344 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on |
|
4345 * @param {object} [oOpts] Optional parameters for modifying the rows to be included |
|
4346 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter |
|
4347 * criterion ("applied") or all TR elements (i.e. no filter). |
|
4348 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. |
|
4349 * Can be either 'current', whereby the current sorting of the table is used, or |
|
4350 * 'original' whereby the original order the data was read into the table is used. |
|
4351 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page |
|
4352 * ("current") or not ("all"). If 'current' is given, then order is assumed to be |
|
4353 * 'current' and filter is 'applied', regardless of what they might be given as. |
|
4354 * @returns {object} jQuery object, filtered by the given selector. |
|
4355 * @dtopt API |
|
4356 * |
|
4357 * @example |
|
4358 * $(document).ready(function() { |
|
4359 * var oTable = $('#example').dataTable(); |
|
4360 * |
|
4361 * // Highlight every second row |
|
4362 * oTable.$('tr:odd').css('backgroundColor', 'blue'); |
|
4363 * } ); |
|
4364 * |
|
4365 * @example |
|
4366 * $(document).ready(function() { |
|
4367 * var oTable = $('#example').dataTable(); |
|
4368 * |
|
4369 * // Filter to rows with 'Webkit' in them, add a background colour and then |
|
4370 * // remove the filter, thus highlighting the 'Webkit' rows only. |
|
4371 * oTable.fnFilter('Webkit'); |
|
4372 * oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue'); |
|
4373 * oTable.fnFilter(''); |
|
4374 * } ); |
|
4375 */ |
|
4376 this.$ = function (sSelector, oOpts) { |
|
4377 var i, iLen, a = [], tr; |
|
4378 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4379 var aoData = oSettings.aoData; |
|
4380 var aiDisplay = oSettings.aiDisplay; |
|
4381 var aiDisplayMaster = oSettings.aiDisplayMaster; |
|
4382 |
|
4383 if (!oOpts) { |
|
4384 oOpts = {}; |
|
4385 } |
|
4386 |
|
4387 oOpts = $.extend({}, { |
|
4388 "filter": "none", // applied |
|
4389 "order": "current", // "original" |
|
4390 "page": "all" // current |
|
4391 }, oOpts); |
|
4392 |
|
4393 // Current page implies that order=current and fitler=applied, since it is fairly |
|
4394 // senseless otherwise |
|
4395 if (oOpts.page == 'current') { |
|
4396 for (i = oSettings._iDisplayStart, iLen = oSettings.fnDisplayEnd(); i < iLen; i++) { |
|
4397 tr = aoData[ aiDisplay[i] ].nTr; |
|
4398 if (tr) { |
|
4399 a.push(tr); |
|
4400 } |
|
4401 } |
|
4402 } |
|
4403 else if (oOpts.order == "current" && oOpts.filter == "none") { |
|
4404 for (i = 0, iLen = aiDisplayMaster.length; i < iLen; i++) { |
|
4405 tr = aoData[ aiDisplayMaster[i] ].nTr; |
|
4406 if (tr) { |
|
4407 a.push(tr); |
|
4408 } |
|
4409 } |
|
4410 } |
|
4411 else if (oOpts.order == "current" && oOpts.filter == "applied") { |
|
4412 for (i = 0, iLen = aiDisplay.length; i < iLen; i++) { |
|
4413 tr = aoData[ aiDisplay[i] ].nTr; |
|
4414 if (tr) { |
|
4415 a.push(tr); |
|
4416 } |
|
4417 } |
|
4418 } |
|
4419 else if (oOpts.order == "original" && oOpts.filter == "none") { |
|
4420 for (i = 0, iLen = aoData.length; i < iLen; i++) { |
|
4421 tr = aoData[ i ].nTr; |
|
4422 if (tr) { |
|
4423 a.push(tr); |
|
4424 } |
|
4425 } |
|
4426 } |
|
4427 else if (oOpts.order == "original" && oOpts.filter == "applied") { |
|
4428 for (i = 0, iLen = aoData.length; i < iLen; i++) { |
|
4429 tr = aoData[ i ].nTr; |
|
4430 if ($.inArray(i, aiDisplay) !== -1 && tr) { |
|
4431 a.push(tr); |
|
4432 } |
|
4433 } |
|
4434 } |
|
4435 else { |
|
4436 _fnLog(oSettings, 1, "Unknown selection options"); |
|
4437 } |
|
4438 |
|
4439 /* We need to filter on the TR elements and also 'find' in their descendants |
|
4440 * to make the selector act like it would in a full table - so we need |
|
4441 * to build both results and then combine them together |
|
4442 */ |
|
4443 var jqA = $(a); |
|
4444 var jqTRs = jqA.filter(sSelector); |
|
4445 var jqDescendants = jqA.find(sSelector); |
|
4446 |
|
4447 return $([].concat($.makeArray(jqTRs), $.makeArray(jqDescendants))); |
|
4448 }; |
|
4449 |
|
4450 |
|
4451 /** |
|
4452 * Almost identical to $ in operation, but in this case returns the data for the matched |
|
4453 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes |
|
4454 * rather than any descendants, so the data can be obtained for the row/cell. If matching |
|
4455 * rows are found, the data returned is the original data array/object that was used to |
|
4456 * create the row (or a generated array if from a DOM source). |
|
4457 * |
|
4458 * This method is often useful in-combination with $ where both functions are given the |
|
4459 * same parameters and the array indexes will match identically. |
|
4460 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on |
|
4461 * @param {object} [oOpts] Optional parameters for modifying the rows to be included |
|
4462 * @param {string} [oOpts.filter=none] Select elements that meet the current filter |
|
4463 * criterion ("applied") or all elements (i.e. no filter). |
|
4464 * @param {string} [oOpts.order=current] Order of the data in the processed array. |
|
4465 * Can be either 'current', whereby the current sorting of the table is used, or |
|
4466 * 'original' whereby the original order the data was read into the table is used. |
|
4467 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page |
|
4468 * ("current") or not ("all"). If 'current' is given, then order is assumed to be |
|
4469 * 'current' and filter is 'applied', regardless of what they might be given as. |
|
4470 * @returns {array} Data for the matched elements. If any elements, as a result of the |
|
4471 * selector, were not TR, TD or TH elements in the DataTable, they will have a null |
|
4472 * entry in the array. |
|
4473 * @dtopt API |
|
4474 * |
|
4475 * @example |
|
4476 * $(document).ready(function() { |
|
4477 * var oTable = $('#example').dataTable(); |
|
4478 * |
|
4479 * // Get the data from the first row in the table |
|
4480 * var data = oTable._('tr:first'); |
|
4481 * |
|
4482 * // Do something useful with the data |
|
4483 * alert( "First cell is: "+data[0] ); |
|
4484 * } ); |
|
4485 * |
|
4486 * @example |
|
4487 * $(document).ready(function() { |
|
4488 * var oTable = $('#example').dataTable(); |
|
4489 * |
|
4490 * // Filter to 'Webkit' and get all data for |
|
4491 * oTable.fnFilter('Webkit'); |
|
4492 * var data = oTable._('tr', {"filter": "applied"}); |
|
4493 * |
|
4494 * // Do something with the data |
|
4495 * alert( data.length+" rows matched the filter" ); |
|
4496 * } ); |
|
4497 */ |
|
4498 this._ = function (sSelector, oOpts) { |
|
4499 var aOut = []; |
|
4500 var i, iLen, iIndex; |
|
4501 var aTrs = this.$(sSelector, oOpts); |
|
4502 |
|
4503 for (i = 0, iLen = aTrs.length; i < iLen; i++) { |
|
4504 aOut.push(this.fnGetData(aTrs[i])); |
|
4505 } |
|
4506 |
|
4507 return aOut; |
|
4508 }; |
|
4509 |
|
4510 |
|
4511 /** |
|
4512 * Add a single new row or multiple rows of data to the table. Please note |
|
4513 * that this is suitable for client-side processing only - if you are using |
|
4514 * server-side processing (i.e. "bServerSide": true), then to add data, you |
|
4515 * must add it to the data source, i.e. the server-side, through an Ajax call. |
|
4516 * @param {array|object} mData The data to be added to the table. This can be: |
|
4517 * <ul> |
|
4518 * <li>1D array of data - add a single row with the data provided</li> |
|
4519 * <li>2D array of arrays - add multiple rows in a single call</li> |
|
4520 * <li>object - data object when using <i>mData</i></li> |
|
4521 * <li>array of objects - multiple data objects when using <i>mData</i></li> |
|
4522 * </ul> |
|
4523 * @param {bool} [bRedraw=true] redraw the table or not |
|
4524 * @returns {array} An array of integers, representing the list of indexes in |
|
4525 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to |
|
4526 * the table. |
|
4527 * @dtopt API |
|
4528 * |
|
4529 * @example |
|
4530 * // Global var for counter |
|
4531 * var giCount = 2; |
|
4532 * |
|
4533 * $(document).ready(function() { |
|
4534 * $('#example').dataTable(); |
|
4535 * } ); |
|
4536 * |
|
4537 * function fnClickAddRow() { |
|
4538 * $('#example').dataTable().fnAddData( [ |
|
4539 * giCount+".1", |
|
4540 * giCount+".2", |
|
4541 * giCount+".3", |
|
4542 * giCount+".4" ] |
|
4543 * ); |
|
4544 * |
|
4545 * giCount++; |
|
4546 * } |
|
4547 */ |
|
4548 this.fnAddData = function (mData, bRedraw) { |
|
4549 if (mData.length === 0) { |
|
4550 return []; |
|
4551 } |
|
4552 |
|
4553 var aiReturn = []; |
|
4554 var iTest; |
|
4555 |
|
4556 /* Find settings from table node */ |
|
4557 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4558 |
|
4559 /* Check if we want to add multiple rows or not */ |
|
4560 if (typeof mData[0] === "object" && mData[0] !== null) { |
|
4561 for (var i = 0; i < mData.length; i++) { |
|
4562 iTest = _fnAddData(oSettings, mData[i]); |
|
4563 if (iTest == -1) { |
|
4564 return aiReturn; |
|
4565 } |
|
4566 aiReturn.push(iTest); |
|
4567 } |
|
4568 } |
|
4569 else { |
|
4570 iTest = _fnAddData(oSettings, mData); |
|
4571 if (iTest == -1) { |
|
4572 return aiReturn; |
|
4573 } |
|
4574 aiReturn.push(iTest); |
|
4575 } |
|
4576 |
|
4577 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
|
4578 |
|
4579 if (bRedraw === undefined || bRedraw) { |
|
4580 _fnReDraw(oSettings); |
|
4581 } |
|
4582 return aiReturn; |
|
4583 }; |
|
4584 |
|
4585 |
|
4586 /** |
|
4587 * This function will make DataTables recalculate the column sizes, based on the data |
|
4588 * contained in the table and the sizes applied to the columns (in the DOM, CSS or |
|
4589 * through the sWidth parameter). This can be useful when the width of the table's |
|
4590 * parent element changes (for example a window resize). |
|
4591 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to |
|
4592 * @dtopt API |
|
4593 * |
|
4594 * @example |
|
4595 * $(document).ready(function() { |
|
4596 * var oTable = $('#example').dataTable( { |
|
4597 * "sScrollY": "200px", |
|
4598 * "bPaginate": false |
|
4599 * } ); |
|
4600 * |
|
4601 * $(window).bind('resize', function () { |
|
4602 * oTable.fnAdjustColumnSizing(); |
|
4603 * } ); |
|
4604 * } ); |
|
4605 */ |
|
4606 this.fnAdjustColumnSizing = function (bRedraw) { |
|
4607 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4608 _fnAdjustColumnSizing(oSettings); |
|
4609 |
|
4610 if (bRedraw === undefined || bRedraw) { |
|
4611 this.fnDraw(false); |
|
4612 } |
|
4613 else if (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") { |
|
4614 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ |
|
4615 this.oApi._fnScrollDraw(oSettings); |
|
4616 } |
|
4617 }; |
|
4618 |
|
4619 |
|
4620 /** |
|
4621 * Quickly and simply clear a table |
|
4622 * @param {bool} [bRedraw=true] redraw the table or not |
|
4623 * @dtopt API |
|
4624 * |
|
4625 * @example |
|
4626 * $(document).ready(function() { |
|
4627 * var oTable = $('#example').dataTable(); |
|
4628 * |
|
4629 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) |
|
4630 * oTable.fnClearTable(); |
|
4631 * } ); |
|
4632 */ |
|
4633 this.fnClearTable = function (bRedraw) { |
|
4634 /* Find settings from table node */ |
|
4635 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4636 _fnClearTable(oSettings); |
|
4637 |
|
4638 if (bRedraw === undefined || bRedraw) { |
|
4639 _fnDraw(oSettings); |
|
4640 } |
|
4641 }; |
|
4642 |
|
4643 |
|
4644 /** |
|
4645 * The exact opposite of 'opening' a row, this function will close any rows which |
|
4646 * are currently 'open'. |
|
4647 * @param {node} nTr the table row to 'close' |
|
4648 * @returns {int} 0 on success, or 1 if failed (can't find the row) |
|
4649 * @dtopt API |
|
4650 * |
|
4651 * @example |
|
4652 * $(document).ready(function() { |
|
4653 * var oTable; |
|
4654 * |
|
4655 * // 'open' an information row when a row is clicked on |
|
4656 * $('#example tbody tr').click( function () { |
|
4657 * if ( oTable.fnIsOpen(this) ) { |
|
4658 * oTable.fnClose( this ); |
|
4659 * } else { |
|
4660 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); |
|
4661 * } |
|
4662 * } ); |
|
4663 * |
|
4664 * oTable = $('#example').dataTable(); |
|
4665 * } ); |
|
4666 */ |
|
4667 this.fnClose = function (nTr) { |
|
4668 /* Find settings from table node */ |
|
4669 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4670 |
|
4671 for (var i = 0; i < oSettings.aoOpenRows.length; i++) { |
|
4672 if (oSettings.aoOpenRows[i].nParent == nTr) { |
|
4673 var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode; |
|
4674 if (nTrParent) { |
|
4675 /* Remove it if it is currently on display */ |
|
4676 nTrParent.removeChild(oSettings.aoOpenRows[i].nTr); |
|
4677 } |
|
4678 oSettings.aoOpenRows.splice(i, 1); |
|
4679 return 0; |
|
4680 } |
|
4681 } |
|
4682 return 1; |
|
4683 }; |
|
4684 |
|
4685 |
|
4686 /** |
|
4687 * Remove a row for the table |
|
4688 * @param {mixed} mTarget The index of the row from aoData to be deleted, or |
|
4689 * the TR element you want to delete |
|
4690 * @param {function|null} [fnCallBack] Callback function |
|
4691 * @param {bool} [bRedraw=true] Redraw the table or not |
|
4692 * @returns {array} The row that was deleted |
|
4693 * @dtopt API |
|
4694 * |
|
4695 * @example |
|
4696 * $(document).ready(function() { |
|
4697 * var oTable = $('#example').dataTable(); |
|
4698 * |
|
4699 * // Immediately remove the first row |
|
4700 * oTable.fnDeleteRow( 0 ); |
|
4701 * } ); |
|
4702 */ |
|
4703 this.fnDeleteRow = function (mTarget, fnCallBack, bRedraw) { |
|
4704 /* Find settings from table node */ |
|
4705 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4706 var i, iLen, iAODataIndex; |
|
4707 |
|
4708 iAODataIndex = (typeof mTarget === 'object') ? |
|
4709 _fnNodeToDataIndex(oSettings, mTarget) : mTarget; |
|
4710 |
|
4711 /* Return the data array from this row */ |
|
4712 var oData = oSettings.aoData.splice(iAODataIndex, 1); |
|
4713 |
|
4714 /* Update the _DT_RowIndex parameter */ |
|
4715 for (i = 0, iLen = oSettings.aoData.length; i < iLen; i++) { |
|
4716 if (oSettings.aoData[i].nTr !== null) { |
|
4717 oSettings.aoData[i].nTr._DT_RowIndex = i; |
|
4718 } |
|
4719 } |
|
4720 |
|
4721 /* Remove the target row from the search array */ |
|
4722 var iDisplayIndex = $.inArray(iAODataIndex, oSettings.aiDisplay); |
|
4723 oSettings.asDataSearch.splice(iDisplayIndex, 1); |
|
4724 |
|
4725 /* Delete from the display arrays */ |
|
4726 _fnDeleteIndex(oSettings.aiDisplayMaster, iAODataIndex); |
|
4727 _fnDeleteIndex(oSettings.aiDisplay, iAODataIndex); |
|
4728 |
|
4729 /* If there is a user callback function - call it */ |
|
4730 if (typeof fnCallBack === "function") { |
|
4731 fnCallBack.call(this, oSettings, oData); |
|
4732 } |
|
4733 |
|
4734 /* Check for an 'overflow' they case for displaying the table */ |
|
4735 if (oSettings._iDisplayStart >= oSettings.fnRecordsDisplay()) { |
|
4736 oSettings._iDisplayStart -= oSettings._iDisplayLength; |
|
4737 if (oSettings._iDisplayStart < 0) { |
|
4738 oSettings._iDisplayStart = 0; |
|
4739 } |
|
4740 } |
|
4741 |
|
4742 if (bRedraw === undefined || bRedraw) { |
|
4743 _fnCalculateEnd(oSettings); |
|
4744 _fnDraw(oSettings); |
|
4745 } |
|
4746 |
|
4747 return oData; |
|
4748 }; |
|
4749 |
|
4750 |
|
4751 /** |
|
4752 * Restore the table to it's original state in the DOM by removing all of DataTables |
|
4753 * enhancements, alterations to the DOM structure of the table and event listeners. |
|
4754 * @param {boolean} [bRemove=false] Completely remove the table from the DOM |
|
4755 * @dtopt API |
|
4756 * |
|
4757 * @example |
|
4758 * $(document).ready(function() { |
|
4759 * // This example is fairly pointless in reality, but shows how fnDestroy can be used |
|
4760 * var oTable = $('#example').dataTable(); |
|
4761 * oTable.fnDestroy(); |
|
4762 * } ); |
|
4763 */ |
|
4764 this.fnDestroy = function (bRemove) { |
|
4765 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4766 var nOrig = oSettings.nTableWrapper.parentNode; |
|
4767 var nBody = oSettings.nTBody; |
|
4768 var i, iLen; |
|
4769 |
|
4770 bRemove = (bRemove === undefined) ? false : bRemove; |
|
4771 |
|
4772 /* Flag to note that the table is currently being destroyed - no action should be taken */ |
|
4773 oSettings.bDestroying = true; |
|
4774 |
|
4775 /* Fire off the destroy callbacks for plug-ins etc */ |
|
4776 _fnCallbackFire(oSettings, "aoDestroyCallback", "destroy", [oSettings]); |
|
4777 |
|
4778 /* If the table is not being removed, restore the hidden columns */ |
|
4779 if (!bRemove) { |
|
4780 for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) { |
|
4781 if (oSettings.aoColumns[i].bVisible === false) { |
|
4782 this.fnSetColumnVis(i, true); |
|
4783 } |
|
4784 } |
|
4785 } |
|
4786 |
|
4787 /* Blitz all DT events */ |
|
4788 $(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT'); |
|
4789 |
|
4790 /* If there is an 'empty' indicator row, remove it */ |
|
4791 $('tbody>tr>td.' + oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove(); |
|
4792 |
|
4793 /* When scrolling we had to break the table up - restore it */ |
|
4794 if (oSettings.nTable != oSettings.nTHead.parentNode) { |
|
4795 $(oSettings.nTable).children('thead').remove(); |
|
4796 oSettings.nTable.appendChild(oSettings.nTHead); |
|
4797 } |
|
4798 |
|
4799 if (oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode) { |
|
4800 $(oSettings.nTable).children('tfoot').remove(); |
|
4801 oSettings.nTable.appendChild(oSettings.nTFoot); |
|
4802 } |
|
4803 |
|
4804 /* Remove the DataTables generated nodes, events and classes */ |
|
4805 oSettings.nTable.parentNode.removeChild(oSettings.nTable); |
|
4806 $(oSettings.nTableWrapper).remove(); |
|
4807 |
|
4808 oSettings.aaSorting = []; |
|
4809 oSettings.aaSortingFixed = []; |
|
4810 _fnSortingClasses(oSettings); |
|
4811 |
|
4812 $(_fnGetTrNodes(oSettings)).removeClass(oSettings.asStripeClasses.join(' ')); |
|
4813 |
|
4814 $('th, td', oSettings.nTHead).removeClass([ |
|
4815 oSettings.oClasses.sSortable, |
|
4816 oSettings.oClasses.sSortableAsc, |
|
4817 oSettings.oClasses.sSortableDesc, |
|
4818 oSettings.oClasses.sSortableNone ].join(' ') |
|
4819 ); |
|
4820 if (oSettings.bJUI) { |
|
4821 $('th span.' + oSettings.oClasses.sSortIcon |
|
4822 + ', td span.' + oSettings.oClasses.sSortIcon, oSettings.nTHead).remove(); |
|
4823 |
|
4824 $('th, td', oSettings.nTHead).each(function () { |
|
4825 var jqWrapper = $('div.' + oSettings.oClasses.sSortJUIWrapper, this); |
|
4826 var kids = jqWrapper.contents(); |
|
4827 $(this).append(kids); |
|
4828 jqWrapper.remove(); |
|
4829 }); |
|
4830 } |
|
4831 |
|
4832 /* Add the TR elements back into the table in their original order */ |
|
4833 if (!bRemove && oSettings.nTableReinsertBefore) { |
|
4834 nOrig.insertBefore(oSettings.nTable, oSettings.nTableReinsertBefore); |
|
4835 } |
|
4836 else if (!bRemove) { |
|
4837 nOrig.appendChild(oSettings.nTable); |
|
4838 } |
|
4839 |
|
4840 for (i = 0, iLen = oSettings.aoData.length; i < iLen; i++) { |
|
4841 if (oSettings.aoData[i].nTr !== null) { |
|
4842 nBody.appendChild(oSettings.aoData[i].nTr); |
|
4843 } |
|
4844 } |
|
4845 |
|
4846 /* Restore the width of the original table */ |
|
4847 if (oSettings.oFeatures.bAutoWidth === true) { |
|
4848 oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth); |
|
4849 } |
|
4850 |
|
4851 /* If the were originally stripe classes - then we add them back here. Note |
|
4852 * this is not fool proof (for example if not all rows had stripe classes - but |
|
4853 * it's a good effort without getting carried away |
|
4854 */ |
|
4855 iLen = oSettings.asDestroyStripes.length; |
|
4856 if (iLen) { |
|
4857 var anRows = $(nBody).children('tr'); |
|
4858 for (i = 0; i < iLen; i++) { |
|
4859 anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass(oSettings.asDestroyStripes[i]); |
|
4860 } |
|
4861 } |
|
4862 |
|
4863 /* Remove the settings object from the settings array */ |
|
4864 for (i = 0, iLen = DataTable.settings.length; i < iLen; i++) { |
|
4865 if (DataTable.settings[i] == oSettings) { |
|
4866 DataTable.settings.splice(i, 1); |
|
4867 } |
|
4868 } |
|
4869 |
|
4870 /* End it all */ |
|
4871 oSettings = null; |
|
4872 oInit = null; |
|
4873 }; |
|
4874 |
|
4875 |
|
4876 /** |
|
4877 * Redraw the table |
|
4878 * @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw. |
|
4879 * @dtopt API |
|
4880 * |
|
4881 * @example |
|
4882 * $(document).ready(function() { |
|
4883 * var oTable = $('#example').dataTable(); |
|
4884 * |
|
4885 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) |
|
4886 * oTable.fnDraw(); |
|
4887 * } ); |
|
4888 */ |
|
4889 this.fnDraw = function (bComplete) { |
|
4890 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4891 if (bComplete === false) { |
|
4892 _fnCalculateEnd(oSettings); |
|
4893 _fnDraw(oSettings); |
|
4894 } |
|
4895 else { |
|
4896 _fnReDraw(oSettings); |
|
4897 } |
|
4898 }; |
|
4899 |
|
4900 |
|
4901 /** |
|
4902 * Filter the input based on data |
|
4903 * @param {string} sInput String to filter the table on |
|
4904 * @param {int|null} [iColumn] Column to limit filtering to |
|
4905 * @param {bool} [bRegex=false] Treat as regular expression or not |
|
4906 * @param {bool} [bSmart=true] Perform smart filtering or not |
|
4907 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) |
|
4908 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) |
|
4909 * @dtopt API |
|
4910 * |
|
4911 * @example |
|
4912 * $(document).ready(function() { |
|
4913 * var oTable = $('#example').dataTable(); |
|
4914 * |
|
4915 * // Sometime later - filter... |
|
4916 * oTable.fnFilter( 'test string' ); |
|
4917 * } ); |
|
4918 */ |
|
4919 this.fnFilter = function (sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive) { |
|
4920 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
4921 |
|
4922 if (!oSettings.oFeatures.bFilter) { |
|
4923 return; |
|
4924 } |
|
4925 |
|
4926 if (bRegex === undefined || bRegex === null) { |
|
4927 bRegex = false; |
|
4928 } |
|
4929 |
|
4930 if (bSmart === undefined || bSmart === null) { |
|
4931 bSmart = true; |
|
4932 } |
|
4933 |
|
4934 if (bShowGlobal === undefined || bShowGlobal === null) { |
|
4935 bShowGlobal = true; |
|
4936 } |
|
4937 |
|
4938 if (bCaseInsensitive === undefined || bCaseInsensitive === null) { |
|
4939 bCaseInsensitive = true; |
|
4940 } |
|
4941 |
|
4942 if (iColumn === undefined || iColumn === null) { |
|
4943 /* Global filter */ |
|
4944 _fnFilterComplete(oSettings, { |
|
4945 "sSearch": sInput + "", |
|
4946 "bRegex": bRegex, |
|
4947 "bSmart": bSmart, |
|
4948 "bCaseInsensitive": bCaseInsensitive |
|
4949 }, 1); |
|
4950 |
|
4951 if (bShowGlobal && oSettings.aanFeatures.f) { |
|
4952 var n = oSettings.aanFeatures.f; |
|
4953 for (var i = 0, iLen = n.length; i < iLen; i++) { |
|
4954 // IE9 throws an 'unknown error' if document.activeElement is used |
|
4955 // inside an iframe or frame... |
|
4956 try { |
|
4957 if (n[i]._DT_Input != document.activeElement) { |
|
4958 $(n[i]._DT_Input).val(sInput); |
|
4959 } |
|
4960 } |
|
4961 catch (e) { |
|
4962 $(n[i]._DT_Input).val(sInput); |
|
4963 } |
|
4964 } |
|
4965 } |
|
4966 } |
|
4967 else { |
|
4968 /* Single column filter */ |
|
4969 $.extend(oSettings.aoPreSearchCols[ iColumn ], { |
|
4970 "sSearch": sInput + "", |
|
4971 "bRegex": bRegex, |
|
4972 "bSmart": bSmart, |
|
4973 "bCaseInsensitive": bCaseInsensitive |
|
4974 }); |
|
4975 _fnFilterComplete(oSettings, oSettings.oPreviousSearch, 1); |
|
4976 } |
|
4977 }; |
|
4978 |
|
4979 |
|
4980 /** |
|
4981 * Get the data for the whole table, an individual row or an individual cell based on the |
|
4982 * provided parameters. |
|
4983 * @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as |
|
4984 * a TR node then the data source for the whole row will be returned. If given as a |
|
4985 * TD/TH cell node then iCol will be automatically calculated and the data for the |
|
4986 * cell returned. If given as an integer, then this is treated as the aoData internal |
|
4987 * data index for the row (see fnGetPosition) and the data for that row used. |
|
4988 * @param {int} [iCol] Optional column index that you want the data of. |
|
4989 * @returns {array|object|string} If mRow is undefined, then the data for all rows is |
|
4990 * returned. If mRow is defined, just data for that row, and is iCol is |
|
4991 * defined, only data for the designated cell is returned. |
|
4992 * @dtopt API |
|
4993 * |
|
4994 * @example |
|
4995 * // Row data |
|
4996 * $(document).ready(function() { |
|
4997 * oTable = $('#example').dataTable(); |
|
4998 * |
|
4999 * oTable.$('tr').click( function () { |
|
5000 * var data = oTable.fnGetData( this ); |
|
5001 * // ... do something with the array / object of data for the row |
|
5002 * } ); |
|
5003 * } ); |
|
5004 * |
|
5005 * @example |
|
5006 * // Individual cell data |
|
5007 * $(document).ready(function() { |
|
5008 * oTable = $('#example').dataTable(); |
|
5009 * |
|
5010 * oTable.$('td').click( function () { |
|
5011 * var sData = oTable.fnGetData( this ); |
|
5012 * alert( 'The cell clicked on had the value of '+sData ); |
|
5013 * } ); |
|
5014 * } ); |
|
5015 */ |
|
5016 this.fnGetData = function (mRow, iCol) { |
|
5017 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5018 |
|
5019 if (mRow !== undefined) { |
|
5020 var iRow = mRow; |
|
5021 if (typeof mRow === 'object') { |
|
5022 var sNode = mRow.nodeName.toLowerCase(); |
|
5023 if (sNode === "tr") { |
|
5024 iRow = _fnNodeToDataIndex(oSettings, mRow); |
|
5025 } |
|
5026 else if (sNode === "td") { |
|
5027 iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode); |
|
5028 iCol = _fnNodeToColumnIndex(oSettings, iRow, mRow); |
|
5029 } |
|
5030 } |
|
5031 |
|
5032 if (iCol !== undefined) { |
|
5033 return _fnGetCellData(oSettings, iRow, iCol, ''); |
|
5034 } |
|
5035 return (oSettings.aoData[iRow] !== undefined) ? |
|
5036 oSettings.aoData[iRow]._aData : null; |
|
5037 } |
|
5038 return _fnGetDataMaster(oSettings); |
|
5039 }; |
|
5040 |
|
5041 |
|
5042 /** |
|
5043 * Get an array of the TR nodes that are used in the table's body. Note that you will |
|
5044 * typically want to use the '$' API method in preference to this as it is more |
|
5045 * flexible. |
|
5046 * @param {int} [iRow] Optional row index for the TR element you want |
|
5047 * @returns {array|node} If iRow is undefined, returns an array of all TR elements |
|
5048 * in the table's body, or iRow is defined, just the TR element requested. |
|
5049 * @dtopt API |
|
5050 * |
|
5051 * @example |
|
5052 * $(document).ready(function() { |
|
5053 * var oTable = $('#example').dataTable(); |
|
5054 * |
|
5055 * // Get the nodes from the table |
|
5056 * var nNodes = oTable.fnGetNodes( ); |
|
5057 * } ); |
|
5058 */ |
|
5059 this.fnGetNodes = function (iRow) { |
|
5060 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5061 |
|
5062 if (iRow !== undefined) { |
|
5063 return (oSettings.aoData[iRow] !== undefined) ? |
|
5064 oSettings.aoData[iRow].nTr : null; |
|
5065 } |
|
5066 return _fnGetTrNodes(oSettings); |
|
5067 }; |
|
5068 |
|
5069 |
|
5070 /** |
|
5071 * Get the array indexes of a particular cell from it's DOM element |
|
5072 * and column index including hidden columns |
|
5073 * @param {node} nNode this can either be a TR, TD or TH in the table's body |
|
5074 * @returns {int} If nNode is given as a TR, then a single index is returned, or |
|
5075 * if given as a cell, an array of [row index, column index (visible), |
|
5076 * column index (all)] is given. |
|
5077 * @dtopt API |
|
5078 * |
|
5079 * @example |
|
5080 * $(document).ready(function() { |
|
5081 * $('#example tbody td').click( function () { |
|
5082 * // Get the position of the current data from the node |
|
5083 * var aPos = oTable.fnGetPosition( this ); |
|
5084 * |
|
5085 * // Get the data array for this row |
|
5086 * var aData = oTable.fnGetData( aPos[0] ); |
|
5087 * |
|
5088 * // Update the data array and return the value |
|
5089 * aData[ aPos[1] ] = 'clicked'; |
|
5090 * this.innerHTML = 'clicked'; |
|
5091 * } ); |
|
5092 * |
|
5093 * // Init DataTables |
|
5094 * oTable = $('#example').dataTable(); |
|
5095 * } ); |
|
5096 */ |
|
5097 this.fnGetPosition = function (nNode) { |
|
5098 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5099 var sNodeName = nNode.nodeName.toUpperCase(); |
|
5100 |
|
5101 if (sNodeName == "TR") { |
|
5102 return _fnNodeToDataIndex(oSettings, nNode); |
|
5103 } |
|
5104 else if (sNodeName == "TD" || sNodeName == "TH") { |
|
5105 var iDataIndex = _fnNodeToDataIndex(oSettings, nNode.parentNode); |
|
5106 var iColumnIndex = _fnNodeToColumnIndex(oSettings, iDataIndex, nNode); |
|
5107 return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex), iColumnIndex ]; |
|
5108 } |
|
5109 return null; |
|
5110 }; |
|
5111 |
|
5112 |
|
5113 /** |
|
5114 * Check to see if a row is 'open' or not. |
|
5115 * @param {node} nTr the table row to check |
|
5116 * @returns {boolean} true if the row is currently open, false otherwise |
|
5117 * @dtopt API |
|
5118 * |
|
5119 * @example |
|
5120 * $(document).ready(function() { |
|
5121 * var oTable; |
|
5122 * |
|
5123 * // 'open' an information row when a row is clicked on |
|
5124 * $('#example tbody tr').click( function () { |
|
5125 * if ( oTable.fnIsOpen(this) ) { |
|
5126 * oTable.fnClose( this ); |
|
5127 * } else { |
|
5128 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); |
|
5129 * } |
|
5130 * } ); |
|
5131 * |
|
5132 * oTable = $('#example').dataTable(); |
|
5133 * } ); |
|
5134 */ |
|
5135 this.fnIsOpen = function (nTr) { |
|
5136 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5137 var aoOpenRows = oSettings.aoOpenRows; |
|
5138 |
|
5139 for (var i = 0; i < oSettings.aoOpenRows.length; i++) { |
|
5140 if (oSettings.aoOpenRows[i].nParent == nTr) { |
|
5141 return true; |
|
5142 } |
|
5143 } |
|
5144 return false; |
|
5145 }; |
|
5146 |
|
5147 |
|
5148 /** |
|
5149 * This function will place a new row directly after a row which is currently |
|
5150 * on display on the page, with the HTML contents that is passed into the |
|
5151 * function. This can be used, for example, to ask for confirmation that a |
|
5152 * particular record should be deleted. |
|
5153 * @param {node} nTr The table row to 'open' |
|
5154 * @param {string|node|jQuery} mHtml The HTML to put into the row |
|
5155 * @param {string} sClass Class to give the new TD cell |
|
5156 * @returns {node} The row opened. Note that if the table row passed in as the |
|
5157 * first parameter, is not found in the table, this method will silently |
|
5158 * return. |
|
5159 * @dtopt API |
|
5160 * |
|
5161 * @example |
|
5162 * $(document).ready(function() { |
|
5163 * var oTable; |
|
5164 * |
|
5165 * // 'open' an information row when a row is clicked on |
|
5166 * $('#example tbody tr').click( function () { |
|
5167 * if ( oTable.fnIsOpen(this) ) { |
|
5168 * oTable.fnClose( this ); |
|
5169 * } else { |
|
5170 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); |
|
5171 * } |
|
5172 * } ); |
|
5173 * |
|
5174 * oTable = $('#example').dataTable(); |
|
5175 * } ); |
|
5176 */ |
|
5177 this.fnOpen = function (nTr, mHtml, sClass) { |
|
5178 /* Find settings from table node */ |
|
5179 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5180 |
|
5181 /* Check that the row given is in the table */ |
|
5182 var nTableRows = _fnGetTrNodes(oSettings); |
|
5183 if ($.inArray(nTr, nTableRows) === -1) { |
|
5184 return; |
|
5185 } |
|
5186 |
|
5187 /* the old open one if there is one */ |
|
5188 this.fnClose(nTr); |
|
5189 |
|
5190 var nNewRow = document.createElement("tr"); |
|
5191 var nNewCell = document.createElement("td"); |
|
5192 nNewRow.appendChild(nNewCell); |
|
5193 nNewCell.className = sClass; |
|
5194 nNewCell.colSpan = _fnVisbleColumns(oSettings); |
|
5195 |
|
5196 if (typeof mHtml === "string") { |
|
5197 nNewCell.innerHTML = mHtml; |
|
5198 } |
|
5199 else { |
|
5200 $(nNewCell).html(mHtml); |
|
5201 } |
|
5202 |
|
5203 /* If the nTr isn't on the page at the moment - then we don't insert at the moment */ |
|
5204 var nTrs = $('tr', oSettings.nTBody); |
|
5205 if ($.inArray(nTr, nTrs) != -1) { |
|
5206 $(nNewRow).insertAfter(nTr); |
|
5207 } |
|
5208 |
|
5209 oSettings.aoOpenRows.push({ |
|
5210 "nTr": nNewRow, |
|
5211 "nParent": nTr |
|
5212 }); |
|
5213 |
|
5214 return nNewRow; |
|
5215 }; |
|
5216 |
|
5217 |
|
5218 /** |
|
5219 * Change the pagination - provides the internal logic for pagination in a simple API |
|
5220 * function. With this function you can have a DataTables table go to the next, |
|
5221 * previous, first or last pages. |
|
5222 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" |
|
5223 * or page number to jump to (integer), note that page 0 is the first page. |
|
5224 * @param {bool} [bRedraw=true] Redraw the table or not |
|
5225 * @dtopt API |
|
5226 * |
|
5227 * @example |
|
5228 * $(document).ready(function() { |
|
5229 * var oTable = $('#example').dataTable(); |
|
5230 * oTable.fnPageChange( 'next' ); |
|
5231 * } ); |
|
5232 */ |
|
5233 this.fnPageChange = function (mAction, bRedraw) { |
|
5234 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5235 _fnPageChange(oSettings, mAction); |
|
5236 _fnCalculateEnd(oSettings); |
|
5237 |
|
5238 if (bRedraw === undefined || bRedraw) { |
|
5239 _fnDraw(oSettings); |
|
5240 } |
|
5241 }; |
|
5242 |
|
5243 |
|
5244 /** |
|
5245 * Show a particular column |
|
5246 * @param {int} iCol The column whose display should be changed |
|
5247 * @param {bool} bShow Show (true) or hide (false) the column |
|
5248 * @param {bool} [bRedraw=true] Redraw the table or not |
|
5249 * @dtopt API |
|
5250 * |
|
5251 * @example |
|
5252 * $(document).ready(function() { |
|
5253 * var oTable = $('#example').dataTable(); |
|
5254 * |
|
5255 * // Hide the second column after initialisation |
|
5256 * oTable.fnSetColumnVis( 1, false ); |
|
5257 * } ); |
|
5258 */ |
|
5259 this.fnSetColumnVis = function (iCol, bShow, bRedraw) { |
|
5260 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5261 var i, iLen; |
|
5262 var aoColumns = oSettings.aoColumns; |
|
5263 var aoData = oSettings.aoData; |
|
5264 var nTd, bAppend, iBefore; |
|
5265 |
|
5266 /* No point in doing anything if we are requesting what is already true */ |
|
5267 if (aoColumns[iCol].bVisible == bShow) { |
|
5268 return; |
|
5269 } |
|
5270 |
|
5271 /* Show the column */ |
|
5272 if (bShow) { |
|
5273 var iInsert = 0; |
|
5274 for (i = 0; i < iCol; i++) { |
|
5275 if (aoColumns[i].bVisible) { |
|
5276 iInsert++; |
|
5277 } |
|
5278 } |
|
5279 |
|
5280 /* Need to decide if we should use appendChild or insertBefore */ |
|
5281 bAppend = (iInsert >= _fnVisbleColumns(oSettings)); |
|
5282 |
|
5283 /* Which coloumn should we be inserting before? */ |
|
5284 if (!bAppend) { |
|
5285 for (i = iCol; i < aoColumns.length; i++) { |
|
5286 if (aoColumns[i].bVisible) { |
|
5287 iBefore = i; |
|
5288 break; |
|
5289 } |
|
5290 } |
|
5291 } |
|
5292 |
|
5293 for (i = 0, iLen = aoData.length; i < iLen; i++) { |
|
5294 if (aoData[i].nTr !== null) { |
|
5295 if (bAppend) { |
|
5296 aoData[i].nTr.appendChild( |
|
5297 aoData[i]._anHidden[iCol] |
|
5298 ); |
|
5299 } |
|
5300 else { |
|
5301 aoData[i].nTr.insertBefore( |
|
5302 aoData[i]._anHidden[iCol], |
|
5303 _fnGetTdNodes(oSettings, i)[iBefore]); |
|
5304 } |
|
5305 } |
|
5306 } |
|
5307 } |
|
5308 else { |
|
5309 /* Remove a column from display */ |
|
5310 for (i = 0, iLen = aoData.length; i < iLen; i++) { |
|
5311 if (aoData[i].nTr !== null) { |
|
5312 nTd = _fnGetTdNodes(oSettings, i)[iCol]; |
|
5313 aoData[i]._anHidden[iCol] = nTd; |
|
5314 nTd.parentNode.removeChild(nTd); |
|
5315 } |
|
5316 } |
|
5317 } |
|
5318 |
|
5319 /* Clear to set the visible flag */ |
|
5320 aoColumns[iCol].bVisible = bShow; |
|
5321 |
|
5322 /* Redraw the header and footer based on the new column visibility */ |
|
5323 _fnDrawHead(oSettings, oSettings.aoHeader); |
|
5324 if (oSettings.nTFoot) { |
|
5325 _fnDrawHead(oSettings, oSettings.aoFooter); |
|
5326 } |
|
5327 |
|
5328 /* If there are any 'open' rows, then we need to alter the colspan for this col change */ |
|
5329 for (i = 0, iLen = oSettings.aoOpenRows.length; i < iLen; i++) { |
|
5330 oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns(oSettings); |
|
5331 } |
|
5332 |
|
5333 /* Do a redraw incase anything depending on the table columns needs it |
|
5334 * (built-in: scrolling) |
|
5335 */ |
|
5336 if (bRedraw === undefined || bRedraw) { |
|
5337 _fnAdjustColumnSizing(oSettings); |
|
5338 _fnDraw(oSettings); |
|
5339 } |
|
5340 |
|
5341 _fnSaveState(oSettings); |
|
5342 }; |
|
5343 |
|
5344 |
|
5345 /** |
|
5346 * Get the settings for a particular table for external manipulation |
|
5347 * @returns {object} DataTables settings object. See |
|
5348 * {@link DataTable.models.oSettings} |
|
5349 * @dtopt API |
|
5350 * |
|
5351 * @example |
|
5352 * $(document).ready(function() { |
|
5353 * var oTable = $('#example').dataTable(); |
|
5354 * var oSettings = oTable.fnSettings(); |
|
5355 * |
|
5356 * // Show an example parameter from the settings |
|
5357 * alert( oSettings._iDisplayStart ); |
|
5358 * } ); |
|
5359 */ |
|
5360 this.fnSettings = function () { |
|
5361 return _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5362 }; |
|
5363 |
|
5364 |
|
5365 /** |
|
5366 * Sort the table by a particular column |
|
5367 * @param {int} iCol the data index to sort on. Note that this will not match the |
|
5368 * 'display index' if you have hidden data entries |
|
5369 * @dtopt API |
|
5370 * |
|
5371 * @example |
|
5372 * $(document).ready(function() { |
|
5373 * var oTable = $('#example').dataTable(); |
|
5374 * |
|
5375 * // Sort immediately with columns 0 and 1 |
|
5376 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); |
|
5377 * } ); |
|
5378 */ |
|
5379 this.fnSort = function (aaSort) { |
|
5380 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5381 oSettings.aaSorting = aaSort; |
|
5382 _fnSort(oSettings); |
|
5383 }; |
|
5384 |
|
5385 |
|
5386 /** |
|
5387 * Attach a sort listener to an element for a given column |
|
5388 * @param {node} nNode the element to attach the sort listener to |
|
5389 * @param {int} iColumn the column that a click on this node will sort on |
|
5390 * @param {function} [fnCallback] callback function when sort is run |
|
5391 * @dtopt API |
|
5392 * |
|
5393 * @example |
|
5394 * $(document).ready(function() { |
|
5395 * var oTable = $('#example').dataTable(); |
|
5396 * |
|
5397 * // Sort on column 1, when 'sorter' is clicked on |
|
5398 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); |
|
5399 * } ); |
|
5400 */ |
|
5401 this.fnSortListener = function (nNode, iColumn, fnCallback) { |
|
5402 _fnSortAttachListener(_fnSettingsFromNode(this[DataTable.ext.iApiIndex]), nNode, iColumn, |
|
5403 fnCallback); |
|
5404 }; |
|
5405 |
|
5406 |
|
5407 /** |
|
5408 * Update a table cell or row - this method will accept either a single value to |
|
5409 * update the cell with, an array of values with one element for each column or |
|
5410 * an object in the same format as the original data source. The function is |
|
5411 * self-referencing in order to make the multi column updates easier. |
|
5412 * @param {object|array|string} mData Data to update the cell/row with |
|
5413 * @param {node|int} mRow TR element you want to update or the aoData index |
|
5414 * @param {int} [iColumn] The column to update (not used of mData is an array or object) |
|
5415 * @param {bool} [bRedraw=true] Redraw the table or not |
|
5416 * @param {bool} [bAction=true] Perform pre-draw actions or not |
|
5417 * @returns {int} 0 on success, 1 on error |
|
5418 * @dtopt API |
|
5419 * |
|
5420 * @example |
|
5421 * $(document).ready(function() { |
|
5422 * var oTable = $('#example').dataTable(); |
|
5423 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell |
|
5424 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row |
|
5425 * } ); |
|
5426 */ |
|
5427 this.fnUpdate = function (mData, mRow, iColumn, bRedraw, bAction) { |
|
5428 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
|
5429 var i, iLen, sDisplay; |
|
5430 var iRow = (typeof mRow === 'object') ? |
|
5431 _fnNodeToDataIndex(oSettings, mRow) : mRow; |
|
5432 |
|
5433 if ($.isArray(mData) && iColumn === undefined) { |
|
5434 /* Array update - update the whole row */ |
|
5435 oSettings.aoData[iRow]._aData = mData.slice(); |
|
5436 |
|
5437 /* Flag to the function that we are recursing */ |
|
5438 for (i = 0; i < oSettings.aoColumns.length; i++) { |
|
5439 this.fnUpdate(_fnGetCellData(oSettings, iRow, i), iRow, i, false, false); |
|
5440 } |
|
5441 } |
|
5442 else if ($.isPlainObject(mData) && iColumn === undefined) { |
|
5443 /* Object update - update the whole row - assume the developer gets the object right */ |
|
5444 oSettings.aoData[iRow]._aData = $.extend(true, {}, mData); |
|
5445 |
|
5446 for (i = 0; i < oSettings.aoColumns.length; i++) { |
|
5447 this.fnUpdate(_fnGetCellData(oSettings, iRow, i), iRow, i, false, false); |
|
5448 } |
|
5449 } |
|
5450 else { |
|
5451 /* Individual cell update */ |
|
5452 _fnSetCellData(oSettings, iRow, iColumn, mData); |
|
5453 sDisplay = _fnGetCellData(oSettings, iRow, iColumn, 'display'); |
|
5454 |
|
5455 var oCol = oSettings.aoColumns[iColumn]; |
|
5456 if (oCol.fnRender !== null) { |
|
5457 sDisplay = _fnRender(oSettings, iRow, iColumn); |
|
5458 if (oCol.bUseRendered) { |
|
5459 _fnSetCellData(oSettings, iRow, iColumn, sDisplay); |
|
5460 } |
|
5461 } |
|
5462 |
|
5463 if (oSettings.aoData[iRow].nTr !== null) { |
|
5464 /* Do the actual HTML update */ |
|
5465 _fnGetTdNodes(oSettings, iRow)[iColumn].innerHTML = sDisplay; |
|
5466 } |
|
5467 } |
|
5468 |
|
5469 /* Modify the search index for this row (strictly this is likely not needed, since fnReDraw |
|
5470 * will rebuild the search array - however, the redraw might be disabled by the user) |
|
5471 */ |
|
5472 var iDisplayIndex = $.inArray(iRow, oSettings.aiDisplay); |
|
5473 oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( |
|
5474 oSettings, |
|
5475 _fnGetRowData(oSettings, iRow, 'filter', _fnGetColumns(oSettings, 'bSearchable')) |
|
5476 ); |
|
5477 |
|
5478 /* Perform pre-draw actions */ |
|
5479 if (bAction === undefined || bAction) { |
|
5480 _fnAdjustColumnSizing(oSettings); |
|
5481 } |
|
5482 |
|
5483 /* Redraw the table */ |
|
5484 if (bRedraw === undefined || bRedraw) { |
|
5485 _fnReDraw(oSettings); |
|
5486 } |
|
5487 return 0; |
|
5488 }; |
|
5489 |
|
5490 |
|
5491 /** |
|
5492 * Provide a common method for plug-ins to check the version of DataTables being used, in order |
|
5493 * to ensure compatibility. |
|
5494 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the |
|
5495 * formats "X" and "X.Y" are also acceptable. |
|
5496 * @returns {boolean} true if this version of DataTables is greater or equal to the required |
|
5497 * version, or false if this version of DataTales is not suitable |
|
5498 * @method |
|
5499 * @dtopt API |
|
5500 * |
|
5501 * @example |
|
5502 * $(document).ready(function() { |
|
5503 * var oTable = $('#example').dataTable(); |
|
5504 * alert( oTable.fnVersionCheck( '1.9.0' ) ); |
|
5505 * } ); |
|
5506 */ |
|
5507 this.fnVersionCheck = DataTable.ext.fnVersionCheck; |
|
5508 |
|
5509 |
|
5510 /* |
|
5511 * This is really a good bit rubbish this method of exposing the internal methods |
|
5512 * publicly... - To be fixed in 2.0 using methods on the prototype |
|
5513 */ |
|
5514 |
|
5515 |
|
5516 /** |
|
5517 * Create a wrapper function for exporting an internal functions to an external API. |
|
5518 * @param {string} sFunc API function name |
|
5519 * @returns {function} wrapped function |
|
5520 * @memberof DataTable#oApi |
|
5521 */ |
|
5522 function _fnExternApiFunc(sFunc) { |
|
5523 return function () { |
|
5524 var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat( |
|
5525 Array.prototype.slice.call(arguments)); |
|
5526 return DataTable.ext.oApi[sFunc].apply(this, aArgs); |
|
5527 }; |
|
5528 } |
|
5529 |
|
5530 |
|
5531 /** |
|
5532 * Reference to internal functions for use by plug-in developers. Note that these |
|
5533 * methods are references to internal functions and are considered to be private. |
|
5534 * If you use these methods, be aware that they are liable to change between versions |
|
5535 * (check the upgrade notes). |
|
5536 * @namespace |
|
5537 */ |
|
5538 this.oApi = { |
|
5539 "_fnExternApiFunc": _fnExternApiFunc, |
|
5540 "_fnInitialise": _fnInitialise, |
|
5541 "_fnInitComplete": _fnInitComplete, |
|
5542 "_fnLanguageCompat": _fnLanguageCompat, |
|
5543 "_fnAddColumn": _fnAddColumn, |
|
5544 "_fnColumnOptions": _fnColumnOptions, |
|
5545 "_fnAddData": _fnAddData, |
|
5546 "_fnCreateTr": _fnCreateTr, |
|
5547 "_fnGatherData": _fnGatherData, |
|
5548 "_fnBuildHead": _fnBuildHead, |
|
5549 "_fnDrawHead": _fnDrawHead, |
|
5550 "_fnDraw": _fnDraw, |
|
5551 "_fnReDraw": _fnReDraw, |
|
5552 "_fnAjaxUpdate": _fnAjaxUpdate, |
|
5553 "_fnAjaxParameters": _fnAjaxParameters, |
|
5554 "_fnAjaxUpdateDraw": _fnAjaxUpdateDraw, |
|
5555 "_fnServerParams": _fnServerParams, |
|
5556 "_fnAddOptionsHtml": _fnAddOptionsHtml, |
|
5557 "_fnFeatureHtmlTable": _fnFeatureHtmlTable, |
|
5558 "_fnScrollDraw": _fnScrollDraw, |
|
5559 "_fnAdjustColumnSizing": _fnAdjustColumnSizing, |
|
5560 "_fnFeatureHtmlFilter": _fnFeatureHtmlFilter, |
|
5561 "_fnFilterComplete": _fnFilterComplete, |
|
5562 "_fnFilterCustom": _fnFilterCustom, |
|
5563 "_fnFilterColumn": _fnFilterColumn, |
|
5564 "_fnFilter": _fnFilter, |
|
5565 "_fnBuildSearchArray": _fnBuildSearchArray, |
|
5566 "_fnBuildSearchRow": _fnBuildSearchRow, |
|
5567 "_fnFilterCreateSearch": _fnFilterCreateSearch, |
|
5568 "_fnDataToSearch": _fnDataToSearch, |
|
5569 "_fnSort": _fnSort, |
|
5570 "_fnSortAttachListener": _fnSortAttachListener, |
|
5571 "_fnSortingClasses": _fnSortingClasses, |
|
5572 "_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate, |
|
5573 "_fnPageChange": _fnPageChange, |
|
5574 "_fnFeatureHtmlInfo": _fnFeatureHtmlInfo, |
|
5575 "_fnUpdateInfo": _fnUpdateInfo, |
|
5576 "_fnFeatureHtmlLength": _fnFeatureHtmlLength, |
|
5577 "_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing, |
|
5578 "_fnProcessingDisplay": _fnProcessingDisplay, |
|
5579 "_fnVisibleToColumnIndex": _fnVisibleToColumnIndex, |
|
5580 "_fnColumnIndexToVisible": _fnColumnIndexToVisible, |
|
5581 "_fnNodeToDataIndex": _fnNodeToDataIndex, |
|
5582 "_fnVisbleColumns": _fnVisbleColumns, |
|
5583 "_fnCalculateEnd": _fnCalculateEnd, |
|
5584 "_fnConvertToWidth": _fnConvertToWidth, |
|
5585 "_fnCalculateColumnWidths": _fnCalculateColumnWidths, |
|
5586 "_fnScrollingWidthAdjust": _fnScrollingWidthAdjust, |
|
5587 "_fnGetWidestNode": _fnGetWidestNode, |
|
5588 "_fnGetMaxLenString": _fnGetMaxLenString, |
|
5589 "_fnStringToCss": _fnStringToCss, |
|
5590 "_fnDetectType": _fnDetectType, |
|
5591 "_fnSettingsFromNode": _fnSettingsFromNode, |
|
5592 "_fnGetDataMaster": _fnGetDataMaster, |
|
5593 "_fnGetTrNodes": _fnGetTrNodes, |
|
5594 "_fnGetTdNodes": _fnGetTdNodes, |
|
5595 "_fnEscapeRegex": _fnEscapeRegex, |
|
5596 "_fnDeleteIndex": _fnDeleteIndex, |
|
5597 "_fnReOrderIndex": _fnReOrderIndex, |
|
5598 "_fnColumnOrdering": _fnColumnOrdering, |
|
5599 "_fnLog": _fnLog, |
|
5600 "_fnClearTable": _fnClearTable, |
|
5601 "_fnSaveState": _fnSaveState, |
|
5602 "_fnLoadState": _fnLoadState, |
|
5603 "_fnCreateCookie": _fnCreateCookie, |
|
5604 "_fnReadCookie": _fnReadCookie, |
|
5605 "_fnDetectHeader": _fnDetectHeader, |
|
5606 "_fnGetUniqueThs": _fnGetUniqueThs, |
|
5607 "_fnScrollBarWidth": _fnScrollBarWidth, |
|
5608 "_fnApplyToChildren": _fnApplyToChildren, |
|
5609 "_fnMap": _fnMap, |
|
5610 "_fnGetRowData": _fnGetRowData, |
|
5611 "_fnGetCellData": _fnGetCellData, |
|
5612 "_fnSetCellData": _fnSetCellData, |
|
5613 "_fnGetObjectDataFn": _fnGetObjectDataFn, |
|
5614 "_fnSetObjectDataFn": _fnSetObjectDataFn, |
|
5615 "_fnApplyColumnDefs": _fnApplyColumnDefs, |
|
5616 "_fnBindAction": _fnBindAction, |
|
5617 "_fnExtend": _fnExtend, |
|
5618 "_fnCallbackReg": _fnCallbackReg, |
|
5619 "_fnCallbackFire": _fnCallbackFire, |
|
5620 "_fnJsonString": _fnJsonString, |
|
5621 "_fnRender": _fnRender, |
|
5622 "_fnNodeToColumnIndex": _fnNodeToColumnIndex, |
|
5623 "_fnInfoMacros": _fnInfoMacros, |
|
5624 "_fnBrowserDetect": _fnBrowserDetect, |
|
5625 "_fnGetColumns": _fnGetColumns |
|
5626 }; |
|
5627 |
|
5628 $.extend(DataTable.ext.oApi, this.oApi); |
|
5629 |
|
5630 for (var sFunc in DataTable.ext.oApi) { |
|
5631 if (sFunc) { |
|
5632 this[sFunc] = _fnExternApiFunc(sFunc); |
|
5633 } |
|
5634 } |
|
5635 |
|
5636 |
|
5637 var _that = this; |
|
5638 this.each(function () { |
|
5639 var i = 0, iLen, j, jLen, k, kLen; |
|
5640 var sId = this.getAttribute('id'); |
|
5641 var bInitHandedOff = false; |
|
5642 var bUsePassedData = false; |
|
5643 |
|
5644 |
|
5645 /* Sanity check */ |
|
5646 if (this.nodeName.toLowerCase() != 'table') { |
|
5647 _fnLog(null, 0, "Attempted to initialise DataTables on a node which is not a " + |
|
5648 "table: " + this.nodeName); |
|
5649 return; |
|
5650 } |
|
5651 |
|
5652 /* Check to see if we are re-initialising a table */ |
|
5653 for (i = 0, iLen = DataTable.settings.length; i < iLen; i++) { |
|
5654 /* Base check on table node */ |
|
5655 if (DataTable.settings[i].nTable == this) { |
|
5656 if (oInit === undefined || oInit.bRetrieve) { |
|
5657 return DataTable.settings[i].oInstance; |
|
5658 } |
|
5659 else if (oInit.bDestroy) { |
|
5660 DataTable.settings[i].oInstance.fnDestroy(); |
|
5661 break; |
|
5662 } |
|
5663 else { |
|
5664 _fnLog(DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n" + |
|
5665 "To retrieve the DataTables object for this table, pass no arguments or see " + |
|
5666 "the docs for bRetrieve and bDestroy"); |
|
5667 return; |
|
5668 } |
|
5669 } |
|
5670 |
|
5671 /* If the element we are initialising has the same ID as a table which was previously |
|
5672 * initialised, but the table nodes don't match (from before) then we destroy the old |
|
5673 * instance by simply deleting it. This is under the assumption that the table has been |
|
5674 * destroyed by other methods. Anyone using non-id selectors will need to do this manually |
|
5675 */ |
|
5676 if (DataTable.settings[i].sTableId == this.id) { |
|
5677 DataTable.settings.splice(i, 1); |
|
5678 break; |
|
5679 } |
|
5680 } |
|
5681 |
|
5682 /* Ensure the table has an ID - required for accessibility */ |
|
5683 if (sId === null || sId === "") { |
|
5684 sId = "DataTables_Table_" + (DataTable.ext._oExternConfig.iNextUnique++); |
|
5685 this.id = sId; |
|
5686 } |
|
5687 |
|
5688 /* Create the settings object for this table and set some of the default parameters */ |
|
5689 var oSettings = $.extend(true, {}, DataTable.models.oSettings, { |
|
5690 "nTable": this, |
|
5691 "oApi": _that.oApi, |
|
5692 "oInit": oInit, |
|
5693 "sDestroyWidth": $(this).width(), |
|
5694 "sInstance": sId, |
|
5695 "sTableId": sId |
|
5696 }); |
|
5697 DataTable.settings.push(oSettings); |
|
5698 |
|
5699 // Need to add the instance after the instance after the settings object has been added |
|
5700 // to the settings array, so we can self reference the table instance if more than one |
|
5701 oSettings.oInstance = (_that.length === 1) ? _that : $(this).dataTable(); |
|
5702 |
|
5703 /* Setting up the initialisation object */ |
|
5704 if (!oInit) { |
|
5705 oInit = {}; |
|
5706 } |
|
5707 |
|
5708 // Backwards compatibility, before we apply all the defaults |
|
5709 if (oInit.oLanguage) { |
|
5710 _fnLanguageCompat(oInit.oLanguage); |
|
5711 } |
|
5712 |
|
5713 oInit = _fnExtend($.extend(true, {}, DataTable.defaults), oInit); |
|
5714 |
|
5715 // Map the initialisation options onto the settings object |
|
5716 _fnMap(oSettings.oFeatures, oInit, "bPaginate"); |
|
5717 _fnMap(oSettings.oFeatures, oInit, "bLengthChange"); |
|
5718 _fnMap(oSettings.oFeatures, oInit, "bFilter"); |
|
5719 _fnMap(oSettings.oFeatures, oInit, "bSort"); |
|
5720 _fnMap(oSettings.oFeatures, oInit, "bInfo"); |
|
5721 _fnMap(oSettings.oFeatures, oInit, "bProcessing"); |
|
5722 _fnMap(oSettings.oFeatures, oInit, "bAutoWidth"); |
|
5723 _fnMap(oSettings.oFeatures, oInit, "bSortClasses"); |
|
5724 _fnMap(oSettings.oFeatures, oInit, "bServerSide"); |
|
5725 _fnMap(oSettings.oFeatures, oInit, "bDeferRender"); |
|
5726 _fnMap(oSettings.oScroll, oInit, "sScrollX", "sX"); |
|
5727 _fnMap(oSettings.oScroll, oInit, "sScrollXInner", "sXInner"); |
|
5728 _fnMap(oSettings.oScroll, oInit, "sScrollY", "sY"); |
|
5729 _fnMap(oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse"); |
|
5730 _fnMap(oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite"); |
|
5731 _fnMap(oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap"); |
|
5732 _fnMap(oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss"); |
|
5733 _fnMap(oSettings, oInit, "asStripeClasses"); |
|
5734 _fnMap(oSettings, oInit, "asStripClasses", "asStripeClasses"); // legacy |
|
5735 _fnMap(oSettings, oInit, "fnServerData"); |
|
5736 _fnMap(oSettings, oInit, "fnFormatNumber"); |
|
5737 _fnMap(oSettings, oInit, "sServerMethod"); |
|
5738 _fnMap(oSettings, oInit, "aaSorting"); |
|
5739 _fnMap(oSettings, oInit, "aaSortingFixed"); |
|
5740 _fnMap(oSettings, oInit, "aLengthMenu"); |
|
5741 _fnMap(oSettings, oInit, "sPaginationType"); |
|
5742 _fnMap(oSettings, oInit, "sAjaxSource"); |
|
5743 _fnMap(oSettings, oInit, "sAjaxDataProp"); |
|
5744 _fnMap(oSettings, oInit, "iCookieDuration"); |
|
5745 _fnMap(oSettings, oInit, "sCookiePrefix"); |
|
5746 _fnMap(oSettings, oInit, "sDom"); |
|
5747 _fnMap(oSettings, oInit, "bSortCellsTop"); |
|
5748 _fnMap(oSettings, oInit, "iTabIndex"); |
|
5749 _fnMap(oSettings, oInit, "oSearch", "oPreviousSearch"); |
|
5750 _fnMap(oSettings, oInit, "aoSearchCols", "aoPreSearchCols"); |
|
5751 _fnMap(oSettings, oInit, "iDisplayLength", "_iDisplayLength"); |
|
5752 _fnMap(oSettings, oInit, "bJQueryUI", "bJUI"); |
|
5753 _fnMap(oSettings, oInit, "fnCookieCallback"); |
|
5754 _fnMap(oSettings, oInit, "fnStateLoad"); |
|
5755 _fnMap(oSettings, oInit, "fnStateSave"); |
|
5756 _fnMap(oSettings.oLanguage, oInit, "fnInfoCallback"); |
|
5757 |
|
5758 /* Callback functions which are array driven */ |
|
5759 _fnCallbackReg(oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user'); |
|
5760 _fnCallbackReg(oSettings, 'aoServerParams', oInit.fnServerParams, 'user'); |
|
5761 _fnCallbackReg(oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user'); |
|
5762 _fnCallbackReg(oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user'); |
|
5763 _fnCallbackReg(oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user'); |
|
5764 _fnCallbackReg(oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user'); |
|
5765 _fnCallbackReg(oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user'); |
|
5766 _fnCallbackReg(oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user'); |
|
5767 _fnCallbackReg(oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user'); |
|
5768 _fnCallbackReg(oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user'); |
|
5769 _fnCallbackReg(oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user'); |
|
5770 |
|
5771 if (oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort && |
|
5772 oSettings.oFeatures.bSortClasses) { |
|
5773 /* Enable sort classes for server-side processing. Safe to do it here, since server-side |
|
5774 * processing must be enabled by the developer |
|
5775 */ |
|
5776 _fnCallbackReg(oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes'); |
|
5777 } |
|
5778 else if (oSettings.oFeatures.bDeferRender) { |
|
5779 _fnCallbackReg(oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes'); |
|
5780 } |
|
5781 |
|
5782 if (oInit.bJQueryUI) { |
|
5783 /* Use the JUI classes object for display. You could clone the oStdClasses object if |
|
5784 * you want to have multiple tables with multiple independent classes |
|
5785 */ |
|
5786 $.extend(oSettings.oClasses, DataTable.ext.oJUIClasses); |
|
5787 |
|
5788 if (oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip") { |
|
5789 /* Set the DOM to use a layout suitable for jQuery UI's theming */ |
|
5790 oSettings.sDom = '<"H"lfr>t<"F"ip>'; |
|
5791 } |
|
5792 } |
|
5793 else { |
|
5794 $.extend(oSettings.oClasses, DataTable.ext.oStdClasses); |
|
5795 } |
|
5796 $(this).addClass(oSettings.oClasses.sTable); |
|
5797 |
|
5798 /* Calculate the scroll bar width and cache it for use later on */ |
|
5799 if (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") { |
|
5800 oSettings.oScroll.iBarWidth = _fnScrollBarWidth(); |
|
5801 } |
|
5802 |
|
5803 if (oSettings.iInitDisplayStart === undefined) { |
|
5804 /* Display start point, taking into account the save saving */ |
|
5805 oSettings.iInitDisplayStart = oInit.iDisplayStart; |
|
5806 oSettings._iDisplayStart = oInit.iDisplayStart; |
|
5807 } |
|
5808 |
|
5809 /* Must be done after everything which can be overridden by a cookie! */ |
|
5810 if (oInit.bStateSave) { |
|
5811 oSettings.oFeatures.bStateSave = true; |
|
5812 _fnLoadState(oSettings, oInit); |
|
5813 _fnCallbackReg(oSettings, 'aoDrawCallback', _fnSaveState, 'state_save'); |
|
5814 } |
|
5815 |
|
5816 if (oInit.iDeferLoading !== null) { |
|
5817 oSettings.bDeferLoading = true; |
|
5818 var tmp = $.isArray(oInit.iDeferLoading); |
|
5819 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; |
|
5820 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; |
|
5821 } |
|
5822 |
|
5823 if (oInit.aaData !== null) { |
|
5824 bUsePassedData = true; |
|
5825 } |
|
5826 |
|
5827 /* Language definitions */ |
|
5828 if (oInit.oLanguage.sUrl !== "") { |
|
5829 /* Get the language definitions from a file - because this Ajax call makes the language |
|
5830 * get async to the remainder of this function we use bInitHandedOff to indicate that |
|
5831 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor |
|
5832 */ |
|
5833 oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl; |
|
5834 $.getJSON(oSettings.oLanguage.sUrl, null, function (json) { |
|
5835 _fnLanguageCompat(json); |
|
5836 $.extend(true, oSettings.oLanguage, oInit.oLanguage, json); |
|
5837 _fnInitialise(oSettings); |
|
5838 }); |
|
5839 bInitHandedOff = true; |
|
5840 } |
|
5841 else { |
|
5842 $.extend(true, oSettings.oLanguage, oInit.oLanguage); |
|
5843 } |
|
5844 |
|
5845 |
|
5846 /* |
|
5847 * Stripes |
|
5848 */ |
|
5849 if (oInit.asStripeClasses === null) { |
|
5850 oSettings.asStripeClasses = [ |
|
5851 oSettings.oClasses.sStripeOdd, |
|
5852 oSettings.oClasses.sStripeEven |
|
5853 ]; |
|
5854 } |
|
5855 |
|
5856 /* Remove row stripe classes if they are already on the table row */ |
|
5857 iLen = oSettings.asStripeClasses.length; |
|
5858 oSettings.asDestroyStripes = []; |
|
5859 if (iLen) { |
|
5860 var bStripeRemove = false; |
|
5861 var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')'); |
|
5862 for (i = 0; i < iLen; i++) { |
|
5863 if (anRows.hasClass(oSettings.asStripeClasses[i])) { |
|
5864 bStripeRemove = true; |
|
5865 |
|
5866 /* Store the classes which we are about to remove so they can be re-added on destroy */ |
|
5867 oSettings.asDestroyStripes.push(oSettings.asStripeClasses[i]); |
|
5868 } |
|
5869 } |
|
5870 |
|
5871 if (bStripeRemove) { |
|
5872 anRows.removeClass(oSettings.asStripeClasses.join(' ')); |
|
5873 } |
|
5874 } |
|
5875 |
|
5876 /* |
|
5877 * Columns |
|
5878 * See if we should load columns automatically or use defined ones |
|
5879 */ |
|
5880 var anThs = []; |
|
5881 var aoColumnsInit; |
|
5882 var nThead = this.getElementsByTagName('thead'); |
|
5883 if (nThead.length !== 0) { |
|
5884 _fnDetectHeader(oSettings.aoHeader, nThead[0]); |
|
5885 anThs = _fnGetUniqueThs(oSettings); |
|
5886 } |
|
5887 |
|
5888 /* If not given a column array, generate one with nulls */ |
|
5889 if (oInit.aoColumns === null) { |
|
5890 aoColumnsInit = []; |
|
5891 for (i = 0, iLen = anThs.length; i < iLen; i++) { |
|
5892 aoColumnsInit.push(null); |
|
5893 } |
|
5894 } |
|
5895 else { |
|
5896 aoColumnsInit = oInit.aoColumns; |
|
5897 } |
|
5898 |
|
5899 /* Add the columns */ |
|
5900 for (i = 0, iLen = aoColumnsInit.length; i < iLen; i++) { |
|
5901 /* Short cut - use the loop to check if we have column visibility state to restore */ |
|
5902 if (oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen) { |
|
5903 if (aoColumnsInit[i] === null) { |
|
5904 aoColumnsInit[i] = {}; |
|
5905 } |
|
5906 aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible; |
|
5907 } |
|
5908 |
|
5909 _fnAddColumn(oSettings, anThs ? anThs[i] : null); |
|
5910 } |
|
5911 |
|
5912 /* Apply the column definitions */ |
|
5913 _fnApplyColumnDefs(oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { |
|
5914 _fnColumnOptions(oSettings, iCol, oDef); |
|
5915 }); |
|
5916 |
|
5917 |
|
5918 /* |
|
5919 * Sorting |
|
5920 * Check the aaSorting array |
|
5921 */ |
|
5922 for (i = 0, iLen = oSettings.aaSorting.length; i < iLen; i++) { |
|
5923 if (oSettings.aaSorting[i][0] >= oSettings.aoColumns.length) { |
|
5924 oSettings.aaSorting[i][0] = 0; |
|
5925 } |
|
5926 var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ]; |
|
5927 |
|
5928 /* Add a default sorting index */ |
|
5929 if (oSettings.aaSorting[i][2] === undefined) { |
|
5930 oSettings.aaSorting[i][2] = 0; |
|
5931 } |
|
5932 |
|
5933 /* If aaSorting is not defined, then we use the first indicator in asSorting */ |
|
5934 if (oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined) { |
|
5935 oSettings.aaSorting[i][1] = oColumn.asSorting[0]; |
|
5936 } |
|
5937 |
|
5938 /* Set the current sorting index based on aoColumns.asSorting */ |
|
5939 for (j = 0, jLen = oColumn.asSorting.length; j < jLen; j++) { |
|
5940 if (oSettings.aaSorting[i][1] == oColumn.asSorting[j]) { |
|
5941 oSettings.aaSorting[i][2] = j; |
|
5942 break; |
|
5943 } |
|
5944 } |
|
5945 } |
|
5946 |
|
5947 /* Do a first pass on the sorting classes (allows any size changes to be taken into |
|
5948 * account, and also will apply sorting disabled classes if disabled |
|
5949 */ |
|
5950 _fnSortingClasses(oSettings); |
|
5951 |
|
5952 |
|
5953 /* |
|
5954 * Final init |
|
5955 * Cache the header, body and footer as required, creating them if needed |
|
5956 */ |
|
5957 |
|
5958 /* Browser support detection */ |
|
5959 _fnBrowserDetect(oSettings); |
|
5960 |
|
5961 // Work around for Webkit bug 83867 - store the caption-side before removing from doc |
|
5962 var captions = $(this).children('caption').each(function () { |
|
5963 this._captionSide = $(this).css('caption-side'); |
|
5964 }); |
|
5965 |
|
5966 var thead = $(this).children('thead'); |
|
5967 if (thead.length === 0) { |
|
5968 thead = [ document.createElement('thead') ]; |
|
5969 this.appendChild(thead[0]); |
|
5970 } |
|
5971 oSettings.nTHead = thead[0]; |
|
5972 |
|
5973 var tbody = $(this).children('tbody'); |
|
5974 if (tbody.length === 0) { |
|
5975 tbody = [ document.createElement('tbody') ]; |
|
5976 this.appendChild(tbody[0]); |
|
5977 } |
|
5978 oSettings.nTBody = tbody[0]; |
|
5979 oSettings.nTBody.setAttribute("role", "alert"); |
|
5980 oSettings.nTBody.setAttribute("aria-live", "polite"); |
|
5981 oSettings.nTBody.setAttribute("aria-relevant", "all"); |
|
5982 |
|
5983 var tfoot = $(this).children('tfoot'); |
|
5984 if (tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "")) { |
|
5985 // If we are a scrolling table, and no footer has been given, then we need to create |
|
5986 // a tfoot element for the caption element to be appended to |
|
5987 tfoot = [ document.createElement('tfoot') ]; |
|
5988 this.appendChild(tfoot[0]); |
|
5989 } |
|
5990 |
|
5991 if (tfoot.length > 0) { |
|
5992 oSettings.nTFoot = tfoot[0]; |
|
5993 _fnDetectHeader(oSettings.aoFooter, oSettings.nTFoot); |
|
5994 } |
|
5995 |
|
5996 /* Check if there is data passing into the constructor */ |
|
5997 if (bUsePassedData) { |
|
5998 for (i = 0; i < oInit.aaData.length; i++) { |
|
5999 _fnAddData(oSettings, oInit.aaData[ i ]); |
|
6000 } |
|
6001 } |
|
6002 else { |
|
6003 /* Grab the data from the page */ |
|
6004 _fnGatherData(oSettings); |
|
6005 } |
|
6006 |
|
6007 /* Copy the data index array */ |
|
6008 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
|
6009 |
|
6010 /* Initialisation complete - table can be drawn */ |
|
6011 oSettings.bInitialised = true; |
|
6012 |
|
6013 /* Check if we need to initialise the table (it might not have been handed off to the |
|
6014 * language processor) |
|
6015 */ |
|
6016 if (bInitHandedOff === false) { |
|
6017 _fnInitialise(oSettings); |
|
6018 } |
|
6019 }); |
|
6020 _that = null; |
|
6021 return this; |
|
6022 }; |
|
6023 |
|
6024 |
|
6025 /** |
|
6026 * Provide a common method for plug-ins to check the version of DataTables being used, in order |
|
6027 * to ensure compatibility. |
|
6028 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the |
|
6029 * formats "X" and "X.Y" are also acceptable. |
|
6030 * @returns {boolean} true if this version of DataTables is greater or equal to the required |
|
6031 * version, or false if this version of DataTales is not suitable |
|
6032 * @static |
|
6033 * @dtopt API-Static |
|
6034 * |
|
6035 * @example |
|
6036 * alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) ); |
|
6037 */ |
|
6038 DataTable.fnVersionCheck = function (sVersion) { |
|
6039 /* This is cheap, but effective */ |
|
6040 var fnZPad = function (Zpad, count) { |
|
6041 while (Zpad.length < count) { |
|
6042 Zpad += '0'; |
|
6043 } |
|
6044 return Zpad; |
|
6045 }; |
|
6046 var aThis = DataTable.ext.sVersion.split('.'); |
|
6047 var aThat = sVersion.split('.'); |
|
6048 var sThis = '', sThat = ''; |
|
6049 |
|
6050 for (var i = 0, iLen = aThat.length; i < iLen; i++) { |
|
6051 sThis += fnZPad(aThis[i], 3); |
|
6052 sThat += fnZPad(aThat[i], 3); |
|
6053 } |
|
6054 |
|
6055 return parseInt(sThis, 10) >= parseInt(sThat, 10); |
|
6056 }; |
|
6057 |
|
6058 |
|
6059 /** |
|
6060 * Check if a TABLE node is a DataTable table already or not. |
|
6061 * @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other |
|
6062 * node types can be passed in, but will always return false). |
|
6063 * @returns {boolean} true the table given is a DataTable, or false otherwise |
|
6064 * @static |
|
6065 * @dtopt API-Static |
|
6066 * |
|
6067 * @example |
|
6068 * var ex = document.getElementById('example'); |
|
6069 * if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) { |
|
6070 * $(ex).dataTable(); |
|
6071 * } |
|
6072 */ |
|
6073 DataTable.fnIsDataTable = function (nTable) { |
|
6074 var o = DataTable.settings; |
|
6075 |
|
6076 for (var i = 0; i < o.length; i++) { |
|
6077 if (o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable) { |
|
6078 return true; |
|
6079 } |
|
6080 } |
|
6081 |
|
6082 return false; |
|
6083 }; |
|
6084 |
|
6085 |
|
6086 /** |
|
6087 * Get all DataTable tables that have been initialised - optionally you can select to |
|
6088 * get only currently visible tables. |
|
6089 * @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or |
|
6090 * visible tables only. |
|
6091 * @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables |
|
6092 * @static |
|
6093 * @dtopt API-Static |
|
6094 * |
|
6095 * @example |
|
6096 * var table = $.fn.dataTable.fnTables(true); |
|
6097 * if ( table.length > 0 ) { |
|
6098 * $(table).dataTable().fnAdjustColumnSizing(); |
|
6099 * } |
|
6100 */ |
|
6101 DataTable.fnTables = function (bVisible) { |
|
6102 var out = []; |
|
6103 |
|
6104 jQuery.each(DataTable.settings, function (i, o) { |
|
6105 if (!bVisible || (bVisible === true && $(o.nTable).is(':visible'))) { |
|
6106 out.push(o.nTable); |
|
6107 } |
|
6108 }); |
|
6109 |
|
6110 return out; |
|
6111 }; |
|
6112 |
|
6113 |
|
6114 /** |
|
6115 * Version string for plug-ins to check compatibility. Allowed format is |
|
6116 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and |
|
6117 * e are optional |
|
6118 * @member |
|
6119 * @type string |
|
6120 * @default Version number |
|
6121 */ |
|
6122 DataTable.version = "1.9.4"; |
|
6123 |
|
6124 /** |
|
6125 * Private data store, containing all of the settings objects that are created for the |
|
6126 * tables on a given page. |
|
6127 * |
|
6128 * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i> |
|
6129 * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>. |
|
6130 * @member |
|
6131 * @type array |
|
6132 * @default [] |
|
6133 * @private |
|
6134 */ |
|
6135 DataTable.settings = []; |
|
6136 |
|
6137 /** |
|
6138 * Object models container, for the various models that DataTables has available |
|
6139 * to it. These models define the objects that are used to hold the active state |
|
6140 * and configuration of the table. |
|
6141 * @namespace |
|
6142 */ |
|
6143 DataTable.models = {}; |
|
6144 |
|
6145 |
|
6146 /** |
|
6147 * DataTables extension options and plug-ins. This namespace acts as a collection "area" |
|
6148 * for plug-ins that can be used to extend the default DataTables behaviour - indeed many |
|
6149 * of the build in methods use this method to provide their own capabilities (sorting methods |
|
6150 * for example). |
|
6151 * |
|
6152 * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed |
|
6153 * and modified by plug-ins. |
|
6154 * @namespace |
|
6155 */ |
|
6156 DataTable.models.ext = { |
|
6157 /** |
|
6158 * Plug-in filtering functions - this method of filtering is complimentary to the default |
|
6159 * type based filtering, and a lot more comprehensive as it allows you complete control |
|
6160 * over the filtering logic. Each element in this array is a function (parameters |
|
6161 * described below) that is called for every row in the table, and your logic decides if |
|
6162 * it should be included in the filtered data set or not. |
|
6163 * <ul> |
|
6164 * <li> |
|
6165 * Function input parameters: |
|
6166 * <ul> |
|
6167 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> |
|
6168 * <li>{array|object} Data for the row to be processed (same as the original format |
|
6169 * that was passed in as the data source, or an array from a DOM data source</li> |
|
6170 * <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can |
|
6171 * be useful to retrieve the TR element if you need DOM interaction.</li> |
|
6172 * </ul> |
|
6173 * </li> |
|
6174 * <li> |
|
6175 * Function return: |
|
6176 * <ul> |
|
6177 * <li>{boolean} Include the row in the filtered result set (true) or not (false)</li> |
|
6178 * </ul> |
|
6179 * </il> |
|
6180 * </ul> |
|
6181 * @type array |
|
6182 * @default [] |
|
6183 * |
|
6184 * @example |
|
6185 * // The following example shows custom filtering being applied to the fourth column (i.e. |
|
6186 * // the aData[3] index) based on two input values from the end-user, matching the data in |
|
6187 * // a certain range. |
|
6188 * $.fn.dataTableExt.afnFiltering.push( |
|
6189 * function( oSettings, aData, iDataIndex ) { |
|
6190 * var iMin = document.getElementById('min').value * 1; |
|
6191 * var iMax = document.getElementById('max').value * 1; |
|
6192 * var iVersion = aData[3] == "-" ? 0 : aData[3]*1; |
|
6193 * if ( iMin == "" && iMax == "" ) { |
|
6194 * return true; |
|
6195 * } |
|
6196 * else if ( iMin == "" && iVersion < iMax ) { |
|
6197 * return true; |
|
6198 * } |
|
6199 * else if ( iMin < iVersion && "" == iMax ) { |
|
6200 * return true; |
|
6201 * } |
|
6202 * else if ( iMin < iVersion && iVersion < iMax ) { |
|
6203 * return true; |
|
6204 * } |
|
6205 * return false; |
|
6206 * } |
|
6207 * ); |
|
6208 */ |
|
6209 "afnFiltering": [], |
|
6210 |
|
6211 |
|
6212 /** |
|
6213 * Plug-in sorting functions - this method of sorting is complimentary to the default type |
|
6214 * based sorting that DataTables does automatically, allowing much greater control over the |
|
6215 * the data that is being used to sort a column. This is useful if you want to do sorting |
|
6216 * based on live data (for example the contents of an 'input' element) rather than just the |
|
6217 * static string that DataTables knows of. The way these plug-ins work is that you create |
|
6218 * an array of the values you wish to be sorted for the column in question and then return |
|
6219 * that array. Which pre-sorting function is run here depends on the sSortDataType parameter |
|
6220 * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort |
|
6221 * data. |
|
6222 * <ul> |
|
6223 * <li> |
|
6224 * Function input parameters: |
|
6225 * <ul> |
|
6226 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> |
|
6227 * <li>{int} Target column index</li> |
|
6228 * </ul> |
|
6229 * </li> |
|
6230 * <li> |
|
6231 * Function return: |
|
6232 * <ul> |
|
6233 * <li>{array} Data for the column to be sorted upon</li> |
|
6234 * </ul> |
|
6235 * </il> |
|
6236 * </ul> |
|
6237 * |
|
6238 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for |
|
6239 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when |
|
6240 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to |
|
6241 * prepare the data as required for the different types. As such, this method is deprecated. |
|
6242 * @type array |
|
6243 * @default [] |
|
6244 * @deprecated |
|
6245 * |
|
6246 * @example |
|
6247 * // Updating the cached sorting information with user entered values in HTML input elements |
|
6248 * jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn ) |
|
6249 * { |
|
6250 * var aData = []; |
|
6251 * $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () { |
|
6252 * aData.push( this.value ); |
|
6253 * } ); |
|
6254 * return aData; |
|
6255 * } |
|
6256 */ |
|
6257 "afnSortData": [], |
|
6258 |
|
6259 |
|
6260 /** |
|
6261 * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are |
|
6262 * available to DataTables. These feature plug-ins are accessible through the sDom initialisation |
|
6263 * option. As such, each feature plug-in must describe a function that is used to initialise |
|
6264 * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name |
|
6265 * of the feature (sFeature). Thus the objects attached to this method must provide: |
|
6266 * <ul> |
|
6267 * <li>{function} fnInit Initialisation of the plug-in |
|
6268 * <ul> |
|
6269 * <li> |
|
6270 * Function input parameters: |
|
6271 * <ul> |
|
6272 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> |
|
6273 * </ul> |
|
6274 * </li> |
|
6275 * <li> |
|
6276 * Function return: |
|
6277 * <ul> |
|
6278 * <li>{node|null} The element which contains your feature. Note that the return |
|
6279 * may also be void if your plug-in does not require to inject any DOM elements |
|
6280 * into DataTables control (sDom) - for example this might be useful when |
|
6281 * developing a plug-in which allows table control via keyboard entry.</li> |
|
6282 * </ul> |
|
6283 * </il> |
|
6284 * </ul> |
|
6285 * </li> |
|
6286 * <li>{character} cFeature Character that will be matched in sDom - case sensitive</li> |
|
6287 * <li>{string} sFeature Feature name</li> |
|
6288 * </ul> |
|
6289 * @type array |
|
6290 * @default [] |
|
6291 * |
|
6292 * @example |
|
6293 * // How TableTools initialises itself. |
|
6294 * $.fn.dataTableExt.aoFeatures.push( { |
|
6295 * "fnInit": function( oSettings ) { |
|
6296 * return new TableTools( { "oDTSettings": oSettings } ); |
|
6297 * }, |
|
6298 * "cFeature": "T", |
|
6299 * "sFeature": "TableTools" |
|
6300 * } ); |
|
6301 */ |
|
6302 "aoFeatures": [], |
|
6303 |
|
6304 |
|
6305 /** |
|
6306 * Type detection plug-in functions - DataTables utilises types to define how sorting and |
|
6307 * filtering behave, and types can be either be defined by the developer (sType for the |
|
6308 * column) or they can be automatically detected by the methods in this array. The functions |
|
6309 * defined in the array are quite simple, taking a single parameter (the data to analyse) |
|
6310 * and returning the type if it is a known type, or null otherwise. |
|
6311 * <ul> |
|
6312 * <li> |
|
6313 * Function input parameters: |
|
6314 * <ul> |
|
6315 * <li>{*} Data from the column cell to be analysed</li> |
|
6316 * </ul> |
|
6317 * </li> |
|
6318 * <li> |
|
6319 * Function return: |
|
6320 * <ul> |
|
6321 * <li>{string|null} Data type detected, or null if unknown (and thus pass it |
|
6322 * on to the other type detection functions.</li> |
|
6323 * </ul> |
|
6324 * </il> |
|
6325 * </ul> |
|
6326 * @type array |
|
6327 * @default [] |
|
6328 * |
|
6329 * @example |
|
6330 * // Currency type detection plug-in: |
|
6331 * jQuery.fn.dataTableExt.aTypes.push( |
|
6332 * function ( sData ) { |
|
6333 * var sValidChars = "0123456789.-"; |
|
6334 * var Char; |
|
6335 * |
|
6336 * // Check the numeric part |
|
6337 * for ( i=1 ; i<sData.length ; i++ ) { |
|
6338 * Char = sData.charAt(i); |
|
6339 * if (sValidChars.indexOf(Char) == -1) { |
|
6340 * return null; |
|
6341 * } |
|
6342 * } |
|
6343 * |
|
6344 * // Check prefixed by currency |
|
6345 * if ( sData.charAt(0) == '$' || sData.charAt(0) == '£' ) { |
|
6346 * return 'currency'; |
|
6347 * } |
|
6348 * return null; |
|
6349 * } |
|
6350 * ); |
|
6351 */ |
|
6352 "aTypes": [], |
|
6353 |
|
6354 |
|
6355 /** |
|
6356 * Provide a common method for plug-ins to check the version of DataTables being used, |
|
6357 * in order to ensure compatibility. |
|
6358 * @type function |
|
6359 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note |
|
6360 * that the formats "X" and "X.Y" are also acceptable. |
|
6361 * @returns {boolean} true if this version of DataTables is greater or equal to the |
|
6362 * required version, or false if this version of DataTales is not suitable |
|
6363 * |
|
6364 * @example |
|
6365 * $(document).ready(function() { |
|
6366 * var oTable = $('#example').dataTable(); |
|
6367 * alert( oTable.fnVersionCheck( '1.9.0' ) ); |
|
6368 * } ); |
|
6369 */ |
|
6370 "fnVersionCheck": DataTable.fnVersionCheck, |
|
6371 |
|
6372 |
|
6373 /** |
|
6374 * Index for what 'this' index API functions should use |
|
6375 * @type int |
|
6376 * @default 0 |
|
6377 */ |
|
6378 "iApiIndex": 0, |
|
6379 |
|
6380 |
|
6381 /** |
|
6382 * Pre-processing of filtering data plug-ins - When you assign the sType for a column |
|
6383 * (or have it automatically detected for you by DataTables or a type detection plug-in), |
|
6384 * you will typically be using this for custom sorting, but it can also be used to provide |
|
6385 * custom filtering by allowing you to pre-processing the data and returning the data in |
|
6386 * the format that should be filtered upon. This is done by adding functions this object |
|
6387 * with a parameter name which matches the sType for that target column. This is the |
|
6388 * corollary of <i>afnSortData</i> for filtering data. |
|
6389 * <ul> |
|
6390 * <li> |
|
6391 * Function input parameters: |
|
6392 * <ul> |
|
6393 * <li>{*} Data from the column cell to be prepared for filtering</li> |
|
6394 * </ul> |
|
6395 * </li> |
|
6396 * <li> |
|
6397 * Function return: |
|
6398 * <ul> |
|
6399 * <li>{string|null} Formatted string that will be used for the filtering.</li> |
|
6400 * </ul> |
|
6401 * </il> |
|
6402 * </ul> |
|
6403 * |
|
6404 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for |
|
6405 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when |
|
6406 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to |
|
6407 * prepare the data as required for the different types. As such, this method is deprecated. |
|
6408 * @type object |
|
6409 * @default {} |
|
6410 * @deprecated |
|
6411 * |
|
6412 * @example |
|
6413 * $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) { |
|
6414 * return sData.replace(/\n/g," ").replace( /<.*?>/g, "" ); |
|
6415 * } |
|
6416 */ |
|
6417 "ofnSearch": {}, |
|
6418 |
|
6419 |
|
6420 /** |
|
6421 * Container for all private functions in DataTables so they can be exposed externally |
|
6422 * @type object |
|
6423 * @default {} |
|
6424 */ |
|
6425 "oApi": {}, |
|
6426 |
|
6427 |
|
6428 /** |
|
6429 * Storage for the various classes that DataTables uses |
|
6430 * @type object |
|
6431 * @default {} |
|
6432 */ |
|
6433 "oStdClasses": {}, |
|
6434 |
|
6435 |
|
6436 /** |
|
6437 * Storage for the various classes that DataTables uses - jQuery UI suitable |
|
6438 * @type object |
|
6439 * @default {} |
|
6440 */ |
|
6441 "oJUIClasses": {}, |
|
6442 |
|
6443 |
|
6444 /** |
|
6445 * Pagination plug-in methods - The style and controls of the pagination can significantly |
|
6446 * impact on how the end user interacts with the data in your table, and DataTables allows |
|
6447 * the addition of pagination controls by extending this object, which can then be enabled |
|
6448 * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that |
|
6449 * is added is an object (the property name of which is what <i>sPaginationType</i> refers |
|
6450 * to) that has two properties, both methods that are used by DataTables to update the |
|
6451 * control's state. |
|
6452 * <ul> |
|
6453 * <li> |
|
6454 * fnInit - Initialisation of the paging controls. Called only during initialisation |
|
6455 * of the table. It is expected that this function will add the required DOM elements |
|
6456 * to the page for the paging controls to work. The element pointer |
|
6457 * 'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging |
|
6458 * controls (note that this is a 2D array to allow for multiple instances of each |
|
6459 * DataTables DOM element). It is suggested that you add the controls to this element |
|
6460 * as children |
|
6461 * <ul> |
|
6462 * <li> |
|
6463 * Function input parameters: |
|
6464 * <ul> |
|
6465 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> |
|
6466 * <li>{node} Container into which the pagination controls must be inserted</li> |
|
6467 * <li>{function} Draw callback function - whenever the controls cause a page |
|
6468 * change, this method must be called to redraw the table.</li> |
|
6469 * </ul> |
|
6470 * </li> |
|
6471 * <li> |
|
6472 * Function return: |
|
6473 * <ul> |
|
6474 * <li>No return required</li> |
|
6475 * </ul> |
|
6476 * </il> |
|
6477 * </ul> |
|
6478 * </il> |
|
6479 * <li> |
|
6480 * fnInit - This function is called whenever the paging status of the table changes and is |
|
6481 * typically used to update classes and/or text of the paging controls to reflex the new |
|
6482 * status. |
|
6483 * <ul> |
|
6484 * <li> |
|
6485 * Function input parameters: |
|
6486 * <ul> |
|
6487 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> |
|
6488 * <li>{function} Draw callback function - in case you need to redraw the table again |
|
6489 * or attach new event listeners</li> |
|
6490 * </ul> |
|
6491 * </li> |
|
6492 * <li> |
|
6493 * Function return: |
|
6494 * <ul> |
|
6495 * <li>No return required</li> |
|
6496 * </ul> |
|
6497 * </il> |
|
6498 * </ul> |
|
6499 * </il> |
|
6500 * </ul> |
|
6501 * @type object |
|
6502 * @default {} |
|
6503 * |
|
6504 * @example |
|
6505 * $.fn.dataTableExt.oPagination.four_button = { |
|
6506 * "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) { |
|
6507 * nFirst = document.createElement( 'span' ); |
|
6508 * nPrevious = document.createElement( 'span' ); |
|
6509 * nNext = document.createElement( 'span' ); |
|
6510 * nLast = document.createElement( 'span' ); |
|
6511 * |
|
6512 * nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) ); |
|
6513 * nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) ); |
|
6514 * nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) ); |
|
6515 * nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) ); |
|
6516 * |
|
6517 * nFirst.className = "paginate_button first"; |
|
6518 * nPrevious.className = "paginate_button previous"; |
|
6519 * nNext.className="paginate_button next"; |
|
6520 * nLast.className = "paginate_button last"; |
|
6521 * |
|
6522 * nPaging.appendChild( nFirst ); |
|
6523 * nPaging.appendChild( nPrevious ); |
|
6524 * nPaging.appendChild( nNext ); |
|
6525 * nPaging.appendChild( nLast ); |
|
6526 * |
|
6527 * $(nFirst).click( function () { |
|
6528 * oSettings.oApi._fnPageChange( oSettings, "first" ); |
|
6529 * fnCallbackDraw( oSettings ); |
|
6530 * } ); |
|
6531 * |
|
6532 * $(nPrevious).click( function() { |
|
6533 * oSettings.oApi._fnPageChange( oSettings, "previous" ); |
|
6534 * fnCallbackDraw( oSettings ); |
|
6535 * } ); |
|
6536 * |
|
6537 * $(nNext).click( function() { |
|
6538 * oSettings.oApi._fnPageChange( oSettings, "next" ); |
|
6539 * fnCallbackDraw( oSettings ); |
|
6540 * } ); |
|
6541 * |
|
6542 * $(nLast).click( function() { |
|
6543 * oSettings.oApi._fnPageChange( oSettings, "last" ); |
|
6544 * fnCallbackDraw( oSettings ); |
|
6545 * } ); |
|
6546 * |
|
6547 * $(nFirst).bind( 'selectstart', function () { return false; } ); |
|
6548 * $(nPrevious).bind( 'selectstart', function () { return false; } ); |
|
6549 * $(nNext).bind( 'selectstart', function () { return false; } ); |
|
6550 * $(nLast).bind( 'selectstart', function () { return false; } ); |
|
6551 * }, |
|
6552 * |
|
6553 * "fnUpdate": function ( oSettings, fnCallbackDraw ) { |
|
6554 * if ( !oSettings.aanFeatures.p ) { |
|
6555 * return; |
|
6556 * } |
|
6557 * |
|
6558 * // Loop over each instance of the pager |
|
6559 * var an = oSettings.aanFeatures.p; |
|
6560 * for ( var i=0, iLen=an.length ; i<iLen ; i++ ) { |
|
6561 * var buttons = an[i].getElementsByTagName('span'); |
|
6562 * if ( oSettings._iDisplayStart === 0 ) { |
|
6563 * buttons[0].className = "paginate_disabled_previous"; |
|
6564 * buttons[1].className = "paginate_disabled_previous"; |
|
6565 * } |
|
6566 * else { |
|
6567 * buttons[0].className = "paginate_enabled_previous"; |
|
6568 * buttons[1].className = "paginate_enabled_previous"; |
|
6569 * } |
|
6570 * |
|
6571 * if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) { |
|
6572 * buttons[2].className = "paginate_disabled_next"; |
|
6573 * buttons[3].className = "paginate_disabled_next"; |
|
6574 * } |
|
6575 * else { |
|
6576 * buttons[2].className = "paginate_enabled_next"; |
|
6577 * buttons[3].className = "paginate_enabled_next"; |
|
6578 * } |
|
6579 * } |
|
6580 * } |
|
6581 * }; |
|
6582 */ |
|
6583 "oPagination": {}, |
|
6584 |
|
6585 |
|
6586 /** |
|
6587 * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the |
|
6588 * data column (you can add your own type detection functions, or override automatic |
|
6589 * detection using sType). With this specific type given to the column, DataTables will |
|
6590 * apply the required sort from the functions in the object. Each sort type must provide |
|
6591 * two mandatory methods, one each for ascending and descending sorting, and can optionally |
|
6592 * provide a pre-formatting method that will help speed up sorting by allowing DataTables |
|
6593 * to pre-format the sort data only once (rather than every time the actual sort functions |
|
6594 * are run). The two sorting functions are typical Javascript sort methods: |
|
6595 * <ul> |
|
6596 * <li> |
|
6597 * Function input parameters: |
|
6598 * <ul> |
|
6599 * <li>{*} Data to compare to the second parameter</li> |
|
6600 * <li>{*} Data to compare to the first parameter</li> |
|
6601 * </ul> |
|
6602 * </li> |
|
6603 * <li> |
|
6604 * Function return: |
|
6605 * <ul> |
|
6606 * <li>{int} Sorting match: <0 if first parameter should be sorted lower than |
|
6607 * the second parameter, ===0 if the two parameters are equal and >0 if |
|
6608 * the first parameter should be sorted height than the second parameter.</li> |
|
6609 * </ul> |
|
6610 * </il> |
|
6611 * </ul> |
|
6612 * @type object |
|
6613 * @default {} |
|
6614 * |
|
6615 * @example |
|
6616 * // Case-sensitive string sorting, with no pre-formatting method |
|
6617 * $.extend( $.fn.dataTableExt.oSort, { |
|
6618 * "string-case-asc": function(x,y) { |
|
6619 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
|
6620 * }, |
|
6621 * "string-case-desc": function(x,y) { |
|
6622 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
|
6623 * } |
|
6624 * } ); |
|
6625 * |
|
6626 * @example |
|
6627 * // Case-insensitive string sorting, with pre-formatting |
|
6628 * $.extend( $.fn.dataTableExt.oSort, { |
|
6629 * "string-pre": function(x) { |
|
6630 * return x.toLowerCase(); |
|
6631 * }, |
|
6632 * "string-asc": function(x,y) { |
|
6633 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
|
6634 * }, |
|
6635 * "string-desc": function(x,y) { |
|
6636 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
|
6637 * } |
|
6638 * } ); |
|
6639 */ |
|
6640 "oSort": {}, |
|
6641 |
|
6642 |
|
6643 /** |
|
6644 * Version string for plug-ins to check compatibility. Allowed format is |
|
6645 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and |
|
6646 * e are optional |
|
6647 * @type string |
|
6648 * @default Version number |
|
6649 */ |
|
6650 "sVersion": DataTable.version, |
|
6651 |
|
6652 |
|
6653 /** |
|
6654 * How should DataTables report an error. Can take the value 'alert' or 'throw' |
|
6655 * @type string |
|
6656 * @default alert |
|
6657 */ |
|
6658 "sErrMode": "alert", |
|
6659 |
|
6660 |
|
6661 /** |
|
6662 * Store information for DataTables to access globally about other instances |
|
6663 * @namespace |
|
6664 * @private |
|
6665 */ |
|
6666 "_oExternConfig": { |
|
6667 /* int:iNextUnique - next unique number for an instance */ |
|
6668 "iNextUnique": 0 |
|
6669 } |
|
6670 }; |
|
6671 |
|
6672 |
|
6673 /** |
|
6674 * Template object for the way in which DataTables holds information about |
|
6675 * search information for the global filter and individual column filters. |
|
6676 * @namespace |
|
6677 */ |
|
6678 DataTable.models.oSearch = { |
|
6679 /** |
|
6680 * Flag to indicate if the filtering should be case insensitive or not |
|
6681 * @type boolean |
|
6682 * @default true |
|
6683 */ |
|
6684 "bCaseInsensitive": true, |
|
6685 |
|
6686 /** |
|
6687 * Applied search term |
|
6688 * @type string |
|
6689 * @default <i>Empty string</i> |
|
6690 */ |
|
6691 "sSearch": "", |
|
6692 |
|
6693 /** |
|
6694 * Flag to indicate if the search term should be interpreted as a |
|
6695 * regular expression (true) or not (false) and therefore and special |
|
6696 * regex characters escaped. |
|
6697 * @type boolean |
|
6698 * @default false |
|
6699 */ |
|
6700 "bRegex": false, |
|
6701 |
|
6702 /** |
|
6703 * Flag to indicate if DataTables is to use its smart filtering or not. |
|
6704 * @type boolean |
|
6705 * @default true |
|
6706 */ |
|
6707 "bSmart": true |
|
6708 }; |
|
6709 |
|
6710 |
|
6711 /** |
|
6712 * Template object for the way in which DataTables holds information about |
|
6713 * each individual row. This is the object format used for the settings |
|
6714 * aoData array. |
|
6715 * @namespace |
|
6716 */ |
|
6717 DataTable.models.oRow = { |
|
6718 /** |
|
6719 * TR element for the row |
|
6720 * @type node |
|
6721 * @default null |
|
6722 */ |
|
6723 "nTr": null, |
|
6724 |
|
6725 /** |
|
6726 * Data object from the original data source for the row. This is either |
|
6727 * an array if using the traditional form of DataTables, or an object if |
|
6728 * using mData options. The exact type will depend on the passed in |
|
6729 * data from the data source, or will be an array if using DOM a data |
|
6730 * source. |
|
6731 * @type array|object |
|
6732 * @default [] |
|
6733 */ |
|
6734 "_aData": [], |
|
6735 |
|
6736 /** |
|
6737 * Sorting data cache - this array is ostensibly the same length as the |
|
6738 * number of columns (although each index is generated only as it is |
|
6739 * needed), and holds the data that is used for sorting each column in the |
|
6740 * row. We do this cache generation at the start of the sort in order that |
|
6741 * the formatting of the sort data need be done only once for each cell |
|
6742 * per sort. This array should not be read from or written to by anything |
|
6743 * other than the master sorting methods. |
|
6744 * @type array |
|
6745 * @default [] |
|
6746 * @private |
|
6747 */ |
|
6748 "_aSortData": [], |
|
6749 |
|
6750 /** |
|
6751 * Array of TD elements that are cached for hidden rows, so they can be |
|
6752 * reinserted into the table if a column is made visible again (or to act |
|
6753 * as a store if a column is made hidden). Only hidden columns have a |
|
6754 * reference in the array. For non-hidden columns the value is either |
|
6755 * undefined or null. |
|
6756 * @type array nodes |
|
6757 * @default [] |
|
6758 * @private |
|
6759 */ |
|
6760 "_anHidden": [], |
|
6761 |
|
6762 /** |
|
6763 * Cache of the class name that DataTables has applied to the row, so we |
|
6764 * can quickly look at this variable rather than needing to do a DOM check |
|
6765 * on className for the nTr property. |
|
6766 * @type string |
|
6767 * @default <i>Empty string</i> |
|
6768 * @private |
|
6769 */ |
|
6770 "_sRowStripe": "" |
|
6771 }; |
|
6772 |
|
6773 |
|
6774 /** |
|
6775 * Template object for the column information object in DataTables. This object |
|
6776 * is held in the settings aoColumns array and contains all the information that |
|
6777 * DataTables needs about each individual column. |
|
6778 * |
|
6779 * Note that this object is related to {@link DataTable.defaults.columns} |
|
6780 * but this one is the internal data store for DataTables's cache of columns. |
|
6781 * It should NOT be manipulated outside of DataTables. Any configuration should |
|
6782 * be done through the initialisation options. |
|
6783 * @namespace |
|
6784 */ |
|
6785 DataTable.models.oColumn = { |
|
6786 /** |
|
6787 * A list of the columns that sorting should occur on when this column |
|
6788 * is sorted. That this property is an array allows multi-column sorting |
|
6789 * to be defined for a column (for example first name / last name columns |
|
6790 * would benefit from this). The values are integers pointing to the |
|
6791 * columns to be sorted on (typically it will be a single integer pointing |
|
6792 * at itself, but that doesn't need to be the case). |
|
6793 * @type array |
|
6794 */ |
|
6795 "aDataSort": null, |
|
6796 |
|
6797 /** |
|
6798 * Define the sorting directions that are applied to the column, in sequence |
|
6799 * as the column is repeatedly sorted upon - i.e. the first value is used |
|
6800 * as the sorting direction when the column if first sorted (clicked on). |
|
6801 * Sort it again (click again) and it will move on to the next index. |
|
6802 * Repeat until loop. |
|
6803 * @type array |
|
6804 */ |
|
6805 "asSorting": null, |
|
6806 |
|
6807 /** |
|
6808 * Flag to indicate if the column is searchable, and thus should be included |
|
6809 * in the filtering or not. |
|
6810 * @type boolean |
|
6811 */ |
|
6812 "bSearchable": null, |
|
6813 |
|
6814 /** |
|
6815 * Flag to indicate if the column is sortable or not. |
|
6816 * @type boolean |
|
6817 */ |
|
6818 "bSortable": null, |
|
6819 |
|
6820 /** |
|
6821 * <code>Deprecated</code> When using fnRender, you have two options for what |
|
6822 * to do with the data, and this property serves as the switch. Firstly, you |
|
6823 * can have the sorting and filtering use the rendered value (true - default), |
|
6824 * or you can have the sorting and filtering us the original value (false). |
|
6825 * |
|
6826 * Please note that this option has now been deprecated and will be removed |
|
6827 * in the next version of DataTables. Please use mRender / mData rather than |
|
6828 * fnRender. |
|
6829 * @type boolean |
|
6830 * @deprecated |
|
6831 */ |
|
6832 "bUseRendered": null, |
|
6833 |
|
6834 /** |
|
6835 * Flag to indicate if the column is currently visible in the table or not |
|
6836 * @type boolean |
|
6837 */ |
|
6838 "bVisible": null, |
|
6839 |
|
6840 /** |
|
6841 * Flag to indicate to the type detection method if the automatic type |
|
6842 * detection should be used, or if a column type (sType) has been specified |
|
6843 * @type boolean |
|
6844 * @default true |
|
6845 * @private |
|
6846 */ |
|
6847 "_bAutoType": true, |
|
6848 |
|
6849 /** |
|
6850 * Developer definable function that is called whenever a cell is created (Ajax source, |
|
6851 * etc) or processed for input (DOM source). This can be used as a compliment to mRender |
|
6852 * allowing you to modify the DOM element (add background colour for example) when the |
|
6853 * element is available. |
|
6854 * @type function |
|
6855 * @param {element} nTd The TD node that has been created |
|
6856 * @param {*} sData The Data for the cell |
|
6857 * @param {array|object} oData The data for the whole row |
|
6858 * @param {int} iRow The row index for the aoData data store |
|
6859 * @default null |
|
6860 */ |
|
6861 "fnCreatedCell": null, |
|
6862 |
|
6863 /** |
|
6864 * Function to get data from a cell in a column. You should <b>never</b> |
|
6865 * access data directly through _aData internally in DataTables - always use |
|
6866 * the method attached to this property. It allows mData to function as |
|
6867 * required. This function is automatically assigned by the column |
|
6868 * initialisation method |
|
6869 * @type function |
|
6870 * @param {array|object} oData The data array/object for the array |
|
6871 * (i.e. aoData[]._aData) |
|
6872 * @param {string} sSpecific The specific data type you want to get - |
|
6873 * 'display', 'type' 'filter' 'sort' |
|
6874 * @returns {*} The data for the cell from the given row's data |
|
6875 * @default null |
|
6876 */ |
|
6877 "fnGetData": null, |
|
6878 |
|
6879 /** |
|
6880 * <code>Deprecated</code> Custom display function that will be called for the |
|
6881 * display of each cell in this column. |
|
6882 * |
|
6883 * Please note that this option has now been deprecated and will be removed |
|
6884 * in the next version of DataTables. Please use mRender / mData rather than |
|
6885 * fnRender. |
|
6886 * @type function |
|
6887 * @param {object} o Object with the following parameters: |
|
6888 * @param {int} o.iDataRow The row in aoData |
|
6889 * @param {int} o.iDataColumn The column in question |
|
6890 * @param {array} o.aData The data for the row in question |
|
6891 * @param {object} o.oSettings The settings object for this DataTables instance |
|
6892 * @returns {string} The string you which to use in the display |
|
6893 * @default null |
|
6894 * @deprecated |
|
6895 */ |
|
6896 "fnRender": null, |
|
6897 |
|
6898 /** |
|
6899 * Function to set data for a cell in the column. You should <b>never</b> |
|
6900 * set the data directly to _aData internally in DataTables - always use |
|
6901 * this method. It allows mData to function as required. This function |
|
6902 * is automatically assigned by the column initialisation method |
|
6903 * @type function |
|
6904 * @param {array|object} oData The data array/object for the array |
|
6905 * (i.e. aoData[]._aData) |
|
6906 * @param {*} sValue Value to set |
|
6907 * @default null |
|
6908 */ |
|
6909 "fnSetData": null, |
|
6910 |
|
6911 /** |
|
6912 * Property to read the value for the cells in the column from the data |
|
6913 * source array / object. If null, then the default content is used, if a |
|
6914 * function is given then the return from the function is used. |
|
6915 * @type function|int|string|null |
|
6916 * @default null |
|
6917 */ |
|
6918 "mData": null, |
|
6919 |
|
6920 /** |
|
6921 * Partner property to mData which is used (only when defined) to get |
|
6922 * the data - i.e. it is basically the same as mData, but without the |
|
6923 * 'set' option, and also the data fed to it is the result from mData. |
|
6924 * This is the rendering method to match the data method of mData. |
|
6925 * @type function|int|string|null |
|
6926 * @default null |
|
6927 */ |
|
6928 "mRender": null, |
|
6929 |
|
6930 /** |
|
6931 * Unique header TH/TD element for this column - this is what the sorting |
|
6932 * listener is attached to (if sorting is enabled.) |
|
6933 * @type node |
|
6934 * @default null |
|
6935 */ |
|
6936 "nTh": null, |
|
6937 |
|
6938 /** |
|
6939 * Unique footer TH/TD element for this column (if there is one). Not used |
|
6940 * in DataTables as such, but can be used for plug-ins to reference the |
|
6941 * footer for each column. |
|
6942 * @type node |
|
6943 * @default null |
|
6944 */ |
|
6945 "nTf": null, |
|
6946 |
|
6947 /** |
|
6948 * The class to apply to all TD elements in the table's TBODY for the column |
|
6949 * @type string |
|
6950 * @default null |
|
6951 */ |
|
6952 "sClass": null, |
|
6953 |
|
6954 /** |
|
6955 * When DataTables calculates the column widths to assign to each column, |
|
6956 * it finds the longest string in each column and then constructs a |
|
6957 * temporary table and reads the widths from that. The problem with this |
|
6958 * is that "mmm" is much wider then "iiii", but the latter is a longer |
|
6959 * string - thus the calculation can go wrong (doing it properly and putting |
|
6960 * it into an DOM object and measuring that is horribly(!) slow). Thus as |
|
6961 * a "work around" we provide this option. It will append its value to the |
|
6962 * text that is found to be the longest string for the column - i.e. padding. |
|
6963 * @type string |
|
6964 */ |
|
6965 "sContentPadding": null, |
|
6966 |
|
6967 /** |
|
6968 * Allows a default value to be given for a column's data, and will be used |
|
6969 * whenever a null data source is encountered (this can be because mData |
|
6970 * is set to null, or because the data source itself is null). |
|
6971 * @type string |
|
6972 * @default null |
|
6973 */ |
|
6974 "sDefaultContent": null, |
|
6975 |
|
6976 /** |
|
6977 * Name for the column, allowing reference to the column by name as well as |
|
6978 * by index (needs a lookup to work by name). |
|
6979 * @type string |
|
6980 */ |
|
6981 "sName": null, |
|
6982 |
|
6983 /** |
|
6984 * Custom sorting data type - defines which of the available plug-ins in |
|
6985 * afnSortData the custom sorting will use - if any is defined. |
|
6986 * @type string |
|
6987 * @default std |
|
6988 */ |
|
6989 "sSortDataType": 'std', |
|
6990 |
|
6991 /** |
|
6992 * Class to be applied to the header element when sorting on this column |
|
6993 * @type string |
|
6994 * @default null |
|
6995 */ |
|
6996 "sSortingClass": null, |
|
6997 |
|
6998 /** |
|
6999 * Class to be applied to the header element when sorting on this column - |
|
7000 * when jQuery UI theming is used. |
|
7001 * @type string |
|
7002 * @default null |
|
7003 */ |
|
7004 "sSortingClassJUI": null, |
|
7005 |
|
7006 /** |
|
7007 * Title of the column - what is seen in the TH element (nTh). |
|
7008 * @type string |
|
7009 */ |
|
7010 "sTitle": null, |
|
7011 |
|
7012 /** |
|
7013 * Column sorting and filtering type |
|
7014 * @type string |
|
7015 * @default null |
|
7016 */ |
|
7017 "sType": null, |
|
7018 |
|
7019 /** |
|
7020 * Width of the column |
|
7021 * @type string |
|
7022 * @default null |
|
7023 */ |
|
7024 "sWidth": null, |
|
7025 |
|
7026 /** |
|
7027 * Width of the column when it was first "encountered" |
|
7028 * @type string |
|
7029 * @default null |
|
7030 */ |
|
7031 "sWidthOrig": null |
|
7032 }; |
|
7033 |
|
7034 |
|
7035 /** |
|
7036 * Initialisation options that can be given to DataTables at initialisation |
|
7037 * time. |
|
7038 * @namespace |
|
7039 */ |
|
7040 DataTable.defaults = { |
|
7041 /** |
|
7042 * An array of data to use for the table, passed in at initialisation which |
|
7043 * will be used in preference to any data which is already in the DOM. This is |
|
7044 * particularly useful for constructing tables purely in Javascript, for |
|
7045 * example with a custom Ajax call. |
|
7046 * @type array |
|
7047 * @default null |
|
7048 * @dtopt Option |
|
7049 * |
|
7050 * @example |
|
7051 * // Using a 2D array data source |
|
7052 * $(document).ready( function () { |
|
7053 * $('#example').dataTable( { |
|
7054 * "aaData": [ |
|
7055 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], |
|
7056 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], |
|
7057 * ], |
|
7058 * "aoColumns": [ |
|
7059 * { "sTitle": "Engine" }, |
|
7060 * { "sTitle": "Browser" }, |
|
7061 * { "sTitle": "Platform" }, |
|
7062 * { "sTitle": "Version" }, |
|
7063 * { "sTitle": "Grade" } |
|
7064 * ] |
|
7065 * } ); |
|
7066 * } ); |
|
7067 * |
|
7068 * @example |
|
7069 * // Using an array of objects as a data source (mData) |
|
7070 * $(document).ready( function () { |
|
7071 * $('#example').dataTable( { |
|
7072 * "aaData": [ |
|
7073 * { |
|
7074 * "engine": "Trident", |
|
7075 * "browser": "Internet Explorer 4.0", |
|
7076 * "platform": "Win 95+", |
|
7077 * "version": 4, |
|
7078 * "grade": "X" |
|
7079 * }, |
|
7080 * { |
|
7081 * "engine": "Trident", |
|
7082 * "browser": "Internet Explorer 5.0", |
|
7083 * "platform": "Win 95+", |
|
7084 * "version": 5, |
|
7085 * "grade": "C" |
|
7086 * } |
|
7087 * ], |
|
7088 * "aoColumns": [ |
|
7089 * { "sTitle": "Engine", "mData": "engine" }, |
|
7090 * { "sTitle": "Browser", "mData": "browser" }, |
|
7091 * { "sTitle": "Platform", "mData": "platform" }, |
|
7092 * { "sTitle": "Version", "mData": "version" }, |
|
7093 * { "sTitle": "Grade", "mData": "grade" } |
|
7094 * ] |
|
7095 * } ); |
|
7096 * } ); |
|
7097 */ |
|
7098 "aaData": null, |
|
7099 |
|
7100 |
|
7101 /** |
|
7102 * If sorting is enabled, then DataTables will perform a first pass sort on |
|
7103 * initialisation. You can define which column(s) the sort is performed upon, |
|
7104 * and the sorting direction, with this variable. The aaSorting array should |
|
7105 * contain an array for each column to be sorted initially containing the |
|
7106 * column's index and a direction string ('asc' or 'desc'). |
|
7107 * @type array |
|
7108 * @default [[0,'asc']] |
|
7109 * @dtopt Option |
|
7110 * |
|
7111 * @example |
|
7112 * // Sort by 3rd column first, and then 4th column |
|
7113 * $(document).ready( function() { |
|
7114 * $('#example').dataTable( { |
|
7115 * "aaSorting": [[2,'asc'], [3,'desc']] |
|
7116 * } ); |
|
7117 * } ); |
|
7118 * |
|
7119 * // No initial sorting |
|
7120 * $(document).ready( function() { |
|
7121 * $('#example').dataTable( { |
|
7122 * "aaSorting": [] |
|
7123 * } ); |
|
7124 * } ); |
|
7125 */ |
|
7126 "aaSorting": [ |
|
7127 [0, 'asc'] |
|
7128 ], |
|
7129 |
|
7130 |
|
7131 /** |
|
7132 * This parameter is basically identical to the aaSorting parameter, but |
|
7133 * cannot be overridden by user interaction with the table. What this means |
|
7134 * is that you could have a column (visible or hidden) which the sorting will |
|
7135 * always be forced on first - any sorting after that (from the user) will |
|
7136 * then be performed as required. This can be useful for grouping rows |
|
7137 * together. |
|
7138 * @type array |
|
7139 * @default null |
|
7140 * @dtopt Option |
|
7141 * |
|
7142 * @example |
|
7143 * $(document).ready( function() { |
|
7144 * $('#example').dataTable( { |
|
7145 * "aaSortingFixed": [[0,'asc']] |
|
7146 * } ); |
|
7147 * } ) |
|
7148 */ |
|
7149 "aaSortingFixed": null, |
|
7150 |
|
7151 |
|
7152 /** |
|
7153 * This parameter allows you to readily specify the entries in the length drop |
|
7154 * down menu that DataTables shows when pagination is enabled. It can be |
|
7155 * either a 1D array of options which will be used for both the displayed |
|
7156 * option and the value, or a 2D array which will use the array in the first |
|
7157 * position as the value, and the array in the second position as the |
|
7158 * displayed options (useful for language strings such as 'All'). |
|
7159 * @type array |
|
7160 * @default [ 10, 25, 50, 100 ] |
|
7161 * @dtopt Option |
|
7162 * |
|
7163 * @example |
|
7164 * $(document).ready( function() { |
|
7165 * $('#example').dataTable( { |
|
7166 * "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] |
|
7167 * } ); |
|
7168 * } ); |
|
7169 * |
|
7170 * @example |
|
7171 * // Setting the default display length as well as length menu |
|
7172 * // This is likely to be wanted if you remove the '10' option which |
|
7173 * // is the iDisplayLength default. |
|
7174 * $(document).ready( function() { |
|
7175 * $('#example').dataTable( { |
|
7176 * "iDisplayLength": 25, |
|
7177 * "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]] |
|
7178 * } ); |
|
7179 * } ); |
|
7180 */ |
|
7181 "aLengthMenu": [ 10, 25, 50, 100 ], |
|
7182 |
|
7183 |
|
7184 /** |
|
7185 * The aoColumns option in the initialisation parameter allows you to define |
|
7186 * details about the way individual columns behave. For a full list of |
|
7187 * column options that can be set, please see |
|
7188 * {@link DataTable.defaults.columns}. Note that if you use aoColumns to |
|
7189 * define your columns, you must have an entry in the array for every single |
|
7190 * column that you have in your table (these can be null if you don't which |
|
7191 * to specify any options). |
|
7192 * @member |
|
7193 */ |
|
7194 "aoColumns": null, |
|
7195 |
|
7196 /** |
|
7197 * Very similar to aoColumns, aoColumnDefs allows you to target a specific |
|
7198 * column, multiple columns, or all columns, using the aTargets property of |
|
7199 * each object in the array. This allows great flexibility when creating |
|
7200 * tables, as the aoColumnDefs arrays can be of any length, targeting the |
|
7201 * columns you specifically want. aoColumnDefs may use any of the column |
|
7202 * options available: {@link DataTable.defaults.columns}, but it _must_ |
|
7203 * have aTargets defined in each object in the array. Values in the aTargets |
|
7204 * array may be: |
|
7205 * <ul> |
|
7206 * <li>a string - class name will be matched on the TH for the column</li> |
|
7207 * <li>0 or a positive integer - column index counting from the left</li> |
|
7208 * <li>a negative integer - column index counting from the right</li> |
|
7209 * <li>the string "_all" - all columns (i.e. assign a default)</li> |
|
7210 * </ul> |
|
7211 * @member |
|
7212 */ |
|
7213 "aoColumnDefs": null, |
|
7214 |
|
7215 |
|
7216 /** |
|
7217 * Basically the same as oSearch, this parameter defines the individual column |
|
7218 * filtering state at initialisation time. The array must be of the same size |
|
7219 * as the number of columns, and each element be an object with the parameters |
|
7220 * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also |
|
7221 * accepted and the default will be used. |
|
7222 * @type array |
|
7223 * @default [] |
|
7224 * @dtopt Option |
|
7225 * |
|
7226 * @example |
|
7227 * $(document).ready( function() { |
|
7228 * $('#example').dataTable( { |
|
7229 * "aoSearchCols": [ |
|
7230 * null, |
|
7231 * { "sSearch": "My filter" }, |
|
7232 * null, |
|
7233 * { "sSearch": "^[0-9]", "bEscapeRegex": false } |
|
7234 * ] |
|
7235 * } ); |
|
7236 * } ) |
|
7237 */ |
|
7238 "aoSearchCols": [], |
|
7239 |
|
7240 |
|
7241 /** |
|
7242 * An array of CSS classes that should be applied to displayed rows. This |
|
7243 * array may be of any length, and DataTables will apply each class |
|
7244 * sequentially, looping when required. |
|
7245 * @type array |
|
7246 * @default null <i>Will take the values determined by the oClasses.sStripe* |
|
7247 * options</i> |
|
7248 * @dtopt Option |
|
7249 * |
|
7250 * @example |
|
7251 * $(document).ready( function() { |
|
7252 * $('#example').dataTable( { |
|
7253 * "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ] |
|
7254 * } ); |
|
7255 * } ) |
|
7256 */ |
|
7257 "asStripeClasses": null, |
|
7258 |
|
7259 |
|
7260 /** |
|
7261 * Enable or disable automatic column width calculation. This can be disabled |
|
7262 * as an optimisation (it takes some time to calculate the widths) if the |
|
7263 * tables widths are passed in using aoColumns. |
|
7264 * @type boolean |
|
7265 * @default true |
|
7266 * @dtopt Features |
|
7267 * |
|
7268 * @example |
|
7269 * $(document).ready( function () { |
|
7270 * $('#example').dataTable( { |
|
7271 * "bAutoWidth": false |
|
7272 * } ); |
|
7273 * } ); |
|
7274 */ |
|
7275 "bAutoWidth": true, |
|
7276 |
|
7277 |
|
7278 /** |
|
7279 * Deferred rendering can provide DataTables with a huge speed boost when you |
|
7280 * are using an Ajax or JS data source for the table. This option, when set to |
|
7281 * true, will cause DataTables to defer the creation of the table elements for |
|
7282 * each row until they are needed for a draw - saving a significant amount of |
|
7283 * time. |
|
7284 * @type boolean |
|
7285 * @default false |
|
7286 * @dtopt Features |
|
7287 * |
|
7288 * @example |
|
7289 * $(document).ready( function() { |
|
7290 * var oTable = $('#example').dataTable( { |
|
7291 * "sAjaxSource": "sources/arrays.txt", |
|
7292 * "bDeferRender": true |
|
7293 * } ); |
|
7294 * } ); |
|
7295 */ |
|
7296 "bDeferRender": false, |
|
7297 |
|
7298 |
|
7299 /** |
|
7300 * Replace a DataTable which matches the given selector and replace it with |
|
7301 * one which has the properties of the new initialisation object passed. If no |
|
7302 * table matches the selector, then the new DataTable will be constructed as |
|
7303 * per normal. |
|
7304 * @type boolean |
|
7305 * @default false |
|
7306 * @dtopt Options |
|
7307 * |
|
7308 * @example |
|
7309 * $(document).ready( function() { |
|
7310 * $('#example').dataTable( { |
|
7311 * "sScrollY": "200px", |
|
7312 * "bPaginate": false |
|
7313 * } ); |
|
7314 * |
|
7315 * // Some time later.... |
|
7316 * $('#example').dataTable( { |
|
7317 * "bFilter": false, |
|
7318 * "bDestroy": true |
|
7319 * } ); |
|
7320 * } ); |
|
7321 */ |
|
7322 "bDestroy": false, |
|
7323 |
|
7324 |
|
7325 /** |
|
7326 * Enable or disable filtering of data. Filtering in DataTables is "smart" in |
|
7327 * that it allows the end user to input multiple words (space separated) and |
|
7328 * will match a row containing those words, even if not in the order that was |
|
7329 * specified (this allow matching across multiple columns). Note that if you |
|
7330 * wish to use filtering in DataTables this must remain 'true' - to remove the |
|
7331 * default filtering input box and retain filtering abilities, please use |
|
7332 * {@link DataTable.defaults.sDom}. |
|
7333 * @type boolean |
|
7334 * @default true |
|
7335 * @dtopt Features |
|
7336 * |
|
7337 * @example |
|
7338 * $(document).ready( function () { |
|
7339 * $('#example').dataTable( { |
|
7340 * "bFilter": false |
|
7341 * } ); |
|
7342 * } ); |
|
7343 */ |
|
7344 "bFilter": true, |
|
7345 |
|
7346 |
|
7347 /** |
|
7348 * Enable or disable the table information display. This shows information |
|
7349 * about the data that is currently visible on the page, including information |
|
7350 * about filtered data if that action is being performed. |
|
7351 * @type boolean |
|
7352 * @default true |
|
7353 * @dtopt Features |
|
7354 * |
|
7355 * @example |
|
7356 * $(document).ready( function () { |
|
7357 * $('#example').dataTable( { |
|
7358 * "bInfo": false |
|
7359 * } ); |
|
7360 * } ); |
|
7361 */ |
|
7362 "bInfo": true, |
|
7363 |
|
7364 |
|
7365 /** |
|
7366 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some |
|
7367 * slightly different and additional mark-up from what DataTables has |
|
7368 * traditionally used). |
|
7369 * @type boolean |
|
7370 * @default false |
|
7371 * @dtopt Features |
|
7372 * |
|
7373 * @example |
|
7374 * $(document).ready( function() { |
|
7375 * $('#example').dataTable( { |
|
7376 * "bJQueryUI": true |
|
7377 * } ); |
|
7378 * } ); |
|
7379 */ |
|
7380 "bJQueryUI": false, |
|
7381 |
|
7382 |
|
7383 /** |
|
7384 * Allows the end user to select the size of a formatted page from a select |
|
7385 * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate). |
|
7386 * @type boolean |
|
7387 * @default true |
|
7388 * @dtopt Features |
|
7389 * |
|
7390 * @example |
|
7391 * $(document).ready( function () { |
|
7392 * $('#example').dataTable( { |
|
7393 * "bLengthChange": false |
|
7394 * } ); |
|
7395 * } ); |
|
7396 */ |
|
7397 "bLengthChange": true, |
|
7398 |
|
7399 |
|
7400 /** |
|
7401 * Enable or disable pagination. |
|
7402 * @type boolean |
|
7403 * @default true |
|
7404 * @dtopt Features |
|
7405 * |
|
7406 * @example |
|
7407 * $(document).ready( function () { |
|
7408 * $('#example').dataTable( { |
|
7409 * "bPaginate": false |
|
7410 * } ); |
|
7411 * } ); |
|
7412 */ |
|
7413 "bPaginate": true, |
|
7414 |
|
7415 |
|
7416 /** |
|
7417 * Enable or disable the display of a 'processing' indicator when the table is |
|
7418 * being processed (e.g. a sort). This is particularly useful for tables with |
|
7419 * large amounts of data where it can take a noticeable amount of time to sort |
|
7420 * the entries. |
|
7421 * @type boolean |
|
7422 * @default false |
|
7423 * @dtopt Features |
|
7424 * |
|
7425 * @example |
|
7426 * $(document).ready( function () { |
|
7427 * $('#example').dataTable( { |
|
7428 * "bProcessing": true |
|
7429 * } ); |
|
7430 * } ); |
|
7431 */ |
|
7432 "bProcessing": false, |
|
7433 |
|
7434 |
|
7435 /** |
|
7436 * Retrieve the DataTables object for the given selector. Note that if the |
|
7437 * table has already been initialised, this parameter will cause DataTables |
|
7438 * to simply return the object that has already been set up - it will not take |
|
7439 * account of any changes you might have made to the initialisation object |
|
7440 * passed to DataTables (setting this parameter to true is an acknowledgement |
|
7441 * that you understand this). bDestroy can be used to reinitialise a table if |
|
7442 * you need. |
|
7443 * @type boolean |
|
7444 * @default false |
|
7445 * @dtopt Options |
|
7446 * |
|
7447 * @example |
|
7448 * $(document).ready( function() { |
|
7449 * initTable(); |
|
7450 * tableActions(); |
|
7451 * } ); |
|
7452 * |
|
7453 * function initTable () |
|
7454 * { |
|
7455 * return $('#example').dataTable( { |
|
7456 * "sScrollY": "200px", |
|
7457 * "bPaginate": false, |
|
7458 * "bRetrieve": true |
|
7459 * } ); |
|
7460 * } |
|
7461 * |
|
7462 * function tableActions () |
|
7463 * { |
|
7464 * var oTable = initTable(); |
|
7465 * // perform API operations with oTable |
|
7466 * } |
|
7467 */ |
|
7468 "bRetrieve": false, |
|
7469 |
|
7470 |
|
7471 /** |
|
7472 * Indicate if DataTables should be allowed to set the padding / margin |
|
7473 * etc for the scrolling header elements or not. Typically you will want |
|
7474 * this. |
|
7475 * @type boolean |
|
7476 * @default true |
|
7477 * @dtopt Options |
|
7478 * |
|
7479 * @example |
|
7480 * $(document).ready( function() { |
|
7481 * $('#example').dataTable( { |
|
7482 * "bScrollAutoCss": false, |
|
7483 * "sScrollY": "200px" |
|
7484 * } ); |
|
7485 * } ); |
|
7486 */ |
|
7487 "bScrollAutoCss": true, |
|
7488 |
|
7489 |
|
7490 /** |
|
7491 * When vertical (y) scrolling is enabled, DataTables will force the height of |
|
7492 * the table's viewport to the given height at all times (useful for layout). |
|
7493 * However, this can look odd when filtering data down to a small data set, |
|
7494 * and the footer is left "floating" further down. This parameter (when |
|
7495 * enabled) will cause DataTables to collapse the table's viewport down when |
|
7496 * the result set will fit within the given Y height. |
|
7497 * @type boolean |
|
7498 * @default false |
|
7499 * @dtopt Options |
|
7500 * |
|
7501 * @example |
|
7502 * $(document).ready( function() { |
|
7503 * $('#example').dataTable( { |
|
7504 * "sScrollY": "200", |
|
7505 * "bScrollCollapse": true |
|
7506 * } ); |
|
7507 * } ); |
|
7508 */ |
|
7509 "bScrollCollapse": false, |
|
7510 |
|
7511 |
|
7512 /** |
|
7513 * Enable infinite scrolling for DataTables (to be used in combination with |
|
7514 * sScrollY). Infinite scrolling means that DataTables will continually load |
|
7515 * data as a user scrolls through a table, which is very useful for large |
|
7516 * dataset. This cannot be used with pagination, which is automatically |
|
7517 * disabled. Note - the Scroller extra for DataTables is recommended in |
|
7518 * in preference to this option. |
|
7519 * @type boolean |
|
7520 * @default false |
|
7521 * @dtopt Features |
|
7522 * |
|
7523 * @example |
|
7524 * $(document).ready( function() { |
|
7525 * $('#example').dataTable( { |
|
7526 * "bScrollInfinite": true, |
|
7527 * "bScrollCollapse": true, |
|
7528 * "sScrollY": "200px" |
|
7529 * } ); |
|
7530 * } ); |
|
7531 */ |
|
7532 "bScrollInfinite": false, |
|
7533 |
|
7534 |
|
7535 /** |
|
7536 * Configure DataTables to use server-side processing. Note that the |
|
7537 * sAjaxSource parameter must also be given in order to give DataTables a |
|
7538 * source to obtain the required data for each draw. |
|
7539 * @type boolean |
|
7540 * @default false |
|
7541 * @dtopt Features |
|
7542 * @dtopt Server-side |
|
7543 * |
|
7544 * @example |
|
7545 * $(document).ready( function () { |
|
7546 * $('#example').dataTable( { |
|
7547 * "bServerSide": true, |
|
7548 * "sAjaxSource": "xhr.php" |
|
7549 * } ); |
|
7550 * } ); |
|
7551 */ |
|
7552 "bServerSide": false, |
|
7553 |
|
7554 |
|
7555 /** |
|
7556 * Enable or disable sorting of columns. Sorting of individual columns can be |
|
7557 * disabled by the "bSortable" option for each column. |
|
7558 * @type boolean |
|
7559 * @default true |
|
7560 * @dtopt Features |
|
7561 * |
|
7562 * @example |
|
7563 * $(document).ready( function () { |
|
7564 * $('#example').dataTable( { |
|
7565 * "bSort": false |
|
7566 * } ); |
|
7567 * } ); |
|
7568 */ |
|
7569 "bSort": true, |
|
7570 |
|
7571 |
|
7572 /** |
|
7573 * Allows control over whether DataTables should use the top (true) unique |
|
7574 * cell that is found for a single column, or the bottom (false - default). |
|
7575 * This is useful when using complex headers. |
|
7576 * @type boolean |
|
7577 * @default false |
|
7578 * @dtopt Options |
|
7579 * |
|
7580 * @example |
|
7581 * $(document).ready( function() { |
|
7582 * $('#example').dataTable( { |
|
7583 * "bSortCellsTop": true |
|
7584 * } ); |
|
7585 * } ); |
|
7586 */ |
|
7587 "bSortCellsTop": false, |
|
7588 |
|
7589 |
|
7590 /** |
|
7591 * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and |
|
7592 * 'sorting_3' to the columns which are currently being sorted on. This is |
|
7593 * presented as a feature switch as it can increase processing time (while |
|
7594 * classes are removed and added) so for large data sets you might want to |
|
7595 * turn this off. |
|
7596 * @type boolean |
|
7597 * @default true |
|
7598 * @dtopt Features |
|
7599 * |
|
7600 * @example |
|
7601 * $(document).ready( function () { |
|
7602 * $('#example').dataTable( { |
|
7603 * "bSortClasses": false |
|
7604 * } ); |
|
7605 * } ); |
|
7606 */ |
|
7607 "bSortClasses": true, |
|
7608 |
|
7609 |
|
7610 /** |
|
7611 * Enable or disable state saving. When enabled a cookie will be used to save |
|
7612 * table display information such as pagination information, display length, |
|
7613 * filtering and sorting. As such when the end user reloads the page the |
|
7614 * display display will match what thy had previously set up. |
|
7615 * @type boolean |
|
7616 * @default false |
|
7617 * @dtopt Features |
|
7618 * |
|
7619 * @example |
|
7620 * $(document).ready( function () { |
|
7621 * $('#example').dataTable( { |
|
7622 * "bStateSave": true |
|
7623 * } ); |
|
7624 * } ); |
|
7625 */ |
|
7626 "bStateSave": false, |
|
7627 |
|
7628 |
|
7629 /** |
|
7630 * Customise the cookie and / or the parameters being stored when using |
|
7631 * DataTables with state saving enabled. This function is called whenever |
|
7632 * the cookie is modified, and it expects a fully formed cookie string to be |
|
7633 * returned. Note that the data object passed in is a Javascript object which |
|
7634 * must be converted to a string (JSON.stringify for example). |
|
7635 * @type function |
|
7636 * @param {string} sName Name of the cookie defined by DataTables |
|
7637 * @param {object} oData Data to be stored in the cookie |
|
7638 * @param {string} sExpires Cookie expires string |
|
7639 * @param {string} sPath Path of the cookie to set |
|
7640 * @returns {string} Cookie formatted string (which should be encoded by |
|
7641 * using encodeURIComponent()) |
|
7642 * @dtopt Callbacks |
|
7643 * |
|
7644 * @example |
|
7645 * $(document).ready( function () { |
|
7646 * $('#example').dataTable( { |
|
7647 * "fnCookieCallback": function (sName, oData, sExpires, sPath) { |
|
7648 * // Customise oData or sName or whatever else here |
|
7649 * return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath; |
|
7650 * } |
|
7651 * } ); |
|
7652 * } ); |
|
7653 */ |
|
7654 "fnCookieCallback": null, |
|
7655 |
|
7656 |
|
7657 /** |
|
7658 * This function is called when a TR element is created (and all TD child |
|
7659 * elements have been inserted), or registered if using a DOM source, allowing |
|
7660 * manipulation of the TR element (adding classes etc). |
|
7661 * @type function |
|
7662 * @param {node} nRow "TR" element for the current row |
|
7663 * @param {array} aData Raw data array for this row |
|
7664 * @param {int} iDataIndex The index of this row in aoData |
|
7665 * @dtopt Callbacks |
|
7666 * |
|
7667 * @example |
|
7668 * $(document).ready( function() { |
|
7669 * $('#example').dataTable( { |
|
7670 * "fnCreatedRow": function( nRow, aData, iDataIndex ) { |
|
7671 * // Bold the grade for all 'A' grade browsers |
|
7672 * if ( aData[4] == "A" ) |
|
7673 * { |
|
7674 * $('td:eq(4)', nRow).html( '<b>A</b>' ); |
|
7675 * } |
|
7676 * } |
|
7677 * } ); |
|
7678 * } ); |
|
7679 */ |
|
7680 "fnCreatedRow": null, |
|
7681 |
|
7682 |
|
7683 /** |
|
7684 * This function is called on every 'draw' event, and allows you to |
|
7685 * dynamically modify any aspect you want about the created DOM. |
|
7686 * @type function |
|
7687 * @param {object} oSettings DataTables settings object |
|
7688 * @dtopt Callbacks |
|
7689 * |
|
7690 * @example |
|
7691 * $(document).ready( function() { |
|
7692 * $('#example').dataTable( { |
|
7693 * "fnDrawCallback": function( oSettings ) { |
|
7694 * alert( 'DataTables has redrawn the table' ); |
|
7695 * } |
|
7696 * } ); |
|
7697 * } ); |
|
7698 */ |
|
7699 "fnDrawCallback": null, |
|
7700 |
|
7701 |
|
7702 /** |
|
7703 * Identical to fnHeaderCallback() but for the table footer this function |
|
7704 * allows you to modify the table footer on every 'draw' even. |
|
7705 * @type function |
|
7706 * @param {node} nFoot "TR" element for the footer |
|
7707 * @param {array} aData Full table data (as derived from the original HTML) |
|
7708 * @param {int} iStart Index for the current display starting point in the |
|
7709 * display array |
|
7710 * @param {int} iEnd Index for the current display ending point in the |
|
7711 * display array |
|
7712 * @param {array int} aiDisplay Index array to translate the visual position |
|
7713 * to the full data array |
|
7714 * @dtopt Callbacks |
|
7715 * |
|
7716 * @example |
|
7717 * $(document).ready( function() { |
|
7718 * $('#example').dataTable( { |
|
7719 * "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) { |
|
7720 * nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart; |
|
7721 * } |
|
7722 * } ); |
|
7723 * } ) |
|
7724 */ |
|
7725 "fnFooterCallback": null, |
|
7726 |
|
7727 |
|
7728 /** |
|
7729 * When rendering large numbers in the information element for the table |
|
7730 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers |
|
7731 * to have a comma separator for the 'thousands' units (e.g. 1 million is |
|
7732 * rendered as "1,000,000") to help readability for the end user. This |
|
7733 * function will override the default method DataTables uses. |
|
7734 * @type function |
|
7735 * @member |
|
7736 * @param {int} iIn number to be formatted |
|
7737 * @returns {string} formatted string for DataTables to show the number |
|
7738 * @dtopt Callbacks |
|
7739 * |
|
7740 * @example |
|
7741 * $(document).ready( function() { |
|
7742 * $('#example').dataTable( { |
|
7743 * "fnFormatNumber": function ( iIn ) { |
|
7744 * if ( iIn < 1000 ) { |
|
7745 * return iIn; |
|
7746 * } else { |
|
7747 * var |
|
7748 * s=(iIn+""), |
|
7749 * a=s.split(""), out="", |
|
7750 * iLen=s.length; |
|
7751 * |
|
7752 * for ( var i=0 ; i<iLen ; i++ ) { |
|
7753 * if ( i%3 === 0 && i !== 0 ) { |
|
7754 * out = "'"+out; |
|
7755 * } |
|
7756 * out = a[iLen-i-1]+out; |
|
7757 * } |
|
7758 * } |
|
7759 * return out; |
|
7760 * }; |
|
7761 * } ); |
|
7762 * } ); |
|
7763 */ |
|
7764 "fnFormatNumber": function (iIn) { |
|
7765 if (iIn < 1000) { |
|
7766 // A small optimisation for what is likely to be the majority of use cases |
|
7767 return iIn; |
|
7768 } |
|
7769 |
|
7770 var s = (iIn + ""), a = s.split(""), out = "", iLen = s.length; |
|
7771 |
|
7772 for (var i = 0; i < iLen; i++) { |
|
7773 if (i % 3 === 0 && i !== 0) { |
|
7774 out = this.oLanguage.sInfoThousands + out; |
|
7775 } |
|
7776 out = a[iLen - i - 1] + out; |
|
7777 } |
|
7778 return out; |
|
7779 }, |
|
7780 |
|
7781 |
|
7782 /** |
|
7783 * This function is called on every 'draw' event, and allows you to |
|
7784 * dynamically modify the header row. This can be used to calculate and |
|
7785 * display useful information about the table. |
|
7786 * @type function |
|
7787 * @param {node} nHead "TR" element for the header |
|
7788 * @param {array} aData Full table data (as derived from the original HTML) |
|
7789 * @param {int} iStart Index for the current display starting point in the |
|
7790 * display array |
|
7791 * @param {int} iEnd Index for the current display ending point in the |
|
7792 * display array |
|
7793 * @param {array int} aiDisplay Index array to translate the visual position |
|
7794 * to the full data array |
|
7795 * @dtopt Callbacks |
|
7796 * |
|
7797 * @example |
|
7798 * $(document).ready( function() { |
|
7799 * $('#example').dataTable( { |
|
7800 * "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) { |
|
7801 * nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records"; |
|
7802 * } |
|
7803 * } ); |
|
7804 * } ) |
|
7805 */ |
|
7806 "fnHeaderCallback": null, |
|
7807 |
|
7808 |
|
7809 /** |
|
7810 * The information element can be used to convey information about the current |
|
7811 * state of the table. Although the internationalisation options presented by |
|
7812 * DataTables are quite capable of dealing with most customisations, there may |
|
7813 * be times where you wish to customise the string further. This callback |
|
7814 * allows you to do exactly that. |
|
7815 * @type function |
|
7816 * @param {object} oSettings DataTables settings object |
|
7817 * @param {int} iStart Starting position in data for the draw |
|
7818 * @param {int} iEnd End position in data for the draw |
|
7819 * @param {int} iMax Total number of rows in the table (regardless of |
|
7820 * filtering) |
|
7821 * @param {int} iTotal Total number of rows in the data set, after filtering |
|
7822 * @param {string} sPre The string that DataTables has formatted using it's |
|
7823 * own rules |
|
7824 * @returns {string} The string to be displayed in the information element. |
|
7825 * @dtopt Callbacks |
|
7826 * |
|
7827 * @example |
|
7828 * $('#example').dataTable( { |
|
7829 * "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) { |
|
7830 * return iStart +" to "+ iEnd; |
|
7831 * } |
|
7832 * } ); |
|
7833 */ |
|
7834 "fnInfoCallback": null, |
|
7835 |
|
7836 |
|
7837 /** |
|
7838 * Called when the table has been initialised. Normally DataTables will |
|
7839 * initialise sequentially and there will be no need for this function, |
|
7840 * however, this does not hold true when using external language information |
|
7841 * since that is obtained using an async XHR call. |
|
7842 * @type function |
|
7843 * @param {object} oSettings DataTables settings object |
|
7844 * @param {object} json The JSON object request from the server - only |
|
7845 * present if client-side Ajax sourced data is used |
|
7846 * @dtopt Callbacks |
|
7847 * |
|
7848 * @example |
|
7849 * $(document).ready( function() { |
|
7850 * $('#example').dataTable( { |
|
7851 * "fnInitComplete": function(oSettings, json) { |
|
7852 * alert( 'DataTables has finished its initialisation.' ); |
|
7853 * } |
|
7854 * } ); |
|
7855 * } ) |
|
7856 */ |
|
7857 "fnInitComplete": null, |
|
7858 |
|
7859 |
|
7860 /** |
|
7861 * Called at the very start of each table draw and can be used to cancel the |
|
7862 * draw by returning false, any other return (including undefined) results in |
|
7863 * the full draw occurring). |
|
7864 * @type function |
|
7865 * @param {object} oSettings DataTables settings object |
|
7866 * @returns {boolean} False will cancel the draw, anything else (including no |
|
7867 * return) will allow it to complete. |
|
7868 * @dtopt Callbacks |
|
7869 * |
|
7870 * @example |
|
7871 * $(document).ready( function() { |
|
7872 * $('#example').dataTable( { |
|
7873 * "fnPreDrawCallback": function( oSettings ) { |
|
7874 * if ( $('#test').val() == 1 ) { |
|
7875 * return false; |
|
7876 * } |
|
7877 * } |
|
7878 * } ); |
|
7879 * } ); |
|
7880 */ |
|
7881 "fnPreDrawCallback": null, |
|
7882 |
|
7883 |
|
7884 /** |
|
7885 * This function allows you to 'post process' each row after it have been |
|
7886 * generated for each table draw, but before it is rendered on screen. This |
|
7887 * function might be used for setting the row class name etc. |
|
7888 * @type function |
|
7889 * @param {node} nRow "TR" element for the current row |
|
7890 * @param {array} aData Raw data array for this row |
|
7891 * @param {int} iDisplayIndex The display index for the current table draw |
|
7892 * @param {int} iDisplayIndexFull The index of the data in the full list of |
|
7893 * rows (after filtering) |
|
7894 * @dtopt Callbacks |
|
7895 * |
|
7896 * @example |
|
7897 * $(document).ready( function() { |
|
7898 * $('#example').dataTable( { |
|
7899 * "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) { |
|
7900 * // Bold the grade for all 'A' grade browsers |
|
7901 * if ( aData[4] == "A" ) |
|
7902 * { |
|
7903 * $('td:eq(4)', nRow).html( '<b>A</b>' ); |
|
7904 * } |
|
7905 * } |
|
7906 * } ); |
|
7907 * } ); |
|
7908 */ |
|
7909 "fnRowCallback": null, |
|
7910 |
|
7911 |
|
7912 /** |
|
7913 * This parameter allows you to override the default function which obtains |
|
7914 * the data from the server ($.getJSON) so something more suitable for your |
|
7915 * application. For example you could use POST data, or pull information from |
|
7916 * a Gears or AIR database. |
|
7917 * @type function |
|
7918 * @member |
|
7919 * @param {string} sSource HTTP source to obtain the data from (sAjaxSource) |
|
7920 * @param {array} aoData A key/value pair object containing the data to send |
|
7921 * to the server |
|
7922 * @param {function} fnCallback to be called on completion of the data get |
|
7923 * process that will draw the data on the page. |
|
7924 * @param {object} oSettings DataTables settings object |
|
7925 * @dtopt Callbacks |
|
7926 * @dtopt Server-side |
|
7927 * |
|
7928 * @example |
|
7929 * // POST data to server |
|
7930 * $(document).ready( function() { |
|
7931 * $('#example').dataTable( { |
|
7932 * "bProcessing": true, |
|
7933 * "bServerSide": true, |
|
7934 * "sAjaxSource": "xhr.php", |
|
7935 * "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) { |
|
7936 * oSettings.jqXHR = $.ajax( { |
|
7937 * "dataType": 'json', |
|
7938 * "type": "POST", |
|
7939 * "url": sSource, |
|
7940 * "data": aoData, |
|
7941 * "success": fnCallback |
|
7942 * } ); |
|
7943 * } |
|
7944 * } ); |
|
7945 * } ); |
|
7946 */ |
|
7947 "fnServerData": function (sUrl, aoData, fnCallback, oSettings) { |
|
7948 oSettings.jqXHR = $.ajax({ |
|
7949 "url": sUrl, |
|
7950 "data": aoData, |
|
7951 "success": function (json) { |
|
7952 if (json.sError) { |
|
7953 oSettings.oApi._fnLog(oSettings, 0, json.sError); |
|
7954 } |
|
7955 |
|
7956 $(oSettings.oInstance).trigger('xhr', [oSettings, json]); |
|
7957 fnCallback(json); |
|
7958 }, |
|
7959 "dataType": "json", |
|
7960 "cache": false, |
|
7961 "type": oSettings.sServerMethod, |
|
7962 "error": function (xhr, error, thrown) { |
|
7963 if (error == "parsererror") { |
|
7964 oSettings.oApi._fnLog(oSettings, 0, "DataTables warning: JSON data from " + |
|
7965 "server could not be parsed. This is caused by a JSON formatting error."); |
|
7966 } |
|
7967 } |
|
7968 }); |
|
7969 }, |
|
7970 |
|
7971 |
|
7972 /** |
|
7973 * It is often useful to send extra data to the server when making an Ajax |
|
7974 * request - for example custom filtering information, and this callback |
|
7975 * function makes it trivial to send extra information to the server. The |
|
7976 * passed in parameter is the data set that has been constructed by |
|
7977 * DataTables, and you can add to this or modify it as you require. |
|
7978 * @type function |
|
7979 * @param {array} aoData Data array (array of objects which are name/value |
|
7980 * pairs) that has been constructed by DataTables and will be sent to the |
|
7981 * server. In the case of Ajax sourced data with server-side processing |
|
7982 * this will be an empty array, for server-side processing there will be a |
|
7983 * significant number of parameters! |
|
7984 * @returns {undefined} Ensure that you modify the aoData array passed in, |
|
7985 * as this is passed by reference. |
|
7986 * @dtopt Callbacks |
|
7987 * @dtopt Server-side |
|
7988 * |
|
7989 * @example |
|
7990 * $(document).ready( function() { |
|
7991 * $('#example').dataTable( { |
|
7992 * "bProcessing": true, |
|
7993 * "bServerSide": true, |
|
7994 * "sAjaxSource": "scripts/server_processing.php", |
|
7995 * "fnServerParams": function ( aoData ) { |
|
7996 * aoData.push( { "name": "more_data", "value": "my_value" } ); |
|
7997 * } |
|
7998 * } ); |
|
7999 * } ); |
|
8000 */ |
|
8001 "fnServerParams": null, |
|
8002 |
|
8003 |
|
8004 /** |
|
8005 * Load the table state. With this function you can define from where, and how, the |
|
8006 * state of a table is loaded. By default DataTables will load from its state saving |
|
8007 * cookie, but you might wish to use local storage (HTML5) or a server-side database. |
|
8008 * @type function |
|
8009 * @member |
|
8010 * @param {object} oSettings DataTables settings object |
|
8011 * @return {object} The DataTables state object to be loaded |
|
8012 * @dtopt Callbacks |
|
8013 * |
|
8014 * @example |
|
8015 * $(document).ready( function() { |
|
8016 * $('#example').dataTable( { |
|
8017 * "bStateSave": true, |
|
8018 * "fnStateLoad": function (oSettings) { |
|
8019 * var o; |
|
8020 * |
|
8021 * // Send an Ajax request to the server to get the data. Note that |
|
8022 * // this is a synchronous request. |
|
8023 * $.ajax( { |
|
8024 * "url": "/state_load", |
|
8025 * "async": false, |
|
8026 * "dataType": "json", |
|
8027 * "success": function (json) { |
|
8028 * o = json; |
|
8029 * } |
|
8030 * } ); |
|
8031 * |
|
8032 * return o; |
|
8033 * } |
|
8034 * } ); |
|
8035 * } ); |
|
8036 */ |
|
8037 "fnStateLoad": function (oSettings) { |
|
8038 var sData = this.oApi._fnReadCookie(oSettings.sCookiePrefix + oSettings.sInstance); |
|
8039 var oData; |
|
8040 |
|
8041 try { |
|
8042 oData = (typeof $.parseJSON === 'function') ? |
|
8043 $.parseJSON(sData) : eval('(' + sData + ')'); |
|
8044 } catch (e) { |
|
8045 oData = null; |
|
8046 } |
|
8047 |
|
8048 return oData; |
|
8049 }, |
|
8050 |
|
8051 |
|
8052 /** |
|
8053 * Callback which allows modification of the saved state prior to loading that state. |
|
8054 * This callback is called when the table is loading state from the stored data, but |
|
8055 * prior to the settings object being modified by the saved state. Note that for |
|
8056 * plug-in authors, you should use the 'stateLoadParams' event to load parameters for |
|
8057 * a plug-in. |
|
8058 * @type function |
|
8059 * @param {object} oSettings DataTables settings object |
|
8060 * @param {object} oData The state object that is to be loaded |
|
8061 * @dtopt Callbacks |
|
8062 * |
|
8063 * @example |
|
8064 * // Remove a saved filter, so filtering is never loaded |
|
8065 * $(document).ready( function() { |
|
8066 * $('#example').dataTable( { |
|
8067 * "bStateSave": true, |
|
8068 * "fnStateLoadParams": function (oSettings, oData) { |
|
8069 * oData.oSearch.sSearch = ""; |
|
8070 * } |
|
8071 * } ); |
|
8072 * } ); |
|
8073 * |
|
8074 * @example |
|
8075 * // Disallow state loading by returning false |
|
8076 * $(document).ready( function() { |
|
8077 * $('#example').dataTable( { |
|
8078 * "bStateSave": true, |
|
8079 * "fnStateLoadParams": function (oSettings, oData) { |
|
8080 * return false; |
|
8081 * } |
|
8082 * } ); |
|
8083 * } ); |
|
8084 */ |
|
8085 "fnStateLoadParams": null, |
|
8086 |
|
8087 |
|
8088 /** |
|
8089 * Callback that is called when the state has been loaded from the state saving method |
|
8090 * and the DataTables settings object has been modified as a result of the loaded state. |
|
8091 * @type function |
|
8092 * @param {object} oSettings DataTables settings object |
|
8093 * @param {object} oData The state object that was loaded |
|
8094 * @dtopt Callbacks |
|
8095 * |
|
8096 * @example |
|
8097 * // Show an alert with the filtering value that was saved |
|
8098 * $(document).ready( function() { |
|
8099 * $('#example').dataTable( { |
|
8100 * "bStateSave": true, |
|
8101 * "fnStateLoaded": function (oSettings, oData) { |
|
8102 * alert( 'Saved filter was: '+oData.oSearch.sSearch ); |
|
8103 * } |
|
8104 * } ); |
|
8105 * } ); |
|
8106 */ |
|
8107 "fnStateLoaded": null, |
|
8108 |
|
8109 |
|
8110 /** |
|
8111 * Save the table state. This function allows you to define where and how the state |
|
8112 * information for the table is stored - by default it will use a cookie, but you |
|
8113 * might want to use local storage (HTML5) or a server-side database. |
|
8114 * @type function |
|
8115 * @member |
|
8116 * @param {object} oSettings DataTables settings object |
|
8117 * @param {object} oData The state object to be saved |
|
8118 * @dtopt Callbacks |
|
8119 * |
|
8120 * @example |
|
8121 * $(document).ready( function() { |
|
8122 * $('#example').dataTable( { |
|
8123 * "bStateSave": true, |
|
8124 * "fnStateSave": function (oSettings, oData) { |
|
8125 * // Send an Ajax request to the server with the state object |
|
8126 * $.ajax( { |
|
8127 * "url": "/state_save", |
|
8128 * "data": oData, |
|
8129 * "dataType": "json", |
|
8130 * "method": "POST" |
|
8131 * "success": function () {} |
|
8132 * } ); |
|
8133 * } |
|
8134 * } ); |
|
8135 * } ); |
|
8136 */ |
|
8137 "fnStateSave": function (oSettings, oData) { |
|
8138 this.oApi._fnCreateCookie( |
|
8139 oSettings.sCookiePrefix + oSettings.sInstance, |
|
8140 this.oApi._fnJsonString(oData), |
|
8141 oSettings.iCookieDuration, |
|
8142 oSettings.sCookiePrefix, |
|
8143 oSettings.fnCookieCallback |
|
8144 ); |
|
8145 }, |
|
8146 |
|
8147 |
|
8148 /** |
|
8149 * Callback which allows modification of the state to be saved. Called when the table |
|
8150 * has changed state a new state save is required. This method allows modification of |
|
8151 * the state saving object prior to actually doing the save, including addition or |
|
8152 * other state properties or modification. Note that for plug-in authors, you should |
|
8153 * use the 'stateSaveParams' event to save parameters for a plug-in. |
|
8154 * @type function |
|
8155 * @param {object} oSettings DataTables settings object |
|
8156 * @param {object} oData The state object to be saved |
|
8157 * @dtopt Callbacks |
|
8158 * |
|
8159 * @example |
|
8160 * // Remove a saved filter, so filtering is never saved |
|
8161 * $(document).ready( function() { |
|
8162 * $('#example').dataTable( { |
|
8163 * "bStateSave": true, |
|
8164 * "fnStateSaveParams": function (oSettings, oData) { |
|
8165 * oData.oSearch.sSearch = ""; |
|
8166 * } |
|
8167 * } ); |
|
8168 * } ); |
|
8169 */ |
|
8170 "fnStateSaveParams": null, |
|
8171 |
|
8172 |
|
8173 /** |
|
8174 * Duration of the cookie which is used for storing session information. This |
|
8175 * value is given in seconds. |
|
8176 * @type int |
|
8177 * @default 7200 <i>(2 hours)</i> |
|
8178 * @dtopt Options |
|
8179 * |
|
8180 * @example |
|
8181 * $(document).ready( function() { |
|
8182 * $('#example').dataTable( { |
|
8183 * "iCookieDuration": 60*60*24; // 1 day |
|
8184 * } ); |
|
8185 * } ) |
|
8186 */ |
|
8187 "iCookieDuration": 7200, |
|
8188 |
|
8189 |
|
8190 /** |
|
8191 * When enabled DataTables will not make a request to the server for the first |
|
8192 * page draw - rather it will use the data already on the page (no sorting etc |
|
8193 * will be applied to it), thus saving on an XHR at load time. iDeferLoading |
|
8194 * is used to indicate that deferred loading is required, but it is also used |
|
8195 * to tell DataTables how many records there are in the full table (allowing |
|
8196 * the information element and pagination to be displayed correctly). In the case |
|
8197 * where a filtering is applied to the table on initial load, this can be |
|
8198 * indicated by giving the parameter as an array, where the first element is |
|
8199 * the number of records available after filtering and the second element is the |
|
8200 * number of records without filtering (allowing the table information element |
|
8201 * to be shown correctly). |
|
8202 * @type int | array |
|
8203 * @default null |
|
8204 * @dtopt Options |
|
8205 * |
|
8206 * @example |
|
8207 * // 57 records available in the table, no filtering applied |
|
8208 * $(document).ready( function() { |
|
8209 * $('#example').dataTable( { |
|
8210 * "bServerSide": true, |
|
8211 * "sAjaxSource": "scripts/server_processing.php", |
|
8212 * "iDeferLoading": 57 |
|
8213 * } ); |
|
8214 * } ); |
|
8215 * |
|
8216 * @example |
|
8217 * // 57 records after filtering, 100 without filtering (an initial filter applied) |
|
8218 * $(document).ready( function() { |
|
8219 * $('#example').dataTable( { |
|
8220 * "bServerSide": true, |
|
8221 * "sAjaxSource": "scripts/server_processing.php", |
|
8222 * "iDeferLoading": [ 57, 100 ], |
|
8223 * "oSearch": { |
|
8224 * "sSearch": "my_filter" |
|
8225 * } |
|
8226 * } ); |
|
8227 * } ); |
|
8228 */ |
|
8229 "iDeferLoading": null, |
|
8230 |
|
8231 |
|
8232 /** |
|
8233 * Number of rows to display on a single page when using pagination. If |
|
8234 * feature enabled (bLengthChange) then the end user will be able to override |
|
8235 * this to a custom setting using a pop-up menu. |
|
8236 * @type int |
|
8237 * @default 10 |
|
8238 * @dtopt Options |
|
8239 * |
|
8240 * @example |
|
8241 * $(document).ready( function() { |
|
8242 * $('#example').dataTable( { |
|
8243 * "iDisplayLength": 50 |
|
8244 * } ); |
|
8245 * } ) |
|
8246 */ |
|
8247 "iDisplayLength": 10, |
|
8248 |
|
8249 |
|
8250 /** |
|
8251 * Define the starting point for data display when using DataTables with |
|
8252 * pagination. Note that this parameter is the number of records, rather than |
|
8253 * the page number, so if you have 10 records per page and want to start on |
|
8254 * the third page, it should be "20". |
|
8255 * @type int |
|
8256 * @default 0 |
|
8257 * @dtopt Options |
|
8258 * |
|
8259 * @example |
|
8260 * $(document).ready( function() { |
|
8261 * $('#example').dataTable( { |
|
8262 * "iDisplayStart": 20 |
|
8263 * } ); |
|
8264 * } ) |
|
8265 */ |
|
8266 "iDisplayStart": 0, |
|
8267 |
|
8268 |
|
8269 /** |
|
8270 * The scroll gap is the amount of scrolling that is left to go before |
|
8271 * DataTables will load the next 'page' of data automatically. You typically |
|
8272 * want a gap which is big enough that the scrolling will be smooth for the |
|
8273 * user, while not so large that it will load more data than need. |
|
8274 * @type int |
|
8275 * @default 100 |
|
8276 * @dtopt Options |
|
8277 * |
|
8278 * @example |
|
8279 * $(document).ready( function() { |
|
8280 * $('#example').dataTable( { |
|
8281 * "bScrollInfinite": true, |
|
8282 * "bScrollCollapse": true, |
|
8283 * "sScrollY": "200px", |
|
8284 * "iScrollLoadGap": 50 |
|
8285 * } ); |
|
8286 * } ); |
|
8287 */ |
|
8288 "iScrollLoadGap": 100, |
|
8289 |
|
8290 |
|
8291 /** |
|
8292 * By default DataTables allows keyboard navigation of the table (sorting, paging, |
|
8293 * and filtering) by adding a tabindex attribute to the required elements. This |
|
8294 * allows you to tab through the controls and press the enter key to activate them. |
|
8295 * The tabindex is default 0, meaning that the tab follows the flow of the document. |
|
8296 * You can overrule this using this parameter if you wish. Use a value of -1 to |
|
8297 * disable built-in keyboard navigation. |
|
8298 * @type int |
|
8299 * @default 0 |
|
8300 * @dtopt Options |
|
8301 * |
|
8302 * @example |
|
8303 * $(document).ready( function() { |
|
8304 * $('#example').dataTable( { |
|
8305 * "iTabIndex": 1 |
|
8306 * } ); |
|
8307 * } ); |
|
8308 */ |
|
8309 "iTabIndex": 0, |
|
8310 |
|
8311 |
|
8312 /** |
|
8313 * All strings that DataTables uses in the user interface that it creates |
|
8314 * are defined in this object, allowing you to modified them individually or |
|
8315 * completely replace them all as required. |
|
8316 * @namespace |
|
8317 */ |
|
8318 "oLanguage": { |
|
8319 /** |
|
8320 * Strings that are used for WAI-ARIA labels and controls only (these are not |
|
8321 * actually visible on the page, but will be read by screenreaders, and thus |
|
8322 * must be internationalised as well). |
|
8323 * @namespace |
|
8324 */ |
|
8325 "oAria": { |
|
8326 /** |
|
8327 * ARIA label that is added to the table headers when the column may be |
|
8328 * sorted ascending by activing the column (click or return when focused). |
|
8329 * Note that the column header is prefixed to this string. |
|
8330 * @type string |
|
8331 * @default : activate to sort column ascending |
|
8332 * @dtopt Language |
|
8333 * |
|
8334 * @example |
|
8335 * $(document).ready( function() { |
|
8336 * $('#example').dataTable( { |
|
8337 * "oLanguage": { |
|
8338 * "oAria": { |
|
8339 * "sSortAscending": " - click/return to sort ascending" |
|
8340 * } |
|
8341 * } |
|
8342 * } ); |
|
8343 * } ); |
|
8344 */ |
|
8345 "sSortAscending": ": activate to sort column ascending", |
|
8346 |
|
8347 /** |
|
8348 * ARIA label that is added to the table headers when the column may be |
|
8349 * sorted descending by activing the column (click or return when focused). |
|
8350 * Note that the column header is prefixed to this string. |
|
8351 * @type string |
|
8352 * @default : activate to sort column ascending |
|
8353 * @dtopt Language |
|
8354 * |
|
8355 * @example |
|
8356 * $(document).ready( function() { |
|
8357 * $('#example').dataTable( { |
|
8358 * "oLanguage": { |
|
8359 * "oAria": { |
|
8360 * "sSortDescending": " - click/return to sort descending" |
|
8361 * } |
|
8362 * } |
|
8363 * } ); |
|
8364 * } ); |
|
8365 */ |
|
8366 "sSortDescending": ": activate to sort column descending" |
|
8367 }, |
|
8368 |
|
8369 /** |
|
8370 * Pagination string used by DataTables for the two built-in pagination |
|
8371 * control types ("two_button" and "full_numbers") |
|
8372 * @namespace |
|
8373 */ |
|
8374 "oPaginate": { |
|
8375 /** |
|
8376 * Text to use when using the 'full_numbers' type of pagination for the |
|
8377 * button to take the user to the first page. |
|
8378 * @type string |
|
8379 * @default First |
|
8380 * @dtopt Language |
|
8381 * |
|
8382 * @example |
|
8383 * $(document).ready( function() { |
|
8384 * $('#example').dataTable( { |
|
8385 * "oLanguage": { |
|
8386 * "oPaginate": { |
|
8387 * "sFirst": "First page" |
|
8388 * } |
|
8389 * } |
|
8390 * } ); |
|
8391 * } ); |
|
8392 */ |
|
8393 "sFirst": "First", |
|
8394 |
|
8395 |
|
8396 /** |
|
8397 * Text to use when using the 'full_numbers' type of pagination for the |
|
8398 * button to take the user to the last page. |
|
8399 * @type string |
|
8400 * @default Last |
|
8401 * @dtopt Language |
|
8402 * |
|
8403 * @example |
|
8404 * $(document).ready( function() { |
|
8405 * $('#example').dataTable( { |
|
8406 * "oLanguage": { |
|
8407 * "oPaginate": { |
|
8408 * "sLast": "Last page" |
|
8409 * } |
|
8410 * } |
|
8411 * } ); |
|
8412 * } ); |
|
8413 */ |
|
8414 "sLast": "Last", |
|
8415 |
|
8416 |
|
8417 /** |
|
8418 * Text to use for the 'next' pagination button (to take the user to the |
|
8419 * next page). |
|
8420 * @type string |
|
8421 * @default Next |
|
8422 * @dtopt Language |
|
8423 * |
|
8424 * @example |
|
8425 * $(document).ready( function() { |
|
8426 * $('#example').dataTable( { |
|
8427 * "oLanguage": { |
|
8428 * "oPaginate": { |
|
8429 * "sNext": "Next page" |
|
8430 * } |
|
8431 * } |
|
8432 * } ); |
|
8433 * } ); |
|
8434 */ |
|
8435 "sNext": "Next", |
|
8436 |
|
8437 |
|
8438 /** |
|
8439 * Text to use for the 'previous' pagination button (to take the user to |
|
8440 * the previous page). |
|
8441 * @type string |
|
8442 * @default Previous |
|
8443 * @dtopt Language |
|
8444 * |
|
8445 * @example |
|
8446 * $(document).ready( function() { |
|
8447 * $('#example').dataTable( { |
|
8448 * "oLanguage": { |
|
8449 * "oPaginate": { |
|
8450 * "sPrevious": "Previous page" |
|
8451 * } |
|
8452 * } |
|
8453 * } ); |
|
8454 * } ); |
|
8455 */ |
|
8456 "sPrevious": "Previous" |
|
8457 }, |
|
8458 |
|
8459 /** |
|
8460 * This string is shown in preference to sZeroRecords when the table is |
|
8461 * empty of data (regardless of filtering). Note that this is an optional |
|
8462 * parameter - if it is not given, the value of sZeroRecords will be used |
|
8463 * instead (either the default or given value). |
|
8464 * @type string |
|
8465 * @default No data available in table |
|
8466 * @dtopt Language |
|
8467 * |
|
8468 * @example |
|
8469 * $(document).ready( function() { |
|
8470 * $('#example').dataTable( { |
|
8471 * "oLanguage": { |
|
8472 * "sEmptyTable": "No data available in table" |
|
8473 * } |
|
8474 * } ); |
|
8475 * } ); |
|
8476 */ |
|
8477 "sEmptyTable": "No data available in table", |
|
8478 |
|
8479 |
|
8480 /** |
|
8481 * This string gives information to the end user about the information that |
|
8482 * is current on display on the page. The _START_, _END_ and _TOTAL_ |
|
8483 * variables are all dynamically replaced as the table display updates, and |
|
8484 * can be freely moved or removed as the language requirements change. |
|
8485 * @type string |
|
8486 * @default Showing _START_ to _END_ of _TOTAL_ entries |
|
8487 * @dtopt Language |
|
8488 * |
|
8489 * @example |
|
8490 * $(document).ready( function() { |
|
8491 * $('#example').dataTable( { |
|
8492 * "oLanguage": { |
|
8493 * "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)" |
|
8494 * } |
|
8495 * } ); |
|
8496 * } ); |
|
8497 */ |
|
8498 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", |
|
8499 |
|
8500 |
|
8501 /** |
|
8502 * Display information string for when the table is empty. Typically the |
|
8503 * format of this string should match sInfo. |
|
8504 * @type string |
|
8505 * @default Showing 0 to 0 of 0 entries |
|
8506 * @dtopt Language |
|
8507 * |
|
8508 * @example |
|
8509 * $(document).ready( function() { |
|
8510 * $('#example').dataTable( { |
|
8511 * "oLanguage": { |
|
8512 * "sInfoEmpty": "No entries to show" |
|
8513 * } |
|
8514 * } ); |
|
8515 * } ); |
|
8516 */ |
|
8517 "sInfoEmpty": "Showing 0 to 0 of 0 entries", |
|
8518 |
|
8519 |
|
8520 /** |
|
8521 * When a user filters the information in a table, this string is appended |
|
8522 * to the information (sInfo) to give an idea of how strong the filtering |
|
8523 * is. The variable _MAX_ is dynamically updated. |
|
8524 * @type string |
|
8525 * @default (filtered from _MAX_ total entries) |
|
8526 * @dtopt Language |
|
8527 * |
|
8528 * @example |
|
8529 * $(document).ready( function() { |
|
8530 * $('#example').dataTable( { |
|
8531 * "oLanguage": { |
|
8532 * "sInfoFiltered": " - filtering from _MAX_ records" |
|
8533 * } |
|
8534 * } ); |
|
8535 * } ); |
|
8536 */ |
|
8537 "sInfoFiltered": "(filtered from _MAX_ total entries)", |
|
8538 |
|
8539 |
|
8540 /** |
|
8541 * If can be useful to append extra information to the info string at times, |
|
8542 * and this variable does exactly that. This information will be appended to |
|
8543 * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are |
|
8544 * being used) at all times. |
|
8545 * @type string |
|
8546 * @default <i>Empty string</i> |
|
8547 * @dtopt Language |
|
8548 * |
|
8549 * @example |
|
8550 * $(document).ready( function() { |
|
8551 * $('#example').dataTable( { |
|
8552 * "oLanguage": { |
|
8553 * "sInfoPostFix": "All records shown are derived from real information." |
|
8554 * } |
|
8555 * } ); |
|
8556 * } ); |
|
8557 */ |
|
8558 "sInfoPostFix": "", |
|
8559 |
|
8560 |
|
8561 /** |
|
8562 * DataTables has a build in number formatter (fnFormatNumber) which is used |
|
8563 * to format large numbers that are used in the table information. By |
|
8564 * default a comma is used, but this can be trivially changed to any |
|
8565 * character you wish with this parameter. |
|
8566 * @type string |
|
8567 * @default , |
|
8568 * @dtopt Language |
|
8569 * |
|
8570 * @example |
|
8571 * $(document).ready( function() { |
|
8572 * $('#example').dataTable( { |
|
8573 * "oLanguage": { |
|
8574 * "sInfoThousands": "'" |
|
8575 * } |
|
8576 * } ); |
|
8577 * } ); |
|
8578 */ |
|
8579 "sInfoThousands": ",", |
|
8580 |
|
8581 |
|
8582 /** |
|
8583 * Detail the action that will be taken when the drop down menu for the |
|
8584 * pagination length option is changed. The '_MENU_' variable is replaced |
|
8585 * with a default select list of 10, 25, 50 and 100, and can be replaced |
|
8586 * with a custom select box if required. |
|
8587 * @type string |
|
8588 * @default Show _MENU_ entries |
|
8589 * @dtopt Language |
|
8590 * |
|
8591 * @example |
|
8592 * // Language change only |
|
8593 * $(document).ready( function() { |
|
8594 * $('#example').dataTable( { |
|
8595 * "oLanguage": { |
|
8596 * "sLengthMenu": "Display _MENU_ records" |
|
8597 * } |
|
8598 * } ); |
|
8599 * } ); |
|
8600 * |
|
8601 * @example |
|
8602 * // Language and options change |
|
8603 * $(document).ready( function() { |
|
8604 * $('#example').dataTable( { |
|
8605 * "oLanguage": { |
|
8606 * "sLengthMenu": 'Display <select>'+ |
|
8607 * '<option value="10">10</option>'+ |
|
8608 * '<option value="20">20</option>'+ |
|
8609 * '<option value="30">30</option>'+ |
|
8610 * '<option value="40">40</option>'+ |
|
8611 * '<option value="50">50</option>'+ |
|
8612 * '<option value="-1">All</option>'+ |
|
8613 * '</select> records' |
|
8614 * } |
|
8615 * } ); |
|
8616 * } ); |
|
8617 */ |
|
8618 "sLengthMenu": "Show _MENU_ entries", |
|
8619 |
|
8620 |
|
8621 /** |
|
8622 * When using Ajax sourced data and during the first draw when DataTables is |
|
8623 * gathering the data, this message is shown in an empty row in the table to |
|
8624 * indicate to the end user the the data is being loaded. Note that this |
|
8625 * parameter is not used when loading data by server-side processing, just |
|
8626 * Ajax sourced data with client-side processing. |
|
8627 * @type string |
|
8628 * @default Loading... |
|
8629 * @dtopt Language |
|
8630 * |
|
8631 * @example |
|
8632 * $(document).ready( function() { |
|
8633 * $('#example').dataTable( { |
|
8634 * "oLanguage": { |
|
8635 * "sLoadingRecords": "Please wait - loading..." |
|
8636 * } |
|
8637 * } ); |
|
8638 * } ); |
|
8639 */ |
|
8640 "sLoadingRecords": "Loading...", |
|
8641 |
|
8642 |
|
8643 /** |
|
8644 * Text which is displayed when the table is processing a user action |
|
8645 * (usually a sort command or similar). |
|
8646 * @type string |
|
8647 * @default Processing... |
|
8648 * @dtopt Language |
|
8649 * |
|
8650 * @example |
|
8651 * $(document).ready( function() { |
|
8652 * $('#example').dataTable( { |
|
8653 * "oLanguage": { |
|
8654 * "sProcessing": "DataTables is currently busy" |
|
8655 * } |
|
8656 * } ); |
|
8657 * } ); |
|
8658 */ |
|
8659 "sProcessing": "Processing...", |
|
8660 |
|
8661 |
|
8662 /** |
|
8663 * Details the actions that will be taken when the user types into the |
|
8664 * filtering input text box. The variable "_INPUT_", if used in the string, |
|
8665 * is replaced with the HTML text box for the filtering input allowing |
|
8666 * control over where it appears in the string. If "_INPUT_" is not given |
|
8667 * then the input box is appended to the string automatically. |
|
8668 * @type string |
|
8669 * @default Search: |
|
8670 * @dtopt Language |
|
8671 * |
|
8672 * @example |
|
8673 * // Input text box will be appended at the end automatically |
|
8674 * $(document).ready( function() { |
|
8675 * $('#example').dataTable( { |
|
8676 * "oLanguage": { |
|
8677 * "sSearch": "Filter records:" |
|
8678 * } |
|
8679 * } ); |
|
8680 * } ); |
|
8681 * |
|
8682 * @example |
|
8683 * // Specify where the filter should appear |
|
8684 * $(document).ready( function() { |
|
8685 * $('#example').dataTable( { |
|
8686 * "oLanguage": { |
|
8687 * "sSearch": "Apply filter _INPUT_ to table" |
|
8688 * } |
|
8689 * } ); |
|
8690 * } ); |
|
8691 */ |
|
8692 "sSearch": "Search:", |
|
8693 |
|
8694 |
|
8695 /** |
|
8696 * All of the language information can be stored in a file on the |
|
8697 * server-side, which DataTables will look up if this parameter is passed. |
|
8698 * It must store the URL of the language file, which is in a JSON format, |
|
8699 * and the object has the same properties as the oLanguage object in the |
|
8700 * initialiser object (i.e. the above parameters). Please refer to one of |
|
8701 * the example language files to see how this works in action. |
|
8702 * @type string |
|
8703 * @default <i>Empty string - i.e. disabled</i> |
|
8704 * @dtopt Language |
|
8705 * |
|
8706 * @example |
|
8707 * $(document).ready( function() { |
|
8708 * $('#example').dataTable( { |
|
8709 * "oLanguage": { |
|
8710 * "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt" |
|
8711 * } |
|
8712 * } ); |
|
8713 * } ); |
|
8714 */ |
|
8715 "sUrl": "", |
|
8716 |
|
8717 |
|
8718 /** |
|
8719 * Text shown inside the table records when the is no information to be |
|
8720 * displayed after filtering. sEmptyTable is shown when there is simply no |
|
8721 * information in the table at all (regardless of filtering). |
|
8722 * @type string |
|
8723 * @default No matching records found |
|
8724 * @dtopt Language |
|
8725 * |
|
8726 * @example |
|
8727 * $(document).ready( function() { |
|
8728 * $('#example').dataTable( { |
|
8729 * "oLanguage": { |
|
8730 * "sZeroRecords": "No records to display" |
|
8731 * } |
|
8732 * } ); |
|
8733 * } ); |
|
8734 */ |
|
8735 "sZeroRecords": "No matching records found" |
|
8736 }, |
|
8737 |
|
8738 |
|
8739 /** |
|
8740 * This parameter allows you to have define the global filtering state at |
|
8741 * initialisation time. As an object the "sSearch" parameter must be |
|
8742 * defined, but all other parameters are optional. When "bRegex" is true, |
|
8743 * the search string will be treated as a regular expression, when false |
|
8744 * (default) it will be treated as a straight string. When "bSmart" |
|
8745 * DataTables will use it's smart filtering methods (to word match at |
|
8746 * any point in the data), when false this will not be done. |
|
8747 * @namespace |
|
8748 * @extends DataTable.models.oSearch |
|
8749 * @dtopt Options |
|
8750 * |
|
8751 * @example |
|
8752 * $(document).ready( function() { |
|
8753 * $('#example').dataTable( { |
|
8754 * "oSearch": {"sSearch": "Initial search"} |
|
8755 * } ); |
|
8756 * } ) |
|
8757 */ |
|
8758 "oSearch": $.extend({}, DataTable.models.oSearch), |
|
8759 |
|
8760 |
|
8761 /** |
|
8762 * By default DataTables will look for the property 'aaData' when obtaining |
|
8763 * data from an Ajax source or for server-side processing - this parameter |
|
8764 * allows that property to be changed. You can use Javascript dotted object |
|
8765 * notation to get a data source for multiple levels of nesting. |
|
8766 * @type string |
|
8767 * @default aaData |
|
8768 * @dtopt Options |
|
8769 * @dtopt Server-side |
|
8770 * |
|
8771 * @example |
|
8772 * // Get data from { "data": [...] } |
|
8773 * $(document).ready( function() { |
|
8774 * var oTable = $('#example').dataTable( { |
|
8775 * "sAjaxSource": "sources/data.txt", |
|
8776 * "sAjaxDataProp": "data" |
|
8777 * } ); |
|
8778 * } ); |
|
8779 * |
|
8780 * @example |
|
8781 * // Get data from { "data": { "inner": [...] } } |
|
8782 * $(document).ready( function() { |
|
8783 * var oTable = $('#example').dataTable( { |
|
8784 * "sAjaxSource": "sources/data.txt", |
|
8785 * "sAjaxDataProp": "data.inner" |
|
8786 * } ); |
|
8787 * } ); |
|
8788 */ |
|
8789 "sAjaxDataProp": "aaData", |
|
8790 |
|
8791 |
|
8792 /** |
|
8793 * You can instruct DataTables to load data from an external source using this |
|
8794 * parameter (use aData if you want to pass data in you already have). Simply |
|
8795 * provide a url a JSON object can be obtained from. This object must include |
|
8796 * the parameter 'aaData' which is the data source for the table. |
|
8797 * @type string |
|
8798 * @default null |
|
8799 * @dtopt Options |
|
8800 * @dtopt Server-side |
|
8801 * |
|
8802 * @example |
|
8803 * $(document).ready( function() { |
|
8804 * $('#example').dataTable( { |
|
8805 * "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php" |
|
8806 * } ); |
|
8807 * } ) |
|
8808 */ |
|
8809 "sAjaxSource": null, |
|
8810 |
|
8811 |
|
8812 /** |
|
8813 * This parameter can be used to override the default prefix that DataTables |
|
8814 * assigns to a cookie when state saving is enabled. |
|
8815 * @type string |
|
8816 * @default SpryMedia_DataTables_ |
|
8817 * @dtopt Options |
|
8818 * |
|
8819 * @example |
|
8820 * $(document).ready( function() { |
|
8821 * $('#example').dataTable( { |
|
8822 * "sCookiePrefix": "my_datatable_", |
|
8823 * } ); |
|
8824 * } ); |
|
8825 */ |
|
8826 "sCookiePrefix": "SpryMedia_DataTables_", |
|
8827 |
|
8828 |
|
8829 /** |
|
8830 * This initialisation variable allows you to specify exactly where in the |
|
8831 * DOM you want DataTables to inject the various controls it adds to the page |
|
8832 * (for example you might want the pagination controls at the top of the |
|
8833 * table). DIV elements (with or without a custom class) can also be added to |
|
8834 * aid styling. The follow syntax is used: |
|
8835 * <ul> |
|
8836 * <li>The following options are allowed: |
|
8837 * <ul> |
|
8838 * <li>'l' - Length changing</li |
|
8839 * <li>'f' - Filtering input</li> |
|
8840 * <li>'t' - The table!</li> |
|
8841 * <li>'i' - Information</li> |
|
8842 * <li>'p' - Pagination</li> |
|
8843 * <li>'r' - pRocessing</li> |
|
8844 * </ul> |
|
8845 * </li> |
|
8846 * <li>The following constants are allowed: |
|
8847 * <ul> |
|
8848 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> |
|
8849 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> |
|
8850 * </ul> |
|
8851 * </li> |
|
8852 * <li>The following syntax is expected: |
|
8853 * <ul> |
|
8854 * <li>'<' and '>' - div elements</li> |
|
8855 * <li>'<"class" and '>' - div with a class</li> |
|
8856 * <li>'<"#id" and '>' - div with an ID</li> |
|
8857 * </ul> |
|
8858 * </li> |
|
8859 * <li>Examples: |
|
8860 * <ul> |
|
8861 * <li>'<"wrapper"flipt>'</li> |
|
8862 * <li>'<lf<t>ip>'</li> |
|
8863 * </ul> |
|
8864 * </li> |
|
8865 * </ul> |
|
8866 * @type string |
|
8867 * @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b> |
|
8868 * <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i> |
|
8869 * @dtopt Options |
|
8870 * |
|
8871 * @example |
|
8872 * $(document).ready( function() { |
|
8873 * $('#example').dataTable( { |
|
8874 * "sDom": '<"top"i>rt<"bottom"flp><"clear">' |
|
8875 * } ); |
|
8876 * } ); |
|
8877 */ |
|
8878 "sDom": "lfrtip", |
|
8879 |
|
8880 |
|
8881 /** |
|
8882 * DataTables features two different built-in pagination interaction methods |
|
8883 * ('two_button' or 'full_numbers') which present different page controls to |
|
8884 * the end user. Further methods can be added using the API (see below). |
|
8885 * @type string |
|
8886 * @default two_button |
|
8887 * @dtopt Options |
|
8888 * |
|
8889 * @example |
|
8890 * $(document).ready( function() { |
|
8891 * $('#example').dataTable( { |
|
8892 * "sPaginationType": "full_numbers" |
|
8893 * } ); |
|
8894 * } ) |
|
8895 */ |
|
8896 "sPaginationType": "two_button", |
|
8897 |
|
8898 |
|
8899 /** |
|
8900 * Enable horizontal scrolling. When a table is too wide to fit into a certain |
|
8901 * layout, or you have a large number of columns in the table, you can enable |
|
8902 * x-scrolling to show the table in a viewport, which can be scrolled. This |
|
8903 * property can be any CSS unit, or a number (in which case it will be treated |
|
8904 * as a pixel measurement). |
|
8905 * @type string |
|
8906 * @default <i>blank string - i.e. disabled</i> |
|
8907 * @dtopt Features |
|
8908 * |
|
8909 * @example |
|
8910 * $(document).ready( function() { |
|
8911 * $('#example').dataTable( { |
|
8912 * "sScrollX": "100%", |
|
8913 * "bScrollCollapse": true |
|
8914 * } ); |
|
8915 * } ); |
|
8916 */ |
|
8917 "sScrollX": "", |
|
8918 |
|
8919 |
|
8920 /** |
|
8921 * This property can be used to force a DataTable to use more width than it |
|
8922 * might otherwise do when x-scrolling is enabled. For example if you have a |
|
8923 * table which requires to be well spaced, this parameter is useful for |
|
8924 * "over-sizing" the table, and thus forcing scrolling. This property can by |
|
8925 * any CSS unit, or a number (in which case it will be treated as a pixel |
|
8926 * measurement). |
|
8927 * @type string |
|
8928 * @default <i>blank string - i.e. disabled</i> |
|
8929 * @dtopt Options |
|
8930 * |
|
8931 * @example |
|
8932 * $(document).ready( function() { |
|
8933 * $('#example').dataTable( { |
|
8934 * "sScrollX": "100%", |
|
8935 * "sScrollXInner": "110%" |
|
8936 * } ); |
|
8937 * } ); |
|
8938 */ |
|
8939 "sScrollXInner": "", |
|
8940 |
|
8941 |
|
8942 /** |
|
8943 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable |
|
8944 * to the given height, and enable scrolling for any data which overflows the |
|
8945 * current viewport. This can be used as an alternative to paging to display |
|
8946 * a lot of data in a small area (although paging and scrolling can both be |
|
8947 * enabled at the same time). This property can be any CSS unit, or a number |
|
8948 * (in which case it will be treated as a pixel measurement). |
|
8949 * @type string |
|
8950 * @default <i>blank string - i.e. disabled</i> |
|
8951 * @dtopt Features |
|
8952 * |
|
8953 * @example |
|
8954 * $(document).ready( function() { |
|
8955 * $('#example').dataTable( { |
|
8956 * "sScrollY": "200px", |
|
8957 * "bPaginate": false |
|
8958 * } ); |
|
8959 * } ); |
|
8960 */ |
|
8961 "sScrollY": "", |
|
8962 |
|
8963 |
|
8964 /** |
|
8965 * Set the HTTP method that is used to make the Ajax call for server-side |
|
8966 * processing or Ajax sourced data. |
|
8967 * @type string |
|
8968 * @default GET |
|
8969 * @dtopt Options |
|
8970 * @dtopt Server-side |
|
8971 * |
|
8972 * @example |
|
8973 * $(document).ready( function() { |
|
8974 * $('#example').dataTable( { |
|
8975 * "bServerSide": true, |
|
8976 * "sAjaxSource": "scripts/post.php", |
|
8977 * "sServerMethod": "POST" |
|
8978 * } ); |
|
8979 * } ); |
|
8980 */ |
|
8981 "sServerMethod": "GET" |
|
8982 }; |
|
8983 |
|
8984 |
|
8985 /** |
|
8986 * Column options that can be given to DataTables at initialisation time. |
|
8987 * @namespace |
|
8988 */ |
|
8989 DataTable.defaults.columns = { |
|
8990 /** |
|
8991 * Allows a column's sorting to take multiple columns into account when |
|
8992 * doing a sort. For example first name / last name columns make sense to |
|
8993 * do a multi-column sort over the two columns. |
|
8994 * @type array |
|
8995 * @default null <i>Takes the value of the column index automatically</i> |
|
8996 * @dtopt Columns |
|
8997 * |
|
8998 * @example |
|
8999 * // Using aoColumnDefs |
|
9000 * $(document).ready( function() { |
|
9001 * $('#example').dataTable( { |
|
9002 * "aoColumnDefs": [ |
|
9003 * { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] }, |
|
9004 * { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] }, |
|
9005 * { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] } |
|
9006 * ] |
|
9007 * } ); |
|
9008 * } ); |
|
9009 * |
|
9010 * @example |
|
9011 * // Using aoColumns |
|
9012 * $(document).ready( function() { |
|
9013 * $('#example').dataTable( { |
|
9014 * "aoColumns": [ |
|
9015 * { "aDataSort": [ 0, 1 ] }, |
|
9016 * { "aDataSort": [ 1, 0 ] }, |
|
9017 * { "aDataSort": [ 2, 3, 4 ] }, |
|
9018 * null, |
|
9019 * null |
|
9020 * ] |
|
9021 * } ); |
|
9022 * } ); |
|
9023 */ |
|
9024 "aDataSort": null, |
|
9025 |
|
9026 |
|
9027 /** |
|
9028 * You can control the default sorting direction, and even alter the behaviour |
|
9029 * of the sort handler (i.e. only allow ascending sorting etc) using this |
|
9030 * parameter. |
|
9031 * @type array |
|
9032 * @default [ 'asc', 'desc' ] |
|
9033 * @dtopt Columns |
|
9034 * |
|
9035 * @example |
|
9036 * // Using aoColumnDefs |
|
9037 * $(document).ready( function() { |
|
9038 * $('#example').dataTable( { |
|
9039 * "aoColumnDefs": [ |
|
9040 * { "asSorting": [ "asc" ], "aTargets": [ 1 ] }, |
|
9041 * { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] }, |
|
9042 * { "asSorting": [ "desc" ], "aTargets": [ 3 ] } |
|
9043 * ] |
|
9044 * } ); |
|
9045 * } ); |
|
9046 * |
|
9047 * @example |
|
9048 * // Using aoColumns |
|
9049 * $(document).ready( function() { |
|
9050 * $('#example').dataTable( { |
|
9051 * "aoColumns": [ |
|
9052 * null, |
|
9053 * { "asSorting": [ "asc" ] }, |
|
9054 * { "asSorting": [ "desc", "asc", "asc" ] }, |
|
9055 * { "asSorting": [ "desc" ] }, |
|
9056 * null |
|
9057 * ] |
|
9058 * } ); |
|
9059 * } ); |
|
9060 */ |
|
9061 "asSorting": [ 'asc', 'desc' ], |
|
9062 |
|
9063 |
|
9064 /** |
|
9065 * Enable or disable filtering on the data in this column. |
|
9066 * @type boolean |
|
9067 * @default true |
|
9068 * @dtopt Columns |
|
9069 * |
|
9070 * @example |
|
9071 * // Using aoColumnDefs |
|
9072 * $(document).ready( function() { |
|
9073 * $('#example').dataTable( { |
|
9074 * "aoColumnDefs": [ |
|
9075 * { "bSearchable": false, "aTargets": [ 0 ] } |
|
9076 * ] } ); |
|
9077 * } ); |
|
9078 * |
|
9079 * @example |
|
9080 * // Using aoColumns |
|
9081 * $(document).ready( function() { |
|
9082 * $('#example').dataTable( { |
|
9083 * "aoColumns": [ |
|
9084 * { "bSearchable": false }, |
|
9085 * null, |
|
9086 * null, |
|
9087 * null, |
|
9088 * null |
|
9089 * ] } ); |
|
9090 * } ); |
|
9091 */ |
|
9092 "bSearchable": true, |
|
9093 |
|
9094 |
|
9095 /** |
|
9096 * Enable or disable sorting on this column. |
|
9097 * @type boolean |
|
9098 * @default true |
|
9099 * @dtopt Columns |
|
9100 * |
|
9101 * @example |
|
9102 * // Using aoColumnDefs |
|
9103 * $(document).ready( function() { |
|
9104 * $('#example').dataTable( { |
|
9105 * "aoColumnDefs": [ |
|
9106 * { "bSortable": false, "aTargets": [ 0 ] } |
|
9107 * ] } ); |
|
9108 * } ); |
|
9109 * |
|
9110 * @example |
|
9111 * // Using aoColumns |
|
9112 * $(document).ready( function() { |
|
9113 * $('#example').dataTable( { |
|
9114 * "aoColumns": [ |
|
9115 * { "bSortable": false }, |
|
9116 * null, |
|
9117 * null, |
|
9118 * null, |
|
9119 * null |
|
9120 * ] } ); |
|
9121 * } ); |
|
9122 */ |
|
9123 "bSortable": true, |
|
9124 |
|
9125 |
|
9126 /** |
|
9127 * <code>Deprecated</code> When using fnRender() for a column, you may wish |
|
9128 * to use the original data (before rendering) for sorting and filtering |
|
9129 * (the default is to used the rendered data that the user can see). This |
|
9130 * may be useful for dates etc. |
|
9131 * |
|
9132 * Please note that this option has now been deprecated and will be removed |
|
9133 * in the next version of DataTables. Please use mRender / mData rather than |
|
9134 * fnRender. |
|
9135 * @type boolean |
|
9136 * @default true |
|
9137 * @dtopt Columns |
|
9138 * @deprecated |
|
9139 */ |
|
9140 "bUseRendered": true, |
|
9141 |
|
9142 |
|
9143 /** |
|
9144 * Enable or disable the display of this column. |
|
9145 * @type boolean |
|
9146 * @default true |
|
9147 * @dtopt Columns |
|
9148 * |
|
9149 * @example |
|
9150 * // Using aoColumnDefs |
|
9151 * $(document).ready( function() { |
|
9152 * $('#example').dataTable( { |
|
9153 * "aoColumnDefs": [ |
|
9154 * { "bVisible": false, "aTargets": [ 0 ] } |
|
9155 * ] } ); |
|
9156 * } ); |
|
9157 * |
|
9158 * @example |
|
9159 * // Using aoColumns |
|
9160 * $(document).ready( function() { |
|
9161 * $('#example').dataTable( { |
|
9162 * "aoColumns": [ |
|
9163 * { "bVisible": false }, |
|
9164 * null, |
|
9165 * null, |
|
9166 * null, |
|
9167 * null |
|
9168 * ] } ); |
|
9169 * } ); |
|
9170 */ |
|
9171 "bVisible": true, |
|
9172 |
|
9173 |
|
9174 /** |
|
9175 * Developer definable function that is called whenever a cell is created (Ajax source, |
|
9176 * etc) or processed for input (DOM source). This can be used as a compliment to mRender |
|
9177 * allowing you to modify the DOM element (add background colour for example) when the |
|
9178 * element is available. |
|
9179 * @type function |
|
9180 * @param {element} nTd The TD node that has been created |
|
9181 * @param {*} sData The Data for the cell |
|
9182 * @param {array|object} oData The data for the whole row |
|
9183 * @param {int} iRow The row index for the aoData data store |
|
9184 * @param {int} iCol The column index for aoColumns |
|
9185 * @dtopt Columns |
|
9186 * |
|
9187 * @example |
|
9188 * $(document).ready( function() { |
|
9189 * $('#example').dataTable( { |
|
9190 * "aoColumnDefs": [ { |
|
9191 * "aTargets": [3], |
|
9192 * "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) { |
|
9193 * if ( sData == "1.7" ) { |
|
9194 * $(nTd).css('color', 'blue') |
|
9195 * } |
|
9196 * } |
|
9197 * } ] |
|
9198 * }); |
|
9199 * } ); |
|
9200 */ |
|
9201 "fnCreatedCell": null, |
|
9202 |
|
9203 |
|
9204 /** |
|
9205 * <code>Deprecated</code> Custom display function that will be called for the |
|
9206 * display of each cell in this column. |
|
9207 * |
|
9208 * Please note that this option has now been deprecated and will be removed |
|
9209 * in the next version of DataTables. Please use mRender / mData rather than |
|
9210 * fnRender. |
|
9211 * @type function |
|
9212 * @param {object} o Object with the following parameters: |
|
9213 * @param {int} o.iDataRow The row in aoData |
|
9214 * @param {int} o.iDataColumn The column in question |
|
9215 * @param {array} o.aData The data for the row in question |
|
9216 * @param {object} o.oSettings The settings object for this DataTables instance |
|
9217 * @param {object} o.mDataProp The data property used for this column |
|
9218 * @param {*} val The current cell value |
|
9219 * @returns {string} The string you which to use in the display |
|
9220 * @dtopt Columns |
|
9221 * @deprecated |
|
9222 */ |
|
9223 "fnRender": null, |
|
9224 |
|
9225 |
|
9226 /** |
|
9227 * The column index (starting from 0!) that you wish a sort to be performed |
|
9228 * upon when this column is selected for sorting. This can be used for sorting |
|
9229 * on hidden columns for example. |
|
9230 * @type int |
|
9231 * @default -1 <i>Use automatically calculated column index</i> |
|
9232 * @dtopt Columns |
|
9233 * |
|
9234 * @example |
|
9235 * // Using aoColumnDefs |
|
9236 * $(document).ready( function() { |
|
9237 * $('#example').dataTable( { |
|
9238 * "aoColumnDefs": [ |
|
9239 * { "iDataSort": 1, "aTargets": [ 0 ] } |
|
9240 * ] |
|
9241 * } ); |
|
9242 * } ); |
|
9243 * |
|
9244 * @example |
|
9245 * // Using aoColumns |
|
9246 * $(document).ready( function() { |
|
9247 * $('#example').dataTable( { |
|
9248 * "aoColumns": [ |
|
9249 * { "iDataSort": 1 }, |
|
9250 * null, |
|
9251 * null, |
|
9252 * null, |
|
9253 * null |
|
9254 * ] |
|
9255 * } ); |
|
9256 * } ); |
|
9257 */ |
|
9258 "iDataSort": -1, |
|
9259 |
|
9260 |
|
9261 /** |
|
9262 * This parameter has been replaced by mData in DataTables to ensure naming |
|
9263 * consistency. mDataProp can still be used, as there is backwards compatibility |
|
9264 * in DataTables for this option, but it is strongly recommended that you use |
|
9265 * mData in preference to mDataProp. |
|
9266 * @name DataTable.defaults.columns.mDataProp |
|
9267 */ |
|
9268 |
|
9269 |
|
9270 /** |
|
9271 * This property can be used to read data from any JSON data source property, |
|
9272 * including deeply nested objects / properties. mData can be given in a |
|
9273 * number of different ways which effect its behaviour: |
|
9274 * <ul> |
|
9275 * <li>integer - treated as an array index for the data source. This is the |
|
9276 * default that DataTables uses (incrementally increased for each column).</li> |
|
9277 * <li>string - read an object property from the data source. Note that you can |
|
9278 * use Javascript dotted notation to read deep properties / arrays from the |
|
9279 * data source.</li> |
|
9280 * <li>null - the sDefaultContent option will be used for the cell (null |
|
9281 * by default, so you will need to specify the default content you want - |
|
9282 * typically an empty string). This can be useful on generated columns such |
|
9283 * as edit / delete action columns.</li> |
|
9284 * <li>function - the function given will be executed whenever DataTables |
|
9285 * needs to set or get the data for a cell in the column. The function |
|
9286 * takes three parameters: |
|
9287 * <ul> |
|
9288 * <li>{array|object} The data source for the row</li> |
|
9289 * <li>{string} The type call data requested - this will be 'set' when |
|
9290 * setting data or 'filter', 'display', 'type', 'sort' or undefined when |
|
9291 * gathering data. Note that when <i>undefined</i> is given for the type |
|
9292 * DataTables expects to get the raw data for the object back</li> |
|
9293 * <li>{*} Data to set when the second parameter is 'set'.</li> |
|
9294 * </ul> |
|
9295 * The return value from the function is not required when 'set' is the type |
|
9296 * of call, but otherwise the return is what will be used for the data |
|
9297 * requested.</li> |
|
9298 * </ul> |
|
9299 * |
|
9300 * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change |
|
9301 * reflects the flexibility of this property and is consistent with the naming of |
|
9302 * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as |
|
9303 * it automatically maps the old name to the new if required. |
|
9304 * @type string|int|function|null |
|
9305 * @default null <i>Use automatically calculated column index</i> |
|
9306 * @dtopt Columns |
|
9307 * |
|
9308 * @example |
|
9309 * // Read table data from objects |
|
9310 * $(document).ready( function() { |
|
9311 * var oTable = $('#example').dataTable( { |
|
9312 * "sAjaxSource": "sources/deep.txt", |
|
9313 * "aoColumns": [ |
|
9314 * { "mData": "engine" }, |
|
9315 * { "mData": "browser" }, |
|
9316 * { "mData": "platform.inner" }, |
|
9317 * { "mData": "platform.details.0" }, |
|
9318 * { "mData": "platform.details.1" } |
|
9319 * ] |
|
9320 * } ); |
|
9321 * } ); |
|
9322 * |
|
9323 * @example |
|
9324 * // Using mData as a function to provide different information for |
|
9325 * // sorting, filtering and display. In this case, currency (price) |
|
9326 * $(document).ready( function() { |
|
9327 * var oTable = $('#example').dataTable( { |
|
9328 * "aoColumnDefs": [ { |
|
9329 * "aTargets": [ 0 ], |
|
9330 * "mData": function ( source, type, val ) { |
|
9331 * if (type === 'set') { |
|
9332 * source.price = val; |
|
9333 * // Store the computed dislay and filter values for efficiency |
|
9334 * source.price_display = val=="" ? "" : "$"+numberFormat(val); |
|
9335 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; |
|
9336 * return; |
|
9337 * } |
|
9338 * else if (type === 'display') { |
|
9339 * return source.price_display; |
|
9340 * } |
|
9341 * else if (type === 'filter') { |
|
9342 * return source.price_filter; |
|
9343 * } |
|
9344 * // 'sort', 'type' and undefined all just use the integer |
|
9345 * return source.price; |
|
9346 * } |
|
9347 * } ] |
|
9348 * } ); |
|
9349 * } ); |
|
9350 */ |
|
9351 "mData": null, |
|
9352 |
|
9353 |
|
9354 /** |
|
9355 * This property is the rendering partner to mData and it is suggested that |
|
9356 * when you want to manipulate data for display (including filtering, sorting etc) |
|
9357 * but not altering the underlying data for the table, use this property. mData |
|
9358 * can actually do everything this property can and more, but this parameter is |
|
9359 * easier to use since there is no 'set' option. Like mData is can be given |
|
9360 * in a number of different ways to effect its behaviour, with the addition of |
|
9361 * supporting array syntax for easy outputting of arrays (including arrays of |
|
9362 * objects): |
|
9363 * <ul> |
|
9364 * <li>integer - treated as an array index for the data source. This is the |
|
9365 * default that DataTables uses (incrementally increased for each column).</li> |
|
9366 * <li>string - read an object property from the data source. Note that you can |
|
9367 * use Javascript dotted notation to read deep properties / arrays from the |
|
9368 * data source and also array brackets to indicate that the data reader should |
|
9369 * loop over the data source array. When characters are given between the array |
|
9370 * brackets, these characters are used to join the data source array together. |
|
9371 * For example: "accounts[, ].name" would result in a comma separated list with |
|
9372 * the 'name' value from the 'accounts' array of objects.</li> |
|
9373 * <li>function - the function given will be executed whenever DataTables |
|
9374 * needs to set or get the data for a cell in the column. The function |
|
9375 * takes three parameters: |
|
9376 * <ul> |
|
9377 * <li>{array|object} The data source for the row (based on mData)</li> |
|
9378 * <li>{string} The type call data requested - this will be 'filter', 'display', |
|
9379 * 'type' or 'sort'.</li> |
|
9380 * <li>{array|object} The full data source for the row (not based on mData)</li> |
|
9381 * </ul> |
|
9382 * The return value from the function is what will be used for the data |
|
9383 * requested.</li> |
|
9384 * </ul> |
|
9385 * @type string|int|function|null |
|
9386 * @default null <i>Use mData</i> |
|
9387 * @dtopt Columns |
|
9388 * |
|
9389 * @example |
|
9390 * // Create a comma separated list from an array of objects |
|
9391 * $(document).ready( function() { |
|
9392 * var oTable = $('#example').dataTable( { |
|
9393 * "sAjaxSource": "sources/deep.txt", |
|
9394 * "aoColumns": [ |
|
9395 * { "mData": "engine" }, |
|
9396 * { "mData": "browser" }, |
|
9397 * { |
|
9398 * "mData": "platform", |
|
9399 * "mRender": "[, ].name" |
|
9400 * } |
|
9401 * ] |
|
9402 * } ); |
|
9403 * } ); |
|
9404 * |
|
9405 * @example |
|
9406 * // Use as a function to create a link from the data source |
|
9407 * $(document).ready( function() { |
|
9408 * var oTable = $('#example').dataTable( { |
|
9409 * "aoColumnDefs": [ |
|
9410 * { |
|
9411 * "aTargets": [ 0 ], |
|
9412 * "mData": "download_link", |
|
9413 * "mRender": function ( data, type, full ) { |
|
9414 * return '<a href="'+data+'">Download</a>'; |
|
9415 * } |
|
9416 * ] |
|
9417 * } ); |
|
9418 * } ); |
|
9419 */ |
|
9420 "mRender": null, |
|
9421 |
|
9422 |
|
9423 /** |
|
9424 * Change the cell type created for the column - either TD cells or TH cells. This |
|
9425 * can be useful as TH cells have semantic meaning in the table body, allowing them |
|
9426 * to act as a header for a row (you may wish to add scope='row' to the TH elements). |
|
9427 * @type string |
|
9428 * @default td |
|
9429 * @dtopt Columns |
|
9430 * |
|
9431 * @example |
|
9432 * // Make the first column use TH cells |
|
9433 * $(document).ready( function() { |
|
9434 * var oTable = $('#example').dataTable( { |
|
9435 * "aoColumnDefs": [ { |
|
9436 * "aTargets": [ 0 ], |
|
9437 * "sCellType": "th" |
|
9438 * } ] |
|
9439 * } ); |
|
9440 * } ); |
|
9441 */ |
|
9442 "sCellType": "td", |
|
9443 |
|
9444 |
|
9445 /** |
|
9446 * Class to give to each cell in this column. |
|
9447 * @type string |
|
9448 * @default <i>Empty string</i> |
|
9449 * @dtopt Columns |
|
9450 * |
|
9451 * @example |
|
9452 * // Using aoColumnDefs |
|
9453 * $(document).ready( function() { |
|
9454 * $('#example').dataTable( { |
|
9455 * "aoColumnDefs": [ |
|
9456 * { "sClass": "my_class", "aTargets": [ 0 ] } |
|
9457 * ] |
|
9458 * } ); |
|
9459 * } ); |
|
9460 * |
|
9461 * @example |
|
9462 * // Using aoColumns |
|
9463 * $(document).ready( function() { |
|
9464 * $('#example').dataTable( { |
|
9465 * "aoColumns": [ |
|
9466 * { "sClass": "my_class" }, |
|
9467 * null, |
|
9468 * null, |
|
9469 * null, |
|
9470 * null |
|
9471 * ] |
|
9472 * } ); |
|
9473 * } ); |
|
9474 */ |
|
9475 "sClass": "", |
|
9476 |
|
9477 /** |
|
9478 * When DataTables calculates the column widths to assign to each column, |
|
9479 * it finds the longest string in each column and then constructs a |
|
9480 * temporary table and reads the widths from that. The problem with this |
|
9481 * is that "mmm" is much wider then "iiii", but the latter is a longer |
|
9482 * string - thus the calculation can go wrong (doing it properly and putting |
|
9483 * it into an DOM object and measuring that is horribly(!) slow). Thus as |
|
9484 * a "work around" we provide this option. It will append its value to the |
|
9485 * text that is found to be the longest string for the column - i.e. padding. |
|
9486 * Generally you shouldn't need this, and it is not documented on the |
|
9487 * general DataTables.net documentation |
|
9488 * @type string |
|
9489 * @default <i>Empty string<i> |
|
9490 * @dtopt Columns |
|
9491 * |
|
9492 * @example |
|
9493 * // Using aoColumns |
|
9494 * $(document).ready( function() { |
|
9495 * $('#example').dataTable( { |
|
9496 * "aoColumns": [ |
|
9497 * null, |
|
9498 * null, |
|
9499 * null, |
|
9500 * { |
|
9501 * "sContentPadding": "mmm" |
|
9502 * } |
|
9503 * ] |
|
9504 * } ); |
|
9505 * } ); |
|
9506 */ |
|
9507 "sContentPadding": "", |
|
9508 |
|
9509 |
|
9510 /** |
|
9511 * Allows a default value to be given for a column's data, and will be used |
|
9512 * whenever a null data source is encountered (this can be because mData |
|
9513 * is set to null, or because the data source itself is null). |
|
9514 * @type string |
|
9515 * @default null |
|
9516 * @dtopt Columns |
|
9517 * |
|
9518 * @example |
|
9519 * // Using aoColumnDefs |
|
9520 * $(document).ready( function() { |
|
9521 * $('#example').dataTable( { |
|
9522 * "aoColumnDefs": [ |
|
9523 * { |
|
9524 * "mData": null, |
|
9525 * "sDefaultContent": "Edit", |
|
9526 * "aTargets": [ -1 ] |
|
9527 * } |
|
9528 * ] |
|
9529 * } ); |
|
9530 * } ); |
|
9531 * |
|
9532 * @example |
|
9533 * // Using aoColumns |
|
9534 * $(document).ready( function() { |
|
9535 * $('#example').dataTable( { |
|
9536 * "aoColumns": [ |
|
9537 * null, |
|
9538 * null, |
|
9539 * null, |
|
9540 * { |
|
9541 * "mData": null, |
|
9542 * "sDefaultContent": "Edit" |
|
9543 * } |
|
9544 * ] |
|
9545 * } ); |
|
9546 * } ); |
|
9547 */ |
|
9548 "sDefaultContent": null, |
|
9549 |
|
9550 |
|
9551 /** |
|
9552 * This parameter is only used in DataTables' server-side processing. It can |
|
9553 * be exceptionally useful to know what columns are being displayed on the |
|
9554 * client side, and to map these to database fields. When defined, the names |
|
9555 * also allow DataTables to reorder information from the server if it comes |
|
9556 * back in an unexpected order (i.e. if you switch your columns around on the |
|
9557 * client-side, your server-side code does not also need updating). |
|
9558 * @type string |
|
9559 * @default <i>Empty string</i> |
|
9560 * @dtopt Columns |
|
9561 * |
|
9562 * @example |
|
9563 * // Using aoColumnDefs |
|
9564 * $(document).ready( function() { |
|
9565 * $('#example').dataTable( { |
|
9566 * "aoColumnDefs": [ |
|
9567 * { "sName": "engine", "aTargets": [ 0 ] }, |
|
9568 * { "sName": "browser", "aTargets": [ 1 ] }, |
|
9569 * { "sName": "platform", "aTargets": [ 2 ] }, |
|
9570 * { "sName": "version", "aTargets": [ 3 ] }, |
|
9571 * { "sName": "grade", "aTargets": [ 4 ] } |
|
9572 * ] |
|
9573 * } ); |
|
9574 * } ); |
|
9575 * |
|
9576 * @example |
|
9577 * // Using aoColumns |
|
9578 * $(document).ready( function() { |
|
9579 * $('#example').dataTable( { |
|
9580 * "aoColumns": [ |
|
9581 * { "sName": "engine" }, |
|
9582 * { "sName": "browser" }, |
|
9583 * { "sName": "platform" }, |
|
9584 * { "sName": "version" }, |
|
9585 * { "sName": "grade" } |
|
9586 * ] |
|
9587 * } ); |
|
9588 * } ); |
|
9589 */ |
|
9590 "sName": "", |
|
9591 |
|
9592 |
|
9593 /** |
|
9594 * Defines a data source type for the sorting which can be used to read |
|
9595 * real-time information from the table (updating the internally cached |
|
9596 * version) prior to sorting. This allows sorting to occur on user editable |
|
9597 * elements such as form inputs. |
|
9598 * @type string |
|
9599 * @default std |
|
9600 * @dtopt Columns |
|
9601 * |
|
9602 * @example |
|
9603 * // Using aoColumnDefs |
|
9604 * $(document).ready( function() { |
|
9605 * $('#example').dataTable( { |
|
9606 * "aoColumnDefs": [ |
|
9607 * { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] }, |
|
9608 * { "sType": "numeric", "aTargets": [ 3 ] }, |
|
9609 * { "sSortDataType": "dom-select", "aTargets": [ 4 ] }, |
|
9610 * { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] } |
|
9611 * ] |
|
9612 * } ); |
|
9613 * } ); |
|
9614 * |
|
9615 * @example |
|
9616 * // Using aoColumns |
|
9617 * $(document).ready( function() { |
|
9618 * $('#example').dataTable( { |
|
9619 * "aoColumns": [ |
|
9620 * null, |
|
9621 * null, |
|
9622 * { "sSortDataType": "dom-text" }, |
|
9623 * { "sSortDataType": "dom-text", "sType": "numeric" }, |
|
9624 * { "sSortDataType": "dom-select" }, |
|
9625 * { "sSortDataType": "dom-checkbox" } |
|
9626 * ] |
|
9627 * } ); |
|
9628 * } ); |
|
9629 */ |
|
9630 "sSortDataType": "std", |
|
9631 |
|
9632 |
|
9633 /** |
|
9634 * The title of this column. |
|
9635 * @type string |
|
9636 * @default null <i>Derived from the 'TH' value for this column in the |
|
9637 * original HTML table.</i> |
|
9638 * @dtopt Columns |
|
9639 * |
|
9640 * @example |
|
9641 * // Using aoColumnDefs |
|
9642 * $(document).ready( function() { |
|
9643 * $('#example').dataTable( { |
|
9644 * "aoColumnDefs": [ |
|
9645 * { "sTitle": "My column title", "aTargets": [ 0 ] } |
|
9646 * ] |
|
9647 * } ); |
|
9648 * } ); |
|
9649 * |
|
9650 * @example |
|
9651 * // Using aoColumns |
|
9652 * $(document).ready( function() { |
|
9653 * $('#example').dataTable( { |
|
9654 * "aoColumns": [ |
|
9655 * { "sTitle": "My column title" }, |
|
9656 * null, |
|
9657 * null, |
|
9658 * null, |
|
9659 * null |
|
9660 * ] |
|
9661 * } ); |
|
9662 * } ); |
|
9663 */ |
|
9664 "sTitle": null, |
|
9665 |
|
9666 |
|
9667 /** |
|
9668 * The type allows you to specify how the data for this column will be sorted. |
|
9669 * Four types (string, numeric, date and html (which will strip HTML tags |
|
9670 * before sorting)) are currently available. Note that only date formats |
|
9671 * understood by Javascript's Date() object will be accepted as type date. For |
|
9672 * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric', |
|
9673 * 'date' or 'html' (by default). Further types can be adding through |
|
9674 * plug-ins. |
|
9675 * @type string |
|
9676 * @default null <i>Auto-detected from raw data</i> |
|
9677 * @dtopt Columns |
|
9678 * |
|
9679 * @example |
|
9680 * // Using aoColumnDefs |
|
9681 * $(document).ready( function() { |
|
9682 * $('#example').dataTable( { |
|
9683 * "aoColumnDefs": [ |
|
9684 * { "sType": "html", "aTargets": [ 0 ] } |
|
9685 * ] |
|
9686 * } ); |
|
9687 * } ); |
|
9688 * |
|
9689 * @example |
|
9690 * // Using aoColumns |
|
9691 * $(document).ready( function() { |
|
9692 * $('#example').dataTable( { |
|
9693 * "aoColumns": [ |
|
9694 * { "sType": "html" }, |
|
9695 * null, |
|
9696 * null, |
|
9697 * null, |
|
9698 * null |
|
9699 * ] |
|
9700 * } ); |
|
9701 * } ); |
|
9702 */ |
|
9703 "sType": null, |
|
9704 |
|
9705 |
|
9706 /** |
|
9707 * Defining the width of the column, this parameter may take any CSS value |
|
9708 * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not |
|
9709 * been given a specific width through this interface ensuring that the table |
|
9710 * remains readable. |
|
9711 * @type string |
|
9712 * @default null <i>Automatic</i> |
|
9713 * @dtopt Columns |
|
9714 * |
|
9715 * @example |
|
9716 * // Using aoColumnDefs |
|
9717 * $(document).ready( function() { |
|
9718 * $('#example').dataTable( { |
|
9719 * "aoColumnDefs": [ |
|
9720 * { "sWidth": "20%", "aTargets": [ 0 ] } |
|
9721 * ] |
|
9722 * } ); |
|
9723 * } ); |
|
9724 * |
|
9725 * @example |
|
9726 * // Using aoColumns |
|
9727 * $(document).ready( function() { |
|
9728 * $('#example').dataTable( { |
|
9729 * "aoColumns": [ |
|
9730 * { "sWidth": "20%" }, |
|
9731 * null, |
|
9732 * null, |
|
9733 * null, |
|
9734 * null |
|
9735 * ] |
|
9736 * } ); |
|
9737 * } ); |
|
9738 */ |
|
9739 "sWidth": null |
|
9740 }; |
|
9741 |
|
9742 |
|
9743 /** |
|
9744 * DataTables settings object - this holds all the information needed for a |
|
9745 * given table, including configuration, data and current application of the |
|
9746 * table options. DataTables does not have a single instance for each DataTable |
|
9747 * with the settings attached to that instance, but rather instances of the |
|
9748 * DataTable "class" are created on-the-fly as needed (typically by a |
|
9749 * $().dataTable() call) and the settings object is then applied to that |
|
9750 * instance. |
|
9751 * |
|
9752 * Note that this object is related to {@link DataTable.defaults} but this |
|
9753 * one is the internal data store for DataTables's cache of columns. It should |
|
9754 * NOT be manipulated outside of DataTables. Any configuration should be done |
|
9755 * through the initialisation options. |
|
9756 * @namespace |
|
9757 * @todo Really should attach the settings object to individual instances so we |
|
9758 * don't need to create new instances on each $().dataTable() call (if the |
|
9759 * table already exists). It would also save passing oSettings around and |
|
9760 * into every single function. However, this is a very significant |
|
9761 * architecture change for DataTables and will almost certainly break |
|
9762 * backwards compatibility with older installations. This is something that |
|
9763 * will be done in 2.0. |
|
9764 */ |
|
9765 DataTable.models.oSettings = { |
|
9766 /** |
|
9767 * Primary features of DataTables and their enablement state. |
|
9768 * @namespace |
|
9769 */ |
|
9770 "oFeatures": { |
|
9771 |
|
9772 /** |
|
9773 * Flag to say if DataTables should automatically try to calculate the |
|
9774 * optimum table and columns widths (true) or not (false). |
|
9775 * Note that this parameter will be set by the initialisation routine. To |
|
9776 * set a default use {@link DataTable.defaults}. |
|
9777 * @type boolean |
|
9778 */ |
|
9779 "bAutoWidth": null, |
|
9780 |
|
9781 /** |
|
9782 * Delay the creation of TR and TD elements until they are actually |
|
9783 * needed by a driven page draw. This can give a significant speed |
|
9784 * increase for Ajax source and Javascript source data, but makes no |
|
9785 * difference at all fro DOM and server-side processing tables. |
|
9786 * Note that this parameter will be set by the initialisation routine. To |
|
9787 * set a default use {@link DataTable.defaults}. |
|
9788 * @type boolean |
|
9789 */ |
|
9790 "bDeferRender": null, |
|
9791 |
|
9792 /** |
|
9793 * Enable filtering on the table or not. Note that if this is disabled |
|
9794 * then there is no filtering at all on the table, including fnFilter. |
|
9795 * To just remove the filtering input use sDom and remove the 'f' option. |
|
9796 * Note that this parameter will be set by the initialisation routine. To |
|
9797 * set a default use {@link DataTable.defaults}. |
|
9798 * @type boolean |
|
9799 */ |
|
9800 "bFilter": null, |
|
9801 |
|
9802 /** |
|
9803 * Table information element (the 'Showing x of y records' div) enable |
|
9804 * flag. |
|
9805 * Note that this parameter will be set by the initialisation routine. To |
|
9806 * set a default use {@link DataTable.defaults}. |
|
9807 * @type boolean |
|
9808 */ |
|
9809 "bInfo": null, |
|
9810 |
|
9811 /** |
|
9812 * Present a user control allowing the end user to change the page size |
|
9813 * when pagination is enabled. |
|
9814 * Note that this parameter will be set by the initialisation routine. To |
|
9815 * set a default use {@link DataTable.defaults}. |
|
9816 * @type boolean |
|
9817 */ |
|
9818 "bLengthChange": null, |
|
9819 |
|
9820 /** |
|
9821 * Pagination enabled or not. Note that if this is disabled then length |
|
9822 * changing must also be disabled. |
|
9823 * Note that this parameter will be set by the initialisation routine. To |
|
9824 * set a default use {@link DataTable.defaults}. |
|
9825 * @type boolean |
|
9826 */ |
|
9827 "bPaginate": null, |
|
9828 |
|
9829 /** |
|
9830 * Processing indicator enable flag whenever DataTables is enacting a |
|
9831 * user request - typically an Ajax request for server-side processing. |
|
9832 * Note that this parameter will be set by the initialisation routine. To |
|
9833 * set a default use {@link DataTable.defaults}. |
|
9834 * @type boolean |
|
9835 */ |
|
9836 "bProcessing": null, |
|
9837 |
|
9838 /** |
|
9839 * Server-side processing enabled flag - when enabled DataTables will |
|
9840 * get all data from the server for every draw - there is no filtering, |
|
9841 * sorting or paging done on the client-side. |
|
9842 * Note that this parameter will be set by the initialisation routine. To |
|
9843 * set a default use {@link DataTable.defaults}. |
|
9844 * @type boolean |
|
9845 */ |
|
9846 "bServerSide": null, |
|
9847 |
|
9848 /** |
|
9849 * Sorting enablement flag. |
|
9850 * Note that this parameter will be set by the initialisation routine. To |
|
9851 * set a default use {@link DataTable.defaults}. |
|
9852 * @type boolean |
|
9853 */ |
|
9854 "bSort": null, |
|
9855 |
|
9856 /** |
|
9857 * Apply a class to the columns which are being sorted to provide a |
|
9858 * visual highlight or not. This can slow things down when enabled since |
|
9859 * there is a lot of DOM interaction. |
|
9860 * Note that this parameter will be set by the initialisation routine. To |
|
9861 * set a default use {@link DataTable.defaults}. |
|
9862 * @type boolean |
|
9863 */ |
|
9864 "bSortClasses": null, |
|
9865 |
|
9866 /** |
|
9867 * State saving enablement flag. |
|
9868 * Note that this parameter will be set by the initialisation routine. To |
|
9869 * set a default use {@link DataTable.defaults}. |
|
9870 * @type boolean |
|
9871 */ |
|
9872 "bStateSave": null |
|
9873 }, |
|
9874 |
|
9875 |
|
9876 /** |
|
9877 * Scrolling settings for a table. |
|
9878 * @namespace |
|
9879 */ |
|
9880 "oScroll": { |
|
9881 /** |
|
9882 * Indicate if DataTables should be allowed to set the padding / margin |
|
9883 * etc for the scrolling header elements or not. Typically you will want |
|
9884 * this. |
|
9885 * Note that this parameter will be set by the initialisation routine. To |
|
9886 * set a default use {@link DataTable.defaults}. |
|
9887 * @type boolean |
|
9888 */ |
|
9889 "bAutoCss": null, |
|
9890 |
|
9891 /** |
|
9892 * When the table is shorter in height than sScrollY, collapse the |
|
9893 * table container down to the height of the table (when true). |
|
9894 * Note that this parameter will be set by the initialisation routine. To |
|
9895 * set a default use {@link DataTable.defaults}. |
|
9896 * @type boolean |
|
9897 */ |
|
9898 "bCollapse": null, |
|
9899 |
|
9900 /** |
|
9901 * Infinite scrolling enablement flag. Now deprecated in favour of |
|
9902 * using the Scroller plug-in. |
|
9903 * Note that this parameter will be set by the initialisation routine. To |
|
9904 * set a default use {@link DataTable.defaults}. |
|
9905 * @type boolean |
|
9906 */ |
|
9907 "bInfinite": null, |
|
9908 |
|
9909 /** |
|
9910 * Width of the scrollbar for the web-browser's platform. Calculated |
|
9911 * during table initialisation. |
|
9912 * @type int |
|
9913 * @default 0 |
|
9914 */ |
|
9915 "iBarWidth": 0, |
|
9916 |
|
9917 /** |
|
9918 * Space (in pixels) between the bottom of the scrolling container and |
|
9919 * the bottom of the scrolling viewport before the next page is loaded |
|
9920 * when using infinite scrolling. |
|
9921 * Note that this parameter will be set by the initialisation routine. To |
|
9922 * set a default use {@link DataTable.defaults}. |
|
9923 * @type int |
|
9924 */ |
|
9925 "iLoadGap": null, |
|
9926 |
|
9927 /** |
|
9928 * Viewport width for horizontal scrolling. Horizontal scrolling is |
|
9929 * disabled if an empty string. |
|
9930 * Note that this parameter will be set by the initialisation routine. To |
|
9931 * set a default use {@link DataTable.defaults}. |
|
9932 * @type string |
|
9933 */ |
|
9934 "sX": null, |
|
9935 |
|
9936 /** |
|
9937 * Width to expand the table to when using x-scrolling. Typically you |
|
9938 * should not need to use this. |
|
9939 * Note that this parameter will be set by the initialisation routine. To |
|
9940 * set a default use {@link DataTable.defaults}. |
|
9941 * @type string |
|
9942 * @deprecated |
|
9943 */ |
|
9944 "sXInner": null, |
|
9945 |
|
9946 /** |
|
9947 * Viewport height for vertical scrolling. Vertical scrolling is disabled |
|
9948 * if an empty string. |
|
9949 * Note that this parameter will be set by the initialisation routine. To |
|
9950 * set a default use {@link DataTable.defaults}. |
|
9951 * @type string |
|
9952 */ |
|
9953 "sY": null |
|
9954 }, |
|
9955 |
|
9956 /** |
|
9957 * Language information for the table. |
|
9958 * @namespace |
|
9959 * @extends DataTable.defaults.oLanguage |
|
9960 */ |
|
9961 "oLanguage": { |
|
9962 /** |
|
9963 * Information callback function. See |
|
9964 * {@link DataTable.defaults.fnInfoCallback} |
|
9965 * @type function |
|
9966 * @default null |
|
9967 */ |
|
9968 "fnInfoCallback": null |
|
9969 }, |
|
9970 |
|
9971 /** |
|
9972 * Browser support parameters |
|
9973 * @namespace |
|
9974 */ |
|
9975 "oBrowser": { |
|
9976 /** |
|
9977 * Indicate if the browser incorrectly calculates width:100% inside a |
|
9978 * scrolling element (IE6/7) |
|
9979 * @type boolean |
|
9980 * @default false |
|
9981 */ |
|
9982 "bScrollOversize": false |
|
9983 }, |
|
9984 |
|
9985 /** |
|
9986 * Array referencing the nodes which are used for the features. The |
|
9987 * parameters of this object match what is allowed by sDom - i.e. |
|
9988 * <ul> |
|
9989 * <li>'l' - Length changing</li> |
|
9990 * <li>'f' - Filtering input</li> |
|
9991 * <li>'t' - The table!</li> |
|
9992 * <li>'i' - Information</li> |
|
9993 * <li>'p' - Pagination</li> |
|
9994 * <li>'r' - pRocessing</li> |
|
9995 * </ul> |
|
9996 * @type array |
|
9997 * @default [] |
|
9998 */ |
|
9999 "aanFeatures": [], |
|
10000 |
|
10001 /** |
|
10002 * Store data information - see {@link DataTable.models.oRow} for detailed |
|
10003 * information. |
|
10004 * @type array |
|
10005 * @default [] |
|
10006 */ |
|
10007 "aoData": [], |
|
10008 |
|
10009 /** |
|
10010 * Array of indexes which are in the current display (after filtering etc) |
|
10011 * @type array |
|
10012 * @default [] |
|
10013 */ |
|
10014 "aiDisplay": [], |
|
10015 |
|
10016 /** |
|
10017 * Array of indexes for display - no filtering |
|
10018 * @type array |
|
10019 * @default [] |
|
10020 */ |
|
10021 "aiDisplayMaster": [], |
|
10022 |
|
10023 /** |
|
10024 * Store information about each column that is in use |
|
10025 * @type array |
|
10026 * @default [] |
|
10027 */ |
|
10028 "aoColumns": [], |
|
10029 |
|
10030 /** |
|
10031 * Store information about the table's header |
|
10032 * @type array |
|
10033 * @default [] |
|
10034 */ |
|
10035 "aoHeader": [], |
|
10036 |
|
10037 /** |
|
10038 * Store information about the table's footer |
|
10039 * @type array |
|
10040 * @default [] |
|
10041 */ |
|
10042 "aoFooter": [], |
|
10043 |
|
10044 /** |
|
10045 * Search data array for regular expression searching |
|
10046 * @type array |
|
10047 * @default [] |
|
10048 */ |
|
10049 "asDataSearch": [], |
|
10050 |
|
10051 /** |
|
10052 * Store the applied global search information in case we want to force a |
|
10053 * research or compare the old search to a new one. |
|
10054 * Note that this parameter will be set by the initialisation routine. To |
|
10055 * set a default use {@link DataTable.defaults}. |
|
10056 * @namespace |
|
10057 * @extends DataTable.models.oSearch |
|
10058 */ |
|
10059 "oPreviousSearch": {}, |
|
10060 |
|
10061 /** |
|
10062 * Store the applied search for each column - see |
|
10063 * {@link DataTable.models.oSearch} for the format that is used for the |
|
10064 * filtering information for each column. |
|
10065 * @type array |
|
10066 * @default [] |
|
10067 */ |
|
10068 "aoPreSearchCols": [], |
|
10069 |
|
10070 /** |
|
10071 * Sorting that is applied to the table. Note that the inner arrays are |
|
10072 * used in the following manner: |
|
10073 * <ul> |
|
10074 * <li>Index 0 - column number</li> |
|
10075 * <li>Index 1 - current sorting direction</li> |
|
10076 * <li>Index 2 - index of asSorting for this column</li> |
|
10077 * </ul> |
|
10078 * Note that this parameter will be set by the initialisation routine. To |
|
10079 * set a default use {@link DataTable.defaults}. |
|
10080 * @type array |
|
10081 * @todo These inner arrays should really be objects |
|
10082 */ |
|
10083 "aaSorting": null, |
|
10084 |
|
10085 /** |
|
10086 * Sorting that is always applied to the table (i.e. prefixed in front of |
|
10087 * aaSorting). |
|
10088 * Note that this parameter will be set by the initialisation routine. To |
|
10089 * set a default use {@link DataTable.defaults}. |
|
10090 * @type array|null |
|
10091 * @default null |
|
10092 */ |
|
10093 "aaSortingFixed": null, |
|
10094 |
|
10095 /** |
|
10096 * Classes to use for the striping of a table. |
|
10097 * Note that this parameter will be set by the initialisation routine. To |
|
10098 * set a default use {@link DataTable.defaults}. |
|
10099 * @type array |
|
10100 * @default [] |
|
10101 */ |
|
10102 "asStripeClasses": null, |
|
10103 |
|
10104 /** |
|
10105 * If restoring a table - we should restore its striping classes as well |
|
10106 * @type array |
|
10107 * @default [] |
|
10108 */ |
|
10109 "asDestroyStripes": [], |
|
10110 |
|
10111 /** |
|
10112 * If restoring a table - we should restore its width |
|
10113 * @type int |
|
10114 * @default 0 |
|
10115 */ |
|
10116 "sDestroyWidth": 0, |
|
10117 |
|
10118 /** |
|
10119 * Callback functions array for every time a row is inserted (i.e. on a draw). |
|
10120 * @type array |
|
10121 * @default [] |
|
10122 */ |
|
10123 "aoRowCallback": [], |
|
10124 |
|
10125 /** |
|
10126 * Callback functions for the header on each draw. |
|
10127 * @type array |
|
10128 * @default [] |
|
10129 */ |
|
10130 "aoHeaderCallback": [], |
|
10131 |
|
10132 /** |
|
10133 * Callback function for the footer on each draw. |
|
10134 * @type array |
|
10135 * @default [] |
|
10136 */ |
|
10137 "aoFooterCallback": [], |
|
10138 |
|
10139 /** |
|
10140 * Array of callback functions for draw callback functions |
|
10141 * @type array |
|
10142 * @default [] |
|
10143 */ |
|
10144 "aoDrawCallback": [], |
|
10145 |
|
10146 /** |
|
10147 * Array of callback functions for row created function |
|
10148 * @type array |
|
10149 * @default [] |
|
10150 */ |
|
10151 "aoRowCreatedCallback": [], |
|
10152 |
|
10153 /** |
|
10154 * Callback functions for just before the table is redrawn. A return of |
|
10155 * false will be used to cancel the draw. |
|
10156 * @type array |
|
10157 * @default [] |
|
10158 */ |
|
10159 "aoPreDrawCallback": [], |
|
10160 |
|
10161 /** |
|
10162 * Callback functions for when the table has been initialised. |
|
10163 * @type array |
|
10164 * @default [] |
|
10165 */ |
|
10166 "aoInitComplete": [], |
|
10167 |
|
10168 |
|
10169 /** |
|
10170 * Callbacks for modifying the settings to be stored for state saving, prior to |
|
10171 * saving state. |
|
10172 * @type array |
|
10173 * @default [] |
|
10174 */ |
|
10175 "aoStateSaveParams": [], |
|
10176 |
|
10177 /** |
|
10178 * Callbacks for modifying the settings that have been stored for state saving |
|
10179 * prior to using the stored values to restore the state. |
|
10180 * @type array |
|
10181 * @default [] |
|
10182 */ |
|
10183 "aoStateLoadParams": [], |
|
10184 |
|
10185 /** |
|
10186 * Callbacks for operating on the settings object once the saved state has been |
|
10187 * loaded |
|
10188 * @type array |
|
10189 * @default [] |
|
10190 */ |
|
10191 "aoStateLoaded": [], |
|
10192 |
|
10193 /** |
|
10194 * Cache the table ID for quick access |
|
10195 * @type string |
|
10196 * @default <i>Empty string</i> |
|
10197 */ |
|
10198 "sTableId": "", |
|
10199 |
|
10200 /** |
|
10201 * The TABLE node for the main table |
|
10202 * @type node |
|
10203 * @default null |
|
10204 */ |
|
10205 "nTable": null, |
|
10206 |
|
10207 /** |
|
10208 * Permanent ref to the thead element |
|
10209 * @type node |
|
10210 * @default null |
|
10211 */ |
|
10212 "nTHead": null, |
|
10213 |
|
10214 /** |
|
10215 * Permanent ref to the tfoot element - if it exists |
|
10216 * @type node |
|
10217 * @default null |
|
10218 */ |
|
10219 "nTFoot": null, |
|
10220 |
|
10221 /** |
|
10222 * Permanent ref to the tbody element |
|
10223 * @type node |
|
10224 * @default null |
|
10225 */ |
|
10226 "nTBody": null, |
|
10227 |
|
10228 /** |
|
10229 * Cache the wrapper node (contains all DataTables controlled elements) |
|
10230 * @type node |
|
10231 * @default null |
|
10232 */ |
|
10233 "nTableWrapper": null, |
|
10234 |
|
10235 /** |
|
10236 * Indicate if when using server-side processing the loading of data |
|
10237 * should be deferred until the second draw. |
|
10238 * Note that this parameter will be set by the initialisation routine. To |
|
10239 * set a default use {@link DataTable.defaults}. |
|
10240 * @type boolean |
|
10241 * @default false |
|
10242 */ |
|
10243 "bDeferLoading": false, |
|
10244 |
|
10245 /** |
|
10246 * Indicate if all required information has been read in |
|
10247 * @type boolean |
|
10248 * @default false |
|
10249 */ |
|
10250 "bInitialised": false, |
|
10251 |
|
10252 /** |
|
10253 * Information about open rows. Each object in the array has the parameters |
|
10254 * 'nTr' and 'nParent' |
|
10255 * @type array |
|
10256 * @default [] |
|
10257 */ |
|
10258 "aoOpenRows": [], |
|
10259 |
|
10260 /** |
|
10261 * Dictate the positioning of DataTables' control elements - see |
|
10262 * {@link DataTable.model.oInit.sDom}. |
|
10263 * Note that this parameter will be set by the initialisation routine. To |
|
10264 * set a default use {@link DataTable.defaults}. |
|
10265 * @type string |
|
10266 * @default null |
|
10267 */ |
|
10268 "sDom": null, |
|
10269 |
|
10270 /** |
|
10271 * Which type of pagination should be used. |
|
10272 * Note that this parameter will be set by the initialisation routine. To |
|
10273 * set a default use {@link DataTable.defaults}. |
|
10274 * @type string |
|
10275 * @default two_button |
|
10276 */ |
|
10277 "sPaginationType": "two_button", |
|
10278 |
|
10279 /** |
|
10280 * The cookie duration (for bStateSave) in seconds. |
|
10281 * Note that this parameter will be set by the initialisation routine. To |
|
10282 * set a default use {@link DataTable.defaults}. |
|
10283 * @type int |
|
10284 * @default 0 |
|
10285 */ |
|
10286 "iCookieDuration": 0, |
|
10287 |
|
10288 /** |
|
10289 * The cookie name prefix. |
|
10290 * Note that this parameter will be set by the initialisation routine. To |
|
10291 * set a default use {@link DataTable.defaults}. |
|
10292 * @type string |
|
10293 * @default <i>Empty string</i> |
|
10294 */ |
|
10295 "sCookiePrefix": "", |
|
10296 |
|
10297 /** |
|
10298 * Callback function for cookie creation. |
|
10299 * Note that this parameter will be set by the initialisation routine. To |
|
10300 * set a default use {@link DataTable.defaults}. |
|
10301 * @type function |
|
10302 * @default null |
|
10303 */ |
|
10304 "fnCookieCallback": null, |
|
10305 |
|
10306 /** |
|
10307 * Array of callback functions for state saving. Each array element is an |
|
10308 * object with the following parameters: |
|
10309 * <ul> |
|
10310 * <li>function:fn - function to call. Takes two parameters, oSettings |
|
10311 * and the JSON string to save that has been thus far created. Returns |
|
10312 * a JSON string to be inserted into a json object |
|
10313 * (i.e. '"param": [ 0, 1, 2]')</li> |
|
10314 * <li>string:sName - name of callback</li> |
|
10315 * </ul> |
|
10316 * @type array |
|
10317 * @default [] |
|
10318 */ |
|
10319 "aoStateSave": [], |
|
10320 |
|
10321 /** |
|
10322 * Array of callback functions for state loading. Each array element is an |
|
10323 * object with the following parameters: |
|
10324 * <ul> |
|
10325 * <li>function:fn - function to call. Takes two parameters, oSettings |
|
10326 * and the object stored. May return false to cancel state loading</li> |
|
10327 * <li>string:sName - name of callback</li> |
|
10328 * </ul> |
|
10329 * @type array |
|
10330 * @default [] |
|
10331 */ |
|
10332 "aoStateLoad": [], |
|
10333 |
|
10334 /** |
|
10335 * State that was loaded from the cookie. Useful for back reference |
|
10336 * @type object |
|
10337 * @default null |
|
10338 */ |
|
10339 "oLoadedState": null, |
|
10340 |
|
10341 /** |
|
10342 * Source url for AJAX data for the table. |
|
10343 * Note that this parameter will be set by the initialisation routine. To |
|
10344 * set a default use {@link DataTable.defaults}. |
|
10345 * @type string |
|
10346 * @default null |
|
10347 */ |
|
10348 "sAjaxSource": null, |
|
10349 |
|
10350 /** |
|
10351 * Property from a given object from which to read the table data from. This |
|
10352 * can be an empty string (when not server-side processing), in which case |
|
10353 * it is assumed an an array is given directly. |
|
10354 * Note that this parameter will be set by the initialisation routine. To |
|
10355 * set a default use {@link DataTable.defaults}. |
|
10356 * @type string |
|
10357 */ |
|
10358 "sAjaxDataProp": null, |
|
10359 |
|
10360 /** |
|
10361 * Note if draw should be blocked while getting data |
|
10362 * @type boolean |
|
10363 * @default true |
|
10364 */ |
|
10365 "bAjaxDataGet": true, |
|
10366 |
|
10367 /** |
|
10368 * The last jQuery XHR object that was used for server-side data gathering. |
|
10369 * This can be used for working with the XHR information in one of the |
|
10370 * callbacks |
|
10371 * @type object |
|
10372 * @default null |
|
10373 */ |
|
10374 "jqXHR": null, |
|
10375 |
|
10376 /** |
|
10377 * Function to get the server-side data. |
|
10378 * Note that this parameter will be set by the initialisation routine. To |
|
10379 * set a default use {@link DataTable.defaults}. |
|
10380 * @type function |
|
10381 */ |
|
10382 "fnServerData": null, |
|
10383 |
|
10384 /** |
|
10385 * Functions which are called prior to sending an Ajax request so extra |
|
10386 * parameters can easily be sent to the server |
|
10387 * @type array |
|
10388 * @default [] |
|
10389 */ |
|
10390 "aoServerParams": [], |
|
10391 |
|
10392 /** |
|
10393 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if |
|
10394 * required). |
|
10395 * Note that this parameter will be set by the initialisation routine. To |
|
10396 * set a default use {@link DataTable.defaults}. |
|
10397 * @type string |
|
10398 */ |
|
10399 "sServerMethod": null, |
|
10400 |
|
10401 /** |
|
10402 * Format numbers for display. |
|
10403 * Note that this parameter will be set by the initialisation routine. To |
|
10404 * set a default use {@link DataTable.defaults}. |
|
10405 * @type function |
|
10406 */ |
|
10407 "fnFormatNumber": null, |
|
10408 |
|
10409 /** |
|
10410 * List of options that can be used for the user selectable length menu. |
|
10411 * Note that this parameter will be set by the initialisation routine. To |
|
10412 * set a default use {@link DataTable.defaults}. |
|
10413 * @type array |
|
10414 * @default [] |
|
10415 */ |
|
10416 "aLengthMenu": null, |
|
10417 |
|
10418 /** |
|
10419 * Counter for the draws that the table does. Also used as a tracker for |
|
10420 * server-side processing |
|
10421 * @type int |
|
10422 * @default 0 |
|
10423 */ |
|
10424 "iDraw": 0, |
|
10425 |
|
10426 /** |
|
10427 * Indicate if a redraw is being done - useful for Ajax |
|
10428 * @type boolean |
|
10429 * @default false |
|
10430 */ |
|
10431 "bDrawing": false, |
|
10432 |
|
10433 /** |
|
10434 * Draw index (iDraw) of the last error when parsing the returned data |
|
10435 * @type int |
|
10436 * @default -1 |
|
10437 */ |
|
10438 "iDrawError": -1, |
|
10439 |
|
10440 /** |
|
10441 * Paging display length |
|
10442 * @type int |
|
10443 * @default 10 |
|
10444 */ |
|
10445 "_iDisplayLength": 10, |
|
10446 |
|
10447 /** |
|
10448 * Paging start point - aiDisplay index |
|
10449 * @type int |
|
10450 * @default 0 |
|
10451 */ |
|
10452 "_iDisplayStart": 0, |
|
10453 |
|
10454 /** |
|
10455 * Paging end point - aiDisplay index. Use fnDisplayEnd rather than |
|
10456 * this property to get the end point |
|
10457 * @type int |
|
10458 * @default 10 |
|
10459 * @private |
|
10460 */ |
|
10461 "_iDisplayEnd": 10, |
|
10462 |
|
10463 /** |
|
10464 * Server-side processing - number of records in the result set |
|
10465 * (i.e. before filtering), Use fnRecordsTotal rather than |
|
10466 * this property to get the value of the number of records, regardless of |
|
10467 * the server-side processing setting. |
|
10468 * @type int |
|
10469 * @default 0 |
|
10470 * @private |
|
10471 */ |
|
10472 "_iRecordsTotal": 0, |
|
10473 |
|
10474 /** |
|
10475 * Server-side processing - number of records in the current display set |
|
10476 * (i.e. after filtering). Use fnRecordsDisplay rather than |
|
10477 * this property to get the value of the number of records, regardless of |
|
10478 * the server-side processing setting. |
|
10479 * @type boolean |
|
10480 * @default 0 |
|
10481 * @private |
|
10482 */ |
|
10483 "_iRecordsDisplay": 0, |
|
10484 |
|
10485 /** |
|
10486 * Flag to indicate if jQuery UI marking and classes should be used. |
|
10487 * Note that this parameter will be set by the initialisation routine. To |
|
10488 * set a default use {@link DataTable.defaults}. |
|
10489 * @type boolean |
|
10490 */ |
|
10491 "bJUI": null, |
|
10492 |
|
10493 /** |
|
10494 * The classes to use for the table |
|
10495 * @type object |
|
10496 * @default {} |
|
10497 */ |
|
10498 "oClasses": {}, |
|
10499 |
|
10500 /** |
|
10501 * Flag attached to the settings object so you can check in the draw |
|
10502 * callback if filtering has been done in the draw. Deprecated in favour of |
|
10503 * events. |
|
10504 * @type boolean |
|
10505 * @default false |
|
10506 * @deprecated |
|
10507 */ |
|
10508 "bFiltered": false, |
|
10509 |
|
10510 /** |
|
10511 * Flag attached to the settings object so you can check in the draw |
|
10512 * callback if sorting has been done in the draw. Deprecated in favour of |
|
10513 * events. |
|
10514 * @type boolean |
|
10515 * @default false |
|
10516 * @deprecated |
|
10517 */ |
|
10518 "bSorted": false, |
|
10519 |
|
10520 /** |
|
10521 * Indicate that if multiple rows are in the header and there is more than |
|
10522 * one unique cell per column, if the top one (true) or bottom one (false) |
|
10523 * should be used for sorting / title by DataTables. |
|
10524 * Note that this parameter will be set by the initialisation routine. To |
|
10525 * set a default use {@link DataTable.defaults}. |
|
10526 * @type boolean |
|
10527 */ |
|
10528 "bSortCellsTop": null, |
|
10529 |
|
10530 /** |
|
10531 * Initialisation object that is used for the table |
|
10532 * @type object |
|
10533 * @default null |
|
10534 */ |
|
10535 "oInit": null, |
|
10536 |
|
10537 /** |
|
10538 * Destroy callback functions - for plug-ins to attach themselves to the |
|
10539 * destroy so they can clean up markup and events. |
|
10540 * @type array |
|
10541 * @default [] |
|
10542 */ |
|
10543 "aoDestroyCallback": [], |
|
10544 |
|
10545 |
|
10546 /** |
|
10547 * Get the number of records in the current record set, before filtering |
|
10548 * @type function |
|
10549 */ |
|
10550 "fnRecordsTotal": function () { |
|
10551 if (this.oFeatures.bServerSide) { |
|
10552 return parseInt(this._iRecordsTotal, 10); |
|
10553 } else { |
|
10554 return this.aiDisplayMaster.length; |
|
10555 } |
|
10556 }, |
|
10557 |
|
10558 /** |
|
10559 * Get the number of records in the current record set, after filtering |
|
10560 * @type function |
|
10561 */ |
|
10562 "fnRecordsDisplay": function () { |
|
10563 if (this.oFeatures.bServerSide) { |
|
10564 return parseInt(this._iRecordsDisplay, 10); |
|
10565 } else { |
|
10566 return this.aiDisplay.length; |
|
10567 } |
|
10568 }, |
|
10569 |
|
10570 /** |
|
10571 * Set the display end point - aiDisplay index |
|
10572 * @type function |
|
10573 * @todo Should do away with _iDisplayEnd and calculate it on-the-fly here |
|
10574 */ |
|
10575 "fnDisplayEnd": function () { |
|
10576 if (this.oFeatures.bServerSide) { |
|
10577 if (this.oFeatures.bPaginate === false || this._iDisplayLength == -1) { |
|
10578 return this._iDisplayStart + this.aiDisplay.length; |
|
10579 } else { |
|
10580 return Math.min(this._iDisplayStart + this._iDisplayLength, |
|
10581 this._iRecordsDisplay); |
|
10582 } |
|
10583 } else { |
|
10584 return this._iDisplayEnd; |
|
10585 } |
|
10586 }, |
|
10587 |
|
10588 /** |
|
10589 * The DataTables object for this table |
|
10590 * @type object |
|
10591 * @default null |
|
10592 */ |
|
10593 "oInstance": null, |
|
10594 |
|
10595 /** |
|
10596 * Unique identifier for each instance of the DataTables object. If there |
|
10597 * is an ID on the table node, then it takes that value, otherwise an |
|
10598 * incrementing internal counter is used. |
|
10599 * @type string |
|
10600 * @default null |
|
10601 */ |
|
10602 "sInstance": null, |
|
10603 |
|
10604 /** |
|
10605 * tabindex attribute value that is added to DataTables control elements, allowing |
|
10606 * keyboard navigation of the table and its controls. |
|
10607 */ |
|
10608 "iTabIndex": 0, |
|
10609 |
|
10610 /** |
|
10611 * DIV container for the footer scrolling table if scrolling |
|
10612 */ |
|
10613 "nScrollHead": null, |
|
10614 |
|
10615 /** |
|
10616 * DIV container for the footer scrolling table if scrolling |
|
10617 */ |
|
10618 "nScrollFoot": null |
|
10619 }; |
|
10620 |
|
10621 /** |
|
10622 * Extension object for DataTables that is used to provide all extension options. |
|
10623 * |
|
10624 * Note that the <i>DataTable.ext</i> object is available through |
|
10625 * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is |
|
10626 * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons. |
|
10627 * @namespace |
|
10628 * @extends DataTable.models.ext |
|
10629 */ |
|
10630 DataTable.ext = $.extend(true, {}, DataTable.models.ext); |
|
10631 |
|
10632 $.extend(DataTable.ext.oStdClasses, { |
|
10633 "sTable": "dataTable", |
|
10634 |
|
10635 /* Two buttons buttons */ |
|
10636 "sPagePrevEnabled": "paginate_enabled_previous", |
|
10637 "sPagePrevDisabled": "paginate_disabled_previous", |
|
10638 "sPageNextEnabled": "paginate_enabled_next", |
|
10639 "sPageNextDisabled": "paginate_disabled_next", |
|
10640 "sPageJUINext": "", |
|
10641 "sPageJUIPrev": "", |
|
10642 |
|
10643 /* Full numbers paging buttons */ |
|
10644 "sPageButton": "paginate_button", |
|
10645 "sPageButtonActive": "paginate_active", |
|
10646 "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled", |
|
10647 "sPageFirst": "first", |
|
10648 "sPagePrevious": "previous", |
|
10649 "sPageNext": "next", |
|
10650 "sPageLast": "last", |
|
10651 |
|
10652 /* Striping classes */ |
|
10653 "sStripeOdd": "odd", |
|
10654 "sStripeEven": "even", |
|
10655 |
|
10656 /* Empty row */ |
|
10657 "sRowEmpty": "dataTables_empty", |
|
10658 |
|
10659 /* Features */ |
|
10660 "sWrapper": "dataTables_wrapper", |
|
10661 "sFilter": "dataTables_filter", |
|
10662 "sInfo": "dataTables_info", |
|
10663 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ |
|
10664 "sLength": "dataTables_length", |
|
10665 "sProcessing": "dataTables_processing", |
|
10666 |
|
10667 /* Sorting */ |
|
10668 "sSortAsc": "sorting_asc", |
|
10669 "sSortDesc": "sorting_desc", |
|
10670 "sSortable": "sorting", /* Sortable in both directions */ |
|
10671 "sSortableAsc": "sorting_asc_disabled", |
|
10672 "sSortableDesc": "sorting_desc_disabled", |
|
10673 "sSortableNone": "sorting_disabled", |
|
10674 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ |
|
10675 "sSortJUIAsc": "", |
|
10676 "sSortJUIDesc": "", |
|
10677 "sSortJUI": "", |
|
10678 "sSortJUIAscAllowed": "", |
|
10679 "sSortJUIDescAllowed": "", |
|
10680 "sSortJUIWrapper": "", |
|
10681 "sSortIcon": "", |
|
10682 |
|
10683 /* Scrolling */ |
|
10684 "sScrollWrapper": "dataTables_scroll", |
|
10685 "sScrollHead": "dataTables_scrollHead", |
|
10686 "sScrollHeadInner": "dataTables_scrollHeadInner", |
|
10687 "sScrollBody": "dataTables_scrollBody", |
|
10688 "sScrollFoot": "dataTables_scrollFoot", |
|
10689 "sScrollFootInner": "dataTables_scrollFootInner", |
|
10690 |
|
10691 /* Misc */ |
|
10692 "sFooterTH": "", |
|
10693 "sJUIHeader": "", |
|
10694 "sJUIFooter": "" |
|
10695 }); |
|
10696 |
|
10697 |
|
10698 $.extend(DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, { |
|
10699 /* Two buttons buttons */ |
|
10700 "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left", |
|
10701 "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled", |
|
10702 "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right", |
|
10703 "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled", |
|
10704 "sPageJUINext": "ui-icon ui-icon-circle-arrow-e", |
|
10705 "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w", |
|
10706 |
|
10707 /* Full numbers paging buttons */ |
|
10708 "sPageButton": "fg-button ui-button ui-state-default", |
|
10709 "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled", |
|
10710 "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled", |
|
10711 "sPageFirst": "first ui-corner-tl ui-corner-bl", |
|
10712 "sPageLast": "last ui-corner-tr ui-corner-br", |
|
10713 |
|
10714 /* Features */ |
|
10715 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi " + |
|
10716 "ui-buttonset-multi paging_", /* Note that the type is postfixed */ |
|
10717 |
|
10718 /* Sorting */ |
|
10719 "sSortAsc": "ui-state-default", |
|
10720 "sSortDesc": "ui-state-default", |
|
10721 "sSortable": "ui-state-default", |
|
10722 "sSortableAsc": "ui-state-default", |
|
10723 "sSortableDesc": "ui-state-default", |
|
10724 "sSortableNone": "ui-state-default", |
|
10725 "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n", |
|
10726 "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s", |
|
10727 "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s", |
|
10728 "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n", |
|
10729 "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s", |
|
10730 "sSortJUIWrapper": "DataTables_sort_wrapper", |
|
10731 "sSortIcon": "DataTables_sort_icon", |
|
10732 |
|
10733 /* Scrolling */ |
|
10734 "sScrollHead": "dataTables_scrollHead ui-state-default", |
|
10735 "sScrollFoot": "dataTables_scrollFoot ui-state-default", |
|
10736 |
|
10737 /* Misc */ |
|
10738 "sFooterTH": "ui-state-default", |
|
10739 "sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix", |
|
10740 "sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix" |
|
10741 }); |
|
10742 |
|
10743 /* |
|
10744 * Variable: oPagination |
|
10745 * Purpose: |
|
10746 * Scope: jQuery.fn.dataTableExt |
|
10747 */ |
|
10748 $.extend(DataTable.ext.oPagination, { |
|
10749 /* |
|
10750 * Variable: two_button |
|
10751 * Purpose: Standard two button (forward/back) pagination |
|
10752 * Scope: jQuery.fn.dataTableExt.oPagination |
|
10753 */ |
|
10754 "two_button": { |
|
10755 /* |
|
10756 * Function: oPagination.two_button.fnInit |
|
10757 * Purpose: Initialise dom elements required for pagination with forward/back buttons only |
|
10758 * Returns: - |
|
10759 * Inputs: object:oSettings - dataTables settings object |
|
10760 * node:nPaging - the DIV which contains this pagination control |
|
10761 * function:fnCallbackDraw - draw function which must be called on update |
|
10762 */ |
|
10763 "fnInit": function (oSettings, nPaging, fnCallbackDraw) { |
|
10764 var oLang = oSettings.oLanguage.oPaginate; |
|
10765 var oClasses = oSettings.oClasses; |
|
10766 var fnClickHandler = function (e) { |
|
10767 if (oSettings.oApi._fnPageChange(oSettings, e.data.action)) { |
|
10768 fnCallbackDraw(oSettings); |
|
10769 } |
|
10770 }; |
|
10771 |
|
10772 var sAppend = (!oSettings.bJUI) ? |
|
10773 '<a class="' + oSettings.oClasses.sPagePrevDisabled + '" tabindex="' + oSettings.iTabIndex + '" role="button">' + oLang.sPrevious + '</a>' + |
|
10774 '<a class="' + oSettings.oClasses.sPageNextDisabled + '" tabindex="' + oSettings.iTabIndex + '" role="button">' + oLang.sNext + '</a>' |
|
10775 : |
|
10776 '<a class="' + oSettings.oClasses.sPagePrevDisabled + '" tabindex="' + oSettings.iTabIndex + '" role="button"><span class="' + oSettings.oClasses.sPageJUIPrev + '"></span></a>' + |
|
10777 '<a class="' + oSettings.oClasses.sPageNextDisabled + '" tabindex="' + oSettings.iTabIndex + '" role="button"><span class="' + oSettings.oClasses.sPageJUINext + '"></span></a>'; |
|
10778 $(nPaging).append(sAppend); |
|
10779 |
|
10780 var els = $('a', nPaging); |
|
10781 var nPrevious = els[0], |
|
10782 nNext = els[1]; |
|
10783 |
|
10784 oSettings.oApi._fnBindAction(nPrevious, {action: "previous"}, fnClickHandler); |
|
10785 oSettings.oApi._fnBindAction(nNext, {action: "next"}, fnClickHandler); |
|
10786 |
|
10787 /* ID the first elements only */ |
|
10788 if (!oSettings.aanFeatures.p) { |
|
10789 nPaging.id = oSettings.sTableId + '_paginate'; |
|
10790 nPrevious.id = oSettings.sTableId + '_previous'; |
|
10791 nNext.id = oSettings.sTableId + '_next'; |
|
10792 |
|
10793 nPrevious.setAttribute('aria-controls', oSettings.sTableId); |
|
10794 nNext.setAttribute('aria-controls', oSettings.sTableId); |
|
10795 } |
|
10796 }, |
|
10797 |
|
10798 /* |
|
10799 * Function: oPagination.two_button.fnUpdate |
|
10800 * Purpose: Update the two button pagination at the end of the draw |
|
10801 * Returns: - |
|
10802 * Inputs: object:oSettings - dataTables settings object |
|
10803 * function:fnCallbackDraw - draw function to call on page change |
|
10804 */ |
|
10805 "fnUpdate": function (oSettings, fnCallbackDraw) { |
|
10806 if (!oSettings.aanFeatures.p) { |
|
10807 return; |
|
10808 } |
|
10809 |
|
10810 var oClasses = oSettings.oClasses; |
|
10811 var an = oSettings.aanFeatures.p; |
|
10812 var nNode; |
|
10813 |
|
10814 /* Loop over each instance of the pager */ |
|
10815 for (var i = 0, iLen = an.length; i < iLen; i++) { |
|
10816 nNode = an[i].firstChild; |
|
10817 if (nNode) { |
|
10818 /* Previous page */ |
|
10819 nNode.className = ( oSettings._iDisplayStart === 0 ) ? |
|
10820 oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled; |
|
10821 |
|
10822 /* Next page */ |
|
10823 nNode = nNode.nextSibling; |
|
10824 nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ? |
|
10825 oClasses.sPageNextDisabled : oClasses.sPageNextEnabled; |
|
10826 } |
|
10827 } |
|
10828 } |
|
10829 }, |
|
10830 |
|
10831 |
|
10832 /* |
|
10833 * Variable: iFullNumbersShowPages |
|
10834 * Purpose: Change the number of pages which can be seen |
|
10835 * Scope: jQuery.fn.dataTableExt.oPagination |
|
10836 */ |
|
10837 "iFullNumbersShowPages": 5, |
|
10838 |
|
10839 /* |
|
10840 * Variable: full_numbers |
|
10841 * Purpose: Full numbers pagination |
|
10842 * Scope: jQuery.fn.dataTableExt.oPagination |
|
10843 */ |
|
10844 "full_numbers": { |
|
10845 /* |
|
10846 * Function: oPagination.full_numbers.fnInit |
|
10847 * Purpose: Initialise dom elements required for pagination with a list of the pages |
|
10848 * Returns: - |
|
10849 * Inputs: object:oSettings - dataTables settings object |
|
10850 * node:nPaging - the DIV which contains this pagination control |
|
10851 * function:fnCallbackDraw - draw function which must be called on update |
|
10852 */ |
|
10853 "fnInit": function (oSettings, nPaging, fnCallbackDraw) { |
|
10854 var oLang = oSettings.oLanguage.oPaginate; |
|
10855 var oClasses = oSettings.oClasses; |
|
10856 var fnClickHandler = function (e) { |
|
10857 if (oSettings.oApi._fnPageChange(oSettings, e.data.action)) { |
|
10858 fnCallbackDraw(oSettings); |
|
10859 } |
|
10860 }; |
|
10861 |
|
10862 $(nPaging).append( |
|
10863 '<a tabindex="' + oSettings.iTabIndex + '" class="' + oClasses.sPageButton + " " + oClasses.sPageFirst + '">' + oLang.sFirst + '</a>' + |
|
10864 '<a tabindex="' + oSettings.iTabIndex + '" class="' + oClasses.sPageButton + " " + oClasses.sPagePrevious + '">' + oLang.sPrevious + '</a>' + |
|
10865 '<span></span>' + |
|
10866 '<a tabindex="' + oSettings.iTabIndex + '" class="' + oClasses.sPageButton + " " + oClasses.sPageNext + '">' + oLang.sNext + '</a>' + |
|
10867 '<a tabindex="' + oSettings.iTabIndex + '" class="' + oClasses.sPageButton + " " + oClasses.sPageLast + '">' + oLang.sLast + '</a>' |
|
10868 ); |
|
10869 var els = $('a', nPaging); |
|
10870 var nFirst = els[0], |
|
10871 nPrev = els[1], |
|
10872 nNext = els[2], |
|
10873 nLast = els[3]; |
|
10874 |
|
10875 oSettings.oApi._fnBindAction(nFirst, {action: "first"}, fnClickHandler); |
|
10876 oSettings.oApi._fnBindAction(nPrev, {action: "previous"}, fnClickHandler); |
|
10877 oSettings.oApi._fnBindAction(nNext, {action: "next"}, fnClickHandler); |
|
10878 oSettings.oApi._fnBindAction(nLast, {action: "last"}, fnClickHandler); |
|
10879 |
|
10880 /* ID the first elements only */ |
|
10881 if (!oSettings.aanFeatures.p) { |
|
10882 nPaging.id = oSettings.sTableId + '_paginate'; |
|
10883 nFirst.id = oSettings.sTableId + '_first'; |
|
10884 nPrev.id = oSettings.sTableId + '_previous'; |
|
10885 nNext.id = oSettings.sTableId + '_next'; |
|
10886 nLast.id = oSettings.sTableId + '_last'; |
|
10887 } |
|
10888 }, |
|
10889 |
|
10890 /* |
|
10891 * Function: oPagination.full_numbers.fnUpdate |
|
10892 * Purpose: Update the list of page buttons shows |
|
10893 * Returns: - |
|
10894 * Inputs: object:oSettings - dataTables settings object |
|
10895 * function:fnCallbackDraw - draw function to call on page change |
|
10896 */ |
|
10897 "fnUpdate": function (oSettings, fnCallbackDraw) { |
|
10898 if (!oSettings.aanFeatures.p) { |
|
10899 return; |
|
10900 } |
|
10901 |
|
10902 var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages; |
|
10903 var iPageCountHalf = Math.floor(iPageCount / 2); |
|
10904 var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength); |
|
10905 var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1; |
|
10906 var sList = ""; |
|
10907 var iStartButton, iEndButton, i, iLen; |
|
10908 var oClasses = oSettings.oClasses; |
|
10909 var anButtons, anStatic, nPaginateList, nNode; |
|
10910 var an = oSettings.aanFeatures.p; |
|
10911 var fnBind = function (j) { |
|
10912 oSettings.oApi._fnBindAction(this, {"page": j + iStartButton - 1}, function (e) { |
|
10913 /* Use the information in the element to jump to the required page */ |
|
10914 oSettings.oApi._fnPageChange(oSettings, e.data.page); |
|
10915 fnCallbackDraw(oSettings); |
|
10916 e.preventDefault(); |
|
10917 }); |
|
10918 }; |
|
10919 |
|
10920 /* Pages calculation */ |
|
10921 if (oSettings._iDisplayLength === -1) { |
|
10922 iStartButton = 1; |
|
10923 iEndButton = 1; |
|
10924 iCurrentPage = 1; |
|
10925 } |
|
10926 else if (iPages < iPageCount) { |
|
10927 iStartButton = 1; |
|
10928 iEndButton = iPages; |
|
10929 } |
|
10930 else if (iCurrentPage <= iPageCountHalf) { |
|
10931 iStartButton = 1; |
|
10932 iEndButton = iPageCount; |
|
10933 } |
|
10934 else if (iCurrentPage >= (iPages - iPageCountHalf)) { |
|
10935 iStartButton = iPages - iPageCount + 1; |
|
10936 iEndButton = iPages; |
|
10937 } |
|
10938 else { |
|
10939 iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1; |
|
10940 iEndButton = iStartButton + iPageCount - 1; |
|
10941 } |
|
10942 |
|
10943 |
|
10944 /* Build the dynamic list */ |
|
10945 for (i = iStartButton; i <= iEndButton; i++) { |
|
10946 sList += (iCurrentPage !== i) ? |
|
10947 '<a tabindex="' + oSettings.iTabIndex + '" class="' + oClasses.sPageButton + '">' + oSettings.fnFormatNumber(i) + '</a>' : |
|
10948 '<a tabindex="' + oSettings.iTabIndex + '" class="' + oClasses.sPageButtonActive + '">' + oSettings.fnFormatNumber(i) + '</a>'; |
|
10949 } |
|
10950 |
|
10951 /* Loop over each instance of the pager */ |
|
10952 for (i = 0, iLen = an.length; i < iLen; i++) { |
|
10953 nNode = an[i]; |
|
10954 if (!nNode.hasChildNodes()) { |
|
10955 continue; |
|
10956 } |
|
10957 |
|
10958 /* Build up the dynamic list first - html and listeners */ |
|
10959 $('span:eq(0)', nNode) |
|
10960 .html(sList) |
|
10961 .children('a').each(fnBind); |
|
10962 |
|
10963 /* Update the permanent button's classes */ |
|
10964 anButtons = nNode.getElementsByTagName('a'); |
|
10965 anStatic = [ |
|
10966 anButtons[0], anButtons[1], |
|
10967 anButtons[anButtons.length - 2], anButtons[anButtons.length - 1] |
|
10968 ]; |
|
10969 |
|
10970 $(anStatic).removeClass(oClasses.sPageButton + " " + oClasses.sPageButtonActive + " " + oClasses.sPageButtonStaticDisabled); |
|
10971 $([anStatic[0], anStatic[1]]).addClass( |
|
10972 (iCurrentPage == 1) ? |
|
10973 oClasses.sPageButtonStaticDisabled : |
|
10974 oClasses.sPageButton |
|
10975 ); |
|
10976 $([anStatic[2], anStatic[3]]).addClass( |
|
10977 (iPages === 0 || iCurrentPage === iPages || oSettings._iDisplayLength === -1) ? |
|
10978 oClasses.sPageButtonStaticDisabled : |
|
10979 oClasses.sPageButton |
|
10980 ); |
|
10981 } |
|
10982 } |
|
10983 } |
|
10984 }); |
|
10985 |
|
10986 $.extend(DataTable.ext.oSort, { |
|
10987 /* |
|
10988 * text sorting |
|
10989 */ |
|
10990 "string-pre": function (a) { |
|
10991 if (typeof a != 'string') { |
|
10992 a = (a !== null && a.toString) ? a.toString() : ''; |
|
10993 } |
|
10994 return a.toLowerCase(); |
|
10995 }, |
|
10996 |
|
10997 "string-asc": function (x, y) { |
|
10998 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
|
10999 }, |
|
11000 |
|
11001 "string-desc": function (x, y) { |
|
11002 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
|
11003 }, |
|
11004 |
|
11005 |
|
11006 /* |
|
11007 * html sorting (ignore html tags) |
|
11008 */ |
|
11009 "html-pre": function (a) { |
|
11010 return a.replace(/<.*?>/g, "").toLowerCase(); |
|
11011 }, |
|
11012 |
|
11013 "html-asc": function (x, y) { |
|
11014 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
|
11015 }, |
|
11016 |
|
11017 "html-desc": function (x, y) { |
|
11018 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
|
11019 }, |
|
11020 |
|
11021 |
|
11022 /* |
|
11023 * date sorting |
|
11024 */ |
|
11025 "date-pre": function (a) { |
|
11026 var x = Date.parse(a); |
|
11027 |
|
11028 if (isNaN(x) || x === "") { |
|
11029 x = Date.parse("01/01/1970 00:00:00"); |
|
11030 } |
|
11031 return x; |
|
11032 }, |
|
11033 |
|
11034 "date-asc": function (x, y) { |
|
11035 return x - y; |
|
11036 }, |
|
11037 |
|
11038 "date-desc": function (x, y) { |
|
11039 return y - x; |
|
11040 }, |
|
11041 |
|
11042 |
|
11043 /* |
|
11044 * numerical sorting |
|
11045 */ |
|
11046 "numeric-pre": function (a) { |
|
11047 return (a == "-" || a === "") ? 0 : a * 1; |
|
11048 }, |
|
11049 |
|
11050 "numeric-asc": function (x, y) { |
|
11051 return x - y; |
|
11052 }, |
|
11053 |
|
11054 "numeric-desc": function (x, y) { |
|
11055 return y - x; |
|
11056 } |
|
11057 }); |
|
11058 |
|
11059 |
|
11060 $.extend(DataTable.ext.aTypes, [ |
|
11061 /* |
|
11062 * Function: - |
|
11063 * Purpose: Check to see if a string is numeric |
|
11064 * Returns: string:'numeric' or null |
|
11065 * Inputs: mixed:sText - string to check |
|
11066 */ |
|
11067 function (sData) { |
|
11068 /* Allow zero length strings as a number */ |
|
11069 if (typeof sData === 'number') { |
|
11070 return 'numeric'; |
|
11071 } |
|
11072 else if (typeof sData !== 'string') { |
|
11073 return null; |
|
11074 } |
|
11075 |
|
11076 var sValidFirstChars = "0123456789-"; |
|
11077 var sValidChars = "0123456789."; |
|
11078 var Char; |
|
11079 var bDecimal = false; |
|
11080 |
|
11081 /* Check for a valid first char (no period and allow negatives) */ |
|
11082 Char = sData.charAt(0); |
|
11083 if (sValidFirstChars.indexOf(Char) == -1) { |
|
11084 return null; |
|
11085 } |
|
11086 |
|
11087 /* Check all the other characters are valid */ |
|
11088 for (var i = 1; i < sData.length; i++) { |
|
11089 Char = sData.charAt(i); |
|
11090 if (sValidChars.indexOf(Char) == -1) { |
|
11091 return null; |
|
11092 } |
|
11093 |
|
11094 /* Only allowed one decimal place... */ |
|
11095 if (Char == ".") { |
|
11096 if (bDecimal) { |
|
11097 return null; |
|
11098 } |
|
11099 bDecimal = true; |
|
11100 } |
|
11101 } |
|
11102 |
|
11103 return 'numeric'; |
|
11104 }, |
|
11105 |
|
11106 /* |
|
11107 * Function: - |
|
11108 * Purpose: Check to see if a string is actually a formatted date |
|
11109 * Returns: string:'date' or null |
|
11110 * Inputs: string:sText - string to check |
|
11111 */ |
|
11112 function (sData) { |
|
11113 var iParse = Date.parse(sData); |
|
11114 if ((iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0)) { |
|
11115 return 'date'; |
|
11116 } |
|
11117 return null; |
|
11118 }, |
|
11119 |
|
11120 /* |
|
11121 * Function: - |
|
11122 * Purpose: Check to see if a string should be treated as an HTML string |
|
11123 * Returns: string:'html' or null |
|
11124 * Inputs: string:sText - string to check |
|
11125 */ |
|
11126 function (sData) { |
|
11127 if (typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1) { |
|
11128 return 'html'; |
|
11129 } |
|
11130 return null; |
|
11131 } |
|
11132 ]); |
|
11133 |
|
11134 |
|
11135 // jQuery aliases |
|
11136 $.fn.DataTable = DataTable; |
|
11137 $.fn.dataTable = DataTable; |
|
11138 $.fn.dataTableSettings = DataTable.settings; |
|
11139 $.fn.dataTableExt = DataTable.ext; |
|
11140 |
|
11141 |
|
11142 // Information about events fired by DataTables - for documentation. |
|
11143 /** |
|
11144 * Draw event, fired whenever the table is redrawn on the page, at the same point as |
|
11145 * fnDrawCallback. This may be useful for binding events or performing calculations when |
|
11146 * the table is altered at all. |
|
11147 * @name DataTable#draw |
|
11148 * @event |
|
11149 * @param {event} e jQuery event object |
|
11150 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} |
|
11151 */ |
|
11152 |
|
11153 /** |
|
11154 * Filter event, fired when the filtering applied to the table (using the build in global |
|
11155 * global filter, or column filters) is altered. |
|
11156 * @name DataTable#filter |
|
11157 * @event |
|
11158 * @param {event} e jQuery event object |
|
11159 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} |
|
11160 */ |
|
11161 |
|
11162 /** |
|
11163 * Page change event, fired when the paging of the table is altered. |
|
11164 * @name DataTable#page |
|
11165 * @event |
|
11166 * @param {event} e jQuery event object |
|
11167 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} |
|
11168 */ |
|
11169 |
|
11170 /** |
|
11171 * Sort event, fired when the sorting applied to the table is altered. |
|
11172 * @name DataTable#sort |
|
11173 * @event |
|
11174 * @param {event} e jQuery event object |
|
11175 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} |
|
11176 */ |
|
11177 |
|
11178 /** |
|
11179 * DataTables initialisation complete event, fired when the table is fully drawn, |
|
11180 * including Ajax data loaded, if Ajax data is required. |
|
11181 * @name DataTable#init |
|
11182 * @event |
|
11183 * @param {event} e jQuery event object |
|
11184 * @param {object} oSettings DataTables settings object |
|
11185 * @param {object} json The JSON object request from the server - only |
|
11186 * present if client-side Ajax sourced data is used</li></ol> |
|
11187 */ |
|
11188 |
|
11189 /** |
|
11190 * State save event, fired when the table has changed state a new state save is required. |
|
11191 * This method allows modification of the state saving object prior to actually doing the |
|
11192 * save, including addition or other state properties (for plug-ins) or modification |
|
11193 * of a DataTables core property. |
|
11194 * @name DataTable#stateSaveParams |
|
11195 * @event |
|
11196 * @param {event} e jQuery event object |
|
11197 * @param {object} oSettings DataTables settings object |
|
11198 * @param {object} json The state information to be saved |
|
11199 */ |
|
11200 |
|
11201 /** |
|
11202 * State load event, fired when the table is loading state from the stored data, but |
|
11203 * prior to the settings object being modified by the saved state - allowing modification |
|
11204 * of the saved state is required or loading of state for a plug-in. |
|
11205 * @name DataTable#stateLoadParams |
|
11206 * @event |
|
11207 * @param {event} e jQuery event object |
|
11208 * @param {object} oSettings DataTables settings object |
|
11209 * @param {object} json The saved state information |
|
11210 */ |
|
11211 |
|
11212 /** |
|
11213 * State loaded event, fired when state has been loaded from stored data and the settings |
|
11214 * object has been modified by the loaded data. |
|
11215 * @name DataTable#stateLoaded |
|
11216 * @event |
|
11217 * @param {event} e jQuery event object |
|
11218 * @param {object} oSettings DataTables settings object |
|
11219 * @param {object} json The saved state information |
|
11220 */ |
|
11221 |
|
11222 /** |
|
11223 * Processing event, fired when DataTables is doing some kind of processing (be it, |
|
11224 * sort, filter or anything else). Can be used to indicate to the end user that |
|
11225 * there is something happening, or that something has finished. |
|
11226 * @name DataTable#processing |
|
11227 * @event |
|
11228 * @param {event} e jQuery event object |
|
11229 * @param {object} oSettings DataTables settings object |
|
11230 * @param {boolean} bShow Flag for if DataTables is doing processing or not |
|
11231 */ |
|
11232 |
|
11233 /** |
|
11234 * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to |
|
11235 * made to the server for new data (note that this trigger is called in fnServerData, |
|
11236 * if you override fnServerData and which to use this event, you need to trigger it in |
|
11237 * you success function). |
|
11238 * @name DataTable#xhr |
|
11239 * @event |
|
11240 * @param {event} e jQuery event object |
|
11241 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} |
|
11242 * @param {object} json JSON returned from the server |
|
11243 */ |
|
11244 |
|
11245 /** |
|
11246 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing |
|
11247 * the bDestroy:true parameter in the initialisation object. This can be used to remove |
|
11248 * bound events, added DOM nodes, etc. |
|
11249 * @name DataTable#destroy |
|
11250 * @event |
|
11251 * @param {event} e jQuery event object |
|
11252 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} |
|
11253 */ |
|
11254 })(jQuery); |
|