0
|
1
|
|
2 /**
|
|
3 * Return the settings object for a particular table
|
|
4 * @param {node} nTable table we are using as a dataTable
|
|
5 * @returns {object} Settings object - or null if not found
|
|
6 * @memberof DataTable#oApi
|
|
7 */
|
|
8 function _fnSettingsFromNode ( nTable )
|
|
9 {
|
|
10 for ( var i=0 ; i<DataTable.settings.length ; i++ )
|
|
11 {
|
|
12 if ( DataTable.settings[i].nTable === nTable )
|
|
13 {
|
|
14 return DataTable.settings[i];
|
|
15 }
|
|
16 }
|
|
17
|
|
18 return null;
|
|
19 }
|
|
20
|
|
21
|
|
22 /**
|
|
23 * Return an array with the TR nodes for the table
|
|
24 * @param {object} oSettings dataTables settings object
|
|
25 * @returns {array} TR array
|
|
26 * @memberof DataTable#oApi
|
|
27 */
|
|
28 function _fnGetTrNodes ( oSettings )
|
|
29 {
|
|
30 var aNodes = [];
|
|
31 var aoData = oSettings.aoData;
|
|
32 for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
|
|
33 {
|
|
34 if ( aoData[i].nTr !== null )
|
|
35 {
|
|
36 aNodes.push( aoData[i].nTr );
|
|
37 }
|
|
38 }
|
|
39 return aNodes;
|
|
40 }
|
|
41
|
|
42
|
|
43 /**
|
|
44 * Return an flat array with all TD nodes for the table, or row
|
|
45 * @param {object} oSettings dataTables settings object
|
|
46 * @param {int} [iIndividualRow] aoData index to get the nodes for - optional
|
|
47 * if not given then the return array will contain all nodes for the table
|
|
48 * @returns {array} TD array
|
|
49 * @memberof DataTable#oApi
|
|
50 */
|
|
51 function _fnGetTdNodes ( oSettings, iIndividualRow )
|
|
52 {
|
|
53 var anReturn = [];
|
|
54 var iCorrector;
|
|
55 var anTds, nTd;
|
|
56 var iRow, iRows=oSettings.aoData.length,
|
|
57 iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
|
|
58
|
|
59 /* Allow the collection to be limited to just one row */
|
|
60 if ( iIndividualRow !== undefined )
|
|
61 {
|
|
62 iStart = iIndividualRow;
|
|
63 iEnd = iIndividualRow+1;
|
|
64 }
|
|
65
|
|
66 for ( iRow=iStart ; iRow<iEnd ; iRow++ )
|
|
67 {
|
|
68 oData = oSettings.aoData[iRow];
|
|
69 if ( oData.nTr !== null )
|
|
70 {
|
|
71 /* get the TD child nodes - taking into account text etc nodes */
|
|
72 anTds = [];
|
|
73 nTd = oData.nTr.firstChild;
|
|
74 while ( nTd )
|
|
75 {
|
|
76 sNodeName = nTd.nodeName.toLowerCase();
|
|
77 if ( sNodeName == 'td' || sNodeName == 'th' )
|
|
78 {
|
|
79 anTds.push( nTd );
|
|
80 }
|
|
81 nTd = nTd.nextSibling;
|
|
82 }
|
|
83
|
|
84 iCorrector = 0;
|
|
85 for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
|
|
86 {
|
|
87 if ( oSettings.aoColumns[iColumn].bVisible )
|
|
88 {
|
|
89 anReturn.push( anTds[iColumn-iCorrector] );
|
|
90 }
|
|
91 else
|
|
92 {
|
|
93 anReturn.push( oData._anHidden[iColumn] );
|
|
94 iCorrector++;
|
|
95 }
|
|
96 }
|
|
97 }
|
|
98 }
|
|
99
|
|
100 return anReturn;
|
|
101 }
|
|
102
|
|
103
|
|
104 /**
|
|
105 * Log an error message
|
|
106 * @param {object} oSettings dataTables settings object
|
|
107 * @param {int} iLevel log error messages, or display them to the user
|
|
108 * @param {string} sMesg error message
|
|
109 * @memberof DataTable#oApi
|
|
110 */
|
|
111 function _fnLog( oSettings, iLevel, sMesg )
|
|
112 {
|
|
113 var sAlert = (oSettings===null) ?
|
|
114 "DataTables warning: "+sMesg :
|
|
115 "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
|
|
116
|
|
117 if ( iLevel === 0 )
|
|
118 {
|
|
119 if ( DataTable.ext.sErrMode == 'alert' )
|
|
120 {
|
|
121 alert( sAlert );
|
|
122 }
|
|
123 else
|
|
124 {
|
|
125 throw new Error(sAlert);
|
|
126 }
|
|
127 return;
|
|
128 }
|
|
129 else if ( window.console && console.log )
|
|
130 {
|
|
131 console.log( sAlert );
|
|
132 }
|
|
133 }
|
|
134
|
|
135
|
|
136 /**
|
|
137 * See if a property is defined on one object, if so assign it to the other object
|
|
138 * @param {object} oRet target object
|
|
139 * @param {object} oSrc source object
|
|
140 * @param {string} sName property
|
|
141 * @param {string} [sMappedName] name to map too - optional, sName used if not given
|
|
142 * @memberof DataTable#oApi
|
|
143 */
|
|
144 function _fnMap( oRet, oSrc, sName, sMappedName )
|
|
145 {
|
|
146 if ( sMappedName === undefined )
|
|
147 {
|
|
148 sMappedName = sName;
|
|
149 }
|
|
150 if ( oSrc[sName] !== undefined )
|
|
151 {
|
|
152 oRet[sMappedName] = oSrc[sName];
|
|
153 }
|
|
154 }
|
|
155
|
|
156
|
|
157 /**
|
|
158 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
|
|
159 * copy arrays. The reason we need to do this, is that we don't want to deep copy array
|
|
160 * init values (such as aaSorting) since the dev wouldn't be able to override them, but
|
|
161 * we do want to deep copy arrays.
|
|
162 * @param {object} oOut Object to extend
|
|
163 * @param {object} oExtender Object from which the properties will be applied to oOut
|
|
164 * @returns {object} oOut Reference, just for convenience - oOut === the return.
|
|
165 * @memberof DataTable#oApi
|
|
166 * @todo This doesn't take account of arrays inside the deep copied objects.
|
|
167 */
|
|
168 function _fnExtend( oOut, oExtender )
|
|
169 {
|
|
170 var val;
|
|
171
|
|
172 for ( var prop in oExtender )
|
|
173 {
|
|
174 if ( oExtender.hasOwnProperty(prop) )
|
|
175 {
|
|
176 val = oExtender[prop];
|
|
177
|
|
178 if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
|
|
179 {
|
|
180 $.extend( true, oOut[prop], val );
|
|
181 }
|
|
182 else
|
|
183 {
|
|
184 oOut[prop] = val;
|
|
185 }
|
|
186 }
|
|
187 }
|
|
188
|
|
189 return oOut;
|
|
190 }
|
|
191
|
|
192
|
|
193 /**
|
|
194 * Bind an event handers to allow a click or return key to activate the callback.
|
|
195 * This is good for accessibility since a return on the keyboard will have the
|
|
196 * same effect as a click, if the element has focus.
|
|
197 * @param {element} n Element to bind the action to
|
|
198 * @param {object} oData Data object to pass to the triggered function
|
|
199 * @param {function} fn Callback function for when the event is triggered
|
|
200 * @memberof DataTable#oApi
|
|
201 */
|
|
202 function _fnBindAction( n, oData, fn )
|
|
203 {
|
|
204 $(n)
|
|
205 .bind( 'click.DT', oData, function (e) {
|
|
206 n.blur(); // Remove focus outline for mouse users
|
|
207 fn(e);
|
|
208 } )
|
|
209 .bind( 'keypress.DT', oData, function (e){
|
|
210 if ( e.which === 13 ) {
|
|
211 fn(e);
|
|
212 } } )
|
|
213 .bind( 'selectstart.DT', function () {
|
|
214 /* Take the brutal approach to cancelling text selection */
|
|
215 return false;
|
|
216 } );
|
|
217 }
|
|
218
|
|
219
|
|
220 /**
|
|
221 * Register a callback function. Easily allows a callback function to be added to
|
|
222 * an array store of callback functions that can then all be called together.
|
|
223 * @param {object} oSettings dataTables settings object
|
|
224 * @param {string} sStore Name of the array storage for the callbacks in oSettings
|
|
225 * @param {function} fn Function to be called back
|
|
226 * @param {string} sName Identifying name for the callback (i.e. a label)
|
|
227 * @memberof DataTable#oApi
|
|
228 */
|
|
229 function _fnCallbackReg( oSettings, sStore, fn, sName )
|
|
230 {
|
|
231 if ( fn )
|
|
232 {
|
|
233 oSettings[sStore].push( {
|
|
234 "fn": fn,
|
|
235 "sName": sName
|
|
236 } );
|
|
237 }
|
|
238 }
|
|
239
|
|
240
|
|
241 /**
|
|
242 * Fire callback functions and trigger events. Note that the loop over the callback
|
|
243 * array store is done backwards! Further note that you do not want to fire off triggers
|
|
244 * in time sensitive applications (for example cell creation) as its slow.
|
|
245 * @param {object} oSettings dataTables settings object
|
|
246 * @param {string} sStore Name of the array storage for the callbacks in oSettings
|
|
247 * @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
|
|
248 * is fired
|
|
249 * @param {array} aArgs Array of arguments to pass to the callback function / trigger
|
|
250 * @memberof DataTable#oApi
|
|
251 */
|
|
252 function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
|
|
253 {
|
|
254 var aoStore = oSettings[sStore];
|
|
255 var aRet =[];
|
|
256
|
|
257 for ( var i=aoStore.length-1 ; i>=0 ; i-- )
|
|
258 {
|
|
259 aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
|
|
260 }
|
|
261
|
|
262 if ( sTrigger !== null )
|
|
263 {
|
|
264 $(oSettings.oInstance).trigger(sTrigger, aArgs);
|
|
265 }
|
|
266
|
|
267 return aRet;
|
|
268 }
|
|
269
|
|
270
|
|
271 /**
|
|
272 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
|
|
273 * library, then we use that as it is fast, safe and accurate. If the function isn't
|
|
274 * available then we need to built it ourselves - the inspiration for this function comes
|
|
275 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
|
|
276 * not perfect and absolutely should not be used as a replacement to json2.js - but it does
|
|
277 * do what we need, without requiring a dependency for DataTables.
|
|
278 * @param {object} o JSON object to be converted
|
|
279 * @returns {string} JSON string
|
|
280 * @memberof DataTable#oApi
|
|
281 */
|
|
282 var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
|
|
283 {
|
|
284 /* Not an object or array */
|
|
285 var sType = typeof o;
|
|
286 if (sType !== "object" || o === null)
|
|
287 {
|
|
288 // simple data type
|
|
289 if (sType === "string")
|
|
290 {
|
|
291 o = '"'+o+'"';
|
|
292 }
|
|
293 return o+"";
|
|
294 }
|
|
295
|
|
296 /* If object or array, need to recurse over it */
|
|
297 var
|
|
298 sProp, mValue,
|
|
299 json = [],
|
|
300 bArr = $.isArray(o);
|
|
301
|
|
302 for (sProp in o)
|
|
303 {
|
|
304 mValue = o[sProp];
|
|
305 sType = typeof mValue;
|
|
306
|
|
307 if (sType === "string")
|
|
308 {
|
|
309 mValue = '"'+mValue+'"';
|
|
310 }
|
|
311 else if (sType === "object" && mValue !== null)
|
|
312 {
|
|
313 mValue = _fnJsonString(mValue);
|
|
314 }
|
|
315
|
|
316 json.push((bArr ? "" : '"'+sProp+'":') + mValue);
|
|
317 }
|
|
318
|
|
319 return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
|
|
320 };
|
|
321
|
|
322
|
|
323 /**
|
|
324 * From some browsers (specifically IE6/7) we need special handling to work around browser
|
|
325 * bugs - this function is used to detect when these workarounds are needed.
|
|
326 * @param {object} oSettings dataTables settings object
|
|
327 * @memberof DataTable#oApi
|
|
328 */
|
|
329 function _fnBrowserDetect( oSettings )
|
|
330 {
|
|
331 /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
|
|
332 * width of the scrollbar, while other browsers ensure the inner element is contained
|
|
333 * without forcing scrolling
|
|
334 */
|
|
335 var n = $(
|
|
336 '<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
|
|
337 '<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
|
|
338 '<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
|
|
339 '</div>'+
|
|
340 '</div>')[0];
|
|
341
|
|
342 document.body.appendChild( n );
|
|
343 oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
|
|
344 document.body.removeChild( n );
|
|
345 }
|
|
346
|