1 /*! TableTools 2.2.0 |
|
2 * 2009-2014 SpryMedia Ltd - datatables.net/license |
|
3 * |
|
4 * ZeroClipboard 1.0.4 |
|
5 * Author: Joseph Huckaby - MIT licensed |
|
6 */ |
|
7 |
|
8 /** |
|
9 * @summary TableTools |
|
10 * @description Tools and buttons for DataTables |
|
11 * @version 2.2.0 |
|
12 * @file dataTables.tableTools.js |
|
13 * @author SpryMedia Ltd (www.sprymedia.co.uk) |
|
14 * @contact www.sprymedia.co.uk/contact |
|
15 * @copyright Copyright 2009-2014 SpryMedia Ltd. |
|
16 * |
|
17 * This source file is free software, available under the following license: |
|
18 * MIT license - http://datatables.net/license/mit |
|
19 * |
|
20 * This source file is distributed in the hope that it will be useful, but |
|
21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|
22 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. |
|
23 * |
|
24 * For details please refer to: http://www.datatables.net |
|
25 */ |
|
26 |
|
27 |
|
28 /* Global scope for TableTools for backwards compatibility. |
|
29 * Will be removed in 2.3 |
|
30 */ |
|
31 var TableTools; |
|
32 |
|
33 (function (window, document, undefined) { |
|
34 |
|
35 |
|
36 var factory = function ($, DataTable) { |
|
37 "use strict"; |
|
38 |
|
39 |
|
40 //include ZeroClipboard.js |
|
41 /* ZeroClipboard 1.0.4 |
|
42 * Author: Joseph Huckaby |
|
43 */ |
|
44 |
|
45 var ZeroClipboard_TableTools = { |
|
46 |
|
47 version: "1.0.4-TableTools2", |
|
48 clients: {}, // registered upload clients on page, indexed by id |
|
49 moviePath: '', // URL to movie |
|
50 nextId: 1, // ID of next movie |
|
51 |
|
52 $: function (thingy) { |
|
53 // simple DOM lookup utility function |
|
54 if (typeof(thingy) == 'string') { |
|
55 thingy = document.getElementById(thingy); |
|
56 } |
|
57 if (!thingy.addClass) { |
|
58 // extend element with a few useful methods |
|
59 thingy.hide = function () { |
|
60 this.style.display = 'none'; |
|
61 }; |
|
62 thingy.show = function () { |
|
63 this.style.display = ''; |
|
64 }; |
|
65 thingy.addClass = function (name) { |
|
66 this.removeClass(name); |
|
67 this.className += ' ' + name; |
|
68 }; |
|
69 thingy.removeClass = function (name) { |
|
70 this.className = this.className.replace(new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, ''); |
|
71 }; |
|
72 thingy.hasClass = function (name) { |
|
73 return !!this.className.match(new RegExp("\\s*" + name + "\\s*")); |
|
74 }; |
|
75 } |
|
76 return thingy; |
|
77 }, |
|
78 |
|
79 setMoviePath: function (path) { |
|
80 // set path to ZeroClipboard.swf |
|
81 this.moviePath = path; |
|
82 }, |
|
83 |
|
84 dispatch: function (id, eventName, args) { |
|
85 // receive event from flash movie, send to client |
|
86 var client = this.clients[id]; |
|
87 if (client) { |
|
88 client.receiveEvent(eventName, args); |
|
89 } |
|
90 }, |
|
91 |
|
92 register: function (id, client) { |
|
93 // register new client to receive events |
|
94 this.clients[id] = client; |
|
95 }, |
|
96 |
|
97 getDOMObjectPosition: function (obj) { |
|
98 // get absolute coordinates for dom element |
|
99 var info = { |
|
100 left: 0, |
|
101 top: 0, |
|
102 width: obj.width ? obj.width : obj.offsetWidth, |
|
103 height: obj.height ? obj.height : obj.offsetHeight |
|
104 }; |
|
105 |
|
106 if (obj.style.width !== "") { |
|
107 info.width = obj.style.width.replace("px", ""); |
|
108 } |
|
109 |
|
110 if (obj.style.height !== "") { |
|
111 info.height = obj.style.height.replace("px", ""); |
|
112 } |
|
113 |
|
114 while (obj) { |
|
115 info.left += obj.offsetLeft; |
|
116 info.top += obj.offsetTop; |
|
117 obj = obj.offsetParent; |
|
118 } |
|
119 |
|
120 return info; |
|
121 }, |
|
122 |
|
123 Client: function (elem) { |
|
124 // constructor for new simple upload client |
|
125 this.handlers = {}; |
|
126 |
|
127 // unique ID |
|
128 this.id = ZeroClipboard_TableTools.nextId++; |
|
129 this.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id; |
|
130 |
|
131 // register client with singleton to receive flash events |
|
132 ZeroClipboard_TableTools.register(this.id, this); |
|
133 |
|
134 // create movie |
|
135 if (elem) { |
|
136 this.glue(elem); |
|
137 } |
|
138 } |
|
139 }; |
|
140 |
|
141 ZeroClipboard_TableTools.Client.prototype = { |
|
142 |
|
143 id: 0, // unique ID for us |
|
144 ready: false, // whether movie is ready to receive events or not |
|
145 movie: null, // reference to movie object |
|
146 clipText: '', // text to copy to clipboard |
|
147 fileName: '', // default file save name |
|
148 action: 'copy', // action to perform |
|
149 handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor |
|
150 cssEffects: true, // enable CSS mouse effects on dom container |
|
151 handlers: null, // user event handlers |
|
152 sized: false, |
|
153 |
|
154 glue: function (elem, title) { |
|
155 // glue to DOM element |
|
156 // elem can be ID or actual DOM element object |
|
157 this.domElement = ZeroClipboard_TableTools.$(elem); |
|
158 |
|
159 // float just above object, or zIndex 99 if dom element isn't set |
|
160 var zIndex = 99; |
|
161 if (this.domElement.style.zIndex) { |
|
162 zIndex = parseInt(this.domElement.style.zIndex, 10) + 1; |
|
163 } |
|
164 |
|
165 // find X/Y position of domElement |
|
166 var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement); |
|
167 |
|
168 // create floating DIV above element |
|
169 this.div = document.createElement('div'); |
|
170 var style = this.div.style; |
|
171 style.position = 'absolute'; |
|
172 style.left = '0px'; |
|
173 style.top = '0px'; |
|
174 style.width = (box.width) + 'px'; |
|
175 style.height = box.height + 'px'; |
|
176 style.zIndex = zIndex; |
|
177 |
|
178 if (typeof title != "undefined" && title !== "") { |
|
179 this.div.title = title; |
|
180 } |
|
181 if (box.width !== 0 && box.height !== 0) { |
|
182 this.sized = true; |
|
183 } |
|
184 |
|
185 // style.backgroundColor = '#f00'; // debug |
|
186 if (this.domElement) { |
|
187 this.domElement.appendChild(this.div); |
|
188 this.div.innerHTML = this.getHTML(box.width, box.height).replace(/&/g, '&'); |
|
189 } |
|
190 }, |
|
191 |
|
192 positionElement: function () { |
|
193 var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement); |
|
194 var style = this.div.style; |
|
195 |
|
196 style.position = 'absolute'; |
|
197 //style.left = (this.domElement.offsetLeft)+'px'; |
|
198 //style.top = this.domElement.offsetTop+'px'; |
|
199 style.width = box.width + 'px'; |
|
200 style.height = box.height + 'px'; |
|
201 |
|
202 if (box.width !== 0 && box.height !== 0) { |
|
203 this.sized = true; |
|
204 } else { |
|
205 return; |
|
206 } |
|
207 |
|
208 var flash = this.div.childNodes[0]; |
|
209 flash.width = box.width; |
|
210 flash.height = box.height; |
|
211 }, |
|
212 |
|
213 getHTML: function (width, height) { |
|
214 // return HTML for movie |
|
215 var html = ''; |
|
216 var flashvars = 'id=' + this.id + |
|
217 '&width=' + width + |
|
218 '&height=' + height; |
|
219 |
|
220 if (navigator.userAgent.match(/MSIE/)) { |
|
221 // IE gets an OBJECT tag |
|
222 var protocol = location.href.match(/^https/i) ? 'https://' : 'http://'; |
|
223 html += '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="' + protocol + 'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="' + width + '" height="' + height + '" id="' + this.movieId + '" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="' + ZeroClipboard_TableTools.moviePath + '" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="' + flashvars + '"/><param name="wmode" value="transparent"/></object>'; |
|
224 } |
|
225 else { |
|
226 // all other browsers get an EMBED tag |
|
227 html += '<embed id="' + this.movieId + '" src="' + ZeroClipboard_TableTools.moviePath + '" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="' + width + '" height="' + height + '" name="' + this.movieId + '" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="' + flashvars + '" wmode="transparent" />'; |
|
228 } |
|
229 return html; |
|
230 }, |
|
231 |
|
232 hide: function () { |
|
233 // temporarily hide floater offscreen |
|
234 if (this.div) { |
|
235 this.div.style.left = '-2000px'; |
|
236 } |
|
237 }, |
|
238 |
|
239 show: function () { |
|
240 // show ourselves after a call to hide() |
|
241 this.reposition(); |
|
242 }, |
|
243 |
|
244 destroy: function () { |
|
245 // destroy control and floater |
|
246 if (this.domElement && this.div) { |
|
247 this.hide(); |
|
248 this.div.innerHTML = ''; |
|
249 |
|
250 var body = document.getElementsByTagName('body')[0]; |
|
251 try { |
|
252 body.removeChild(this.div); |
|
253 } catch (e) { |
|
254 } |
|
255 |
|
256 this.domElement = null; |
|
257 this.div = null; |
|
258 } |
|
259 }, |
|
260 |
|
261 reposition: function (elem) { |
|
262 // reposition our floating div, optionally to new container |
|
263 // warning: container CANNOT change size, only position |
|
264 if (elem) { |
|
265 this.domElement = ZeroClipboard_TableTools.$(elem); |
|
266 if (!this.domElement) { |
|
267 this.hide(); |
|
268 } |
|
269 } |
|
270 |
|
271 if (this.domElement && this.div) { |
|
272 var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement); |
|
273 var style = this.div.style; |
|
274 style.left = '' + box.left + 'px'; |
|
275 style.top = '' + box.top + 'px'; |
|
276 } |
|
277 }, |
|
278 |
|
279 clearText: function () { |
|
280 // clear the text to be copy / saved |
|
281 this.clipText = ''; |
|
282 if (this.ready) { |
|
283 this.movie.clearText(); |
|
284 } |
|
285 }, |
|
286 |
|
287 appendText: function (newText) { |
|
288 // append text to that which is to be copied / saved |
|
289 this.clipText += newText; |
|
290 if (this.ready) { |
|
291 this.movie.appendText(newText); |
|
292 } |
|
293 }, |
|
294 |
|
295 setText: function (newText) { |
|
296 // set text to be copied to be copied / saved |
|
297 this.clipText = newText; |
|
298 if (this.ready) { |
|
299 this.movie.setText(newText); |
|
300 } |
|
301 }, |
|
302 |
|
303 setCharSet: function (charSet) { |
|
304 // set the character set (UTF16LE or UTF8) |
|
305 this.charSet = charSet; |
|
306 if (this.ready) { |
|
307 this.movie.setCharSet(charSet); |
|
308 } |
|
309 }, |
|
310 |
|
311 setBomInc: function (bomInc) { |
|
312 // set if the BOM should be included or not |
|
313 this.incBom = bomInc; |
|
314 if (this.ready) { |
|
315 this.movie.setBomInc(bomInc); |
|
316 } |
|
317 }, |
|
318 |
|
319 setFileName: function (newText) { |
|
320 // set the file name |
|
321 this.fileName = newText; |
|
322 if (this.ready) { |
|
323 this.movie.setFileName(newText); |
|
324 } |
|
325 }, |
|
326 |
|
327 setAction: function (newText) { |
|
328 // set action (save or copy) |
|
329 this.action = newText; |
|
330 if (this.ready) { |
|
331 this.movie.setAction(newText); |
|
332 } |
|
333 }, |
|
334 |
|
335 addEventListener: function (eventName, func) { |
|
336 // add user event listener for event |
|
337 // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel |
|
338 eventName = eventName.toString().toLowerCase().replace(/^on/, ''); |
|
339 if (!this.handlers[eventName]) { |
|
340 this.handlers[eventName] = []; |
|
341 } |
|
342 this.handlers[eventName].push(func); |
|
343 }, |
|
344 |
|
345 setHandCursor: function (enabled) { |
|
346 // enable hand cursor (true), or default arrow cursor (false) |
|
347 this.handCursorEnabled = enabled; |
|
348 if (this.ready) { |
|
349 this.movie.setHandCursor(enabled); |
|
350 } |
|
351 }, |
|
352 |
|
353 setCSSEffects: function (enabled) { |
|
354 // enable or disable CSS effects on DOM container |
|
355 this.cssEffects = !!enabled; |
|
356 }, |
|
357 |
|
358 receiveEvent: function (eventName, args) { |
|
359 var self; |
|
360 |
|
361 // receive event from flash |
|
362 eventName = eventName.toString().toLowerCase().replace(/^on/, ''); |
|
363 |
|
364 // special behavior for certain events |
|
365 switch (eventName) { |
|
366 case 'load': |
|
367 // movie claims it is ready, but in IE this isn't always the case... |
|
368 // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function |
|
369 this.movie = document.getElementById(this.movieId); |
|
370 if (!this.movie) { |
|
371 self = this; |
|
372 setTimeout(function () { |
|
373 self.receiveEvent('load', null); |
|
374 }, 1); |
|
375 return; |
|
376 } |
|
377 |
|
378 // firefox on pc needs a "kick" in order to set these in certain cases |
|
379 if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) { |
|
380 self = this; |
|
381 setTimeout(function () { |
|
382 self.receiveEvent('load', null); |
|
383 }, 100); |
|
384 this.ready = true; |
|
385 return; |
|
386 } |
|
387 |
|
388 this.ready = true; |
|
389 this.movie.clearText(); |
|
390 this.movie.appendText(this.clipText); |
|
391 this.movie.setFileName(this.fileName); |
|
392 this.movie.setAction(this.action); |
|
393 this.movie.setCharSet(this.charSet); |
|
394 this.movie.setBomInc(this.incBom); |
|
395 this.movie.setHandCursor(this.handCursorEnabled); |
|
396 break; |
|
397 |
|
398 case 'mouseover': |
|
399 if (this.domElement && this.cssEffects) { |
|
400 //this.domElement.addClass('hover'); |
|
401 if (this.recoverActive) { |
|
402 this.domElement.addClass('active'); |
|
403 } |
|
404 } |
|
405 break; |
|
406 |
|
407 case 'mouseout': |
|
408 if (this.domElement && this.cssEffects) { |
|
409 this.recoverActive = false; |
|
410 if (this.domElement.hasClass('active')) { |
|
411 this.domElement.removeClass('active'); |
|
412 this.recoverActive = true; |
|
413 } |
|
414 //this.domElement.removeClass('hover'); |
|
415 } |
|
416 break; |
|
417 |
|
418 case 'mousedown': |
|
419 if (this.domElement && this.cssEffects) { |
|
420 this.domElement.addClass('active'); |
|
421 } |
|
422 break; |
|
423 |
|
424 case 'mouseup': |
|
425 if (this.domElement && this.cssEffects) { |
|
426 this.domElement.removeClass('active'); |
|
427 this.recoverActive = false; |
|
428 } |
|
429 break; |
|
430 } // switch eventName |
|
431 |
|
432 if (this.handlers[eventName]) { |
|
433 for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) { |
|
434 var func = this.handlers[eventName][idx]; |
|
435 |
|
436 if (typeof(func) == 'function') { |
|
437 // actual function reference |
|
438 func(this, args); |
|
439 } |
|
440 else if ((typeof(func) == 'object') && (func.length == 2)) { |
|
441 // PHP style object + method, i.e. [myObject, 'myMethod'] |
|
442 func[0][ func[1] ](this, args); |
|
443 } |
|
444 else if (typeof(func) == 'string') { |
|
445 // name of function |
|
446 window[func](this, args); |
|
447 } |
|
448 } // foreach event handler defined |
|
449 } // user defined handler for event |
|
450 } |
|
451 |
|
452 }; |
|
453 |
|
454 // For the Flash binding to work, ZeroClipboard_TableTools must be on the global |
|
455 // object list |
|
456 window.ZeroClipboard_TableTools = ZeroClipboard_TableTools; |
|
457 //include TableTools.js |
|
458 /* TableTools |
|
459 * 2009-2014 SpryMedia Ltd - datatables.net/license |
|
460 */ |
|
461 |
|
462 /*globals ZeroClipboard_TableTools*/ |
|
463 |
|
464 /* Global scope for TableTools */ |
|
465 var TableTools; |
|
466 |
|
467 (function ($, window, document) { |
|
468 |
|
469 /** |
|
470 * TableTools provides flexible buttons and other tools for a DataTables enhanced table |
|
471 * @class TableTools |
|
472 * @constructor |
|
473 * @param {Object} oDT DataTables instance. When using DataTables 1.10 this can |
|
474 * also be a jQuery collection, jQuery selector, table node, DataTables API |
|
475 * instance or DataTables settings object. |
|
476 * @param {Object} oOpts TableTools options |
|
477 * @param {String} oOpts.sSwfPath ZeroClipboard SWF path |
|
478 * @param {String} oOpts.sRowSelect Row selection options - 'none', 'single', 'multi' or 'os' |
|
479 * @param {Function} oOpts.fnPreRowSelect Callback function just prior to row selection |
|
480 * @param {Function} oOpts.fnRowSelected Callback function just after row selection |
|
481 * @param {Function} oOpts.fnRowDeselected Callback function when row is deselected |
|
482 * @param {Array} oOpts.aButtons List of buttons to be used |
|
483 */ |
|
484 TableTools = function (oDT, oOpts) { |
|
485 /* Santiy check that we are a new instance */ |
|
486 if (!this instanceof TableTools) { |
|
487 alert("Warning: TableTools must be initialised with the keyword 'new'"); |
|
488 } |
|
489 |
|
490 // In 1.10 we can use the API to get the settings object from a number of |
|
491 // sources |
|
492 var dtSettings = $.fn.dataTable.Api ? |
|
493 new $.fn.dataTable.Api(oDT).settings()[0] : |
|
494 oDT.fnSettings(); |
|
495 |
|
496 |
|
497 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
498 * Public class variables |
|
499 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
500 |
|
501 /** |
|
502 * @namespace Settings object which contains customisable information for TableTools instance |
|
503 */ |
|
504 this.s = { |
|
505 /** |
|
506 * Store 'this' so the instance can be retrieved from the settings object |
|
507 * @property that |
|
508 * @type object |
|
509 * @default this |
|
510 */ |
|
511 "that": this, |
|
512 |
|
513 /** |
|
514 * DataTables settings objects |
|
515 * @property dt |
|
516 * @type object |
|
517 * @default <i>From the oDT init option</i> |
|
518 */ |
|
519 "dt": dtSettings, |
|
520 |
|
521 /** |
|
522 * @namespace Print specific information |
|
523 */ |
|
524 "print": { |
|
525 /** |
|
526 * DataTables draw 'start' point before the printing display was shown |
|
527 * @property saveStart |
|
528 * @type int |
|
529 * @default -1 |
|
530 */ |
|
531 "saveStart": -1, |
|
532 |
|
533 /** |
|
534 * DataTables draw 'length' point before the printing display was shown |
|
535 * @property saveLength |
|
536 * @type int |
|
537 * @default -1 |
|
538 */ |
|
539 "saveLength": -1, |
|
540 |
|
541 /** |
|
542 * Page scrolling point before the printing display was shown so it can be restored |
|
543 * @property saveScroll |
|
544 * @type int |
|
545 * @default -1 |
|
546 */ |
|
547 "saveScroll": -1, |
|
548 |
|
549 /** |
|
550 * Wrapped function to end the print display (to maintain scope) |
|
551 * @property funcEnd |
|
552 * @type Function |
|
553 * @default function () {} |
|
554 */ |
|
555 "funcEnd": function () { |
|
556 } |
|
557 }, |
|
558 |
|
559 /** |
|
560 * A unique ID is assigned to each button in each instance |
|
561 * @property buttonCounter |
|
562 * @type int |
|
563 * @default 0 |
|
564 */ |
|
565 "buttonCounter": 0, |
|
566 |
|
567 /** |
|
568 * @namespace Select rows specific information |
|
569 */ |
|
570 "select": { |
|
571 /** |
|
572 * Select type - can be 'none', 'single' or 'multi' |
|
573 * @property type |
|
574 * @type string |
|
575 * @default "" |
|
576 */ |
|
577 "type": "", |
|
578 |
|
579 /** |
|
580 * Array of nodes which are currently selected |
|
581 * @property selected |
|
582 * @type array |
|
583 * @default [] |
|
584 */ |
|
585 "selected": [], |
|
586 |
|
587 /** |
|
588 * Function to run before the selection can take place. Will cancel the select if the |
|
589 * function returns false |
|
590 * @property preRowSelect |
|
591 * @type Function |
|
592 * @default null |
|
593 */ |
|
594 "preRowSelect": null, |
|
595 |
|
596 /** |
|
597 * Function to run when a row is selected |
|
598 * @property postSelected |
|
599 * @type Function |
|
600 * @default null |
|
601 */ |
|
602 "postSelected": null, |
|
603 |
|
604 /** |
|
605 * Function to run when a row is deselected |
|
606 * @property postDeselected |
|
607 * @type Function |
|
608 * @default null |
|
609 */ |
|
610 "postDeselected": null, |
|
611 |
|
612 /** |
|
613 * Indicate if all rows are selected (needed for server-side processing) |
|
614 * @property all |
|
615 * @type boolean |
|
616 * @default false |
|
617 */ |
|
618 "all": false, |
|
619 |
|
620 /** |
|
621 * Class name to add to selected TR nodes |
|
622 * @property selectedClass |
|
623 * @type String |
|
624 * @default "" |
|
625 */ |
|
626 "selectedClass": "" |
|
627 }, |
|
628 |
|
629 /** |
|
630 * Store of the user input customisation object |
|
631 * @property custom |
|
632 * @type object |
|
633 * @default {} |
|
634 */ |
|
635 "custom": {}, |
|
636 |
|
637 /** |
|
638 * SWF movie path |
|
639 * @property swfPath |
|
640 * @type string |
|
641 * @default "" |
|
642 */ |
|
643 "swfPath": "", |
|
644 |
|
645 /** |
|
646 * Default button set |
|
647 * @property buttonSet |
|
648 * @type array |
|
649 * @default [] |
|
650 */ |
|
651 "buttonSet": [], |
|
652 |
|
653 /** |
|
654 * When there is more than one TableTools instance for a DataTable, there must be a |
|
655 * master which controls events (row selection etc) |
|
656 * @property master |
|
657 * @type boolean |
|
658 * @default false |
|
659 */ |
|
660 "master": false, |
|
661 |
|
662 /** |
|
663 * Tag names that are used for creating collections and buttons |
|
664 * @namesapce |
|
665 */ |
|
666 "tags": {} |
|
667 }; |
|
668 |
|
669 |
|
670 /** |
|
671 * @namespace Common and useful DOM elements for the class instance |
|
672 */ |
|
673 this.dom = { |
|
674 /** |
|
675 * DIV element that is create and all TableTools buttons (and their children) put into |
|
676 * @property container |
|
677 * @type node |
|
678 * @default null |
|
679 */ |
|
680 "container": null, |
|
681 |
|
682 /** |
|
683 * The table node to which TableTools will be applied |
|
684 * @property table |
|
685 * @type node |
|
686 * @default null |
|
687 */ |
|
688 "table": null, |
|
689 |
|
690 /** |
|
691 * @namespace Nodes used for the print display |
|
692 */ |
|
693 "print": { |
|
694 /** |
|
695 * Nodes which have been removed from the display by setting them to display none |
|
696 * @property hidden |
|
697 * @type array |
|
698 * @default [] |
|
699 */ |
|
700 "hidden": [], |
|
701 |
|
702 /** |
|
703 * The information display saying telling the user about the print display |
|
704 * @property message |
|
705 * @type node |
|
706 * @default null |
|
707 */ |
|
708 "message": null |
|
709 }, |
|
710 |
|
711 /** |
|
712 * @namespace Nodes used for a collection display. This contains the currently used collection |
|
713 */ |
|
714 "collection": { |
|
715 /** |
|
716 * The div wrapper containing the buttons in the collection (i.e. the menu) |
|
717 * @property collection |
|
718 * @type node |
|
719 * @default null |
|
720 */ |
|
721 "collection": null, |
|
722 |
|
723 /** |
|
724 * Background display to provide focus and capture events |
|
725 * @property background |
|
726 * @type node |
|
727 * @default null |
|
728 */ |
|
729 "background": null |
|
730 } |
|
731 }; |
|
732 |
|
733 /** |
|
734 * @namespace Name space for the classes that this TableTools instance will use |
|
735 * @extends TableTools.classes |
|
736 */ |
|
737 this.classes = $.extend(true, {}, TableTools.classes); |
|
738 if (this.s.dt.bJUI) { |
|
739 $.extend(true, this.classes, TableTools.classes_themeroller); |
|
740 } |
|
741 |
|
742 |
|
743 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
744 * Public class methods |
|
745 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
746 |
|
747 /** |
|
748 * Retreieve the settings object from an instance |
|
749 * @method fnSettings |
|
750 * @returns {object} TableTools settings object |
|
751 */ |
|
752 this.fnSettings = function () { |
|
753 return this.s; |
|
754 }; |
|
755 |
|
756 |
|
757 /* Constructor logic */ |
|
758 if (typeof oOpts == 'undefined') { |
|
759 oOpts = {}; |
|
760 } |
|
761 |
|
762 this._fnConstruct(oOpts); |
|
763 |
|
764 return this; |
|
765 }; |
|
766 |
|
767 |
|
768 TableTools.prototype = { |
|
769 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
770 * Public methods |
|
771 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
772 |
|
773 /** |
|
774 * Retreieve the settings object from an instance |
|
775 * @returns {array} List of TR nodes which are currently selected |
|
776 * @param {boolean} [filtered=false] Get only selected rows which are |
|
777 * available given the filtering applied to the table. By default |
|
778 * this is false - i.e. all rows, regardless of filtering are |
|
779 selected. |
|
780 */ |
|
781 "fnGetSelected": function (filtered) { |
|
782 var |
|
783 out = [], |
|
784 data = this.s.dt.aoData, |
|
785 displayed = this.s.dt.aiDisplay, |
|
786 i, iLen; |
|
787 |
|
788 if (filtered) { |
|
789 // Only consider filtered rows |
|
790 for (i = 0, iLen = displayed.length; i < iLen; i++) { |
|
791 if (data[ displayed[i] ]._DTTT_selected) { |
|
792 out.push(data[ displayed[i] ].nTr); |
|
793 } |
|
794 } |
|
795 } |
|
796 else { |
|
797 // Use all rows |
|
798 for (i = 0, iLen = data.length; i < iLen; i++) { |
|
799 if (data[i]._DTTT_selected) { |
|
800 out.push(data[i].nTr); |
|
801 } |
|
802 } |
|
803 } |
|
804 |
|
805 return out; |
|
806 }, |
|
807 |
|
808 |
|
809 /** |
|
810 * Get the data source objects/arrays from DataTables for the selected rows (same as |
|
811 * fnGetSelected followed by fnGetData on each row from the table) |
|
812 * @returns {array} Data from the TR nodes which are currently selected |
|
813 */ |
|
814 "fnGetSelectedData": function () { |
|
815 var out = []; |
|
816 var data = this.s.dt.aoData; |
|
817 var i, iLen; |
|
818 |
|
819 for (i = 0, iLen = data.length; i < iLen; i++) { |
|
820 if (data[i]._DTTT_selected) { |
|
821 out.push(this.s.dt.oInstance.fnGetData(i)); |
|
822 } |
|
823 } |
|
824 |
|
825 return out; |
|
826 }, |
|
827 |
|
828 |
|
829 /** |
|
830 * Check to see if a current row is selected or not |
|
831 * @param {Node} n TR node to check if it is currently selected or not |
|
832 * @returns {Boolean} true if select, false otherwise |
|
833 */ |
|
834 "fnIsSelected": function (n) { |
|
835 var pos = this.s.dt.oInstance.fnGetPosition(n); |
|
836 return (this.s.dt.aoData[pos]._DTTT_selected === true) ? true : false; |
|
837 }, |
|
838 |
|
839 |
|
840 /** |
|
841 * Select all rows in the table |
|
842 * @param {boolean} [filtered=false] Select only rows which are available |
|
843 * given the filtering applied to the table. By default this is false - |
|
844 * i.e. all rows, regardless of filtering are selected. |
|
845 */ |
|
846 "fnSelectAll": function (filtered) { |
|
847 var s = this._fnGetMasterSettings(); |
|
848 |
|
849 this._fnRowSelect((filtered === true) ? |
|
850 s.dt.aiDisplay : |
|
851 s.dt.aoData |
|
852 ); |
|
853 }, |
|
854 |
|
855 |
|
856 /** |
|
857 * Deselect all rows in the table |
|
858 * @param {boolean} [filtered=false] Deselect only rows which are available |
|
859 * given the filtering applied to the table. By default this is false - |
|
860 * i.e. all rows, regardless of filtering are deselected. |
|
861 */ |
|
862 "fnSelectNone": function (filtered) { |
|
863 var s = this._fnGetMasterSettings(); |
|
864 |
|
865 this._fnRowDeselect(this.fnGetSelected(filtered)); |
|
866 }, |
|
867 |
|
868 |
|
869 /** |
|
870 * Select row(s) |
|
871 * @param {node|object|array} n The row(s) to select. Can be a single DOM |
|
872 * TR node, an array of TR nodes or a jQuery object. |
|
873 */ |
|
874 "fnSelect": function (n) { |
|
875 if (this.s.select.type == "single") { |
|
876 this.fnSelectNone(); |
|
877 this._fnRowSelect(n); |
|
878 } |
|
879 else if (this.s.select.type == "multi") { |
|
880 this._fnRowSelect(n); |
|
881 } |
|
882 }, |
|
883 |
|
884 |
|
885 /** |
|
886 * Deselect row(s) |
|
887 * @param {node|object|array} n The row(s) to deselect. Can be a single DOM |
|
888 * TR node, an array of TR nodes or a jQuery object. |
|
889 */ |
|
890 "fnDeselect": function (n) { |
|
891 this._fnRowDeselect(n); |
|
892 }, |
|
893 |
|
894 |
|
895 /** |
|
896 * Get the title of the document - useful for file names. The title is retrieved from either |
|
897 * the configuration object's 'title' parameter, or the HTML document title |
|
898 * @param {Object} oConfig Button configuration object |
|
899 * @returns {String} Button title |
|
900 */ |
|
901 "fnGetTitle": function (oConfig) { |
|
902 var sTitle = ""; |
|
903 if (typeof oConfig.sTitle != 'undefined' && oConfig.sTitle !== "") { |
|
904 sTitle = oConfig.sTitle; |
|
905 } else { |
|
906 var anTitle = document.getElementsByTagName('title'); |
|
907 if (anTitle.length > 0) { |
|
908 sTitle = anTitle[0].innerHTML; |
|
909 } |
|
910 } |
|
911 |
|
912 /* Strip characters which the OS will object to - checking for UTF8 support in the scripting |
|
913 * engine |
|
914 */ |
|
915 if ("\u00A1".toString().length < 4) { |
|
916 return sTitle.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, ""); |
|
917 } else { |
|
918 return sTitle.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g, ""); |
|
919 } |
|
920 }, |
|
921 |
|
922 |
|
923 /** |
|
924 * Calculate a unity array with the column width by proportion for a set of columns to be |
|
925 * included for a button. This is particularly useful for PDF creation, where we can use the |
|
926 * column widths calculated by the browser to size the columns in the PDF. |
|
927 * @param {Object} oConfig Button configuration object |
|
928 * @returns {Array} Unity array of column ratios |
|
929 */ |
|
930 "fnCalcColRatios": function (oConfig) { |
|
931 var |
|
932 aoCols = this.s.dt.aoColumns, |
|
933 aColumnsInc = this._fnColumnTargets(oConfig.mColumns), |
|
934 aColWidths = [], |
|
935 iWidth = 0, iTotal = 0, i, iLen; |
|
936 |
|
937 for (i = 0, iLen = aColumnsInc.length; i < iLen; i++) { |
|
938 if (aColumnsInc[i]) { |
|
939 iWidth = aoCols[i].nTh.offsetWidth; |
|
940 iTotal += iWidth; |
|
941 aColWidths.push(iWidth); |
|
942 } |
|
943 } |
|
944 |
|
945 for (i = 0, iLen = aColWidths.length; i < iLen; i++) { |
|
946 aColWidths[i] = aColWidths[i] / iTotal; |
|
947 } |
|
948 |
|
949 return aColWidths.join('\t'); |
|
950 }, |
|
951 |
|
952 |
|
953 /** |
|
954 * Get the information contained in a table as a string |
|
955 * @param {Object} oConfig Button configuration object |
|
956 * @returns {String} Table data as a string |
|
957 */ |
|
958 "fnGetTableData": function (oConfig) { |
|
959 /* In future this could be used to get data from a plain HTML source as well as DataTables */ |
|
960 if (this.s.dt) { |
|
961 return this._fnGetDataTablesData(oConfig); |
|
962 } |
|
963 }, |
|
964 |
|
965 |
|
966 /** |
|
967 * Pass text to a flash button instance, which will be used on the button's click handler |
|
968 * @param {Object} clip Flash button object |
|
969 * @param {String} text Text to set |
|
970 */ |
|
971 "fnSetText": function (clip, text) { |
|
972 this._fnFlashSetText(clip, text); |
|
973 }, |
|
974 |
|
975 |
|
976 /** |
|
977 * Resize the flash elements of the buttons attached to this TableTools instance - this is |
|
978 * useful for when initialising TableTools when it is hidden (display:none) since sizes can't |
|
979 * be calculated at that time. |
|
980 */ |
|
981 "fnResizeButtons": function () { |
|
982 for (var cli in ZeroClipboard_TableTools.clients) { |
|
983 if (cli) { |
|
984 var client = ZeroClipboard_TableTools.clients[cli]; |
|
985 if (typeof client.domElement != 'undefined' && |
|
986 client.domElement.parentNode) { |
|
987 client.positionElement(); |
|
988 } |
|
989 } |
|
990 } |
|
991 }, |
|
992 |
|
993 |
|
994 /** |
|
995 * Check to see if any of the ZeroClipboard client's attached need to be resized |
|
996 */ |
|
997 "fnResizeRequired": function () { |
|
998 for (var cli in ZeroClipboard_TableTools.clients) { |
|
999 if (cli) { |
|
1000 var client = ZeroClipboard_TableTools.clients[cli]; |
|
1001 if (typeof client.domElement != 'undefined' && |
|
1002 client.domElement.parentNode == this.dom.container && |
|
1003 client.sized === false) { |
|
1004 return true; |
|
1005 } |
|
1006 } |
|
1007 } |
|
1008 return false; |
|
1009 }, |
|
1010 |
|
1011 |
|
1012 /** |
|
1013 * Programmatically enable or disable the print view |
|
1014 * @param {boolean} [bView=true] Show the print view if true or not given. If false, then |
|
1015 * terminate the print view and return to normal. |
|
1016 * @param {object} [oConfig={}] Configuration for the print view |
|
1017 * @param {boolean} [oConfig.bShowAll=false] Show all rows in the table if true |
|
1018 * @param {string} [oConfig.sInfo] Information message, displayed as an overlay to the |
|
1019 * user to let them know what the print view is. |
|
1020 * @param {string} [oConfig.sMessage] HTML string to show at the top of the document - will |
|
1021 * be included in the printed document. |
|
1022 */ |
|
1023 "fnPrint": function (bView, oConfig) { |
|
1024 if (oConfig === undefined) { |
|
1025 oConfig = {}; |
|
1026 } |
|
1027 |
|
1028 if (bView === undefined || bView) { |
|
1029 this._fnPrintStart(oConfig); |
|
1030 } |
|
1031 else { |
|
1032 this._fnPrintEnd(); |
|
1033 } |
|
1034 }, |
|
1035 |
|
1036 |
|
1037 /** |
|
1038 * Show a message to the end user which is nicely styled |
|
1039 * @param {string} message The HTML string to show to the user |
|
1040 * @param {int} time The duration the message is to be shown on screen for (mS) |
|
1041 */ |
|
1042 "fnInfo": function (message, time) { |
|
1043 var info = $('<div/>') |
|
1044 .addClass(this.classes.print.info) |
|
1045 .html(message) |
|
1046 .appendTo('body'); |
|
1047 |
|
1048 setTimeout(function () { |
|
1049 info.fadeOut("normal", function () { |
|
1050 info.remove(); |
|
1051 }); |
|
1052 }, time); |
|
1053 }, |
|
1054 |
|
1055 |
|
1056 /** |
|
1057 * Get the container element of the instance for attaching to the DOM |
|
1058 * @returns {node} DOM node |
|
1059 */ |
|
1060 "fnContainer": function () { |
|
1061 return this.dom.container; |
|
1062 }, |
|
1063 |
|
1064 |
|
1065 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
1066 * Private methods (they are of course public in JS, but recommended as private) |
|
1067 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
1068 |
|
1069 /** |
|
1070 * Constructor logic |
|
1071 * @method _fnConstruct |
|
1072 * @param {Object} oOpts Same as TableTools constructor |
|
1073 * @returns void |
|
1074 * @private |
|
1075 */ |
|
1076 "_fnConstruct": function (oOpts) { |
|
1077 var that = this; |
|
1078 |
|
1079 this._fnCustomiseSettings(oOpts); |
|
1080 |
|
1081 /* Container element */ |
|
1082 this.dom.container = document.createElement(this.s.tags.container); |
|
1083 this.dom.container.className = this.classes.container; |
|
1084 |
|
1085 /* Row selection config */ |
|
1086 if (this.s.select.type != 'none') { |
|
1087 this._fnRowSelectConfig(); |
|
1088 } |
|
1089 |
|
1090 /* Buttons */ |
|
1091 this._fnButtonDefinations(this.s.buttonSet, this.dom.container); |
|
1092 |
|
1093 /* Destructor */ |
|
1094 this.s.dt.aoDestroyCallback.push({ |
|
1095 "sName": "TableTools", |
|
1096 "fn": function () { |
|
1097 $(that.s.dt.nTBody).off('click.DTTT_Select', 'tr'); |
|
1098 $(that.dom.container).empty(); |
|
1099 } |
|
1100 }); |
|
1101 }, |
|
1102 |
|
1103 |
|
1104 /** |
|
1105 * Take the user defined settings and the default settings and combine them. |
|
1106 * @method _fnCustomiseSettings |
|
1107 * @param {Object} oOpts Same as TableTools constructor |
|
1108 * @returns void |
|
1109 * @private |
|
1110 */ |
|
1111 "_fnCustomiseSettings": function (oOpts) { |
|
1112 /* Is this the master control instance or not? */ |
|
1113 if (typeof this.s.dt._TableToolsInit == 'undefined') { |
|
1114 this.s.master = true; |
|
1115 this.s.dt._TableToolsInit = true; |
|
1116 } |
|
1117 |
|
1118 /* We can use the table node from comparisons to group controls */ |
|
1119 this.dom.table = this.s.dt.nTable; |
|
1120 |
|
1121 /* Clone the defaults and then the user options */ |
|
1122 this.s.custom = $.extend({}, TableTools.DEFAULTS, oOpts); |
|
1123 |
|
1124 /* Flash file location */ |
|
1125 this.s.swfPath = this.s.custom.sSwfPath; |
|
1126 if (typeof ZeroClipboard_TableTools != 'undefined') { |
|
1127 ZeroClipboard_TableTools.moviePath = this.s.swfPath; |
|
1128 } |
|
1129 |
|
1130 /* Table row selecting */ |
|
1131 this.s.select.type = this.s.custom.sRowSelect; |
|
1132 this.s.select.preRowSelect = this.s.custom.fnPreRowSelect; |
|
1133 this.s.select.postSelected = this.s.custom.fnRowSelected; |
|
1134 this.s.select.postDeselected = this.s.custom.fnRowDeselected; |
|
1135 |
|
1136 // Backwards compatibility - allow the user to specify a custom class in the initialiser |
|
1137 if (this.s.custom.sSelectedClass) { |
|
1138 this.classes.select.row = this.s.custom.sSelectedClass; |
|
1139 } |
|
1140 |
|
1141 this.s.tags = this.s.custom.oTags; |
|
1142 |
|
1143 /* Button set */ |
|
1144 this.s.buttonSet = this.s.custom.aButtons; |
|
1145 }, |
|
1146 |
|
1147 |
|
1148 /** |
|
1149 * Take the user input arrays and expand them to be fully defined, and then add them to a given |
|
1150 * DOM element |
|
1151 * @method _fnButtonDefinations |
|
1152 * @param {array} buttonSet Set of user defined buttons |
|
1153 * @param {node} wrapper Node to add the created buttons to |
|
1154 * @returns void |
|
1155 * @private |
|
1156 */ |
|
1157 "_fnButtonDefinations": function (buttonSet, wrapper) { |
|
1158 var buttonDef; |
|
1159 |
|
1160 for (var i = 0, iLen = buttonSet.length; i < iLen; i++) { |
|
1161 if (typeof buttonSet[i] == "string") { |
|
1162 if (typeof TableTools.BUTTONS[ buttonSet[i] ] == 'undefined') { |
|
1163 alert("TableTools: Warning - unknown button type: " + buttonSet[i]); |
|
1164 continue; |
|
1165 } |
|
1166 buttonDef = $.extend({}, TableTools.BUTTONS[ buttonSet[i] ], true); |
|
1167 } |
|
1168 else { |
|
1169 if (typeof TableTools.BUTTONS[ buttonSet[i].sExtends ] == 'undefined') { |
|
1170 alert("TableTools: Warning - unknown button type: " + buttonSet[i].sExtends); |
|
1171 continue; |
|
1172 } |
|
1173 var o = $.extend({}, TableTools.BUTTONS[ buttonSet[i].sExtends ], true); |
|
1174 buttonDef = $.extend(o, buttonSet[i], true); |
|
1175 } |
|
1176 |
|
1177 wrapper.appendChild(this._fnCreateButton( |
|
1178 buttonDef, |
|
1179 $(wrapper).hasClass(this.classes.collection.container) |
|
1180 )); |
|
1181 } |
|
1182 }, |
|
1183 |
|
1184 |
|
1185 /** |
|
1186 * Create and configure a TableTools button |
|
1187 * @method _fnCreateButton |
|
1188 * @param {Object} oConfig Button configuration object |
|
1189 * @returns {Node} Button element |
|
1190 * @private |
|
1191 */ |
|
1192 "_fnCreateButton": function (oConfig, bCollectionButton) { |
|
1193 var nButton = this._fnButtonBase(oConfig, bCollectionButton); |
|
1194 |
|
1195 if (oConfig.sAction.match(/flash/)) { |
|
1196 this._fnFlashConfig(nButton, oConfig); |
|
1197 } |
|
1198 else if (oConfig.sAction == "text") { |
|
1199 this._fnTextConfig(nButton, oConfig); |
|
1200 } |
|
1201 else if (oConfig.sAction == "div") { |
|
1202 this._fnTextConfig(nButton, oConfig); |
|
1203 } |
|
1204 else if (oConfig.sAction == "collection") { |
|
1205 this._fnTextConfig(nButton, oConfig); |
|
1206 this._fnCollectionConfig(nButton, oConfig); |
|
1207 } |
|
1208 |
|
1209 return nButton; |
|
1210 }, |
|
1211 |
|
1212 |
|
1213 /** |
|
1214 * Create the DOM needed for the button and apply some base properties. All buttons start here |
|
1215 * @method _fnButtonBase |
|
1216 * @param {o} oConfig Button configuration object |
|
1217 * @returns {Node} DIV element for the button |
|
1218 * @private |
|
1219 */ |
|
1220 "_fnButtonBase": function (o, bCollectionButton) { |
|
1221 var sTag, sLiner, sClass; |
|
1222 |
|
1223 if (bCollectionButton) { |
|
1224 sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.collection.button; |
|
1225 sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.collection.liner; |
|
1226 sClass = this.classes.collection.buttons.normal; |
|
1227 } |
|
1228 else { |
|
1229 sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.button; |
|
1230 sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.liner; |
|
1231 sClass = this.classes.buttons.normal; |
|
1232 } |
|
1233 |
|
1234 var |
|
1235 nButton = document.createElement(sTag), |
|
1236 nSpan = document.createElement(sLiner), |
|
1237 masterS = this._fnGetMasterSettings(); |
|
1238 |
|
1239 nButton.className = sClass + " " + o.sButtonClass; |
|
1240 nButton.setAttribute('id', "ToolTables_" + this.s.dt.sInstance + "_" + masterS.buttonCounter); |
|
1241 nButton.appendChild(nSpan); |
|
1242 nSpan.innerHTML = o.sButtonText; |
|
1243 |
|
1244 masterS.buttonCounter++; |
|
1245 |
|
1246 return nButton; |
|
1247 }, |
|
1248 |
|
1249 |
|
1250 /** |
|
1251 * Get the settings object for the master instance. When more than one TableTools instance is |
|
1252 * assigned to a DataTable, only one of them can be the 'master' (for the select rows). As such, |
|
1253 * we will typically want to interact with that master for global properties. |
|
1254 * @method _fnGetMasterSettings |
|
1255 * @returns {Object} TableTools settings object |
|
1256 * @private |
|
1257 */ |
|
1258 "_fnGetMasterSettings": function () { |
|
1259 if (this.s.master) { |
|
1260 return this.s; |
|
1261 } |
|
1262 else { |
|
1263 /* Look for the master which has the same DT as this one */ |
|
1264 var instances = TableTools._aInstances; |
|
1265 for (var i = 0, iLen = instances.length; i < iLen; i++) { |
|
1266 if (this.dom.table == instances[i].s.dt.nTable) { |
|
1267 return instances[i].s; |
|
1268 } |
|
1269 } |
|
1270 } |
|
1271 }, |
|
1272 |
|
1273 |
|
1274 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
1275 * Button collection functions |
|
1276 */ |
|
1277 |
|
1278 /** |
|
1279 * Create a collection button, when activated will present a drop down list of other buttons |
|
1280 * @param {Node} nButton Button to use for the collection activation |
|
1281 * @param {Object} oConfig Button configuration object |
|
1282 * @returns void |
|
1283 * @private |
|
1284 */ |
|
1285 "_fnCollectionConfig": function (nButton, oConfig) { |
|
1286 var nHidden = document.createElement(this.s.tags.collection.container); |
|
1287 nHidden.style.display = "none"; |
|
1288 nHidden.className = this.classes.collection.container; |
|
1289 oConfig._collection = nHidden; |
|
1290 document.body.appendChild(nHidden); |
|
1291 |
|
1292 this._fnButtonDefinations(oConfig.aButtons, nHidden); |
|
1293 }, |
|
1294 |
|
1295 |
|
1296 /** |
|
1297 * Show a button collection |
|
1298 * @param {Node} nButton Button to use for the collection |
|
1299 * @param {Object} oConfig Button configuration object |
|
1300 * @returns void |
|
1301 * @private |
|
1302 */ |
|
1303 "_fnCollectionShow": function (nButton, oConfig) { |
|
1304 var |
|
1305 that = this, |
|
1306 oPos = $(nButton).offset(), |
|
1307 nHidden = oConfig._collection, |
|
1308 iDivX = oPos.left, |
|
1309 iDivY = oPos.top + $(nButton).outerHeight(), |
|
1310 iWinHeight = $(window).height(), iDocHeight = $(document).height(), |
|
1311 iWinWidth = $(window).width(), iDocWidth = $(document).width(); |
|
1312 |
|
1313 nHidden.style.position = "absolute"; |
|
1314 nHidden.style.left = iDivX + "px"; |
|
1315 nHidden.style.top = iDivY + "px"; |
|
1316 nHidden.style.display = "block"; |
|
1317 $(nHidden).css('opacity', 0); |
|
1318 |
|
1319 var nBackground = document.createElement('div'); |
|
1320 nBackground.style.position = "absolute"; |
|
1321 nBackground.style.left = "0px"; |
|
1322 nBackground.style.top = "0px"; |
|
1323 nBackground.style.height = ((iWinHeight > iDocHeight) ? iWinHeight : iDocHeight) + "px"; |
|
1324 nBackground.style.width = ((iWinWidth > iDocWidth) ? iWinWidth : iDocWidth) + "px"; |
|
1325 nBackground.className = this.classes.collection.background; |
|
1326 $(nBackground).css('opacity', 0); |
|
1327 |
|
1328 document.body.appendChild(nBackground); |
|
1329 document.body.appendChild(nHidden); |
|
1330 |
|
1331 /* Visual corrections to try and keep the collection visible */ |
|
1332 var iDivWidth = $(nHidden).outerWidth(); |
|
1333 var iDivHeight = $(nHidden).outerHeight(); |
|
1334 |
|
1335 if (iDivX + iDivWidth > iDocWidth) { |
|
1336 nHidden.style.left = (iDocWidth - iDivWidth) + "px"; |
|
1337 } |
|
1338 |
|
1339 if (iDivY + iDivHeight > iDocHeight) { |
|
1340 nHidden.style.top = (iDivY - iDivHeight - $(nButton).outerHeight()) + "px"; |
|
1341 } |
|
1342 |
|
1343 this.dom.collection.collection = nHidden; |
|
1344 this.dom.collection.background = nBackground; |
|
1345 |
|
1346 /* This results in a very small delay for the end user but it allows the animation to be |
|
1347 * much smoother. If you don't want the animation, then the setTimeout can be removed |
|
1348 */ |
|
1349 setTimeout(function () { |
|
1350 $(nHidden).animate({"opacity": 1}, 500); |
|
1351 $(nBackground).animate({"opacity": 0.25}, 500); |
|
1352 }, 10); |
|
1353 |
|
1354 /* Resize the buttons to the Flash contents fit */ |
|
1355 this.fnResizeButtons(); |
|
1356 |
|
1357 /* Event handler to remove the collection display */ |
|
1358 $(nBackground).click(function () { |
|
1359 that._fnCollectionHide.call(that, null, null); |
|
1360 }); |
|
1361 }, |
|
1362 |
|
1363 |
|
1364 /** |
|
1365 * Hide a button collection |
|
1366 * @param {Node} nButton Button to use for the collection |
|
1367 * @param {Object} oConfig Button configuration object |
|
1368 * @returns void |
|
1369 * @private |
|
1370 */ |
|
1371 "_fnCollectionHide": function (nButton, oConfig) { |
|
1372 if (oConfig !== null && oConfig.sExtends == 'collection') { |
|
1373 return; |
|
1374 } |
|
1375 |
|
1376 if (this.dom.collection.collection !== null) { |
|
1377 $(this.dom.collection.collection).animate({"opacity": 0}, 500, function (e) { |
|
1378 this.style.display = "none"; |
|
1379 }); |
|
1380 |
|
1381 $(this.dom.collection.background).animate({"opacity": 0}, 500, function (e) { |
|
1382 this.parentNode.removeChild(this); |
|
1383 }); |
|
1384 |
|
1385 this.dom.collection.collection = null; |
|
1386 this.dom.collection.background = null; |
|
1387 } |
|
1388 }, |
|
1389 |
|
1390 |
|
1391 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
1392 * Row selection functions |
|
1393 */ |
|
1394 |
|
1395 /** |
|
1396 * Add event handlers to a table to allow for row selection |
|
1397 * @method _fnRowSelectConfig |
|
1398 * @returns void |
|
1399 * @private |
|
1400 */ |
|
1401 "_fnRowSelectConfig": function () { |
|
1402 if (this.s.master) { |
|
1403 var |
|
1404 that = this, |
|
1405 i, iLen, |
|
1406 dt = this.s.dt, |
|
1407 aoOpenRows = this.s.dt.aoOpenRows; |
|
1408 |
|
1409 $(dt.nTable).addClass(this.classes.select.table); |
|
1410 |
|
1411 // When using OS style selection, we want to cancel the shift text |
|
1412 // selection, but only when the shift key is used (so you can |
|
1413 // actually still select text in the table) |
|
1414 if (this.s.select.type === 'os') { |
|
1415 $(dt.nTBody).on('mousedown.DTTT_Select', 'tr', function (e) { |
|
1416 if (e.shiftKey) { |
|
1417 |
|
1418 $(dt.nTBody) |
|
1419 .css('-moz-user-select', 'none') |
|
1420 .one('selectstart.DTTT_Select', 'tr', function () { |
|
1421 return false; |
|
1422 }); |
|
1423 } |
|
1424 }); |
|
1425 |
|
1426 $(dt.nTBody).on('mouseup.DTTT_Select', 'tr', function (e) { |
|
1427 $(dt.nTBody).css('-moz-user-select', ''); |
|
1428 }); |
|
1429 } |
|
1430 |
|
1431 // Row selection |
|
1432 $(dt.nTBody).on('click.DTTT_Select', 'tr', function (e) { |
|
1433 var select = that.s.select; |
|
1434 var pos = that.s.dt.oInstance.fnGetPosition(this); |
|
1435 |
|
1436 /* Sub-table must be ignored (odd that the selector won't do this with >) */ |
|
1437 if (this.parentNode != dt.nTBody) { |
|
1438 return; |
|
1439 } |
|
1440 |
|
1441 /* Check that we are actually working with a DataTables controlled row */ |
|
1442 if (dt.oInstance.fnGetData(this) === null) { |
|
1443 return; |
|
1444 } |
|
1445 |
|
1446 // Shift click, ctrl click and simple click handling to make |
|
1447 // row selection a lot like a file system in desktop OSs |
|
1448 if (select.type == 'os') { |
|
1449 if (e.ctrlKey || e.metaKey) { |
|
1450 // Add or remove from the selection |
|
1451 if (that.fnIsSelected(this)) { |
|
1452 that._fnRowDeselect(this, e); |
|
1453 } |
|
1454 else { |
|
1455 that._fnRowSelect(this, e); |
|
1456 } |
|
1457 } |
|
1458 else if (e.shiftKey) { |
|
1459 // Add a range of rows, from the last selected row to |
|
1460 // this one |
|
1461 var rowIdxs = that.s.dt.aiDisplay.slice(); // visible rows |
|
1462 var idx1 = $.inArray(select.lastRow, rowIdxs); |
|
1463 var idx2 = $.inArray(pos, rowIdxs); |
|
1464 |
|
1465 if (that.fnGetSelected().length === 0 || idx1 === -1) { |
|
1466 // select from top to here - slightly odd, but both |
|
1467 // Windows and Mac OS do this |
|
1468 rowIdxs.splice($.inArray(pos, rowIdxs) + 1, rowIdxs.length); |
|
1469 } |
|
1470 else { |
|
1471 // reverse so we can shift click 'up' as well as down |
|
1472 if (idx1 > idx2) { |
|
1473 var tmp = idx2; |
|
1474 idx2 = idx1; |
|
1475 idx1 = tmp; |
|
1476 } |
|
1477 |
|
1478 rowIdxs.splice(idx2 + 1, rowIdxs.length); |
|
1479 rowIdxs.splice(0, idx1); |
|
1480 } |
|
1481 |
|
1482 if (!that.fnIsSelected(this)) { |
|
1483 // Select range |
|
1484 that._fnRowSelect(rowIdxs, e); |
|
1485 } |
|
1486 else { |
|
1487 // Deselect range - need to keep the clicked on row selected |
|
1488 rowIdxs.splice($.inArray(pos, rowIdxs), 1); |
|
1489 that._fnRowDeselect(rowIdxs, e); |
|
1490 } |
|
1491 } |
|
1492 else { |
|
1493 // No cmd or shift click. Deselect current if selected, |
|
1494 // or select this row only |
|
1495 if (that.fnIsSelected(this) && that.fnGetSelected().length === 1) { |
|
1496 that._fnRowDeselect(this, e); |
|
1497 } |
|
1498 else { |
|
1499 that.fnSelectNone(); |
|
1500 that._fnRowSelect(this, e); |
|
1501 } |
|
1502 } |
|
1503 } |
|
1504 else if (that.fnIsSelected(this)) { |
|
1505 that._fnRowDeselect(this, e); |
|
1506 } |
|
1507 else if (select.type == "single") { |
|
1508 that.fnSelectNone(); |
|
1509 that._fnRowSelect(this, e); |
|
1510 } |
|
1511 else if (select.type == "multi") { |
|
1512 that._fnRowSelect(this, e); |
|
1513 } |
|
1514 |
|
1515 select.lastRow = pos; |
|
1516 });//.on('selectstart', function () { return false; } ); |
|
1517 |
|
1518 // Bind a listener to the DataTable for when new rows are created. |
|
1519 // This allows rows to be visually selected when they should be and |
|
1520 // deferred rendering is used. |
|
1521 dt.oApi._fnCallbackReg(dt, 'aoRowCreatedCallback', function (tr, data, index) { |
|
1522 if (dt.aoData[index]._DTTT_selected) { |
|
1523 $(tr).addClass(that.classes.select.row); |
|
1524 } |
|
1525 }, 'TableTools-SelectAll'); |
|
1526 } |
|
1527 }, |
|
1528 |
|
1529 /** |
|
1530 * Select rows |
|
1531 * @param {*} src Rows to select - see _fnSelectData for a description of valid inputs |
|
1532 * @private |
|
1533 */ |
|
1534 "_fnRowSelect": function (src, e) { |
|
1535 var |
|
1536 that = this, |
|
1537 data = this._fnSelectData(src), |
|
1538 firstTr = data.length === 0 ? null : data[0].nTr, |
|
1539 anSelected = [], |
|
1540 i, len; |
|
1541 |
|
1542 // Get all the rows that will be selected |
|
1543 for (i = 0, len = data.length; i < len; i++) { |
|
1544 if (data[i].nTr) { |
|
1545 anSelected.push(data[i].nTr); |
|
1546 } |
|
1547 } |
|
1548 |
|
1549 // User defined pre-selection function |
|
1550 if (this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anSelected, true)) { |
|
1551 return; |
|
1552 } |
|
1553 |
|
1554 // Mark them as selected |
|
1555 for (i = 0, len = data.length; i < len; i++) { |
|
1556 data[i]._DTTT_selected = true; |
|
1557 |
|
1558 if (data[i].nTr) { |
|
1559 $(data[i].nTr).addClass(that.classes.select.row); |
|
1560 } |
|
1561 } |
|
1562 |
|
1563 // Post-selection function |
|
1564 if (this.s.select.postSelected !== null) { |
|
1565 this.s.select.postSelected.call(this, anSelected); |
|
1566 } |
|
1567 |
|
1568 TableTools._fnEventDispatch(this, 'select', anSelected, true); |
|
1569 }, |
|
1570 |
|
1571 /** |
|
1572 * Deselect rows |
|
1573 * @param {*} src Rows to deselect - see _fnSelectData for a description of valid inputs |
|
1574 * @private |
|
1575 */ |
|
1576 "_fnRowDeselect": function (src, e) { |
|
1577 var |
|
1578 that = this, |
|
1579 data = this._fnSelectData(src), |
|
1580 firstTr = data.length === 0 ? null : data[0].nTr, |
|
1581 anDeselectedTrs = [], |
|
1582 i, len; |
|
1583 |
|
1584 // Get all the rows that will be deselected |
|
1585 for (i = 0, len = data.length; i < len; i++) { |
|
1586 if (data[i].nTr) { |
|
1587 anDeselectedTrs.push(data[i].nTr); |
|
1588 } |
|
1589 } |
|
1590 |
|
1591 // User defined pre-selection function |
|
1592 if (this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anDeselectedTrs, false)) { |
|
1593 return; |
|
1594 } |
|
1595 |
|
1596 // Mark them as deselected |
|
1597 for (i = 0, len = data.length; i < len; i++) { |
|
1598 data[i]._DTTT_selected = false; |
|
1599 |
|
1600 if (data[i].nTr) { |
|
1601 $(data[i].nTr).removeClass(that.classes.select.row); |
|
1602 } |
|
1603 } |
|
1604 |
|
1605 // Post-deselection function |
|
1606 if (this.s.select.postDeselected !== null) { |
|
1607 this.s.select.postDeselected.call(this, anDeselectedTrs); |
|
1608 } |
|
1609 |
|
1610 TableTools._fnEventDispatch(this, 'select', anDeselectedTrs, false); |
|
1611 }, |
|
1612 |
|
1613 /** |
|
1614 * Take a data source for row selection and convert it into aoData points for the DT |
|
1615 * @param {*} src Can be a single DOM TR node, an array of TR nodes (including a |
|
1616 * a jQuery object), a single aoData point from DataTables, an array of aoData |
|
1617 * points or an array of aoData indexes |
|
1618 * @returns {array} An array of aoData points |
|
1619 */ |
|
1620 "_fnSelectData": function (src) { |
|
1621 var out = [], pos, i, iLen; |
|
1622 |
|
1623 if (src.nodeName) { |
|
1624 // Single node |
|
1625 pos = this.s.dt.oInstance.fnGetPosition(src); |
|
1626 out.push(this.s.dt.aoData[pos]); |
|
1627 } |
|
1628 else if (typeof src.length !== 'undefined') { |
|
1629 // jQuery object or an array of nodes, or aoData points |
|
1630 for (i = 0, iLen = src.length; i < iLen; i++) { |
|
1631 if (src[i].nodeName) { |
|
1632 pos = this.s.dt.oInstance.fnGetPosition(src[i]); |
|
1633 out.push(this.s.dt.aoData[pos]); |
|
1634 } |
|
1635 else if (typeof src[i] === 'number') { |
|
1636 out.push(this.s.dt.aoData[ src[i] ]); |
|
1637 } |
|
1638 else { |
|
1639 out.push(src[i]); |
|
1640 } |
|
1641 } |
|
1642 |
|
1643 return out; |
|
1644 } |
|
1645 else { |
|
1646 // A single aoData point |
|
1647 out.push(src); |
|
1648 } |
|
1649 |
|
1650 return out; |
|
1651 }, |
|
1652 |
|
1653 |
|
1654 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
1655 * Text button functions |
|
1656 */ |
|
1657 |
|
1658 /** |
|
1659 * Configure a text based button for interaction events |
|
1660 * @method _fnTextConfig |
|
1661 * @param {Node} nButton Button element which is being considered |
|
1662 * @param {Object} oConfig Button configuration object |
|
1663 * @returns void |
|
1664 * @private |
|
1665 */ |
|
1666 "_fnTextConfig": function (nButton, oConfig) { |
|
1667 var that = this; |
|
1668 |
|
1669 if (oConfig.fnInit !== null) { |
|
1670 oConfig.fnInit.call(this, nButton, oConfig); |
|
1671 } |
|
1672 |
|
1673 if (oConfig.sToolTip !== "") { |
|
1674 nButton.title = oConfig.sToolTip; |
|
1675 } |
|
1676 |
|
1677 $(nButton).hover(function () { |
|
1678 if (oConfig.fnMouseover !== null) { |
|
1679 oConfig.fnMouseover.call(this, nButton, oConfig, null); |
|
1680 } |
|
1681 }, function () { |
|
1682 if (oConfig.fnMouseout !== null) { |
|
1683 oConfig.fnMouseout.call(this, nButton, oConfig, null); |
|
1684 } |
|
1685 }); |
|
1686 |
|
1687 if (oConfig.fnSelect !== null) { |
|
1688 TableTools._fnEventListen(this, 'select', function (n) { |
|
1689 oConfig.fnSelect.call(that, nButton, oConfig, n); |
|
1690 }); |
|
1691 } |
|
1692 |
|
1693 $(nButton).click(function (e) { |
|
1694 //e.preventDefault(); |
|
1695 |
|
1696 if (oConfig.fnClick !== null) { |
|
1697 oConfig.fnClick.call(that, nButton, oConfig, null, e); |
|
1698 } |
|
1699 |
|
1700 /* Provide a complete function to match the behaviour of the flash elements */ |
|
1701 if (oConfig.fnComplete !== null) { |
|
1702 oConfig.fnComplete.call(that, nButton, oConfig, null, null); |
|
1703 } |
|
1704 |
|
1705 that._fnCollectionHide(nButton, oConfig); |
|
1706 }); |
|
1707 }, |
|
1708 |
|
1709 |
|
1710 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
1711 * Flash button functions |
|
1712 */ |
|
1713 |
|
1714 /** |
|
1715 * Configure a flash based button for interaction events |
|
1716 * @method _fnFlashConfig |
|
1717 * @param {Node} nButton Button element which is being considered |
|
1718 * @param {o} oConfig Button configuration object |
|
1719 * @returns void |
|
1720 * @private |
|
1721 */ |
|
1722 "_fnFlashConfig": function (nButton, oConfig) { |
|
1723 var that = this; |
|
1724 var flash = new ZeroClipboard_TableTools.Client(); |
|
1725 |
|
1726 if (oConfig.fnInit !== null) { |
|
1727 oConfig.fnInit.call(this, nButton, oConfig); |
|
1728 } |
|
1729 |
|
1730 flash.setHandCursor(true); |
|
1731 |
|
1732 if (oConfig.sAction == "flash_save") { |
|
1733 flash.setAction('save'); |
|
1734 flash.setCharSet((oConfig.sCharSet == "utf16le") ? 'UTF16LE' : 'UTF8'); |
|
1735 flash.setBomInc(oConfig.bBomInc); |
|
1736 flash.setFileName(oConfig.sFileName.replace('*', this.fnGetTitle(oConfig))); |
|
1737 } |
|
1738 else if (oConfig.sAction == "flash_pdf") { |
|
1739 flash.setAction('pdf'); |
|
1740 flash.setFileName(oConfig.sFileName.replace('*', this.fnGetTitle(oConfig))); |
|
1741 } |
|
1742 else { |
|
1743 flash.setAction('copy'); |
|
1744 } |
|
1745 |
|
1746 flash.addEventListener('mouseOver', function (client) { |
|
1747 if (oConfig.fnMouseover !== null) { |
|
1748 oConfig.fnMouseover.call(that, nButton, oConfig, flash); |
|
1749 } |
|
1750 }); |
|
1751 |
|
1752 flash.addEventListener('mouseOut', function (client) { |
|
1753 if (oConfig.fnMouseout !== null) { |
|
1754 oConfig.fnMouseout.call(that, nButton, oConfig, flash); |
|
1755 } |
|
1756 }); |
|
1757 |
|
1758 flash.addEventListener('mouseDown', function (client) { |
|
1759 if (oConfig.fnClick !== null) { |
|
1760 oConfig.fnClick.call(that, nButton, oConfig, flash); |
|
1761 } |
|
1762 }); |
|
1763 |
|
1764 flash.addEventListener('complete', function (client, text) { |
|
1765 if (oConfig.fnComplete !== null) { |
|
1766 oConfig.fnComplete.call(that, nButton, oConfig, flash, text); |
|
1767 } |
|
1768 that._fnCollectionHide(nButton, oConfig); |
|
1769 }); |
|
1770 |
|
1771 this._fnFlashGlue(flash, nButton, oConfig.sToolTip); |
|
1772 }, |
|
1773 |
|
1774 |
|
1775 /** |
|
1776 * Wait until the id is in the DOM before we "glue" the swf. Note that this function will call |
|
1777 * itself (using setTimeout) until it completes successfully |
|
1778 * @method _fnFlashGlue |
|
1779 * @param {Object} clip Zero clipboard object |
|
1780 * @param {Node} node node to glue swf to |
|
1781 * @param {String} text title of the flash movie |
|
1782 * @returns void |
|
1783 * @private |
|
1784 */ |
|
1785 "_fnFlashGlue": function (flash, node, text) { |
|
1786 var that = this; |
|
1787 var id = node.getAttribute('id'); |
|
1788 |
|
1789 if (document.getElementById(id)) { |
|
1790 flash.glue(node, text); |
|
1791 } |
|
1792 else { |
|
1793 setTimeout(function () { |
|
1794 that._fnFlashGlue(flash, node, text); |
|
1795 }, 100); |
|
1796 } |
|
1797 }, |
|
1798 |
|
1799 |
|
1800 /** |
|
1801 * Set the text for the flash clip to deal with |
|
1802 * |
|
1803 * This function is required for large information sets. There is a limit on the |
|
1804 * amount of data that can be transferred between Javascript and Flash in a single call, so |
|
1805 * we use this method to build up the text in Flash by sending over chunks. It is estimated |
|
1806 * that the data limit is around 64k, although it is undocumented, and appears to be different |
|
1807 * between different flash versions. We chunk at 8KiB. |
|
1808 * @method _fnFlashSetText |
|
1809 * @param {Object} clip the ZeroClipboard object |
|
1810 * @param {String} sData the data to be set |
|
1811 * @returns void |
|
1812 * @private |
|
1813 */ |
|
1814 "_fnFlashSetText": function (clip, sData) { |
|
1815 var asData = this._fnChunkData(sData, 8192); |
|
1816 |
|
1817 clip.clearText(); |
|
1818 for (var i = 0, iLen = asData.length; i < iLen; i++) { |
|
1819 clip.appendText(asData[i]); |
|
1820 } |
|
1821 }, |
|
1822 |
|
1823 |
|
1824 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
1825 * Data retrieval functions |
|
1826 */ |
|
1827 |
|
1828 /** |
|
1829 * Convert the mixed columns variable into a boolean array the same size as the columns, which |
|
1830 * indicates which columns we want to include |
|
1831 * @method _fnColumnTargets |
|
1832 * @param {String|Array} mColumns The columns to be included in data retrieval. If a string |
|
1833 * then it can take the value of "visible" or "hidden" (to include all visible or |
|
1834 * hidden columns respectively). Or an array of column indexes |
|
1835 * @returns {Array} A boolean array the length of the columns of the table, which each value |
|
1836 * indicating if the column is to be included or not |
|
1837 * @private |
|
1838 */ |
|
1839 "_fnColumnTargets": function (mColumns) { |
|
1840 var aColumns = []; |
|
1841 var dt = this.s.dt; |
|
1842 var i, iLen; |
|
1843 |
|
1844 if (typeof mColumns == "object") { |
|
1845 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
1846 aColumns.push(false); |
|
1847 } |
|
1848 |
|
1849 for (i = 0, iLen = mColumns.length; i < iLen; i++) { |
|
1850 aColumns[ mColumns[i] ] = true; |
|
1851 } |
|
1852 } |
|
1853 else if (mColumns == "visible") { |
|
1854 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
1855 aColumns.push(dt.aoColumns[i].bVisible ? true : false); |
|
1856 } |
|
1857 } |
|
1858 else if (mColumns == "hidden") { |
|
1859 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
1860 aColumns.push(dt.aoColumns[i].bVisible ? false : true); |
|
1861 } |
|
1862 } |
|
1863 else if (mColumns == "sortable") { |
|
1864 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
1865 aColumns.push(dt.aoColumns[i].bSortable ? true : false); |
|
1866 } |
|
1867 } |
|
1868 else /* all */ |
|
1869 { |
|
1870 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
1871 aColumns.push(true); |
|
1872 } |
|
1873 } |
|
1874 |
|
1875 return aColumns; |
|
1876 }, |
|
1877 |
|
1878 |
|
1879 /** |
|
1880 * New line character(s) depend on the platforms |
|
1881 * @method method |
|
1882 * @param {Object} oConfig Button configuration object - only interested in oConfig.sNewLine |
|
1883 * @returns {String} Newline character |
|
1884 */ |
|
1885 "_fnNewline": function (oConfig) { |
|
1886 if (oConfig.sNewLine == "auto") { |
|
1887 return navigator.userAgent.match(/Windows/) ? "\r\n" : "\n"; |
|
1888 } |
|
1889 else { |
|
1890 return oConfig.sNewLine; |
|
1891 } |
|
1892 }, |
|
1893 |
|
1894 |
|
1895 /** |
|
1896 * Get data from DataTables' internals and format it for output |
|
1897 * @method _fnGetDataTablesData |
|
1898 * @param {Object} oConfig Button configuration object |
|
1899 * @param {String} oConfig.sFieldBoundary Field boundary for the data cells in the string |
|
1900 * @param {String} oConfig.sFieldSeperator Field separator for the data cells |
|
1901 * @param {String} oConfig.sNewline New line options |
|
1902 * @param {Mixed} oConfig.mColumns Which columns should be included in the output |
|
1903 * @param {Boolean} oConfig.bHeader Include the header |
|
1904 * @param {Boolean} oConfig.bFooter Include the footer |
|
1905 * @param {Boolean} oConfig.bSelectedOnly Include only the selected rows in the output |
|
1906 * @returns {String} Concatenated string of data |
|
1907 * @private |
|
1908 */ |
|
1909 "_fnGetDataTablesData": function (oConfig) { |
|
1910 var i, iLen, j, jLen; |
|
1911 var aRow, aData = [], sLoopData = '', arr; |
|
1912 var dt = this.s.dt, tr, child; |
|
1913 var regex = new RegExp(oConfig.sFieldBoundary, "g"); |
|
1914 /* Do it here for speed */ |
|
1915 var aColumnsInc = this._fnColumnTargets(oConfig.mColumns); |
|
1916 var bSelectedOnly = (typeof oConfig.bSelectedOnly != 'undefined') ? oConfig.bSelectedOnly : false; |
|
1917 |
|
1918 /* |
|
1919 * Header |
|
1920 */ |
|
1921 if (oConfig.bHeader) { |
|
1922 aRow = []; |
|
1923 |
|
1924 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
1925 if (aColumnsInc[i]) { |
|
1926 sLoopData = dt.aoColumns[i].sTitle.replace(/\n/g, " ").replace(/<.*?>/g, "").replace(/^\s+|\s+$/g, ""); |
|
1927 sLoopData = this._fnHtmlDecode(sLoopData); |
|
1928 |
|
1929 aRow.push(this._fnBoundData(sLoopData, oConfig.sFieldBoundary, regex)); |
|
1930 } |
|
1931 } |
|
1932 |
|
1933 aData.push(aRow.join(oConfig.sFieldSeperator)); |
|
1934 } |
|
1935 |
|
1936 /* |
|
1937 * Body |
|
1938 */ |
|
1939 var aSelected = this.fnGetSelected(); |
|
1940 bSelectedOnly = this.s.select.type !== "none" && bSelectedOnly && aSelected.length !== 0; |
|
1941 |
|
1942 var aDataIndex = dt.oInstance |
|
1943 .$('tr', oConfig.oSelectorOpts) |
|
1944 .map(function (id, row) { |
|
1945 // If "selected only", then ensure that the row is in the selected list |
|
1946 return bSelectedOnly && $.inArray(row, aSelected) === -1 ? |
|
1947 null : |
|
1948 dt.oInstance.fnGetPosition(row); |
|
1949 }) |
|
1950 .get(); |
|
1951 |
|
1952 for (j = 0, jLen = aDataIndex.length; j < jLen; j++) { |
|
1953 tr = dt.aoData[ aDataIndex[j] ].nTr; |
|
1954 aRow = []; |
|
1955 |
|
1956 /* Columns */ |
|
1957 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
1958 if (aColumnsInc[i]) { |
|
1959 /* Convert to strings (with small optimisation) */ |
|
1960 var mTypeData = dt.oApi._fnGetCellData(dt, aDataIndex[j], i, 'display'); |
|
1961 if (oConfig.fnCellRender) { |
|
1962 sLoopData = oConfig.fnCellRender(mTypeData, i, tr, aDataIndex[j]) + ""; |
|
1963 } |
|
1964 else if (typeof mTypeData == "string") { |
|
1965 /* Strip newlines, replace img tags with alt attr. and finally strip html... */ |
|
1966 sLoopData = mTypeData.replace(/\n/g, " "); |
|
1967 sLoopData = |
|
1968 sLoopData.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi, |
|
1969 '$1$2$3'); |
|
1970 sLoopData = sLoopData.replace(/<.*?>/g, ""); |
|
1971 } |
|
1972 else { |
|
1973 sLoopData = mTypeData + ""; |
|
1974 } |
|
1975 |
|
1976 /* Trim and clean the data */ |
|
1977 sLoopData = sLoopData.replace(/^\s+/, '').replace(/\s+$/, ''); |
|
1978 sLoopData = this._fnHtmlDecode(sLoopData); |
|
1979 |
|
1980 /* Bound it and add it to the total data */ |
|
1981 aRow.push(this._fnBoundData(sLoopData, oConfig.sFieldBoundary, regex)); |
|
1982 } |
|
1983 } |
|
1984 |
|
1985 aData.push(aRow.join(oConfig.sFieldSeperator)); |
|
1986 |
|
1987 /* Details rows from fnOpen */ |
|
1988 if (oConfig.bOpenRows) { |
|
1989 arr = $.grep(dt.aoOpenRows, function (o) { |
|
1990 return o.nParent === tr; |
|
1991 }); |
|
1992 |
|
1993 if (arr.length === 1) { |
|
1994 sLoopData = this._fnBoundData($('td', arr[0].nTr).html(), oConfig.sFieldBoundary, regex); |
|
1995 aData.push(sLoopData); |
|
1996 } |
|
1997 } |
|
1998 } |
|
1999 |
|
2000 /* |
|
2001 * Footer |
|
2002 */ |
|
2003 if (oConfig.bFooter && dt.nTFoot !== null) { |
|
2004 aRow = []; |
|
2005 |
|
2006 for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) { |
|
2007 if (aColumnsInc[i] && dt.aoColumns[i].nTf !== null) { |
|
2008 sLoopData = dt.aoColumns[i].nTf.innerHTML.replace(/\n/g, " ").replace(/<.*?>/g, ""); |
|
2009 sLoopData = this._fnHtmlDecode(sLoopData); |
|
2010 |
|
2011 aRow.push(this._fnBoundData(sLoopData, oConfig.sFieldBoundary, regex)); |
|
2012 } |
|
2013 } |
|
2014 |
|
2015 aData.push(aRow.join(oConfig.sFieldSeperator)); |
|
2016 } |
|
2017 |
|
2018 var _sLastData = aData.join(this._fnNewline(oConfig)); |
|
2019 return _sLastData; |
|
2020 }, |
|
2021 |
|
2022 |
|
2023 /** |
|
2024 * Wrap data up with a boundary string |
|
2025 * @method _fnBoundData |
|
2026 * @param {String} sData data to bound |
|
2027 * @param {String} sBoundary bounding char(s) |
|
2028 * @param {RegExp} regex search for the bounding chars - constructed outside for efficiency |
|
2029 * in the loop |
|
2030 * @returns {String} bound data |
|
2031 * @private |
|
2032 */ |
|
2033 "_fnBoundData": function (sData, sBoundary, regex) { |
|
2034 if (sBoundary === "") { |
|
2035 return sData; |
|
2036 } |
|
2037 else { |
|
2038 return sBoundary + sData.replace(regex, sBoundary + sBoundary) + sBoundary; |
|
2039 } |
|
2040 }, |
|
2041 |
|
2042 |
|
2043 /** |
|
2044 * Break a string up into an array of smaller strings |
|
2045 * @method _fnChunkData |
|
2046 * @param {String} sData data to be broken up |
|
2047 * @param {Int} iSize chunk size |
|
2048 * @returns {Array} String array of broken up text |
|
2049 * @private |
|
2050 */ |
|
2051 "_fnChunkData": function (sData, iSize) { |
|
2052 var asReturn = []; |
|
2053 var iStrlen = sData.length; |
|
2054 |
|
2055 for (var i = 0; i < iStrlen; i += iSize) { |
|
2056 if (i + iSize < iStrlen) { |
|
2057 asReturn.push(sData.substring(i, i + iSize)); |
|
2058 } |
|
2059 else { |
|
2060 asReturn.push(sData.substring(i, iStrlen)); |
|
2061 } |
|
2062 } |
|
2063 |
|
2064 return asReturn; |
|
2065 }, |
|
2066 |
|
2067 |
|
2068 /** |
|
2069 * Decode HTML entities |
|
2070 * @method _fnHtmlDecode |
|
2071 * @param {String} sData encoded string |
|
2072 * @returns {String} decoded string |
|
2073 * @private |
|
2074 */ |
|
2075 "_fnHtmlDecode": function (sData) { |
|
2076 if (sData.indexOf('&') === -1) { |
|
2077 return sData; |
|
2078 } |
|
2079 |
|
2080 var n = document.createElement('div'); |
|
2081 |
|
2082 return sData.replace(/&([^\s]*);/g, function (match, match2) { |
|
2083 if (match.substr(1, 1) === '#') { |
|
2084 return String.fromCharCode(Number(match2.substr(1))); |
|
2085 } |
|
2086 else { |
|
2087 n.innerHTML = match; |
|
2088 return n.childNodes[0].nodeValue; |
|
2089 } |
|
2090 }); |
|
2091 }, |
|
2092 |
|
2093 |
|
2094 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
2095 * Printing functions |
|
2096 */ |
|
2097 |
|
2098 /** |
|
2099 * Show print display |
|
2100 * @method _fnPrintStart |
|
2101 * @param {Event} e Event object |
|
2102 * @param {Object} oConfig Button configuration object |
|
2103 * @returns void |
|
2104 * @private |
|
2105 */ |
|
2106 "_fnPrintStart": function (oConfig) { |
|
2107 var that = this; |
|
2108 var oSetDT = this.s.dt; |
|
2109 |
|
2110 /* Parse through the DOM hiding everything that isn't needed for the table */ |
|
2111 this._fnPrintHideNodes(oSetDT.nTable); |
|
2112 |
|
2113 /* Show the whole table */ |
|
2114 this.s.print.saveStart = oSetDT._iDisplayStart; |
|
2115 this.s.print.saveLength = oSetDT._iDisplayLength; |
|
2116 |
|
2117 if (oConfig.bShowAll) { |
|
2118 oSetDT._iDisplayStart = 0; |
|
2119 oSetDT._iDisplayLength = -1; |
|
2120 if (oSetDT.oApi._fnCalculateEnd) { |
|
2121 oSetDT.oApi._fnCalculateEnd(oSetDT); |
|
2122 } |
|
2123 oSetDT.oApi._fnDraw(oSetDT); |
|
2124 } |
|
2125 |
|
2126 /* Adjust the display for scrolling which might be done by DataTables */ |
|
2127 if (oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "") { |
|
2128 this._fnPrintScrollStart(oSetDT); |
|
2129 |
|
2130 // If the table redraws while in print view, the DataTables scrolling |
|
2131 // setup would hide the header, so we need to readd it on draw |
|
2132 $(this.s.dt.nTable).bind('draw.DTTT_Print', function () { |
|
2133 that._fnPrintScrollStart(oSetDT); |
|
2134 }); |
|
2135 } |
|
2136 |
|
2137 /* Remove the other DataTables feature nodes - but leave the table! and info div */ |
|
2138 var anFeature = oSetDT.aanFeatures; |
|
2139 for (var cFeature in anFeature) { |
|
2140 if (cFeature != 'i' && cFeature != 't' && cFeature.length == 1) { |
|
2141 for (var i = 0, iLen = anFeature[cFeature].length; i < iLen; i++) { |
|
2142 this.dom.print.hidden.push({ |
|
2143 "node": anFeature[cFeature][i], |
|
2144 "display": "block" |
|
2145 }); |
|
2146 anFeature[cFeature][i].style.display = "none"; |
|
2147 } |
|
2148 } |
|
2149 } |
|
2150 |
|
2151 /* Print class can be used for styling */ |
|
2152 $(document.body).addClass(this.classes.print.body); |
|
2153 |
|
2154 /* Show information message to let the user know what is happening */ |
|
2155 if (oConfig.sInfo !== "") { |
|
2156 this.fnInfo(oConfig.sInfo, 3000); |
|
2157 } |
|
2158 |
|
2159 /* Add a message at the top of the page */ |
|
2160 if (oConfig.sMessage) { |
|
2161 $('<div/>') |
|
2162 .addClass(this.classes.print.message) |
|
2163 .html(oConfig.sMessage) |
|
2164 .prepend('body'); |
|
2165 } |
|
2166 |
|
2167 /* Cache the scrolling and the jump to the top of the page */ |
|
2168 this.s.print.saveScroll = $(window).scrollTop(); |
|
2169 window.scrollTo(0, 0); |
|
2170 |
|
2171 /* Bind a key event listener to the document for the escape key - |
|
2172 * it is removed in the callback |
|
2173 */ |
|
2174 $(document).bind("keydown.DTTT", function (e) { |
|
2175 /* Only interested in the escape key */ |
|
2176 if (e.keyCode == 27) { |
|
2177 e.preventDefault(); |
|
2178 that._fnPrintEnd.call(that, e); |
|
2179 } |
|
2180 }); |
|
2181 }, |
|
2182 |
|
2183 |
|
2184 /** |
|
2185 * Printing is finished, resume normal display |
|
2186 * @method _fnPrintEnd |
|
2187 * @param {Event} e Event object |
|
2188 * @returns void |
|
2189 * @private |
|
2190 */ |
|
2191 "_fnPrintEnd": function (e) { |
|
2192 var that = this; |
|
2193 var oSetDT = this.s.dt; |
|
2194 var oSetPrint = this.s.print; |
|
2195 var oDomPrint = this.dom.print; |
|
2196 |
|
2197 /* Show all hidden nodes */ |
|
2198 this._fnPrintShowNodes(); |
|
2199 |
|
2200 /* Restore DataTables' scrolling */ |
|
2201 if (oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "") { |
|
2202 $(this.s.dt.nTable).unbind('draw.DTTT_Print'); |
|
2203 |
|
2204 this._fnPrintScrollEnd(); |
|
2205 } |
|
2206 |
|
2207 /* Restore the scroll */ |
|
2208 window.scrollTo(0, oSetPrint.saveScroll); |
|
2209 |
|
2210 /* Drop the print message */ |
|
2211 if (oDomPrint.message !== null) { |
|
2212 document.body.removeChild(oDomPrint.message); |
|
2213 oDomPrint.message = null; |
|
2214 } |
|
2215 |
|
2216 /* Styling class */ |
|
2217 $(document.body).removeClass('DTTT_Print'); |
|
2218 |
|
2219 /* Restore the table length */ |
|
2220 oSetDT._iDisplayStart = oSetPrint.saveStart; |
|
2221 oSetDT._iDisplayLength = oSetPrint.saveLength; |
|
2222 if (oSetDT.oApi._fnCalculateEnd) { |
|
2223 oSetDT.oApi._fnCalculateEnd(oSetDT); |
|
2224 } |
|
2225 oSetDT.oApi._fnDraw(oSetDT); |
|
2226 |
|
2227 $(document).unbind("keydown.DTTT"); |
|
2228 }, |
|
2229 |
|
2230 |
|
2231 /** |
|
2232 * Take account of scrolling in DataTables by showing the full table |
|
2233 * @returns void |
|
2234 * @private |
|
2235 */ |
|
2236 "_fnPrintScrollStart": function () { |
|
2237 var |
|
2238 oSetDT = this.s.dt, |
|
2239 nScrollHeadInner = oSetDT.nScrollHead.getElementsByTagName('div')[0], |
|
2240 nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], |
|
2241 nScrollBody = oSetDT.nTable.parentNode, |
|
2242 nTheadSize, nTfootSize; |
|
2243 |
|
2244 /* Copy the header in the thead in the body table, this way we show one single table when |
|
2245 * in print view. Note that this section of code is more or less verbatim from DT 1.7.0 |
|
2246 */ |
|
2247 nTheadSize = oSetDT.nTable.getElementsByTagName('thead'); |
|
2248 if (nTheadSize.length > 0) { |
|
2249 oSetDT.nTable.removeChild(nTheadSize[0]); |
|
2250 } |
|
2251 |
|
2252 if (oSetDT.nTFoot !== null) { |
|
2253 nTfootSize = oSetDT.nTable.getElementsByTagName('tfoot'); |
|
2254 if (nTfootSize.length > 0) { |
|
2255 oSetDT.nTable.removeChild(nTfootSize[0]); |
|
2256 } |
|
2257 } |
|
2258 |
|
2259 nTheadSize = oSetDT.nTHead.cloneNode(true); |
|
2260 oSetDT.nTable.insertBefore(nTheadSize, oSetDT.nTable.childNodes[0]); |
|
2261 |
|
2262 if (oSetDT.nTFoot !== null) { |
|
2263 nTfootSize = oSetDT.nTFoot.cloneNode(true); |
|
2264 oSetDT.nTable.insertBefore(nTfootSize, oSetDT.nTable.childNodes[1]); |
|
2265 } |
|
2266 |
|
2267 /* Now adjust the table's viewport so we can actually see it */ |
|
2268 if (oSetDT.oScroll.sX !== "") { |
|
2269 oSetDT.nTable.style.width = $(oSetDT.nTable).outerWidth() + "px"; |
|
2270 nScrollBody.style.width = $(oSetDT.nTable).outerWidth() + "px"; |
|
2271 nScrollBody.style.overflow = "visible"; |
|
2272 } |
|
2273 |
|
2274 if (oSetDT.oScroll.sY !== "") { |
|
2275 nScrollBody.style.height = $(oSetDT.nTable).outerHeight() + "px"; |
|
2276 nScrollBody.style.overflow = "visible"; |
|
2277 } |
|
2278 }, |
|
2279 |
|
2280 |
|
2281 /** |
|
2282 * Take account of scrolling in DataTables by showing the full table. Note that the redraw of |
|
2283 * the DataTable that we do will actually deal with the majority of the hard work here |
|
2284 * @returns void |
|
2285 * @private |
|
2286 */ |
|
2287 "_fnPrintScrollEnd": function () { |
|
2288 var |
|
2289 oSetDT = this.s.dt, |
|
2290 nScrollBody = oSetDT.nTable.parentNode; |
|
2291 |
|
2292 if (oSetDT.oScroll.sX !== "") { |
|
2293 nScrollBody.style.width = oSetDT.oApi._fnStringToCss(oSetDT.oScroll.sX); |
|
2294 nScrollBody.style.overflow = "auto"; |
|
2295 } |
|
2296 |
|
2297 if (oSetDT.oScroll.sY !== "") { |
|
2298 nScrollBody.style.height = oSetDT.oApi._fnStringToCss(oSetDT.oScroll.sY); |
|
2299 nScrollBody.style.overflow = "auto"; |
|
2300 } |
|
2301 }, |
|
2302 |
|
2303 |
|
2304 /** |
|
2305 * Resume the display of all TableTools hidden nodes |
|
2306 * @method _fnPrintShowNodes |
|
2307 * @returns void |
|
2308 * @private |
|
2309 */ |
|
2310 "_fnPrintShowNodes": function () { |
|
2311 var anHidden = this.dom.print.hidden; |
|
2312 |
|
2313 for (var i = 0, iLen = anHidden.length; i < iLen; i++) { |
|
2314 anHidden[i].node.style.display = anHidden[i].display; |
|
2315 } |
|
2316 anHidden.splice(0, anHidden.length); |
|
2317 }, |
|
2318 |
|
2319 |
|
2320 /** |
|
2321 * Hide nodes which are not needed in order to display the table. Note that this function is |
|
2322 * recursive |
|
2323 * @method _fnPrintHideNodes |
|
2324 * @param {Node} nNode Element which should be showing in a 'print' display |
|
2325 * @returns void |
|
2326 * @private |
|
2327 */ |
|
2328 "_fnPrintHideNodes": function (nNode) { |
|
2329 var anHidden = this.dom.print.hidden; |
|
2330 |
|
2331 var nParent = nNode.parentNode; |
|
2332 var nChildren = nParent.childNodes; |
|
2333 for (var i = 0, iLen = nChildren.length; i < iLen; i++) { |
|
2334 if (nChildren[i] != nNode && nChildren[i].nodeType == 1) { |
|
2335 /* If our node is shown (don't want to show nodes which were previously hidden) */ |
|
2336 var sDisplay = $(nChildren[i]).css("display"); |
|
2337 if (sDisplay != "none") { |
|
2338 /* Cache the node and it's previous state so we can restore it */ |
|
2339 anHidden.push({ |
|
2340 "node": nChildren[i], |
|
2341 "display": sDisplay |
|
2342 }); |
|
2343 nChildren[i].style.display = "none"; |
|
2344 } |
|
2345 } |
|
2346 } |
|
2347 |
|
2348 if (nParent.nodeName.toUpperCase() != "BODY") { |
|
2349 this._fnPrintHideNodes(nParent); |
|
2350 } |
|
2351 } |
|
2352 }; |
|
2353 |
|
2354 |
|
2355 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
2356 * Static variables |
|
2357 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
2358 |
|
2359 /** |
|
2360 * Store of all instances that have been created of TableTools, so one can look up other (when |
|
2361 * there is need of a master) |
|
2362 * @property _aInstances |
|
2363 * @type Array |
|
2364 * @default [] |
|
2365 * @private |
|
2366 */ |
|
2367 TableTools._aInstances = []; |
|
2368 |
|
2369 |
|
2370 /** |
|
2371 * Store of all listeners and their callback functions |
|
2372 * @property _aListeners |
|
2373 * @type Array |
|
2374 * @default [] |
|
2375 */ |
|
2376 TableTools._aListeners = []; |
|
2377 |
|
2378 |
|
2379 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
2380 * Static methods |
|
2381 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
2382 |
|
2383 /** |
|
2384 * Get an array of all the master instances |
|
2385 * @method fnGetMasters |
|
2386 * @returns {Array} List of master TableTools instances |
|
2387 * @static |
|
2388 */ |
|
2389 TableTools.fnGetMasters = function () { |
|
2390 var a = []; |
|
2391 for (var i = 0, iLen = TableTools._aInstances.length; i < iLen; i++) { |
|
2392 if (TableTools._aInstances[i].s.master) { |
|
2393 a.push(TableTools._aInstances[i]); |
|
2394 } |
|
2395 } |
|
2396 return a; |
|
2397 }; |
|
2398 |
|
2399 /** |
|
2400 * Get the master instance for a table node (or id if a string is given) |
|
2401 * @method fnGetInstance |
|
2402 * @returns {Object} ID of table OR table node, for which we want the TableTools instance |
|
2403 * @static |
|
2404 */ |
|
2405 TableTools.fnGetInstance = function (node) { |
|
2406 if (typeof node != 'object') { |
|
2407 node = document.getElementById(node); |
|
2408 } |
|
2409 |
|
2410 for (var i = 0, iLen = TableTools._aInstances.length; i < iLen; i++) { |
|
2411 if (TableTools._aInstances[i].s.master && TableTools._aInstances[i].dom.table == node) { |
|
2412 return TableTools._aInstances[i]; |
|
2413 } |
|
2414 } |
|
2415 return null; |
|
2416 }; |
|
2417 |
|
2418 |
|
2419 /** |
|
2420 * Add a listener for a specific event |
|
2421 * @method _fnEventListen |
|
2422 * @param {Object} that Scope of the listening function (i.e. 'this' in the caller) |
|
2423 * @param {String} type Event type |
|
2424 * @param {Function} fn Function |
|
2425 * @returns void |
|
2426 * @private |
|
2427 * @static |
|
2428 */ |
|
2429 TableTools._fnEventListen = function (that, type, fn) { |
|
2430 TableTools._aListeners.push({ |
|
2431 "that": that, |
|
2432 "type": type, |
|
2433 "fn": fn |
|
2434 }); |
|
2435 }; |
|
2436 |
|
2437 |
|
2438 /** |
|
2439 * An event has occurred - look up every listener and fire it off. We check that the event we are |
|
2440 * going to fire is attached to the same table (using the table node as reference) before firing |
|
2441 * @method _fnEventDispatch |
|
2442 * @param {Object} that Scope of the listening function (i.e. 'this' in the caller) |
|
2443 * @param {String} type Event type |
|
2444 * @param {Node} node Element that the event occurred on (may be null) |
|
2445 * @param {boolean} [selected] Indicate if the node was selected (true) or deselected (false) |
|
2446 * @returns void |
|
2447 * @private |
|
2448 * @static |
|
2449 */ |
|
2450 TableTools._fnEventDispatch = function (that, type, node, selected) { |
|
2451 var listeners = TableTools._aListeners; |
|
2452 for (var i = 0, iLen = listeners.length; i < iLen; i++) { |
|
2453 if (that.dom.table == listeners[i].that.dom.table && listeners[i].type == type) { |
|
2454 listeners[i].fn(node, selected); |
|
2455 } |
|
2456 } |
|
2457 }; |
|
2458 |
|
2459 |
|
2460 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
2461 * Constants |
|
2462 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
2463 |
|
2464 |
|
2465 TableTools.buttonBase = { |
|
2466 // Button base |
|
2467 "sAction": "text", |
|
2468 "sTag": "default", |
|
2469 "sLinerTag": "default", |
|
2470 "sButtonClass": "DTTT_button_text", |
|
2471 "sButtonText": "Button text", |
|
2472 "sTitle": "", |
|
2473 "sToolTip": "", |
|
2474 |
|
2475 // Common button specific options |
|
2476 "sCharSet": "utf8", |
|
2477 "bBomInc": false, |
|
2478 "sFileName": "*.csv", |
|
2479 "sFieldBoundary": "", |
|
2480 "sFieldSeperator": "\t", |
|
2481 "sNewLine": "auto", |
|
2482 "mColumns": "all", /* "all", "visible", "hidden" or array of column integers */ |
|
2483 "bHeader": true, |
|
2484 "bFooter": true, |
|
2485 "bOpenRows": false, |
|
2486 "bSelectedOnly": false, |
|
2487 "oSelectorOpts": undefined, // See http://datatables.net/docs/DataTables/1.9.4/#$ for full options |
|
2488 |
|
2489 // Callbacks |
|
2490 "fnMouseover": null, |
|
2491 "fnMouseout": null, |
|
2492 "fnClick": null, |
|
2493 "fnSelect": null, |
|
2494 "fnComplete": null, |
|
2495 "fnInit": null, |
|
2496 "fnCellRender": null |
|
2497 }; |
|
2498 |
|
2499 |
|
2500 /** |
|
2501 * @namespace Default button configurations |
|
2502 */ |
|
2503 TableTools.BUTTONS = { |
|
2504 "csv": $.extend({}, TableTools.buttonBase, { |
|
2505 "sAction": "flash_save", |
|
2506 "sButtonClass": "DTTT_button_csv", |
|
2507 "sButtonText": "CSV", |
|
2508 "sFieldBoundary": '"', |
|
2509 "sFieldSeperator": ",", |
|
2510 "fnClick": function (nButton, oConfig, flash) { |
|
2511 this.fnSetText(flash, this.fnGetTableData(oConfig)); |
|
2512 } |
|
2513 }), |
|
2514 |
|
2515 "xls": $.extend({}, TableTools.buttonBase, { |
|
2516 "sAction": "flash_save", |
|
2517 "sCharSet": "utf16le", |
|
2518 "bBomInc": true, |
|
2519 "sButtonClass": "DTTT_button_xls", |
|
2520 "sButtonText": "Excel", |
|
2521 "fnClick": function (nButton, oConfig, flash) { |
|
2522 this.fnSetText(flash, this.fnGetTableData(oConfig)); |
|
2523 } |
|
2524 }), |
|
2525 |
|
2526 "copy": $.extend({}, TableTools.buttonBase, { |
|
2527 "sAction": "flash_copy", |
|
2528 "sButtonClass": "DTTT_button_copy", |
|
2529 "sButtonText": "Copy", |
|
2530 "fnClick": function (nButton, oConfig, flash) { |
|
2531 this.fnSetText(flash, this.fnGetTableData(oConfig)); |
|
2532 }, |
|
2533 "fnComplete": function (nButton, oConfig, flash, text) { |
|
2534 var |
|
2535 lines = text.split('\n').length, |
|
2536 len = this.s.dt.nTFoot === null ? lines - 1 : lines - 2, |
|
2537 plural = (len == 1) ? "" : "s"; |
|
2538 this.fnInfo('<h6>Table copied</h6>' + |
|
2539 '<p>Copied ' + len + ' row' + plural + ' to the clipboard.</p>', |
|
2540 1500 |
|
2541 ); |
|
2542 } |
|
2543 }), |
|
2544 |
|
2545 "pdf": $.extend({}, TableTools.buttonBase, { |
|
2546 "sAction": "flash_pdf", |
|
2547 "sNewLine": "\n", |
|
2548 "sFileName": "*.pdf", |
|
2549 "sButtonClass": "DTTT_button_pdf", |
|
2550 "sButtonText": "PDF", |
|
2551 "sPdfOrientation": "portrait", |
|
2552 "sPdfSize": "A4", |
|
2553 "sPdfMessage": "", |
|
2554 "fnClick": function (nButton, oConfig, flash) { |
|
2555 this.fnSetText(flash, |
|
2556 "title:" + this.fnGetTitle(oConfig) + "\n" + |
|
2557 "message:" + oConfig.sPdfMessage + "\n" + |
|
2558 "colWidth:" + this.fnCalcColRatios(oConfig) + "\n" + |
|
2559 "orientation:" + oConfig.sPdfOrientation + "\n" + |
|
2560 "size:" + oConfig.sPdfSize + "\n" + |
|
2561 "--/TableToolsOpts--\n" + |
|
2562 this.fnGetTableData(oConfig) |
|
2563 ); |
|
2564 } |
|
2565 }), |
|
2566 |
|
2567 "print": $.extend({}, TableTools.buttonBase, { |
|
2568 "sInfo": "<h6>Print view</h6><p>Please use your browser's print function to " + |
|
2569 "print this table. Press escape when finished.</p>", |
|
2570 "sMessage": null, |
|
2571 "bShowAll": true, |
|
2572 "sToolTip": "View print view", |
|
2573 "sButtonClass": "DTTT_button_print", |
|
2574 "sButtonText": "Print", |
|
2575 "fnClick": function (nButton, oConfig) { |
|
2576 this.fnPrint(true, oConfig); |
|
2577 } |
|
2578 }), |
|
2579 |
|
2580 "text": $.extend({}, TableTools.buttonBase), |
|
2581 |
|
2582 "select": $.extend({}, TableTools.buttonBase, { |
|
2583 "sButtonText": "Select button", |
|
2584 "fnSelect": function (nButton, oConfig) { |
|
2585 if (this.fnGetSelected().length !== 0) { |
|
2586 $(nButton).removeClass(this.classes.buttons.disabled); |
|
2587 } else { |
|
2588 $(nButton).addClass(this.classes.buttons.disabled); |
|
2589 } |
|
2590 }, |
|
2591 "fnInit": function (nButton, oConfig) { |
|
2592 $(nButton).addClass(this.classes.buttons.disabled); |
|
2593 } |
|
2594 }), |
|
2595 |
|
2596 "select_single": $.extend({}, TableTools.buttonBase, { |
|
2597 "sButtonText": "Select button", |
|
2598 "fnSelect": function (nButton, oConfig) { |
|
2599 var iSelected = this.fnGetSelected().length; |
|
2600 if (iSelected == 1) { |
|
2601 $(nButton).removeClass(this.classes.buttons.disabled); |
|
2602 } else { |
|
2603 $(nButton).addClass(this.classes.buttons.disabled); |
|
2604 } |
|
2605 }, |
|
2606 "fnInit": function (nButton, oConfig) { |
|
2607 $(nButton).addClass(this.classes.buttons.disabled); |
|
2608 } |
|
2609 }), |
|
2610 |
|
2611 "select_all": $.extend({}, TableTools.buttonBase, { |
|
2612 "sButtonText": "Select all", |
|
2613 "fnClick": function (nButton, oConfig) { |
|
2614 this.fnSelectAll(); |
|
2615 }, |
|
2616 "fnSelect": function (nButton, oConfig) { |
|
2617 if (this.fnGetSelected().length == this.s.dt.fnRecordsDisplay()) { |
|
2618 $(nButton).addClass(this.classes.buttons.disabled); |
|
2619 } else { |
|
2620 $(nButton).removeClass(this.classes.buttons.disabled); |
|
2621 } |
|
2622 } |
|
2623 }), |
|
2624 |
|
2625 "select_none": $.extend({}, TableTools.buttonBase, { |
|
2626 "sButtonText": "Deselect all", |
|
2627 "fnClick": function (nButton, oConfig) { |
|
2628 this.fnSelectNone(); |
|
2629 }, |
|
2630 "fnSelect": function (nButton, oConfig) { |
|
2631 if (this.fnGetSelected().length !== 0) { |
|
2632 $(nButton).removeClass(this.classes.buttons.disabled); |
|
2633 } else { |
|
2634 $(nButton).addClass(this.classes.buttons.disabled); |
|
2635 } |
|
2636 }, |
|
2637 "fnInit": function (nButton, oConfig) { |
|
2638 $(nButton).addClass(this.classes.buttons.disabled); |
|
2639 } |
|
2640 }), |
|
2641 |
|
2642 "ajax": $.extend({}, TableTools.buttonBase, { |
|
2643 "sAjaxUrl": "/xhr.php", |
|
2644 "sButtonText": "Ajax button", |
|
2645 "fnClick": function (nButton, oConfig) { |
|
2646 var sData = this.fnGetTableData(oConfig); |
|
2647 $.ajax({ |
|
2648 "url": oConfig.sAjaxUrl, |
|
2649 "data": [ |
|
2650 { "name": "tableData", "value": sData } |
|
2651 ], |
|
2652 "success": oConfig.fnAjaxComplete, |
|
2653 "dataType": "json", |
|
2654 "type": "POST", |
|
2655 "cache": false, |
|
2656 "error": function () { |
|
2657 alert("Error detected when sending table data to server"); |
|
2658 } |
|
2659 }); |
|
2660 }, |
|
2661 "fnAjaxComplete": function (json) { |
|
2662 alert('Ajax complete'); |
|
2663 } |
|
2664 }), |
|
2665 |
|
2666 "div": $.extend({}, TableTools.buttonBase, { |
|
2667 "sAction": "div", |
|
2668 "sTag": "div", |
|
2669 "sButtonClass": "DTTT_nonbutton", |
|
2670 "sButtonText": "Text button" |
|
2671 }), |
|
2672 |
|
2673 "collection": $.extend({}, TableTools.buttonBase, { |
|
2674 "sAction": "collection", |
|
2675 "sButtonClass": "DTTT_button_collection", |
|
2676 "sButtonText": "Collection", |
|
2677 "fnClick": function (nButton, oConfig) { |
|
2678 this._fnCollectionShow(nButton, oConfig); |
|
2679 } |
|
2680 }) |
|
2681 }; |
|
2682 /* |
|
2683 * on* callback parameters: |
|
2684 * 1. node - button element |
|
2685 * 2. object - configuration object for this button |
|
2686 * 3. object - ZeroClipboard reference (flash button only) |
|
2687 * 4. string - Returned string from Flash (flash button only - and only on 'complete') |
|
2688 */ |
|
2689 |
|
2690 // Alias to match the other plug-ins styling |
|
2691 TableTools.buttons = TableTools.BUTTONS; |
|
2692 |
|
2693 |
|
2694 /** |
|
2695 * @namespace Classes used by TableTools - allows the styles to be override easily. |
|
2696 * Note that when TableTools initialises it will take a copy of the classes object |
|
2697 * and will use its internal copy for the remainder of its run time. |
|
2698 */ |
|
2699 TableTools.classes = { |
|
2700 "container": "DTTT_container", |
|
2701 "buttons": { |
|
2702 "normal": "DTTT_button", |
|
2703 "disabled": "DTTT_disabled" |
|
2704 }, |
|
2705 "collection": { |
|
2706 "container": "DTTT_collection", |
|
2707 "background": "DTTT_collection_background", |
|
2708 "buttons": { |
|
2709 "normal": "DTTT_button", |
|
2710 "disabled": "DTTT_disabled" |
|
2711 } |
|
2712 }, |
|
2713 "select": { |
|
2714 "table": "DTTT_selectable", |
|
2715 "row": "DTTT_selected selected" |
|
2716 }, |
|
2717 "print": { |
|
2718 "body": "DTTT_Print", |
|
2719 "info": "DTTT_print_info", |
|
2720 "message": "DTTT_PrintMessage" |
|
2721 } |
|
2722 }; |
|
2723 |
|
2724 |
|
2725 /** |
|
2726 * @namespace ThemeRoller classes - built in for compatibility with DataTables' |
|
2727 * bJQueryUI option. |
|
2728 */ |
|
2729 TableTools.classes_themeroller = { |
|
2730 "container": "DTTT_container ui-buttonset ui-buttonset-multi", |
|
2731 "buttons": { |
|
2732 "normal": "DTTT_button ui-button ui-state-default" |
|
2733 }, |
|
2734 "collection": { |
|
2735 "container": "DTTT_collection ui-buttonset ui-buttonset-multi" |
|
2736 } |
|
2737 }; |
|
2738 |
|
2739 |
|
2740 /** |
|
2741 * @namespace TableTools default settings for initialisation |
|
2742 */ |
|
2743 TableTools.DEFAULTS = { |
|
2744 "sSwfPath": "../swf/copy_csv_xls_pdf.swf", |
|
2745 "sRowSelect": "none", |
|
2746 "sSelectedClass": null, |
|
2747 "fnPreRowSelect": null, |
|
2748 "fnRowSelected": null, |
|
2749 "fnRowDeselected": null, |
|
2750 "aButtons": [ "copy", "csv", "xls", "pdf", "print" ], |
|
2751 "oTags": { |
|
2752 "container": "div", |
|
2753 "button": "a", // We really want to use buttons here, but Firefox and IE ignore the |
|
2754 // click on the Flash element in the button (but not mouse[in|out]). |
|
2755 "liner": "span", |
|
2756 "collection": { |
|
2757 "container": "div", |
|
2758 "button": "a", |
|
2759 "liner": "span" |
|
2760 } |
|
2761 } |
|
2762 }; |
|
2763 |
|
2764 // Alias to match the other plug-ins |
|
2765 TableTools.defaults = TableTools.DEFAULTS; |
|
2766 |
|
2767 |
|
2768 /** |
|
2769 * Name of this class |
|
2770 * @constant CLASS |
|
2771 * @type String |
|
2772 * @default TableTools |
|
2773 */ |
|
2774 TableTools.prototype.CLASS = "TableTools"; |
|
2775 |
|
2776 |
|
2777 /** |
|
2778 * TableTools version |
|
2779 * @constant VERSION |
|
2780 * @type String |
|
2781 * @default See code |
|
2782 */ |
|
2783 TableTools.version = "2.2.0-dev"; |
|
2784 |
|
2785 |
|
2786 // DataTables 1.10 API |
|
2787 // |
|
2788 // This will be extended in a big way in in TableTools 3 to provide API methods |
|
2789 // such as rows().select() and rows.selected() etc, but for the moment the |
|
2790 // tabletools() method simply returns the instance. |
|
2791 |
|
2792 if ($.fn.dataTable.Api) { |
|
2793 $.fn.dataTable.Api.register('tabletools()', function () { |
|
2794 var tt = null; |
|
2795 |
|
2796 if (this.context.length > 0) { |
|
2797 tt = TableTools.fnGetInstance(this.context[0].nTable); |
|
2798 } |
|
2799 |
|
2800 return tt; |
|
2801 }); |
|
2802 } |
|
2803 |
|
2804 |
|
2805 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
2806 * Initialisation |
|
2807 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
|
2808 |
|
2809 /* |
|
2810 * Register a new feature with DataTables |
|
2811 */ |
|
2812 if (typeof $.fn.dataTable == "function" && |
|
2813 typeof $.fn.dataTableExt.fnVersionCheck == "function" && |
|
2814 $.fn.dataTableExt.fnVersionCheck('1.9.0')) { |
|
2815 $.fn.dataTableExt.aoFeatures.push({ |
|
2816 "fnInit": function (oDTSettings) { |
|
2817 var init = oDTSettings.oInit; |
|
2818 var opts = init.tableTools || init.oTableTools || {}; |
|
2819 |
|
2820 var oTT = new TableTools(oDTSettings.oInstance, opts); |
|
2821 TableTools._aInstances.push(oTT); |
|
2822 |
|
2823 return oTT.dom.container; |
|
2824 }, |
|
2825 "cFeature": "T", |
|
2826 "sFeature": "TableTools" |
|
2827 }); |
|
2828 } |
|
2829 else { |
|
2830 alert("Warning: TableTools requires DataTables 1.9.0 or newer - www.datatables.net/download"); |
|
2831 } |
|
2832 |
|
2833 $.fn.DataTable.TableTools = TableTools; |
|
2834 |
|
2835 })(jQuery, window, document); |
|
2836 |
|
2837 /* |
|
2838 * Register a new feature with DataTables |
|
2839 */ |
|
2840 if (typeof $.fn.dataTable == "function" && |
|
2841 typeof $.fn.dataTableExt.fnVersionCheck == "function" && |
|
2842 $.fn.dataTableExt.fnVersionCheck('1.9.0')) { |
|
2843 $.fn.dataTableExt.aoFeatures.push({ |
|
2844 "fnInit": function (oDTSettings) { |
|
2845 var oOpts = typeof oDTSettings.oInit.oTableTools != 'undefined' ? |
|
2846 oDTSettings.oInit.oTableTools : {}; |
|
2847 |
|
2848 var oTT = new TableTools(oDTSettings.oInstance, oOpts); |
|
2849 TableTools._aInstances.push(oTT); |
|
2850 |
|
2851 return oTT.dom.container; |
|
2852 }, |
|
2853 "cFeature": "T", |
|
2854 "sFeature": "TableTools" |
|
2855 }); |
|
2856 } |
|
2857 else { |
|
2858 alert("Warning: TableTools 2 requires DataTables 1.9.0 or newer - www.datatables.net/download"); |
|
2859 } |
|
2860 |
|
2861 |
|
2862 $.fn.dataTable.TableTools = TableTools; |
|
2863 $.fn.DataTable.TableTools = TableTools; |
|
2864 |
|
2865 |
|
2866 return TableTools; |
|
2867 }; // /factory |
|
2868 |
|
2869 |
|
2870 factory(jQuery, jQuery.fn.dataTable); |
|
2871 |
|
2872 |
|
2873 })(window, document); |
|
2874 |
|