dataTables.tableTools.js 83 KB

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