Mercurial > repos > saskia-hiltemann > ireport
comparison DataTables-1.9.4/media/src/core/core.draw.js @ 0:ac5f9272033b draft
first upload
author | saskia-hiltemann |
---|---|
date | Tue, 01 Jul 2014 11:42:23 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:ac5f9272033b |
---|---|
1 /** | |
2 * Create a new TR element (and it's TD children) for a row | |
3 * @param {object} oSettings dataTables settings object | |
4 * @param {int} iRow Row to consider | |
5 * @memberof DataTable#oApi | |
6 */ | |
7 function _fnCreateTr ( oSettings, iRow ) | |
8 { | |
9 var oData = oSettings.aoData[iRow]; | |
10 var nTd; | |
11 | |
12 if ( oData.nTr === null ) | |
13 { | |
14 oData.nTr = document.createElement('tr'); | |
15 | |
16 /* Use a private property on the node to allow reserve mapping from the node | |
17 * to the aoData array for fast look up | |
18 */ | |
19 oData.nTr._DT_RowIndex = iRow; | |
20 | |
21 /* Special parameters can be given by the data source to be used on the row */ | |
22 if ( oData._aData.DT_RowId ) | |
23 { | |
24 oData.nTr.id = oData._aData.DT_RowId; | |
25 } | |
26 | |
27 if ( oData._aData.DT_RowClass ) | |
28 { | |
29 oData.nTr.className = oData._aData.DT_RowClass; | |
30 } | |
31 | |
32 /* Process each column */ | |
33 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) | |
34 { | |
35 var oCol = oSettings.aoColumns[i]; | |
36 nTd = document.createElement( oCol.sCellType ); | |
37 | |
38 /* Render if needed - if bUseRendered is true then we already have the rendered | |
39 * value in the data source - so can just use that | |
40 */ | |
41 nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ? | |
42 _fnRender( oSettings, iRow, i ) : | |
43 _fnGetCellData( oSettings, iRow, i, 'display' ); | |
44 | |
45 /* Add user defined class */ | |
46 if ( oCol.sClass !== null ) | |
47 { | |
48 nTd.className = oCol.sClass; | |
49 } | |
50 | |
51 if ( oCol.bVisible ) | |
52 { | |
53 oData.nTr.appendChild( nTd ); | |
54 oData._anHidden[i] = null; | |
55 } | |
56 else | |
57 { | |
58 oData._anHidden[i] = nTd; | |
59 } | |
60 | |
61 if ( oCol.fnCreatedCell ) | |
62 { | |
63 oCol.fnCreatedCell.call( oSettings.oInstance, | |
64 nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i | |
65 ); | |
66 } | |
67 } | |
68 | |
69 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] ); | |
70 } | |
71 } | |
72 | |
73 | |
74 /** | |
75 * Create the HTML header for the table | |
76 * @param {object} oSettings dataTables settings object | |
77 * @memberof DataTable#oApi | |
78 */ | |
79 function _fnBuildHead( oSettings ) | |
80 { | |
81 var i, nTh, iLen, j, jLen; | |
82 var iThs = $('th, td', oSettings.nTHead).length; | |
83 var iCorrector = 0; | |
84 var jqChildren; | |
85 | |
86 /* If there is a header in place - then use it - otherwise it's going to get nuked... */ | |
87 if ( iThs !== 0 ) | |
88 { | |
89 /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */ | |
90 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) | |
91 { | |
92 nTh = oSettings.aoColumns[i].nTh; | |
93 nTh.setAttribute('role', 'columnheader'); | |
94 if ( oSettings.aoColumns[i].bSortable ) | |
95 { | |
96 nTh.setAttribute('tabindex', oSettings.iTabIndex); | |
97 nTh.setAttribute('aria-controls', oSettings.sTableId); | |
98 } | |
99 | |
100 if ( oSettings.aoColumns[i].sClass !== null ) | |
101 { | |
102 $(nTh).addClass( oSettings.aoColumns[i].sClass ); | |
103 } | |
104 | |
105 /* Set the title of the column if it is user defined (not what was auto detected) */ | |
106 if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML ) | |
107 { | |
108 nTh.innerHTML = oSettings.aoColumns[i].sTitle; | |
109 } | |
110 } | |
111 } | |
112 else | |
113 { | |
114 /* We don't have a header in the DOM - so we are going to have to create one */ | |
115 var nTr = document.createElement( "tr" ); | |
116 | |
117 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) | |
118 { | |
119 nTh = oSettings.aoColumns[i].nTh; | |
120 nTh.innerHTML = oSettings.aoColumns[i].sTitle; | |
121 nTh.setAttribute('tabindex', '0'); | |
122 | |
123 if ( oSettings.aoColumns[i].sClass !== null ) | |
124 { | |
125 $(nTh).addClass( oSettings.aoColumns[i].sClass ); | |
126 } | |
127 | |
128 nTr.appendChild( nTh ); | |
129 } | |
130 $(oSettings.nTHead).html( '' )[0].appendChild( nTr ); | |
131 _fnDetectHeader( oSettings.aoHeader, oSettings.nTHead ); | |
132 } | |
133 | |
134 /* ARIA role for the rows */ | |
135 $(oSettings.nTHead).children('tr').attr('role', 'row'); | |
136 | |
137 /* Add the extra markup needed by jQuery UI's themes */ | |
138 if ( oSettings.bJUI ) | |
139 { | |
140 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) | |
141 { | |
142 nTh = oSettings.aoColumns[i].nTh; | |
143 | |
144 var nDiv = document.createElement('div'); | |
145 nDiv.className = oSettings.oClasses.sSortJUIWrapper; | |
146 $(nTh).contents().appendTo(nDiv); | |
147 | |
148 var nSpan = document.createElement('span'); | |
149 nSpan.className = oSettings.oClasses.sSortIcon; | |
150 nDiv.appendChild( nSpan ); | |
151 nTh.appendChild( nDiv ); | |
152 } | |
153 } | |
154 | |
155 if ( oSettings.oFeatures.bSort ) | |
156 { | |
157 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) | |
158 { | |
159 if ( oSettings.aoColumns[i].bSortable !== false ) | |
160 { | |
161 _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i ); | |
162 } | |
163 else | |
164 { | |
165 $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone ); | |
166 } | |
167 } | |
168 } | |
169 | |
170 /* Deal with the footer - add classes if required */ | |
171 if ( oSettings.oClasses.sFooterTH !== "" ) | |
172 { | |
173 $(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH ); | |
174 } | |
175 | |
176 /* Cache the footer elements */ | |
177 if ( oSettings.nTFoot !== null ) | |
178 { | |
179 var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter ); | |
180 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) | |
181 { | |
182 if ( anCells[i] ) | |
183 { | |
184 oSettings.aoColumns[i].nTf = anCells[i]; | |
185 if ( oSettings.aoColumns[i].sClass ) | |
186 { | |
187 $(anCells[i]).addClass( oSettings.aoColumns[i].sClass ); | |
188 } | |
189 } | |
190 } | |
191 } | |
192 } | |
193 | |
194 | |
195 /** | |
196 * Draw the header (or footer) element based on the column visibility states. The | |
197 * methodology here is to use the layout array from _fnDetectHeader, modified for | |
198 * the instantaneous column visibility, to construct the new layout. The grid is | |
199 * traversed over cell at a time in a rows x columns grid fashion, although each | |
200 * cell insert can cover multiple elements in the grid - which is tracks using the | |
201 * aApplied array. Cell inserts in the grid will only occur where there isn't | |
202 * already a cell in that position. | |
203 * @param {object} oSettings dataTables settings object | |
204 * @param array {objects} aoSource Layout array from _fnDetectHeader | |
205 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, | |
206 * @memberof DataTable#oApi | |
207 */ | |
208 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) | |
209 { | |
210 var i, iLen, j, jLen, k, kLen, n, nLocalTr; | |
211 var aoLocal = []; | |
212 var aApplied = []; | |
213 var iColumns = oSettings.aoColumns.length; | |
214 var iRowspan, iColspan; | |
215 | |
216 if ( bIncludeHidden === undefined ) | |
217 { | |
218 bIncludeHidden = false; | |
219 } | |
220 | |
221 /* Make a copy of the master layout array, but without the visible columns in it */ | |
222 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) | |
223 { | |
224 aoLocal[i] = aoSource[i].slice(); | |
225 aoLocal[i].nTr = aoSource[i].nTr; | |
226 | |
227 /* Remove any columns which are currently hidden */ | |
228 for ( j=iColumns-1 ; j>=0 ; j-- ) | |
229 { | |
230 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) | |
231 { | |
232 aoLocal[i].splice( j, 1 ); | |
233 } | |
234 } | |
235 | |
236 /* Prep the applied array - it needs an element for each row */ | |
237 aApplied.push( [] ); | |
238 } | |
239 | |
240 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) | |
241 { | |
242 nLocalTr = aoLocal[i].nTr; | |
243 | |
244 /* All cells are going to be replaced, so empty out the row */ | |
245 if ( nLocalTr ) | |
246 { | |
247 while( (n = nLocalTr.firstChild) ) | |
248 { | |
249 nLocalTr.removeChild( n ); | |
250 } | |
251 } | |
252 | |
253 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) | |
254 { | |
255 iRowspan = 1; | |
256 iColspan = 1; | |
257 | |
258 /* Check to see if there is already a cell (row/colspan) covering our target | |
259 * insert point. If there is, then there is nothing to do. | |
260 */ | |
261 if ( aApplied[i][j] === undefined ) | |
262 { | |
263 nLocalTr.appendChild( aoLocal[i][j].cell ); | |
264 aApplied[i][j] = 1; | |
265 | |
266 /* Expand the cell to cover as many rows as needed */ | |
267 while ( aoLocal[i+iRowspan] !== undefined && | |
268 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) | |
269 { | |
270 aApplied[i+iRowspan][j] = 1; | |
271 iRowspan++; | |
272 } | |
273 | |
274 /* Expand the cell to cover as many columns as needed */ | |
275 while ( aoLocal[i][j+iColspan] !== undefined && | |
276 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) | |
277 { | |
278 /* Must update the applied array over the rows for the columns */ | |
279 for ( k=0 ; k<iRowspan ; k++ ) | |
280 { | |
281 aApplied[i+k][j+iColspan] = 1; | |
282 } | |
283 iColspan++; | |
284 } | |
285 | |
286 /* Do the actual expansion in the DOM */ | |
287 aoLocal[i][j].cell.rowSpan = iRowspan; | |
288 aoLocal[i][j].cell.colSpan = iColspan; | |
289 } | |
290 } | |
291 } | |
292 } | |
293 | |
294 | |
295 /** | |
296 * Insert the required TR nodes into the table for display | |
297 * @param {object} oSettings dataTables settings object | |
298 * @memberof DataTable#oApi | |
299 */ | |
300 function _fnDraw( oSettings ) | |
301 { | |
302 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ | |
303 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); | |
304 if ( $.inArray( false, aPreDraw ) !== -1 ) | |
305 { | |
306 _fnProcessingDisplay( oSettings, false ); | |
307 return; | |
308 } | |
309 | |
310 var i, iLen, n; | |
311 var anRows = []; | |
312 var iRowCount = 0; | |
313 var iStripes = oSettings.asStripeClasses.length; | |
314 var iOpenRows = oSettings.aoOpenRows.length; | |
315 | |
316 oSettings.bDrawing = true; | |
317 | |
318 /* Check and see if we have an initial draw position from state saving */ | |
319 if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 ) | |
320 { | |
321 if ( oSettings.oFeatures.bServerSide ) | |
322 { | |
323 oSettings._iDisplayStart = oSettings.iInitDisplayStart; | |
324 } | |
325 else | |
326 { | |
327 oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ? | |
328 0 : oSettings.iInitDisplayStart; | |
329 } | |
330 oSettings.iInitDisplayStart = -1; | |
331 _fnCalculateEnd( oSettings ); | |
332 } | |
333 | |
334 /* Server-side processing draw intercept */ | |
335 if ( oSettings.bDeferLoading ) | |
336 { | |
337 oSettings.bDeferLoading = false; | |
338 oSettings.iDraw++; | |
339 } | |
340 else if ( !oSettings.oFeatures.bServerSide ) | |
341 { | |
342 oSettings.iDraw++; | |
343 } | |
344 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) | |
345 { | |
346 return; | |
347 } | |
348 | |
349 if ( oSettings.aiDisplay.length !== 0 ) | |
350 { | |
351 var iStart = oSettings._iDisplayStart; | |
352 var iEnd = oSettings._iDisplayEnd; | |
353 | |
354 if ( oSettings.oFeatures.bServerSide ) | |
355 { | |
356 iStart = 0; | |
357 iEnd = oSettings.aoData.length; | |
358 } | |
359 | |
360 for ( var j=iStart ; j<iEnd ; j++ ) | |
361 { | |
362 var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ]; | |
363 if ( aoData.nTr === null ) | |
364 { | |
365 _fnCreateTr( oSettings, oSettings.aiDisplay[j] ); | |
366 } | |
367 | |
368 var nRow = aoData.nTr; | |
369 | |
370 /* Remove the old striping classes and then add the new one */ | |
371 if ( iStripes !== 0 ) | |
372 { | |
373 var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ]; | |
374 if ( aoData._sRowStripe != sStripe ) | |
375 { | |
376 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); | |
377 aoData._sRowStripe = sStripe; | |
378 } | |
379 } | |
380 | |
381 /* Row callback functions - might want to manipulate the row */ | |
382 _fnCallbackFire( oSettings, 'aoRowCallback', null, | |
383 [nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] ); | |
384 | |
385 anRows.push( nRow ); | |
386 iRowCount++; | |
387 | |
388 /* If there is an open row - and it is attached to this parent - attach it on redraw */ | |
389 if ( iOpenRows !== 0 ) | |
390 { | |
391 for ( var k=0 ; k<iOpenRows ; k++ ) | |
392 { | |
393 if ( nRow == oSettings.aoOpenRows[k].nParent ) | |
394 { | |
395 anRows.push( oSettings.aoOpenRows[k].nTr ); | |
396 break; | |
397 } | |
398 } | |
399 } | |
400 } | |
401 } | |
402 else | |
403 { | |
404 /* Table is empty - create a row with an empty message in it */ | |
405 anRows[ 0 ] = document.createElement( 'tr' ); | |
406 | |
407 if ( oSettings.asStripeClasses[0] ) | |
408 { | |
409 anRows[ 0 ].className = oSettings.asStripeClasses[0]; | |
410 } | |
411 | |
412 var oLang = oSettings.oLanguage; | |
413 var sZero = oLang.sZeroRecords; | |
414 if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide ) | |
415 { | |
416 sZero = oLang.sLoadingRecords; | |
417 } | |
418 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) | |
419 { | |
420 sZero = oLang.sEmptyTable; | |
421 } | |
422 | |
423 var nTd = document.createElement( 'td' ); | |
424 nTd.setAttribute( 'valign', "top" ); | |
425 nTd.colSpan = _fnVisbleColumns( oSettings ); | |
426 nTd.className = oSettings.oClasses.sRowEmpty; | |
427 nTd.innerHTML = _fnInfoMacros( oSettings, sZero ); | |
428 | |
429 anRows[ iRowCount ].appendChild( nTd ); | |
430 } | |
431 | |
432 /* Header and footer callbacks */ | |
433 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], | |
434 _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] ); | |
435 | |
436 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], | |
437 _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] ); | |
438 | |
439 /* | |
440 * Need to remove any old row from the display - note we can't just empty the tbody using | |
441 * $().html('') since this will unbind the jQuery event handlers (even although the node | |
442 * still exists!) - equally we can't use innerHTML, since IE throws an exception. | |
443 */ | |
444 var | |
445 nAddFrag = document.createDocumentFragment(), | |
446 nRemoveFrag = document.createDocumentFragment(), | |
447 nBodyPar, nTrs; | |
448 | |
449 if ( oSettings.nTBody ) | |
450 { | |
451 nBodyPar = oSettings.nTBody.parentNode; | |
452 nRemoveFrag.appendChild( oSettings.nTBody ); | |
453 | |
454 /* When doing infinite scrolling, only remove child rows when sorting, filtering or start | |
455 * up. When not infinite scroll, always do it. | |
456 */ | |
457 if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete || | |
458 oSettings.bSorted || oSettings.bFiltered ) | |
459 { | |
460 while( (n = oSettings.nTBody.firstChild) ) | |
461 { | |
462 oSettings.nTBody.removeChild( n ); | |
463 } | |
464 } | |
465 | |
466 /* Put the draw table into the dom */ | |
467 for ( i=0, iLen=anRows.length ; i<iLen ; i++ ) | |
468 { | |
469 nAddFrag.appendChild( anRows[i] ); | |
470 } | |
471 | |
472 oSettings.nTBody.appendChild( nAddFrag ); | |
473 if ( nBodyPar !== null ) | |
474 { | |
475 nBodyPar.appendChild( oSettings.nTBody ); | |
476 } | |
477 } | |
478 | |
479 /* Call all required callback functions for the end of a draw */ | |
480 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); | |
481 | |
482 /* Draw is complete, sorting and filtering must be as well */ | |
483 oSettings.bSorted = false; | |
484 oSettings.bFiltered = false; | |
485 oSettings.bDrawing = false; | |
486 | |
487 if ( oSettings.oFeatures.bServerSide ) | |
488 { | |
489 _fnProcessingDisplay( oSettings, false ); | |
490 if ( !oSettings._bInitComplete ) | |
491 { | |
492 _fnInitComplete( oSettings ); | |
493 } | |
494 } | |
495 } | |
496 | |
497 | |
498 /** | |
499 * Redraw the table - taking account of the various features which are enabled | |
500 * @param {object} oSettings dataTables settings object | |
501 * @memberof DataTable#oApi | |
502 */ | |
503 function _fnReDraw( oSettings ) | |
504 { | |
505 if ( oSettings.oFeatures.bSort ) | |
506 { | |
507 /* Sorting will refilter and draw for us */ | |
508 _fnSort( oSettings, oSettings.oPreviousSearch ); | |
509 } | |
510 else if ( oSettings.oFeatures.bFilter ) | |
511 { | |
512 /* Filtering will redraw for us */ | |
513 _fnFilterComplete( oSettings, oSettings.oPreviousSearch ); | |
514 } | |
515 else | |
516 { | |
517 _fnCalculateEnd( oSettings ); | |
518 _fnDraw( oSettings ); | |
519 } | |
520 } | |
521 | |
522 | |
523 /** | |
524 * Add the options to the page HTML for the table | |
525 * @param {object} oSettings dataTables settings object | |
526 * @memberof DataTable#oApi | |
527 */ | |
528 function _fnAddOptionsHtml ( oSettings ) | |
529 { | |
530 /* | |
531 * Create a temporary, empty, div which we can later on replace with what we have generated | |
532 * we do it this way to rendering the 'options' html offline - speed :-) | |
533 */ | |
534 var nHolding = $('<div></div>')[0]; | |
535 oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable ); | |
536 | |
537 /* | |
538 * All DataTables are wrapped in a div | |
539 */ | |
540 oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0]; | |
541 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; | |
542 | |
543 /* Track where we want to insert the option */ | |
544 var nInsertNode = oSettings.nTableWrapper; | |
545 | |
546 /* Loop over the user set positioning and place the elements as needed */ | |
547 var aDom = oSettings.sDom.split(''); | |
548 var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j; | |
549 for ( var i=0 ; i<aDom.length ; i++ ) | |
550 { | |
551 iPushFeature = 0; | |
552 cOption = aDom[i]; | |
553 | |
554 if ( cOption == '<' ) | |
555 { | |
556 /* New container div */ | |
557 nNewNode = $('<div></div>')[0]; | |
558 | |
559 /* Check to see if we should append an id and/or a class name to the container */ | |
560 cNext = aDom[i+1]; | |
561 if ( cNext == "'" || cNext == '"' ) | |
562 { | |
563 sAttr = ""; | |
564 j = 2; | |
565 while ( aDom[i+j] != cNext ) | |
566 { | |
567 sAttr += aDom[i+j]; | |
568 j++; | |
569 } | |
570 | |
571 /* Replace jQuery UI constants */ | |
572 if ( sAttr == "H" ) | |
573 { | |
574 sAttr = oSettings.oClasses.sJUIHeader; | |
575 } | |
576 else if ( sAttr == "F" ) | |
577 { | |
578 sAttr = oSettings.oClasses.sJUIFooter; | |
579 } | |
580 | |
581 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic | |
582 * breaks the string into parts and applies them as needed | |
583 */ | |
584 if ( sAttr.indexOf('.') != -1 ) | |
585 { | |
586 var aSplit = sAttr.split('.'); | |
587 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); | |
588 nNewNode.className = aSplit[1]; | |
589 } | |
590 else if ( sAttr.charAt(0) == "#" ) | |
591 { | |
592 nNewNode.id = sAttr.substr(1, sAttr.length-1); | |
593 } | |
594 else | |
595 { | |
596 nNewNode.className = sAttr; | |
597 } | |
598 | |
599 i += j; /* Move along the position array */ | |
600 } | |
601 | |
602 nInsertNode.appendChild( nNewNode ); | |
603 nInsertNode = nNewNode; | |
604 } | |
605 else if ( cOption == '>' ) | |
606 { | |
607 /* End container div */ | |
608 nInsertNode = nInsertNode.parentNode; | |
609 } | |
610 else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange ) | |
611 { | |
612 /* Length */ | |
613 nTmp = _fnFeatureHtmlLength( oSettings ); | |
614 iPushFeature = 1; | |
615 } | |
616 else if ( cOption == 'f' && oSettings.oFeatures.bFilter ) | |
617 { | |
618 /* Filter */ | |
619 nTmp = _fnFeatureHtmlFilter( oSettings ); | |
620 iPushFeature = 1; | |
621 } | |
622 else if ( cOption == 'r' && oSettings.oFeatures.bProcessing ) | |
623 { | |
624 /* pRocessing */ | |
625 nTmp = _fnFeatureHtmlProcessing( oSettings ); | |
626 iPushFeature = 1; | |
627 } | |
628 else if ( cOption == 't' ) | |
629 { | |
630 /* Table */ | |
631 nTmp = _fnFeatureHtmlTable( oSettings ); | |
632 iPushFeature = 1; | |
633 } | |
634 else if ( cOption == 'i' && oSettings.oFeatures.bInfo ) | |
635 { | |
636 /* Info */ | |
637 nTmp = _fnFeatureHtmlInfo( oSettings ); | |
638 iPushFeature = 1; | |
639 } | |
640 else if ( cOption == 'p' && oSettings.oFeatures.bPaginate ) | |
641 { | |
642 /* Pagination */ | |
643 nTmp = _fnFeatureHtmlPaginate( oSettings ); | |
644 iPushFeature = 1; | |
645 } | |
646 else if ( DataTable.ext.aoFeatures.length !== 0 ) | |
647 { | |
648 /* Plug-in features */ | |
649 var aoFeatures = DataTable.ext.aoFeatures; | |
650 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) | |
651 { | |
652 if ( cOption == aoFeatures[k].cFeature ) | |
653 { | |
654 nTmp = aoFeatures[k].fnInit( oSettings ); | |
655 if ( nTmp ) | |
656 { | |
657 iPushFeature = 1; | |
658 } | |
659 break; | |
660 } | |
661 } | |
662 } | |
663 | |
664 /* Add to the 2D features array */ | |
665 if ( iPushFeature == 1 && nTmp !== null ) | |
666 { | |
667 if ( typeof oSettings.aanFeatures[cOption] !== 'object' ) | |
668 { | |
669 oSettings.aanFeatures[cOption] = []; | |
670 } | |
671 oSettings.aanFeatures[cOption].push( nTmp ); | |
672 nInsertNode.appendChild( nTmp ); | |
673 } | |
674 } | |
675 | |
676 /* Built our DOM structure - replace the holding div with what we want */ | |
677 nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding ); | |
678 } | |
679 | |
680 | |
681 /** | |
682 * Use the DOM source to create up an array of header cells. The idea here is to | |
683 * create a layout grid (array) of rows x columns, which contains a reference | |
684 * to the cell that that point in the grid (regardless of col/rowspan), such that | |
685 * any column / row could be removed and the new grid constructed | |
686 * @param array {object} aLayout Array to store the calculated layout in | |
687 * @param {node} nThead The header/footer element for the table | |
688 * @memberof DataTable#oApi | |
689 */ | |
690 function _fnDetectHeader ( aLayout, nThead ) | |
691 { | |
692 var nTrs = $(nThead).children('tr'); | |
693 var nTr, nCell; | |
694 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; | |
695 var bUnique; | |
696 var fnShiftCol = function ( a, i, j ) { | |
697 var k = a[i]; | |
698 while ( k[j] ) { | |
699 j++; | |
700 } | |
701 return j; | |
702 }; | |
703 | |
704 aLayout.splice( 0, aLayout.length ); | |
705 | |
706 /* We know how many rows there are in the layout - so prep it */ | |
707 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) | |
708 { | |
709 aLayout.push( [] ); | |
710 } | |
711 | |
712 /* Calculate a layout array */ | |
713 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) | |
714 { | |
715 nTr = nTrs[i]; | |
716 iColumn = 0; | |
717 | |
718 /* For every cell in the row... */ | |
719 nCell = nTr.firstChild; | |
720 while ( nCell ) { | |
721 if ( nCell.nodeName.toUpperCase() == "TD" || | |
722 nCell.nodeName.toUpperCase() == "TH" ) | |
723 { | |
724 /* Get the col and rowspan attributes from the DOM and sanitise them */ | |
725 iColspan = nCell.getAttribute('colspan') * 1; | |
726 iRowspan = nCell.getAttribute('rowspan') * 1; | |
727 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; | |
728 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; | |
729 | |
730 /* There might be colspan cells already in this row, so shift our target | |
731 * accordingly | |
732 */ | |
733 iColShifted = fnShiftCol( aLayout, i, iColumn ); | |
734 | |
735 /* Cache calculation for unique columns */ | |
736 bUnique = iColspan === 1 ? true : false; | |
737 | |
738 /* If there is col / rowspan, copy the information into the layout grid */ | |
739 for ( l=0 ; l<iColspan ; l++ ) | |
740 { | |
741 for ( k=0 ; k<iRowspan ; k++ ) | |
742 { | |
743 aLayout[i+k][iColShifted+l] = { | |
744 "cell": nCell, | |
745 "unique": bUnique | |
746 }; | |
747 aLayout[i+k].nTr = nTr; | |
748 } | |
749 } | |
750 } | |
751 nCell = nCell.nextSibling; | |
752 } | |
753 } | |
754 } | |
755 | |
756 | |
757 /** | |
758 * Get an array of unique th elements, one for each column | |
759 * @param {object} oSettings dataTables settings object | |
760 * @param {node} nHeader automatically detect the layout from this node - optional | |
761 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional | |
762 * @returns array {node} aReturn list of unique th's | |
763 * @memberof DataTable#oApi | |
764 */ | |
765 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) | |
766 { | |
767 var aReturn = []; | |
768 if ( !aLayout ) | |
769 { | |
770 aLayout = oSettings.aoHeader; | |
771 if ( nHeader ) | |
772 { | |
773 aLayout = []; | |
774 _fnDetectHeader( aLayout, nHeader ); | |
775 } | |
776 } | |
777 | |
778 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) | |
779 { | |
780 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) | |
781 { | |
782 if ( aLayout[i][j].unique && | |
783 (!aReturn[j] || !oSettings.bSortCellsTop) ) | |
784 { | |
785 aReturn[j] = aLayout[i][j].cell; | |
786 } | |
787 } | |
788 } | |
789 | |
790 return aReturn; | |
791 } | |
792 |