comparison DataTables-1.9.4/media/src/core/core.sizing.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 * Convert a CSS unit width to pixels (e.g. 2em)
3 * @param {string} sWidth width to be converted
4 * @param {node} nParent parent to get the with for (required for relative widths) - optional
5 * @returns {int} iWidth width in pixels
6 * @memberof DataTable#oApi
7 */
8 function _fnConvertToWidth ( sWidth, nParent )
9 {
10 if ( !sWidth || sWidth === null || sWidth === '' )
11 {
12 return 0;
13 }
14
15 if ( !nParent )
16 {
17 nParent = document.body;
18 }
19
20 var iWidth;
21 var nTmp = document.createElement( "div" );
22 nTmp.style.width = _fnStringToCss( sWidth );
23
24 nParent.appendChild( nTmp );
25 iWidth = nTmp.offsetWidth;
26 nParent.removeChild( nTmp );
27
28 return ( iWidth );
29 }
30
31
32 /**
33 * Calculate the width of columns for the table
34 * @param {object} oSettings dataTables settings object
35 * @memberof DataTable#oApi
36 */
37 function _fnCalculateColumnWidths ( oSettings )
38 {
39 var iTableWidth = oSettings.nTable.offsetWidth;
40 var iUserInputs = 0;
41 var iTmpWidth;
42 var iVisibleColumns = 0;
43 var iColums = oSettings.aoColumns.length;
44 var i, iIndex, iCorrector, iWidth;
45 var oHeaders = $('th', oSettings.nTHead);
46 var widthAttr = oSettings.nTable.getAttribute('width');
47 var nWrapper = oSettings.nTable.parentNode;
48
49 /* Convert any user input sizes into pixel sizes */
50 for ( i=0 ; i<iColums ; i++ )
51 {
52 if ( oSettings.aoColumns[i].bVisible )
53 {
54 iVisibleColumns++;
55
56 if ( oSettings.aoColumns[i].sWidth !== null )
57 {
58 iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig,
59 nWrapper );
60 if ( iTmpWidth !== null )
61 {
62 oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
63 }
64
65 iUserInputs++;
66 }
67 }
68 }
69
70 /* If the number of columns in the DOM equals the number that we have to process in
71 * DataTables, then we can use the offsets that are created by the web-browser. No custom
72 * sizes can be set in order for this to happen, nor scrolling used
73 */
74 if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
75 oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
76 {
77 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
78 {
79 iTmpWidth = $(oHeaders[i]).width();
80 if ( iTmpWidth !== null )
81 {
82 oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
83 }
84 }
85 }
86 else
87 {
88 /* Otherwise we are going to have to do some calculations to get the width of each column.
89 * Construct a 1 row table with the widest node in the data, and any user defined widths,
90 * then insert it into the DOM and allow the browser to do all the hard work of
91 * calculating table widths.
92 */
93 var
94 nCalcTmp = oSettings.nTable.cloneNode( false ),
95 nTheadClone = oSettings.nTHead.cloneNode(true),
96 nBody = document.createElement( 'tbody' ),
97 nTr = document.createElement( 'tr' ),
98 nDivSizing;
99
100 nCalcTmp.removeAttribute( "id" );
101 nCalcTmp.appendChild( nTheadClone );
102 if ( oSettings.nTFoot !== null )
103 {
104 nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
105 _fnApplyToChildren( function(n) {
106 n.style.width = "";
107 }, nCalcTmp.getElementsByTagName('tr') );
108 }
109
110 nCalcTmp.appendChild( nBody );
111 nBody.appendChild( nTr );
112
113 /* Remove any sizing that was previously applied by the styles */
114 var jqColSizing = $('thead th', nCalcTmp);
115 if ( jqColSizing.length === 0 )
116 {
117 jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
118 }
119
120 /* Apply custom sizing to the cloned header */
121 var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
122 iCorrector = 0;
123 for ( i=0 ; i<iColums ; i++ )
124 {
125 var oColumn = oSettings.aoColumns[i];
126 if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
127 {
128 nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
129 }
130 else if ( oColumn.bVisible )
131 {
132 nThs[i-iCorrector].style.width = "";
133 }
134 else
135 {
136 iCorrector++;
137 }
138 }
139
140 /* Find the biggest td for each column and put it into the table */
141 for ( i=0 ; i<iColums ; i++ )
142 {
143 if ( oSettings.aoColumns[i].bVisible )
144 {
145 var nTd = _fnGetWidestNode( oSettings, i );
146 if ( nTd !== null )
147 {
148 nTd = nTd.cloneNode(true);
149 if ( oSettings.aoColumns[i].sContentPadding !== "" )
150 {
151 nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
152 }
153 nTr.appendChild( nTd );
154 }
155 }
156 }
157
158 /* Build the table and 'display' it */
159 nWrapper.appendChild( nCalcTmp );
160
161 /* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
162 * when not scrolling leave the table width as it is. This results in slightly different,
163 * but I think correct behaviour
164 */
165 if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
166 {
167 nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
168 }
169 else if ( oSettings.oScroll.sX !== "" )
170 {
171 nCalcTmp.style.width = "";
172 if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
173 {
174 nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
175 }
176 }
177 else if ( oSettings.oScroll.sY !== "" )
178 {
179 nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
180 }
181 else if ( widthAttr )
182 {
183 nCalcTmp.style.width = _fnStringToCss( widthAttr );
184 }
185 nCalcTmp.style.visibility = "hidden";
186
187 /* Scrolling considerations */
188 _fnScrollingWidthAdjust( oSettings, nCalcTmp );
189
190 /* Read the width's calculated by the browser and store them for use by the caller. We
191 * first of all try to use the elements in the body, but it is possible that there are
192 * no elements there, under which circumstances we use the header elements
193 */
194 var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
195 if ( oNodes.length === 0 )
196 {
197 oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
198 }
199
200 /* Browsers need a bit of a hand when a width is assigned to any columns when
201 * x-scrolling as they tend to collapse the table to the min-width, even if
202 * we sent the column widths. So we need to keep track of what the table width
203 * should be by summing the user given values, and the automatic values
204 */
205 if ( oSettings.oScroll.sX !== "" )
206 {
207 var iTotal = 0;
208 iCorrector = 0;
209 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
210 {
211 if ( oSettings.aoColumns[i].bVisible )
212 {
213 if ( oSettings.aoColumns[i].sWidthOrig === null )
214 {
215 iTotal += $(oNodes[iCorrector]).outerWidth();
216 }
217 else
218 {
219 iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
220 ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
221 }
222 iCorrector++;
223 }
224 }
225
226 nCalcTmp.style.width = _fnStringToCss( iTotal );
227 oSettings.nTable.style.width = _fnStringToCss( iTotal );
228 }
229
230 iCorrector = 0;
231 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
232 {
233 if ( oSettings.aoColumns[i].bVisible )
234 {
235 iWidth = $(oNodes[iCorrector]).width();
236 if ( iWidth !== null && iWidth > 0 )
237 {
238 oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
239 }
240 iCorrector++;
241 }
242 }
243
244 var cssWidth = $(nCalcTmp).css('width');
245 oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
246 cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
247 nCalcTmp.parentNode.removeChild( nCalcTmp );
248 }
249
250 if ( widthAttr )
251 {
252 oSettings.nTable.style.width = _fnStringToCss( widthAttr );
253 }
254 }
255
256
257 /**
258 * Adjust a table's width to take account of scrolling
259 * @param {object} oSettings dataTables settings object
260 * @param {node} n table node
261 * @memberof DataTable#oApi
262 */
263 function _fnScrollingWidthAdjust ( oSettings, n )
264 {
265 if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
266 {
267 /* When y-scrolling only, we want to remove the width of the scroll bar so the table
268 * + scroll bar will fit into the area avaialble.
269 */
270 var iOrigWidth = $(n).width();
271 n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
272 }
273 else if ( oSettings.oScroll.sX !== "" )
274 {
275 /* When x-scrolling both ways, fix the table at it's current size, without adjusting */
276 n.style.width = _fnStringToCss( $(n).outerWidth() );
277 }
278 }
279
280
281 /**
282 * Get the widest node
283 * @param {object} oSettings dataTables settings object
284 * @param {int} iCol column of interest
285 * @returns {node} widest table node
286 * @memberof DataTable#oApi
287 */
288 function _fnGetWidestNode( oSettings, iCol )
289 {
290 var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
291 if ( iMaxIndex < 0 )
292 {
293 return null;
294 }
295
296 if ( oSettings.aoData[iMaxIndex].nTr === null )
297 {
298 var n = document.createElement('td');
299 n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
300 return n;
301 }
302 return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
303 }
304
305
306 /**
307 * Get the maximum strlen for each data column
308 * @param {object} oSettings dataTables settings object
309 * @param {int} iCol column of interest
310 * @returns {string} max string length for each column
311 * @memberof DataTable#oApi
312 */
313 function _fnGetMaxLenString( oSettings, iCol )
314 {
315 var iMax = -1;
316 var iMaxIndex = -1;
317
318 for ( var i=0 ; i<oSettings.aoData.length ; i++ )
319 {
320 var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
321 s = s.replace( /<.*?>/g, "" );
322 if ( s.length > iMax )
323 {
324 iMax = s.length;
325 iMaxIndex = i;
326 }
327 }
328
329 return iMaxIndex;
330 }
331
332
333 /**
334 * Append a CSS unit (only if required) to a string
335 * @param {array} aArray1 first array
336 * @param {array} aArray2 second array
337 * @returns {int} 0 if match, 1 if length is different, 2 if no match
338 * @memberof DataTable#oApi
339 */
340 function _fnStringToCss( s )
341 {
342 if ( s === null )
343 {
344 return "0px";
345 }
346
347 if ( typeof s == 'number' )
348 {
349 if ( s < 0 )
350 {
351 return "0px";
352 }
353 return s+"px";
354 }
355
356 /* Check if the last character is not 0-9 */
357 var c = s.charCodeAt( s.length-1 );
358 if (c < 0x30 || c > 0x39)
359 {
360 return s;
361 }
362 return s+"px";
363 }
364
365
366 /**
367 * Get the width of a scroll bar in this browser being used
368 * @returns {int} width in pixels
369 * @memberof DataTable#oApi
370 */
371 function _fnScrollBarWidth ()
372 {
373 var inner = document.createElement('p');
374 var style = inner.style;
375 style.width = "100%";
376 style.height = "200px";
377 style.padding = "0px";
378
379 var outer = document.createElement('div');
380 style = outer.style;
381 style.position = "absolute";
382 style.top = "0px";
383 style.left = "0px";
384 style.visibility = "hidden";
385 style.width = "200px";
386 style.height = "150px";
387 style.padding = "0px";
388 style.overflow = "hidden";
389 outer.appendChild(inner);
390
391 document.body.appendChild(outer);
392 var w1 = inner.offsetWidth;
393 outer.style.overflow = 'scroll';
394 var w2 = inner.offsetWidth;
395 if ( w1 == w2 )
396 {
397 w2 = outer.clientWidth;
398 }
399
400 document.body.removeChild(outer);
401 return (w1 - w2);
402 }
403