Wordfence Security – Firewall & Malware Scan - Version 6.3.18

Version Description

Download this release

Release Info

Developer wfryan
Plugin Icon 128x128 Wordfence Security – Firewall & Malware Scan
Version 6.3.18
Comparing to
See all releases

Code changes from version 6.3.17 to 6.3.18

js/jquery.dataTables.js DELETED
@@ -1,15321 +0,0 @@
1
- /*
2
- * This combined file was created by the WFDataTables downloader builder:
3
- * https://datatables.net/download
4
- *
5
- * To rebuild or modify this file with the latest versions of the included
6
- * software please visit:
7
- * https://datatables.net/download/#dt/dt-1.10.13
8
- *
9
- * Included libraries:
10
- * WFDataTables 1.10.13
11
- */
12
-
13
- /*! WFDataTables 1.10.13
14
- * ©2008-2016 SpryMedia Ltd - datatables.net/license
15
- */
16
-
17
- /**
18
- * @summary WFDataTables
19
- * @description Paginate, search and order HTML tables
20
- * @version 1.10.13
21
- * @file jquery.wfDataTables.js
22
- * @author SpryMedia Ltd
23
- * @contact www.datatables.net
24
- * @copyright Copyright 2008-2016 SpryMedia Ltd.
25
- *
26
- * This source file is free software, available under the following license:
27
- * MIT license - http://datatables.net/license
28
- *
29
- * This source file is distributed in the hope that it will be useful, but
30
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31
- * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
32
- *
33
- * For details please refer to: http://www.datatables.net
34
- */
35
-
36
- /*jslint evil: true, undef: true, browser: true */
37
- /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
38
-
39
- (function( factory ) {
40
- "use strict";
41
-
42
- if ( typeof define === 'function' && define.amd ) {
43
- // AMD
44
- define( ['jquery'], function ( $ ) {
45
- return factory( $, window, document );
46
- } );
47
- }
48
- else if ( typeof exports === 'object' ) {
49
- // CommonJS
50
- module.exports = function (root, $) {
51
- if ( ! root ) {
52
- // CommonJS environments without a window global must pass a
53
- // root. This will give an error otherwise
54
- root = window;
55
- }
56
-
57
- if ( ! $ ) {
58
- $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
59
- require('jquery') :
60
- require('jquery')( root );
61
- }
62
-
63
- return factory( $, root, root.document );
64
- };
65
- }
66
- else {
67
- // Browser
68
- factory( jQuery, window, document );
69
- }
70
- }
71
- (function( $, window, document, undefined ) {
72
- "use strict";
73
-
74
- /**
75
- * WFDataTables is a plug-in for the jQuery Javascript library. It is a highly
76
- * flexible tool, based upon the foundations of progressive enhancement,
77
- * which will add advanced interaction controls to any HTML table. For a
78
- * full list of features please refer to
79
- * [WFDataTables.net](href="http://datatables.net).
80
- *
81
- * Note that the `WFDataTable` object is not a global variable but is aliased
82
- * to `jQuery.fn.WFDataTable` and `jQuery.fn.wfDataTable` through which it may
83
- * be accessed.
84
- *
85
- * @class
86
- * @param {object} [init={}] Configuration object for WFDataTables. Options
87
- * are defined by {@link WFDataTable.defaults}
88
- * @requires jQuery 1.7+
89
- *
90
- * @example
91
- * // Basic initialisation
92
- * $(document).ready( function {
93
- * $('#example').wfDataTable();
94
- * } );
95
- *
96
- * @example
97
- * // Initialisation with configuration options - in this case, disable
98
- * // pagination and sorting.
99
- * $(document).ready( function {
100
- * $('#example').wfDataTable( {
101
- * "paginate": false,
102
- * "sort": false
103
- * } );
104
- * } );
105
- */
106
- var WFDataTable = function ( options )
107
- {
108
- /**
109
- * Perform a jQuery selector action on the table's TR elements (from the tbody) and
110
- * return the resulting jQuery object.
111
- * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
112
- * @param {object} [oOpts] Optional parameters for modifying the rows to be included
113
- * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
114
- * criterion ("applied") or all TR elements (i.e. no filter).
115
- * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
116
- * Can be either 'current', whereby the current sorting of the table is used, or
117
- * 'original' whereby the original order the data was read into the table is used.
118
- * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
119
- * ("current") or not ("all"). If 'current' is given, then order is assumed to be
120
- * 'current' and filter is 'applied', regardless of what they might be given as.
121
- * @returns {object} jQuery object, filtered by the given selector.
122
- * @dtopt API
123
- * @deprecated Since v1.10
124
- *
125
- * @example
126
- * $(document).ready(function() {
127
- * var oTable = $('#example').wfDataTable();
128
- *
129
- * // Highlight every second row
130
- * oTable.$('tr:odd').css('backgroundColor', 'blue');
131
- * } );
132
- *
133
- * @example
134
- * $(document).ready(function() {
135
- * var oTable = $('#example').wfDataTable();
136
- *
137
- * // Filter to rows with 'Webkit' in them, add a background colour and then
138
- * // remove the filter, thus highlighting the 'Webkit' rows only.
139
- * oTable.fnFilter('Webkit');
140
- * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
141
- * oTable.fnFilter('');
142
- * } );
143
- */
144
- this.$ = function ( sSelector, oOpts )
145
- {
146
- return this.api(true).$( sSelector, oOpts );
147
- };
148
-
149
-
150
- /**
151
- * Almost identical to $ in operation, but in this case returns the data for the matched
152
- * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
153
- * rather than any descendants, so the data can be obtained for the row/cell. If matching
154
- * rows are found, the data returned is the original data array/object that was used to
155
- * create the row (or a generated array if from a DOM source).
156
- *
157
- * This method is often useful in-combination with $ where both functions are given the
158
- * same parameters and the array indexes will match identically.
159
- * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
160
- * @param {object} [oOpts] Optional parameters for modifying the rows to be included
161
- * @param {string} [oOpts.filter=none] Select elements that meet the current filter
162
- * criterion ("applied") or all elements (i.e. no filter).
163
- * @param {string} [oOpts.order=current] Order of the data in the processed array.
164
- * Can be either 'current', whereby the current sorting of the table is used, or
165
- * 'original' whereby the original order the data was read into the table is used.
166
- * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
167
- * ("current") or not ("all"). If 'current' is given, then order is assumed to be
168
- * 'current' and filter is 'applied', regardless of what they might be given as.
169
- * @returns {array} Data for the matched elements. If any elements, as a result of the
170
- * selector, were not TR, TD or TH elements in the WFDataTable, they will have a null
171
- * entry in the array.
172
- * @dtopt API
173
- * @deprecated Since v1.10
174
- *
175
- * @example
176
- * $(document).ready(function() {
177
- * var oTable = $('#example').wfDataTable();
178
- *
179
- * // Get the data from the first row in the table
180
- * var data = oTable._('tr:first');
181
- *
182
- * // Do something useful with the data
183
- * alert( "First cell is: "+data[0] );
184
- * } );
185
- *
186
- * @example
187
- * $(document).ready(function() {
188
- * var oTable = $('#example').wfDataTable();
189
- *
190
- * // Filter to 'Webkit' and get all data for
191
- * oTable.fnFilter('Webkit');
192
- * var data = oTable._('tr', {"search": "applied"});
193
- *
194
- * // Do something with the data
195
- * alert( data.length+" rows matched the search" );
196
- * } );
197
- */
198
- this._ = function ( sSelector, oOpts )
199
- {
200
- return this.api(true).rows( sSelector, oOpts ).data();
201
- };
202
-
203
-
204
- /**
205
- * Create a WFDataTables Api instance, with the currently selected tables for
206
- * the Api's context.
207
- * @param {boolean} [traditional=false] Set the API instance's context to be
208
- * only the table referred to by the `WFDataTable.ext.iApiIndex` option, as was
209
- * used in the API presented by WFDataTables 1.9- (i.e. the traditional mode),
210
- * or if all tables captured in the jQuery object should be used.
211
- * @return {WFDataTables.Api}
212
- */
213
- this.api = function ( traditional )
214
- {
215
- return traditional ?
216
- new _Api(
217
- _fnSettingsFromNode( this[ _ext.iApiIndex ] )
218
- ) :
219
- new _Api( this );
220
- };
221
-
222
-
223
- /**
224
- * Add a single new row or multiple rows of data to the table. Please note
225
- * that this is suitable for client-side processing only - if you are using
226
- * server-side processing (i.e. "bServerSide": true), then to add data, you
227
- * must add it to the data source, i.e. the server-side, through an Ajax call.
228
- * @param {array|object} data The data to be added to the table. This can be:
229
- * <ul>
230
- * <li>1D array of data - add a single row with the data provided</li>
231
- * <li>2D array of arrays - add multiple rows in a single call</li>
232
- * <li>object - data object when using <i>mData</i></li>
233
- * <li>array of objects - multiple data objects when using <i>mData</i></li>
234
- * </ul>
235
- * @param {bool} [redraw=true] redraw the table or not
236
- * @returns {array} An array of integers, representing the list of indexes in
237
- * <i>aoData</i> ({@link WFDataTable.models.oSettings}) that have been added to
238
- * the table.
239
- * @dtopt API
240
- * @deprecated Since v1.10
241
- *
242
- * @example
243
- * // Global var for counter
244
- * var giCount = 2;
245
- *
246
- * $(document).ready(function() {
247
- * $('#example').wfDataTable();
248
- * } );
249
- *
250
- * function fnClickAddRow() {
251
- * $('#example').wfDataTable().fnAddData( [
252
- * giCount+".1",
253
- * giCount+".2",
254
- * giCount+".3",
255
- * giCount+".4" ]
256
- * );
257
- *
258
- * giCount++;
259
- * }
260
- */
261
- this.fnAddData = function( data, redraw )
262
- {
263
- var api = this.api( true );
264
-
265
- /* Check if we want to add multiple rows or not */
266
- var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
267
- api.rows.add( data ) :
268
- api.row.add( data );
269
-
270
- if ( redraw === undefined || redraw ) {
271
- api.draw();
272
- }
273
-
274
- return rows.flatten().toArray();
275
- };
276
-
277
-
278
- /**
279
- * This function will make WFDataTables recalculate the column sizes, based on the data
280
- * contained in the table and the sizes applied to the columns (in the DOM, CSS or
281
- * through the sWidth parameter). This can be useful when the width of the table's
282
- * parent element changes (for example a window resize).
283
- * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
284
- * @dtopt API
285
- * @deprecated Since v1.10
286
- *
287
- * @example
288
- * $(document).ready(function() {
289
- * var oTable = $('#example').wfDataTable( {
290
- * "sScrollY": "200px",
291
- * "bPaginate": false
292
- * } );
293
- *
294
- * $(window).on('resize', function () {
295
- * oTable.fnAdjustColumnSizing();
296
- * } );
297
- * } );
298
- */
299
- this.fnAdjustColumnSizing = function ( bRedraw )
300
- {
301
- var api = this.api( true ).columns.adjust();
302
- var settings = api.settings()[0];
303
- var scroll = settings.oScroll;
304
-
305
- if ( bRedraw === undefined || bRedraw ) {
306
- api.draw( false );
307
- }
308
- else if ( scroll.sX !== "" || scroll.sY !== "" ) {
309
- /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
310
- _fnScrollDraw( settings );
311
- }
312
- };
313
-
314
-
315
- /**
316
- * Quickly and simply clear a table
317
- * @param {bool} [bRedraw=true] redraw the table or not
318
- * @dtopt API
319
- * @deprecated Since v1.10
320
- *
321
- * @example
322
- * $(document).ready(function() {
323
- * var oTable = $('#example').wfDataTable();
324
- *
325
- * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
326
- * oTable.fnClearTable();
327
- * } );
328
- */
329
- this.fnClearTable = function( bRedraw )
330
- {
331
- var api = this.api( true ).clear();
332
-
333
- if ( bRedraw === undefined || bRedraw ) {
334
- api.draw();
335
- }
336
- };
337
-
338
-
339
- /**
340
- * The exact opposite of 'opening' a row, this function will close any rows which
341
- * are currently 'open'.
342
- * @param {node} nTr the table row to 'close'
343
- * @returns {int} 0 on success, or 1 if failed (can't find the row)
344
- * @dtopt API
345
- * @deprecated Since v1.10
346
- *
347
- * @example
348
- * $(document).ready(function() {
349
- * var oTable;
350
- *
351
- * // 'open' an information row when a row is clicked on
352
- * $('#example tbody tr').click( function () {
353
- * if ( oTable.fnIsOpen(this) ) {
354
- * oTable.fnClose( this );
355
- * } else {
356
- * oTable.fnOpen( this, "Temporary row opened", "info_row" );
357
- * }
358
- * } );
359
- *
360
- * oTable = $('#example').wfDataTable();
361
- * } );
362
- */
363
- this.fnClose = function( nTr )
364
- {
365
- this.api( true ).row( nTr ).child.hide();
366
- };
367
-
368
-
369
- /**
370
- * Remove a row for the table
371
- * @param {mixed} target The index of the row from aoData to be deleted, or
372
- * the TR element you want to delete
373
- * @param {function|null} [callBack] Callback function
374
- * @param {bool} [redraw=true] Redraw the table or not
375
- * @returns {array} The row that was deleted
376
- * @dtopt API
377
- * @deprecated Since v1.10
378
- *
379
- * @example
380
- * $(document).ready(function() {
381
- * var oTable = $('#example').wfDataTable();
382
- *
383
- * // Immediately remove the first row
384
- * oTable.fnDeleteRow( 0 );
385
- * } );
386
- */
387
- this.fnDeleteRow = function( target, callback, redraw )
388
- {
389
- var api = this.api( true );
390
- var rows = api.rows( target );
391
- var settings = rows.settings()[0];
392
- var data = settings.aoData[ rows[0][0] ];
393
-
394
- rows.remove();
395
-
396
- if ( callback ) {
397
- callback.call( this, settings, data );
398
- }
399
-
400
- if ( redraw === undefined || redraw ) {
401
- api.draw();
402
- }
403
-
404
- return data;
405
- };
406
-
407
-
408
- /**
409
- * Restore the table to it's original state in the DOM by removing all of WFDataTables
410
- * enhancements, alterations to the DOM structure of the table and event listeners.
411
- * @param {boolean} [remove=false] Completely remove the table from the DOM
412
- * @dtopt API
413
- * @deprecated Since v1.10
414
- *
415
- * @example
416
- * $(document).ready(function() {
417
- * // This example is fairly pointless in reality, but shows how fnDestroy can be used
418
- * var oTable = $('#example').wfDataTable();
419
- * oTable.fnDestroy();
420
- * } );
421
- */
422
- this.fnDestroy = function ( remove )
423
- {
424
- this.api( true ).destroy( remove );
425
- };
426
-
427
-
428
- /**
429
- * Redraw the table
430
- * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
431
- * @dtopt API
432
- * @deprecated Since v1.10
433
- *
434
- * @example
435
- * $(document).ready(function() {
436
- * var oTable = $('#example').wfDataTable();
437
- *
438
- * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
439
- * oTable.fnDraw();
440
- * } );
441
- */
442
- this.fnDraw = function( complete )
443
- {
444
- // Note that this isn't an exact match to the old call to _fnDraw - it takes
445
- // into account the new data, but can hold position.
446
- this.api( true ).draw( complete );
447
- };
448
-
449
-
450
- /**
451
- * Filter the input based on data
452
- * @param {string} sInput String to filter the table on
453
- * @param {int|null} [iColumn] Column to limit filtering to
454
- * @param {bool} [bRegex=false] Treat as regular expression or not
455
- * @param {bool} [bSmart=true] Perform smart filtering or not
456
- * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
457
- * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
458
- * @dtopt API
459
- * @deprecated Since v1.10
460
- *
461
- * @example
462
- * $(document).ready(function() {
463
- * var oTable = $('#example').wfDataTable();
464
- *
465
- * // Sometime later - filter...
466
- * oTable.fnFilter( 'test string' );
467
- * } );
468
- */
469
- this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
470
- {
471
- var api = this.api( true );
472
-
473
- if ( iColumn === null || iColumn === undefined ) {
474
- api.search( sInput, bRegex, bSmart, bCaseInsensitive );
475
- }
476
- else {
477
- api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
478
- }
479
-
480
- api.draw();
481
- };
482
-
483
-
484
- /**
485
- * Get the data for the whole table, an individual row or an individual cell based on the
486
- * provided parameters.
487
- * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
488
- * a TR node then the data source for the whole row will be returned. If given as a
489
- * TD/TH cell node then iCol will be automatically calculated and the data for the
490
- * cell returned. If given as an integer, then this is treated as the aoData internal
491
- * data index for the row (see fnGetPosition) and the data for that row used.
492
- * @param {int} [col] Optional column index that you want the data of.
493
- * @returns {array|object|string} If mRow is undefined, then the data for all rows is
494
- * returned. If mRow is defined, just data for that row, and is iCol is
495
- * defined, only data for the designated cell is returned.
496
- * @dtopt API
497
- * @deprecated Since v1.10
498
- *
499
- * @example
500
- * // Row data
501
- * $(document).ready(function() {
502
- * oTable = $('#example').wfDataTable();
503
- *
504
- * oTable.$('tr').click( function () {
505
- * var data = oTable.fnGetData( this );
506
- * // ... do something with the array / object of data for the row
507
- * } );
508
- * } );
509
- *
510
- * @example
511
- * // Individual cell data
512
- * $(document).ready(function() {
513
- * oTable = $('#example').wfDataTable();
514
- *
515
- * oTable.$('td').click( function () {
516
- * var sData = oTable.fnGetData( this );
517
- * alert( 'The cell clicked on had the value of '+sData );
518
- * } );
519
- * } );
520
- */
521
- this.fnGetData = function( src, col )
522
- {
523
- var api = this.api( true );
524
-
525
- if ( src !== undefined ) {
526
- var type = src.nodeName ? src.nodeName.toLowerCase() : '';
527
-
528
- return col !== undefined || type == 'td' || type == 'th' ?
529
- api.cell( src, col ).data() :
530
- api.row( src ).data() || null;
531
- }
532
-
533
- return api.data().toArray();
534
- };
535
-
536
-
537
- /**
538
- * Get an array of the TR nodes that are used in the table's body. Note that you will
539
- * typically want to use the '#x27; API method in preference to this as it is more
540
- * flexible.
541
- * @param {int} [iRow] Optional row index for the TR element you want
542
- * @returns {array|node} If iRow is undefined, returns an array of all TR elements
543
- * in the table's body, or iRow is defined, just the TR element requested.
544
- * @dtopt API
545
- * @deprecated Since v1.10
546
- *
547
- * @example
548
- * $(document).ready(function() {
549
- * var oTable = $('#example').wfDataTable();
550
- *
551
- * // Get the nodes from the table
552
- * var nNodes = oTable.fnGetNodes( );
553
- * } );
554
- */
555
- this.fnGetNodes = function( iRow )
556
- {
557
- var api = this.api( true );
558
-
559
- return iRow !== undefined ?
560
- api.row( iRow ).node() :
561
- api.rows().nodes().flatten().toArray();
562
- };
563
-
564
-
565
- /**
566
- * Get the array indexes of a particular cell from it's DOM element
567
- * and column index including hidden columns
568
- * @param {node} node this can either be a TR, TD or TH in the table's body
569
- * @returns {int} If nNode is given as a TR, then a single index is returned, or
570
- * if given as a cell, an array of [row index, column index (visible),
571
- * column index (all)] is given.
572
- * @dtopt API
573
- * @deprecated Since v1.10
574
- *
575
- * @example
576
- * $(document).ready(function() {
577
- * $('#example tbody td').click( function () {
578
- * // Get the position of the current data from the node
579
- * var aPos = oTable.fnGetPosition( this );
580
- *
581
- * // Get the data array for this row
582
- * var aData = oTable.fnGetData( aPos[0] );
583
- *
584
- * // Update the data array and return the value
585
- * aData[ aPos[1] ] = 'clicked';
586
- * this.innerHTML = 'clicked';
587
- * } );
588
- *
589
- * // Init WFDataTables
590
- * oTable = $('#example').wfDataTable();
591
- * } );
592
- */
593
- this.fnGetPosition = function( node )
594
- {
595
- var api = this.api( true );
596
- var nodeName = node.nodeName.toUpperCase();
597
-
598
- if ( nodeName == 'TR' ) {
599
- return api.row( node ).index();
600
- }
601
- else if ( nodeName == 'TD' || nodeName == 'TH' ) {
602
- var cell = api.cell( node ).index();
603
-
604
- return [
605
- cell.row,
606
- cell.columnVisible,
607
- cell.column
608
- ];
609
- }
610
- return null;
611
- };
612
-
613
-
614
- /**
615
- * Check to see if a row is 'open' or not.
616
- * @param {node} nTr the table row to check
617
- * @returns {boolean} true if the row is currently open, false otherwise
618
- * @dtopt API
619
- * @deprecated Since v1.10
620
- *
621
- * @example
622
- * $(document).ready(function() {
623
- * var oTable;
624
- *
625
- * // 'open' an information row when a row is clicked on
626
- * $('#example tbody tr').click( function () {
627
- * if ( oTable.fnIsOpen(this) ) {
628
- * oTable.fnClose( this );
629
- * } else {
630
- * oTable.fnOpen( this, "Temporary row opened", "info_row" );
631
- * }
632
- * } );
633
- *
634
- * oTable = $('#example').wfDataTable();
635
- * } );
636
- */
637
- this.fnIsOpen = function( nTr )
638
- {
639
- return this.api( true ).row( nTr ).child.isShown();
640
- };
641
-
642
-
643
- /**
644
- * This function will place a new row directly after a row which is currently
645
- * on display on the page, with the HTML contents that is passed into the
646
- * function. This can be used, for example, to ask for confirmation that a
647
- * particular record should be deleted.
648
- * @param {node} nTr The table row to 'open'
649
- * @param {string|node|jQuery} mHtml The HTML to put into the row
650
- * @param {string} sClass Class to give the new TD cell
651
- * @returns {node} The row opened. Note that if the table row passed in as the
652
- * first parameter, is not found in the table, this method will silently
653
- * return.
654
- * @dtopt API
655
- * @deprecated Since v1.10
656
- *
657
- * @example
658
- * $(document).ready(function() {
659
- * var oTable;
660
- *
661
- * // 'open' an information row when a row is clicked on
662
- * $('#example tbody tr').click( function () {
663
- * if ( oTable.fnIsOpen(this) ) {
664
- * oTable.fnClose( this );
665
- * } else {
666
- * oTable.fnOpen( this, "Temporary row opened", "info_row" );
667
- * }
668
- * } );
669
- *
670
- * oTable = $('#example').wfDataTable();
671
- * } );
672
- */
673
- this.fnOpen = function( nTr, mHtml, sClass )
674
- {
675
- return this.api( true )
676
- .row( nTr )
677
- .child( mHtml, sClass )
678
- .show()
679
- .child()[0];
680
- };
681
-
682
-
683
- /**
684
- * Change the pagination - provides the internal logic for pagination in a simple API
685
- * function. With this function you can have a WFDataTables table go to the next,
686
- * previous, first or last pages.
687
- * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
688
- * or page number to jump to (integer), note that page 0 is the first page.
689
- * @param {bool} [bRedraw=true] Redraw the table or not
690
- * @dtopt API
691
- * @deprecated Since v1.10
692
- *
693
- * @example
694
- * $(document).ready(function() {
695
- * var oTable = $('#example').wfDataTable();
696
- * oTable.fnPageChange( 'next' );
697
- * } );
698
- */
699
- this.fnPageChange = function ( mAction, bRedraw )
700
- {
701
- var api = this.api( true ).page( mAction );
702
-
703
- if ( bRedraw === undefined || bRedraw ) {
704
- api.draw(false);
705
- }
706
- };
707
-
708
-
709
- /**
710
- * Show a particular column
711
- * @param {int} iCol The column whose display should be changed
712
- * @param {bool} bShow Show (true) or hide (false) the column
713
- * @param {bool} [bRedraw=true] Redraw the table or not
714
- * @dtopt API
715
- * @deprecated Since v1.10
716
- *
717
- * @example
718
- * $(document).ready(function() {
719
- * var oTable = $('#example').wfDataTable();
720
- *
721
- * // Hide the second column after initialisation
722
- * oTable.fnSetColumnVis( 1, false );
723
- * } );
724
- */
725
- this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
726
- {
727
- var api = this.api( true ).column( iCol ).visible( bShow );
728
-
729
- if ( bRedraw === undefined || bRedraw ) {
730
- api.columns.adjust().draw();
731
- }
732
- };
733
-
734
-
735
- /**
736
- * Get the settings for a particular table for external manipulation
737
- * @returns {object} WFDataTables settings object. See
738
- * {@link WFDataTable.models.oSettings}
739
- * @dtopt API
740
- * @deprecated Since v1.10
741
- *
742
- * @example
743
- * $(document).ready(function() {
744
- * var oTable = $('#example').wfDataTable();
745
- * var oSettings = oTable.fnSettings();
746
- *
747
- * // Show an example parameter from the settings
748
- * alert( oSettings._iDisplayStart );
749
- * } );
750
- */
751
- this.fnSettings = function()
752
- {
753
- return _fnSettingsFromNode( this[_ext.iApiIndex] );
754
- };
755
-
756
-
757
- /**
758
- * Sort the table by a particular column
759
- * @param {int} iCol the data index to sort on. Note that this will not match the
760
- * 'display index' if you have hidden data entries
761
- * @dtopt API
762
- * @deprecated Since v1.10
763
- *
764
- * @example
765
- * $(document).ready(function() {
766
- * var oTable = $('#example').wfDataTable();
767
- *
768
- * // Sort immediately with columns 0 and 1
769
- * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
770
- * } );
771
- */
772
- this.fnSort = function( aaSort )
773
- {
774
- this.api( true ).order( aaSort ).draw();
775
- };
776
-
777
-
778
- /**
779
- * Attach a sort listener to an element for a given column
780
- * @param {node} nNode the element to attach the sort listener to
781
- * @param {int} iColumn the column that a click on this node will sort on
782
- * @param {function} [fnCallback] callback function when sort is run
783
- * @dtopt API
784
- * @deprecated Since v1.10
785
- *
786
- * @example
787
- * $(document).ready(function() {
788
- * var oTable = $('#example').wfDataTable();
789
- *
790
- * // Sort on column 1, when 'sorter' is clicked on
791
- * oTable.fnSortListener( document.getElementById('sorter'), 1 );
792
- * } );
793
- */
794
- this.fnSortListener = function( nNode, iColumn, fnCallback )
795
- {
796
- this.api( true ).order.listener( nNode, iColumn, fnCallback );
797
- };
798
-
799
-
800
- /**
801
- * Update a table cell or row - this method will accept either a single value to
802
- * update the cell with, an array of values with one element for each column or
803
- * an object in the same format as the original data source. The function is
804
- * self-referencing in order to make the multi column updates easier.
805
- * @param {object|array|string} mData Data to update the cell/row with
806
- * @param {node|int} mRow TR element you want to update or the aoData index
807
- * @param {int} [iColumn] The column to update, give as null or undefined to
808
- * update a whole row.
809
- * @param {bool} [bRedraw=true] Redraw the table or not
810
- * @param {bool} [bAction=true] Perform pre-draw actions or not
811
- * @returns {int} 0 on success, 1 on error
812
- * @dtopt API
813
- * @deprecated Since v1.10
814
- *
815
- * @example
816
- * $(document).ready(function() {
817
- * var oTable = $('#example').wfDataTable();
818
- * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
819
- * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
820
- * } );
821
- */
822
- this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
823
- {
824
- var api = this.api( true );
825
-
826
- if ( iColumn === undefined || iColumn === null ) {
827
- api.row( mRow ).data( mData );
828
- }
829
- else {
830
- api.cell( mRow, iColumn ).data( mData );
831
- }
832
-
833
- if ( bAction === undefined || bAction ) {
834
- api.columns.adjust();
835
- }
836
-
837
- if ( bRedraw === undefined || bRedraw ) {
838
- api.draw();
839
- }
840
- return 0;
841
- };
842
-
843
-
844
- /**
845
- * Provide a common method for plug-ins to check the version of WFDataTables being used, in order
846
- * to ensure compatibility.
847
- * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
848
- * formats "X" and "X.Y" are also acceptable.
849
- * @returns {boolean} true if this version of WFDataTables is greater or equal to the required
850
- * version, or false if this version of DataTales is not suitable
851
- * @method
852
- * @dtopt API
853
- * @deprecated Since v1.10
854
- *
855
- * @example
856
- * $(document).ready(function() {
857
- * var oTable = $('#example').wfDataTable();
858
- * alert( oTable.fnVersionCheck( '1.9.0' ) );
859
- * } );
860
- */
861
- this.fnVersionCheck = _ext.fnVersionCheck;
862
-
863
-
864
- var _that = this;
865
- var emptyInit = options === undefined;
866
- var len = this.length;
867
-
868
- if ( emptyInit ) {
869
- options = {};
870
- }
871
-
872
- this.oApi = this.internal = _ext.internal;
873
-
874
- // Extend with old style plug-in API methods
875
- for ( var fn in WFDataTable.ext.internal ) {
876
- if ( fn ) {
877
- this[fn] = _fnExternApiFunc(fn);
878
- }
879
- }
880
-
881
- this.each(function() {
882
- // For each initialisation we want to give it a clean initialisation
883
- // object that can be bashed around
884
- var o = {};
885
- var oInit = len > 1 ? // optimisation for single table case
886
- _fnExtend( o, options, true ) :
887
- options;
888
-
889
- /*global oInit,_that,emptyInit*/
890
- var i=0, iLen, j, jLen, k, kLen;
891
- var sId = this.getAttribute( 'id' );
892
- var bInitHandedOff = false;
893
- var defaults = WFDataTable.defaults;
894
- var $this = $(this);
895
-
896
-
897
- /* Sanity check */
898
- if ( this.nodeName.toLowerCase() != 'table' )
899
- {
900
- _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
901
- return;
902
- }
903
-
904
- /* Backwards compatibility for the defaults */
905
- _fnCompatOpts( defaults );
906
- _fnCompatCols( defaults.column );
907
-
908
- /* Convert the camel-case defaults to Hungarian */
909
- _fnCamelToHungarian( defaults, defaults, true );
910
- _fnCamelToHungarian( defaults.column, defaults.column, true );
911
-
912
- /* Setting up the initialisation object */
913
- _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
914
-
915
-
916
-
917
- /* Check to see if we are re-initialising a table */
918
- var allSettings = WFDataTable.settings;
919
- for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
920
- {
921
- var s = allSettings[i];
922
-
923
- /* Base check on table node */
924
- if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
925
- {
926
- var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
927
- var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
928
-
929
- if ( emptyInit || bRetrieve )
930
- {
931
- return s.oInstance;
932
- }
933
- else if ( bDestroy )
934
- {
935
- s.oInstance.fnDestroy();
936
- break;
937
- }
938
- else
939
- {
940
- _fnLog( s, 0, 'Cannot reinitialise WFDataTable', 3 );
941
- return;
942
- }
943
- }
944
-
945
- /* If the element we are initialising has the same ID as a table which was previously
946
- * initialised, but the table nodes don't match (from before) then we destroy the old
947
- * instance by simply deleting it. This is under the assumption that the table has been
948
- * destroyed by other methods. Anyone using non-id selectors will need to do this manually
949
- */
950
- if ( s.sTableId == this.id )
951
- {
952
- allSettings.splice( i, 1 );
953
- break;
954
- }
955
- }
956
-
957
- /* Ensure the table has an ID - required for accessibility */
958
- if ( sId === null || sId === "" )
959
- {
960
- sId = "WFDataTables_Table_"+(WFDataTable.ext._unique++);
961
- this.id = sId;
962
- }
963
-
964
- /* Create the settings object for this table and set some of the default parameters */
965
- var oSettings = $.extend( true, {}, WFDataTable.models.oSettings, {
966
- "sDestroyWidth": $this[0].style.width,
967
- "sInstance": sId,
968
- "sTableId": sId
969
- } );
970
- oSettings.nTable = this;
971
- oSettings.oApi = _that.internal;
972
- oSettings.oInit = oInit;
973
-
974
- allSettings.push( oSettings );
975
-
976
- // Need to add the instance after the instance after the settings object has been added
977
- // to the settings array, so we can self reference the table instance if more than one
978
- oSettings.oInstance = (_that.length===1) ? _that : $this.wfDataTable();
979
-
980
- // Backwards compatibility, before we apply all the defaults
981
- _fnCompatOpts( oInit );
982
-
983
- if ( oInit.oLanguage )
984
- {
985
- _fnLanguageCompat( oInit.oLanguage );
986
- }
987
-
988
- // If the length menu is given, but the init display length is not, use the length menu
989
- if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
990
- {
991
- oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
992
- oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
993
- }
994
-
995
- // Apply the defaults and init options to make a single init object will all
996
- // options defined from defaults and instance options.
997
- oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
998
-
999
-
1000
- // Map the initialisation options onto the settings object
1001
- _fnMap( oSettings.oFeatures, oInit, [
1002
- "bPaginate",
1003
- "bLengthChange",
1004
- "bFilter",
1005
- "bSort",
1006
- "bSortMulti",
1007
- "bInfo",
1008
- "bProcessing",
1009
- "bAutoWidth",
1010
- "bSortClasses",
1011
- "bServerSide",
1012
- "bDeferRender"
1013
- ] );
1014
- _fnMap( oSettings, oInit, [
1015
- "asStripeClasses",
1016
- "ajax",
1017
- "fnServerData",
1018
- "fnFormatNumber",
1019
- "sServerMethod",
1020
- "aaSorting",
1021
- "aaSortingFixed",
1022
- "aLengthMenu",
1023
- "sPaginationType",
1024
- "sAjaxSource",
1025
- "sAjaxDataProp",
1026
- "iStateDuration",
1027
- "sDom",
1028
- "bSortCellsTop",
1029
- "iTabIndex",
1030
- "fnStateLoadCallback",
1031
- "fnStateSaveCallback",
1032
- "renderer",
1033
- "searchDelay",
1034
- "rowId",
1035
- [ "iCookieDuration", "iStateDuration" ], // backwards compat
1036
- [ "oSearch", "oPreviousSearch" ],
1037
- [ "aoSearchCols", "aoPreSearchCols" ],
1038
- [ "iDisplayLength", "_iDisplayLength" ],
1039
- [ "bJQueryUI", "bJUI" ]
1040
- ] );
1041
- _fnMap( oSettings.oScroll, oInit, [
1042
- [ "sScrollX", "sX" ],
1043
- [ "sScrollXInner", "sXInner" ],
1044
- [ "sScrollY", "sY" ],
1045
- [ "bScrollCollapse", "bCollapse" ]
1046
- ] );
1047
- _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1048
-
1049
- /* Callback functions which are array driven */
1050
- _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1051
- _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1052
- _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1053
- _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1054
- _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1055
- _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1056
- _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1057
- _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1058
- _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1059
- _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1060
- _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1061
-
1062
- oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1063
-
1064
- /* Browser support detection */
1065
- _fnBrowserDetect( oSettings );
1066
-
1067
- var oClasses = oSettings.oClasses;
1068
-
1069
- // @todo Remove in 1.11
1070
- if ( oInit.bJQueryUI )
1071
- {
1072
- /* Use the JUI classes object for display. You could clone the oStdClasses object if
1073
- * you want to have multiple tables with multiple independent classes
1074
- */
1075
- $.extend( oClasses, WFDataTable.ext.oJUIClasses, oInit.oClasses );
1076
-
1077
- if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
1078
- {
1079
- /* Set the DOM to use a layout suitable for jQuery UI's theming */
1080
- oSettings.sDom = '<"H"lfr>t<"F"ip>';
1081
- }
1082
-
1083
- if ( ! oSettings.renderer ) {
1084
- oSettings.renderer = 'jqueryui';
1085
- }
1086
- else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
1087
- oSettings.renderer.header = 'jqueryui';
1088
- }
1089
- }
1090
- else
1091
- {
1092
- $.extend( oClasses, WFDataTable.ext.classes, oInit.oClasses );
1093
- }
1094
- $this.addClass( oClasses.sTable );
1095
-
1096
-
1097
- if ( oSettings.iInitDisplayStart === undefined )
1098
- {
1099
- /* Display start point, taking into account the save saving */
1100
- oSettings.iInitDisplayStart = oInit.iDisplayStart;
1101
- oSettings._iDisplayStart = oInit.iDisplayStart;
1102
- }
1103
-
1104
- if ( oInit.iDeferLoading !== null )
1105
- {
1106
- oSettings.bDeferLoading = true;
1107
- var tmp = $.isArray( oInit.iDeferLoading );
1108
- oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1109
- oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1110
- }
1111
-
1112
- /* Language definitions */
1113
- var oLanguage = oSettings.oLanguage;
1114
- $.extend( true, oLanguage, oInit.oLanguage );
1115
-
1116
- if ( oLanguage.sUrl )
1117
- {
1118
- /* Get the language definitions from a file - because this Ajax call makes the language
1119
- * get async to the remainder of this function we use bInitHandedOff to indicate that
1120
- * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1121
- */
1122
- $.ajax( {
1123
- dataType: 'json',
1124
- url: oLanguage.sUrl,
1125
- success: function ( json ) {
1126
- _fnLanguageCompat( json );
1127
- _fnCamelToHungarian( defaults.oLanguage, json );
1128
- $.extend( true, oLanguage, json );
1129
- _fnInitialise( oSettings );
1130
- },
1131
- error: function () {
1132
- // Error occurred loading language file, continue on as best we can
1133
- _fnInitialise( oSettings );
1134
- }
1135
- } );
1136
- bInitHandedOff = true;
1137
- }
1138
-
1139
- /*
1140
- * Stripes
1141
- */
1142
- if ( oInit.asStripeClasses === null )
1143
- {
1144
- oSettings.asStripeClasses =[
1145
- oClasses.sStripeOdd,
1146
- oClasses.sStripeEven
1147
- ];
1148
- }
1149
-
1150
- /* Remove row stripe classes if they are already on the table row */
1151
- var stripeClasses = oSettings.asStripeClasses;
1152
- var rowOne = $this.children('tbody').find('tr').eq(0);
1153
- if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1154
- return rowOne.hasClass(el);
1155
- } ) ) !== -1 ) {
1156
- $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1157
- oSettings.asDestroyStripes = stripeClasses.slice();
1158
- }
1159
-
1160
- /*
1161
- * Columns
1162
- * See if we should load columns automatically or use defined ones
1163
- */
1164
- var anThs = [];
1165
- var aoColumnsInit;
1166
- var nThead = this.getElementsByTagName('thead');
1167
- if ( nThead.length !== 0 )
1168
- {
1169
- _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1170
- anThs = _fnGetUniqueThs( oSettings );
1171
- }
1172
-
1173
- /* If not given a column array, generate one with nulls */
1174
- if ( oInit.aoColumns === null )
1175
- {
1176
- aoColumnsInit = [];
1177
- for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1178
- {
1179
- aoColumnsInit.push( null );
1180
- }
1181
- }
1182
- else
1183
- {
1184
- aoColumnsInit = oInit.aoColumns;
1185
- }
1186
-
1187
- /* Add the columns */
1188
- for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1189
- {
1190
- _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1191
- }
1192
-
1193
- /* Apply the column definitions */
1194
- _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1195
- _fnColumnOptions( oSettings, iCol, oDef );
1196
- } );
1197
-
1198
- /* HTML5 attribute detection - build an mData object automatically if the
1199
- * attributes are found
1200
- */
1201
- if ( rowOne.length ) {
1202
- var a = function ( cell, name ) {
1203
- return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1204
- };
1205
-
1206
- $( rowOne[0] ).children('th, td').each( function (i, cell) {
1207
- var col = oSettings.aoColumns[i];
1208
-
1209
- if ( col.mData === i ) {
1210
- var sort = a( cell, 'sort' ) || a( cell, 'order' );
1211
- var filter = a( cell, 'filter' ) || a( cell, 'search' );
1212
-
1213
- if ( sort !== null || filter !== null ) {
1214
- col.mData = {
1215
- _: i+'.display',
1216
- sort: sort !== null ? i+'.@data-'+sort : undefined,
1217
- type: sort !== null ? i+'.@data-'+sort : undefined,
1218
- filter: filter !== null ? i+'.@data-'+filter : undefined
1219
- };
1220
-
1221
- _fnColumnOptions( oSettings, i );
1222
- }
1223
- }
1224
- } );
1225
- }
1226
-
1227
- var features = oSettings.oFeatures;
1228
- var loadedInit = function () {
1229
- /*
1230
- * Sorting
1231
- * @todo For modularisation (1.11) this needs to do into a sort start up handler
1232
- */
1233
-
1234
- // If aaSorting is not defined, then we use the first indicator in asSorting
1235
- // in case that has been altered, so the default sort reflects that option
1236
- if ( oInit.aaSorting === undefined ) {
1237
- var sorting = oSettings.aaSorting;
1238
- for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1239
- sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1240
- }
1241
- }
1242
-
1243
- /* Do a first pass on the sorting classes (allows any size changes to be taken into
1244
- * account, and also will apply sorting disabled classes if disabled
1245
- */
1246
- _fnSortingClasses( oSettings );
1247
-
1248
- if ( features.bSort ) {
1249
- _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1250
- if ( oSettings.bSorted ) {
1251
- var aSort = _fnSortFlatten( oSettings );
1252
- var sortedColumns = {};
1253
-
1254
- $.each( aSort, function (i, val) {
1255
- sortedColumns[ val.src ] = val.dir;
1256
- } );
1257
-
1258
- _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1259
- _fnSortAria( oSettings );
1260
- }
1261
- } );
1262
- }
1263
-
1264
- _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1265
- if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1266
- _fnSortingClasses( oSettings );
1267
- }
1268
- }, 'sc' );
1269
-
1270
-
1271
- /*
1272
- * Final init
1273
- * Cache the header, body and footer as required, creating them if needed
1274
- */
1275
-
1276
- // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1277
- var captions = $this.children('caption').each( function () {
1278
- this._captionSide = $(this).css('caption-side');
1279
- } );
1280
-
1281
- var thead = $this.children('thead');
1282
- if ( thead.length === 0 ) {
1283
- thead = $('<thead/>').appendTo($this);
1284
- }
1285
- oSettings.nTHead = thead[0];
1286
-
1287
- var tbody = $this.children('tbody');
1288
- if ( tbody.length === 0 ) {
1289
- tbody = $('<tbody/>').appendTo($this);
1290
- }
1291
- oSettings.nTBody = tbody[0];
1292
-
1293
- var tfoot = $this.children('tfoot');
1294
- if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1295
- // If we are a scrolling table, and no footer has been given, then we need to create
1296
- // a tfoot element for the caption element to be appended to
1297
- tfoot = $('<tfoot/>').appendTo($this);
1298
- }
1299
-
1300
- if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1301
- $this.addClass( oClasses.sNoFooter );
1302
- }
1303
- else if ( tfoot.length > 0 ) {
1304
- oSettings.nTFoot = tfoot[0];
1305
- _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1306
- }
1307
-
1308
- /* Check if there is data passing into the constructor */
1309
- if ( oInit.aaData ) {
1310
- for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1311
- _fnAddData( oSettings, oInit.aaData[ i ] );
1312
- }
1313
- }
1314
- else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1315
- /* Grab the data from the page - only do this when deferred loading or no Ajax
1316
- * source since there is no point in reading the DOM data if we are then going
1317
- * to replace it with Ajax data
1318
- */
1319
- _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1320
- }
1321
-
1322
- /* Copy the data index array */
1323
- oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1324
-
1325
- /* Initialisation complete - table can be drawn */
1326
- oSettings.bInitialised = true;
1327
-
1328
- /* Check if we need to initialise the table (it might not have been handed off to the
1329
- * language processor)
1330
- */
1331
- if ( bInitHandedOff === false ) {
1332
- _fnInitialise( oSettings );
1333
- }
1334
- };
1335
-
1336
- /* Must be done after everything which can be overridden by the state saving! */
1337
- if ( oInit.bStateSave )
1338
- {
1339
- features.bStateSave = true;
1340
- _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1341
- _fnLoadState( oSettings, oInit, loadedInit );
1342
- }
1343
- else {
1344
- loadedInit();
1345
- }
1346
-
1347
- } );
1348
- _that = null;
1349
- return this;
1350
- };
1351
-
1352
-
1353
- /*
1354
- * It is useful to have variables which are scoped locally so only the
1355
- * WFDataTables functions can access them and they don't leak into global space.
1356
- * At the same time these functions are often useful over multiple files in the
1357
- * core and API, so we list, or at least document, all variables which are used
1358
- * by WFDataTables as private variables here. This also ensures that there is no
1359
- * clashing of variable names and that they can easily referenced for reuse.
1360
- */
1361
-
1362
-
1363
- // Defined else where
1364
- // _selector_run
1365
- // _selector_opts
1366
- // _selector_first
1367
- // _selector_row_indexes
1368
-
1369
- var _ext; // WFDataTable.ext
1370
- var _Api; // WFDataTable.Api
1371
- var _api_register; // WFDataTable.Api.register
1372
- var _api_registerPlural; // WFDataTable.Api.registerPlural
1373
-
1374
- var _re_dic = {};
1375
- var _re_new_lines = /[\r\n]/g;
1376
- var _re_html = /<.*?>/g;
1377
-
1378
- // This is not strict ISO8601 - Date.parse() is quite lax, although
1379
- // implementations differ between browsers.
1380
- var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?#x2F;;
1381
-
1382
- // Escape regular expression special characters
1383
- var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '#x27;, '^', '-' ].join('|\\') + ')', 'g' );
1384
-
1385
- // http://en.wikipedia.org/wiki/Foreign_exchange_market
1386
- // - \u20BD - Russian ruble.
1387
- // - \u20a9 - South Korean Won
1388
- // - \u20BA - Turkish Lira
1389
- // - \u20B9 - Indian Rupee
1390
- // - R - Brazil (R$) and South Africa
1391
- // - fr - Swiss Franc
1392
- // - kr - Swedish krona, Norwegian krone and Danish krone
1393
- // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1394
- // standards as thousands separators.
1395
- var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
1396
-
1397
-
1398
- var _empty = function ( d ) {
1399
- return !d || d === true || d === '-' ? true : false;
1400
- };
1401
-
1402
-
1403
- var _intVal = function ( s ) {
1404
- var integer = parseInt( s, 10 );
1405
- return !isNaN(integer) && isFinite(s) ? integer : null;
1406
- };
1407
-
1408
- // Convert from a formatted number with characters other than `.` as the
1409
- // decimal place, to a Javascript number
1410
- var _numToDecimal = function ( num, decimalPoint ) {
1411
- // Cache created regular expressions for speed as this function is called often
1412
- if ( ! _re_dic[ decimalPoint ] ) {
1413
- _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1414
- }
1415
- return typeof num === 'string' && decimalPoint !== '.' ?
1416
- num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1417
- num;
1418
- };
1419
-
1420
-
1421
- var _isNumber = function ( d, decimalPoint, formatted ) {
1422
- var strType = typeof d === 'string';
1423
-
1424
- // If empty return immediately so there must be a number if it is a
1425
- // formatted string (this stops the string "k", or "kr", etc being detected
1426
- // as a formatted number for currency
1427
- if ( _empty( d ) ) {
1428
- return true;
1429
- }
1430
-
1431
- if ( decimalPoint && strType ) {
1432
- d = _numToDecimal( d, decimalPoint );
1433
- }
1434
-
1435
- if ( formatted && strType ) {
1436
- d = d.replace( _re_formatted_numeric, '' );
1437
- }
1438
-
1439
- return !isNaN( parseFloat(d) ) && isFinite( d );
1440
- };
1441
-
1442
-
1443
- // A string without HTML in it can be considered to be HTML still
1444
- var _isHtml = function ( d ) {
1445
- return _empty( d ) || typeof d === 'string';
1446
- };
1447
-
1448
-
1449
- var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1450
- if ( _empty( d ) ) {
1451
- return true;
1452
- }
1453
-
1454
- var html = _isHtml( d );
1455
- return ! html ?
1456
- null :
1457
- _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1458
- true :
1459
- null;
1460
- };
1461
-
1462
-
1463
- var _pluck = function ( a, prop, prop2 ) {
1464
- var out = [];
1465
- var i=0, ien=a.length;
1466
-
1467
- // Could have the test in the loop for slightly smaller code, but speed
1468
- // is essential here
1469
- if ( prop2 !== undefined ) {
1470
- for ( ; i<ien ; i++ ) {
1471
- if ( a[i] && a[i][ prop ] ) {
1472
- out.push( a[i][ prop ][ prop2 ] );
1473
- }
1474
- }
1475
- }
1476
- else {
1477
- for ( ; i<ien ; i++ ) {
1478
- if ( a[i] ) {
1479
- out.push( a[i][ prop ] );
1480
- }
1481
- }
1482
- }
1483
-
1484
- return out;
1485
- };
1486
-
1487
-
1488
- // Basically the same as _pluck, but rather than looping over `a` we use `order`
1489
- // as the indexes to pick from `a`
1490
- var _pluck_order = function ( a, order, prop, prop2 )
1491
- {
1492
- var out = [];
1493
- var i=0, ien=order.length;
1494
-
1495
- // Could have the test in the loop for slightly smaller code, but speed
1496
- // is essential here
1497
- if ( prop2 !== undefined ) {
1498
- for ( ; i<ien ; i++ ) {
1499
- if ( a[ order[i] ][ prop ] ) {
1500
- out.push( a[ order[i] ][ prop ][ prop2 ] );
1501
- }
1502
- }
1503
- }
1504
- else {
1505
- for ( ; i<ien ; i++ ) {
1506
- out.push( a[ order[i] ][ prop ] );
1507
- }
1508
- }
1509
-
1510
- return out;
1511
- };
1512
-
1513
-
1514
- var _range = function ( len, start )
1515
- {
1516
- var out = [];
1517
- var end;
1518
-
1519
- if ( start === undefined ) {
1520
- start = 0;
1521
- end = len;
1522
- }
1523
- else {
1524
- end = start;
1525
- start = len;
1526
- }
1527
-
1528
- for ( var i=start ; i<end ; i++ ) {
1529
- out.push( i );
1530
- }
1531
-
1532
- return out;
1533
- };
1534
-
1535
-
1536
- var _removeEmpty = function ( a )
1537
- {
1538
- var out = [];
1539
-
1540
- for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1541
- if ( a[i] ) { // careful - will remove all falsy values!
1542
- out.push( a[i] );
1543
- }
1544
- }
1545
-
1546
- return out;
1547
- };
1548
-
1549
-
1550
- var _stripHtml = function ( d ) {
1551
- return d.replace( _re_html, '' );
1552
- };
1553
-
1554
-
1555
- /**
1556
- * Find the unique elements in a source array.
1557
- *
1558
- * @param {array} src Source array
1559
- * @return {array} Array of unique items
1560
- * @ignore
1561
- */
1562
- var _unique = function ( src )
1563
- {
1564
- // A faster unique method is to use object keys to identify used values,
1565
- // but this doesn't work with arrays or objects, which we must also
1566
- // consider. See jsperf.com/compare-array-unique-versions/4 for more
1567
- // information.
1568
- var
1569
- out = [],
1570
- val,
1571
- i, ien=src.length,
1572
- j, k=0;
1573
-
1574
- again: for ( i=0 ; i<ien ; i++ ) {
1575
- val = src[i];
1576
-
1577
- for ( j=0 ; j<k ; j++ ) {
1578
- if ( out[j] === val ) {
1579
- continue again;
1580
- }
1581
- }
1582
-
1583
- out.push( val );
1584
- k++;
1585
- }
1586
-
1587
- return out;
1588
- };
1589
-
1590
-
1591
- /**
1592
- * WFDataTables utility methods
1593
- *
1594
- * This namespace provides helper methods that WFDataTables uses internally to
1595
- * create a WFDataTable, but which are not exclusively used only for WFDataTables.
1596
- * These methods can be used by extension authors to save the duplication of
1597
- * code.
1598
- *
1599
- * @namespace
1600
- */
1601
- WFDataTable.util = {
1602
- /**
1603
- * Throttle the calls to a function. Arguments and context are maintained
1604
- * for the throttled function.
1605
- *
1606
- * @param {function} fn Function to be called
1607
- * @param {integer} freq Call frequency in mS
1608
- * @return {function} Wrapped function
1609
- */
1610
- throttle: function ( fn, freq ) {
1611
- var
1612
- frequency = freq !== undefined ? freq : 200,
1613
- last,
1614
- timer;
1615
-
1616
- return function () {
1617
- var
1618
- that = this,
1619
- now = +new Date(),
1620
- args = arguments;
1621
-
1622
- if ( last && now < last + frequency ) {
1623
- clearTimeout( timer );
1624
-
1625
- timer = setTimeout( function () {
1626
- last = undefined;
1627
- fn.apply( that, args );
1628
- }, frequency );
1629
- }
1630
- else {
1631
- last = now;
1632
- fn.apply( that, args );
1633
- }
1634
- };
1635
- },
1636
-
1637
-
1638
- /**
1639
- * Escape a string such that it can be used in a regular expression
1640
- *
1641
- * @param {string} val string to escape
1642
- * @returns {string} escaped string
1643
- */
1644
- escapeRegex: function ( val ) {
1645
- return val.replace( _re_escape_regex, '\\$1' );
1646
- }
1647
- };
1648
-
1649
-
1650
-
1651
- /**
1652
- * Create a mapping object that allows camel case parameters to be looked up
1653
- * for their Hungarian counterparts. The mapping is stored in a private
1654
- * parameter called `_hungarianMap` which can be accessed on the source object.
1655
- * @param {object} o
1656
- * @memberof WFDataTable#oApi
1657
- */
1658
- function _fnHungarianMap ( o )
1659
- {
1660
- var
1661
- hungarian = 'a aa ai ao as b fn i m o s ',
1662
- match,
1663
- newKey,
1664
- map = {};
1665
-
1666
- $.each( o, function (key, val) {
1667
- match = key.match(/^([^A-Z]+?)([A-Z])/);
1668
-
1669
- if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1670
- {
1671
- newKey = key.replace( match[0], match[2].toLowerCase() );
1672
- map[ newKey ] = key;
1673
-
1674
- if ( match[1] === 'o' )
1675
- {
1676
- _fnHungarianMap( o[key] );
1677
- }
1678
- }
1679
- } );
1680
-
1681
- o._hungarianMap = map;
1682
- }
1683
-
1684
-
1685
- /**
1686
- * Convert from camel case parameters to Hungarian, based on a Hungarian map
1687
- * created by _fnHungarianMap.
1688
- * @param {object} src The model object which holds all parameters that can be
1689
- * mapped.
1690
- * @param {object} user The object to convert from camel case to Hungarian.
1691
- * @param {boolean} force When set to `true`, properties which already have a
1692
- * Hungarian value in the `user` object will be overwritten. Otherwise they
1693
- * won't be.
1694
- * @memberof WFDataTable#oApi
1695
- */
1696
- function _fnCamelToHungarian ( src, user, force )
1697
- {
1698
- if ( ! src._hungarianMap ) {
1699
- _fnHungarianMap( src );
1700
- }
1701
-
1702
- var hungarianKey;
1703
-
1704
- $.each( user, function (key, val) {
1705
- hungarianKey = src._hungarianMap[ key ];
1706
-
1707
- if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1708
- {
1709
- // For objects, we need to buzz down into the object to copy parameters
1710
- if ( hungarianKey.charAt(0) === 'o' )
1711
- {
1712
- // Copy the camelCase options over to the hungarian
1713
- if ( ! user[ hungarianKey ] ) {
1714
- user[ hungarianKey ] = {};
1715
- }
1716
- $.extend( true, user[hungarianKey], user[key] );
1717
-
1718
- _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1719
- }
1720
- else {
1721
- user[hungarianKey] = user[ key ];
1722
- }
1723
- }
1724
- } );
1725
- }
1726
-
1727
-
1728
- /**
1729
- * Language compatibility - when certain options are given, and others aren't, we
1730
- * need to duplicate the values over, in order to provide backwards compatibility
1731
- * with older language files.
1732
- * @param {object} oSettings dataTables settings object
1733
- * @memberof WFDataTable#oApi
1734
- */
1735
- function _fnLanguageCompat( lang )
1736
- {
1737
- var defaults = WFDataTable.defaults.oLanguage;
1738
- var zeroRecords = lang.sZeroRecords;
1739
-
1740
- /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
1741
- * sZeroRecords - assuming that is given.
1742
- */
1743
- if ( ! lang.sEmptyTable && zeroRecords &&
1744
- defaults.sEmptyTable === "No data available in table" )
1745
- {
1746
- _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1747
- }
1748
-
1749
- /* Likewise with loading records */
1750
- if ( ! lang.sLoadingRecords && zeroRecords &&
1751
- defaults.sLoadingRecords === "Loading..." )
1752
- {
1753
- _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1754
- }
1755
-
1756
- // Old parameter name of the thousands separator mapped onto the new
1757
- if ( lang.sInfoThousands ) {
1758
- lang.sThousands = lang.sInfoThousands;
1759
- }
1760
-
1761
- var decimal = lang.sDecimal;
1762
- if ( decimal ) {
1763
- _addNumericSort( decimal );
1764
- }
1765
- }
1766
-
1767
-
1768
- /**
1769
- * Map one parameter onto another
1770
- * @param {object} o Object to map
1771
- * @param {*} knew The new parameter name
1772
- * @param {*} old The old parameter name
1773
- */
1774
- var _fnCompatMap = function ( o, knew, old ) {
1775
- if ( o[ knew ] !== undefined ) {
1776
- o[ old ] = o[ knew ];
1777
- }
1778
- };
1779
-
1780
-
1781
- /**
1782
- * Provide backwards compatibility for the main DT options. Note that the new
1783
- * options are mapped onto the old parameters, so this is an external interface
1784
- * change only.
1785
- * @param {object} init Object to map
1786
- */
1787
- function _fnCompatOpts ( init )
1788
- {
1789
- _fnCompatMap( init, 'ordering', 'bSort' );
1790
- _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
1791
- _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
1792
- _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1793
- _fnCompatMap( init, 'order', 'aaSorting' );
1794
- _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
1795
- _fnCompatMap( init, 'paging', 'bPaginate' );
1796
- _fnCompatMap( init, 'pagingType', 'sPaginationType' );
1797
- _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1798
- _fnCompatMap( init, 'searching', 'bFilter' );
1799
-
1800
- // Boolean initialisation of x-scrolling
1801
- if ( typeof init.sScrollX === 'boolean' ) {
1802
- init.sScrollX = init.sScrollX ? '100%' : '';
1803
- }
1804
- if ( typeof init.scrollX === 'boolean' ) {
1805
- init.scrollX = init.scrollX ? '100%' : '';
1806
- }
1807
-
1808
- // Column search objects are in an array, so it needs to be converted
1809
- // element by element
1810
- var searchCols = init.aoSearchCols;
1811
-
1812
- if ( searchCols ) {
1813
- for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1814
- if ( searchCols[i] ) {
1815
- _fnCamelToHungarian( WFDataTable.models.oSearch, searchCols[i] );
1816
- }
1817
- }
1818
- }
1819
- }
1820
-
1821
-
1822
- /**
1823
- * Provide backwards compatibility for column options. Note that the new options
1824
- * are mapped onto the old parameters, so this is an external interface change
1825
- * only.
1826
- * @param {object} init Object to map
1827
- */
1828
- function _fnCompatCols ( init )
1829
- {
1830
- _fnCompatMap( init, 'orderable', 'bSortable' );
1831
- _fnCompatMap( init, 'orderData', 'aDataSort' );
1832
- _fnCompatMap( init, 'orderSequence', 'asSorting' );
1833
- _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1834
-
1835
- // orderData can be given as an integer
1836
- var dataSort = init.aDataSort;
1837
- if ( dataSort && ! $.isArray( dataSort ) ) {
1838
- init.aDataSort = [ dataSort ];
1839
- }
1840
- }
1841
-
1842
-
1843
- /**
1844
- * Browser feature detection for capabilities, quirks
1845
- * @param {object} settings dataTables settings object
1846
- * @memberof WFDataTable#oApi
1847
- */
1848
- function _fnBrowserDetect( settings )
1849
- {
1850
- // We don't need to do this every time WFDataTables is constructed, the values
1851
- // calculated are specific to the browser and OS configuration which we
1852
- // don't expect to change between initialisations
1853
- if ( ! WFDataTable.__browser ) {
1854
- var browser = {};
1855
- WFDataTable.__browser = browser;
1856
-
1857
- // Scrolling feature / quirks detection
1858
- var n = $('<div/>')
1859
- .css( {
1860
- position: 'fixed',
1861
- top: 0,
1862
- left: $(window).scrollLeft()*-1, // allow for scrolling
1863
- height: 1,
1864
- width: 1,
1865
- overflow: 'hidden'
1866
- } )
1867
- .append(
1868
- $('<div/>')
1869
- .css( {
1870
- position: 'absolute',
1871
- top: 1,
1872
- left: 1,
1873
- width: 100,
1874
- overflow: 'scroll'
1875
- } )
1876
- .append(
1877
- $('<div/>')
1878
- .css( {
1879
- width: '100%',
1880
- height: 10
1881
- } )
1882
- )
1883
- )
1884
- .appendTo( 'body' );
1885
-
1886
- var outer = n.children();
1887
- var inner = outer.children();
1888
-
1889
- // Numbers below, in order, are:
1890
- // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1891
- //
1892
- // IE6 XP: 100 100 100 83
1893
- // IE7 Vista: 100 100 100 83
1894
- // IE 8+ Windows: 83 83 100 83
1895
- // Evergreen Windows: 83 83 100 83
1896
- // Evergreen Mac with scrollbars: 85 85 100 85
1897
- // Evergreen Mac without scrollbars: 100 100 100 100
1898
-
1899
- // Get scrollbar width
1900
- browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1901
-
1902
- // IE6/7 will oversize a width 100% element inside a scrolling element, to
1903
- // include the width of the scrollbar, while other browsers ensure the inner
1904
- // element is contained without forcing scrolling
1905
- browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1906
-
1907
- // In rtl text layout, some browsers (most, but not all) will place the
1908
- // scrollbar on the left, rather than the right.
1909
- browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1910
-
1911
- // IE8- don't provide height and width for getBoundingClientRect
1912
- browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1913
-
1914
- n.remove();
1915
- }
1916
-
1917
- $.extend( settings.oBrowser, WFDataTable.__browser );
1918
- settings.oScroll.iBarWidth = WFDataTable.__browser.barWidth;
1919
- }
1920
-
1921
-
1922
- /**
1923
- * Array.prototype reduce[Right] method, used for browsers which don't support
1924
- * JS 1.6. Done this way to reduce code size, since we iterate either way
1925
- * @param {object} settings dataTables settings object
1926
- * @memberof WFDataTable#oApi
1927
- */
1928
- function _fnReduce ( that, fn, init, start, end, inc )
1929
- {
1930
- var
1931
- i = start,
1932
- value,
1933
- isSet = false;
1934
-
1935
- if ( init !== undefined ) {
1936
- value = init;
1937
- isSet = true;
1938
- }
1939
-
1940
- while ( i !== end ) {
1941
- if ( ! that.hasOwnProperty(i) ) {
1942
- continue;
1943
- }
1944
-
1945
- value = isSet ?
1946
- fn( value, that[i], i, that ) :
1947
- that[i];
1948
-
1949
- isSet = true;
1950
- i += inc;
1951
- }
1952
-
1953
- return value;
1954
- }
1955
-
1956
- /**
1957
- * Add a column to the list used for the table with default values
1958
- * @param {object} oSettings dataTables settings object
1959
- * @param {node} nTh The th element for this column
1960
- * @memberof WFDataTable#oApi
1961
- */
1962
- function _fnAddColumn( oSettings, nTh )
1963
- {
1964
- // Add column to aoColumns array
1965
- var oDefaults = WFDataTable.defaults.column;
1966
- var iCol = oSettings.aoColumns.length;
1967
- var oCol = $.extend( {}, WFDataTable.models.oColumn, oDefaults, {
1968
- "nTh": nTh ? nTh : document.createElement('th'),
1969
- "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
1970
- "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1971
- "mData": oDefaults.mData ? oDefaults.mData : iCol,
1972
- idx: iCol
1973
- } );
1974
- oSettings.aoColumns.push( oCol );
1975
-
1976
- // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1977
- // passed into extend can be undefined. This allows the user to give a default
1978
- // with only some of the parameters defined, and also not give a default
1979
- var searchCols = oSettings.aoPreSearchCols;
1980
- searchCols[ iCol ] = $.extend( {}, WFDataTable.models.oSearch, searchCols[ iCol ] );
1981
-
1982
- // Use the default column options function to initialise classes etc
1983
- _fnColumnOptions( oSettings, iCol, $(nTh).data() );
1984
- }
1985
-
1986
-
1987
- /**
1988
- * Apply options for a column
1989
- * @param {object} oSettings dataTables settings object
1990
- * @param {int} iCol column index to consider
1991
- * @param {object} oOptions object with sType, bVisible and bSearchable etc
1992
- * @memberof WFDataTable#oApi
1993
- */
1994
- function _fnColumnOptions( oSettings, iCol, oOptions )
1995
- {
1996
- var oCol = oSettings.aoColumns[ iCol ];
1997
- var oClasses = oSettings.oClasses;
1998
- var th = $(oCol.nTh);
1999
-
2000
- // Try to get width information from the DOM. We can't get it from CSS
2001
- // as we'd need to parse the CSS stylesheet. `width` option can override
2002
- if ( ! oCol.sWidthOrig ) {
2003
- // Width attribute
2004
- oCol.sWidthOrig = th.attr('width') || null;
2005
-
2006
- // Style attribute
2007
- var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2008
- if ( t ) {
2009
- oCol.sWidthOrig = t[1];
2010
- }
2011
- }
2012
-
2013
- /* User specified column options */
2014
- if ( oOptions !== undefined && oOptions !== null )
2015
- {
2016
- // Backwards compatibility
2017
- _fnCompatCols( oOptions );
2018
-
2019
- // Map camel case parameters to their Hungarian counterparts
2020
- _fnCamelToHungarian( WFDataTable.defaults.column, oOptions );
2021
-
2022
- /* Backwards compatibility for mDataProp */
2023
- if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2024
- {
2025
- oOptions.mData = oOptions.mDataProp;
2026
- }
2027
-
2028
- if ( oOptions.sType )
2029
- {
2030
- oCol._sManualType = oOptions.sType;
2031
- }
2032
-
2033
- // `class` is a reserved word in Javascript, so we need to provide
2034
- // the ability to use a valid name for the camel case input
2035
- if ( oOptions.className && ! oOptions.sClass )
2036
- {
2037
- oOptions.sClass = oOptions.className;
2038
- }
2039
-
2040
- $.extend( oCol, oOptions );
2041
- _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2042
-
2043
- /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2044
- * priority if defined
2045
- */
2046
- if ( oOptions.iDataSort !== undefined )
2047
- {
2048
- oCol.aDataSort = [ oOptions.iDataSort ];
2049
- }
2050
- _fnMap( oCol, oOptions, "aDataSort" );
2051
- }
2052
-
2053
- /* Cache the data get and set functions for speed */
2054
- var mDataSrc = oCol.mData;
2055
- var mData = _fnGetObjectDataFn( mDataSrc );
2056
- var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2057
-
2058
- var attrTest = function( src ) {
2059
- return typeof src === 'string' && src.indexOf('@') !== -1;
2060
- };
2061
- oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2062
- attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2063
- );
2064
- oCol._setter = null;
2065
-
2066
- oCol.fnGetData = function (rowData, type, meta) {
2067
- var innerData = mData( rowData, type, undefined, meta );
2068
-
2069
- return mRender && type ?
2070
- mRender( innerData, type, rowData, meta ) :
2071
- innerData;
2072
- };
2073
- oCol.fnSetData = function ( rowData, val, meta ) {
2074
- return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2075
- };
2076
-
2077
- // Indicate if WFDataTables should read DOM data as an object or array
2078
- // Used in _fnGetRowElements
2079
- if ( typeof mDataSrc !== 'number' ) {
2080
- oSettings._rowReadObject = true;
2081
- }
2082
-
2083
- /* Feature sorting overrides column specific when off */
2084
- if ( !oSettings.oFeatures.bSort )
2085
- {
2086
- oCol.bSortable = false;
2087
- th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2088
- }
2089
-
2090
- /* Check that the class assignment is correct for sorting */
2091
- var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2092
- var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2093
- if ( !oCol.bSortable || (!bAsc && !bDesc) )
2094
- {
2095
- oCol.sSortingClass = oClasses.sSortableNone;
2096
- oCol.sSortingClassJUI = "";
2097
- }
2098
- else if ( bAsc && !bDesc )
2099
- {
2100
- oCol.sSortingClass = oClasses.sSortableAsc;
2101
- oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2102
- }
2103
- else if ( !bAsc && bDesc )
2104
- {
2105
- oCol.sSortingClass = oClasses.sSortableDesc;
2106
- oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2107
- }
2108
- else
2109
- {
2110
- oCol.sSortingClass = oClasses.sSortable;
2111
- oCol.sSortingClassJUI = oClasses.sSortJUI;
2112
- }
2113
- }
2114
-
2115
-
2116
- /**
2117
- * Adjust the table column widths for new data. Note: you would probably want to
2118
- * do a redraw after calling this function!
2119
- * @param {object} settings dataTables settings object
2120
- * @memberof WFDataTable#oApi
2121
- */
2122
- function _fnAdjustColumnSizing ( settings )
2123
- {
2124
- /* Not interested in doing column width calculation if auto-width is disabled */
2125
- if ( settings.oFeatures.bAutoWidth !== false )
2126
- {
2127
- var columns = settings.aoColumns;
2128
-
2129
- _fnCalculateColumnWidths( settings );
2130
- for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2131
- {
2132
- columns[i].nTh.style.width = columns[i].sWidth;
2133
- }
2134
- }
2135
-
2136
- var scroll = settings.oScroll;
2137
- if ( scroll.sY !== '' || scroll.sX !== '')
2138
- {
2139
- _fnScrollDraw( settings );
2140
- }
2141
-
2142
- _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2143
- }
2144
-
2145
-
2146
- /**
2147
- * Covert the index of a visible column to the index in the data array (take account
2148
- * of hidden columns)
2149
- * @param {object} oSettings dataTables settings object
2150
- * @param {int} iMatch Visible column index to lookup
2151
- * @returns {int} i the data index
2152
- * @memberof WFDataTable#oApi
2153
- */
2154
- function _fnVisibleToColumnIndex( oSettings, iMatch )
2155
- {
2156
- var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2157
-
2158
- return typeof aiVis[iMatch] === 'number' ?
2159
- aiVis[iMatch] :
2160
- null;
2161
- }
2162
-
2163
-
2164
- /**
2165
- * Covert the index of an index in the data array and convert it to the visible
2166
- * column index (take account of hidden columns)
2167
- * @param {int} iMatch Column index to lookup
2168
- * @param {object} oSettings dataTables settings object
2169
- * @returns {int} i the data index
2170
- * @memberof WFDataTable#oApi
2171
- */
2172
- function _fnColumnIndexToVisible( oSettings, iMatch )
2173
- {
2174
- var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2175
- var iPos = $.inArray( iMatch, aiVis );
2176
-
2177
- return iPos !== -1 ? iPos : null;
2178
- }
2179
-
2180
-
2181
- /**
2182
- * Get the number of visible columns
2183
- * @param {object} oSettings dataTables settings object
2184
- * @returns {int} i the number of visible columns
2185
- * @memberof WFDataTable#oApi
2186
- */
2187
- function _fnVisbleColumns( oSettings )
2188
- {
2189
- var vis = 0;
2190
-
2191
- // No reduce in IE8, use a loop for now
2192
- $.each( oSettings.aoColumns, function ( i, col ) {
2193
- if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2194
- vis++;
2195
- }
2196
- } );
2197
-
2198
- return vis;
2199
- }
2200
-
2201
-
2202
- /**
2203
- * Get an array of column indexes that match a given property
2204
- * @param {object} oSettings dataTables settings object
2205
- * @param {string} sParam Parameter in aoColumns to look for - typically
2206
- * bVisible or bSearchable
2207
- * @returns {array} Array of indexes with matched properties
2208
- * @memberof WFDataTable#oApi
2209
- */
2210
- function _fnGetColumns( oSettings, sParam )
2211
- {
2212
- var a = [];
2213
-
2214
- $.map( oSettings.aoColumns, function(val, i) {
2215
- if ( val[sParam] ) {
2216
- a.push( i );
2217
- }
2218
- } );
2219
-
2220
- return a;
2221
- }
2222
-
2223
-
2224
- /**
2225
- * Calculate the 'type' of a column
2226
- * @param {object} settings dataTables settings object
2227
- * @memberof WFDataTable#oApi
2228
- */
2229
- function _fnColumnTypes ( settings )
2230
- {
2231
- var columns = settings.aoColumns;
2232
- var data = settings.aoData;
2233
- var types = WFDataTable.ext.type.detect;
2234
- var i, ien, j, jen, k, ken;
2235
- var col, cell, detectedType, cache;
2236
-
2237
- // For each column, spin over the
2238
- for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2239
- col = columns[i];
2240
- cache = [];
2241
-
2242
- if ( ! col.sType && col._sManualType ) {
2243
- col.sType = col._sManualType;
2244
- }
2245
- else if ( ! col.sType ) {
2246
- for ( j=0, jen=types.length ; j<jen ; j++ ) {
2247
- for ( k=0, ken=data.length ; k<ken ; k++ ) {
2248
- // Use a cache array so we only need to get the type data
2249
- // from the formatter once (when using multiple detectors)
2250
- if ( cache[k] === undefined ) {
2251
- cache[k] = _fnGetCellData( settings, k, i, 'type' );
2252
- }
2253
-
2254
- detectedType = types[j]( cache[k], settings );
2255
-
2256
- // If null, then this type can't apply to this column, so
2257
- // rather than testing all cells, break out. There is an
2258
- // exception for the last type which is `html`. We need to
2259
- // scan all rows since it is possible to mix string and HTML
2260
- // types
2261
- if ( ! detectedType && j !== types.length-1 ) {
2262
- break;
2263
- }
2264
-
2265
- // Only a single match is needed for html type since it is
2266
- // bottom of the pile and very similar to string
2267
- if ( detectedType === 'html' ) {
2268
- break;
2269
- }
2270
- }
2271
-
2272
- // Type is valid for all data points in the column - use this
2273
- // type
2274
- if ( detectedType ) {
2275
- col.sType = detectedType;
2276
- break;
2277
- }
2278
- }
2279
-
2280
- // Fall back - if no type was detected, always use string
2281
- if ( ! col.sType ) {
2282
- col.sType = 'string';
2283
- }
2284
- }
2285
- }
2286
- }
2287
-
2288
-
2289
- /**
2290
- * Take the column definitions and static columns arrays and calculate how
2291
- * they relate to column indexes. The callback function will then apply the
2292
- * definition found for a column to a suitable configuration object.
2293
- * @param {object} oSettings dataTables settings object
2294
- * @param {array} aoColDefs The aoColumnDefs array that is to be applied
2295
- * @param {array} aoCols The aoColumns array that defines columns individually
2296
- * @param {function} fn Callback function - takes two parameters, the calculated
2297
- * column index and the definition for that column.
2298
- * @memberof WFDataTable#oApi
2299
- */
2300
- function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2301
- {
2302
- var i, iLen, j, jLen, k, kLen, def;
2303
- var columns = oSettings.aoColumns;
2304
-
2305
- // Column definitions with aTargets
2306
- if ( aoColDefs )
2307
- {
2308
- /* Loop over the definitions array - loop in reverse so first instance has priority */
2309
- for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2310
- {
2311
- def = aoColDefs[i];
2312
-
2313
- /* Each definition can target multiple columns, as it is an array */
2314
- var aTargets = def.targets !== undefined ?
2315
- def.targets :
2316
- def.aTargets;
2317
-
2318
- if ( ! $.isArray( aTargets ) )
2319
- {
2320
- aTargets = [ aTargets ];
2321
- }
2322
-
2323
- for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2324
- {
2325
- if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2326
- {
2327
- /* Add columns that we don't yet know about */
2328
- while( columns.length <= aTargets[j] )
2329
- {
2330
- _fnAddColumn( oSettings );
2331
- }
2332
-
2333
- /* Integer, basic index */
2334
- fn( aTargets[j], def );
2335
- }
2336
- else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2337
- {
2338
- /* Negative integer, right to left column counting */
2339
- fn( columns.length+aTargets[j], def );
2340
- }
2341
- else if ( typeof aTargets[j] === 'string' )
2342
- {
2343
- /* Class name matching on TH element */
2344
- for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2345
- {
2346
- if ( aTargets[j] == "_all" ||
2347
- $(columns[k].nTh).hasClass( aTargets[j] ) )
2348
- {
2349
- fn( k, def );
2350
- }
2351
- }
2352
- }
2353
- }
2354
- }
2355
- }
2356
-
2357
- // Statically defined columns array
2358
- if ( aoCols )
2359
- {
2360
- for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2361
- {
2362
- fn( i, aoCols[i] );
2363
- }
2364
- }
2365
- }
2366
-
2367
- /**
2368
- * Add a data array to the table, creating DOM node etc. This is the parallel to
2369
- * _fnGatherData, but for adding rows from a Javascript source, rather than a
2370
- * DOM source.
2371
- * @param {object} oSettings dataTables settings object
2372
- * @param {array} aData data array to be added
2373
- * @param {node} [nTr] TR element to add to the table - optional. If not given,
2374
- * WFDataTables will create a row automatically
2375
- * @param {array} [anTds] Array of TD|TH elements for the row - must be given
2376
- * if nTr is.
2377
- * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2378
- * @memberof WFDataTable#oApi
2379
- */
2380
- function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2381
- {
2382
- /* Create the object for storing information about this new row */
2383
- var iRow = oSettings.aoData.length;
2384
- var oData = $.extend( true, {}, WFDataTable.models.oRow, {
2385
- src: nTr ? 'dom' : 'data',
2386
- idx: iRow
2387
- } );
2388
-
2389
- oData._aData = aDataIn;
2390
- oSettings.aoData.push( oData );
2391
-
2392
- /* Create the cells */
2393
- var nTd, sThisType;
2394
- var columns = oSettings.aoColumns;
2395
-
2396
- // Invalidate the column types as the new data needs to be revalidated
2397
- for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2398
- {
2399
- columns[i].sType = null;
2400
- }
2401
-
2402
- /* Add to the display array */
2403
- oSettings.aiDisplayMaster.push( iRow );
2404
-
2405
- var id = oSettings.rowIdFn( aDataIn );
2406
- if ( id !== undefined ) {
2407
- oSettings.aIds[ id ] = oData;
2408
- }
2409
-
2410
- /* Create the DOM information, or register it if already present */
2411
- if ( nTr || ! oSettings.oFeatures.bDeferRender )
2412
- {
2413
- _fnCreateTr( oSettings, iRow, nTr, anTds );
2414
- }
2415
-
2416
- return iRow;
2417
- }
2418
-
2419
-
2420
- /**
2421
- * Add one or more TR elements to the table. Generally we'd expect to
2422
- * use this for reading data from a DOM sourced table, but it could be
2423
- * used for an TR element. Note that if a TR is given, it is used (i.e.
2424
- * it is not cloned).
2425
- * @param {object} settings dataTables settings object
2426
- * @param {array|node|jQuery} trs The TR element(s) to add to the table
2427
- * @returns {array} Array of indexes for the added rows
2428
- * @memberof WFDataTable#oApi
2429
- */
2430
- function _fnAddTr( settings, trs )
2431
- {
2432
- var row;
2433
-
2434
- // Allow an individual node to be passed in
2435
- if ( ! (trs instanceof $) ) {
2436
- trs = $(trs);
2437
- }
2438
-
2439
- return trs.map( function (i, el) {
2440
- row = _fnGetRowElements( settings, el );
2441
- return _fnAddData( settings, row.data, el, row.cells );
2442
- } );
2443
- }
2444
-
2445
-
2446
- /**
2447
- * Take a TR element and convert it to an index in aoData
2448
- * @param {object} oSettings dataTables settings object
2449
- * @param {node} n the TR element to find
2450
- * @returns {int} index if the node is found, null if not
2451
- * @memberof WFDataTable#oApi
2452
- */
2453
- function _fnNodeToDataIndex( oSettings, n )
2454
- {
2455
- return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2456
- }
2457
-
2458
-
2459
- /**
2460
- * Take a TD element and convert it into a column data index (not the visible index)
2461
- * @param {object} oSettings dataTables settings object
2462
- * @param {int} iRow The row number the TD/TH can be found in
2463
- * @param {node} n The TD/TH element to find
2464
- * @returns {int} index if the node is found, -1 if not
2465
- * @memberof WFDataTable#oApi
2466
- */
2467
- function _fnNodeToColumnIndex( oSettings, iRow, n )
2468
- {
2469
- return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2470
- }
2471
-
2472
-
2473
- /**
2474
- * Get the data for a given cell from the internal cache, taking into account data mapping
2475
- * @param {object} settings dataTables settings object
2476
- * @param {int} rowIdx aoData row id
2477
- * @param {int} colIdx Column index
2478
- * @param {string} type data get type ('display', 'type' 'filter' 'sort')
2479
- * @returns {*} Cell data
2480
- * @memberof WFDataTable#oApi
2481
- */
2482
- function _fnGetCellData( settings, rowIdx, colIdx, type )
2483
- {
2484
- var draw = settings.iDraw;
2485
- var col = settings.aoColumns[colIdx];
2486
- var rowData = settings.aoData[rowIdx]._aData;
2487
- var defaultContent = col.sDefaultContent;
2488
- var cellData = col.fnGetData( rowData, type, {
2489
- settings: settings,
2490
- row: rowIdx,
2491
- col: colIdx
2492
- } );
2493
-
2494
- if ( cellData === undefined ) {
2495
- if ( settings.iDrawError != draw && defaultContent === null ) {
2496
- _fnLog( settings, 0, "Requested unknown parameter "+
2497
- (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2498
- " for row "+rowIdx+", column "+colIdx, 4 );
2499
- settings.iDrawError = draw;
2500
- }
2501
- return defaultContent;
2502
- }
2503
-
2504
- // When the data source is null and a specific data type is requested (i.e.
2505
- // not the original data), we can use default column data
2506
- if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2507
- cellData = defaultContent;
2508
- }
2509
- else if ( typeof cellData === 'function' ) {
2510
- // If the data source is a function, then we run it and use the return,
2511
- // executing in the scope of the data object (for instances)
2512
- return cellData.call( rowData );
2513
- }
2514
-
2515
- if ( cellData === null && type == 'display' ) {
2516
- return '';
2517
- }
2518
- return cellData;
2519
- }
2520
-
2521
-
2522
- /**
2523
- * Set the value for a specific cell, into the internal data cache
2524
- * @param {object} settings dataTables settings object
2525
- * @param {int} rowIdx aoData row id
2526
- * @param {int} colIdx Column index
2527
- * @param {*} val Value to set
2528
- * @memberof WFDataTable#oApi
2529
- */
2530
- function _fnSetCellData( settings, rowIdx, colIdx, val )
2531
- {
2532
- var col = settings.aoColumns[colIdx];
2533
- var rowData = settings.aoData[rowIdx]._aData;
2534
-
2535
- col.fnSetData( rowData, val, {
2536
- settings: settings,
2537
- row: rowIdx,
2538
- col: colIdx
2539
- } );
2540
- }
2541
-
2542
-
2543
- // Private variable that is used to match action syntax in the data property object
2544
- var __reArray = /\[.*?\]#x2F;;
2545
- var __reFn = /\(\)#x2F;;
2546
-
2547
- /**
2548
- * Split string on periods, taking into account escaped periods
2549
- * @param {string} str String to split
2550
- * @return {array} Split string
2551
- */
2552
- function _fnSplitObjNotation( str )
2553
- {
2554
- return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2555
- return s.replace(/\\\./g, '.');
2556
- } );
2557
- }
2558
-
2559
-
2560
- /**
2561
- * Return a function that can be used to get data from a source object, taking
2562
- * into account the ability to use nested objects as a source
2563
- * @param {string|int|function} mSource The data source for the object
2564
- * @returns {function} Data get function
2565
- * @memberof WFDataTable#oApi
2566
- */
2567
- function _fnGetObjectDataFn( mSource )
2568
- {
2569
- if ( $.isPlainObject( mSource ) )
2570
- {
2571
- /* Build an object of get functions, and wrap them in a single call */
2572
- var o = {};
2573
- $.each( mSource, function (key, val) {
2574
- if ( val ) {
2575
- o[key] = _fnGetObjectDataFn( val );
2576
- }
2577
- } );
2578
-
2579
- return function (data, type, row, meta) {
2580
- var t = o[type] || o._;
2581
- return t !== undefined ?
2582
- t(data, type, row, meta) :
2583
- data;
2584
- };
2585
- }
2586
- else if ( mSource === null )
2587
- {
2588
- /* Give an empty string for rendering / sorting etc */
2589
- return function (data) { // type, row and meta also passed, but not used
2590
- return data;
2591
- };
2592
- }
2593
- else if ( typeof mSource === 'function' )
2594
- {
2595
- return function (data, type, row, meta) {
2596
- return mSource( data, type, row, meta );
2597
- };
2598
- }
2599
- else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2600
- mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2601
- {
2602
- /* If there is a . in the source string then the data source is in a
2603
- * nested object so we loop over the data for each level to get the next
2604
- * level down. On each loop we test for undefined, and if found immediately
2605
- * return. This allows entire objects to be missing and sDefaultContent to
2606
- * be used if defined, rather than throwing an error
2607
- */
2608
- var fetchData = function (data, type, src) {
2609
- var arrayNotation, funcNotation, out, innerSrc;
2610
-
2611
- if ( src !== "" )
2612
- {
2613
- var a = _fnSplitObjNotation( src );
2614
-
2615
- for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2616
- {
2617
- // Check if we are dealing with special notation
2618
- arrayNotation = a[i].match(__reArray);
2619
- funcNotation = a[i].match(__reFn);
2620
-
2621
- if ( arrayNotation )
2622
- {
2623
- // Array notation
2624
- a[i] = a[i].replace(__reArray, '');
2625
-
2626
- // Condition allows simply [] to be passed in
2627
- if ( a[i] !== "" ) {
2628
- data = data[ a[i] ];
2629
- }
2630
- out = [];
2631
-
2632
- // Get the remainder of the nested object to get
2633
- a.splice( 0, i+1 );
2634
- innerSrc = a.join('.');
2635
-
2636
- // Traverse each entry in the array getting the properties requested
2637
- if ( $.isArray( data ) ) {
2638
- for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2639
- out.push( fetchData( data[j], type, innerSrc ) );
2640
- }
2641
- }
2642
-
2643
- // If a string is given in between the array notation indicators, that
2644
- // is used to join the strings together, otherwise an array is returned
2645
- var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2646
- data = (join==="") ? out : out.join(join);
2647
-
2648
- // The inner call to fetchData has already traversed through the remainder
2649
- // of the source requested, so we exit from the loop
2650
- break;
2651
- }
2652
- else if ( funcNotation )
2653
- {
2654
- // Function call
2655
- a[i] = a[i].replace(__reFn, '');
2656
- data = data[ a[i] ]();
2657
- continue;
2658
- }
2659
-
2660
- if ( data === null || data[ a[i] ] === undefined )
2661
- {
2662
- return undefined;
2663
- }
2664
- data = data[ a[i] ];
2665
- }
2666
- }
2667
-
2668
- return data;
2669
- };
2670
-
2671
- return function (data, type) { // row and meta also passed, but not used
2672
- return fetchData( data, type, mSource );
2673
- };
2674
- }
2675
- else
2676
- {
2677
- /* Array or flat object mapping */
2678
- return function (data, type) { // row and meta also passed, but not used
2679
- return data[mSource];
2680
- };
2681
- }
2682
- }
2683
-
2684
-
2685
- /**
2686
- * Return a function that can be used to set data from a source object, taking
2687
- * into account the ability to use nested objects as a source
2688
- * @param {string|int|function} mSource The data source for the object
2689
- * @returns {function} Data set function
2690
- * @memberof WFDataTable#oApi
2691
- */
2692
- function _fnSetObjectDataFn( mSource )
2693
- {
2694
- if ( $.isPlainObject( mSource ) )
2695
- {
2696
- /* Unlike get, only the underscore (global) option is used for for
2697
- * setting data since we don't know the type here. This is why an object
2698
- * option is not documented for `mData` (which is read/write), but it is
2699
- * for `mRender` which is read only.
2700
- */
2701
- return _fnSetObjectDataFn( mSource._ );
2702
- }
2703
- else if ( mSource === null )
2704
- {
2705
- /* Nothing to do when the data source is null */
2706
- return function () {};
2707
- }
2708
- else if ( typeof mSource === 'function' )
2709
- {
2710
- return function (data, val, meta) {
2711
- mSource( data, 'set', val, meta );
2712
- };
2713
- }
2714
- else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2715
- mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2716
- {
2717
- /* Like the get, we need to get data from a nested object */
2718
- var setData = function (data, val, src) {
2719
- var a = _fnSplitObjNotation( src ), b;
2720
- var aLast = a[a.length-1];
2721
- var arrayNotation, funcNotation, o, innerSrc;
2722
-
2723
- for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2724
- {
2725
- // Check if we are dealing with an array notation request
2726
- arrayNotation = a[i].match(__reArray);
2727
- funcNotation = a[i].match(__reFn);
2728
-
2729
- if ( arrayNotation )
2730
- {
2731
- a[i] = a[i].replace(__reArray, '');
2732
- data[ a[i] ] = [];
2733
-
2734
- // Get the remainder of the nested object to set so we can recurse
2735
- b = a.slice();
2736
- b.splice( 0, i+1 );
2737
- innerSrc = b.join('.');
2738
-
2739
- // Traverse each entry in the array setting the properties requested
2740
- if ( $.isArray( val ) )
2741
- {
2742
- for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2743
- {
2744
- o = {};
2745
- setData( o, val[j], innerSrc );
2746
- data[ a[i] ].push( o );
2747
- }
2748
- }
2749
- else
2750
- {
2751
- // We've been asked to save data to an array, but it
2752
- // isn't array data to be saved. Best that can be done
2753
- // is to just save the value.
2754
- data[ a[i] ] = val;
2755
- }
2756
-
2757
- // The inner call to setData has already traversed through the remainder
2758
- // of the source and has set the data, thus we can exit here
2759
- return;
2760
- }
2761
- else if ( funcNotation )
2762
- {
2763
- // Function call
2764
- a[i] = a[i].replace(__reFn, '');
2765
- data = data[ a[i] ]( val );
2766
- }
2767
-
2768
- // If the nested object doesn't currently exist - since we are
2769
- // trying to set the value - create it
2770
- if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2771
- {
2772
- data[ a[i] ] = {};
2773
- }
2774
- data = data[ a[i] ];
2775
- }
2776
-
2777
- // Last item in the input - i.e, the actual set
2778
- if ( aLast.match(__reFn ) )
2779
- {
2780
- // Function call
2781
- data = data[ aLast.replace(__reFn, '') ]( val );
2782
- }
2783
- else
2784
- {
2785
- // If array notation is used, we just want to strip it and use the property name
2786
- // and assign the value. If it isn't used, then we get the result we want anyway
2787
- data[ aLast.replace(__reArray, '') ] = val;
2788
- }
2789
- };
2790
-
2791
- return function (data, val) { // meta is also passed in, but not used
2792
- return setData( data, val, mSource );
2793
- };
2794
- }
2795
- else
2796
- {
2797
- /* Array or flat object mapping */
2798
- return function (data, val) { // meta is also passed in, but not used
2799
- data[mSource] = val;
2800
- };
2801
- }
2802
- }
2803
-
2804
-
2805
- /**
2806
- * Return an array with the full table data
2807
- * @param {object} oSettings dataTables settings object
2808
- * @returns array {array} aData Master data array
2809
- * @memberof WFDataTable#oApi
2810
- */
2811
- function _fnGetDataMaster ( settings )
2812
- {
2813
- return _pluck( settings.aoData, '_aData' );
2814
- }
2815
-
2816
-
2817
- /**
2818
- * Nuke the table
2819
- * @param {object} oSettings dataTables settings object
2820
- * @memberof WFDataTable#oApi
2821
- */
2822
- function _fnClearTable( settings )
2823
- {
2824
- settings.aoData.length = 0;
2825
- settings.aiDisplayMaster.length = 0;
2826
- settings.aiDisplay.length = 0;
2827
- settings.aIds = {};
2828
- }
2829
-
2830
-
2831
- /**
2832
- * Take an array of integers (index array) and remove a target integer (value - not
2833
- * the key!)
2834
- * @param {array} a Index array to target
2835
- * @param {int} iTarget value to find
2836
- * @memberof WFDataTable#oApi
2837
- */
2838
- function _fnDeleteIndex( a, iTarget, splice )
2839
- {
2840
- var iTargetIndex = -1;
2841
-
2842
- for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2843
- {
2844
- if ( a[i] == iTarget )
2845
- {
2846
- iTargetIndex = i;
2847
- }
2848
- else if ( a[i] > iTarget )
2849
- {
2850
- a[i]--;
2851
- }
2852
- }
2853
-
2854
- if ( iTargetIndex != -1 && splice === undefined )
2855
- {
2856
- a.splice( iTargetIndex, 1 );
2857
- }
2858
- }
2859
-
2860
-
2861
- /**
2862
- * Mark cached data as invalid such that a re-read of the data will occur when
2863
- * the cached data is next requested. Also update from the data source object.
2864
- *
2865
- * @param {object} settings WFDataTables settings object
2866
- * @param {int} rowIdx Row index to invalidate
2867
- * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
2868
- * or 'data'
2869
- * @param {int} [colIdx] Column index to invalidate. If undefined the whole
2870
- * row will be invalidated
2871
- * @memberof WFDataTable#oApi
2872
- *
2873
- * @todo For the modularisation of v1.11 this will need to become a callback, so
2874
- * the sort and filter methods can subscribe to it. That will required
2875
- * initialisation options for sorting, which is why it is not already baked in
2876
- */
2877
- function _fnInvalidate( settings, rowIdx, src, colIdx )
2878
- {
2879
- var row = settings.aoData[ rowIdx ];
2880
- var i, ien;
2881
- var cellWrite = function ( cell, col ) {
2882
- // This is very frustrating, but in IE if you just write directly
2883
- // to innerHTML, and elements that are overwritten are GC'ed,
2884
- // even if there is a reference to them elsewhere
2885
- while ( cell.childNodes.length ) {
2886
- cell.removeChild( cell.firstChild );
2887
- }
2888
-
2889
- cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2890
- };
2891
-
2892
- // Are we reading last data from DOM or the data object?
2893
- if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2894
- // Read the data from the DOM
2895
- row._aData = _fnGetRowElements(
2896
- settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2897
- )
2898
- .data;
2899
- }
2900
- else {
2901
- // Reading from data object, update the DOM
2902
- var cells = row.anCells;
2903
-
2904
- if ( cells ) {
2905
- if ( colIdx !== undefined ) {
2906
- cellWrite( cells[colIdx], colIdx );
2907
- }
2908
- else {
2909
- for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2910
- cellWrite( cells[i], i );
2911
- }
2912
- }
2913
- }
2914
- }
2915
-
2916
- // For both row and cell invalidation, the cached data for sorting and
2917
- // filtering is nulled out
2918
- row._aSortData = null;
2919
- row._aFilterData = null;
2920
-
2921
- // Invalidate the type for a specific column (if given) or all columns since
2922
- // the data might have changed
2923
- var cols = settings.aoColumns;
2924
- if ( colIdx !== undefined ) {
2925
- cols[ colIdx ].sType = null;
2926
- }
2927
- else {
2928
- for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2929
- cols[i].sType = null;
2930
- }
2931
-
2932
- // Update WFDataTables special `DT_*` attributes for the row
2933
- _fnRowAttributes( settings, row );
2934
- }
2935
- }
2936
-
2937
-
2938
- /**
2939
- * Build a data source object from an HTML row, reading the contents of the
2940
- * cells that are in the row.
2941
- *
2942
- * @param {object} settings WFDataTables settings object
2943
- * @param {node|object} TR element from which to read data or existing row
2944
- * object from which to re-read the data from the cells
2945
- * @param {int} [colIdx] Optional column index
2946
- * @param {array|object} [d] Data source object. If `colIdx` is given then this
2947
- * parameter should also be given and will be used to write the data into.
2948
- * Only the column in question will be written
2949
- * @returns {object} Object with two parameters: `data` the data read, in
2950
- * document order, and `cells` and array of nodes (they can be useful to the
2951
- * caller, so rather than needing a second traversal to get them, just return
2952
- * them from here).
2953
- * @memberof WFDataTable#oApi
2954
- */
2955
- function _fnGetRowElements( settings, row, colIdx, d )
2956
- {
2957
- var
2958
- tds = [],
2959
- td = row.firstChild,
2960
- name, col, o, i=0, contents,
2961
- columns = settings.aoColumns,
2962
- objectRead = settings._rowReadObject;
2963
-
2964
- // Allow the data object to be passed in, or construct
2965
- d = d !== undefined ?
2966
- d :
2967
- objectRead ?
2968
- {} :
2969
- [];
2970
-
2971
- var attr = function ( str, td ) {
2972
- if ( typeof str === 'string' ) {
2973
- var idx = str.indexOf('@');
2974
-
2975
- if ( idx !== -1 ) {
2976
- var attr = str.substring( idx+1 );
2977
- var setter = _fnSetObjectDataFn( str );
2978
- setter( d, td.getAttribute( attr ) );
2979
- }
2980
- }
2981
- };
2982
-
2983
- // Read data from a cell and store into the data object
2984
- var cellProcess = function ( cell ) {
2985
- if ( colIdx === undefined || colIdx === i ) {
2986
- col = columns[i];
2987
- contents = $.trim(cell.innerHTML);
2988
-
2989
- if ( col && col._bAttrSrc ) {
2990
- var setter = _fnSetObjectDataFn( col.mData._ );
2991
- setter( d, contents );
2992
-
2993
- attr( col.mData.sort, cell );
2994
- attr( col.mData.type, cell );
2995
- attr( col.mData.filter, cell );
2996
- }
2997
- else {
2998
- // Depending on the `data` option for the columns the data can
2999
- // be read to either an object or an array.
3000
- if ( objectRead ) {
3001
- if ( ! col._setter ) {
3002
- // Cache the setter function
3003
- col._setter = _fnSetObjectDataFn( col.mData );
3004
- }
3005
- col._setter( d, contents );
3006
- }
3007
- else {
3008
- d[i] = contents;
3009
- }
3010
- }
3011
- }
3012
-
3013
- i++;
3014
- };