Add datatables-1.9.4 and jquery-1.10.2 libraries
[proteocache.git] / webapp / resources / datatables-1.9.4 / media / src / core / core.sizing.js
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