Mercurial > repos > saskia-hiltemann > ireport
comparison DataTables-1.9.4/media/src/core/core.scrolling.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 * Add any control elements for the table - specifically scrolling | |
3 * @param {object} oSettings dataTables settings object | |
4 * @returns {node} Node to add to the DOM | |
5 * @memberof DataTable#oApi | |
6 */ | |
7 function _fnFeatureHtmlTable ( oSettings ) | |
8 { | |
9 /* Check if scrolling is enabled or not - if not then leave the DOM unaltered */ | |
10 if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" ) | |
11 { | |
12 return oSettings.nTable; | |
13 } | |
14 | |
15 /* | |
16 * The HTML structure that we want to generate in this function is: | |
17 * div - nScroller | |
18 * div - nScrollHead | |
19 * div - nScrollHeadInner | |
20 * table - nScrollHeadTable | |
21 * thead - nThead | |
22 * div - nScrollBody | |
23 * table - oSettings.nTable | |
24 * thead - nTheadSize | |
25 * tbody - nTbody | |
26 * div - nScrollFoot | |
27 * div - nScrollFootInner | |
28 * table - nScrollFootTable | |
29 * tfoot - nTfoot | |
30 */ | |
31 var | |
32 nScroller = document.createElement('div'), | |
33 nScrollHead = document.createElement('div'), | |
34 nScrollHeadInner = document.createElement('div'), | |
35 nScrollBody = document.createElement('div'), | |
36 nScrollFoot = document.createElement('div'), | |
37 nScrollFootInner = document.createElement('div'), | |
38 nScrollHeadTable = oSettings.nTable.cloneNode(false), | |
39 nScrollFootTable = oSettings.nTable.cloneNode(false), | |
40 nThead = oSettings.nTable.getElementsByTagName('thead')[0], | |
41 nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : | |
42 oSettings.nTable.getElementsByTagName('tfoot')[0], | |
43 oClasses = oSettings.oClasses; | |
44 | |
45 nScrollHead.appendChild( nScrollHeadInner ); | |
46 nScrollFoot.appendChild( nScrollFootInner ); | |
47 nScrollBody.appendChild( oSettings.nTable ); | |
48 nScroller.appendChild( nScrollHead ); | |
49 nScroller.appendChild( nScrollBody ); | |
50 nScrollHeadInner.appendChild( nScrollHeadTable ); | |
51 nScrollHeadTable.appendChild( nThead ); | |
52 if ( nTfoot !== null ) | |
53 { | |
54 nScroller.appendChild( nScrollFoot ); | |
55 nScrollFootInner.appendChild( nScrollFootTable ); | |
56 nScrollFootTable.appendChild( nTfoot ); | |
57 } | |
58 | |
59 nScroller.className = oClasses.sScrollWrapper; | |
60 nScrollHead.className = oClasses.sScrollHead; | |
61 nScrollHeadInner.className = oClasses.sScrollHeadInner; | |
62 nScrollBody.className = oClasses.sScrollBody; | |
63 nScrollFoot.className = oClasses.sScrollFoot; | |
64 nScrollFootInner.className = oClasses.sScrollFootInner; | |
65 | |
66 if ( oSettings.oScroll.bAutoCss ) | |
67 { | |
68 nScrollHead.style.overflow = "hidden"; | |
69 nScrollHead.style.position = "relative"; | |
70 nScrollFoot.style.overflow = "hidden"; | |
71 nScrollBody.style.overflow = "auto"; | |
72 } | |
73 | |
74 nScrollHead.style.border = "0"; | |
75 nScrollHead.style.width = "100%"; | |
76 nScrollFoot.style.border = "0"; | |
77 nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ? | |
78 oSettings.oScroll.sXInner : "100%"; /* will be overwritten */ | |
79 | |
80 /* Modify attributes to respect the clones */ | |
81 nScrollHeadTable.removeAttribute('id'); | |
82 nScrollHeadTable.style.marginLeft = "0"; | |
83 oSettings.nTable.style.marginLeft = "0"; | |
84 if ( nTfoot !== null ) | |
85 { | |
86 nScrollFootTable.removeAttribute('id'); | |
87 nScrollFootTable.style.marginLeft = "0"; | |
88 } | |
89 | |
90 /* Move caption elements from the body to the header, footer or leave where it is | |
91 * depending on the configuration. Note that the DTD says there can be only one caption */ | |
92 var nCaption = $(oSettings.nTable).children('caption'); | |
93 if ( nCaption.length > 0 ) | |
94 { | |
95 nCaption = nCaption[0]; | |
96 if ( nCaption._captionSide === "top" ) | |
97 { | |
98 nScrollHeadTable.appendChild( nCaption ); | |
99 } | |
100 else if ( nCaption._captionSide === "bottom" && nTfoot ) | |
101 { | |
102 nScrollFootTable.appendChild( nCaption ); | |
103 } | |
104 } | |
105 | |
106 /* | |
107 * Sizing | |
108 */ | |
109 /* When x-scrolling add the width and a scroller to move the header with the body */ | |
110 if ( oSettings.oScroll.sX !== "" ) | |
111 { | |
112 nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX ); | |
113 nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX ); | |
114 | |
115 if ( nTfoot !== null ) | |
116 { | |
117 nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX ); | |
118 } | |
119 | |
120 /* When the body is scrolled, then we also want to scroll the headers */ | |
121 $(nScrollBody).scroll( function (e) { | |
122 nScrollHead.scrollLeft = this.scrollLeft; | |
123 | |
124 if ( nTfoot !== null ) | |
125 { | |
126 nScrollFoot.scrollLeft = this.scrollLeft; | |
127 } | |
128 } ); | |
129 } | |
130 | |
131 /* When yscrolling, add the height */ | |
132 if ( oSettings.oScroll.sY !== "" ) | |
133 { | |
134 nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY ); | |
135 } | |
136 | |
137 /* Redraw - align columns across the tables */ | |
138 oSettings.aoDrawCallback.push( { | |
139 "fn": _fnScrollDraw, | |
140 "sName": "scrolling" | |
141 } ); | |
142 | |
143 /* Infinite scrolling event handlers */ | |
144 if ( oSettings.oScroll.bInfinite ) | |
145 { | |
146 $(nScrollBody).scroll( function() { | |
147 /* Use a blocker to stop scrolling from loading more data while other data is still loading */ | |
148 if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 ) | |
149 { | |
150 /* Check if we should load the next data set */ | |
151 if ( $(this).scrollTop() + $(this).height() > | |
152 $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap ) | |
153 { | |
154 /* Only do the redraw if we have to - we might be at the end of the data */ | |
155 if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() ) | |
156 { | |
157 _fnPageChange( oSettings, 'next' ); | |
158 _fnCalculateEnd( oSettings ); | |
159 _fnDraw( oSettings ); | |
160 } | |
161 } | |
162 } | |
163 } ); | |
164 } | |
165 | |
166 oSettings.nScrollHead = nScrollHead; | |
167 oSettings.nScrollFoot = nScrollFoot; | |
168 | |
169 return nScroller; | |
170 } | |
171 | |
172 | |
173 /** | |
174 * Update the various tables for resizing. It's a bit of a pig this function, but | |
175 * basically the idea to: | |
176 * 1. Re-create the table inside the scrolling div | |
177 * 2. Take live measurements from the DOM | |
178 * 3. Apply the measurements | |
179 * 4. Clean up | |
180 * @param {object} o dataTables settings object | |
181 * @returns {node} Node to add to the DOM | |
182 * @memberof DataTable#oApi | |
183 */ | |
184 function _fnScrollDraw ( o ) | |
185 { | |
186 var | |
187 nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0], | |
188 nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], | |
189 nScrollBody = o.nTable.parentNode, | |
190 i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis, | |
191 nTheadSize, nTfootSize, | |
192 iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth, | |
193 nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null, | |
194 nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null, | |
195 ie67 = o.oBrowser.bScrollOversize, | |
196 zeroOut = function(nSizer) { | |
197 oStyle = nSizer.style; | |
198 oStyle.paddingTop = "0"; | |
199 oStyle.paddingBottom = "0"; | |
200 oStyle.borderTopWidth = "0"; | |
201 oStyle.borderBottomWidth = "0"; | |
202 oStyle.height = 0; | |
203 }; | |
204 | |
205 /* | |
206 * 1. Re-create the table inside the scrolling div | |
207 */ | |
208 | |
209 /* Remove the old minimised thead and tfoot elements in the inner table */ | |
210 $(o.nTable).children('thead, tfoot').remove(); | |
211 | |
212 /* Clone the current header and footer elements and then place it into the inner table */ | |
213 nTheadSize = $(o.nTHead).clone()[0]; | |
214 o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] ); | |
215 anHeadToSize = o.nTHead.getElementsByTagName('tr'); | |
216 anHeadSizers = nTheadSize.getElementsByTagName('tr'); | |
217 | |
218 if ( o.nTFoot !== null ) | |
219 { | |
220 nTfootSize = $(o.nTFoot).clone()[0]; | |
221 o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] ); | |
222 anFootToSize = o.nTFoot.getElementsByTagName('tr'); | |
223 anFootSizers = nTfootSize.getElementsByTagName('tr'); | |
224 } | |
225 | |
226 /* | |
227 * 2. Take live measurements from the DOM - do not alter the DOM itself! | |
228 */ | |
229 | |
230 /* Remove old sizing and apply the calculated column widths | |
231 * Get the unique column headers in the newly created (cloned) header. We want to apply the | |
232 * calculated sizes to this header | |
233 */ | |
234 if ( o.oScroll.sX === "" ) | |
235 { | |
236 nScrollBody.style.width = '100%'; | |
237 nScrollHeadInner.parentNode.style.width = '100%'; | |
238 } | |
239 | |
240 var nThs = _fnGetUniqueThs( o, nTheadSize ); | |
241 for ( i=0, iLen=nThs.length ; i<iLen ; i++ ) | |
242 { | |
243 iVis = _fnVisibleToColumnIndex( o, i ); | |
244 nThs[i].style.width = o.aoColumns[iVis].sWidth; | |
245 } | |
246 | |
247 if ( o.nTFoot !== null ) | |
248 { | |
249 _fnApplyToChildren( function(n) { | |
250 n.style.width = ""; | |
251 }, anFootSizers ); | |
252 } | |
253 | |
254 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we | |
255 // will end up forcing the scrollbar to appear, making our measurements wrong for when we | |
256 // then hide it (end of this function), so add the header height to the body scroller. | |
257 if ( o.oScroll.bCollapse && o.oScroll.sY !== "" ) | |
258 { | |
259 nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px"; | |
260 } | |
261 | |
262 /* Size the table as a whole */ | |
263 iSanityWidth = $(o.nTable).outerWidth(); | |
264 if ( o.oScroll.sX === "" ) | |
265 { | |
266 /* No x scrolling */ | |
267 o.nTable.style.width = "100%"; | |
268 | |
269 /* I know this is rubbish - but IE7 will make the width of the table when 100% include | |
270 * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this | |
271 * into account. | |
272 */ | |
273 if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || | |
274 $(nScrollBody).css('overflow-y') == "scroll") ) | |
275 { | |
276 o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth); | |
277 } | |
278 } | |
279 else | |
280 { | |
281 if ( o.oScroll.sXInner !== "" ) | |
282 { | |
283 /* x scroll inner has been given - use it */ | |
284 o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner); | |
285 } | |
286 else if ( iSanityWidth == $(nScrollBody).width() && | |
287 $(nScrollBody).height() < $(o.nTable).height() ) | |
288 { | |
289 /* There is y-scrolling - try to take account of the y scroll bar */ | |
290 o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth ); | |
291 if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth ) | |
292 { | |
293 /* Not possible to take account of it */ | |
294 o.nTable.style.width = _fnStringToCss( iSanityWidth ); | |
295 } | |
296 } | |
297 else | |
298 { | |
299 /* All else fails */ | |
300 o.nTable.style.width = _fnStringToCss( iSanityWidth ); | |
301 } | |
302 } | |
303 | |
304 /* Recalculate the sanity width - now that we've applied the required width, before it was | |
305 * a temporary variable. This is required because the column width calculation is done | |
306 * before this table DOM is created. | |
307 */ | |
308 iSanityWidth = $(o.nTable).outerWidth(); | |
309 | |
310 /* We want the hidden header to have zero height, so remove padding and borders. Then | |
311 * set the width based on the real headers | |
312 */ | |
313 | |
314 // Apply all styles in one pass. Invalidates layout only once because we don't read any | |
315 // DOM properties. | |
316 _fnApplyToChildren( zeroOut, anHeadSizers ); | |
317 | |
318 // Read all widths in next pass. Forces layout only once because we do not change | |
319 // any DOM properties. | |
320 _fnApplyToChildren( function(nSizer) { | |
321 aApplied.push( _fnStringToCss( $(nSizer).width() ) ); | |
322 }, anHeadSizers ); | |
323 | |
324 // Apply all widths in final pass. Invalidates layout only once because we do not | |
325 // read any DOM properties. | |
326 _fnApplyToChildren( function(nToSize, i) { | |
327 nToSize.style.width = aApplied[i]; | |
328 }, anHeadToSize ); | |
329 | |
330 $(anHeadSizers).height(0); | |
331 | |
332 /* Same again with the footer if we have one */ | |
333 if ( o.nTFoot !== null ) | |
334 { | |
335 _fnApplyToChildren( zeroOut, anFootSizers ); | |
336 | |
337 _fnApplyToChildren( function(nSizer) { | |
338 aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) ); | |
339 }, anFootSizers ); | |
340 | |
341 _fnApplyToChildren( function(nToSize, i) { | |
342 nToSize.style.width = aAppliedFooter[i]; | |
343 }, anFootToSize ); | |
344 | |
345 $(anFootSizers).height(0); | |
346 } | |
347 | |
348 /* | |
349 * 3. Apply the measurements | |
350 */ | |
351 | |
352 /* "Hide" the header and footer that we used for the sizing. We want to also fix their width | |
353 * to what they currently are | |
354 */ | |
355 _fnApplyToChildren( function(nSizer, i) { | |
356 nSizer.innerHTML = ""; | |
357 nSizer.style.width = aApplied[i]; | |
358 }, anHeadSizers ); | |
359 | |
360 if ( o.nTFoot !== null ) | |
361 { | |
362 _fnApplyToChildren( function(nSizer, i) { | |
363 nSizer.innerHTML = ""; | |
364 nSizer.style.width = aAppliedFooter[i]; | |
365 }, anFootSizers ); | |
366 } | |
367 | |
368 /* Sanity check that the table is of a sensible width. If not then we are going to get | |
369 * misalignment - try to prevent this by not allowing the table to shrink below its min width | |
370 */ | |
371 if ( $(o.nTable).outerWidth() < iSanityWidth ) | |
372 { | |
373 /* The min width depends upon if we have a vertical scrollbar visible or not */ | |
374 var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || | |
375 $(nScrollBody).css('overflow-y') == "scroll")) ? | |
376 iSanityWidth+o.oScroll.iBarWidth : iSanityWidth; | |
377 | |
378 /* IE6/7 are a law unto themselves... */ | |
379 if ( ie67 && (nScrollBody.scrollHeight > | |
380 nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") ) | |
381 { | |
382 o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth ); | |
383 } | |
384 | |
385 /* Apply the calculated minimum width to the table wrappers */ | |
386 nScrollBody.style.width = _fnStringToCss( iCorrection ); | |
387 o.nScrollHead.style.width = _fnStringToCss( iCorrection ); | |
388 | |
389 if ( o.nTFoot !== null ) | |
390 { | |
391 o.nScrollFoot.style.width = _fnStringToCss( iCorrection ); | |
392 } | |
393 | |
394 /* And give the user a warning that we've stopped the table getting too small */ | |
395 if ( o.oScroll.sX === "" ) | |
396 { | |
397 _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ | |
398 " misalignment. The table has been drawn at its minimum possible width." ); | |
399 } | |
400 else if ( o.oScroll.sXInner !== "" ) | |
401 { | |
402 _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ | |
403 " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+ | |
404 " calculation" ); | |
405 } | |
406 } | |
407 else | |
408 { | |
409 nScrollBody.style.width = _fnStringToCss( '100%' ); | |
410 o.nScrollHead.style.width = _fnStringToCss( '100%' ); | |
411 | |
412 if ( o.nTFoot !== null ) | |
413 { | |
414 o.nScrollFoot.style.width = _fnStringToCss( '100%' ); | |
415 } | |
416 } | |
417 | |
418 | |
419 /* | |
420 * 4. Clean up | |
421 */ | |
422 if ( o.oScroll.sY === "" ) | |
423 { | |
424 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting | |
425 * the scrollbar height from the visible display, rather than adding it on. We need to | |
426 * set the height in order to sort this. Don't want to do it in any other browsers. | |
427 */ | |
428 if ( ie67 ) | |
429 { | |
430 nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth ); | |
431 } | |
432 } | |
433 | |
434 if ( o.oScroll.sY !== "" && o.oScroll.bCollapse ) | |
435 { | |
436 nScrollBody.style.height = _fnStringToCss( o.oScroll.sY ); | |
437 | |
438 var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ? | |
439 o.oScroll.iBarWidth : 0; | |
440 if ( o.nTable.offsetHeight < nScrollBody.offsetHeight ) | |
441 { | |
442 nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra ); | |
443 } | |
444 } | |
445 | |
446 /* Finally set the width's of the header and footer tables */ | |
447 var iOuterWidth = $(o.nTable).outerWidth(); | |
448 nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth ); | |
449 nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth ); | |
450 | |
451 // Figure out if there are scrollbar present - if so then we need a the header and footer to | |
452 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) | |
453 var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll"; | |
454 nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; | |
455 | |
456 if ( o.nTFoot !== null ) | |
457 { | |
458 nScrollFootTable.style.width = _fnStringToCss( iOuterWidth ); | |
459 nScrollFootInner.style.width = _fnStringToCss( iOuterWidth ); | |
460 nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; | |
461 } | |
462 | |
463 /* Adjust the position of the header in case we loose the y-scrollbar */ | |
464 $(nScrollBody).scroll(); | |
465 | |
466 /* If sorting or filtering has occurred, jump the scrolling back to the top */ | |
467 if ( o.bSorted || o.bFiltered ) | |
468 { | |
469 nScrollBody.scrollTop = 0; | |
470 } | |
471 } | |
472 | |
473 | |
474 /** | |
475 * Apply a given function to the display child nodes of an element array (typically | |
476 * TD children of TR rows | |
477 * @param {function} fn Method to apply to the objects | |
478 * @param array {nodes} an1 List of elements to look through for display children | |
479 * @param array {nodes} an2 Another list (identical structure to the first) - optional | |
480 * @memberof DataTable#oApi | |
481 */ | |
482 function _fnApplyToChildren( fn, an1, an2 ) | |
483 { | |
484 var index=0, i=0, iLen=an1.length; | |
485 var nNode1, nNode2; | |
486 | |
487 while ( i < iLen ) | |
488 { | |
489 nNode1 = an1[i].firstChild; | |
490 nNode2 = an2 ? an2[i].firstChild : null; | |
491 while ( nNode1 ) | |
492 { | |
493 if ( nNode1.nodeType === 1 ) | |
494 { | |
495 if ( an2 ) | |
496 { | |
497 fn( nNode1, nNode2, index ); | |
498 } | |
499 else | |
500 { | |
501 fn( nNode1, index ); | |
502 } | |
503 index++; | |
504 } | |
505 nNode1 = nNode1.nextSibling; | |
506 nNode2 = an2 ? nNode2.nextSibling : null; | |
507 } | |
508 i++; | |
509 } | |
510 } | |
511 |