Add datatables-1.9.4 and jquery-1.10.2 libraries
[proteocache.git] / webapp / resources / datatables-1.9.4 / media / src / core / core.data.js
1 /**
2  * Add a data array to the table, creating DOM node etc. This is the parallel to 
3  * _fnGatherData, but for adding rows from a Javascript source, rather than a
4  * DOM source.
5  *  @param {object} oSettings dataTables settings object
6  *  @param {array} aData data array to be added
7  *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
8  *  @memberof DataTable#oApi
9  */
10 function _fnAddData ( oSettings, aDataSupplied )
11 {
12         var oCol;
13         
14         /* Take an independent copy of the data source so we can bash it about as we wish */
15         var aDataIn = ($.isArray(aDataSupplied)) ?
16                 aDataSupplied.slice() :
17                 $.extend( true, {}, aDataSupplied );
18         
19         /* Create the object for storing information about this new row */
20         var iRow = oSettings.aoData.length;
21         var oData = $.extend( true, {}, DataTable.models.oRow );
22         oData._aData = aDataIn;
23         oSettings.aoData.push( oData );
24
25         /* Create the cells */
26         var nTd, sThisType;
27         for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
28         {
29                 oCol = oSettings.aoColumns[i];
30
31                 /* Use rendered data for filtering / sorting */
32                 if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
33                 {
34                         _fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
35                 }
36                 else
37                 {
38                         _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
39                 }
40                 
41                 /* See if we should auto-detect the column type */
42                 if ( oCol._bAutoType && oCol.sType != 'string' )
43                 {
44                         /* Attempt to auto detect the type - same as _fnGatherData() */
45                         var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
46                         if ( sVarType !== null && sVarType !== '' )
47                         {
48                                 sThisType = _fnDetectType( sVarType );
49                                 if ( oCol.sType === null )
50                                 {
51                                         oCol.sType = sThisType;
52                                 }
53                                 else if ( oCol.sType != sThisType && oCol.sType != "html" )
54                                 {
55                                         /* String is always the 'fallback' option */
56                                         oCol.sType = 'string';
57                                 }
58                         }
59                 }
60         }
61         
62         /* Add to the display array */
63         oSettings.aiDisplayMaster.push( iRow );
64
65         /* Create the DOM information */
66         if ( !oSettings.oFeatures.bDeferRender )
67         {
68                 _fnCreateTr( oSettings, iRow );
69         }
70
71         return iRow;
72 }
73
74
75 /**
76  * Read in the data from the target table from the DOM
77  *  @param {object} oSettings dataTables settings object
78  *  @memberof DataTable#oApi
79  */
80 function _fnGatherData( oSettings )
81 {
82         var iLoop, i, iLen, j, jLen, jInner,
83                 nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
84                 iRow, iRows, iColumn, iColumns, sNodeName,
85                 oCol, oData;
86         
87         /*
88          * Process by row first
89          * Add the data object for the whole table - storing the tr node. Note - no point in getting
90          * DOM based data if we are going to go and replace it with Ajax source data.
91          */
92         if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
93         {
94                 nTr = oSettings.nTBody.firstChild;
95                 while ( nTr )
96                 {
97                         if ( nTr.nodeName.toUpperCase() == "TR" )
98                         {
99                                 iThisIndex = oSettings.aoData.length;
100                                 nTr._DT_RowIndex = iThisIndex;
101                                 oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
102                                         "nTr": nTr
103                                 } ) );
104
105                                 oSettings.aiDisplayMaster.push( iThisIndex );
106                                 nTd = nTr.firstChild;
107                                 jInner = 0;
108                                 while ( nTd )
109                                 {
110                                         sNodeName = nTd.nodeName.toUpperCase();
111                                         if ( sNodeName == "TD" || sNodeName == "TH" )
112                                         {
113                                                 _fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
114                                                 jInner++;
115                                         }
116                                         nTd = nTd.nextSibling;
117                                 }
118                         }
119                         nTr = nTr.nextSibling;
120                 }
121         }
122         
123         /* Gather in the TD elements of the Table - note that this is basically the same as
124          * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
125          * setup!
126          */
127         nTrs = _fnGetTrNodes( oSettings );
128         nTds = [];
129         for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
130         {
131                 nTd = nTrs[i].firstChild;
132                 while ( nTd )
133                 {
134                         sNodeName = nTd.nodeName.toUpperCase();
135                         if ( sNodeName == "TD" || sNodeName == "TH" )
136                         {
137                                 nTds.push( nTd );
138                         }
139                         nTd = nTd.nextSibling;
140                 }
141         }
142         
143         /* Now process by column */
144         for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
145         {
146                 oCol = oSettings.aoColumns[iColumn];
147
148                 /* Get the title of the column - unless there is a user set one */
149                 if ( oCol.sTitle === null )
150                 {
151                         oCol.sTitle = oCol.nTh.innerHTML;
152                 }
153                 
154                 var
155                         bAutoType = oCol._bAutoType,
156                         bRender = typeof oCol.fnRender === 'function',
157                         bClass = oCol.sClass !== null,
158                         bVisible = oCol.bVisible,
159                         nCell, sThisType, sRendered, sValType;
160                 
161                 /* A single loop to rule them all (and be more efficient) */
162                 if ( bAutoType || bRender || bClass || !bVisible )
163                 {
164                         for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
165                         {
166                                 oData = oSettings.aoData[iRow];
167                                 nCell = nTds[ (iRow*iColumns) + iColumn ];
168                                 
169                                 /* Type detection */
170                                 if ( bAutoType && oCol.sType != 'string' )
171                                 {
172                                         sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
173                                         if ( sValType !== '' )
174                                         {
175                                                 sThisType = _fnDetectType( sValType );
176                                                 if ( oCol.sType === null )
177                                                 {
178                                                         oCol.sType = sThisType;
179                                                 }
180                                                 else if ( oCol.sType != sThisType && 
181                                                           oCol.sType != "html" )
182                                                 {
183                                                         /* String is always the 'fallback' option */
184                                                         oCol.sType = 'string';
185                                                 }
186                                         }
187                                 }
188
189                                 if ( oCol.mRender )
190                                 {
191                                         // mRender has been defined, so we need to get the value and set it
192                                         nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
193                                 }
194                                 else if ( oCol.mData !== iColumn )
195                                 {
196                                         // If mData is not the same as the column number, then we need to
197                                         // get the dev set value. If it is the column, no point in wasting
198                                         // time setting the value that is already there!
199                                         nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
200                                 }
201                                 
202                                 /* Rendering */
203                                 if ( bRender )
204                                 {
205                                         sRendered = _fnRender( oSettings, iRow, iColumn );
206                                         nCell.innerHTML = sRendered;
207                                         if ( oCol.bUseRendered )
208                                         {
209                                                 /* Use the rendered data for filtering / sorting */
210                                                 _fnSetCellData( oSettings, iRow, iColumn, sRendered );
211                                         }
212                                 }
213                                 
214                                 /* Classes */
215                                 if ( bClass )
216                                 {
217                                         nCell.className += ' '+oCol.sClass;
218                                 }
219                                 
220                                 /* Column visibility */
221                                 if ( !bVisible )
222                                 {
223                                         oData._anHidden[iColumn] = nCell;
224                                         nCell.parentNode.removeChild( nCell );
225                                 }
226                                 else
227                                 {
228                                         oData._anHidden[iColumn] = null;
229                                 }
230
231                                 if ( oCol.fnCreatedCell )
232                                 {
233                                         oCol.fnCreatedCell.call( oSettings.oInstance,
234                                                 nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
235                                         );
236                                 }
237                         }
238                 }
239         }
240
241         /* Row created callbacks */
242         if ( oSettings.aoRowCreatedCallback.length !== 0 )
243         {
244                 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
245                 {
246                         oData = oSettings.aoData[i];
247                         _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
248                 }
249         }
250 }
251
252
253 /**
254  * Take a TR element and convert it to an index in aoData
255  *  @param {object} oSettings dataTables settings object
256  *  @param {node} n the TR element to find
257  *  @returns {int} index if the node is found, null if not
258  *  @memberof DataTable#oApi
259  */
260 function _fnNodeToDataIndex( oSettings, n )
261 {
262         return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
263 }
264
265
266 /**
267  * Take a TD element and convert it into a column data index (not the visible index)
268  *  @param {object} oSettings dataTables settings object
269  *  @param {int} iRow The row number the TD/TH can be found in
270  *  @param {node} n The TD/TH element to find
271  *  @returns {int} index if the node is found, -1 if not
272  *  @memberof DataTable#oApi
273  */
274 function _fnNodeToColumnIndex( oSettings, iRow, n )
275 {
276         var anCells = _fnGetTdNodes( oSettings, iRow );
277
278         for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
279         {
280                 if ( anCells[i] === n )
281                 {
282                         return i;
283                 }
284         }
285         return -1;
286 }
287
288
289 /**
290  * Get an array of data for a given row from the internal data cache
291  *  @param {object} oSettings dataTables settings object
292  *  @param {int} iRow aoData row id
293  *  @param {string} sSpecific data get type ('type' 'filter' 'sort')
294  *  @param {array} aiColumns Array of column indexes to get data from
295  *  @returns {array} Data array
296  *  @memberof DataTable#oApi
297  */
298 function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
299 {
300         var out = [];
301         for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
302         {
303                 out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
304         }
305         return out;
306 }
307
308
309 /**
310  * Get the data for a given cell from the internal cache, taking into account data mapping
311  *  @param {object} oSettings dataTables settings object
312  *  @param {int} iRow aoData row id
313  *  @param {int} iCol Column index
314  *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
315  *  @returns {*} Cell data
316  *  @memberof DataTable#oApi
317  */
318 function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
319 {
320         var sData;
321         var oCol = oSettings.aoColumns[iCol];
322         var oData = oSettings.aoData[iRow]._aData;
323
324         if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
325         {
326                 if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
327                 {
328                         _fnLog( oSettings, 0, "Requested unknown parameter "+
329                                 (typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
330                                 " from the data source for row "+iRow );
331                         oSettings.iDrawError = oSettings.iDraw;
332                 }
333                 return oCol.sDefaultContent;
334         }
335
336         /* When the data source is null, we can use default column data */
337         if ( sData === null && oCol.sDefaultContent !== null )
338         {
339                 sData = oCol.sDefaultContent;
340         }
341         else if ( typeof sData === 'function' )
342         {
343                 /* If the data source is a function, then we run it and use the return */
344                 return sData();
345         }
346
347         if ( sSpecific == 'display' && sData === null )
348         {
349                 return '';
350         }
351         return sData;
352 }
353
354
355 /**
356  * Set the value for a specific cell, into the internal data cache
357  *  @param {object} oSettings dataTables settings object
358  *  @param {int} iRow aoData row id
359  *  @param {int} iCol Column index
360  *  @param {*} val Value to set
361  *  @memberof DataTable#oApi
362  */
363 function _fnSetCellData( oSettings, iRow, iCol, val )
364 {
365         var oCol = oSettings.aoColumns[iCol];
366         var oData = oSettings.aoData[iRow]._aData;
367
368         oCol.fnSetData( oData, val );
369 }
370
371
372 // Private variable that is used to match array syntax in the data property object
373 var __reArray = /\[.*?\]$/;
374
375 /**
376  * Return a function that can be used to get data from a source object, taking
377  * into account the ability to use nested objects as a source
378  *  @param {string|int|function} mSource The data source for the object
379  *  @returns {function} Data get function
380  *  @memberof DataTable#oApi
381  */
382 function _fnGetObjectDataFn( mSource )
383 {
384         if ( mSource === null )
385         {
386                 /* Give an empty string for rendering / sorting etc */
387                 return function (data, type) {
388                         return null;
389                 };
390         }
391         else if ( typeof mSource === 'function' )
392         {
393                 return function (data, type, extra) {
394                         return mSource( data, type, extra );
395                 };
396         }
397         else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
398         {
399                 /* If there is a . in the source string then the data source is in a 
400                  * nested object so we loop over the data for each level to get the next
401                  * level down. On each loop we test for undefined, and if found immediately
402                  * return. This allows entire objects to be missing and sDefaultContent to
403                  * be used if defined, rather than throwing an error
404                  */
405                 var fetchData = function (data, type, src) {
406                         var a = src.split('.');
407                         var arrayNotation, out, innerSrc;
408
409                         if ( src !== "" )
410                         {
411                                 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
412                                 {
413                                         // Check if we are dealing with an array notation request
414                                         arrayNotation = a[i].match(__reArray);
415
416                                         if ( arrayNotation ) {
417                                                 a[i] = a[i].replace(__reArray, '');
418
419                                                 // Condition allows simply [] to be passed in
420                                                 if ( a[i] !== "" ) {
421                                                         data = data[ a[i] ];
422                                                 }
423                                                 out = [];
424                                                 
425                                                 // Get the remainder of the nested object to get
426                                                 a.splice( 0, i+1 );
427                                                 innerSrc = a.join('.');
428
429                                                 // Traverse each entry in the array getting the properties requested
430                                                 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
431                                                         out.push( fetchData( data[j], type, innerSrc ) );
432                                                 }
433
434                                                 // If a string is given in between the array notation indicators, that
435                                                 // is used to join the strings together, otherwise an array is returned
436                                                 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
437                                                 data = (join==="") ? out : out.join(join);
438
439                                                 // The inner call to fetchData has already traversed through the remainder
440                                                 // of the source requested, so we exit from the loop
441                                                 break;
442                                         }
443
444                                         if ( data === null || data[ a[i] ] === undefined )
445                                         {
446                                                 return undefined;
447                                         }
448                                         data = data[ a[i] ];
449                                 }
450                         }
451
452                         return data;
453                 };
454
455                 return function (data, type) {
456                         return fetchData( data, type, mSource );
457                 };
458         }
459         else
460         {
461                 /* Array or flat object mapping */
462                 return function (data, type) {
463                         return data[mSource];   
464                 };
465         }
466 }
467
468
469 /**
470  * Return a function that can be used to set data from a source object, taking
471  * into account the ability to use nested objects as a source
472  *  @param {string|int|function} mSource The data source for the object
473  *  @returns {function} Data set function
474  *  @memberof DataTable#oApi
475  */
476 function _fnSetObjectDataFn( mSource )
477 {
478         if ( mSource === null )
479         {
480                 /* Nothing to do when the data source is null */
481                 return function (data, val) {};
482         }
483         else if ( typeof mSource === 'function' )
484         {
485                 return function (data, val) {
486                         mSource( data, 'set', val );
487                 };
488         }
489         else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
490         {
491                 /* Like the get, we need to get data from a nested object */
492                 var setData = function (data, val, src) {
493                         var a = src.split('.'), b;
494                         var arrayNotation, o, innerSrc;
495
496                         for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
497                         {
498                                 // Check if we are dealing with an array notation request
499                                 arrayNotation = a[i].match(__reArray);
500
501                                 if ( arrayNotation )
502                                 {
503                                         a[i] = a[i].replace(__reArray, '');
504                                         data[ a[i] ] = [];
505                                         
506                                         // Get the remainder of the nested object to set so we can recurse
507                                         b = a.slice();
508                                         b.splice( 0, i+1 );
509                                         innerSrc = b.join('.');
510
511                                         // Traverse each entry in the array setting the properties requested
512                                         for ( var j=0, jLen=val.length ; j<jLen ; j++ )
513                                         {
514                                                 o = {};
515                                                 setData( o, val[j], innerSrc );
516                                                 data[ a[i] ].push( o );
517                                         }
518
519                                         // The inner call to setData has already traversed through the remainder
520                                         // of the source and has set the data, thus we can exit here
521                                         return;
522                                 }
523
524                                 // If the nested object doesn't currently exist - since we are
525                                 // trying to set the value - create it
526                                 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
527                                 {
528                                         data[ a[i] ] = {};
529                                 }
530                                 data = data[ a[i] ];
531                         }
532
533                         // If array notation is used, we just want to strip it and use the property name
534                         // and assign the value. If it isn't used, then we get the result we want anyway
535                         data[ a[a.length-1].replace(__reArray, '') ] = val;
536                 };
537
538                 return function (data, val) {
539                         return setData( data, val, mSource );
540                 };
541         }
542         else
543         {
544                 /* Array or flat object mapping */
545                 return function (data, val) {
546                         data[mSource] = val;    
547                 };
548         }
549 }
550
551
552 /**
553  * Return an array with the full table data
554  *  @param {object} oSettings dataTables settings object
555  *  @returns array {array} aData Master data array
556  *  @memberof DataTable#oApi
557  */
558 function _fnGetDataMaster ( oSettings )
559 {
560         var aData = [];
561         var iLen = oSettings.aoData.length;
562         for ( var i=0 ; i<iLen; i++ )
563         {
564                 aData.push( oSettings.aoData[i]._aData );
565         }
566         return aData;
567 }
568
569
570 /**
571  * Nuke the table
572  *  @param {object} oSettings dataTables settings object
573  *  @memberof DataTable#oApi
574  */
575 function _fnClearTable( oSettings )
576 {
577         oSettings.aoData.splice( 0, oSettings.aoData.length );
578         oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
579         oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
580         _fnCalculateEnd( oSettings );
581 }
582
583
584  /**
585  * Take an array of integers (index array) and remove a target integer (value - not 
586  * the key!)
587  *  @param {array} a Index array to target
588  *  @param {int} iTarget value to find
589  *  @memberof DataTable#oApi
590  */
591 function _fnDeleteIndex( a, iTarget )
592 {
593         var iTargetIndex = -1;
594         
595         for ( var i=0, iLen=a.length ; i<iLen ; i++ )
596         {
597                 if ( a[i] == iTarget )
598                 {
599                         iTargetIndex = i;
600                 }
601                 else if ( a[i] > iTarget )
602                 {
603                         a[i]--;
604                 }
605         }
606         
607         if ( iTargetIndex != -1 )
608         {
609                 a.splice( iTargetIndex, 1 );
610         }
611 }
612
613
614  /**
615  * Call the developer defined fnRender function for a given cell (row/column) with
616  * the required parameters and return the result.
617  *  @param {object} oSettings dataTables settings object
618  *  @param {int} iRow aoData index for the row
619  *  @param {int} iCol aoColumns index for the column
620  *  @returns {*} Return of the developer's fnRender function
621  *  @memberof DataTable#oApi
622  */
623 function _fnRender( oSettings, iRow, iCol )
624 {
625         var oCol = oSettings.aoColumns[iCol];
626
627         return oCol.fnRender( {
628                 "iDataRow":    iRow,
629                 "iDataColumn": iCol,
630                 "oSettings":   oSettings,
631                 "aData":       oSettings.aoData[iRow]._aData,
632                 "mDataProp":   oCol.mData
633         }, _fnGetCellData(oSettings, iRow, iCol, 'display') );
634 }