datatables.bundle.js 884 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392
  1. /*! DataTables 1.10.19
  2. * ©2008-2018 SpryMedia Ltd - datatables.net/license
  3. */
  4. /**
  5. * @summary DataTables
  6. * @description Paginate, search and order HTML tables
  7. * @version 1.10.19
  8. * @file jquery.dataTables.js
  9. * @author SpryMedia Ltd
  10. * @contact www.datatables.net
  11. * @copyright Copyright 2008-2018 SpryMedia Ltd.
  12. *
  13. * This source file is free software, available under the following license:
  14. * MIT license - http://datatables.net/license
  15. *
  16. * This source file is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  19. *
  20. * For details please refer to: http://www.datatables.net
  21. */
  22. /*jslint evil: true, undef: true, browser: true */
  23. /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
  24. (function( factory ) {
  25. "use strict";
  26. if ( typeof define === 'function' && define.amd ) {
  27. // AMD
  28. define( ['jquery'], function ( $ ) {
  29. return factory( $, window, document );
  30. } );
  31. }
  32. else if ( typeof exports === 'object' ) {
  33. // CommonJS
  34. module.exports = function (root, $) {
  35. if ( ! root ) {
  36. // CommonJS environments without a window global must pass a
  37. // root. This will give an error otherwise
  38. root = window;
  39. }
  40. if ( ! $ ) {
  41. $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
  42. require('jquery') :
  43. require('jquery')( root );
  44. }
  45. return factory( $, root, root.document );
  46. };
  47. }
  48. else {
  49. // Browser
  50. factory( jQuery, window, document );
  51. }
  52. }
  53. (function( $, window, document, undefined ) {
  54. "use strict";
  55. /**
  56. * DataTables is a plug-in for the jQuery Javascript library. It is a highly
  57. * flexible tool, based upon the foundations of progressive enhancement,
  58. * which will add advanced interaction controls to any HTML table. For a
  59. * full list of features please refer to
  60. * [DataTables.net](href="http://datatables.net).
  61. *
  62. * Note that the `DataTable` object is not a global variable but is aliased
  63. * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
  64. * be accessed.
  65. *
  66. * @class
  67. * @param {object} [init={}] Configuration object for DataTables. Options
  68. * are defined by {@link DataTable.defaults}
  69. * @requires jQuery 1.7+
  70. *
  71. * @example
  72. * // Basic initialisation
  73. * $(document).ready( function {
  74. * $('#example').dataTable();
  75. * } );
  76. *
  77. * @example
  78. * // Initialisation with configuration options - in this case, disable
  79. * // pagination and sorting.
  80. * $(document).ready( function {
  81. * $('#example').dataTable( {
  82. * "paginate": false,
  83. * "sort": false
  84. * } );
  85. * } );
  86. */
  87. var DataTable = function ( options )
  88. {
  89. /**
  90. * Perform a jQuery selector action on the table's TR elements (from the tbody) and
  91. * return the resulting jQuery object.
  92. * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
  93. * @param {object} [oOpts] Optional parameters for modifying the rows to be included
  94. * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
  95. * criterion ("applied") or all TR elements (i.e. no filter).
  96. * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
  97. * Can be either 'current', whereby the current sorting of the table is used, or
  98. * 'original' whereby the original order the data was read into the table is used.
  99. * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
  100. * ("current") or not ("all"). If 'current' is given, then order is assumed to be
  101. * 'current' and filter is 'applied', regardless of what they might be given as.
  102. * @returns {object} jQuery object, filtered by the given selector.
  103. * @dtopt API
  104. * @deprecated Since v1.10
  105. *
  106. * @example
  107. * $(document).ready(function() {
  108. * var oTable = $('#example').dataTable();
  109. *
  110. * // Highlight every second row
  111. * oTable.$('tr:odd').css('backgroundColor', 'blue');
  112. * } );
  113. *
  114. * @example
  115. * $(document).ready(function() {
  116. * var oTable = $('#example').dataTable();
  117. *
  118. * // Filter to rows with 'Webkit' in them, add a background colour and then
  119. * // remove the filter, thus highlighting the 'Webkit' rows only.
  120. * oTable.fnFilter('Webkit');
  121. * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
  122. * oTable.fnFilter('');
  123. * } );
  124. */
  125. this.$ = function ( sSelector, oOpts )
  126. {
  127. return this.api(true).$( sSelector, oOpts );
  128. };
  129. /**
  130. * Almost identical to $ in operation, but in this case returns the data for the matched
  131. * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
  132. * rather than any descendants, so the data can be obtained for the row/cell. If matching
  133. * rows are found, the data returned is the original data array/object that was used to
  134. * create the row (or a generated array if from a DOM source).
  135. *
  136. * This method is often useful in-combination with $ where both functions are given the
  137. * same parameters and the array indexes will match identically.
  138. * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
  139. * @param {object} [oOpts] Optional parameters for modifying the rows to be included
  140. * @param {string} [oOpts.filter=none] Select elements that meet the current filter
  141. * criterion ("applied") or all elements (i.e. no filter).
  142. * @param {string} [oOpts.order=current] Order of the data in the processed array.
  143. * Can be either 'current', whereby the current sorting of the table is used, or
  144. * 'original' whereby the original order the data was read into the table is used.
  145. * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
  146. * ("current") or not ("all"). If 'current' is given, then order is assumed to be
  147. * 'current' and filter is 'applied', regardless of what they might be given as.
  148. * @returns {array} Data for the matched elements. If any elements, as a result of the
  149. * selector, were not TR, TD or TH elements in the DataTable, they will have a null
  150. * entry in the array.
  151. * @dtopt API
  152. * @deprecated Since v1.10
  153. *
  154. * @example
  155. * $(document).ready(function() {
  156. * var oTable = $('#example').dataTable();
  157. *
  158. * // Get the data from the first row in the table
  159. * var data = oTable._('tr:first');
  160. *
  161. * // Do something useful with the data
  162. * alert( "First cell is: "+data[0] );
  163. * } );
  164. *
  165. * @example
  166. * $(document).ready(function() {
  167. * var oTable = $('#example').dataTable();
  168. *
  169. * // Filter to 'Webkit' and get all data for
  170. * oTable.fnFilter('Webkit');
  171. * var data = oTable._('tr', {"search": "applied"});
  172. *
  173. * // Do something with the data
  174. * alert( data.length+" rows matched the search" );
  175. * } );
  176. */
  177. this._ = function ( sSelector, oOpts )
  178. {
  179. return this.api(true).rows( sSelector, oOpts ).data();
  180. };
  181. /**
  182. * Create a DataTables Api instance, with the currently selected tables for
  183. * the Api's context.
  184. * @param {boolean} [traditional=false] Set the API instance's context to be
  185. * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
  186. * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
  187. * or if all tables captured in the jQuery object should be used.
  188. * @return {DataTables.Api}
  189. */
  190. this.api = function ( traditional )
  191. {
  192. return traditional ?
  193. new _Api(
  194. _fnSettingsFromNode( this[ _ext.iApiIndex ] )
  195. ) :
  196. new _Api( this );
  197. };
  198. /**
  199. * Add a single new row or multiple rows of data to the table. Please note
  200. * that this is suitable for client-side processing only - if you are using
  201. * server-side processing (i.e. "bServerSide": true), then to add data, you
  202. * must add it to the data source, i.e. the server-side, through an Ajax call.
  203. * @param {array|object} data The data to be added to the table. This can be:
  204. * <ul>
  205. * <li>1D array of data - add a single row with the data provided</li>
  206. * <li>2D array of arrays - add multiple rows in a single call</li>
  207. * <li>object - data object when using <i>mData</i></li>
  208. * <li>array of objects - multiple data objects when using <i>mData</i></li>
  209. * </ul>
  210. * @param {bool} [redraw=true] redraw the table or not
  211. * @returns {array} An array of integers, representing the list of indexes in
  212. * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
  213. * the table.
  214. * @dtopt API
  215. * @deprecated Since v1.10
  216. *
  217. * @example
  218. * // Global var for counter
  219. * var giCount = 2;
  220. *
  221. * $(document).ready(function() {
  222. * $('#example').dataTable();
  223. * } );
  224. *
  225. * function fnClickAddRow() {
  226. * $('#example').dataTable().fnAddData( [
  227. * giCount+".1",
  228. * giCount+".2",
  229. * giCount+".3",
  230. * giCount+".4" ]
  231. * );
  232. *
  233. * giCount++;
  234. * }
  235. */
  236. this.fnAddData = function( data, redraw )
  237. {
  238. var api = this.api( true );
  239. /* Check if we want to add multiple rows or not */
  240. var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
  241. api.rows.add( data ) :
  242. api.row.add( data );
  243. if ( redraw === undefined || redraw ) {
  244. api.draw();
  245. }
  246. return rows.flatten().toArray();
  247. };
  248. /**
  249. * This function will make DataTables recalculate the column sizes, based on the data
  250. * contained in the table and the sizes applied to the columns (in the DOM, CSS or
  251. * through the sWidth parameter). This can be useful when the width of the table's
  252. * parent element changes (for example a window resize).
  253. * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
  254. * @dtopt API
  255. * @deprecated Since v1.10
  256. *
  257. * @example
  258. * $(document).ready(function() {
  259. * var oTable = $('#example').dataTable( {
  260. * "sScrollY": "200px",
  261. * "bPaginate": false
  262. * } );
  263. *
  264. * $(window).on('resize', function () {
  265. * oTable.fnAdjustColumnSizing();
  266. * } );
  267. * } );
  268. */
  269. this.fnAdjustColumnSizing = function ( bRedraw )
  270. {
  271. var api = this.api( true ).columns.adjust();
  272. var settings = api.settings()[0];
  273. var scroll = settings.oScroll;
  274. if ( bRedraw === undefined || bRedraw ) {
  275. api.draw( false );
  276. }
  277. else if ( scroll.sX !== "" || scroll.sY !== "" ) {
  278. /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
  279. _fnScrollDraw( settings );
  280. }
  281. };
  282. /**
  283. * Quickly and simply clear a table
  284. * @param {bool} [bRedraw=true] redraw the table or not
  285. * @dtopt API
  286. * @deprecated Since v1.10
  287. *
  288. * @example
  289. * $(document).ready(function() {
  290. * var oTable = $('#example').dataTable();
  291. *
  292. * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
  293. * oTable.fnClearTable();
  294. * } );
  295. */
  296. this.fnClearTable = function( bRedraw )
  297. {
  298. var api = this.api( true ).clear();
  299. if ( bRedraw === undefined || bRedraw ) {
  300. api.draw();
  301. }
  302. };
  303. /**
  304. * The exact opposite of 'opening' a row, this function will close any rows which
  305. * are currently 'open'.
  306. * @param {node} nTr the table row to 'close'
  307. * @returns {int} 0 on success, or 1 if failed (can't find the row)
  308. * @dtopt API
  309. * @deprecated Since v1.10
  310. *
  311. * @example
  312. * $(document).ready(function() {
  313. * var oTable;
  314. *
  315. * // 'open' an information row when a row is clicked on
  316. * $('#example tbody tr').click( function () {
  317. * if ( oTable.fnIsOpen(this) ) {
  318. * oTable.fnClose( this );
  319. * } else {
  320. * oTable.fnOpen( this, "Temporary row opened", "info_row" );
  321. * }
  322. * } );
  323. *
  324. * oTable = $('#example').dataTable();
  325. * } );
  326. */
  327. this.fnClose = function( nTr )
  328. {
  329. this.api( true ).row( nTr ).child.hide();
  330. };
  331. /**
  332. * Remove a row for the table
  333. * @param {mixed} target The index of the row from aoData to be deleted, or
  334. * the TR element you want to delete
  335. * @param {function|null} [callBack] Callback function
  336. * @param {bool} [redraw=true] Redraw the table or not
  337. * @returns {array} The row that was deleted
  338. * @dtopt API
  339. * @deprecated Since v1.10
  340. *
  341. * @example
  342. * $(document).ready(function() {
  343. * var oTable = $('#example').dataTable();
  344. *
  345. * // Immediately remove the first row
  346. * oTable.fnDeleteRow( 0 );
  347. * } );
  348. */
  349. this.fnDeleteRow = function( target, callback, redraw )
  350. {
  351. var api = this.api( true );
  352. var rows = api.rows( target );
  353. var settings = rows.settings()[0];
  354. var data = settings.aoData[ rows[0][0] ];
  355. rows.remove();
  356. if ( callback ) {
  357. callback.call( this, settings, data );
  358. }
  359. if ( redraw === undefined || redraw ) {
  360. api.draw();
  361. }
  362. return data;
  363. };
  364. /**
  365. * Restore the table to it's original state in the DOM by removing all of DataTables
  366. * enhancements, alterations to the DOM structure of the table and event listeners.
  367. * @param {boolean} [remove=false] Completely remove the table from the DOM
  368. * @dtopt API
  369. * @deprecated Since v1.10
  370. *
  371. * @example
  372. * $(document).ready(function() {
  373. * // This example is fairly pointless in reality, but shows how fnDestroy can be used
  374. * var oTable = $('#example').dataTable();
  375. * oTable.fnDestroy();
  376. * } );
  377. */
  378. this.fnDestroy = function ( remove )
  379. {
  380. this.api( true ).destroy( remove );
  381. };
  382. /**
  383. * Redraw the table
  384. * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
  385. * @dtopt API
  386. * @deprecated Since v1.10
  387. *
  388. * @example
  389. * $(document).ready(function() {
  390. * var oTable = $('#example').dataTable();
  391. *
  392. * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
  393. * oTable.fnDraw();
  394. * } );
  395. */
  396. this.fnDraw = function( complete )
  397. {
  398. // Note that this isn't an exact match to the old call to _fnDraw - it takes
  399. // into account the new data, but can hold position.
  400. this.api( true ).draw( complete );
  401. };
  402. /**
  403. * Filter the input based on data
  404. * @param {string} sInput String to filter the table on
  405. * @param {int|null} [iColumn] Column to limit filtering to
  406. * @param {bool} [bRegex=false] Treat as regular expression or not
  407. * @param {bool} [bSmart=true] Perform smart filtering or not
  408. * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
  409. * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
  410. * @dtopt API
  411. * @deprecated Since v1.10
  412. *
  413. * @example
  414. * $(document).ready(function() {
  415. * var oTable = $('#example').dataTable();
  416. *
  417. * // Sometime later - filter...
  418. * oTable.fnFilter( 'test string' );
  419. * } );
  420. */
  421. this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
  422. {
  423. var api = this.api( true );
  424. if ( iColumn === null || iColumn === undefined ) {
  425. api.search( sInput, bRegex, bSmart, bCaseInsensitive );
  426. }
  427. else {
  428. api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
  429. }
  430. api.draw();
  431. };
  432. /**
  433. * Get the data for the whole table, an individual row or an individual cell based on the
  434. * provided parameters.
  435. * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
  436. * a TR node then the data source for the whole row will be returned. If given as a
  437. * TD/TH cell node then iCol will be automatically calculated and the data for the
  438. * cell returned. If given as an integer, then this is treated as the aoData internal
  439. * data index for the row (see fnGetPosition) and the data for that row used.
  440. * @param {int} [col] Optional column index that you want the data of.
  441. * @returns {array|object|string} If mRow is undefined, then the data for all rows is
  442. * returned. If mRow is defined, just data for that row, and is iCol is
  443. * defined, only data for the designated cell is returned.
  444. * @dtopt API
  445. * @deprecated Since v1.10
  446. *
  447. * @example
  448. * // Row data
  449. * $(document).ready(function() {
  450. * oTable = $('#example').dataTable();
  451. *
  452. * oTable.$('tr').click( function () {
  453. * var data = oTable.fnGetData( this );
  454. * // ... do something with the array / object of data for the row
  455. * } );
  456. * } );
  457. *
  458. * @example
  459. * // Individual cell data
  460. * $(document).ready(function() {
  461. * oTable = $('#example').dataTable();
  462. *
  463. * oTable.$('td').click( function () {
  464. * var sData = oTable.fnGetData( this );
  465. * alert( 'The cell clicked on had the value of '+sData );
  466. * } );
  467. * } );
  468. */
  469. this.fnGetData = function( src, col )
  470. {
  471. var api = this.api( true );
  472. if ( src !== undefined ) {
  473. var type = src.nodeName ? src.nodeName.toLowerCase() : '';
  474. return col !== undefined || type == 'td' || type == 'th' ?
  475. api.cell( src, col ).data() :
  476. api.row( src ).data() || null;
  477. }
  478. return api.data().toArray();
  479. };
  480. /**
  481. * Get an array of the TR nodes that are used in the table's body. Note that you will
  482. * typically want to use the '$' API method in preference to this as it is more
  483. * flexible.
  484. * @param {int} [iRow] Optional row index for the TR element you want
  485. * @returns {array|node} If iRow is undefined, returns an array of all TR elements
  486. * in the table's body, or iRow is defined, just the TR element requested.
  487. * @dtopt API
  488. * @deprecated Since v1.10
  489. *
  490. * @example
  491. * $(document).ready(function() {
  492. * var oTable = $('#example').dataTable();
  493. *
  494. * // Get the nodes from the table
  495. * var nNodes = oTable.fnGetNodes( );
  496. * } );
  497. */
  498. this.fnGetNodes = function( iRow )
  499. {
  500. var api = this.api( true );
  501. return iRow !== undefined ?
  502. api.row( iRow ).node() :
  503. api.rows().nodes().flatten().toArray();
  504. };
  505. /**
  506. * Get the array indexes of a particular cell from it's DOM element
  507. * and column index including hidden columns
  508. * @param {node} node this can either be a TR, TD or TH in the table's body
  509. * @returns {int} If nNode is given as a TR, then a single index is returned, or
  510. * if given as a cell, an array of [row index, column index (visible),
  511. * column index (all)] is given.
  512. * @dtopt API
  513. * @deprecated Since v1.10
  514. *
  515. * @example
  516. * $(document).ready(function() {
  517. * $('#example tbody td').click( function () {
  518. * // Get the position of the current data from the node
  519. * var aPos = oTable.fnGetPosition( this );
  520. *
  521. * // Get the data array for this row
  522. * var aData = oTable.fnGetData( aPos[0] );
  523. *
  524. * // Update the data array and return the value
  525. * aData[ aPos[1] ] = 'clicked';
  526. * this.innerHTML = 'clicked';
  527. * } );
  528. *
  529. * // Init DataTables
  530. * oTable = $('#example').dataTable();
  531. * } );
  532. */
  533. this.fnGetPosition = function( node )
  534. {
  535. var api = this.api( true );
  536. var nodeName = node.nodeName.toUpperCase();
  537. if ( nodeName == 'TR' ) {
  538. return api.row( node ).index();
  539. }
  540. else if ( nodeName == 'TD' || nodeName == 'TH' ) {
  541. var cell = api.cell( node ).index();
  542. return [
  543. cell.row,
  544. cell.columnVisible,
  545. cell.column
  546. ];
  547. }
  548. return null;
  549. };
  550. /**
  551. * Check to see if a row is 'open' or not.
  552. * @param {node} nTr the table row to check
  553. * @returns {boolean} true if the row is currently open, false otherwise
  554. * @dtopt API
  555. * @deprecated Since v1.10
  556. *
  557. * @example
  558. * $(document).ready(function() {
  559. * var oTable;
  560. *
  561. * // 'open' an information row when a row is clicked on
  562. * $('#example tbody tr').click( function () {
  563. * if ( oTable.fnIsOpen(this) ) {
  564. * oTable.fnClose( this );
  565. * } else {
  566. * oTable.fnOpen( this, "Temporary row opened", "info_row" );
  567. * }
  568. * } );
  569. *
  570. * oTable = $('#example').dataTable();
  571. * } );
  572. */
  573. this.fnIsOpen = function( nTr )
  574. {
  575. return this.api( true ).row( nTr ).child.isShown();
  576. };
  577. /**
  578. * This function will place a new row directly after a row which is currently
  579. * on display on the page, with the HTML contents that is passed into the
  580. * function. This can be used, for example, to ask for confirmation that a
  581. * particular record should be deleted.
  582. * @param {node} nTr The table row to 'open'
  583. * @param {string|node|jQuery} mHtml The HTML to put into the row
  584. * @param {string} sClass Class to give the new TD cell
  585. * @returns {node} The row opened. Note that if the table row passed in as the
  586. * first parameter, is not found in the table, this method will silently
  587. * return.
  588. * @dtopt API
  589. * @deprecated Since v1.10
  590. *
  591. * @example
  592. * $(document).ready(function() {
  593. * var oTable;
  594. *
  595. * // 'open' an information row when a row is clicked on
  596. * $('#example tbody tr').click( function () {
  597. * if ( oTable.fnIsOpen(this) ) {
  598. * oTable.fnClose( this );
  599. * } else {
  600. * oTable.fnOpen( this, "Temporary row opened", "info_row" );
  601. * }
  602. * } );
  603. *
  604. * oTable = $('#example').dataTable();
  605. * } );
  606. */
  607. this.fnOpen = function( nTr, mHtml, sClass )
  608. {
  609. return this.api( true )
  610. .row( nTr )
  611. .child( mHtml, sClass )
  612. .show()
  613. .child()[0];
  614. };
  615. /**
  616. * Change the pagination - provides the internal logic for pagination in a simple API
  617. * function. With this function you can have a DataTables table go to the next,
  618. * previous, first or last pages.
  619. * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
  620. * or page number to jump to (integer), note that page 0 is the first page.
  621. * @param {bool} [bRedraw=true] Redraw the table or not
  622. * @dtopt API
  623. * @deprecated Since v1.10
  624. *
  625. * @example
  626. * $(document).ready(function() {
  627. * var oTable = $('#example').dataTable();
  628. * oTable.fnPageChange( 'next' );
  629. * } );
  630. */
  631. this.fnPageChange = function ( mAction, bRedraw )
  632. {
  633. var api = this.api( true ).page( mAction );
  634. if ( bRedraw === undefined || bRedraw ) {
  635. api.draw(false);
  636. }
  637. };
  638. /**
  639. * Show a particular column
  640. * @param {int} iCol The column whose display should be changed
  641. * @param {bool} bShow Show (true) or hide (false) the column
  642. * @param {bool} [bRedraw=true] Redraw the table or not
  643. * @dtopt API
  644. * @deprecated Since v1.10
  645. *
  646. * @example
  647. * $(document).ready(function() {
  648. * var oTable = $('#example').dataTable();
  649. *
  650. * // Hide the second column after initialisation
  651. * oTable.fnSetColumnVis( 1, false );
  652. * } );
  653. */
  654. this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
  655. {
  656. var api = this.api( true ).column( iCol ).visible( bShow );
  657. if ( bRedraw === undefined || bRedraw ) {
  658. api.columns.adjust().draw();
  659. }
  660. };
  661. /**
  662. * Get the settings for a particular table for external manipulation
  663. * @returns {object} DataTables settings object. See
  664. * {@link DataTable.models.oSettings}
  665. * @dtopt API
  666. * @deprecated Since v1.10
  667. *
  668. * @example
  669. * $(document).ready(function() {
  670. * var oTable = $('#example').dataTable();
  671. * var oSettings = oTable.fnSettings();
  672. *
  673. * // Show an example parameter from the settings
  674. * alert( oSettings._iDisplayStart );
  675. * } );
  676. */
  677. this.fnSettings = function()
  678. {
  679. return _fnSettingsFromNode( this[_ext.iApiIndex] );
  680. };
  681. /**
  682. * Sort the table by a particular column
  683. * @param {int} iCol the data index to sort on. Note that this will not match the
  684. * 'display index' if you have hidden data entries
  685. * @dtopt API
  686. * @deprecated Since v1.10
  687. *
  688. * @example
  689. * $(document).ready(function() {
  690. * var oTable = $('#example').dataTable();
  691. *
  692. * // Sort immediately with columns 0 and 1
  693. * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
  694. * } );
  695. */
  696. this.fnSort = function( aaSort )
  697. {
  698. this.api( true ).order( aaSort ).draw();
  699. };
  700. /**
  701. * Attach a sort listener to an element for a given column
  702. * @param {node} nNode the element to attach the sort listener to
  703. * @param {int} iColumn the column that a click on this node will sort on
  704. * @param {function} [fnCallback] callback function when sort is run
  705. * @dtopt API
  706. * @deprecated Since v1.10
  707. *
  708. * @example
  709. * $(document).ready(function() {
  710. * var oTable = $('#example').dataTable();
  711. *
  712. * // Sort on column 1, when 'sorter' is clicked on
  713. * oTable.fnSortListener( document.getElementById('sorter'), 1 );
  714. * } );
  715. */
  716. this.fnSortListener = function( nNode, iColumn, fnCallback )
  717. {
  718. this.api( true ).order.listener( nNode, iColumn, fnCallback );
  719. };
  720. /**
  721. * Update a table cell or row - this method will accept either a single value to
  722. * update the cell with, an array of values with one element for each column or
  723. * an object in the same format as the original data source. The function is
  724. * self-referencing in order to make the multi column updates easier.
  725. * @param {object|array|string} mData Data to update the cell/row with
  726. * @param {node|int} mRow TR element you want to update or the aoData index
  727. * @param {int} [iColumn] The column to update, give as null or undefined to
  728. * update a whole row.
  729. * @param {bool} [bRedraw=true] Redraw the table or not
  730. * @param {bool} [bAction=true] Perform pre-draw actions or not
  731. * @returns {int} 0 on success, 1 on error
  732. * @dtopt API
  733. * @deprecated Since v1.10
  734. *
  735. * @example
  736. * $(document).ready(function() {
  737. * var oTable = $('#example').dataTable();
  738. * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
  739. * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
  740. * } );
  741. */
  742. this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
  743. {
  744. var api = this.api( true );
  745. if ( iColumn === undefined || iColumn === null ) {
  746. api.row( mRow ).data( mData );
  747. }
  748. else {
  749. api.cell( mRow, iColumn ).data( mData );
  750. }
  751. if ( bAction === undefined || bAction ) {
  752. api.columns.adjust();
  753. }
  754. if ( bRedraw === undefined || bRedraw ) {
  755. api.draw();
  756. }
  757. return 0;
  758. };
  759. /**
  760. * Provide a common method for plug-ins to check the version of DataTables being used, in order
  761. * to ensure compatibility.
  762. * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
  763. * formats "X" and "X.Y" are also acceptable.
  764. * @returns {boolean} true if this version of DataTables is greater or equal to the required
  765. * version, or false if this version of DataTales is not suitable
  766. * @method
  767. * @dtopt API
  768. * @deprecated Since v1.10
  769. *
  770. * @example
  771. * $(document).ready(function() {
  772. * var oTable = $('#example').dataTable();
  773. * alert( oTable.fnVersionCheck( '1.9.0' ) );
  774. * } );
  775. */
  776. this.fnVersionCheck = _ext.fnVersionCheck;
  777. var _that = this;
  778. var emptyInit = options === undefined;
  779. var len = this.length;
  780. if ( emptyInit ) {
  781. options = {};
  782. }
  783. this.oApi = this.internal = _ext.internal;
  784. // Extend with old style plug-in API methods
  785. for ( var fn in DataTable.ext.internal ) {
  786. if ( fn ) {
  787. this[fn] = _fnExternApiFunc(fn);
  788. }
  789. }
  790. this.each(function() {
  791. // For each initialisation we want to give it a clean initialisation
  792. // object that can be bashed around
  793. var o = {};
  794. var oInit = len > 1 ? // optimisation for single table case
  795. _fnExtend( o, options, true ) :
  796. options;
  797. /*global oInit,_that,emptyInit*/
  798. var i=0, iLen, j, jLen, k, kLen;
  799. var sId = this.getAttribute( 'id' );
  800. var bInitHandedOff = false;
  801. var defaults = DataTable.defaults;
  802. var $this = $(this);
  803. /* Sanity check */
  804. if ( this.nodeName.toLowerCase() != 'table' )
  805. {
  806. _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
  807. return;
  808. }
  809. /* Backwards compatibility for the defaults */
  810. _fnCompatOpts( defaults );
  811. _fnCompatCols( defaults.column );
  812. /* Convert the camel-case defaults to Hungarian */
  813. _fnCamelToHungarian( defaults, defaults, true );
  814. _fnCamelToHungarian( defaults.column, defaults.column, true );
  815. /* Setting up the initialisation object */
  816. _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
  817. /* Check to see if we are re-initialising a table */
  818. var allSettings = DataTable.settings;
  819. for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
  820. {
  821. var s = allSettings[i];
  822. /* Base check on table node */
  823. if (
  824. s.nTable == this ||
  825. (s.nTHead && s.nTHead.parentNode == this) ||
  826. (s.nTFoot && s.nTFoot.parentNode == this)
  827. ) {
  828. var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
  829. var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
  830. if ( emptyInit || bRetrieve )
  831. {
  832. return s.oInstance;
  833. }
  834. else if ( bDestroy )
  835. {
  836. s.oInstance.fnDestroy();
  837. break;
  838. }
  839. else
  840. {
  841. _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
  842. return;
  843. }
  844. }
  845. /* If the element we are initialising has the same ID as a table which was previously
  846. * initialised, but the table nodes don't match (from before) then we destroy the old
  847. * instance by simply deleting it. This is under the assumption that the table has been
  848. * destroyed by other methods. Anyone using non-id selectors will need to do this manually
  849. */
  850. if ( s.sTableId == this.id )
  851. {
  852. allSettings.splice( i, 1 );
  853. break;
  854. }
  855. }
  856. /* Ensure the table has an ID - required for accessibility */
  857. if ( sId === null || sId === "" )
  858. {
  859. sId = "DataTables_Table_"+(DataTable.ext._unique++);
  860. this.id = sId;
  861. }
  862. /* Create the settings object for this table and set some of the default parameters */
  863. var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
  864. "sDestroyWidth": $this[0].style.width,
  865. "sInstance": sId,
  866. "sTableId": sId
  867. } );
  868. oSettings.nTable = this;
  869. oSettings.oApi = _that.internal;
  870. oSettings.oInit = oInit;
  871. allSettings.push( oSettings );
  872. // Need to add the instance after the instance after the settings object has been added
  873. // to the settings array, so we can self reference the table instance if more than one
  874. oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
  875. // Backwards compatibility, before we apply all the defaults
  876. _fnCompatOpts( oInit );
  877. _fnLanguageCompat( oInit.oLanguage );
  878. // If the length menu is given, but the init display length is not, use the length menu
  879. if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
  880. {
  881. oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
  882. oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
  883. }
  884. // Apply the defaults and init options to make a single init object will all
  885. // options defined from defaults and instance options.
  886. oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
  887. // Map the initialisation options onto the settings object
  888. _fnMap( oSettings.oFeatures, oInit, [
  889. "bPaginate",
  890. "bLengthChange",
  891. "bFilter",
  892. "bSort",
  893. "bSortMulti",
  894. "bInfo",
  895. "bProcessing",
  896. "bAutoWidth",
  897. "bSortClasses",
  898. "bServerSide",
  899. "bDeferRender"
  900. ] );
  901. _fnMap( oSettings, oInit, [
  902. "asStripeClasses",
  903. "ajax",
  904. "fnServerData",
  905. "fnFormatNumber",
  906. "sServerMethod",
  907. "aaSorting",
  908. "aaSortingFixed",
  909. "aLengthMenu",
  910. "sPaginationType",
  911. "sAjaxSource",
  912. "sAjaxDataProp",
  913. "iStateDuration",
  914. "sDom",
  915. "bSortCellsTop",
  916. "iTabIndex",
  917. "fnStateLoadCallback",
  918. "fnStateSaveCallback",
  919. "renderer",
  920. "searchDelay",
  921. "rowId",
  922. [ "iCookieDuration", "iStateDuration" ], // backwards compat
  923. [ "oSearch", "oPreviousSearch" ],
  924. [ "aoSearchCols", "aoPreSearchCols" ],
  925. [ "iDisplayLength", "_iDisplayLength" ]
  926. ] );
  927. _fnMap( oSettings.oScroll, oInit, [
  928. [ "sScrollX", "sX" ],
  929. [ "sScrollXInner", "sXInner" ],
  930. [ "sScrollY", "sY" ],
  931. [ "bScrollCollapse", "bCollapse" ]
  932. ] );
  933. _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
  934. /* Callback functions which are array driven */
  935. _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
  936. _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
  937. _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
  938. _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
  939. _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
  940. _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
  941. _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
  942. _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
  943. _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
  944. _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
  945. _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
  946. oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
  947. /* Browser support detection */
  948. _fnBrowserDetect( oSettings );
  949. var oClasses = oSettings.oClasses;
  950. $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
  951. $this.addClass( oClasses.sTable );
  952. if ( oSettings.iInitDisplayStart === undefined )
  953. {
  954. /* Display start point, taking into account the save saving */
  955. oSettings.iInitDisplayStart = oInit.iDisplayStart;
  956. oSettings._iDisplayStart = oInit.iDisplayStart;
  957. }
  958. if ( oInit.iDeferLoading !== null )
  959. {
  960. oSettings.bDeferLoading = true;
  961. var tmp = $.isArray( oInit.iDeferLoading );
  962. oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
  963. oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
  964. }
  965. /* Language definitions */
  966. var oLanguage = oSettings.oLanguage;
  967. $.extend( true, oLanguage, oInit.oLanguage );
  968. if ( oLanguage.sUrl )
  969. {
  970. /* Get the language definitions from a file - because this Ajax call makes the language
  971. * get async to the remainder of this function we use bInitHandedOff to indicate that
  972. * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
  973. */
  974. $.ajax( {
  975. dataType: 'json',
  976. url: oLanguage.sUrl,
  977. success: function ( json ) {
  978. _fnLanguageCompat( json );
  979. _fnCamelToHungarian( defaults.oLanguage, json );
  980. $.extend( true, oLanguage, json );
  981. _fnInitialise( oSettings );
  982. },
  983. error: function () {
  984. // Error occurred loading language file, continue on as best we can
  985. _fnInitialise( oSettings );
  986. }
  987. } );
  988. bInitHandedOff = true;
  989. }
  990. /*
  991. * Stripes
  992. */
  993. if ( oInit.asStripeClasses === null )
  994. {
  995. oSettings.asStripeClasses =[
  996. oClasses.sStripeOdd,
  997. oClasses.sStripeEven
  998. ];
  999. }
  1000. /* Remove row stripe classes if they are already on the table row */
  1001. var stripeClasses = oSettings.asStripeClasses;
  1002. var rowOne = $this.children('tbody').find('tr').eq(0);
  1003. if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
  1004. return rowOne.hasClass(el);
  1005. } ) ) !== -1 ) {
  1006. $('tbody tr', this).removeClass( stripeClasses.join(' ') );
  1007. oSettings.asDestroyStripes = stripeClasses.slice();
  1008. }
  1009. /*
  1010. * Columns
  1011. * See if we should load columns automatically or use defined ones
  1012. */
  1013. var anThs = [];
  1014. var aoColumnsInit;
  1015. var nThead = this.getElementsByTagName('thead');
  1016. if ( nThead.length !== 0 )
  1017. {
  1018. _fnDetectHeader( oSettings.aoHeader, nThead[0] );
  1019. anThs = _fnGetUniqueThs( oSettings );
  1020. }
  1021. /* If not given a column array, generate one with nulls */
  1022. if ( oInit.aoColumns === null )
  1023. {
  1024. aoColumnsInit = [];
  1025. for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
  1026. {
  1027. aoColumnsInit.push( null );
  1028. }
  1029. }
  1030. else
  1031. {
  1032. aoColumnsInit = oInit.aoColumns;
  1033. }
  1034. /* Add the columns */
  1035. for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
  1036. {
  1037. _fnAddColumn( oSettings, anThs ? anThs[i] : null );
  1038. }
  1039. /* Apply the column definitions */
  1040. _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
  1041. _fnColumnOptions( oSettings, iCol, oDef );
  1042. } );
  1043. /* HTML5 attribute detection - build an mData object automatically if the
  1044. * attributes are found
  1045. */
  1046. if ( rowOne.length ) {
  1047. var a = function ( cell, name ) {
  1048. return cell.getAttribute( 'data-'+name ) !== null ? name : null;
  1049. };
  1050. $( rowOne[0] ).children('th, td').each( function (i, cell) {
  1051. var col = oSettings.aoColumns[i];
  1052. if ( col.mData === i ) {
  1053. var sort = a( cell, 'sort' ) || a( cell, 'order' );
  1054. var filter = a( cell, 'filter' ) || a( cell, 'search' );
  1055. if ( sort !== null || filter !== null ) {
  1056. col.mData = {
  1057. _: i+'.display',
  1058. sort: sort !== null ? i+'.@data-'+sort : undefined,
  1059. type: sort !== null ? i+'.@data-'+sort : undefined,
  1060. filter: filter !== null ? i+'.@data-'+filter : undefined
  1061. };
  1062. _fnColumnOptions( oSettings, i );
  1063. }
  1064. }
  1065. } );
  1066. }
  1067. var features = oSettings.oFeatures;
  1068. var loadedInit = function () {
  1069. /*
  1070. * Sorting
  1071. * @todo For modularisation (1.11) this needs to do into a sort start up handler
  1072. */
  1073. // If aaSorting is not defined, then we use the first indicator in asSorting
  1074. // in case that has been altered, so the default sort reflects that option
  1075. if ( oInit.aaSorting === undefined ) {
  1076. var sorting = oSettings.aaSorting;
  1077. for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
  1078. sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
  1079. }
  1080. }
  1081. /* Do a first pass on the sorting classes (allows any size changes to be taken into
  1082. * account, and also will apply sorting disabled classes if disabled
  1083. */
  1084. _fnSortingClasses( oSettings );
  1085. if ( features.bSort ) {
  1086. _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
  1087. if ( oSettings.bSorted ) {
  1088. var aSort = _fnSortFlatten( oSettings );
  1089. var sortedColumns = {};
  1090. $.each( aSort, function (i, val) {
  1091. sortedColumns[ val.src ] = val.dir;
  1092. } );
  1093. _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
  1094. _fnSortAria( oSettings );
  1095. }
  1096. } );
  1097. }
  1098. _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
  1099. if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
  1100. _fnSortingClasses( oSettings );
  1101. }
  1102. }, 'sc' );
  1103. /*
  1104. * Final init
  1105. * Cache the header, body and footer as required, creating them if needed
  1106. */
  1107. // Work around for Webkit bug 83867 - store the caption-side before removing from doc
  1108. var captions = $this.children('caption').each( function () {
  1109. this._captionSide = $(this).css('caption-side');
  1110. } );
  1111. var thead = $this.children('thead');
  1112. if ( thead.length === 0 ) {
  1113. thead = $('<thead/>').appendTo($this);
  1114. }
  1115. oSettings.nTHead = thead[0];
  1116. var tbody = $this.children('tbody');
  1117. if ( tbody.length === 0 ) {
  1118. tbody = $('<tbody/>').appendTo($this);
  1119. }
  1120. oSettings.nTBody = tbody[0];
  1121. var tfoot = $this.children('tfoot');
  1122. if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
  1123. // If we are a scrolling table, and no footer has been given, then we need to create
  1124. // a tfoot element for the caption element to be appended to
  1125. tfoot = $('<tfoot/>').appendTo($this);
  1126. }
  1127. if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
  1128. $this.addClass( oClasses.sNoFooter );
  1129. }
  1130. else if ( tfoot.length > 0 ) {
  1131. oSettings.nTFoot = tfoot[0];
  1132. _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
  1133. }
  1134. /* Check if there is data passing into the constructor */
  1135. if ( oInit.aaData ) {
  1136. for ( i=0 ; i<oInit.aaData.length ; i++ ) {
  1137. _fnAddData( oSettings, oInit.aaData[ i ] );
  1138. }
  1139. }
  1140. else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
  1141. /* Grab the data from the page - only do this when deferred loading or no Ajax
  1142. * source since there is no point in reading the DOM data if we are then going
  1143. * to replace it with Ajax data
  1144. */
  1145. _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
  1146. }
  1147. /* Copy the data index array */
  1148. oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
  1149. /* Initialisation complete - table can be drawn */
  1150. oSettings.bInitialised = true;
  1151. /* Check if we need to initialise the table (it might not have been handed off to the
  1152. * language processor)
  1153. */
  1154. if ( bInitHandedOff === false ) {
  1155. _fnInitialise( oSettings );
  1156. }
  1157. };
  1158. /* Must be done after everything which can be overridden by the state saving! */
  1159. if ( oInit.bStateSave )
  1160. {
  1161. features.bStateSave = true;
  1162. _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
  1163. _fnLoadState( oSettings, oInit, loadedInit );
  1164. }
  1165. else {
  1166. loadedInit();
  1167. }
  1168. } );
  1169. _that = null;
  1170. return this;
  1171. };
  1172. /*
  1173. * It is useful to have variables which are scoped locally so only the
  1174. * DataTables functions can access them and they don't leak into global space.
  1175. * At the same time these functions are often useful over multiple files in the
  1176. * core and API, so we list, or at least document, all variables which are used
  1177. * by DataTables as private variables here. This also ensures that there is no
  1178. * clashing of variable names and that they can easily referenced for reuse.
  1179. */
  1180. // Defined else where
  1181. // _selector_run
  1182. // _selector_opts
  1183. // _selector_first
  1184. // _selector_row_indexes
  1185. var _ext; // DataTable.ext
  1186. var _Api; // DataTable.Api
  1187. var _api_register; // DataTable.Api.register
  1188. var _api_registerPlural; // DataTable.Api.registerPlural
  1189. var _re_dic = {};
  1190. var _re_new_lines = /[\r\n]/g;
  1191. var _re_html = /<.*?>/g;
  1192. // This is not strict ISO8601 - Date.parse() is quite lax, although
  1193. // implementations differ between browsers.
  1194. var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
  1195. // Escape regular expression special characters
  1196. var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
  1197. // http://en.wikipedia.org/wiki/Foreign_exchange_market
  1198. // - \u20BD - Russian ruble.
  1199. // - \u20a9 - South Korean Won
  1200. // - \u20BA - Turkish Lira
  1201. // - \u20B9 - Indian Rupee
  1202. // - R - Brazil (R$) and South Africa
  1203. // - fr - Swiss Franc
  1204. // - kr - Swedish krona, Norwegian krone and Danish krone
  1205. // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
  1206. // - Ƀ - Bitcoin
  1207. // - Ξ - Ethereum
  1208. // standards as thousands separators.
  1209. var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
  1210. var _empty = function ( d ) {
  1211. return !d || d === true || d === '-' ? true : false;
  1212. };
  1213. var _intVal = function ( s ) {
  1214. var integer = parseInt( s, 10 );
  1215. return !isNaN(integer) && isFinite(s) ? integer : null;
  1216. };
  1217. // Convert from a formatted number with characters other than `.` as the
  1218. // decimal place, to a Javascript number
  1219. var _numToDecimal = function ( num, decimalPoint ) {
  1220. // Cache created regular expressions for speed as this function is called often
  1221. if ( ! _re_dic[ decimalPoint ] ) {
  1222. _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
  1223. }
  1224. return typeof num === 'string' && decimalPoint !== '.' ?
  1225. num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
  1226. num;
  1227. };
  1228. var _isNumber = function ( d, decimalPoint, formatted ) {
  1229. var strType = typeof d === 'string';
  1230. // If empty return immediately so there must be a number if it is a
  1231. // formatted string (this stops the string "k", or "kr", etc being detected
  1232. // as a formatted number for currency
  1233. if ( _empty( d ) ) {
  1234. return true;
  1235. }
  1236. if ( decimalPoint && strType ) {
  1237. d = _numToDecimal( d, decimalPoint );
  1238. }
  1239. if ( formatted && strType ) {
  1240. d = d.replace( _re_formatted_numeric, '' );
  1241. }
  1242. return !isNaN( parseFloat(d) ) && isFinite( d );
  1243. };
  1244. // A string without HTML in it can be considered to be HTML still
  1245. var _isHtml = function ( d ) {
  1246. return _empty( d ) || typeof d === 'string';
  1247. };
  1248. var _htmlNumeric = function ( d, decimalPoint, formatted ) {
  1249. if ( _empty( d ) ) {
  1250. return true;
  1251. }
  1252. var html = _isHtml( d );
  1253. return ! html ?
  1254. null :
  1255. _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
  1256. true :
  1257. null;
  1258. };
  1259. var _pluck = function ( a, prop, prop2 ) {
  1260. var out = [];
  1261. var i=0, ien=a.length;
  1262. // Could have the test in the loop for slightly smaller code, but speed
  1263. // is essential here
  1264. if ( prop2 !== undefined ) {
  1265. for ( ; i<ien ; i++ ) {
  1266. if ( a[i] && a[i][ prop ] ) {
  1267. out.push( a[i][ prop ][ prop2 ] );
  1268. }
  1269. }
  1270. }
  1271. else {
  1272. for ( ; i<ien ; i++ ) {
  1273. if ( a[i] ) {
  1274. out.push( a[i][ prop ] );
  1275. }
  1276. }
  1277. }
  1278. return out;
  1279. };
  1280. // Basically the same as _pluck, but rather than looping over `a` we use `order`
  1281. // as the indexes to pick from `a`
  1282. var _pluck_order = function ( a, order, prop, prop2 )
  1283. {
  1284. var out = [];
  1285. var i=0, ien=order.length;
  1286. // Could have the test in the loop for slightly smaller code, but speed
  1287. // is essential here
  1288. if ( prop2 !== undefined ) {
  1289. for ( ; i<ien ; i++ ) {
  1290. if ( a[ order[i] ][ prop ] ) {
  1291. out.push( a[ order[i] ][ prop ][ prop2 ] );
  1292. }
  1293. }
  1294. }
  1295. else {
  1296. for ( ; i<ien ; i++ ) {
  1297. out.push( a[ order[i] ][ prop ] );
  1298. }
  1299. }
  1300. return out;
  1301. };
  1302. var _range = function ( len, start )
  1303. {
  1304. var out = [];
  1305. var end;
  1306. if ( start === undefined ) {
  1307. start = 0;
  1308. end = len;
  1309. }
  1310. else {
  1311. end = start;
  1312. start = len;
  1313. }
  1314. for ( var i=start ; i<end ; i++ ) {
  1315. out.push( i );
  1316. }
  1317. return out;
  1318. };
  1319. var _removeEmpty = function ( a )
  1320. {
  1321. var out = [];
  1322. for ( var i=0, ien=a.length ; i<ien ; i++ ) {
  1323. if ( a[i] ) { // careful - will remove all falsy values!
  1324. out.push( a[i] );
  1325. }
  1326. }
  1327. return out;
  1328. };
  1329. var _stripHtml = function ( d ) {
  1330. return d.replace( _re_html, '' );
  1331. };
  1332. /**
  1333. * Determine if all values in the array are unique. This means we can short
  1334. * cut the _unique method at the cost of a single loop. A sorted array is used
  1335. * to easily check the values.
  1336. *
  1337. * @param {array} src Source array
  1338. * @return {boolean} true if all unique, false otherwise
  1339. * @ignore
  1340. */
  1341. var _areAllUnique = function ( src ) {
  1342. if ( src.length < 2 ) {
  1343. return true;
  1344. }
  1345. var sorted = src.slice().sort();
  1346. var last = sorted[0];
  1347. for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
  1348. if ( sorted[i] === last ) {
  1349. return false;
  1350. }
  1351. last = sorted[i];
  1352. }
  1353. return true;
  1354. };
  1355. /**
  1356. * Find the unique elements in a source array.
  1357. *
  1358. * @param {array} src Source array
  1359. * @return {array} Array of unique items
  1360. * @ignore
  1361. */
  1362. var _unique = function ( src )
  1363. {
  1364. if ( _areAllUnique( src ) ) {
  1365. return src.slice();
  1366. }
  1367. // A faster unique method is to use object keys to identify used values,
  1368. // but this doesn't work with arrays or objects, which we must also
  1369. // consider. See jsperf.com/compare-array-unique-versions/4 for more
  1370. // information.
  1371. var
  1372. out = [],
  1373. val,
  1374. i, ien=src.length,
  1375. j, k=0;
  1376. again: for ( i=0 ; i<ien ; i++ ) {
  1377. val = src[i];
  1378. for ( j=0 ; j<k ; j++ ) {
  1379. if ( out[j] === val ) {
  1380. continue again;
  1381. }
  1382. }
  1383. out.push( val );
  1384. k++;
  1385. }
  1386. return out;
  1387. };
  1388. /**
  1389. * DataTables utility methods
  1390. *
  1391. * This namespace provides helper methods that DataTables uses internally to
  1392. * create a DataTable, but which are not exclusively used only for DataTables.
  1393. * These methods can be used by extension authors to save the duplication of
  1394. * code.
  1395. *
  1396. * @namespace
  1397. */
  1398. DataTable.util = {
  1399. /**
  1400. * Throttle the calls to a function. Arguments and context are maintained
  1401. * for the throttled function.
  1402. *
  1403. * @param {function} fn Function to be called
  1404. * @param {integer} freq Call frequency in mS
  1405. * @return {function} Wrapped function
  1406. */
  1407. throttle: function ( fn, freq ) {
  1408. var
  1409. frequency = freq !== undefined ? freq : 200,
  1410. last,
  1411. timer;
  1412. return function () {
  1413. var
  1414. that = this,
  1415. now = +new Date(),
  1416. args = arguments;
  1417. if ( last && now < last + frequency ) {
  1418. clearTimeout( timer );
  1419. timer = setTimeout( function () {
  1420. last = undefined;
  1421. fn.apply( that, args );
  1422. }, frequency );
  1423. }
  1424. else {
  1425. last = now;
  1426. fn.apply( that, args );
  1427. }
  1428. };
  1429. },
  1430. /**
  1431. * Escape a string such that it can be used in a regular expression
  1432. *
  1433. * @param {string} val string to escape
  1434. * @returns {string} escaped string
  1435. */
  1436. escapeRegex: function ( val ) {
  1437. return val.replace( _re_escape_regex, '\\$1' );
  1438. }
  1439. };
  1440. /**
  1441. * Create a mapping object that allows camel case parameters to be looked up
  1442. * for their Hungarian counterparts. The mapping is stored in a private
  1443. * parameter called `_hungarianMap` which can be accessed on the source object.
  1444. * @param {object} o
  1445. * @memberof DataTable#oApi
  1446. */
  1447. function _fnHungarianMap ( o )
  1448. {
  1449. var
  1450. hungarian = 'a aa ai ao as b fn i m o s ',
  1451. match,
  1452. newKey,
  1453. map = {};
  1454. $.each( o, function (key, val) {
  1455. match = key.match(/^([^A-Z]+?)([A-Z])/);
  1456. if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
  1457. {
  1458. newKey = key.replace( match[0], match[2].toLowerCase() );
  1459. map[ newKey ] = key;
  1460. if ( match[1] === 'o' )
  1461. {
  1462. _fnHungarianMap( o[key] );
  1463. }
  1464. }
  1465. } );
  1466. o._hungarianMap = map;
  1467. }
  1468. /**
  1469. * Convert from camel case parameters to Hungarian, based on a Hungarian map
  1470. * created by _fnHungarianMap.
  1471. * @param {object} src The model object which holds all parameters that can be
  1472. * mapped.
  1473. * @param {object} user The object to convert from camel case to Hungarian.
  1474. * @param {boolean} force When set to `true`, properties which already have a
  1475. * Hungarian value in the `user` object will be overwritten. Otherwise they
  1476. * won't be.
  1477. * @memberof DataTable#oApi
  1478. */
  1479. function _fnCamelToHungarian ( src, user, force )
  1480. {
  1481. if ( ! src._hungarianMap ) {
  1482. _fnHungarianMap( src );
  1483. }
  1484. var hungarianKey;
  1485. $.each( user, function (key, val) {
  1486. hungarianKey = src._hungarianMap[ key ];
  1487. if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
  1488. {
  1489. // For objects, we need to buzz down into the object to copy parameters
  1490. if ( hungarianKey.charAt(0) === 'o' )
  1491. {
  1492. // Copy the camelCase options over to the hungarian
  1493. if ( ! user[ hungarianKey ] ) {
  1494. user[ hungarianKey ] = {};
  1495. }
  1496. $.extend( true, user[hungarianKey], user[key] );
  1497. _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
  1498. }
  1499. else {
  1500. user[hungarianKey] = user[ key ];
  1501. }
  1502. }
  1503. } );
  1504. }
  1505. /**
  1506. * Language compatibility - when certain options are given, and others aren't, we
  1507. * need to duplicate the values over, in order to provide backwards compatibility
  1508. * with older language files.
  1509. * @param {object} oSettings dataTables settings object
  1510. * @memberof DataTable#oApi
  1511. */
  1512. function _fnLanguageCompat( lang )
  1513. {
  1514. // Note the use of the Hungarian notation for the parameters in this method as
  1515. // this is called after the mapping of camelCase to Hungarian
  1516. var defaults = DataTable.defaults.oLanguage;
  1517. // Default mapping
  1518. var defaultDecimal = defaults.sDecimal;
  1519. if ( defaultDecimal ) {
  1520. _addNumericSort( defaultDecimal );
  1521. }
  1522. if ( lang ) {
  1523. var zeroRecords = lang.sZeroRecords;
  1524. // Backwards compatibility - if there is no sEmptyTable given, then use the same as
  1525. // sZeroRecords - assuming that is given.
  1526. if ( ! lang.sEmptyTable && zeroRecords &&
  1527. defaults.sEmptyTable === "No data available in table" )
  1528. {
  1529. _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
  1530. }
  1531. // Likewise with loading records
  1532. if ( ! lang.sLoadingRecords && zeroRecords &&
  1533. defaults.sLoadingRecords === "Loading..." )
  1534. {
  1535. _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
  1536. }
  1537. // Old parameter name of the thousands separator mapped onto the new
  1538. if ( lang.sInfoThousands ) {
  1539. lang.sThousands = lang.sInfoThousands;
  1540. }
  1541. var decimal = lang.sDecimal;
  1542. if ( decimal && defaultDecimal !== decimal ) {
  1543. _addNumericSort( decimal );
  1544. }
  1545. }
  1546. }
  1547. /**
  1548. * Map one parameter onto another
  1549. * @param {object} o Object to map
  1550. * @param {*} knew The new parameter name
  1551. * @param {*} old The old parameter name
  1552. */
  1553. var _fnCompatMap = function ( o, knew, old ) {
  1554. if ( o[ knew ] !== undefined ) {
  1555. o[ old ] = o[ knew ];
  1556. }
  1557. };
  1558. /**
  1559. * Provide backwards compatibility for the main DT options. Note that the new
  1560. * options are mapped onto the old parameters, so this is an external interface
  1561. * change only.
  1562. * @param {object} init Object to map
  1563. */
  1564. function _fnCompatOpts ( init )
  1565. {
  1566. _fnCompatMap( init, 'ordering', 'bSort' );
  1567. _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
  1568. _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
  1569. _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
  1570. _fnCompatMap( init, 'order', 'aaSorting' );
  1571. _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
  1572. _fnCompatMap( init, 'paging', 'bPaginate' );
  1573. _fnCompatMap( init, 'pagingType', 'sPaginationType' );
  1574. _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
  1575. _fnCompatMap( init, 'searching', 'bFilter' );
  1576. // Boolean initialisation of x-scrolling
  1577. if ( typeof init.sScrollX === 'boolean' ) {
  1578. init.sScrollX = init.sScrollX ? '100%' : '';
  1579. }
  1580. if ( typeof init.scrollX === 'boolean' ) {
  1581. init.scrollX = init.scrollX ? '100%' : '';
  1582. }
  1583. // Column search objects are in an array, so it needs to be converted
  1584. // element by element
  1585. var searchCols = init.aoSearchCols;
  1586. if ( searchCols ) {
  1587. for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
  1588. if ( searchCols[i] ) {
  1589. _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
  1590. }
  1591. }
  1592. }
  1593. }
  1594. /**
  1595. * Provide backwards compatibility for column options. Note that the new options
  1596. * are mapped onto the old parameters, so this is an external interface change
  1597. * only.
  1598. * @param {object} init Object to map
  1599. */
  1600. function _fnCompatCols ( init )
  1601. {
  1602. _fnCompatMap( init, 'orderable', 'bSortable' );
  1603. _fnCompatMap( init, 'orderData', 'aDataSort' );
  1604. _fnCompatMap( init, 'orderSequence', 'asSorting' );
  1605. _fnCompatMap( init, 'orderDataType', 'sortDataType' );
  1606. // orderData can be given as an integer
  1607. var dataSort = init.aDataSort;
  1608. if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
  1609. init.aDataSort = [ dataSort ];
  1610. }
  1611. }
  1612. /**
  1613. * Browser feature detection for capabilities, quirks
  1614. * @param {object} settings dataTables settings object
  1615. * @memberof DataTable#oApi
  1616. */
  1617. function _fnBrowserDetect( settings )
  1618. {
  1619. // We don't need to do this every time DataTables is constructed, the values
  1620. // calculated are specific to the browser and OS configuration which we
  1621. // don't expect to change between initialisations
  1622. if ( ! DataTable.__browser ) {
  1623. var browser = {};
  1624. DataTable.__browser = browser;
  1625. // Scrolling feature / quirks detection
  1626. var n = $('<div/>')
  1627. .css( {
  1628. position: 'fixed',
  1629. top: 0,
  1630. left: $(window).scrollLeft()*-1, // allow for scrolling
  1631. height: 1,
  1632. width: 1,
  1633. overflow: 'hidden'
  1634. } )
  1635. .append(
  1636. $('<div/>')
  1637. .css( {
  1638. position: 'absolute',
  1639. top: 1,
  1640. left: 1,
  1641. width: 100,
  1642. overflow: 'scroll'
  1643. } )
  1644. .append(
  1645. $('<div/>')
  1646. .css( {
  1647. width: '100%',
  1648. height: 10
  1649. } )
  1650. )
  1651. )
  1652. .appendTo( 'body' );
  1653. var outer = n.children();
  1654. var inner = outer.children();
  1655. // Numbers below, in order, are:
  1656. // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
  1657. //
  1658. // IE6 XP: 100 100 100 83
  1659. // IE7 Vista: 100 100 100 83
  1660. // IE 8+ Windows: 83 83 100 83
  1661. // Evergreen Windows: 83 83 100 83
  1662. // Evergreen Mac with scrollbars: 85 85 100 85
  1663. // Evergreen Mac without scrollbars: 100 100 100 100
  1664. // Get scrollbar width
  1665. browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
  1666. // IE6/7 will oversize a width 100% element inside a scrolling element, to
  1667. // include the width of the scrollbar, while other browsers ensure the inner
  1668. // element is contained without forcing scrolling
  1669. browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
  1670. // In rtl text layout, some browsers (most, but not all) will place the
  1671. // scrollbar on the left, rather than the right.
  1672. browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
  1673. // IE8- don't provide height and width for getBoundingClientRect
  1674. browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
  1675. n.remove();
  1676. }
  1677. $.extend( settings.oBrowser, DataTable.__browser );
  1678. settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
  1679. }
  1680. /**
  1681. * Array.prototype reduce[Right] method, used for browsers which don't support
  1682. * JS 1.6. Done this way to reduce code size, since we iterate either way
  1683. * @param {object} settings dataTables settings object
  1684. * @memberof DataTable#oApi
  1685. */
  1686. function _fnReduce ( that, fn, init, start, end, inc )
  1687. {
  1688. var
  1689. i = start,
  1690. value,
  1691. isSet = false;
  1692. if ( init !== undefined ) {
  1693. value = init;
  1694. isSet = true;
  1695. }
  1696. while ( i !== end ) {
  1697. if ( ! that.hasOwnProperty(i) ) {
  1698. continue;
  1699. }
  1700. value = isSet ?
  1701. fn( value, that[i], i, that ) :
  1702. that[i];
  1703. isSet = true;
  1704. i += inc;
  1705. }
  1706. return value;
  1707. }
  1708. /**
  1709. * Add a column to the list used for the table with default values
  1710. * @param {object} oSettings dataTables settings object
  1711. * @param {node} nTh The th element for this column
  1712. * @memberof DataTable#oApi
  1713. */
  1714. function _fnAddColumn( oSettings, nTh )
  1715. {
  1716. // Add column to aoColumns array
  1717. var oDefaults = DataTable.defaults.column;
  1718. var iCol = oSettings.aoColumns.length;
  1719. var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
  1720. "nTh": nTh ? nTh : document.createElement('th'),
  1721. "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
  1722. "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
  1723. "mData": oDefaults.mData ? oDefaults.mData : iCol,
  1724. idx: iCol
  1725. } );
  1726. oSettings.aoColumns.push( oCol );
  1727. // Add search object for column specific search. Note that the `searchCols[ iCol ]`
  1728. // passed into extend can be undefined. This allows the user to give a default
  1729. // with only some of the parameters defined, and also not give a default
  1730. var searchCols = oSettings.aoPreSearchCols;
  1731. searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
  1732. // Use the default column options function to initialise classes etc
  1733. _fnColumnOptions( oSettings, iCol, $(nTh).data() );
  1734. }
  1735. /**
  1736. * Apply options for a column
  1737. * @param {object} oSettings dataTables settings object
  1738. * @param {int} iCol column index to consider
  1739. * @param {object} oOptions object with sType, bVisible and bSearchable etc
  1740. * @memberof DataTable#oApi
  1741. */
  1742. function _fnColumnOptions( oSettings, iCol, oOptions )
  1743. {
  1744. var oCol = oSettings.aoColumns[ iCol ];
  1745. var oClasses = oSettings.oClasses;
  1746. var th = $(oCol.nTh);
  1747. // Try to get width information from the DOM. We can't get it from CSS
  1748. // as we'd need to parse the CSS stylesheet. `width` option can override
  1749. if ( ! oCol.sWidthOrig ) {
  1750. // Width attribute
  1751. oCol.sWidthOrig = th.attr('width') || null;
  1752. // Style attribute
  1753. var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
  1754. if ( t ) {
  1755. oCol.sWidthOrig = t[1];
  1756. }
  1757. }
  1758. /* User specified column options */
  1759. if ( oOptions !== undefined && oOptions !== null )
  1760. {
  1761. // Backwards compatibility
  1762. _fnCompatCols( oOptions );
  1763. // Map camel case parameters to their Hungarian counterparts
  1764. _fnCamelToHungarian( DataTable.defaults.column, oOptions );
  1765. /* Backwards compatibility for mDataProp */
  1766. if ( oOptions.mDataProp !== undefined && !oOptions.mData )
  1767. {
  1768. oOptions.mData = oOptions.mDataProp;
  1769. }
  1770. if ( oOptions.sType )
  1771. {
  1772. oCol._sManualType = oOptions.sType;
  1773. }
  1774. // `class` is a reserved word in Javascript, so we need to provide
  1775. // the ability to use a valid name for the camel case input
  1776. if ( oOptions.className && ! oOptions.sClass )
  1777. {
  1778. oOptions.sClass = oOptions.className;
  1779. }
  1780. if ( oOptions.sClass ) {
  1781. th.addClass( oOptions.sClass );
  1782. }
  1783. $.extend( oCol, oOptions );
  1784. _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
  1785. /* iDataSort to be applied (backwards compatibility), but aDataSort will take
  1786. * priority if defined
  1787. */
  1788. if ( oOptions.iDataSort !== undefined )
  1789. {
  1790. oCol.aDataSort = [ oOptions.iDataSort ];
  1791. }
  1792. _fnMap( oCol, oOptions, "aDataSort" );
  1793. }
  1794. /* Cache the data get and set functions for speed */
  1795. var mDataSrc = oCol.mData;
  1796. var mData = _fnGetObjectDataFn( mDataSrc );
  1797. var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
  1798. var attrTest = function( src ) {
  1799. return typeof src === 'string' && src.indexOf('@') !== -1;
  1800. };
  1801. oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
  1802. attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
  1803. );
  1804. oCol._setter = null;
  1805. oCol.fnGetData = function (rowData, type, meta) {
  1806. var innerData = mData( rowData, type, undefined, meta );
  1807. return mRender && type ?
  1808. mRender( innerData, type, rowData, meta ) :
  1809. innerData;
  1810. };
  1811. oCol.fnSetData = function ( rowData, val, meta ) {
  1812. return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
  1813. };
  1814. // Indicate if DataTables should read DOM data as an object or array
  1815. // Used in _fnGetRowElements
  1816. if ( typeof mDataSrc !== 'number' ) {
  1817. oSettings._rowReadObject = true;
  1818. }
  1819. /* Feature sorting overrides column specific when off */
  1820. if ( !oSettings.oFeatures.bSort )
  1821. {
  1822. oCol.bSortable = false;
  1823. th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
  1824. }
  1825. /* Check that the class assignment is correct for sorting */
  1826. var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
  1827. var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
  1828. if ( !oCol.bSortable || (!bAsc && !bDesc) )
  1829. {
  1830. oCol.sSortingClass = oClasses.sSortableNone;
  1831. oCol.sSortingClassJUI = "";
  1832. }
  1833. else if ( bAsc && !bDesc )
  1834. {
  1835. oCol.sSortingClass = oClasses.sSortableAsc;
  1836. oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
  1837. }
  1838. else if ( !bAsc && bDesc )
  1839. {
  1840. oCol.sSortingClass = oClasses.sSortableDesc;
  1841. oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
  1842. }
  1843. else
  1844. {
  1845. oCol.sSortingClass = oClasses.sSortable;
  1846. oCol.sSortingClassJUI = oClasses.sSortJUI;
  1847. }
  1848. }
  1849. /**
  1850. * Adjust the table column widths for new data. Note: you would probably want to
  1851. * do a redraw after calling this function!
  1852. * @param {object} settings dataTables settings object
  1853. * @memberof DataTable#oApi
  1854. */
  1855. function _fnAdjustColumnSizing ( settings )
  1856. {
  1857. /* Not interested in doing column width calculation if auto-width is disabled */
  1858. if ( settings.oFeatures.bAutoWidth !== false )
  1859. {
  1860. var columns = settings.aoColumns;
  1861. _fnCalculateColumnWidths( settings );
  1862. for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
  1863. {
  1864. columns[i].nTh.style.width = columns[i].sWidth;
  1865. }
  1866. }
  1867. var scroll = settings.oScroll;
  1868. if ( scroll.sY !== '' || scroll.sX !== '')
  1869. {
  1870. _fnScrollDraw( settings );
  1871. }
  1872. _fnCallbackFire( settings, null, 'column-sizing', [settings] );
  1873. }
  1874. /**
  1875. * Covert the index of a visible column to the index in the data array (take account
  1876. * of hidden columns)
  1877. * @param {object} oSettings dataTables settings object
  1878. * @param {int} iMatch Visible column index to lookup
  1879. * @returns {int} i the data index
  1880. * @memberof DataTable#oApi
  1881. */
  1882. function _fnVisibleToColumnIndex( oSettings, iMatch )
  1883. {
  1884. var aiVis = _fnGetColumns( oSettings, 'bVisible' );
  1885. return typeof aiVis[iMatch] === 'number' ?
  1886. aiVis[iMatch] :
  1887. null;
  1888. }
  1889. /**
  1890. * Covert the index of an index in the data array and convert it to the visible
  1891. * column index (take account of hidden columns)
  1892. * @param {int} iMatch Column index to lookup
  1893. * @param {object} oSettings dataTables settings object
  1894. * @returns {int} i the data index
  1895. * @memberof DataTable#oApi
  1896. */
  1897. function _fnColumnIndexToVisible( oSettings, iMatch )
  1898. {
  1899. var aiVis = _fnGetColumns( oSettings, 'bVisible' );
  1900. var iPos = $.inArray( iMatch, aiVis );
  1901. return iPos !== -1 ? iPos : null;
  1902. }
  1903. /**
  1904. * Get the number of visible columns
  1905. * @param {object} oSettings dataTables settings object
  1906. * @returns {int} i the number of visible columns
  1907. * @memberof DataTable#oApi
  1908. */
  1909. function _fnVisbleColumns( oSettings )
  1910. {
  1911. var vis = 0;
  1912. // No reduce in IE8, use a loop for now
  1913. $.each( oSettings.aoColumns, function ( i, col ) {
  1914. if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
  1915. vis++;
  1916. }
  1917. } );
  1918. return vis;
  1919. }
  1920. /**
  1921. * Get an array of column indexes that match a given property
  1922. * @param {object} oSettings dataTables settings object
  1923. * @param {string} sParam Parameter in aoColumns to look for - typically
  1924. * bVisible or bSearchable
  1925. * @returns {array} Array of indexes with matched properties
  1926. * @memberof DataTable#oApi
  1927. */
  1928. function _fnGetColumns( oSettings, sParam )
  1929. {
  1930. var a = [];
  1931. $.map( oSettings.aoColumns, function(val, i) {
  1932. if ( val[sParam] ) {
  1933. a.push( i );
  1934. }
  1935. } );
  1936. return a;
  1937. }
  1938. /**
  1939. * Calculate the 'type' of a column
  1940. * @param {object} settings dataTables settings object
  1941. * @memberof DataTable#oApi
  1942. */
  1943. function _fnColumnTypes ( settings )
  1944. {
  1945. var columns = settings.aoColumns;
  1946. var data = settings.aoData;
  1947. var types = DataTable.ext.type.detect;
  1948. var i, ien, j, jen, k, ken;
  1949. var col, cell, detectedType, cache;
  1950. // For each column, spin over the
  1951. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  1952. col = columns[i];
  1953. cache = [];
  1954. if ( ! col.sType && col._sManualType ) {
  1955. col.sType = col._sManualType;
  1956. }
  1957. else if ( ! col.sType ) {
  1958. for ( j=0, jen=types.length ; j<jen ; j++ ) {
  1959. for ( k=0, ken=data.length ; k<ken ; k++ ) {
  1960. // Use a cache array so we only need to get the type data
  1961. // from the formatter once (when using multiple detectors)
  1962. if ( cache[k] === undefined ) {
  1963. cache[k] = _fnGetCellData( settings, k, i, 'type' );
  1964. }
  1965. detectedType = types[j]( cache[k], settings );
  1966. // If null, then this type can't apply to this column, so
  1967. // rather than testing all cells, break out. There is an
  1968. // exception for the last type which is `html`. We need to
  1969. // scan all rows since it is possible to mix string and HTML
  1970. // types
  1971. if ( ! detectedType && j !== types.length-1 ) {
  1972. break;
  1973. }
  1974. // Only a single match is needed for html type since it is
  1975. // bottom of the pile and very similar to string
  1976. if ( detectedType === 'html' ) {
  1977. break;
  1978. }
  1979. }
  1980. // Type is valid for all data points in the column - use this
  1981. // type
  1982. if ( detectedType ) {
  1983. col.sType = detectedType;
  1984. break;
  1985. }
  1986. }
  1987. // Fall back - if no type was detected, always use string
  1988. if ( ! col.sType ) {
  1989. col.sType = 'string';
  1990. }
  1991. }
  1992. }
  1993. }
  1994. /**
  1995. * Take the column definitions and static columns arrays and calculate how
  1996. * they relate to column indexes. The callback function will then apply the
  1997. * definition found for a column to a suitable configuration object.
  1998. * @param {object} oSettings dataTables settings object
  1999. * @param {array} aoColDefs The aoColumnDefs array that is to be applied
  2000. * @param {array} aoCols The aoColumns array that defines columns individually
  2001. * @param {function} fn Callback function - takes two parameters, the calculated
  2002. * column index and the definition for that column.
  2003. * @memberof DataTable#oApi
  2004. */
  2005. function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
  2006. {
  2007. var i, iLen, j, jLen, k, kLen, def;
  2008. var columns = oSettings.aoColumns;
  2009. // Column definitions with aTargets
  2010. if ( aoColDefs )
  2011. {
  2012. /* Loop over the definitions array - loop in reverse so first instance has priority */
  2013. for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
  2014. {
  2015. def = aoColDefs[i];
  2016. /* Each definition can target multiple columns, as it is an array */
  2017. var aTargets = def.targets !== undefined ?
  2018. def.targets :
  2019. def.aTargets;
  2020. if ( ! $.isArray( aTargets ) )
  2021. {
  2022. aTargets = [ aTargets ];
  2023. }
  2024. for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
  2025. {
  2026. if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
  2027. {
  2028. /* Add columns that we don't yet know about */
  2029. while( columns.length <= aTargets[j] )
  2030. {
  2031. _fnAddColumn( oSettings );
  2032. }
  2033. /* Integer, basic index */
  2034. fn( aTargets[j], def );
  2035. }
  2036. else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
  2037. {
  2038. /* Negative integer, right to left column counting */
  2039. fn( columns.length+aTargets[j], def );
  2040. }
  2041. else if ( typeof aTargets[j] === 'string' )
  2042. {
  2043. /* Class name matching on TH element */
  2044. for ( k=0, kLen=columns.length ; k<kLen ; k++ )
  2045. {
  2046. if ( aTargets[j] == "_all" ||
  2047. $(columns[k].nTh).hasClass( aTargets[j] ) )
  2048. {
  2049. fn( k, def );
  2050. }
  2051. }
  2052. }
  2053. }
  2054. }
  2055. }
  2056. // Statically defined columns array
  2057. if ( aoCols )
  2058. {
  2059. for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
  2060. {
  2061. fn( i, aoCols[i] );
  2062. }
  2063. }
  2064. }
  2065. /**
  2066. * Add a data array to the table, creating DOM node etc. This is the parallel to
  2067. * _fnGatherData, but for adding rows from a Javascript source, rather than a
  2068. * DOM source.
  2069. * @param {object} oSettings dataTables settings object
  2070. * @param {array} aData data array to be added
  2071. * @param {node} [nTr] TR element to add to the table - optional. If not given,
  2072. * DataTables will create a row automatically
  2073. * @param {array} [anTds] Array of TD|TH elements for the row - must be given
  2074. * if nTr is.
  2075. * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
  2076. * @memberof DataTable#oApi
  2077. */
  2078. function _fnAddData ( oSettings, aDataIn, nTr, anTds )
  2079. {
  2080. /* Create the object for storing information about this new row */
  2081. var iRow = oSettings.aoData.length;
  2082. var oData = $.extend( true, {}, DataTable.models.oRow, {
  2083. src: nTr ? 'dom' : 'data',
  2084. idx: iRow
  2085. } );
  2086. oData._aData = aDataIn;
  2087. oSettings.aoData.push( oData );
  2088. /* Create the cells */
  2089. var nTd, sThisType;
  2090. var columns = oSettings.aoColumns;
  2091. // Invalidate the column types as the new data needs to be revalidated
  2092. for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
  2093. {
  2094. columns[i].sType = null;
  2095. }
  2096. /* Add to the display array */
  2097. oSettings.aiDisplayMaster.push( iRow );
  2098. var id = oSettings.rowIdFn( aDataIn );
  2099. if ( id !== undefined ) {
  2100. oSettings.aIds[ id ] = oData;
  2101. }
  2102. /* Create the DOM information, or register it if already present */
  2103. if ( nTr || ! oSettings.oFeatures.bDeferRender )
  2104. {
  2105. _fnCreateTr( oSettings, iRow, nTr, anTds );
  2106. }
  2107. return iRow;
  2108. }
  2109. /**
  2110. * Add one or more TR elements to the table. Generally we'd expect to
  2111. * use this for reading data from a DOM sourced table, but it could be
  2112. * used for an TR element. Note that if a TR is given, it is used (i.e.
  2113. * it is not cloned).
  2114. * @param {object} settings dataTables settings object
  2115. * @param {array|node|jQuery} trs The TR element(s) to add to the table
  2116. * @returns {array} Array of indexes for the added rows
  2117. * @memberof DataTable#oApi
  2118. */
  2119. function _fnAddTr( settings, trs )
  2120. {
  2121. var row;
  2122. // Allow an individual node to be passed in
  2123. if ( ! (trs instanceof $) ) {
  2124. trs = $(trs);
  2125. }
  2126. return trs.map( function (i, el) {
  2127. row = _fnGetRowElements( settings, el );
  2128. return _fnAddData( settings, row.data, el, row.cells );
  2129. } );
  2130. }
  2131. /**
  2132. * Take a TR element and convert it to an index in aoData
  2133. * @param {object} oSettings dataTables settings object
  2134. * @param {node} n the TR element to find
  2135. * @returns {int} index if the node is found, null if not
  2136. * @memberof DataTable#oApi
  2137. */
  2138. function _fnNodeToDataIndex( oSettings, n )
  2139. {
  2140. return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
  2141. }
  2142. /**
  2143. * Take a TD element and convert it into a column data index (not the visible index)
  2144. * @param {object} oSettings dataTables settings object
  2145. * @param {int} iRow The row number the TD/TH can be found in
  2146. * @param {node} n The TD/TH element to find
  2147. * @returns {int} index if the node is found, -1 if not
  2148. * @memberof DataTable#oApi
  2149. */
  2150. function _fnNodeToColumnIndex( oSettings, iRow, n )
  2151. {
  2152. return $.inArray( n, oSettings.aoData[ iRow ].anCells );
  2153. }
  2154. /**
  2155. * Get the data for a given cell from the internal cache, taking into account data mapping
  2156. * @param {object} settings dataTables settings object
  2157. * @param {int} rowIdx aoData row id
  2158. * @param {int} colIdx Column index
  2159. * @param {string} type data get type ('display', 'type' 'filter' 'sort')
  2160. * @returns {*} Cell data
  2161. * @memberof DataTable#oApi
  2162. */
  2163. function _fnGetCellData( settings, rowIdx, colIdx, type )
  2164. {
  2165. var draw = settings.iDraw;
  2166. var col = settings.aoColumns[colIdx];
  2167. var rowData = settings.aoData[rowIdx]._aData;
  2168. var defaultContent = col.sDefaultContent;
  2169. var cellData = col.fnGetData( rowData, type, {
  2170. settings: settings,
  2171. row: rowIdx,
  2172. col: colIdx
  2173. } );
  2174. if ( cellData === undefined ) {
  2175. if ( settings.iDrawError != draw && defaultContent === null ) {
  2176. _fnLog( settings, 0, "Requested unknown parameter "+
  2177. (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
  2178. " for row "+rowIdx+", column "+colIdx, 4 );
  2179. settings.iDrawError = draw;
  2180. }
  2181. return defaultContent;
  2182. }
  2183. // When the data source is null and a specific data type is requested (i.e.
  2184. // not the original data), we can use default column data
  2185. if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
  2186. cellData = defaultContent;
  2187. }
  2188. else if ( typeof cellData === 'function' ) {
  2189. // If the data source is a function, then we run it and use the return,
  2190. // executing in the scope of the data object (for instances)
  2191. return cellData.call( rowData );
  2192. }
  2193. if ( cellData === null && type == 'display' ) {
  2194. return '';
  2195. }
  2196. return cellData;
  2197. }
  2198. /**
  2199. * Set the value for a specific cell, into the internal data cache
  2200. * @param {object} settings dataTables settings object
  2201. * @param {int} rowIdx aoData row id
  2202. * @param {int} colIdx Column index
  2203. * @param {*} val Value to set
  2204. * @memberof DataTable#oApi
  2205. */
  2206. function _fnSetCellData( settings, rowIdx, colIdx, val )
  2207. {
  2208. var col = settings.aoColumns[colIdx];
  2209. var rowData = settings.aoData[rowIdx]._aData;
  2210. col.fnSetData( rowData, val, {
  2211. settings: settings,
  2212. row: rowIdx,
  2213. col: colIdx
  2214. } );
  2215. }
  2216. // Private variable that is used to match action syntax in the data property object
  2217. var __reArray = /\[.*?\]$/;
  2218. var __reFn = /\(\)$/;
  2219. /**
  2220. * Split string on periods, taking into account escaped periods
  2221. * @param {string} str String to split
  2222. * @return {array} Split string
  2223. */
  2224. function _fnSplitObjNotation( str )
  2225. {
  2226. return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
  2227. return s.replace(/\\\./g, '.');
  2228. } );
  2229. }
  2230. /**
  2231. * Return a function that can be used to get data from a source object, taking
  2232. * into account the ability to use nested objects as a source
  2233. * @param {string|int|function} mSource The data source for the object
  2234. * @returns {function} Data get function
  2235. * @memberof DataTable#oApi
  2236. */
  2237. function _fnGetObjectDataFn( mSource )
  2238. {
  2239. if ( $.isPlainObject( mSource ) )
  2240. {
  2241. /* Build an object of get functions, and wrap them in a single call */
  2242. var o = {};
  2243. $.each( mSource, function (key, val) {
  2244. if ( val ) {
  2245. o[key] = _fnGetObjectDataFn( val );
  2246. }
  2247. } );
  2248. return function (data, type, row, meta) {
  2249. var t = o[type] || o._;
  2250. return t !== undefined ?
  2251. t(data, type, row, meta) :
  2252. data;
  2253. };
  2254. }
  2255. else if ( mSource === null )
  2256. {
  2257. /* Give an empty string for rendering / sorting etc */
  2258. return function (data) { // type, row and meta also passed, but not used
  2259. return data;
  2260. };
  2261. }
  2262. else if ( typeof mSource === 'function' )
  2263. {
  2264. return function (data, type, row, meta) {
  2265. return mSource( data, type, row, meta );
  2266. };
  2267. }
  2268. else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
  2269. mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
  2270. {
  2271. /* If there is a . in the source string then the data source is in a
  2272. * nested object so we loop over the data for each level to get the next
  2273. * level down. On each loop we test for undefined, and if found immediately
  2274. * return. This allows entire objects to be missing and sDefaultContent to
  2275. * be used if defined, rather than throwing an error
  2276. */
  2277. var fetchData = function (data, type, src) {
  2278. var arrayNotation, funcNotation, out, innerSrc;
  2279. if ( src !== "" )
  2280. {
  2281. var a = _fnSplitObjNotation( src );
  2282. for ( var i=0, iLen=a.length ; i<iLen ; i++ )
  2283. {
  2284. // Check if we are dealing with special notation
  2285. arrayNotation = a[i].match(__reArray);
  2286. funcNotation = a[i].match(__reFn);
  2287. if ( arrayNotation )
  2288. {
  2289. // Array notation
  2290. a[i] = a[i].replace(__reArray, '');
  2291. // Condition allows simply [] to be passed in
  2292. if ( a[i] !== "" ) {
  2293. data = data[ a[i] ];
  2294. }
  2295. out = [];
  2296. // Get the remainder of the nested object to get
  2297. a.splice( 0, i+1 );
  2298. innerSrc = a.join('.');
  2299. // Traverse each entry in the array getting the properties requested
  2300. if ( $.isArray( data ) ) {
  2301. for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
  2302. out.push( fetchData( data[j], type, innerSrc ) );
  2303. }
  2304. }
  2305. // If a string is given in between the array notation indicators, that
  2306. // is used to join the strings together, otherwise an array is returned
  2307. var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
  2308. data = (join==="") ? out : out.join(join);
  2309. // The inner call to fetchData has already traversed through the remainder
  2310. // of the source requested, so we exit from the loop
  2311. break;
  2312. }
  2313. else if ( funcNotation )
  2314. {
  2315. // Function call
  2316. a[i] = a[i].replace(__reFn, '');
  2317. data = data[ a[i] ]();
  2318. continue;
  2319. }
  2320. if ( data === null || data[ a[i] ] === undefined )
  2321. {
  2322. return undefined;
  2323. }
  2324. data = data[ a[i] ];
  2325. }
  2326. }
  2327. return data;
  2328. };
  2329. return function (data, type) { // row and meta also passed, but not used
  2330. return fetchData( data, type, mSource );
  2331. };
  2332. }
  2333. else
  2334. {
  2335. /* Array or flat object mapping */
  2336. return function (data, type) { // row and meta also passed, but not used
  2337. return data[mSource];
  2338. };
  2339. }
  2340. }
  2341. /**
  2342. * Return a function that can be used to set data from a source object, taking
  2343. * into account the ability to use nested objects as a source
  2344. * @param {string|int|function} mSource The data source for the object
  2345. * @returns {function} Data set function
  2346. * @memberof DataTable#oApi
  2347. */
  2348. function _fnSetObjectDataFn( mSource )
  2349. {
  2350. if ( $.isPlainObject( mSource ) )
  2351. {
  2352. /* Unlike get, only the underscore (global) option is used for for
  2353. * setting data since we don't know the type here. This is why an object
  2354. * option is not documented for `mData` (which is read/write), but it is
  2355. * for `mRender` which is read only.
  2356. */
  2357. return _fnSetObjectDataFn( mSource._ );
  2358. }
  2359. else if ( mSource === null )
  2360. {
  2361. /* Nothing to do when the data source is null */
  2362. return function () {};
  2363. }
  2364. else if ( typeof mSource === 'function' )
  2365. {
  2366. return function (data, val, meta) {
  2367. mSource( data, 'set', val, meta );
  2368. };
  2369. }
  2370. else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
  2371. mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
  2372. {
  2373. /* Like the get, we need to get data from a nested object */
  2374. var setData = function (data, val, src) {
  2375. var a = _fnSplitObjNotation( src ), b;
  2376. var aLast = a[a.length-1];
  2377. var arrayNotation, funcNotation, o, innerSrc;
  2378. for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
  2379. {
  2380. // Check if we are dealing with an array notation request
  2381. arrayNotation = a[i].match(__reArray);
  2382. funcNotation = a[i].match(__reFn);
  2383. if ( arrayNotation )
  2384. {
  2385. a[i] = a[i].replace(__reArray, '');
  2386. data[ a[i] ] = [];
  2387. // Get the remainder of the nested object to set so we can recurse
  2388. b = a.slice();
  2389. b.splice( 0, i+1 );
  2390. innerSrc = b.join('.');
  2391. // Traverse each entry in the array setting the properties requested
  2392. if ( $.isArray( val ) )
  2393. {
  2394. for ( var j=0, jLen=val.length ; j<jLen ; j++ )
  2395. {
  2396. o = {};
  2397. setData( o, val[j], innerSrc );
  2398. data[ a[i] ].push( o );
  2399. }
  2400. }
  2401. else
  2402. {
  2403. // We've been asked to save data to an array, but it
  2404. // isn't array data to be saved. Best that can be done
  2405. // is to just save the value.
  2406. data[ a[i] ] = val;
  2407. }
  2408. // The inner call to setData has already traversed through the remainder
  2409. // of the source and has set the data, thus we can exit here
  2410. return;
  2411. }
  2412. else if ( funcNotation )
  2413. {
  2414. // Function call
  2415. a[i] = a[i].replace(__reFn, '');
  2416. data = data[ a[i] ]( val );
  2417. }
  2418. // If the nested object doesn't currently exist - since we are
  2419. // trying to set the value - create it
  2420. if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
  2421. {
  2422. data[ a[i] ] = {};
  2423. }
  2424. data = data[ a[i] ];
  2425. }
  2426. // Last item in the input - i.e, the actual set
  2427. if ( aLast.match(__reFn ) )
  2428. {
  2429. // Function call
  2430. data = data[ aLast.replace(__reFn, '') ]( val );
  2431. }
  2432. else
  2433. {
  2434. // If array notation is used, we just want to strip it and use the property name
  2435. // and assign the value. If it isn't used, then we get the result we want anyway
  2436. data[ aLast.replace(__reArray, '') ] = val;
  2437. }
  2438. };
  2439. return function (data, val) { // meta is also passed in, but not used
  2440. return setData( data, val, mSource );
  2441. };
  2442. }
  2443. else
  2444. {
  2445. /* Array or flat object mapping */
  2446. return function (data, val) { // meta is also passed in, but not used
  2447. data[mSource] = val;
  2448. };
  2449. }
  2450. }
  2451. /**
  2452. * Return an array with the full table data
  2453. * @param {object} oSettings dataTables settings object
  2454. * @returns array {array} aData Master data array
  2455. * @memberof DataTable#oApi
  2456. */
  2457. function _fnGetDataMaster ( settings )
  2458. {
  2459. return _pluck( settings.aoData, '_aData' );
  2460. }
  2461. /**
  2462. * Nuke the table
  2463. * @param {object} oSettings dataTables settings object
  2464. * @memberof DataTable#oApi
  2465. */
  2466. function _fnClearTable( settings )
  2467. {
  2468. settings.aoData.length = 0;
  2469. settings.aiDisplayMaster.length = 0;
  2470. settings.aiDisplay.length = 0;
  2471. settings.aIds = {};
  2472. }
  2473. /**
  2474. * Take an array of integers (index array) and remove a target integer (value - not
  2475. * the key!)
  2476. * @param {array} a Index array to target
  2477. * @param {int} iTarget value to find
  2478. * @memberof DataTable#oApi
  2479. */
  2480. function _fnDeleteIndex( a, iTarget, splice )
  2481. {
  2482. var iTargetIndex = -1;
  2483. for ( var i=0, iLen=a.length ; i<iLen ; i++ )
  2484. {
  2485. if ( a[i] == iTarget )
  2486. {
  2487. iTargetIndex = i;
  2488. }
  2489. else if ( a[i] > iTarget )
  2490. {
  2491. a[i]--;
  2492. }
  2493. }
  2494. if ( iTargetIndex != -1 && splice === undefined )
  2495. {
  2496. a.splice( iTargetIndex, 1 );
  2497. }
  2498. }
  2499. /**
  2500. * Mark cached data as invalid such that a re-read of the data will occur when
  2501. * the cached data is next requested. Also update from the data source object.
  2502. *
  2503. * @param {object} settings DataTables settings object
  2504. * @param {int} rowIdx Row index to invalidate
  2505. * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
  2506. * or 'data'
  2507. * @param {int} [colIdx] Column index to invalidate. If undefined the whole
  2508. * row will be invalidated
  2509. * @memberof DataTable#oApi
  2510. *
  2511. * @todo For the modularisation of v1.11 this will need to become a callback, so
  2512. * the sort and filter methods can subscribe to it. That will required
  2513. * initialisation options for sorting, which is why it is not already baked in
  2514. */
  2515. function _fnInvalidate( settings, rowIdx, src, colIdx )
  2516. {
  2517. var row = settings.aoData[ rowIdx ];
  2518. var i, ien;
  2519. var cellWrite = function ( cell, col ) {
  2520. // This is very frustrating, but in IE if you just write directly
  2521. // to innerHTML, and elements that are overwritten are GC'ed,
  2522. // even if there is a reference to them elsewhere
  2523. while ( cell.childNodes.length ) {
  2524. cell.removeChild( cell.firstChild );
  2525. }
  2526. cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
  2527. };
  2528. // Are we reading last data from DOM or the data object?
  2529. if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
  2530. // Read the data from the DOM
  2531. row._aData = _fnGetRowElements(
  2532. settings, row, colIdx, colIdx === undefined ? undefined : row._aData
  2533. )
  2534. .data;
  2535. }
  2536. else {
  2537. // Reading from data object, update the DOM
  2538. var cells = row.anCells;
  2539. if ( cells ) {
  2540. if ( colIdx !== undefined ) {
  2541. cellWrite( cells[colIdx], colIdx );
  2542. }
  2543. else {
  2544. for ( i=0, ien=cells.length ; i<ien ; i++ ) {
  2545. cellWrite( cells[i], i );
  2546. }
  2547. }
  2548. }
  2549. }
  2550. // For both row and cell invalidation, the cached data for sorting and
  2551. // filtering is nulled out
  2552. row._aSortData = null;
  2553. row._aFilterData = null;
  2554. // Invalidate the type for a specific column (if given) or all columns since
  2555. // the data might have changed
  2556. var cols = settings.aoColumns;
  2557. if ( colIdx !== undefined ) {
  2558. cols[ colIdx ].sType = null;
  2559. }
  2560. else {
  2561. for ( i=0, ien=cols.length ; i<ien ; i++ ) {
  2562. cols[i].sType = null;
  2563. }
  2564. // Update DataTables special `DT_*` attributes for the row
  2565. _fnRowAttributes( settings, row );
  2566. }
  2567. }
  2568. /**
  2569. * Build a data source object from an HTML row, reading the contents of the
  2570. * cells that are in the row.
  2571. *
  2572. * @param {object} settings DataTables settings object
  2573. * @param {node|object} TR element from which to read data or existing row
  2574. * object from which to re-read the data from the cells
  2575. * @param {int} [colIdx] Optional column index
  2576. * @param {array|object} [d] Data source object. If `colIdx` is given then this
  2577. * parameter should also be given and will be used to write the data into.
  2578. * Only the column in question will be written
  2579. * @returns {object} Object with two parameters: `data` the data read, in
  2580. * document order, and `cells` and array of nodes (they can be useful to the
  2581. * caller, so rather than needing a second traversal to get them, just return
  2582. * them from here).
  2583. * @memberof DataTable#oApi
  2584. */
  2585. function _fnGetRowElements( settings, row, colIdx, d )
  2586. {
  2587. var
  2588. tds = [],
  2589. td = row.firstChild,
  2590. name, col, o, i=0, contents,
  2591. columns = settings.aoColumns,
  2592. objectRead = settings._rowReadObject;
  2593. // Allow the data object to be passed in, or construct
  2594. d = d !== undefined ?
  2595. d :
  2596. objectRead ?
  2597. {} :
  2598. [];
  2599. var attr = function ( str, td ) {
  2600. if ( typeof str === 'string' ) {
  2601. var idx = str.indexOf('@');
  2602. if ( idx !== -1 ) {
  2603. var attr = str.substring( idx+1 );
  2604. var setter = _fnSetObjectDataFn( str );
  2605. setter( d, td.getAttribute( attr ) );
  2606. }
  2607. }
  2608. };
  2609. // Read data from a cell and store into the data object
  2610. var cellProcess = function ( cell ) {
  2611. if ( colIdx === undefined || colIdx === i ) {
  2612. col = columns[i];
  2613. contents = $.trim(cell.innerHTML);
  2614. if ( col && col._bAttrSrc ) {
  2615. var setter = _fnSetObjectDataFn( col.mData._ );
  2616. setter( d, contents );
  2617. attr( col.mData.sort, cell );
  2618. attr( col.mData.type, cell );
  2619. attr( col.mData.filter, cell );
  2620. }
  2621. else {
  2622. // Depending on the `data` option for the columns the data can
  2623. // be read to either an object or an array.
  2624. if ( objectRead ) {
  2625. if ( ! col._setter ) {
  2626. // Cache the setter function
  2627. col._setter = _fnSetObjectDataFn( col.mData );
  2628. }
  2629. col._setter( d, contents );
  2630. }
  2631. else {
  2632. d[i] = contents;
  2633. }
  2634. }
  2635. }
  2636. i++;
  2637. };
  2638. if ( td ) {
  2639. // `tr` element was passed in
  2640. while ( td ) {
  2641. name = td.nodeName.toUpperCase();
  2642. if ( name == "TD" || name == "TH" ) {
  2643. cellProcess( td );
  2644. tds.push( td );
  2645. }
  2646. td = td.nextSibling;
  2647. }
  2648. }
  2649. else {
  2650. // Existing row object passed in
  2651. tds = row.anCells;
  2652. for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
  2653. cellProcess( tds[j] );
  2654. }
  2655. }
  2656. // Read the ID from the DOM if present
  2657. var rowNode = row.firstChild ? row : row.nTr;
  2658. if ( rowNode ) {
  2659. var id = rowNode.getAttribute( 'id' );
  2660. if ( id ) {
  2661. _fnSetObjectDataFn( settings.rowId )( d, id );
  2662. }
  2663. }
  2664. return {
  2665. data: d,
  2666. cells: tds
  2667. };
  2668. }
  2669. /**
  2670. * Create a new TR element (and it's TD children) for a row
  2671. * @param {object} oSettings dataTables settings object
  2672. * @param {int} iRow Row to consider
  2673. * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
  2674. * DataTables will create a row automatically
  2675. * @param {array} [anTds] Array of TD|TH elements for the row - must be given
  2676. * if nTr is.
  2677. * @memberof DataTable#oApi
  2678. */
  2679. function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
  2680. {
  2681. var
  2682. row = oSettings.aoData[iRow],
  2683. rowData = row._aData,
  2684. cells = [],
  2685. nTr, nTd, oCol,
  2686. i, iLen;
  2687. if ( row.nTr === null )
  2688. {
  2689. nTr = nTrIn || document.createElement('tr');
  2690. row.nTr = nTr;
  2691. row.anCells = cells;
  2692. /* Use a private property on the node to allow reserve mapping from the node
  2693. * to the aoData array for fast look up
  2694. */
  2695. nTr._DT_RowIndex = iRow;
  2696. /* Special parameters can be given by the data source to be used on the row */
  2697. _fnRowAttributes( oSettings, row );
  2698. /* Process each column */
  2699. for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
  2700. {
  2701. oCol = oSettings.aoColumns[i];
  2702. nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
  2703. nTd._DT_CellIndex = {
  2704. row: iRow,
  2705. column: i
  2706. };
  2707. cells.push( nTd );
  2708. // Need to create the HTML if new, or if a rendering function is defined
  2709. if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
  2710. (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
  2711. ) {
  2712. nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
  2713. }
  2714. /* Add user defined class */
  2715. if ( oCol.sClass )
  2716. {
  2717. nTd.className += ' '+oCol.sClass;
  2718. }
  2719. // Visibility - add or remove as required
  2720. if ( oCol.bVisible && ! nTrIn )
  2721. {
  2722. nTr.appendChild( nTd );
  2723. }
  2724. else if ( ! oCol.bVisible && nTrIn )
  2725. {
  2726. nTd.parentNode.removeChild( nTd );
  2727. }
  2728. if ( oCol.fnCreatedCell )
  2729. {
  2730. oCol.fnCreatedCell.call( oSettings.oInstance,
  2731. nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
  2732. );
  2733. }
  2734. }
  2735. _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );
  2736. }
  2737. // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
  2738. // and deployed
  2739. row.nTr.setAttribute( 'role', 'row' );
  2740. }
  2741. /**
  2742. * Add attributes to a row based on the special `DT_*` parameters in a data
  2743. * source object.
  2744. * @param {object} settings DataTables settings object
  2745. * @param {object} DataTables row object for the row to be modified
  2746. * @memberof DataTable#oApi
  2747. */
  2748. function _fnRowAttributes( settings, row )
  2749. {
  2750. var tr = row.nTr;
  2751. var data = row._aData;
  2752. if ( tr ) {
  2753. var id = settings.rowIdFn( data );
  2754. if ( id ) {
  2755. tr.id = id;
  2756. }
  2757. if ( data.DT_RowClass ) {
  2758. // Remove any classes added by DT_RowClass before
  2759. var a = data.DT_RowClass.split(' ');
  2760. row.__rowc = row.__rowc ?
  2761. _unique( row.__rowc.concat( a ) ) :
  2762. a;
  2763. $(tr)
  2764. .removeClass( row.__rowc.join(' ') )
  2765. .addClass( data.DT_RowClass );
  2766. }
  2767. if ( data.DT_RowAttr ) {
  2768. $(tr).attr( data.DT_RowAttr );
  2769. }
  2770. if ( data.DT_RowData ) {
  2771. $(tr).data( data.DT_RowData );
  2772. }
  2773. }
  2774. }
  2775. /**
  2776. * Create the HTML header for the table
  2777. * @param {object} oSettings dataTables settings object
  2778. * @memberof DataTable#oApi
  2779. */
  2780. function _fnBuildHead( oSettings )
  2781. {
  2782. var i, ien, cell, row, column;
  2783. var thead = oSettings.nTHead;
  2784. var tfoot = oSettings.nTFoot;
  2785. var createHeader = $('th, td', thead).length === 0;
  2786. var classes = oSettings.oClasses;
  2787. var columns = oSettings.aoColumns;
  2788. if ( createHeader ) {
  2789. row = $('<tr/>').appendTo( thead );
  2790. }
  2791. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  2792. column = columns[i];
  2793. cell = $( column.nTh ).addClass( column.sClass );
  2794. if ( createHeader ) {
  2795. cell.appendTo( row );
  2796. }
  2797. // 1.11 move into sorting
  2798. if ( oSettings.oFeatures.bSort ) {
  2799. cell.addClass( column.sSortingClass );
  2800. if ( column.bSortable !== false ) {
  2801. cell
  2802. .attr( 'tabindex', oSettings.iTabIndex )
  2803. .attr( 'aria-controls', oSettings.sTableId );
  2804. _fnSortAttachListener( oSettings, column.nTh, i );
  2805. }
  2806. }
  2807. if ( column.sTitle != cell[0].innerHTML ) {
  2808. cell.html( column.sTitle );
  2809. }
  2810. _fnRenderer( oSettings, 'header' )(
  2811. oSettings, cell, column, classes
  2812. );
  2813. }
  2814. if ( createHeader ) {
  2815. _fnDetectHeader( oSettings.aoHeader, thead );
  2816. }
  2817. /* ARIA role for the rows */
  2818. $(thead).find('>tr').attr('role', 'row');
  2819. /* Deal with the footer - add classes if required */
  2820. $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
  2821. $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
  2822. // Cache the footer cells. Note that we only take the cells from the first
  2823. // row in the footer. If there is more than one row the user wants to
  2824. // interact with, they need to use the table().foot() method. Note also this
  2825. // allows cells to be used for multiple columns using colspan
  2826. if ( tfoot !== null ) {
  2827. var cells = oSettings.aoFooter[0];
  2828. for ( i=0, ien=cells.length ; i<ien ; i++ ) {
  2829. column = columns[i];
  2830. column.nTf = cells[i].cell;
  2831. if ( column.sClass ) {
  2832. $(column.nTf).addClass( column.sClass );
  2833. }
  2834. }
  2835. }
  2836. }
  2837. /**
  2838. * Draw the header (or footer) element based on the column visibility states. The
  2839. * methodology here is to use the layout array from _fnDetectHeader, modified for
  2840. * the instantaneous column visibility, to construct the new layout. The grid is
  2841. * traversed over cell at a time in a rows x columns grid fashion, although each
  2842. * cell insert can cover multiple elements in the grid - which is tracks using the
  2843. * aApplied array. Cell inserts in the grid will only occur where there isn't
  2844. * already a cell in that position.
  2845. * @param {object} oSettings dataTables settings object
  2846. * @param array {objects} aoSource Layout array from _fnDetectHeader
  2847. * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
  2848. * @memberof DataTable#oApi
  2849. */
  2850. function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
  2851. {
  2852. var i, iLen, j, jLen, k, kLen, n, nLocalTr;
  2853. var aoLocal = [];
  2854. var aApplied = [];
  2855. var iColumns = oSettings.aoColumns.length;
  2856. var iRowspan, iColspan;
  2857. if ( ! aoSource )
  2858. {
  2859. return;
  2860. }
  2861. if ( bIncludeHidden === undefined )
  2862. {
  2863. bIncludeHidden = false;
  2864. }
  2865. /* Make a copy of the master layout array, but without the visible columns in it */
  2866. for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
  2867. {
  2868. aoLocal[i] = aoSource[i].slice();
  2869. aoLocal[i].nTr = aoSource[i].nTr;
  2870. /* Remove any columns which are currently hidden */
  2871. for ( j=iColumns-1 ; j>=0 ; j-- )
  2872. {
  2873. if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
  2874. {
  2875. aoLocal[i].splice( j, 1 );
  2876. }
  2877. }
  2878. /* Prep the applied array - it needs an element for each row */
  2879. aApplied.push( [] );
  2880. }
  2881. for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
  2882. {
  2883. nLocalTr = aoLocal[i].nTr;
  2884. /* All cells are going to be replaced, so empty out the row */
  2885. if ( nLocalTr )
  2886. {
  2887. while( (n = nLocalTr.firstChild) )
  2888. {
  2889. nLocalTr.removeChild( n );
  2890. }
  2891. }
  2892. for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
  2893. {
  2894. iRowspan = 1;
  2895. iColspan = 1;
  2896. /* Check to see if there is already a cell (row/colspan) covering our target
  2897. * insert point. If there is, then there is nothing to do.
  2898. */
  2899. if ( aApplied[i][j] === undefined )
  2900. {
  2901. nLocalTr.appendChild( aoLocal[i][j].cell );
  2902. aApplied[i][j] = 1;
  2903. /* Expand the cell to cover as many rows as needed */
  2904. while ( aoLocal[i+iRowspan] !== undefined &&
  2905. aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
  2906. {
  2907. aApplied[i+iRowspan][j] = 1;
  2908. iRowspan++;
  2909. }
  2910. /* Expand the cell to cover as many columns as needed */
  2911. while ( aoLocal[i][j+iColspan] !== undefined &&
  2912. aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
  2913. {
  2914. /* Must update the applied array over the rows for the columns */
  2915. for ( k=0 ; k<iRowspan ; k++ )
  2916. {
  2917. aApplied[i+k][j+iColspan] = 1;
  2918. }
  2919. iColspan++;
  2920. }
  2921. /* Do the actual expansion in the DOM */
  2922. $(aoLocal[i][j].cell)
  2923. .attr('rowspan', iRowspan)
  2924. .attr('colspan', iColspan);
  2925. }
  2926. }
  2927. }
  2928. }
  2929. /**
  2930. * Insert the required TR nodes into the table for display
  2931. * @param {object} oSettings dataTables settings object
  2932. * @memberof DataTable#oApi
  2933. */
  2934. function _fnDraw( oSettings )
  2935. {
  2936. /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
  2937. var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
  2938. if ( $.inArray( false, aPreDraw ) !== -1 )
  2939. {
  2940. _fnProcessingDisplay( oSettings, false );
  2941. return;
  2942. }
  2943. var i, iLen, n;
  2944. var anRows = [];
  2945. var iRowCount = 0;
  2946. var asStripeClasses = oSettings.asStripeClasses;
  2947. var iStripes = asStripeClasses.length;
  2948. var iOpenRows = oSettings.aoOpenRows.length;
  2949. var oLang = oSettings.oLanguage;
  2950. var iInitDisplayStart = oSettings.iInitDisplayStart;
  2951. var bServerSide = _fnDataSource( oSettings ) == 'ssp';
  2952. var aiDisplay = oSettings.aiDisplay;
  2953. oSettings.bDrawing = true;
  2954. /* Check and see if we have an initial draw position from state saving */
  2955. if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
  2956. {
  2957. oSettings._iDisplayStart = bServerSide ?
  2958. iInitDisplayStart :
  2959. iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
  2960. 0 :
  2961. iInitDisplayStart;
  2962. oSettings.iInitDisplayStart = -1;
  2963. }
  2964. var iDisplayStart = oSettings._iDisplayStart;
  2965. var iDisplayEnd = oSettings.fnDisplayEnd();
  2966. /* Server-side processing draw intercept */
  2967. if ( oSettings.bDeferLoading )
  2968. {
  2969. oSettings.bDeferLoading = false;
  2970. oSettings.iDraw++;
  2971. _fnProcessingDisplay( oSettings, false );
  2972. }
  2973. else if ( !bServerSide )
  2974. {
  2975. oSettings.iDraw++;
  2976. }
  2977. else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
  2978. {
  2979. return;
  2980. }
  2981. if ( aiDisplay.length !== 0 )
  2982. {
  2983. var iStart = bServerSide ? 0 : iDisplayStart;
  2984. var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
  2985. for ( var j=iStart ; j<iEnd ; j++ )
  2986. {
  2987. var iDataIndex = aiDisplay[j];
  2988. var aoData = oSettings.aoData[ iDataIndex ];
  2989. if ( aoData.nTr === null )
  2990. {
  2991. _fnCreateTr( oSettings, iDataIndex );
  2992. }
  2993. var nRow = aoData.nTr;
  2994. /* Remove the old striping classes and then add the new one */
  2995. if ( iStripes !== 0 )
  2996. {
  2997. var sStripe = asStripeClasses[ iRowCount % iStripes ];
  2998. if ( aoData._sRowStripe != sStripe )
  2999. {
  3000. $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
  3001. aoData._sRowStripe = sStripe;
  3002. }
  3003. }
  3004. // Row callback functions - might want to manipulate the row
  3005. // iRowCount and j are not currently documented. Are they at all
  3006. // useful?
  3007. _fnCallbackFire( oSettings, 'aoRowCallback', null,
  3008. [nRow, aoData._aData, iRowCount, j, iDataIndex] );
  3009. anRows.push( nRow );
  3010. iRowCount++;
  3011. }
  3012. }
  3013. else
  3014. {
  3015. /* Table is empty - create a row with an empty message in it */
  3016. var sZero = oLang.sZeroRecords;
  3017. if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
  3018. {
  3019. sZero = oLang.sLoadingRecords;
  3020. }
  3021. else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
  3022. {
  3023. sZero = oLang.sEmptyTable;
  3024. }
  3025. anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
  3026. .append( $('<td />', {
  3027. 'valign': 'top',
  3028. 'colSpan': _fnVisbleColumns( oSettings ),
  3029. 'class': oSettings.oClasses.sRowEmpty
  3030. } ).html( sZero ) )[0];
  3031. }
  3032. /* Header and footer callbacks */
  3033. _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
  3034. _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
  3035. _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
  3036. _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
  3037. var body = $(oSettings.nTBody);
  3038. body.children().detach();
  3039. body.append( $(anRows) );
  3040. /* Call all required callback functions for the end of a draw */
  3041. _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
  3042. /* Draw is complete, sorting and filtering must be as well */
  3043. oSettings.bSorted = false;
  3044. oSettings.bFiltered = false;
  3045. oSettings.bDrawing = false;
  3046. }
  3047. /**
  3048. * Redraw the table - taking account of the various features which are enabled
  3049. * @param {object} oSettings dataTables settings object
  3050. * @param {boolean} [holdPosition] Keep the current paging position. By default
  3051. * the paging is reset to the first page
  3052. * @memberof DataTable#oApi
  3053. */
  3054. function _fnReDraw( settings, holdPosition )
  3055. {
  3056. var
  3057. features = settings.oFeatures,
  3058. sort = features.bSort,
  3059. filter = features.bFilter;
  3060. if ( sort ) {
  3061. _fnSort( settings );
  3062. }
  3063. if ( filter ) {
  3064. _fnFilterComplete( settings, settings.oPreviousSearch );
  3065. }
  3066. else {
  3067. // No filtering, so we want to just use the display master
  3068. settings.aiDisplay = settings.aiDisplayMaster.slice();
  3069. }
  3070. if ( holdPosition !== true ) {
  3071. settings._iDisplayStart = 0;
  3072. }
  3073. // Let any modules know about the draw hold position state (used by
  3074. // scrolling internally)
  3075. settings._drawHold = holdPosition;
  3076. _fnDraw( settings );
  3077. settings._drawHold = false;
  3078. }
  3079. /**
  3080. * Add the options to the page HTML for the table
  3081. * @param {object} oSettings dataTables settings object
  3082. * @memberof DataTable#oApi
  3083. */
  3084. function _fnAddOptionsHtml ( oSettings )
  3085. {
  3086. var classes = oSettings.oClasses;
  3087. var table = $(oSettings.nTable);
  3088. var holding = $('<div/>').insertBefore( table ); // Holding element for speed
  3089. var features = oSettings.oFeatures;
  3090. // All DataTables are wrapped in a div
  3091. var insert = $('<div/>', {
  3092. id: oSettings.sTableId+'_wrapper',
  3093. 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
  3094. } );
  3095. oSettings.nHolding = holding[0];
  3096. oSettings.nTableWrapper = insert[0];
  3097. oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
  3098. /* Loop over the user set positioning and place the elements as needed */
  3099. var aDom = oSettings.sDom.split('');
  3100. var featureNode, cOption, nNewNode, cNext, sAttr, j;
  3101. for ( var i=0 ; i<aDom.length ; i++ )
  3102. {
  3103. featureNode = null;
  3104. cOption = aDom[i];
  3105. if ( cOption == '<' )
  3106. {
  3107. /* New container div */
  3108. nNewNode = $('<div/>')[0];
  3109. /* Check to see if we should append an id and/or a class name to the container */
  3110. cNext = aDom[i+1];
  3111. if ( cNext == "'" || cNext == '"' )
  3112. {
  3113. sAttr = "";
  3114. j = 2;
  3115. while ( aDom[i+j] != cNext )
  3116. {
  3117. sAttr += aDom[i+j];
  3118. j++;
  3119. }
  3120. /* Replace jQuery UI constants @todo depreciated */
  3121. if ( sAttr == "H" )
  3122. {
  3123. sAttr = classes.sJUIHeader;
  3124. }
  3125. else if ( sAttr == "F" )
  3126. {
  3127. sAttr = classes.sJUIFooter;
  3128. }
  3129. /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
  3130. * breaks the string into parts and applies them as needed
  3131. */
  3132. if ( sAttr.indexOf('.') != -1 )
  3133. {
  3134. var aSplit = sAttr.split('.');
  3135. nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
  3136. nNewNode.className = aSplit[1];
  3137. }
  3138. else if ( sAttr.charAt(0) == "#" )
  3139. {
  3140. nNewNode.id = sAttr.substr(1, sAttr.length-1);
  3141. }
  3142. else
  3143. {
  3144. nNewNode.className = sAttr;
  3145. }
  3146. i += j; /* Move along the position array */
  3147. }
  3148. insert.append( nNewNode );
  3149. insert = $(nNewNode);
  3150. }
  3151. else if ( cOption == '>' )
  3152. {
  3153. /* End container div */
  3154. insert = insert.parent();
  3155. }
  3156. // @todo Move options into their own plugins?
  3157. else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
  3158. {
  3159. /* Length */
  3160. featureNode = _fnFeatureHtmlLength( oSettings );
  3161. }
  3162. else if ( cOption == 'f' && features.bFilter )
  3163. {
  3164. /* Filter */
  3165. featureNode = _fnFeatureHtmlFilter( oSettings );
  3166. }
  3167. else if ( cOption == 'r' && features.bProcessing )
  3168. {
  3169. /* pRocessing */
  3170. featureNode = _fnFeatureHtmlProcessing( oSettings );
  3171. }
  3172. else if ( cOption == 't' )
  3173. {
  3174. /* Table */
  3175. featureNode = _fnFeatureHtmlTable( oSettings );
  3176. }
  3177. else if ( cOption == 'i' && features.bInfo )
  3178. {
  3179. /* Info */
  3180. featureNode = _fnFeatureHtmlInfo( oSettings );
  3181. }
  3182. else if ( cOption == 'p' && features.bPaginate )
  3183. {
  3184. /* Pagination */
  3185. featureNode = _fnFeatureHtmlPaginate( oSettings );
  3186. }
  3187. else if ( DataTable.ext.feature.length !== 0 )
  3188. {
  3189. /* Plug-in features */
  3190. var aoFeatures = DataTable.ext.feature;
  3191. for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
  3192. {
  3193. if ( cOption == aoFeatures[k].cFeature )
  3194. {
  3195. featureNode = aoFeatures[k].fnInit( oSettings );
  3196. break;
  3197. }
  3198. }
  3199. }
  3200. /* Add to the 2D features array */
  3201. if ( featureNode )
  3202. {
  3203. var aanFeatures = oSettings.aanFeatures;
  3204. if ( ! aanFeatures[cOption] )
  3205. {
  3206. aanFeatures[cOption] = [];
  3207. }
  3208. aanFeatures[cOption].push( featureNode );
  3209. insert.append( featureNode );
  3210. }
  3211. }
  3212. /* Built our DOM structure - replace the holding div with what we want */
  3213. holding.replaceWith( insert );
  3214. oSettings.nHolding = null;
  3215. }
  3216. /**
  3217. * Use the DOM source to create up an array of header cells. The idea here is to
  3218. * create a layout grid (array) of rows x columns, which contains a reference
  3219. * to the cell that that point in the grid (regardless of col/rowspan), such that
  3220. * any column / row could be removed and the new grid constructed
  3221. * @param array {object} aLayout Array to store the calculated layout in
  3222. * @param {node} nThead The header/footer element for the table
  3223. * @memberof DataTable#oApi
  3224. */
  3225. function _fnDetectHeader ( aLayout, nThead )
  3226. {
  3227. var nTrs = $(nThead).children('tr');
  3228. var nTr, nCell;
  3229. var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
  3230. var bUnique;
  3231. var fnShiftCol = function ( a, i, j ) {
  3232. var k = a[i];
  3233. while ( k[j] ) {
  3234. j++;
  3235. }
  3236. return j;
  3237. };
  3238. aLayout.splice( 0, aLayout.length );
  3239. /* We know how many rows there are in the layout - so prep it */
  3240. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  3241. {
  3242. aLayout.push( [] );
  3243. }
  3244. /* Calculate a layout array */
  3245. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  3246. {
  3247. nTr = nTrs[i];
  3248. iColumn = 0;
  3249. /* For every cell in the row... */
  3250. nCell = nTr.firstChild;
  3251. while ( nCell ) {
  3252. if ( nCell.nodeName.toUpperCase() == "TD" ||
  3253. nCell.nodeName.toUpperCase() == "TH" )
  3254. {
  3255. /* Get the col and rowspan attributes from the DOM and sanitise them */
  3256. iColspan = nCell.getAttribute('colspan') * 1;
  3257. iRowspan = nCell.getAttribute('rowspan') * 1;
  3258. iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
  3259. iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
  3260. /* There might be colspan cells already in this row, so shift our target
  3261. * accordingly
  3262. */
  3263. iColShifted = fnShiftCol( aLayout, i, iColumn );
  3264. /* Cache calculation for unique columns */
  3265. bUnique = iColspan === 1 ? true : false;
  3266. /* If there is col / rowspan, copy the information into the layout grid */
  3267. for ( l=0 ; l<iColspan ; l++ )
  3268. {
  3269. for ( k=0 ; k<iRowspan ; k++ )
  3270. {
  3271. aLayout[i+k][iColShifted+l] = {
  3272. "cell": nCell,
  3273. "unique": bUnique
  3274. };
  3275. aLayout[i+k].nTr = nTr;
  3276. }
  3277. }
  3278. }
  3279. nCell = nCell.nextSibling;
  3280. }
  3281. }
  3282. }
  3283. /**
  3284. * Get an array of unique th elements, one for each column
  3285. * @param {object} oSettings dataTables settings object
  3286. * @param {node} nHeader automatically detect the layout from this node - optional
  3287. * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
  3288. * @returns array {node} aReturn list of unique th's
  3289. * @memberof DataTable#oApi
  3290. */
  3291. function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
  3292. {
  3293. var aReturn = [];
  3294. if ( !aLayout )
  3295. {
  3296. aLayout = oSettings.aoHeader;
  3297. if ( nHeader )
  3298. {
  3299. aLayout = [];
  3300. _fnDetectHeader( aLayout, nHeader );
  3301. }
  3302. }
  3303. for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
  3304. {
  3305. for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
  3306. {
  3307. if ( aLayout[i][j].unique &&
  3308. (!aReturn[j] || !oSettings.bSortCellsTop) )
  3309. {
  3310. aReturn[j] = aLayout[i][j].cell;
  3311. }
  3312. }
  3313. }
  3314. return aReturn;
  3315. }
  3316. /**
  3317. * Create an Ajax call based on the table's settings, taking into account that
  3318. * parameters can have multiple forms, and backwards compatibility.
  3319. *
  3320. * @param {object} oSettings dataTables settings object
  3321. * @param {array} data Data to send to the server, required by
  3322. * DataTables - may be augmented by developer callbacks
  3323. * @param {function} fn Callback function to run when data is obtained
  3324. */
  3325. function _fnBuildAjax( oSettings, data, fn )
  3326. {
  3327. // Compatibility with 1.9-, allow fnServerData and event to manipulate
  3328. _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
  3329. // Convert to object based for 1.10+ if using the old array scheme which can
  3330. // come from server-side processing or serverParams
  3331. if ( data && $.isArray(data) ) {
  3332. var tmp = {};
  3333. var rbracket = /(.*?)\[\]$/;
  3334. $.each( data, function (key, val) {
  3335. var match = val.name.match(rbracket);
  3336. if ( match ) {
  3337. // Support for arrays
  3338. var name = match[0];
  3339. if ( ! tmp[ name ] ) {
  3340. tmp[ name ] = [];
  3341. }
  3342. tmp[ name ].push( val.value );
  3343. }
  3344. else {
  3345. tmp[val.name] = val.value;
  3346. }
  3347. } );
  3348. data = tmp;
  3349. }
  3350. var ajaxData;
  3351. var ajax = oSettings.ajax;
  3352. var instance = oSettings.oInstance;
  3353. var callback = function ( json ) {
  3354. _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
  3355. fn( json );
  3356. };
  3357. if ( $.isPlainObject( ajax ) && ajax.data )
  3358. {
  3359. ajaxData = ajax.data;
  3360. var newData = typeof ajaxData === 'function' ?
  3361. ajaxData( data, oSettings ) : // fn can manipulate data or return
  3362. ajaxData; // an object object or array to merge
  3363. // If the function returned something, use that alone
  3364. data = typeof ajaxData === 'function' && newData ?
  3365. newData :
  3366. $.extend( true, data, newData );
  3367. // Remove the data property as we've resolved it already and don't want
  3368. // jQuery to do it again (it is restored at the end of the function)
  3369. delete ajax.data;
  3370. }
  3371. var baseAjax = {
  3372. "data": data,
  3373. "success": function (json) {
  3374. var error = json.error || json.sError;
  3375. if ( error ) {
  3376. _fnLog( oSettings, 0, error );
  3377. }
  3378. oSettings.json = json;
  3379. callback( json );
  3380. },
  3381. "dataType": "json",
  3382. "cache": false,
  3383. "type": oSettings.sServerMethod,
  3384. "error": function (xhr, error, thrown) {
  3385. var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
  3386. if ( $.inArray( true, ret ) === -1 ) {
  3387. if ( error == "parsererror" ) {
  3388. _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
  3389. }
  3390. else if ( xhr.readyState === 4 ) {
  3391. _fnLog( oSettings, 0, 'Ajax error', 7 );
  3392. }
  3393. }
  3394. _fnProcessingDisplay( oSettings, false );
  3395. }
  3396. };
  3397. // Store the data submitted for the API
  3398. oSettings.oAjaxData = data;
  3399. // Allow plug-ins and external processes to modify the data
  3400. _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
  3401. if ( oSettings.fnServerData )
  3402. {
  3403. // DataTables 1.9- compatibility
  3404. oSettings.fnServerData.call( instance,
  3405. oSettings.sAjaxSource,
  3406. $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
  3407. return { name: key, value: val };
  3408. } ),
  3409. callback,
  3410. oSettings
  3411. );
  3412. }
  3413. else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
  3414. {
  3415. // DataTables 1.9- compatibility
  3416. oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
  3417. url: ajax || oSettings.sAjaxSource
  3418. } ) );
  3419. }
  3420. else if ( typeof ajax === 'function' )
  3421. {
  3422. // Is a function - let the caller define what needs to be done
  3423. oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
  3424. }
  3425. else
  3426. {
  3427. // Object to extend the base settings
  3428. oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
  3429. // Restore for next time around
  3430. ajax.data = ajaxData;
  3431. }
  3432. }
  3433. /**
  3434. * Update the table using an Ajax call
  3435. * @param {object} settings dataTables settings object
  3436. * @returns {boolean} Block the table drawing or not
  3437. * @memberof DataTable#oApi
  3438. */
  3439. function _fnAjaxUpdate( settings )
  3440. {
  3441. if ( settings.bAjaxDataGet ) {
  3442. settings.iDraw++;
  3443. _fnProcessingDisplay( settings, true );
  3444. _fnBuildAjax(
  3445. settings,
  3446. _fnAjaxParameters( settings ),
  3447. function(json) {
  3448. _fnAjaxUpdateDraw( settings, json );
  3449. }
  3450. );
  3451. return false;
  3452. }
  3453. return true;
  3454. }
  3455. /**
  3456. * Build up the parameters in an object needed for a server-side processing
  3457. * request. Note that this is basically done twice, is different ways - a modern
  3458. * method which is used by default in DataTables 1.10 which uses objects and
  3459. * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
  3460. * the sAjaxSource option is used in the initialisation, or the legacyAjax
  3461. * option is set.
  3462. * @param {object} oSettings dataTables settings object
  3463. * @returns {bool} block the table drawing or not
  3464. * @memberof DataTable#oApi
  3465. */
  3466. function _fnAjaxParameters( settings )
  3467. {
  3468. var
  3469. columns = settings.aoColumns,
  3470. columnCount = columns.length,
  3471. features = settings.oFeatures,
  3472. preSearch = settings.oPreviousSearch,
  3473. preColSearch = settings.aoPreSearchCols,
  3474. i, data = [], dataProp, column, columnSearch,
  3475. sort = _fnSortFlatten( settings ),
  3476. displayStart = settings._iDisplayStart,
  3477. displayLength = features.bPaginate !== false ?
  3478. settings._iDisplayLength :
  3479. -1;
  3480. var param = function ( name, value ) {
  3481. data.push( { 'name': name, 'value': value } );
  3482. };
  3483. // DataTables 1.9- compatible method
  3484. param( 'sEcho', settings.iDraw );
  3485. param( 'iColumns', columnCount );
  3486. param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
  3487. param( 'iDisplayStart', displayStart );
  3488. param( 'iDisplayLength', displayLength );
  3489. // DataTables 1.10+ method
  3490. var d = {
  3491. draw: settings.iDraw,
  3492. columns: [],
  3493. order: [],
  3494. start: displayStart,
  3495. length: displayLength,
  3496. search: {
  3497. value: preSearch.sSearch,
  3498. regex: preSearch.bRegex
  3499. }
  3500. };
  3501. for ( i=0 ; i<columnCount ; i++ ) {
  3502. column = columns[i];
  3503. columnSearch = preColSearch[i];
  3504. dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
  3505. d.columns.push( {
  3506. data: dataProp,
  3507. name: column.sName,
  3508. searchable: column.bSearchable,
  3509. orderable: column.bSortable,
  3510. search: {
  3511. value: columnSearch.sSearch,
  3512. regex: columnSearch.bRegex
  3513. }
  3514. } );
  3515. param( "mDataProp_"+i, dataProp );
  3516. if ( features.bFilter ) {
  3517. param( 'sSearch_'+i, columnSearch.sSearch );
  3518. param( 'bRegex_'+i, columnSearch.bRegex );
  3519. param( 'bSearchable_'+i, column.bSearchable );
  3520. }
  3521. if ( features.bSort ) {
  3522. param( 'bSortable_'+i, column.bSortable );
  3523. }
  3524. }
  3525. if ( features.bFilter ) {
  3526. param( 'sSearch', preSearch.sSearch );
  3527. param( 'bRegex', preSearch.bRegex );
  3528. }
  3529. if ( features.bSort ) {
  3530. $.each( sort, function ( i, val ) {
  3531. d.order.push( { column: val.col, dir: val.dir } );
  3532. param( 'iSortCol_'+i, val.col );
  3533. param( 'sSortDir_'+i, val.dir );
  3534. } );
  3535. param( 'iSortingCols', sort.length );
  3536. }
  3537. // If the legacy.ajax parameter is null, then we automatically decide which
  3538. // form to use, based on sAjaxSource
  3539. var legacy = DataTable.ext.legacy.ajax;
  3540. if ( legacy === null ) {
  3541. return settings.sAjaxSource ? data : d;
  3542. }
  3543. // Otherwise, if legacy has been specified then we use that to decide on the
  3544. // form
  3545. return legacy ? data : d;
  3546. }
  3547. /**
  3548. * Data the data from the server (nuking the old) and redraw the table
  3549. * @param {object} oSettings dataTables settings object
  3550. * @param {object} json json data return from the server.
  3551. * @param {string} json.sEcho Tracking flag for DataTables to match requests
  3552. * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
  3553. * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
  3554. * @param {array} json.aaData The data to display on this page
  3555. * @param {string} [json.sColumns] Column ordering (sName, comma separated)
  3556. * @memberof DataTable#oApi
  3557. */
  3558. function _fnAjaxUpdateDraw ( settings, json )
  3559. {
  3560. // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
  3561. // Support both
  3562. var compat = function ( old, modern ) {
  3563. return json[old] !== undefined ? json[old] : json[modern];
  3564. };
  3565. var data = _fnAjaxDataSrc( settings, json );
  3566. var draw = compat( 'sEcho', 'draw' );
  3567. var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
  3568. var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
  3569. if ( draw ) {
  3570. // Protect against out of sequence returns
  3571. if ( draw*1 < settings.iDraw ) {
  3572. return;
  3573. }
  3574. settings.iDraw = draw * 1;
  3575. }
  3576. _fnClearTable( settings );
  3577. settings._iRecordsTotal = parseInt(recordsTotal, 10);
  3578. settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
  3579. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  3580. _fnAddData( settings, data[i] );
  3581. }
  3582. settings.aiDisplay = settings.aiDisplayMaster.slice();
  3583. settings.bAjaxDataGet = false;
  3584. _fnDraw( settings );
  3585. if ( ! settings._bInitComplete ) {
  3586. _fnInitComplete( settings, json );
  3587. }
  3588. settings.bAjaxDataGet = true;
  3589. _fnProcessingDisplay( settings, false );
  3590. }
  3591. /**
  3592. * Get the data from the JSON data source to use for drawing a table. Using
  3593. * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
  3594. * source object, or from a processing function.
  3595. * @param {object} oSettings dataTables settings object
  3596. * @param {object} json Data source object / array from the server
  3597. * @return {array} Array of data to use
  3598. */
  3599. function _fnAjaxDataSrc ( oSettings, json )
  3600. {
  3601. var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
  3602. oSettings.ajax.dataSrc :
  3603. oSettings.sAjaxDataProp; // Compatibility with 1.9-.
  3604. // Compatibility with 1.9-. In order to read from aaData, check if the
  3605. // default has been changed, if not, check for aaData
  3606. if ( dataSrc === 'data' ) {
  3607. return json.aaData || json[dataSrc];
  3608. }
  3609. return dataSrc !== "" ?
  3610. _fnGetObjectDataFn( dataSrc )( json ) :
  3611. json;
  3612. }
  3613. /**
  3614. * Generate the node required for filtering text
  3615. * @returns {node} Filter control element
  3616. * @param {object} oSettings dataTables settings object
  3617. * @memberof DataTable#oApi
  3618. */
  3619. function _fnFeatureHtmlFilter ( settings )
  3620. {
  3621. var classes = settings.oClasses;
  3622. var tableId = settings.sTableId;
  3623. var language = settings.oLanguage;
  3624. var previousSearch = settings.oPreviousSearch;
  3625. var features = settings.aanFeatures;
  3626. var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
  3627. var str = language.sSearch;
  3628. str = str.match(/_INPUT_/) ?
  3629. str.replace('_INPUT_', input) :
  3630. str+input;
  3631. var filter = $('<div/>', {
  3632. 'id': ! features.f ? tableId+'_filter' : null,
  3633. 'class': classes.sFilter
  3634. } )
  3635. .append( $('<label/>' ).append( str ) );
  3636. var searchFn = function() {
  3637. /* Update all other filter input elements for the new display */
  3638. var n = features.f;
  3639. var val = !this.value ? "" : this.value; // mental IE8 fix :-(
  3640. /* Now do the filter */
  3641. if ( val != previousSearch.sSearch ) {
  3642. _fnFilterComplete( settings, {
  3643. "sSearch": val,
  3644. "bRegex": previousSearch.bRegex,
  3645. "bSmart": previousSearch.bSmart ,
  3646. "bCaseInsensitive": previousSearch.bCaseInsensitive
  3647. } );
  3648. // Need to redraw, without resorting
  3649. settings._iDisplayStart = 0;
  3650. _fnDraw( settings );
  3651. }
  3652. };
  3653. var searchDelay = settings.searchDelay !== null ?
  3654. settings.searchDelay :
  3655. _fnDataSource( settings ) === 'ssp' ?
  3656. 400 :
  3657. 0;
  3658. var jqFilter = $('input', filter)
  3659. .val( previousSearch.sSearch )
  3660. .attr( 'placeholder', language.sSearchPlaceholder )
  3661. .on(
  3662. 'keyup.DT search.DT input.DT paste.DT cut.DT',
  3663. searchDelay ?
  3664. _fnThrottle( searchFn, searchDelay ) :
  3665. searchFn
  3666. )
  3667. .on( 'keypress.DT', function(e) {
  3668. /* Prevent form submission */
  3669. if ( e.keyCode == 13 ) {
  3670. return false;
  3671. }
  3672. } )
  3673. .attr('aria-controls', tableId);
  3674. // Update the input elements whenever the table is filtered
  3675. $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
  3676. if ( settings === s ) {
  3677. // IE9 throws an 'unknown error' if document.activeElement is used
  3678. // inside an iframe or frame...
  3679. try {
  3680. if ( jqFilter[0] !== document.activeElement ) {
  3681. jqFilter.val( previousSearch.sSearch );
  3682. }
  3683. }
  3684. catch ( e ) {}
  3685. }
  3686. } );
  3687. return filter[0];
  3688. }
  3689. /**
  3690. * Filter the table using both the global filter and column based filtering
  3691. * @param {object} oSettings dataTables settings object
  3692. * @param {object} oSearch search information
  3693. * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
  3694. * @memberof DataTable#oApi
  3695. */
  3696. function _fnFilterComplete ( oSettings, oInput, iForce )
  3697. {
  3698. var oPrevSearch = oSettings.oPreviousSearch;
  3699. var aoPrevSearch = oSettings.aoPreSearchCols;
  3700. var fnSaveFilter = function ( oFilter ) {
  3701. /* Save the filtering values */
  3702. oPrevSearch.sSearch = oFilter.sSearch;
  3703. oPrevSearch.bRegex = oFilter.bRegex;
  3704. oPrevSearch.bSmart = oFilter.bSmart;
  3705. oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
  3706. };
  3707. var fnRegex = function ( o ) {
  3708. // Backwards compatibility with the bEscapeRegex option
  3709. return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
  3710. };
  3711. // Resolve any column types that are unknown due to addition or invalidation
  3712. // @todo As per sort - can this be moved into an event handler?
  3713. _fnColumnTypes( oSettings );
  3714. /* In server-side processing all filtering is done by the server, so no point hanging around here */
  3715. if ( _fnDataSource( oSettings ) != 'ssp' )
  3716. {
  3717. /* Global filter */
  3718. _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
  3719. fnSaveFilter( oInput );
  3720. /* Now do the individual column filter */
  3721. for ( var i=0 ; i<aoPrevSearch.length ; i++ )
  3722. {
  3723. _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
  3724. aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
  3725. }
  3726. /* Custom filtering */
  3727. _fnFilterCustom( oSettings );
  3728. }
  3729. else
  3730. {
  3731. fnSaveFilter( oInput );
  3732. }
  3733. /* Tell the draw function we have been filtering */
  3734. oSettings.bFiltered = true;
  3735. _fnCallbackFire( oSettings, null, 'search', [oSettings] );
  3736. }
  3737. /**
  3738. * Apply custom filtering functions
  3739. * @param {object} oSettings dataTables settings object
  3740. * @memberof DataTable#oApi
  3741. */
  3742. function _fnFilterCustom( settings )
  3743. {
  3744. var filters = DataTable.ext.search;
  3745. var displayRows = settings.aiDisplay;
  3746. var row, rowIdx;
  3747. for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
  3748. var rows = [];
  3749. // Loop over each row and see if it should be included
  3750. for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
  3751. rowIdx = displayRows[ j ];
  3752. row = settings.aoData[ rowIdx ];
  3753. if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
  3754. rows.push( rowIdx );
  3755. }
  3756. }
  3757. // So the array reference doesn't break set the results into the
  3758. // existing array
  3759. displayRows.length = 0;
  3760. $.merge( displayRows, rows );
  3761. }
  3762. }
  3763. /**
  3764. * Filter the table on a per-column basis
  3765. * @param {object} oSettings dataTables settings object
  3766. * @param {string} sInput string to filter on
  3767. * @param {int} iColumn column to filter
  3768. * @param {bool} bRegex treat search string as a regular expression or not
  3769. * @param {bool} bSmart use smart filtering or not
  3770. * @param {bool} bCaseInsensitive Do case insenstive matching or not
  3771. * @memberof DataTable#oApi
  3772. */
  3773. function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
  3774. {
  3775. if ( searchStr === '' ) {
  3776. return;
  3777. }
  3778. var data;
  3779. var out = [];
  3780. var display = settings.aiDisplay;
  3781. var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
  3782. for ( var i=0 ; i<display.length ; i++ ) {
  3783. data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
  3784. if ( rpSearch.test( data ) ) {
  3785. out.push( display[i] );
  3786. }
  3787. }
  3788. settings.aiDisplay = out;
  3789. }
  3790. /**
  3791. * Filter the data table based on user input and draw the table
  3792. * @param {object} settings dataTables settings object
  3793. * @param {string} input string to filter on
  3794. * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
  3795. * @param {bool} regex treat as a regular expression or not
  3796. * @param {bool} smart perform smart filtering or not
  3797. * @param {bool} caseInsensitive Do case insenstive matching or not
  3798. * @memberof DataTable#oApi
  3799. */
  3800. function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
  3801. {
  3802. var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
  3803. var prevSearch = settings.oPreviousSearch.sSearch;
  3804. var displayMaster = settings.aiDisplayMaster;
  3805. var display, invalidated, i;
  3806. var filtered = [];
  3807. // Need to take account of custom filtering functions - always filter
  3808. if ( DataTable.ext.search.length !== 0 ) {
  3809. force = true;
  3810. }
  3811. // Check if any of the rows were invalidated
  3812. invalidated = _fnFilterData( settings );
  3813. // If the input is blank - we just want the full data set
  3814. if ( input.length <= 0 ) {
  3815. settings.aiDisplay = displayMaster.slice();
  3816. }
  3817. else {
  3818. // New search - start from the master array
  3819. if ( invalidated ||
  3820. force ||
  3821. prevSearch.length > input.length ||
  3822. input.indexOf(prevSearch) !== 0 ||
  3823. settings.bSorted // On resort, the display master needs to be
  3824. // re-filtered since indexes will have changed
  3825. ) {
  3826. settings.aiDisplay = displayMaster.slice();
  3827. }
  3828. // Search the display array
  3829. display = settings.aiDisplay;
  3830. for ( i=0 ; i<display.length ; i++ ) {
  3831. if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
  3832. filtered.push( display[i] );
  3833. }
  3834. }
  3835. settings.aiDisplay = filtered;
  3836. }
  3837. }
  3838. /**
  3839. * Build a regular expression object suitable for searching a table
  3840. * @param {string} sSearch string to search for
  3841. * @param {bool} bRegex treat as a regular expression or not
  3842. * @param {bool} bSmart perform smart filtering or not
  3843. * @param {bool} bCaseInsensitive Do case insensitive matching or not
  3844. * @returns {RegExp} constructed object
  3845. * @memberof DataTable#oApi
  3846. */
  3847. function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
  3848. {
  3849. search = regex ?
  3850. search :
  3851. _fnEscapeRegex( search );
  3852. if ( smart ) {
  3853. /* For smart filtering we want to allow the search to work regardless of
  3854. * word order. We also want double quoted text to be preserved, so word
  3855. * order is important - a la google. So this is what we want to
  3856. * generate:
  3857. *
  3858. * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
  3859. */
  3860. var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
  3861. if ( word.charAt(0) === '"' ) {
  3862. var m = word.match( /^"(.*)"$/ );
  3863. word = m ? m[1] : word;
  3864. }
  3865. return word.replace('"', '');
  3866. } );
  3867. search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
  3868. }
  3869. return new RegExp( search, caseInsensitive ? 'i' : '' );
  3870. }
  3871. /**
  3872. * Escape a string such that it can be used in a regular expression
  3873. * @param {string} sVal string to escape
  3874. * @returns {string} escaped string
  3875. * @memberof DataTable#oApi
  3876. */
  3877. var _fnEscapeRegex = DataTable.util.escapeRegex;
  3878. var __filter_div = $('<div>')[0];
  3879. var __filter_div_textContent = __filter_div.textContent !== undefined;
  3880. // Update the filtering data for each row if needed (by invalidation or first run)
  3881. function _fnFilterData ( settings )
  3882. {
  3883. var columns = settings.aoColumns;
  3884. var column;
  3885. var i, j, ien, jen, filterData, cellData, row;
  3886. var fomatters = DataTable.ext.type.search;
  3887. var wasInvalidated = false;
  3888. for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  3889. row = settings.aoData[i];
  3890. if ( ! row._aFilterData ) {
  3891. filterData = [];
  3892. for ( j=0, jen=columns.length ; j<jen ; j++ ) {
  3893. column = columns[j];
  3894. if ( column.bSearchable ) {
  3895. cellData = _fnGetCellData( settings, i, j, 'filter' );
  3896. if ( fomatters[ column.sType ] ) {
  3897. cellData = fomatters[ column.sType ]( cellData );
  3898. }
  3899. // Search in DataTables 1.10 is string based. In 1.11 this
  3900. // should be altered to also allow strict type checking.
  3901. if ( cellData === null ) {
  3902. cellData = '';
  3903. }
  3904. if ( typeof cellData !== 'string' && cellData.toString ) {
  3905. cellData = cellData.toString();
  3906. }
  3907. }
  3908. else {
  3909. cellData = '';
  3910. }
  3911. // If it looks like there is an HTML entity in the string,
  3912. // attempt to decode it so sorting works as expected. Note that
  3913. // we could use a single line of jQuery to do this, but the DOM
  3914. // method used here is much faster http://jsperf.com/html-decode
  3915. if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
  3916. __filter_div.innerHTML = cellData;
  3917. cellData = __filter_div_textContent ?
  3918. __filter_div.textContent :
  3919. __filter_div.innerText;
  3920. }
  3921. if ( cellData.replace ) {
  3922. cellData = cellData.replace(/[\r\n]/g, '');
  3923. }
  3924. filterData.push( cellData );
  3925. }
  3926. row._aFilterData = filterData;
  3927. row._sFilterRow = filterData.join(' ');
  3928. wasInvalidated = true;
  3929. }
  3930. }
  3931. return wasInvalidated;
  3932. }
  3933. /**
  3934. * Convert from the internal Hungarian notation to camelCase for external
  3935. * interaction
  3936. * @param {object} obj Object to convert
  3937. * @returns {object} Inverted object
  3938. * @memberof DataTable#oApi
  3939. */
  3940. function _fnSearchToCamel ( obj )
  3941. {
  3942. return {
  3943. search: obj.sSearch,
  3944. smart: obj.bSmart,
  3945. regex: obj.bRegex,
  3946. caseInsensitive: obj.bCaseInsensitive
  3947. };
  3948. }
  3949. /**
  3950. * Convert from camelCase notation to the internal Hungarian. We could use the
  3951. * Hungarian convert function here, but this is cleaner
  3952. * @param {object} obj Object to convert
  3953. * @returns {object} Inverted object
  3954. * @memberof DataTable#oApi
  3955. */
  3956. function _fnSearchToHung ( obj )
  3957. {
  3958. return {
  3959. sSearch: obj.search,
  3960. bSmart: obj.smart,
  3961. bRegex: obj.regex,
  3962. bCaseInsensitive: obj.caseInsensitive
  3963. };
  3964. }
  3965. /**
  3966. * Generate the node required for the info display
  3967. * @param {object} oSettings dataTables settings object
  3968. * @returns {node} Information element
  3969. * @memberof DataTable#oApi
  3970. */
  3971. function _fnFeatureHtmlInfo ( settings )
  3972. {
  3973. var
  3974. tid = settings.sTableId,
  3975. nodes = settings.aanFeatures.i,
  3976. n = $('<div/>', {
  3977. 'class': settings.oClasses.sInfo,
  3978. 'id': ! nodes ? tid+'_info' : null
  3979. } );
  3980. if ( ! nodes ) {
  3981. // Update display on each draw
  3982. settings.aoDrawCallback.push( {
  3983. "fn": _fnUpdateInfo,
  3984. "sName": "information"
  3985. } );
  3986. n
  3987. .attr( 'role', 'status' )
  3988. .attr( 'aria-live', 'polite' );
  3989. // Table is described by our info div
  3990. $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
  3991. }
  3992. return n[0];
  3993. }
  3994. /**
  3995. * Update the information elements in the display
  3996. * @param {object} settings dataTables settings object
  3997. * @memberof DataTable#oApi
  3998. */
  3999. function _fnUpdateInfo ( settings )
  4000. {
  4001. /* Show information about the table */
  4002. var nodes = settings.aanFeatures.i;
  4003. if ( nodes.length === 0 ) {
  4004. return;
  4005. }
  4006. var
  4007. lang = settings.oLanguage,
  4008. start = settings._iDisplayStart+1,
  4009. end = settings.fnDisplayEnd(),
  4010. max = settings.fnRecordsTotal(),
  4011. total = settings.fnRecordsDisplay(),
  4012. out = total ?
  4013. lang.sInfo :
  4014. lang.sInfoEmpty;
  4015. if ( total !== max ) {
  4016. /* Record set after filtering */
  4017. out += ' ' + lang.sInfoFiltered;
  4018. }
  4019. // Convert the macros
  4020. out += lang.sInfoPostFix;
  4021. out = _fnInfoMacros( settings, out );
  4022. var callback = lang.fnInfoCallback;
  4023. if ( callback !== null ) {
  4024. out = callback.call( settings.oInstance,
  4025. settings, start, end, max, total, out
  4026. );
  4027. }
  4028. $(nodes).html( out );
  4029. }
  4030. function _fnInfoMacros ( settings, str )
  4031. {
  4032. // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
  4033. // internally
  4034. var
  4035. formatter = settings.fnFormatNumber,
  4036. start = settings._iDisplayStart+1,
  4037. len = settings._iDisplayLength,
  4038. vis = settings.fnRecordsDisplay(),
  4039. all = len === -1;
  4040. return str.
  4041. replace(/_START_/g, formatter.call( settings, start ) ).
  4042. replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
  4043. replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
  4044. replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
  4045. replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
  4046. replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
  4047. }
  4048. /**
  4049. * Draw the table for the first time, adding all required features
  4050. * @param {object} settings dataTables settings object
  4051. * @memberof DataTable#oApi
  4052. */
  4053. function _fnInitialise ( settings )
  4054. {
  4055. var i, iLen, iAjaxStart=settings.iInitDisplayStart;
  4056. var columns = settings.aoColumns, column;
  4057. var features = settings.oFeatures;
  4058. var deferLoading = settings.bDeferLoading; // value modified by the draw
  4059. /* Ensure that the table data is fully initialised */
  4060. if ( ! settings.bInitialised ) {
  4061. setTimeout( function(){ _fnInitialise( settings ); }, 200 );
  4062. return;
  4063. }
  4064. /* Show the display HTML options */
  4065. _fnAddOptionsHtml( settings );
  4066. /* Build and draw the header / footer for the table */
  4067. _fnBuildHead( settings );
  4068. _fnDrawHead( settings, settings.aoHeader );
  4069. _fnDrawHead( settings, settings.aoFooter );
  4070. /* Okay to show that something is going on now */
  4071. _fnProcessingDisplay( settings, true );
  4072. /* Calculate sizes for columns */
  4073. if ( features.bAutoWidth ) {
  4074. _fnCalculateColumnWidths( settings );
  4075. }
  4076. for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
  4077. column = columns[i];
  4078. if ( column.sWidth ) {
  4079. column.nTh.style.width = _fnStringToCss( column.sWidth );
  4080. }
  4081. }
  4082. _fnCallbackFire( settings, null, 'preInit', [settings] );
  4083. // If there is default sorting required - let's do it. The sort function
  4084. // will do the drawing for us. Otherwise we draw the table regardless of the
  4085. // Ajax source - this allows the table to look initialised for Ajax sourcing
  4086. // data (show 'loading' message possibly)
  4087. _fnReDraw( settings );
  4088. // Server-side processing init complete is done by _fnAjaxUpdateDraw
  4089. var dataSrc = _fnDataSource( settings );
  4090. if ( dataSrc != 'ssp' || deferLoading ) {
  4091. // if there is an ajax source load the data
  4092. if ( dataSrc == 'ajax' ) {
  4093. _fnBuildAjax( settings, [], function(json) {
  4094. var aData = _fnAjaxDataSrc( settings, json );
  4095. // Got the data - add it to the table
  4096. for ( i=0 ; i<aData.length ; i++ ) {
  4097. _fnAddData( settings, aData[i] );
  4098. }
  4099. // Reset the init display for cookie saving. We've already done
  4100. // a filter, and therefore cleared it before. So we need to make
  4101. // it appear 'fresh'
  4102. settings.iInitDisplayStart = iAjaxStart;
  4103. _fnReDraw( settings );
  4104. _fnProcessingDisplay( settings, false );
  4105. _fnInitComplete( settings, json );
  4106. }, settings );
  4107. }
  4108. else {
  4109. _fnProcessingDisplay( settings, false );
  4110. _fnInitComplete( settings );
  4111. }
  4112. }
  4113. }
  4114. /**
  4115. * Draw the table for the first time, adding all required features
  4116. * @param {object} oSettings dataTables settings object
  4117. * @param {object} [json] JSON from the server that completed the table, if using Ajax source
  4118. * with client-side processing (optional)
  4119. * @memberof DataTable#oApi
  4120. */
  4121. function _fnInitComplete ( settings, json )
  4122. {
  4123. settings._bInitComplete = true;
  4124. // When data was added after the initialisation (data or Ajax) we need to
  4125. // calculate the column sizing
  4126. if ( json || settings.oInit.aaData ) {
  4127. _fnAdjustColumnSizing( settings );
  4128. }
  4129. _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
  4130. _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
  4131. }
  4132. function _fnLengthChange ( settings, val )
  4133. {
  4134. var len = parseInt( val, 10 );
  4135. settings._iDisplayLength = len;
  4136. _fnLengthOverflow( settings );
  4137. // Fire length change event
  4138. _fnCallbackFire( settings, null, 'length', [settings, len] );
  4139. }
  4140. /**
  4141. * Generate the node required for user display length changing
  4142. * @param {object} settings dataTables settings object
  4143. * @returns {node} Display length feature node
  4144. * @memberof DataTable#oApi
  4145. */
  4146. function _fnFeatureHtmlLength ( settings )
  4147. {
  4148. var
  4149. classes = settings.oClasses,
  4150. tableId = settings.sTableId,
  4151. menu = settings.aLengthMenu,
  4152. d2 = $.isArray( menu[0] ),
  4153. lengths = d2 ? menu[0] : menu,
  4154. language = d2 ? menu[1] : menu;
  4155. var select = $('<select/>', {
  4156. 'name': tableId+'_length',
  4157. 'aria-controls': tableId,
  4158. 'class': classes.sLengthSelect
  4159. } );
  4160. for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
  4161. select[0][ i ] = new Option(
  4162. typeof language[i] === 'number' ?
  4163. settings.fnFormatNumber( language[i] ) :
  4164. language[i],
  4165. lengths[i]
  4166. );
  4167. }
  4168. var div = $('<div><label/></div>').addClass( classes.sLength );
  4169. if ( ! settings.aanFeatures.l ) {
  4170. div[0].id = tableId+'_length';
  4171. }
  4172. div.children().append(
  4173. settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
  4174. );
  4175. // Can't use `select` variable as user might provide their own and the
  4176. // reference is broken by the use of outerHTML
  4177. $('select', div)
  4178. .val( settings._iDisplayLength )
  4179. .on( 'change.DT', function(e) {
  4180. _fnLengthChange( settings, $(this).val() );
  4181. _fnDraw( settings );
  4182. } );
  4183. // Update node value whenever anything changes the table's length
  4184. $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
  4185. if ( settings === s ) {
  4186. $('select', div).val( len );
  4187. }
  4188. } );
  4189. return div[0];
  4190. }
  4191. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4192. * Note that most of the paging logic is done in
  4193. * DataTable.ext.pager
  4194. */
  4195. /**
  4196. * Generate the node required for default pagination
  4197. * @param {object} oSettings dataTables settings object
  4198. * @returns {node} Pagination feature node
  4199. * @memberof DataTable#oApi
  4200. */
  4201. function _fnFeatureHtmlPaginate ( settings )
  4202. {
  4203. var
  4204. type = settings.sPaginationType,
  4205. plugin = DataTable.ext.pager[ type ],
  4206. modern = typeof plugin === 'function',
  4207. redraw = function( settings ) {
  4208. _fnDraw( settings );
  4209. },
  4210. node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
  4211. features = settings.aanFeatures;
  4212. if ( ! modern ) {
  4213. plugin.fnInit( settings, node, redraw );
  4214. }
  4215. /* Add a draw callback for the pagination on first instance, to update the paging display */
  4216. if ( ! features.p )
  4217. {
  4218. node.id = settings.sTableId+'_paginate';
  4219. settings.aoDrawCallback.push( {
  4220. "fn": function( settings ) {
  4221. if ( modern ) {
  4222. var
  4223. start = settings._iDisplayStart,
  4224. len = settings._iDisplayLength,
  4225. visRecords = settings.fnRecordsDisplay(),
  4226. all = len === -1,
  4227. page = all ? 0 : Math.ceil( start / len ),
  4228. pages = all ? 1 : Math.ceil( visRecords / len ),
  4229. buttons = plugin(page, pages),
  4230. i, ien;
  4231. for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
  4232. _fnRenderer( settings, 'pageButton' )(
  4233. settings, features.p[i], i, buttons, page, pages
  4234. );
  4235. }
  4236. }
  4237. else {
  4238. plugin.fnUpdate( settings, redraw );
  4239. }
  4240. },
  4241. "sName": "pagination"
  4242. } );
  4243. }
  4244. return node;
  4245. }
  4246. /**
  4247. * Alter the display settings to change the page
  4248. * @param {object} settings DataTables settings object
  4249. * @param {string|int} action Paging action to take: "first", "previous",
  4250. * "next" or "last" or page number to jump to (integer)
  4251. * @param [bool] redraw Automatically draw the update or not
  4252. * @returns {bool} true page has changed, false - no change
  4253. * @memberof DataTable#oApi
  4254. */
  4255. function _fnPageChange ( settings, action, redraw )
  4256. {
  4257. var
  4258. start = settings._iDisplayStart,
  4259. len = settings._iDisplayLength,
  4260. records = settings.fnRecordsDisplay();
  4261. if ( records === 0 || len === -1 )
  4262. {
  4263. start = 0;
  4264. }
  4265. else if ( typeof action === "number" )
  4266. {
  4267. start = action * len;
  4268. if ( start > records )
  4269. {
  4270. start = 0;
  4271. }
  4272. }
  4273. else if ( action == "first" )
  4274. {
  4275. start = 0;
  4276. }
  4277. else if ( action == "previous" )
  4278. {
  4279. start = len >= 0 ?
  4280. start - len :
  4281. 0;
  4282. if ( start < 0 )
  4283. {
  4284. start = 0;
  4285. }
  4286. }
  4287. else if ( action == "next" )
  4288. {
  4289. if ( start + len < records )
  4290. {
  4291. start += len;
  4292. }
  4293. }
  4294. else if ( action == "last" )
  4295. {
  4296. start = Math.floor( (records-1) / len) * len;
  4297. }
  4298. else
  4299. {
  4300. _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
  4301. }
  4302. var changed = settings._iDisplayStart !== start;
  4303. settings._iDisplayStart = start;
  4304. if ( changed ) {
  4305. _fnCallbackFire( settings, null, 'page', [settings] );
  4306. if ( redraw ) {
  4307. _fnDraw( settings );
  4308. }
  4309. }
  4310. return changed;
  4311. }
  4312. /**
  4313. * Generate the node required for the processing node
  4314. * @param {object} settings dataTables settings object
  4315. * @returns {node} Processing element
  4316. * @memberof DataTable#oApi
  4317. */
  4318. function _fnFeatureHtmlProcessing ( settings )
  4319. {
  4320. return $('<div/>', {
  4321. 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
  4322. 'class': settings.oClasses.sProcessing
  4323. } )
  4324. .html( settings.oLanguage.sProcessing )
  4325. .insertBefore( settings.nTable )[0];
  4326. }
  4327. /**
  4328. * Display or hide the processing indicator
  4329. * @param {object} settings dataTables settings object
  4330. * @param {bool} show Show the processing indicator (true) or not (false)
  4331. * @memberof DataTable#oApi
  4332. */
  4333. function _fnProcessingDisplay ( settings, show )
  4334. {
  4335. if ( settings.oFeatures.bProcessing ) {
  4336. $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
  4337. }
  4338. _fnCallbackFire( settings, null, 'processing', [settings, show] );
  4339. }
  4340. /**
  4341. * Add any control elements for the table - specifically scrolling
  4342. * @param {object} settings dataTables settings object
  4343. * @returns {node} Node to add to the DOM
  4344. * @memberof DataTable#oApi
  4345. */
  4346. function _fnFeatureHtmlTable ( settings )
  4347. {
  4348. var table = $(settings.nTable);
  4349. // Add the ARIA grid role to the table
  4350. table.attr( 'role', 'grid' );
  4351. // Scrolling from here on in
  4352. var scroll = settings.oScroll;
  4353. if ( scroll.sX === '' && scroll.sY === '' ) {
  4354. return settings.nTable;
  4355. }
  4356. var scrollX = scroll.sX;
  4357. var scrollY = scroll.sY;
  4358. var classes = settings.oClasses;
  4359. var caption = table.children('caption');
  4360. var captionSide = caption.length ? caption[0]._captionSide : null;
  4361. var headerClone = $( table[0].cloneNode(false) );
  4362. var footerClone = $( table[0].cloneNode(false) );
  4363. var footer = table.children('tfoot');
  4364. var _div = '<div/>';
  4365. var size = function ( s ) {
  4366. return !s ? null : _fnStringToCss( s );
  4367. };
  4368. if ( ! footer.length ) {
  4369. footer = null;
  4370. }
  4371. /*
  4372. * The HTML structure that we want to generate in this function is:
  4373. * div - scroller
  4374. * div - scroll head
  4375. * div - scroll head inner
  4376. * table - scroll head table
  4377. * thead - thead
  4378. * div - scroll body
  4379. * table - table (master table)
  4380. * thead - thead clone for sizing
  4381. * tbody - tbody
  4382. * div - scroll foot
  4383. * div - scroll foot inner
  4384. * table - scroll foot table
  4385. * tfoot - tfoot
  4386. */
  4387. var scroller = $( _div, { 'class': classes.sScrollWrapper } )
  4388. .append(
  4389. $(_div, { 'class': classes.sScrollHead } )
  4390. .css( {
  4391. overflow: 'hidden',
  4392. position: 'relative',
  4393. border: 0,
  4394. width: scrollX ? size(scrollX) : '100%'
  4395. } )
  4396. .append(
  4397. $(_div, { 'class': classes.sScrollHeadInner } )
  4398. .css( {
  4399. 'box-sizing': 'content-box',
  4400. width: scroll.sXInner || '100%'
  4401. } )
  4402. .append(
  4403. headerClone
  4404. .removeAttr('id')
  4405. .css( 'margin-left', 0 )
  4406. .append( captionSide === 'top' ? caption : null )
  4407. .append(
  4408. table.children('thead')
  4409. )
  4410. )
  4411. )
  4412. )
  4413. .append(
  4414. $(_div, { 'class': classes.sScrollBody } )
  4415. .css( {
  4416. position: 'relative',
  4417. overflow: 'auto',
  4418. width: size( scrollX )
  4419. } )
  4420. .append( table )
  4421. );
  4422. if ( footer ) {
  4423. scroller.append(
  4424. $(_div, { 'class': classes.sScrollFoot } )
  4425. .css( {
  4426. overflow: 'hidden',
  4427. border: 0,
  4428. width: scrollX ? size(scrollX) : '100%'
  4429. } )
  4430. .append(
  4431. $(_div, { 'class': classes.sScrollFootInner } )
  4432. .append(
  4433. footerClone
  4434. .removeAttr('id')
  4435. .css( 'margin-left', 0 )
  4436. .append( captionSide === 'bottom' ? caption : null )
  4437. .append(
  4438. table.children('tfoot')
  4439. )
  4440. )
  4441. )
  4442. );
  4443. }
  4444. var children = scroller.children();
  4445. var scrollHead = children[0];
  4446. var scrollBody = children[1];
  4447. var scrollFoot = footer ? children[2] : null;
  4448. // When the body is scrolled, then we also want to scroll the headers
  4449. if ( scrollX ) {
  4450. $(scrollBody).on( 'scroll.DT', function (e) {
  4451. var scrollLeft = this.scrollLeft;
  4452. scrollHead.scrollLeft = scrollLeft;
  4453. if ( footer ) {
  4454. scrollFoot.scrollLeft = scrollLeft;
  4455. }
  4456. } );
  4457. }
  4458. $(scrollBody).css(
  4459. scrollY && scroll.bCollapse ? 'max-height' : 'height',
  4460. scrollY
  4461. );
  4462. settings.nScrollHead = scrollHead;
  4463. settings.nScrollBody = scrollBody;
  4464. settings.nScrollFoot = scrollFoot;
  4465. // On redraw - align columns
  4466. settings.aoDrawCallback.push( {
  4467. "fn": _fnScrollDraw,
  4468. "sName": "scrolling"
  4469. } );
  4470. return scroller[0];
  4471. }
  4472. /**
  4473. * Update the header, footer and body tables for resizing - i.e. column
  4474. * alignment.
  4475. *
  4476. * Welcome to the most horrible function DataTables. The process that this
  4477. * function follows is basically:
  4478. * 1. Re-create the table inside the scrolling div
  4479. * 2. Take live measurements from the DOM
  4480. * 3. Apply the measurements to align the columns
  4481. * 4. Clean up
  4482. *
  4483. * @param {object} settings dataTables settings object
  4484. * @memberof DataTable#oApi
  4485. */
  4486. function _fnScrollDraw ( settings )
  4487. {
  4488. // Given that this is such a monster function, a lot of variables are use
  4489. // to try and keep the minimised size as small as possible
  4490. var
  4491. scroll = settings.oScroll,
  4492. scrollX = scroll.sX,
  4493. scrollXInner = scroll.sXInner,
  4494. scrollY = scroll.sY,
  4495. barWidth = scroll.iBarWidth,
  4496. divHeader = $(settings.nScrollHead),
  4497. divHeaderStyle = divHeader[0].style,
  4498. divHeaderInner = divHeader.children('div'),
  4499. divHeaderInnerStyle = divHeaderInner[0].style,
  4500. divHeaderTable = divHeaderInner.children('table'),
  4501. divBodyEl = settings.nScrollBody,
  4502. divBody = $(divBodyEl),
  4503. divBodyStyle = divBodyEl.style,
  4504. divFooter = $(settings.nScrollFoot),
  4505. divFooterInner = divFooter.children('div'),
  4506. divFooterTable = divFooterInner.children('table'),
  4507. header = $(settings.nTHead),
  4508. table = $(settings.nTable),
  4509. tableEl = table[0],
  4510. tableStyle = tableEl.style,
  4511. footer = settings.nTFoot ? $(settings.nTFoot) : null,
  4512. browser = settings.oBrowser,
  4513. ie67 = browser.bScrollOversize,
  4514. dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
  4515. headerTrgEls, footerTrgEls,
  4516. headerSrcEls, footerSrcEls,
  4517. headerCopy, footerCopy,
  4518. headerWidths=[], footerWidths=[],
  4519. headerContent=[], footerContent=[],
  4520. idx, correction, sanityWidth,
  4521. zeroOut = function(nSizer) {
  4522. var style = nSizer.style;
  4523. style.paddingTop = "0";
  4524. style.paddingBottom = "0";
  4525. style.borderTopWidth = "0";
  4526. style.borderBottomWidth = "0";
  4527. style.height = 0;
  4528. };
  4529. // If the scrollbar visibility has changed from the last draw, we need to
  4530. // adjust the column sizes as the table width will have changed to account
  4531. // for the scrollbar
  4532. var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
  4533. if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
  4534. settings.scrollBarVis = scrollBarVis;
  4535. _fnAdjustColumnSizing( settings );
  4536. return; // adjust column sizing will call this function again
  4537. }
  4538. else {
  4539. settings.scrollBarVis = scrollBarVis;
  4540. }
  4541. /*
  4542. * 1. Re-create the table inside the scrolling div
  4543. */
  4544. // Remove the old minimised thead and tfoot elements in the inner table
  4545. table.children('thead, tfoot').remove();
  4546. if ( footer ) {
  4547. footerCopy = footer.clone().prependTo( table );
  4548. footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
  4549. footerSrcEls = footerCopy.find('tr');
  4550. }
  4551. // Clone the current header and footer elements and then place it into the inner table
  4552. headerCopy = header.clone().prependTo( table );
  4553. headerTrgEls = header.find('tr'); // original header is in its own table
  4554. headerSrcEls = headerCopy.find('tr');
  4555. headerCopy.find('th, td').removeAttr('tabindex');
  4556. /*
  4557. * 2. Take live measurements from the DOM - do not alter the DOM itself!
  4558. */
  4559. // Remove old sizing and apply the calculated column widths
  4560. // Get the unique column headers in the newly created (cloned) header. We want to apply the
  4561. // calculated sizes to this header
  4562. if ( ! scrollX )
  4563. {
  4564. divBodyStyle.width = '100%';
  4565. divHeader[0].style.width = '100%';
  4566. }
  4567. $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
  4568. idx = _fnVisibleToColumnIndex( settings, i );
  4569. el.style.width = settings.aoColumns[idx].sWidth;
  4570. } );
  4571. if ( footer ) {
  4572. _fnApplyToChildren( function(n) {
  4573. n.style.width = "";
  4574. }, footerSrcEls );
  4575. }
  4576. // Size the table as a whole
  4577. sanityWidth = table.outerWidth();
  4578. if ( scrollX === "" ) {
  4579. // No x scrolling
  4580. tableStyle.width = "100%";
  4581. // IE7 will make the width of the table when 100% include the scrollbar
  4582. // - which is shouldn't. When there is a scrollbar we need to take this
  4583. // into account.
  4584. if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
  4585. divBody.css('overflow-y') == "scroll")
  4586. ) {
  4587. tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
  4588. }
  4589. // Recalculate the sanity width
  4590. sanityWidth = table.outerWidth();
  4591. }
  4592. else if ( scrollXInner !== "" ) {
  4593. // legacy x scroll inner has been given - use it
  4594. tableStyle.width = _fnStringToCss(scrollXInner);
  4595. // Recalculate the sanity width
  4596. sanityWidth = table.outerWidth();
  4597. }
  4598. // Hidden header should have zero height, so remove padding and borders. Then
  4599. // set the width based on the real headers
  4600. // Apply all styles in one pass
  4601. _fnApplyToChildren( zeroOut, headerSrcEls );
  4602. // Read all widths in next pass
  4603. _fnApplyToChildren( function(nSizer) {
  4604. headerContent.push( nSizer.innerHTML );
  4605. headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
  4606. }, headerSrcEls );
  4607. // Apply all widths in final pass
  4608. _fnApplyToChildren( function(nToSize, i) {
  4609. // Only apply widths to the DataTables detected header cells - this
  4610. // prevents complex headers from having contradictory sizes applied
  4611. if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
  4612. nToSize.style.width = headerWidths[i];
  4613. }
  4614. }, headerTrgEls );
  4615. $(headerSrcEls).height(0);
  4616. /* Same again with the footer if we have one */
  4617. if ( footer )
  4618. {
  4619. _fnApplyToChildren( zeroOut, footerSrcEls );
  4620. _fnApplyToChildren( function(nSizer) {
  4621. footerContent.push( nSizer.innerHTML );
  4622. footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
  4623. }, footerSrcEls );
  4624. _fnApplyToChildren( function(nToSize, i) {
  4625. nToSize.style.width = footerWidths[i];
  4626. }, footerTrgEls );
  4627. $(footerSrcEls).height(0);
  4628. }
  4629. /*
  4630. * 3. Apply the measurements
  4631. */
  4632. // "Hide" the header and footer that we used for the sizing. We need to keep
  4633. // the content of the cell so that the width applied to the header and body
  4634. // both match, but we want to hide it completely. We want to also fix their
  4635. // width to what they currently are
  4636. _fnApplyToChildren( function(nSizer, i) {
  4637. nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
  4638. nSizer.childNodes[0].style.height = "0";
  4639. nSizer.childNodes[0].style.overflow = "hidden";
  4640. nSizer.style.width = headerWidths[i];
  4641. }, headerSrcEls );
  4642. if ( footer )
  4643. {
  4644. _fnApplyToChildren( function(nSizer, i) {
  4645. nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
  4646. nSizer.childNodes[0].style.height = "0";
  4647. nSizer.childNodes[0].style.overflow = "hidden";
  4648. nSizer.style.width = footerWidths[i];
  4649. }, footerSrcEls );
  4650. }
  4651. // Sanity check that the table is of a sensible width. If not then we are going to get
  4652. // misalignment - try to prevent this by not allowing the table to shrink below its min width
  4653. if ( table.outerWidth() < sanityWidth )
  4654. {
  4655. // The min width depends upon if we have a vertical scrollbar visible or not */
  4656. correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
  4657. divBody.css('overflow-y') == "scroll")) ?
  4658. sanityWidth+barWidth :
  4659. sanityWidth;
  4660. // IE6/7 are a law unto themselves...
  4661. if ( ie67 && (divBodyEl.scrollHeight >
  4662. divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
  4663. ) {
  4664. tableStyle.width = _fnStringToCss( correction-barWidth );
  4665. }
  4666. // And give the user a warning that we've stopped the table getting too small
  4667. if ( scrollX === "" || scrollXInner !== "" ) {
  4668. _fnLog( settings, 1, 'Possible column misalignment', 6 );
  4669. }
  4670. }
  4671. else
  4672. {
  4673. correction = '100%';
  4674. }
  4675. // Apply to the container elements
  4676. divBodyStyle.width = _fnStringToCss( correction );
  4677. divHeaderStyle.width = _fnStringToCss( correction );
  4678. if ( footer ) {
  4679. settings.nScrollFoot.style.width = _fnStringToCss( correction );
  4680. }
  4681. /*
  4682. * 4. Clean up
  4683. */
  4684. if ( ! scrollY ) {
  4685. /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
  4686. * the scrollbar height from the visible display, rather than adding it on. We need to
  4687. * set the height in order to sort this. Don't want to do it in any other browsers.
  4688. */
  4689. if ( ie67 ) {
  4690. divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
  4691. }
  4692. }
  4693. /* Finally set the width's of the header and footer tables */
  4694. var iOuterWidth = table.outerWidth();
  4695. divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
  4696. divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
  4697. // Figure out if there are scrollbar present - if so then we need a the header and footer to
  4698. // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
  4699. var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
  4700. var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
  4701. divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
  4702. if ( footer ) {
  4703. divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
  4704. divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
  4705. divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
  4706. }
  4707. // Correct DOM ordering for colgroup - comes before the thead
  4708. table.children('colgroup').insertBefore( table.children('thead') );
  4709. /* Adjust the position of the header in case we loose the y-scrollbar */
  4710. divBody.scroll();
  4711. // If sorting or filtering has occurred, jump the scrolling back to the top
  4712. // only if we aren't holding the position
  4713. if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
  4714. divBodyEl.scrollTop = 0;
  4715. }
  4716. }
  4717. /**
  4718. * Apply a given function to the display child nodes of an element array (typically
  4719. * TD children of TR rows
  4720. * @param {function} fn Method to apply to the objects
  4721. * @param array {nodes} an1 List of elements to look through for display children
  4722. * @param array {nodes} an2 Another list (identical structure to the first) - optional
  4723. * @memberof DataTable#oApi
  4724. */
  4725. function _fnApplyToChildren( fn, an1, an2 )
  4726. {
  4727. var index=0, i=0, iLen=an1.length;
  4728. var nNode1, nNode2;
  4729. while ( i < iLen ) {
  4730. nNode1 = an1[i].firstChild;
  4731. nNode2 = an2 ? an2[i].firstChild : null;
  4732. while ( nNode1 ) {
  4733. if ( nNode1.nodeType === 1 ) {
  4734. if ( an2 ) {
  4735. fn( nNode1, nNode2, index );
  4736. }
  4737. else {
  4738. fn( nNode1, index );
  4739. }
  4740. index++;
  4741. }
  4742. nNode1 = nNode1.nextSibling;
  4743. nNode2 = an2 ? nNode2.nextSibling : null;
  4744. }
  4745. i++;
  4746. }
  4747. }
  4748. var __re_html_remove = /<.*?>/g;
  4749. /**
  4750. * Calculate the width of columns for the table
  4751. * @param {object} oSettings dataTables settings object
  4752. * @memberof DataTable#oApi
  4753. */
  4754. function _fnCalculateColumnWidths ( oSettings )
  4755. {
  4756. var
  4757. table = oSettings.nTable,
  4758. columns = oSettings.aoColumns,
  4759. scroll = oSettings.oScroll,
  4760. scrollY = scroll.sY,
  4761. scrollX = scroll.sX,
  4762. scrollXInner = scroll.sXInner,
  4763. columnCount = columns.length,
  4764. visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
  4765. headerCells = $('th', oSettings.nTHead),
  4766. tableWidthAttr = table.getAttribute('width'), // from DOM element
  4767. tableContainer = table.parentNode,
  4768. userInputs = false,
  4769. i, column, columnIdx, width, outerWidth,
  4770. browser = oSettings.oBrowser,
  4771. ie67 = browser.bScrollOversize;
  4772. var styleWidth = table.style.width;
  4773. if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
  4774. tableWidthAttr = styleWidth;
  4775. }
  4776. /* Convert any user input sizes into pixel sizes */
  4777. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4778. column = columns[ visibleColumns[i] ];
  4779. if ( column.sWidth !== null ) {
  4780. column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
  4781. userInputs = true;
  4782. }
  4783. }
  4784. /* If the number of columns in the DOM equals the number that we have to
  4785. * process in DataTables, then we can use the offsets that are created by
  4786. * the web- browser. No custom sizes can be set in order for this to happen,
  4787. * nor scrolling used
  4788. */
  4789. if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
  4790. columnCount == _fnVisbleColumns( oSettings ) &&
  4791. columnCount == headerCells.length
  4792. ) {
  4793. for ( i=0 ; i<columnCount ; i++ ) {
  4794. var colIdx = _fnVisibleToColumnIndex( oSettings, i );
  4795. if ( colIdx !== null ) {
  4796. columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
  4797. }
  4798. }
  4799. }
  4800. else
  4801. {
  4802. // Otherwise construct a single row, worst case, table with the widest
  4803. // node in the data, assign any user defined widths, then insert it into
  4804. // the DOM and allow the browser to do all the hard work of calculating
  4805. // table widths
  4806. var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
  4807. .css( 'visibility', 'hidden' )
  4808. .removeAttr( 'id' );
  4809. // Clean up the table body
  4810. tmpTable.find('tbody tr').remove();
  4811. var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
  4812. // Clone the table header and footer - we can't use the header / footer
  4813. // from the cloned table, since if scrolling is active, the table's
  4814. // real header and footer are contained in different table tags
  4815. tmpTable.find('thead, tfoot').remove();
  4816. tmpTable
  4817. .append( $(oSettings.nTHead).clone() )
  4818. .append( $(oSettings.nTFoot).clone() );
  4819. // Remove any assigned widths from the footer (from scrolling)
  4820. tmpTable.find('tfoot th, tfoot td').css('width', '');
  4821. // Apply custom sizing to the cloned header
  4822. headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
  4823. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4824. column = columns[ visibleColumns[i] ];
  4825. headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
  4826. _fnStringToCss( column.sWidthOrig ) :
  4827. '';
  4828. // For scrollX we need to force the column width otherwise the
  4829. // browser will collapse it. If this width is smaller than the
  4830. // width the column requires, then it will have no effect
  4831. if ( column.sWidthOrig && scrollX ) {
  4832. $( headerCells[i] ).append( $('<div/>').css( {
  4833. width: column.sWidthOrig,
  4834. margin: 0,
  4835. padding: 0,
  4836. border: 0,
  4837. height: 1
  4838. } ) );
  4839. }
  4840. }
  4841. // Find the widest cell for each column and put it into the table
  4842. if ( oSettings.aoData.length ) {
  4843. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4844. columnIdx = visibleColumns[i];
  4845. column = columns[ columnIdx ];
  4846. $( _fnGetWidestNode( oSettings, columnIdx ) )
  4847. .clone( false )
  4848. .append( column.sContentPadding )
  4849. .appendTo( tr );
  4850. }
  4851. }
  4852. // Tidy the temporary table - remove name attributes so there aren't
  4853. // duplicated in the dom (radio elements for example)
  4854. $('[name]', tmpTable).removeAttr('name');
  4855. // Table has been built, attach to the document so we can work with it.
  4856. // A holding element is used, positioned at the top of the container
  4857. // with minimal height, so it has no effect on if the container scrolls
  4858. // or not. Otherwise it might trigger scrolling when it actually isn't
  4859. // needed
  4860. var holder = $('<div/>').css( scrollX || scrollY ?
  4861. {
  4862. position: 'absolute',
  4863. top: 0,
  4864. left: 0,
  4865. height: 1,
  4866. right: 0,
  4867. overflow: 'hidden'
  4868. } :
  4869. {}
  4870. )
  4871. .append( tmpTable )
  4872. .appendTo( tableContainer );
  4873. // When scrolling (X or Y) we want to set the width of the table as
  4874. // appropriate. However, when not scrolling leave the table width as it
  4875. // is. This results in slightly different, but I think correct behaviour
  4876. if ( scrollX && scrollXInner ) {
  4877. tmpTable.width( scrollXInner );
  4878. }
  4879. else if ( scrollX ) {
  4880. tmpTable.css( 'width', 'auto' );
  4881. tmpTable.removeAttr('width');
  4882. // If there is no width attribute or style, then allow the table to
  4883. // collapse
  4884. if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
  4885. tmpTable.width( tableContainer.clientWidth );
  4886. }
  4887. }
  4888. else if ( scrollY ) {
  4889. tmpTable.width( tableContainer.clientWidth );
  4890. }
  4891. else if ( tableWidthAttr ) {
  4892. tmpTable.width( tableWidthAttr );
  4893. }
  4894. // Get the width of each column in the constructed table - we need to
  4895. // know the inner width (so it can be assigned to the other table's
  4896. // cells) and the outer width so we can calculate the full width of the
  4897. // table. This is safe since DataTables requires a unique cell for each
  4898. // column, but if ever a header can span multiple columns, this will
  4899. // need to be modified.
  4900. var total = 0;
  4901. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4902. var cell = $(headerCells[i]);
  4903. var border = cell.outerWidth() - cell.width();
  4904. // Use getBounding... where possible (not IE8-) because it can give
  4905. // sub-pixel accuracy, which we then want to round up!
  4906. var bounding = browser.bBounding ?
  4907. Math.ceil( headerCells[i].getBoundingClientRect().width ) :
  4908. cell.outerWidth();
  4909. // Total is tracked to remove any sub-pixel errors as the outerWidth
  4910. // of the table might not equal the total given here (IE!).
  4911. total += bounding;
  4912. // Width for each column to use
  4913. columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
  4914. }
  4915. table.style.width = _fnStringToCss( total );
  4916. // Finished with the table - ditch it
  4917. holder.remove();
  4918. }
  4919. // If there is a width attr, we want to attach an event listener which
  4920. // allows the table sizing to automatically adjust when the window is
  4921. // resized. Use the width attr rather than CSS, since we can't know if the
  4922. // CSS is a relative value or absolute - DOM read is always px.
  4923. if ( tableWidthAttr ) {
  4924. table.style.width = _fnStringToCss( tableWidthAttr );
  4925. }
  4926. if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
  4927. var bindResize = function () {
  4928. $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
  4929. _fnAdjustColumnSizing( oSettings );
  4930. } ) );
  4931. };
  4932. // IE6/7 will crash if we bind a resize event handler on page load.
  4933. // To be removed in 1.11 which drops IE6/7 support
  4934. if ( ie67 ) {
  4935. setTimeout( bindResize, 1000 );
  4936. }
  4937. else {
  4938. bindResize();
  4939. }
  4940. oSettings._reszEvt = true;
  4941. }
  4942. }
  4943. /**
  4944. * Throttle the calls to a function. Arguments and context are maintained for
  4945. * the throttled function
  4946. * @param {function} fn Function to be called
  4947. * @param {int} [freq=200] call frequency in mS
  4948. * @returns {function} wrapped function
  4949. * @memberof DataTable#oApi
  4950. */
  4951. var _fnThrottle = DataTable.util.throttle;
  4952. /**
  4953. * Convert a CSS unit width to pixels (e.g. 2em)
  4954. * @param {string} width width to be converted
  4955. * @param {node} parent parent to get the with for (required for relative widths) - optional
  4956. * @returns {int} width in pixels
  4957. * @memberof DataTable#oApi
  4958. */
  4959. function _fnConvertToWidth ( width, parent )
  4960. {
  4961. if ( ! width ) {
  4962. return 0;
  4963. }
  4964. var n = $('<div/>')
  4965. .css( 'width', _fnStringToCss( width ) )
  4966. .appendTo( parent || document.body );
  4967. var val = n[0].offsetWidth;
  4968. n.remove();
  4969. return val;
  4970. }
  4971. /**
  4972. * Get the widest node
  4973. * @param {object} settings dataTables settings object
  4974. * @param {int} colIdx column of interest
  4975. * @returns {node} widest table node
  4976. * @memberof DataTable#oApi
  4977. */
  4978. function _fnGetWidestNode( settings, colIdx )
  4979. {
  4980. var idx = _fnGetMaxLenString( settings, colIdx );
  4981. if ( idx < 0 ) {
  4982. return null;
  4983. }
  4984. var data = settings.aoData[ idx ];
  4985. return ! data.nTr ? // Might not have been created when deferred rendering
  4986. $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
  4987. data.anCells[ colIdx ];
  4988. }
  4989. /**
  4990. * Get the maximum strlen for each data column
  4991. * @param {object} settings dataTables settings object
  4992. * @param {int} colIdx column of interest
  4993. * @returns {string} max string length for each column
  4994. * @memberof DataTable#oApi
  4995. */
  4996. function _fnGetMaxLenString( settings, colIdx )
  4997. {
  4998. var s, max=-1, maxIdx = -1;
  4999. for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  5000. s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
  5001. s = s.replace( __re_html_remove, '' );
  5002. s = s.replace( /&nbsp;/g, ' ' );
  5003. if ( s.length > max ) {
  5004. max = s.length;
  5005. maxIdx = i;
  5006. }
  5007. }
  5008. return maxIdx;
  5009. }
  5010. /**
  5011. * Append a CSS unit (only if required) to a string
  5012. * @param {string} value to css-ify
  5013. * @returns {string} value with css unit
  5014. * @memberof DataTable#oApi
  5015. */
  5016. function _fnStringToCss( s )
  5017. {
  5018. if ( s === null ) {
  5019. return '0px';
  5020. }
  5021. if ( typeof s == 'number' ) {
  5022. return s < 0 ?
  5023. '0px' :
  5024. s+'px';
  5025. }
  5026. // Check it has a unit character already
  5027. return s.match(/\d$/) ?
  5028. s+'px' :
  5029. s;
  5030. }
  5031. function _fnSortFlatten ( settings )
  5032. {
  5033. var
  5034. i, iLen, k, kLen,
  5035. aSort = [],
  5036. aiOrig = [],
  5037. aoColumns = settings.aoColumns,
  5038. aDataSort, iCol, sType, srcCol,
  5039. fixed = settings.aaSortingFixed,
  5040. fixedObj = $.isPlainObject( fixed ),
  5041. nestedSort = [],
  5042. add = function ( a ) {
  5043. if ( a.length && ! $.isArray( a[0] ) ) {
  5044. // 1D array
  5045. nestedSort.push( a );
  5046. }
  5047. else {
  5048. // 2D array
  5049. $.merge( nestedSort, a );
  5050. }
  5051. };
  5052. // Build the sort array, with pre-fix and post-fix options if they have been
  5053. // specified
  5054. if ( $.isArray( fixed ) ) {
  5055. add( fixed );
  5056. }
  5057. if ( fixedObj && fixed.pre ) {
  5058. add( fixed.pre );
  5059. }
  5060. add( settings.aaSorting );
  5061. if (fixedObj && fixed.post ) {
  5062. add( fixed.post );
  5063. }
  5064. for ( i=0 ; i<nestedSort.length ; i++ )
  5065. {
  5066. srcCol = nestedSort[i][0];
  5067. aDataSort = aoColumns[ srcCol ].aDataSort;
  5068. for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
  5069. {
  5070. iCol = aDataSort[k];
  5071. sType = aoColumns[ iCol ].sType || 'string';
  5072. if ( nestedSort[i]._idx === undefined ) {
  5073. nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
  5074. }
  5075. aSort.push( {
  5076. src: srcCol,
  5077. col: iCol,
  5078. dir: nestedSort[i][1],
  5079. index: nestedSort[i]._idx,
  5080. type: sType,
  5081. formatter: DataTable.ext.type.order[ sType+"-pre" ]
  5082. } );
  5083. }
  5084. }
  5085. return aSort;
  5086. }
  5087. /**
  5088. * Change the order of the table
  5089. * @param {object} oSettings dataTables settings object
  5090. * @memberof DataTable#oApi
  5091. * @todo This really needs split up!
  5092. */
  5093. function _fnSort ( oSettings )
  5094. {
  5095. var
  5096. i, ien, iLen, j, jLen, k, kLen,
  5097. sDataType, nTh,
  5098. aiOrig = [],
  5099. oExtSort = DataTable.ext.type.order,
  5100. aoData = oSettings.aoData,
  5101. aoColumns = oSettings.aoColumns,
  5102. aDataSort, data, iCol, sType, oSort,
  5103. formatters = 0,
  5104. sortCol,
  5105. displayMaster = oSettings.aiDisplayMaster,
  5106. aSort;
  5107. // Resolve any column types that are unknown due to addition or invalidation
  5108. // @todo Can this be moved into a 'data-ready' handler which is called when
  5109. // data is going to be used in the table?
  5110. _fnColumnTypes( oSettings );
  5111. aSort = _fnSortFlatten( oSettings );
  5112. for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
  5113. sortCol = aSort[i];
  5114. // Track if we can use the fast sort algorithm
  5115. if ( sortCol.formatter ) {
  5116. formatters++;
  5117. }
  5118. // Load the data needed for the sort, for each cell
  5119. _fnSortData( oSettings, sortCol.col );
  5120. }
  5121. /* No sorting required if server-side or no sorting array */
  5122. if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
  5123. {
  5124. // Create a value - key array of the current row positions such that we can use their
  5125. // current position during the sort, if values match, in order to perform stable sorting
  5126. for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
  5127. aiOrig[ displayMaster[i] ] = i;
  5128. }
  5129. /* Do the sort - here we want multi-column sorting based on a given data source (column)
  5130. * and sorting function (from oSort) in a certain direction. It's reasonably complex to
  5131. * follow on it's own, but this is what we want (example two column sorting):
  5132. * fnLocalSorting = function(a,b){
  5133. * var iTest;
  5134. * iTest = oSort['string-asc']('data11', 'data12');
  5135. * if (iTest !== 0)
  5136. * return iTest;
  5137. * iTest = oSort['numeric-desc']('data21', 'data22');
  5138. * if (iTest !== 0)
  5139. * return iTest;
  5140. * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
  5141. * }
  5142. * Basically we have a test for each sorting column, if the data in that column is equal,
  5143. * test the next column. If all columns match, then we use a numeric sort on the row
  5144. * positions in the original data array to provide a stable sort.
  5145. *
  5146. * Note - I know it seems excessive to have two sorting methods, but the first is around
  5147. * 15% faster, so the second is only maintained for backwards compatibility with sorting
  5148. * methods which do not have a pre-sort formatting function.
  5149. */
  5150. if ( formatters === aSort.length ) {
  5151. // All sort types have formatting functions
  5152. displayMaster.sort( function ( a, b ) {
  5153. var
  5154. x, y, k, test, sort,
  5155. len=aSort.length,
  5156. dataA = aoData[a]._aSortData,
  5157. dataB = aoData[b]._aSortData;
  5158. for ( k=0 ; k<len ; k++ ) {
  5159. sort = aSort[k];
  5160. x = dataA[ sort.col ];
  5161. y = dataB[ sort.col ];
  5162. test = x<y ? -1 : x>y ? 1 : 0;
  5163. if ( test !== 0 ) {
  5164. return sort.dir === 'asc' ? test : -test;
  5165. }
  5166. }
  5167. x = aiOrig[a];
  5168. y = aiOrig[b];
  5169. return x<y ? -1 : x>y ? 1 : 0;
  5170. } );
  5171. }
  5172. else {
  5173. // Depreciated - remove in 1.11 (providing a plug-in option)
  5174. // Not all sort types have formatting methods, so we have to call their sorting
  5175. // methods.
  5176. displayMaster.sort( function ( a, b ) {
  5177. var
  5178. x, y, k, l, test, sort, fn,
  5179. len=aSort.length,
  5180. dataA = aoData[a]._aSortData,
  5181. dataB = aoData[b]._aSortData;
  5182. for ( k=0 ; k<len ; k++ ) {
  5183. sort = aSort[k];
  5184. x = dataA[ sort.col ];
  5185. y = dataB[ sort.col ];
  5186. fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
  5187. test = fn( x, y );
  5188. if ( test !== 0 ) {
  5189. return test;
  5190. }
  5191. }
  5192. x = aiOrig[a];
  5193. y = aiOrig[b];
  5194. return x<y ? -1 : x>y ? 1 : 0;
  5195. } );
  5196. }
  5197. }
  5198. /* Tell the draw function that we have sorted the data */
  5199. oSettings.bSorted = true;
  5200. }
  5201. function _fnSortAria ( settings )
  5202. {
  5203. var label;
  5204. var nextSort;
  5205. var columns = settings.aoColumns;
  5206. var aSort = _fnSortFlatten( settings );
  5207. var oAria = settings.oLanguage.oAria;
  5208. // ARIA attributes - need to loop all columns, to update all (removing old
  5209. // attributes as needed)
  5210. for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
  5211. {
  5212. var col = columns[i];
  5213. var asSorting = col.asSorting;
  5214. var sTitle = col.sTitle.replace( /<.*?>/g, "" );
  5215. var th = col.nTh;
  5216. // IE7 is throwing an error when setting these properties with jQuery's
  5217. // attr() and removeAttr() methods...
  5218. th.removeAttribute('aria-sort');
  5219. /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
  5220. if ( col.bSortable ) {
  5221. if ( aSort.length > 0 && aSort[0].col == i ) {
  5222. th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
  5223. nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
  5224. }
  5225. else {
  5226. nextSort = asSorting[0];
  5227. }
  5228. label = sTitle + ( nextSort === "asc" ?
  5229. oAria.sSortAscending :
  5230. oAria.sSortDescending
  5231. );
  5232. }
  5233. else {
  5234. label = sTitle;
  5235. }
  5236. th.setAttribute('aria-label', label);
  5237. }
  5238. }
  5239. /**
  5240. * Function to run on user sort request
  5241. * @param {object} settings dataTables settings object
  5242. * @param {node} attachTo node to attach the handler to
  5243. * @param {int} colIdx column sorting index
  5244. * @param {boolean} [append=false] Append the requested sort to the existing
  5245. * sort if true (i.e. multi-column sort)
  5246. * @param {function} [callback] callback function
  5247. * @memberof DataTable#oApi
  5248. */
  5249. function _fnSortListener ( settings, colIdx, append, callback )
  5250. {
  5251. var col = settings.aoColumns[ colIdx ];
  5252. var sorting = settings.aaSorting;
  5253. var asSorting = col.asSorting;
  5254. var nextSortIdx;
  5255. var next = function ( a, overflow ) {
  5256. var idx = a._idx;
  5257. if ( idx === undefined ) {
  5258. idx = $.inArray( a[1], asSorting );
  5259. }
  5260. return idx+1 < asSorting.length ?
  5261. idx+1 :
  5262. overflow ?
  5263. null :
  5264. 0;
  5265. };
  5266. // Convert to 2D array if needed
  5267. if ( typeof sorting[0] === 'number' ) {
  5268. sorting = settings.aaSorting = [ sorting ];
  5269. }
  5270. // If appending the sort then we are multi-column sorting
  5271. if ( append && settings.oFeatures.bSortMulti ) {
  5272. // Are we already doing some kind of sort on this column?
  5273. var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
  5274. if ( sortIdx !== -1 ) {
  5275. // Yes, modify the sort
  5276. nextSortIdx = next( sorting[sortIdx], true );
  5277. if ( nextSortIdx === null && sorting.length === 1 ) {
  5278. nextSortIdx = 0; // can't remove sorting completely
  5279. }
  5280. if ( nextSortIdx === null ) {
  5281. sorting.splice( sortIdx, 1 );
  5282. }
  5283. else {
  5284. sorting[sortIdx][1] = asSorting[ nextSortIdx ];
  5285. sorting[sortIdx]._idx = nextSortIdx;
  5286. }
  5287. }
  5288. else {
  5289. // No sort on this column yet
  5290. sorting.push( [ colIdx, asSorting[0], 0 ] );
  5291. sorting[sorting.length-1]._idx = 0;
  5292. }
  5293. }
  5294. else if ( sorting.length && sorting[0][0] == colIdx ) {
  5295. // Single column - already sorting on this column, modify the sort
  5296. nextSortIdx = next( sorting[0] );
  5297. sorting.length = 1;
  5298. sorting[0][1] = asSorting[ nextSortIdx ];
  5299. sorting[0]._idx = nextSortIdx;
  5300. }
  5301. else {
  5302. // Single column - sort only on this column
  5303. sorting.length = 0;
  5304. sorting.push( [ colIdx, asSorting[0] ] );
  5305. sorting[0]._idx = 0;
  5306. }
  5307. // Run the sort by calling a full redraw
  5308. _fnReDraw( settings );
  5309. // callback used for async user interaction
  5310. if ( typeof callback == 'function' ) {
  5311. callback( settings );
  5312. }
  5313. }
  5314. /**
  5315. * Attach a sort handler (click) to a node
  5316. * @param {object} settings dataTables settings object
  5317. * @param {node} attachTo node to attach the handler to
  5318. * @param {int} colIdx column sorting index
  5319. * @param {function} [callback] callback function
  5320. * @memberof DataTable#oApi
  5321. */
  5322. function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
  5323. {
  5324. var col = settings.aoColumns[ colIdx ];
  5325. _fnBindAction( attachTo, {}, function (e) {
  5326. /* If the column is not sortable - don't to anything */
  5327. if ( col.bSortable === false ) {
  5328. return;
  5329. }
  5330. // If processing is enabled use a timeout to allow the processing
  5331. // display to be shown - otherwise to it synchronously
  5332. if ( settings.oFeatures.bProcessing ) {
  5333. _fnProcessingDisplay( settings, true );
  5334. setTimeout( function() {
  5335. _fnSortListener( settings, colIdx, e.shiftKey, callback );
  5336. // In server-side processing, the draw callback will remove the
  5337. // processing display
  5338. if ( _fnDataSource( settings ) !== 'ssp' ) {
  5339. _fnProcessingDisplay( settings, false );
  5340. }
  5341. }, 0 );
  5342. }
  5343. else {
  5344. _fnSortListener( settings, colIdx, e.shiftKey, callback );
  5345. }
  5346. } );
  5347. }
  5348. /**
  5349. * Set the sorting classes on table's body, Note: it is safe to call this function
  5350. * when bSort and bSortClasses are false
  5351. * @param {object} oSettings dataTables settings object
  5352. * @memberof DataTable#oApi
  5353. */
  5354. function _fnSortingClasses( settings )
  5355. {
  5356. var oldSort = settings.aLastSort;
  5357. var sortClass = settings.oClasses.sSortColumn;
  5358. var sort = _fnSortFlatten( settings );
  5359. var features = settings.oFeatures;
  5360. var i, ien, colIdx;
  5361. if ( features.bSort && features.bSortClasses ) {
  5362. // Remove old sorting classes
  5363. for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
  5364. colIdx = oldSort[i].src;
  5365. // Remove column sorting
  5366. $( _pluck( settings.aoData, 'anCells', colIdx ) )
  5367. .removeClass( sortClass + (i<2 ? i+1 : 3) );
  5368. }
  5369. // Add new column sorting
  5370. for ( i=0, ien=sort.length ; i<ien ; i++ ) {
  5371. colIdx = sort[i].src;
  5372. $( _pluck( settings.aoData, 'anCells', colIdx ) )
  5373. .addClass( sortClass + (i<2 ? i+1 : 3) );
  5374. }
  5375. }
  5376. settings.aLastSort = sort;
  5377. }
  5378. // Get the data to sort a column, be it from cache, fresh (populating the
  5379. // cache), or from a sort formatter
  5380. function _fnSortData( settings, idx )
  5381. {
  5382. // Custom sorting function - provided by the sort data type
  5383. var column = settings.aoColumns[ idx ];
  5384. var customSort = DataTable.ext.order[ column.sSortDataType ];
  5385. var customData;
  5386. if ( customSort ) {
  5387. customData = customSort.call( settings.oInstance, settings, idx,
  5388. _fnColumnIndexToVisible( settings, idx )
  5389. );
  5390. }
  5391. // Use / populate cache
  5392. var row, cellData;
  5393. var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
  5394. for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  5395. row = settings.aoData[i];
  5396. if ( ! row._aSortData ) {
  5397. row._aSortData = [];
  5398. }
  5399. if ( ! row._aSortData[idx] || customSort ) {
  5400. cellData = customSort ?
  5401. customData[i] : // If there was a custom sort function, use data from there
  5402. _fnGetCellData( settings, i, idx, 'sort' );
  5403. row._aSortData[ idx ] = formatter ?
  5404. formatter( cellData ) :
  5405. cellData;
  5406. }
  5407. }
  5408. }
  5409. /**
  5410. * Save the state of a table
  5411. * @param {object} oSettings dataTables settings object
  5412. * @memberof DataTable#oApi
  5413. */
  5414. function _fnSaveState ( settings )
  5415. {
  5416. if ( !settings.oFeatures.bStateSave || settings.bDestroying )
  5417. {
  5418. return;
  5419. }
  5420. /* Store the interesting variables */
  5421. var state = {
  5422. time: +new Date(),
  5423. start: settings._iDisplayStart,
  5424. length: settings._iDisplayLength,
  5425. order: $.extend( true, [], settings.aaSorting ),
  5426. search: _fnSearchToCamel( settings.oPreviousSearch ),
  5427. columns: $.map( settings.aoColumns, function ( col, i ) {
  5428. return {
  5429. visible: col.bVisible,
  5430. search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
  5431. };
  5432. } )
  5433. };
  5434. _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
  5435. settings.oSavedState = state;
  5436. settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
  5437. }
  5438. /**
  5439. * Attempt to load a saved table state
  5440. * @param {object} oSettings dataTables settings object
  5441. * @param {object} oInit DataTables init object so we can override settings
  5442. * @param {function} callback Callback to execute when the state has been loaded
  5443. * @memberof DataTable#oApi
  5444. */
  5445. function _fnLoadState ( settings, oInit, callback )
  5446. {
  5447. var i, ien;
  5448. var columns = settings.aoColumns;
  5449. var loaded = function ( s ) {
  5450. if ( ! s || ! s.time ) {
  5451. callback();
  5452. return;
  5453. }
  5454. // Allow custom and plug-in manipulation functions to alter the saved data set and
  5455. // cancelling of loading by returning false
  5456. var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
  5457. if ( $.inArray( false, abStateLoad ) !== -1 ) {
  5458. callback();
  5459. return;
  5460. }
  5461. // Reject old data
  5462. var duration = settings.iStateDuration;
  5463. if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
  5464. callback();
  5465. return;
  5466. }
  5467. // Number of columns have changed - all bets are off, no restore of settings
  5468. if ( s.columns && columns.length !== s.columns.length ) {
  5469. callback();
  5470. return;
  5471. }
  5472. // Store the saved state so it might be accessed at any time
  5473. settings.oLoadedState = $.extend( true, {}, s );
  5474. // Restore key features - todo - for 1.11 this needs to be done by
  5475. // subscribed events
  5476. if ( s.start !== undefined ) {
  5477. settings._iDisplayStart = s.start;
  5478. settings.iInitDisplayStart = s.start;
  5479. }
  5480. if ( s.length !== undefined ) {
  5481. settings._iDisplayLength = s.length;
  5482. }
  5483. // Order
  5484. if ( s.order !== undefined ) {
  5485. settings.aaSorting = [];
  5486. $.each( s.order, function ( i, col ) {
  5487. settings.aaSorting.push( col[0] >= columns.length ?
  5488. [ 0, col[1] ] :
  5489. col
  5490. );
  5491. } );
  5492. }
  5493. // Search
  5494. if ( s.search !== undefined ) {
  5495. $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
  5496. }
  5497. // Columns
  5498. //
  5499. if ( s.columns ) {
  5500. for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
  5501. var col = s.columns[i];
  5502. // Visibility
  5503. if ( col.visible !== undefined ) {
  5504. columns[i].bVisible = col.visible;
  5505. }
  5506. // Search
  5507. if ( col.search !== undefined ) {
  5508. $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
  5509. }
  5510. }
  5511. }
  5512. _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
  5513. callback();
  5514. }
  5515. if ( ! settings.oFeatures.bStateSave ) {
  5516. callback();
  5517. return;
  5518. }
  5519. var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
  5520. if ( state !== undefined ) {
  5521. loaded( state );
  5522. }
  5523. // otherwise, wait for the loaded callback to be executed
  5524. }
  5525. /**
  5526. * Return the settings object for a particular table
  5527. * @param {node} table table we are using as a dataTable
  5528. * @returns {object} Settings object - or null if not found
  5529. * @memberof DataTable#oApi
  5530. */
  5531. function _fnSettingsFromNode ( table )
  5532. {
  5533. var settings = DataTable.settings;
  5534. var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
  5535. return idx !== -1 ?
  5536. settings[ idx ] :
  5537. null;
  5538. }
  5539. /**
  5540. * Log an error message
  5541. * @param {object} settings dataTables settings object
  5542. * @param {int} level log error messages, or display them to the user
  5543. * @param {string} msg error message
  5544. * @param {int} tn Technical note id to get more information about the error.
  5545. * @memberof DataTable#oApi
  5546. */
  5547. function _fnLog( settings, level, msg, tn )
  5548. {
  5549. msg = 'DataTables warning: '+
  5550. (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
  5551. if ( tn ) {
  5552. msg += '. For more information about this error, please see '+
  5553. 'http://datatables.net/tn/'+tn;
  5554. }
  5555. if ( ! level ) {
  5556. // Backwards compatibility pre 1.10
  5557. var ext = DataTable.ext;
  5558. var type = ext.sErrMode || ext.errMode;
  5559. if ( settings ) {
  5560. _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
  5561. }
  5562. if ( type == 'alert' ) {
  5563. alert( msg );
  5564. }
  5565. else if ( type == 'throw' ) {
  5566. throw new Error(msg);
  5567. }
  5568. else if ( typeof type == 'function' ) {
  5569. type( settings, tn, msg );
  5570. }
  5571. }
  5572. else if ( window.console && console.log ) {
  5573. console.log( msg );
  5574. }
  5575. }
  5576. /**
  5577. * See if a property is defined on one object, if so assign it to the other object
  5578. * @param {object} ret target object
  5579. * @param {object} src source object
  5580. * @param {string} name property
  5581. * @param {string} [mappedName] name to map too - optional, name used if not given
  5582. * @memberof DataTable#oApi
  5583. */
  5584. function _fnMap( ret, src, name, mappedName )
  5585. {
  5586. if ( $.isArray( name ) ) {
  5587. $.each( name, function (i, val) {
  5588. if ( $.isArray( val ) ) {
  5589. _fnMap( ret, src, val[0], val[1] );
  5590. }
  5591. else {
  5592. _fnMap( ret, src, val );
  5593. }
  5594. } );
  5595. return;
  5596. }
  5597. if ( mappedName === undefined ) {
  5598. mappedName = name;
  5599. }
  5600. if ( src[name] !== undefined ) {
  5601. ret[mappedName] = src[name];
  5602. }
  5603. }
  5604. /**
  5605. * Extend objects - very similar to jQuery.extend, but deep copy objects, and
  5606. * shallow copy arrays. The reason we need to do this, is that we don't want to
  5607. * deep copy array init values (such as aaSorting) since the dev wouldn't be
  5608. * able to override them, but we do want to deep copy arrays.
  5609. * @param {object} out Object to extend
  5610. * @param {object} extender Object from which the properties will be applied to
  5611. * out
  5612. * @param {boolean} breakRefs If true, then arrays will be sliced to take an
  5613. * independent copy with the exception of the `data` or `aaData` parameters
  5614. * if they are present. This is so you can pass in a collection to
  5615. * DataTables and have that used as your data source without breaking the
  5616. * references
  5617. * @returns {object} out Reference, just for convenience - out === the return.
  5618. * @memberof DataTable#oApi
  5619. * @todo This doesn't take account of arrays inside the deep copied objects.
  5620. */
  5621. function _fnExtend( out, extender, breakRefs )
  5622. {
  5623. var val;
  5624. for ( var prop in extender ) {
  5625. if ( extender.hasOwnProperty(prop) ) {
  5626. val = extender[prop];
  5627. if ( $.isPlainObject( val ) ) {
  5628. if ( ! $.isPlainObject( out[prop] ) ) {
  5629. out[prop] = {};
  5630. }
  5631. $.extend( true, out[prop], val );
  5632. }
  5633. else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
  5634. out[prop] = val.slice();
  5635. }
  5636. else {
  5637. out[prop] = val;
  5638. }
  5639. }
  5640. }
  5641. return out;
  5642. }
  5643. /**
  5644. * Bind an event handers to allow a click or return key to activate the callback.
  5645. * This is good for accessibility since a return on the keyboard will have the
  5646. * same effect as a click, if the element has focus.
  5647. * @param {element} n Element to bind the action to
  5648. * @param {object} oData Data object to pass to the triggered function
  5649. * @param {function} fn Callback function for when the event is triggered
  5650. * @memberof DataTable#oApi
  5651. */
  5652. function _fnBindAction( n, oData, fn )
  5653. {
  5654. $(n)
  5655. .on( 'click.DT', oData, function (e) {
  5656. $(n).blur(); // Remove focus outline for mouse users
  5657. fn(e);
  5658. } )
  5659. .on( 'keypress.DT', oData, function (e){
  5660. if ( e.which === 13 ) {
  5661. e.preventDefault();
  5662. fn(e);
  5663. }
  5664. } )
  5665. .on( 'selectstart.DT', function () {
  5666. /* Take the brutal approach to cancelling text selection */
  5667. return false;
  5668. } );
  5669. }
  5670. /**
  5671. * Register a callback function. Easily allows a callback function to be added to
  5672. * an array store of callback functions that can then all be called together.
  5673. * @param {object} oSettings dataTables settings object
  5674. * @param {string} sStore Name of the array storage for the callbacks in oSettings
  5675. * @param {function} fn Function to be called back
  5676. * @param {string} sName Identifying name for the callback (i.e. a label)
  5677. * @memberof DataTable#oApi
  5678. */
  5679. function _fnCallbackReg( oSettings, sStore, fn, sName )
  5680. {
  5681. if ( fn )
  5682. {
  5683. oSettings[sStore].push( {
  5684. "fn": fn,
  5685. "sName": sName
  5686. } );
  5687. }
  5688. }
  5689. /**
  5690. * Fire callback functions and trigger events. Note that the loop over the
  5691. * callback array store is done backwards! Further note that you do not want to
  5692. * fire off triggers in time sensitive applications (for example cell creation)
  5693. * as its slow.
  5694. * @param {object} settings dataTables settings object
  5695. * @param {string} callbackArr Name of the array storage for the callbacks in
  5696. * oSettings
  5697. * @param {string} eventName Name of the jQuery custom event to trigger. If
  5698. * null no trigger is fired
  5699. * @param {array} args Array of arguments to pass to the callback function /
  5700. * trigger
  5701. * @memberof DataTable#oApi
  5702. */
  5703. function _fnCallbackFire( settings, callbackArr, eventName, args )
  5704. {
  5705. var ret = [];
  5706. if ( callbackArr ) {
  5707. ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
  5708. return val.fn.apply( settings.oInstance, args );
  5709. } );
  5710. }
  5711. if ( eventName !== null ) {
  5712. var e = $.Event( eventName+'.dt' );
  5713. $(settings.nTable).trigger( e, args );
  5714. ret.push( e.result );
  5715. }
  5716. return ret;
  5717. }
  5718. function _fnLengthOverflow ( settings )
  5719. {
  5720. var
  5721. start = settings._iDisplayStart,
  5722. end = settings.fnDisplayEnd(),
  5723. len = settings._iDisplayLength;
  5724. /* If we have space to show extra rows (backing up from the end point - then do so */
  5725. if ( start >= end )
  5726. {
  5727. start = end - len;
  5728. }
  5729. // Keep the start record on the current page
  5730. start -= (start % len);
  5731. if ( len === -1 || start < 0 )
  5732. {
  5733. start = 0;
  5734. }
  5735. settings._iDisplayStart = start;
  5736. }
  5737. function _fnRenderer( settings, type )
  5738. {
  5739. var renderer = settings.renderer;
  5740. var host = DataTable.ext.renderer[type];
  5741. if ( $.isPlainObject( renderer ) && renderer[type] ) {
  5742. // Specific renderer for this type. If available use it, otherwise use
  5743. // the default.
  5744. return host[renderer[type]] || host._;
  5745. }
  5746. else if ( typeof renderer === 'string' ) {
  5747. // Common renderer - if there is one available for this type use it,
  5748. // otherwise use the default
  5749. return host[renderer] || host._;
  5750. }
  5751. // Use the default
  5752. return host._;
  5753. }
  5754. /**
  5755. * Detect the data source being used for the table. Used to simplify the code
  5756. * a little (ajax) and to make it compress a little smaller.
  5757. *
  5758. * @param {object} settings dataTables settings object
  5759. * @returns {string} Data source
  5760. * @memberof DataTable#oApi
  5761. */
  5762. function _fnDataSource ( settings )
  5763. {
  5764. if ( settings.oFeatures.bServerSide ) {
  5765. return 'ssp';
  5766. }
  5767. else if ( settings.ajax || settings.sAjaxSource ) {
  5768. return 'ajax';
  5769. }
  5770. return 'dom';
  5771. }
  5772. /**
  5773. * Computed structure of the DataTables API, defined by the options passed to
  5774. * `DataTable.Api.register()` when building the API.
  5775. *
  5776. * The structure is built in order to speed creation and extension of the Api
  5777. * objects since the extensions are effectively pre-parsed.
  5778. *
  5779. * The array is an array of objects with the following structure, where this
  5780. * base array represents the Api prototype base:
  5781. *
  5782. * [
  5783. * {
  5784. * name: 'data' -- string - Property name
  5785. * val: function () {}, -- function - Api method (or undefined if just an object
  5786. * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
  5787. * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
  5788. * },
  5789. * {
  5790. * name: 'row'
  5791. * val: {},
  5792. * methodExt: [ ... ],
  5793. * propExt: [
  5794. * {
  5795. * name: 'data'
  5796. * val: function () {},
  5797. * methodExt: [ ... ],
  5798. * propExt: [ ... ]
  5799. * },
  5800. * ...
  5801. * ]
  5802. * }
  5803. * ]
  5804. *
  5805. * @type {Array}
  5806. * @ignore
  5807. */
  5808. var __apiStruct = [];
  5809. /**
  5810. * `Array.prototype` reference.
  5811. *
  5812. * @type object
  5813. * @ignore
  5814. */
  5815. var __arrayProto = Array.prototype;
  5816. /**
  5817. * Abstraction for `context` parameter of the `Api` constructor to allow it to
  5818. * take several different forms for ease of use.
  5819. *
  5820. * Each of the input parameter types will be converted to a DataTables settings
  5821. * object where possible.
  5822. *
  5823. * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
  5824. * of:
  5825. *
  5826. * * `string` - jQuery selector. Any DataTables' matching the given selector
  5827. * with be found and used.
  5828. * * `node` - `TABLE` node which has already been formed into a DataTable.
  5829. * * `jQuery` - A jQuery object of `TABLE` nodes.
  5830. * * `object` - DataTables settings object
  5831. * * `DataTables.Api` - API instance
  5832. * @return {array|null} Matching DataTables settings objects. `null` or
  5833. * `undefined` is returned if no matching DataTable is found.
  5834. * @ignore
  5835. */
  5836. var _toSettings = function ( mixed )
  5837. {
  5838. var idx, jq;
  5839. var settings = DataTable.settings;
  5840. var tables = $.map( settings, function (el, i) {
  5841. return el.nTable;
  5842. } );
  5843. if ( ! mixed ) {
  5844. return [];
  5845. }
  5846. else if ( mixed.nTable && mixed.oApi ) {
  5847. // DataTables settings object
  5848. return [ mixed ];
  5849. }
  5850. else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
  5851. // Table node
  5852. idx = $.inArray( mixed, tables );
  5853. return idx !== -1 ? [ settings[idx] ] : null;
  5854. }
  5855. else if ( mixed && typeof mixed.settings === 'function' ) {
  5856. return mixed.settings().toArray();
  5857. }
  5858. else if ( typeof mixed === 'string' ) {
  5859. // jQuery selector
  5860. jq = $(mixed);
  5861. }
  5862. else if ( mixed instanceof $ ) {
  5863. // jQuery object (also DataTables instance)
  5864. jq = mixed;
  5865. }
  5866. if ( jq ) {
  5867. return jq.map( function(i) {
  5868. idx = $.inArray( this, tables );
  5869. return idx !== -1 ? settings[idx] : null;
  5870. } ).toArray();
  5871. }
  5872. };
  5873. /**
  5874. * DataTables API class - used to control and interface with one or more
  5875. * DataTables enhanced tables.
  5876. *
  5877. * The API class is heavily based on jQuery, presenting a chainable interface
  5878. * that you can use to interact with tables. Each instance of the API class has
  5879. * a "context" - i.e. the tables that it will operate on. This could be a single
  5880. * table, all tables on a page or a sub-set thereof.
  5881. *
  5882. * Additionally the API is designed to allow you to easily work with the data in
  5883. * the tables, retrieving and manipulating it as required. This is done by
  5884. * presenting the API class as an array like interface. The contents of the
  5885. * array depend upon the actions requested by each method (for example
  5886. * `rows().nodes()` will return an array of nodes, while `rows().data()` will
  5887. * return an array of objects or arrays depending upon your table's
  5888. * configuration). The API object has a number of array like methods (`push`,
  5889. * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
  5890. * `unique` etc) to assist your working with the data held in a table.
  5891. *
  5892. * Most methods (those which return an Api instance) are chainable, which means
  5893. * the return from a method call also has all of the methods available that the
  5894. * top level object had. For example, these two calls are equivalent:
  5895. *
  5896. * // Not chained
  5897. * api.row.add( {...} );
  5898. * api.draw();
  5899. *
  5900. * // Chained
  5901. * api.row.add( {...} ).draw();
  5902. *
  5903. * @class DataTable.Api
  5904. * @param {array|object|string|jQuery} context DataTable identifier. This is
  5905. * used to define which DataTables enhanced tables this API will operate on.
  5906. * Can be one of:
  5907. *
  5908. * * `string` - jQuery selector. Any DataTables' matching the given selector
  5909. * with be found and used.
  5910. * * `node` - `TABLE` node which has already been formed into a DataTable.
  5911. * * `jQuery` - A jQuery object of `TABLE` nodes.
  5912. * * `object` - DataTables settings object
  5913. * @param {array} [data] Data to initialise the Api instance with.
  5914. *
  5915. * @example
  5916. * // Direct initialisation during DataTables construction
  5917. * var api = $('#example').DataTable();
  5918. *
  5919. * @example
  5920. * // Initialisation using a DataTables jQuery object
  5921. * var api = $('#example').dataTable().api();
  5922. *
  5923. * @example
  5924. * // Initialisation as a constructor
  5925. * var api = new $.fn.DataTable.Api( 'table.dataTable' );
  5926. */
  5927. _Api = function ( context, data )
  5928. {
  5929. if ( ! (this instanceof _Api) ) {
  5930. return new _Api( context, data );
  5931. }
  5932. var settings = [];
  5933. var ctxSettings = function ( o ) {
  5934. var a = _toSettings( o );
  5935. if ( a ) {
  5936. settings = settings.concat( a );
  5937. }
  5938. };
  5939. if ( $.isArray( context ) ) {
  5940. for ( var i=0, ien=context.length ; i<ien ; i++ ) {
  5941. ctxSettings( context[i] );
  5942. }
  5943. }
  5944. else {
  5945. ctxSettings( context );
  5946. }
  5947. // Remove duplicates
  5948. this.context = _unique( settings );
  5949. // Initial data
  5950. if ( data ) {
  5951. $.merge( this, data );
  5952. }
  5953. // selector
  5954. this.selector = {
  5955. rows: null,
  5956. cols: null,
  5957. opts: null
  5958. };
  5959. _Api.extend( this, this, __apiStruct );
  5960. };
  5961. DataTable.Api = _Api;
  5962. // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
  5963. // isPlainObject.
  5964. $.extend( _Api.prototype, {
  5965. any: function ()
  5966. {
  5967. return this.count() !== 0;
  5968. },
  5969. concat: __arrayProto.concat,
  5970. context: [], // array of table settings objects
  5971. count: function ()
  5972. {
  5973. return this.flatten().length;
  5974. },
  5975. each: function ( fn )
  5976. {
  5977. for ( var i=0, ien=this.length ; i<ien; i++ ) {
  5978. fn.call( this, this[i], i, this );
  5979. }
  5980. return this;
  5981. },
  5982. eq: function ( idx )
  5983. {
  5984. var ctx = this.context;
  5985. return ctx.length > idx ?
  5986. new _Api( ctx[idx], this[idx] ) :
  5987. null;
  5988. },
  5989. filter: function ( fn )
  5990. {
  5991. var a = [];
  5992. if ( __arrayProto.filter ) {
  5993. a = __arrayProto.filter.call( this, fn, this );
  5994. }
  5995. else {
  5996. // Compatibility for browsers without EMCA-252-5 (JS 1.6)
  5997. for ( var i=0, ien=this.length ; i<ien ; i++ ) {
  5998. if ( fn.call( this, this[i], i, this ) ) {
  5999. a.push( this[i] );
  6000. }
  6001. }
  6002. }
  6003. return new _Api( this.context, a );
  6004. },
  6005. flatten: function ()
  6006. {
  6007. var a = [];
  6008. return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
  6009. },
  6010. join: __arrayProto.join,
  6011. indexOf: __arrayProto.indexOf || function (obj, start)
  6012. {
  6013. for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
  6014. if ( this[i] === obj ) {
  6015. return i;
  6016. }
  6017. }
  6018. return -1;
  6019. },
  6020. iterator: function ( flatten, type, fn, alwaysNew ) {
  6021. var
  6022. a = [], ret,
  6023. i, ien, j, jen,
  6024. context = this.context,
  6025. rows, items, item,
  6026. selector = this.selector;
  6027. // Argument shifting
  6028. if ( typeof flatten === 'string' ) {
  6029. alwaysNew = fn;
  6030. fn = type;
  6031. type = flatten;
  6032. flatten = false;
  6033. }
  6034. for ( i=0, ien=context.length ; i<ien ; i++ ) {
  6035. var apiInst = new _Api( context[i] );
  6036. if ( type === 'table' ) {
  6037. ret = fn.call( apiInst, context[i], i );
  6038. if ( ret !== undefined ) {
  6039. a.push( ret );
  6040. }
  6041. }
  6042. else if ( type === 'columns' || type === 'rows' ) {
  6043. // this has same length as context - one entry for each table
  6044. ret = fn.call( apiInst, context[i], this[i], i );
  6045. if ( ret !== undefined ) {
  6046. a.push( ret );
  6047. }
  6048. }
  6049. else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
  6050. // columns and rows share the same structure.
  6051. // 'this' is an array of column indexes for each context
  6052. items = this[i];
  6053. if ( type === 'column-rows' ) {
  6054. rows = _selector_row_indexes( context[i], selector.opts );
  6055. }
  6056. for ( j=0, jen=items.length ; j<jen ; j++ ) {
  6057. item = items[j];
  6058. if ( type === 'cell' ) {
  6059. ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
  6060. }
  6061. else {
  6062. ret = fn.call( apiInst, context[i], item, i, j, rows );
  6063. }
  6064. if ( ret !== undefined ) {
  6065. a.push( ret );
  6066. }
  6067. }
  6068. }
  6069. }
  6070. if ( a.length || alwaysNew ) {
  6071. var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
  6072. var apiSelector = api.selector;
  6073. apiSelector.rows = selector.rows;
  6074. apiSelector.cols = selector.cols;
  6075. apiSelector.opts = selector.opts;
  6076. return api;
  6077. }
  6078. return this;
  6079. },
  6080. lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
  6081. {
  6082. // Bit cheeky...
  6083. return this.indexOf.apply( this.toArray.reverse(), arguments );
  6084. },
  6085. length: 0,
  6086. map: function ( fn )
  6087. {
  6088. var a = [];
  6089. if ( __arrayProto.map ) {
  6090. a = __arrayProto.map.call( this, fn, this );
  6091. }
  6092. else {
  6093. // Compatibility for browsers without EMCA-252-5 (JS 1.6)
  6094. for ( var i=0, ien=this.length ; i<ien ; i++ ) {
  6095. a.push( fn.call( this, this[i], i ) );
  6096. }
  6097. }
  6098. return new _Api( this.context, a );
  6099. },
  6100. pluck: function ( prop )
  6101. {
  6102. return this.map( function ( el ) {
  6103. return el[ prop ];
  6104. } );
  6105. },
  6106. pop: __arrayProto.pop,
  6107. push: __arrayProto.push,
  6108. // Does not return an API instance
  6109. reduce: __arrayProto.reduce || function ( fn, init )
  6110. {
  6111. return _fnReduce( this, fn, init, 0, this.length, 1 );
  6112. },
  6113. reduceRight: __arrayProto.reduceRight || function ( fn, init )
  6114. {
  6115. return _fnReduce( this, fn, init, this.length-1, -1, -1 );
  6116. },
  6117. reverse: __arrayProto.reverse,
  6118. // Object with rows, columns and opts
  6119. selector: null,
  6120. shift: __arrayProto.shift,
  6121. slice: function () {
  6122. return new _Api( this.context, this );
  6123. },
  6124. sort: __arrayProto.sort, // ? name - order?
  6125. splice: __arrayProto.splice,
  6126. toArray: function ()
  6127. {
  6128. return __arrayProto.slice.call( this );
  6129. },
  6130. to$: function ()
  6131. {
  6132. return $( this );
  6133. },
  6134. toJQuery: function ()
  6135. {
  6136. return $( this );
  6137. },
  6138. unique: function ()
  6139. {
  6140. return new _Api( this.context, _unique(this) );
  6141. },
  6142. unshift: __arrayProto.unshift
  6143. } );
  6144. _Api.extend = function ( scope, obj, ext )
  6145. {
  6146. // Only extend API instances and static properties of the API
  6147. if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
  6148. return;
  6149. }
  6150. var
  6151. i, ien,
  6152. j, jen,
  6153. struct, inner,
  6154. methodScoping = function ( scope, fn, struc ) {
  6155. return function () {
  6156. var ret = fn.apply( scope, arguments );
  6157. // Method extension
  6158. _Api.extend( ret, ret, struc.methodExt );
  6159. return ret;
  6160. };
  6161. };
  6162. for ( i=0, ien=ext.length ; i<ien ; i++ ) {
  6163. struct = ext[i];
  6164. // Value
  6165. obj[ struct.name ] = typeof struct.val === 'function' ?
  6166. methodScoping( scope, struct.val, struct ) :
  6167. $.isPlainObject( struct.val ) ?
  6168. {} :
  6169. struct.val;
  6170. obj[ struct.name ].__dt_wrapper = true;
  6171. // Property extension
  6172. _Api.extend( scope, obj[ struct.name ], struct.propExt );
  6173. }
  6174. };
  6175. // @todo - Is there need for an augment function?
  6176. // _Api.augment = function ( inst, name )
  6177. // {
  6178. // // Find src object in the structure from the name
  6179. // var parts = name.split('.');
  6180. // _Api.extend( inst, obj );
  6181. // };
  6182. // [
  6183. // {
  6184. // name: 'data' -- string - Property name
  6185. // val: function () {}, -- function - Api method (or undefined if just an object
  6186. // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
  6187. // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
  6188. // },
  6189. // {
  6190. // name: 'row'
  6191. // val: {},
  6192. // methodExt: [ ... ],
  6193. // propExt: [
  6194. // {
  6195. // name: 'data'
  6196. // val: function () {},
  6197. // methodExt: [ ... ],
  6198. // propExt: [ ... ]
  6199. // },
  6200. // ...
  6201. // ]
  6202. // }
  6203. // ]
  6204. _Api.register = _api_register = function ( name, val )
  6205. {
  6206. if ( $.isArray( name ) ) {
  6207. for ( var j=0, jen=name.length ; j<jen ; j++ ) {
  6208. _Api.register( name[j], val );
  6209. }
  6210. return;
  6211. }
  6212. var
  6213. i, ien,
  6214. heir = name.split('.'),
  6215. struct = __apiStruct,
  6216. key, method;
  6217. var find = function ( src, name ) {
  6218. for ( var i=0, ien=src.length ; i<ien ; i++ ) {
  6219. if ( src[i].name === name ) {
  6220. return src[i];
  6221. }
  6222. }
  6223. return null;
  6224. };
  6225. for ( i=0, ien=heir.length ; i<ien ; i++ ) {
  6226. method = heir[i].indexOf('()') !== -1;
  6227. key = method ?
  6228. heir[i].replace('()', '') :
  6229. heir[i];
  6230. var src = find( struct, key );
  6231. if ( ! src ) {
  6232. src = {
  6233. name: key,
  6234. val: {},
  6235. methodExt: [],
  6236. propExt: []
  6237. };
  6238. struct.push( src );
  6239. }
  6240. if ( i === ien-1 ) {
  6241. src.val = val;
  6242. }
  6243. else {
  6244. struct = method ?
  6245. src.methodExt :
  6246. src.propExt;
  6247. }
  6248. }
  6249. };
  6250. _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
  6251. _Api.register( pluralName, val );
  6252. _Api.register( singularName, function () {
  6253. var ret = val.apply( this, arguments );
  6254. if ( ret === this ) {
  6255. // Returned item is the API instance that was passed in, return it
  6256. return this;
  6257. }
  6258. else if ( ret instanceof _Api ) {
  6259. // New API instance returned, want the value from the first item
  6260. // in the returned array for the singular result.
  6261. return ret.length ?
  6262. $.isArray( ret[0] ) ?
  6263. new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
  6264. ret[0] :
  6265. undefined;
  6266. }
  6267. // Non-API return - just fire it back
  6268. return ret;
  6269. } );
  6270. };
  6271. /**
  6272. * Selector for HTML tables. Apply the given selector to the give array of
  6273. * DataTables settings objects.
  6274. *
  6275. * @param {string|integer} [selector] jQuery selector string or integer
  6276. * @param {array} Array of DataTables settings objects to be filtered
  6277. * @return {array}
  6278. * @ignore
  6279. */
  6280. var __table_selector = function ( selector, a )
  6281. {
  6282. // Integer is used to pick out a table by index
  6283. if ( typeof selector === 'number' ) {
  6284. return [ a[ selector ] ];
  6285. }
  6286. // Perform a jQuery selector on the table nodes
  6287. var nodes = $.map( a, function (el, i) {
  6288. return el.nTable;
  6289. } );
  6290. return $(nodes)
  6291. .filter( selector )
  6292. .map( function (i) {
  6293. // Need to translate back from the table node to the settings
  6294. var idx = $.inArray( this, nodes );
  6295. return a[ idx ];
  6296. } )
  6297. .toArray();
  6298. };
  6299. /**
  6300. * Context selector for the API's context (i.e. the tables the API instance
  6301. * refers to.
  6302. *
  6303. * @name DataTable.Api#tables
  6304. * @param {string|integer} [selector] Selector to pick which tables the iterator
  6305. * should operate on. If not given, all tables in the current context are
  6306. * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
  6307. * select multiple tables or as an integer to select a single table.
  6308. * @returns {DataTable.Api} Returns a new API instance if a selector is given.
  6309. */
  6310. _api_register( 'tables()', function ( selector ) {
  6311. // A new instance is created if there was a selector specified
  6312. return selector ?
  6313. new _Api( __table_selector( selector, this.context ) ) :
  6314. this;
  6315. } );
  6316. _api_register( 'table()', function ( selector ) {
  6317. var tables = this.tables( selector );
  6318. var ctx = tables.context;
  6319. // Truncate to the first matched table
  6320. return ctx.length ?
  6321. new _Api( ctx[0] ) :
  6322. tables;
  6323. } );
  6324. _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
  6325. return this.iterator( 'table', function ( ctx ) {
  6326. return ctx.nTable;
  6327. }, 1 );
  6328. } );
  6329. _api_registerPlural( 'tables().body()', 'table().body()' , function () {
  6330. return this.iterator( 'table', function ( ctx ) {
  6331. return ctx.nTBody;
  6332. }, 1 );
  6333. } );
  6334. _api_registerPlural( 'tables().header()', 'table().header()' , function () {
  6335. return this.iterator( 'table', function ( ctx ) {
  6336. return ctx.nTHead;
  6337. }, 1 );
  6338. } );
  6339. _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
  6340. return this.iterator( 'table', function ( ctx ) {
  6341. return ctx.nTFoot;
  6342. }, 1 );
  6343. } );
  6344. _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
  6345. return this.iterator( 'table', function ( ctx ) {
  6346. return ctx.nTableWrapper;
  6347. }, 1 );
  6348. } );
  6349. /**
  6350. * Redraw the tables in the current context.
  6351. */
  6352. _api_register( 'draw()', function ( paging ) {
  6353. return this.iterator( 'table', function ( settings ) {
  6354. if ( paging === 'page' ) {
  6355. _fnDraw( settings );
  6356. }
  6357. else {
  6358. if ( typeof paging === 'string' ) {
  6359. paging = paging === 'full-hold' ?
  6360. false :
  6361. true;
  6362. }
  6363. _fnReDraw( settings, paging===false );
  6364. }
  6365. } );
  6366. } );
  6367. /**
  6368. * Get the current page index.
  6369. *
  6370. * @return {integer} Current page index (zero based)
  6371. *//**
  6372. * Set the current page.
  6373. *
  6374. * Note that if you attempt to show a page which does not exist, DataTables will
  6375. * not throw an error, but rather reset the paging.
  6376. *
  6377. * @param {integer|string} action The paging action to take. This can be one of:
  6378. * * `integer` - The page index to jump to
  6379. * * `string` - An action to take:
  6380. * * `first` - Jump to first page.
  6381. * * `next` - Jump to the next page
  6382. * * `previous` - Jump to previous page
  6383. * * `last` - Jump to the last page.
  6384. * @returns {DataTables.Api} this
  6385. */
  6386. _api_register( 'page()', function ( action ) {
  6387. if ( action === undefined ) {
  6388. return this.page.info().page; // not an expensive call
  6389. }
  6390. // else, have an action to take on all tables
  6391. return this.iterator( 'table', function ( settings ) {
  6392. _fnPageChange( settings, action );
  6393. } );
  6394. } );
  6395. /**
  6396. * Paging information for the first table in the current context.
  6397. *
  6398. * If you require paging information for another table, use the `table()` method
  6399. * with a suitable selector.
  6400. *
  6401. * @return {object} Object with the following properties set:
  6402. * * `page` - Current page index (zero based - i.e. the first page is `0`)
  6403. * * `pages` - Total number of pages
  6404. * * `start` - Display index for the first record shown on the current page
  6405. * * `end` - Display index for the last record shown on the current page
  6406. * * `length` - Display length (number of records). Note that generally `start
  6407. * + length = end`, but this is not always true, for example if there are
  6408. * only 2 records to show on the final page, with a length of 10.
  6409. * * `recordsTotal` - Full data set length
  6410. * * `recordsDisplay` - Data set length once the current filtering criterion
  6411. * are applied.
  6412. */
  6413. _api_register( 'page.info()', function ( action ) {
  6414. if ( this.context.length === 0 ) {
  6415. return undefined;
  6416. }
  6417. var
  6418. settings = this.context[0],
  6419. start = settings._iDisplayStart,
  6420. len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
  6421. visRecords = settings.fnRecordsDisplay(),
  6422. all = len === -1;
  6423. return {
  6424. "page": all ? 0 : Math.floor( start / len ),
  6425. "pages": all ? 1 : Math.ceil( visRecords / len ),
  6426. "start": start,
  6427. "end": settings.fnDisplayEnd(),
  6428. "length": len,
  6429. "recordsTotal": settings.fnRecordsTotal(),
  6430. "recordsDisplay": visRecords,
  6431. "serverSide": _fnDataSource( settings ) === 'ssp'
  6432. };
  6433. } );
  6434. /**
  6435. * Get the current page length.
  6436. *
  6437. * @return {integer} Current page length. Note `-1` indicates that all records
  6438. * are to be shown.
  6439. *//**
  6440. * Set the current page length.
  6441. *
  6442. * @param {integer} Page length to set. Use `-1` to show all records.
  6443. * @returns {DataTables.Api} this
  6444. */
  6445. _api_register( 'page.len()', function ( len ) {
  6446. // Note that we can't call this function 'length()' because `length`
  6447. // is a Javascript property of functions which defines how many arguments
  6448. // the function expects.
  6449. if ( len === undefined ) {
  6450. return this.context.length !== 0 ?
  6451. this.context[0]._iDisplayLength :
  6452. undefined;
  6453. }
  6454. // else, set the page length
  6455. return this.iterator( 'table', function ( settings ) {
  6456. _fnLengthChange( settings, len );
  6457. } );
  6458. } );
  6459. var __reload = function ( settings, holdPosition, callback ) {
  6460. // Use the draw event to trigger a callback
  6461. if ( callback ) {
  6462. var api = new _Api( settings );
  6463. api.one( 'draw', function () {
  6464. callback( api.ajax.json() );
  6465. } );
  6466. }
  6467. if ( _fnDataSource( settings ) == 'ssp' ) {
  6468. _fnReDraw( settings, holdPosition );
  6469. }
  6470. else {
  6471. _fnProcessingDisplay( settings, true );
  6472. // Cancel an existing request
  6473. var xhr = settings.jqXHR;
  6474. if ( xhr && xhr.readyState !== 4 ) {
  6475. xhr.abort();
  6476. }
  6477. // Trigger xhr
  6478. _fnBuildAjax( settings, [], function( json ) {
  6479. _fnClearTable( settings );
  6480. var data = _fnAjaxDataSrc( settings, json );
  6481. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  6482. _fnAddData( settings, data[i] );
  6483. }
  6484. _fnReDraw( settings, holdPosition );
  6485. _fnProcessingDisplay( settings, false );
  6486. } );
  6487. }
  6488. };
  6489. /**
  6490. * Get the JSON response from the last Ajax request that DataTables made to the
  6491. * server. Note that this returns the JSON from the first table in the current
  6492. * context.
  6493. *
  6494. * @return {object} JSON received from the server.
  6495. */
  6496. _api_register( 'ajax.json()', function () {
  6497. var ctx = this.context;
  6498. if ( ctx.length > 0 ) {
  6499. return ctx[0].json;
  6500. }
  6501. // else return undefined;
  6502. } );
  6503. /**
  6504. * Get the data submitted in the last Ajax request
  6505. */
  6506. _api_register( 'ajax.params()', function () {
  6507. var ctx = this.context;
  6508. if ( ctx.length > 0 ) {
  6509. return ctx[0].oAjaxData;
  6510. }
  6511. // else return undefined;
  6512. } );
  6513. /**
  6514. * Reload tables from the Ajax data source. Note that this function will
  6515. * automatically re-draw the table when the remote data has been loaded.
  6516. *
  6517. * @param {boolean} [reset=true] Reset (default) or hold the current paging
  6518. * position. A full re-sort and re-filter is performed when this method is
  6519. * called, which is why the pagination reset is the default action.
  6520. * @returns {DataTables.Api} this
  6521. */
  6522. _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
  6523. return this.iterator( 'table', function (settings) {
  6524. __reload( settings, resetPaging===false, callback );
  6525. } );
  6526. } );
  6527. /**
  6528. * Get the current Ajax URL. Note that this returns the URL from the first
  6529. * table in the current context.
  6530. *
  6531. * @return {string} Current Ajax source URL
  6532. *//**
  6533. * Set the Ajax URL. Note that this will set the URL for all tables in the
  6534. * current context.
  6535. *
  6536. * @param {string} url URL to set.
  6537. * @returns {DataTables.Api} this
  6538. */
  6539. _api_register( 'ajax.url()', function ( url ) {
  6540. var ctx = this.context;
  6541. if ( url === undefined ) {
  6542. // get
  6543. if ( ctx.length === 0 ) {
  6544. return undefined;
  6545. }
  6546. ctx = ctx[0];
  6547. return ctx.ajax ?
  6548. $.isPlainObject( ctx.ajax ) ?
  6549. ctx.ajax.url :
  6550. ctx.ajax :
  6551. ctx.sAjaxSource;
  6552. }
  6553. // set
  6554. return this.iterator( 'table', function ( settings ) {
  6555. if ( $.isPlainObject( settings.ajax ) ) {
  6556. settings.ajax.url = url;
  6557. }
  6558. else {
  6559. settings.ajax = url;
  6560. }
  6561. // No need to consider sAjaxSource here since DataTables gives priority
  6562. // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
  6563. // value of `sAjaxSource` redundant.
  6564. } );
  6565. } );
  6566. /**
  6567. * Load data from the newly set Ajax URL. Note that this method is only
  6568. * available when `ajax.url()` is used to set a URL. Additionally, this method
  6569. * has the same effect as calling `ajax.reload()` but is provided for
  6570. * convenience when setting a new URL. Like `ajax.reload()` it will
  6571. * automatically redraw the table once the remote data has been loaded.
  6572. *
  6573. * @returns {DataTables.Api} this
  6574. */
  6575. _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
  6576. // Same as a reload, but makes sense to present it for easy access after a
  6577. // url change
  6578. return this.iterator( 'table', function ( ctx ) {
  6579. __reload( ctx, resetPaging===false, callback );
  6580. } );
  6581. } );
  6582. var _selector_run = function ( type, selector, selectFn, settings, opts )
  6583. {
  6584. var
  6585. out = [], res,
  6586. a, i, ien, j, jen,
  6587. selectorType = typeof selector;
  6588. // Can't just check for isArray here, as an API or jQuery instance might be
  6589. // given with their array like look
  6590. if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
  6591. selector = [ selector ];
  6592. }
  6593. for ( i=0, ien=selector.length ; i<ien ; i++ ) {
  6594. // Only split on simple strings - complex expressions will be jQuery selectors
  6595. a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
  6596. selector[i].split(',') :
  6597. [ selector[i] ];
  6598. for ( j=0, jen=a.length ; j<jen ; j++ ) {
  6599. res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
  6600. if ( res && res.length ) {
  6601. out = out.concat( res );
  6602. }
  6603. }
  6604. }
  6605. // selector extensions
  6606. var ext = _ext.selector[ type ];
  6607. if ( ext.length ) {
  6608. for ( i=0, ien=ext.length ; i<ien ; i++ ) {
  6609. out = ext[i]( settings, opts, out );
  6610. }
  6611. }
  6612. return _unique( out );
  6613. };
  6614. var _selector_opts = function ( opts )
  6615. {
  6616. if ( ! opts ) {
  6617. opts = {};
  6618. }
  6619. // Backwards compatibility for 1.9- which used the terminology filter rather
  6620. // than search
  6621. if ( opts.filter && opts.search === undefined ) {
  6622. opts.search = opts.filter;
  6623. }
  6624. return $.extend( {
  6625. search: 'none',
  6626. order: 'current',
  6627. page: 'all'
  6628. }, opts );
  6629. };
  6630. var _selector_first = function ( inst )
  6631. {
  6632. // Reduce the API instance to the first item found
  6633. for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
  6634. if ( inst[i].length > 0 ) {
  6635. // Assign the first element to the first item in the instance
  6636. // and truncate the instance and context
  6637. inst[0] = inst[i];
  6638. inst[0].length = 1;
  6639. inst.length = 1;
  6640. inst.context = [ inst.context[i] ];
  6641. return inst;
  6642. }
  6643. }
  6644. // Not found - return an empty instance
  6645. inst.length = 0;
  6646. return inst;
  6647. };
  6648. var _selector_row_indexes = function ( settings, opts )
  6649. {
  6650. var
  6651. i, ien, tmp, a=[],
  6652. displayFiltered = settings.aiDisplay,
  6653. displayMaster = settings.aiDisplayMaster;
  6654. var
  6655. search = opts.search, // none, applied, removed
  6656. order = opts.order, // applied, current, index (original - compatibility with 1.9)
  6657. page = opts.page; // all, current
  6658. if ( _fnDataSource( settings ) == 'ssp' ) {
  6659. // In server-side processing mode, most options are irrelevant since
  6660. // rows not shown don't exist and the index order is the applied order
  6661. // Removed is a special case - for consistency just return an empty
  6662. // array
  6663. return search === 'removed' ?
  6664. [] :
  6665. _range( 0, displayMaster.length );
  6666. }
  6667. else if ( page == 'current' ) {
  6668. // Current page implies that order=current and fitler=applied, since it is
  6669. // fairly senseless otherwise, regardless of what order and search actually
  6670. // are
  6671. for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
  6672. a.push( displayFiltered[i] );
  6673. }
  6674. }
  6675. else if ( order == 'current' || order == 'applied' ) {
  6676. if ( search == 'none') {
  6677. a = displayMaster.slice();
  6678. }
  6679. else if ( search == 'applied' ) {
  6680. a = displayFiltered.slice();
  6681. }
  6682. else if ( search == 'removed' ) {
  6683. // O(n+m) solution by creating a hash map
  6684. var displayFilteredMap = {};
  6685. for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
  6686. displayFilteredMap[displayFiltered[i]] = null;
  6687. }
  6688. a = $.map( displayMaster, function (el) {
  6689. return ! displayFilteredMap.hasOwnProperty(el) ?
  6690. el :
  6691. null;
  6692. } );
  6693. }
  6694. }
  6695. else if ( order == 'index' || order == 'original' ) {
  6696. for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  6697. if ( search == 'none' ) {
  6698. a.push( i );
  6699. }
  6700. else { // applied | removed
  6701. tmp = $.inArray( i, displayFiltered );
  6702. if ((tmp === -1 && search == 'removed') ||
  6703. (tmp >= 0 && search == 'applied') )
  6704. {
  6705. a.push( i );
  6706. }
  6707. }
  6708. }
  6709. }
  6710. return a;
  6711. };
  6712. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6713. * Rows
  6714. *
  6715. * {} - no selector - use all available rows
  6716. * {integer} - row aoData index
  6717. * {node} - TR node
  6718. * {string} - jQuery selector to apply to the TR elements
  6719. * {array} - jQuery array of nodes, or simply an array of TR nodes
  6720. *
  6721. */
  6722. var __row_selector = function ( settings, selector, opts )
  6723. {
  6724. var rows;
  6725. var run = function ( sel ) {
  6726. var selInt = _intVal( sel );
  6727. var i, ien;
  6728. var aoData = settings.aoData;
  6729. // Short cut - selector is a number and no options provided (default is
  6730. // all records, so no need to check if the index is in there, since it
  6731. // must be - dev error if the index doesn't exist).
  6732. if ( selInt !== null && ! opts ) {
  6733. return [ selInt ];
  6734. }
  6735. if ( ! rows ) {
  6736. rows = _selector_row_indexes( settings, opts );
  6737. }
  6738. if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
  6739. // Selector - integer
  6740. return [ selInt ];
  6741. }
  6742. else if ( sel === null || sel === undefined || sel === '' ) {
  6743. // Selector - none
  6744. return rows;
  6745. }
  6746. // Selector - function
  6747. if ( typeof sel === 'function' ) {
  6748. return $.map( rows, function (idx) {
  6749. var row = aoData[ idx ];
  6750. return sel( idx, row._aData, row.nTr ) ? idx : null;
  6751. } );
  6752. }
  6753. // Selector - node
  6754. if ( sel.nodeName ) {
  6755. var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup
  6756. var cellIdx = sel._DT_CellIndex;
  6757. if ( rowIdx !== undefined ) {
  6758. // Make sure that the row is actually still present in the table
  6759. return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
  6760. [ rowIdx ] :
  6761. [];
  6762. }
  6763. else if ( cellIdx ) {
  6764. return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel ?
  6765. [ cellIdx.row ] :
  6766. [];
  6767. }
  6768. else {
  6769. var host = $(sel).closest('*[data-dt-row]');
  6770. return host.length ?
  6771. [ host.data('dt-row') ] :
  6772. [];
  6773. }
  6774. }
  6775. // ID selector. Want to always be able to select rows by id, regardless
  6776. // of if the tr element has been created or not, so can't rely upon
  6777. // jQuery here - hence a custom implementation. This does not match
  6778. // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
  6779. // but to select it using a CSS selector engine (like Sizzle or
  6780. // querySelect) it would need to need to be escaped for some characters.
  6781. // DataTables simplifies this for row selectors since you can select
  6782. // only a row. A # indicates an id any anything that follows is the id -
  6783. // unescaped.
  6784. if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
  6785. // get row index from id
  6786. var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
  6787. if ( rowObj !== undefined ) {
  6788. return [ rowObj.idx ];
  6789. }
  6790. // need to fall through to jQuery in case there is DOM id that
  6791. // matches
  6792. }
  6793. // Get nodes in the order from the `rows` array with null values removed
  6794. var nodes = _removeEmpty(
  6795. _pluck_order( settings.aoData, rows, 'nTr' )
  6796. );
  6797. // Selector - jQuery selector string, array of nodes or jQuery object/
  6798. // As jQuery's .filter() allows jQuery objects to be passed in filter,
  6799. // it also allows arrays, so this will cope with all three options
  6800. return $(nodes)
  6801. .filter( sel )
  6802. .map( function () {
  6803. return this._DT_RowIndex;
  6804. } )
  6805. .toArray();
  6806. };
  6807. return _selector_run( 'row', selector, run, settings, opts );
  6808. };
  6809. _api_register( 'rows()', function ( selector, opts ) {
  6810. // argument shifting
  6811. if ( selector === undefined ) {
  6812. selector = '';
  6813. }
  6814. else if ( $.isPlainObject( selector ) ) {
  6815. opts = selector;
  6816. selector = '';
  6817. }
  6818. opts = _selector_opts( opts );
  6819. var inst = this.iterator( 'table', function ( settings ) {
  6820. return __row_selector( settings, selector, opts );
  6821. }, 1 );
  6822. // Want argument shifting here and in __row_selector?
  6823. inst.selector.rows = selector;
  6824. inst.selector.opts = opts;
  6825. return inst;
  6826. } );
  6827. _api_register( 'rows().nodes()', function () {
  6828. return this.iterator( 'row', function ( settings, row ) {
  6829. return settings.aoData[ row ].nTr || undefined;
  6830. }, 1 );
  6831. } );
  6832. _api_register( 'rows().data()', function () {
  6833. return this.iterator( true, 'rows', function ( settings, rows ) {
  6834. return _pluck_order( settings.aoData, rows, '_aData' );
  6835. }, 1 );
  6836. } );
  6837. _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
  6838. return this.iterator( 'row', function ( settings, row ) {
  6839. var r = settings.aoData[ row ];
  6840. return type === 'search' ? r._aFilterData : r._aSortData;
  6841. }, 1 );
  6842. } );
  6843. _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
  6844. return this.iterator( 'row', function ( settings, row ) {
  6845. _fnInvalidate( settings, row, src );
  6846. } );
  6847. } );
  6848. _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
  6849. return this.iterator( 'row', function ( settings, row ) {
  6850. return row;
  6851. }, 1 );
  6852. } );
  6853. _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
  6854. var a = [];
  6855. var context = this.context;
  6856. // `iterator` will drop undefined values, but in this case we want them
  6857. for ( var i=0, ien=context.length ; i<ien ; i++ ) {
  6858. for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
  6859. var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
  6860. a.push( (hash === true ? '#' : '' )+ id );
  6861. }
  6862. }
  6863. return new _Api( context, a );
  6864. } );
  6865. _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
  6866. var that = this;
  6867. this.iterator( 'row', function ( settings, row, thatIdx ) {
  6868. var data = settings.aoData;
  6869. var rowData = data[ row ];
  6870. var i, ien, j, jen;
  6871. var loopRow, loopCells;
  6872. data.splice( row, 1 );
  6873. // Update the cached indexes
  6874. for ( i=0, ien=data.length ; i<ien ; i++ ) {
  6875. loopRow = data[i];
  6876. loopCells = loopRow.anCells;
  6877. // Rows
  6878. if ( loopRow.nTr !== null ) {
  6879. loopRow.nTr._DT_RowIndex = i;
  6880. }
  6881. // Cells
  6882. if ( loopCells !== null ) {
  6883. for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
  6884. loopCells[j]._DT_CellIndex.row = i;
  6885. }
  6886. }
  6887. }
  6888. // Delete from the display arrays
  6889. _fnDeleteIndex( settings.aiDisplayMaster, row );
  6890. _fnDeleteIndex( settings.aiDisplay, row );
  6891. _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
  6892. // For server-side processing tables - subtract the deleted row from the count
  6893. if ( settings._iRecordsDisplay > 0 ) {
  6894. settings._iRecordsDisplay--;
  6895. }
  6896. // Check for an 'overflow' they case for displaying the table
  6897. _fnLengthOverflow( settings );
  6898. // Remove the row's ID reference if there is one
  6899. var id = settings.rowIdFn( rowData._aData );
  6900. if ( id !== undefined ) {
  6901. delete settings.aIds[ id ];
  6902. }
  6903. } );
  6904. this.iterator( 'table', function ( settings ) {
  6905. for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  6906. settings.aoData[i].idx = i;
  6907. }
  6908. } );
  6909. return this;
  6910. } );
  6911. _api_register( 'rows.add()', function ( rows ) {
  6912. var newRows = this.iterator( 'table', function ( settings ) {
  6913. var row, i, ien;
  6914. var out = [];
  6915. for ( i=0, ien=rows.length ; i<ien ; i++ ) {
  6916. row = rows[i];
  6917. if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
  6918. out.push( _fnAddTr( settings, row )[0] );
  6919. }
  6920. else {
  6921. out.push( _fnAddData( settings, row ) );
  6922. }
  6923. }
  6924. return out;
  6925. }, 1 );
  6926. // Return an Api.rows() extended instance, so rows().nodes() etc can be used
  6927. var modRows = this.rows( -1 );
  6928. modRows.pop();
  6929. $.merge( modRows, newRows );
  6930. return modRows;
  6931. } );
  6932. /**
  6933. *
  6934. */
  6935. _api_register( 'row()', function ( selector, opts ) {
  6936. return _selector_first( this.rows( selector, opts ) );
  6937. } );
  6938. _api_register( 'row().data()', function ( data ) {
  6939. var ctx = this.context;
  6940. if ( data === undefined ) {
  6941. // Get
  6942. return ctx.length && this.length ?
  6943. ctx[0].aoData[ this[0] ]._aData :
  6944. undefined;
  6945. }
  6946. // Set
  6947. var row = ctx[0].aoData[ this[0] ];
  6948. row._aData = data;
  6949. // If the DOM has an id, and the data source is an array
  6950. if ( $.isArray( data ) && row.nTr.id ) {
  6951. _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
  6952. }
  6953. // Automatically invalidate
  6954. _fnInvalidate( ctx[0], this[0], 'data' );
  6955. return this;
  6956. } );
  6957. _api_register( 'row().node()', function () {
  6958. var ctx = this.context;
  6959. return ctx.length && this.length ?
  6960. ctx[0].aoData[ this[0] ].nTr || null :
  6961. null;
  6962. } );
  6963. _api_register( 'row.add()', function ( row ) {
  6964. // Allow a jQuery object to be passed in - only a single row is added from
  6965. // it though - the first element in the set
  6966. if ( row instanceof $ && row.length ) {
  6967. row = row[0];
  6968. }
  6969. var rows = this.iterator( 'table', function ( settings ) {
  6970. if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
  6971. return _fnAddTr( settings, row )[0];
  6972. }
  6973. return _fnAddData( settings, row );
  6974. } );
  6975. // Return an Api.rows() extended instance, with the newly added row selected
  6976. return this.row( rows[0] );
  6977. } );
  6978. var __details_add = function ( ctx, row, data, klass )
  6979. {
  6980. // Convert to array of TR elements
  6981. var rows = [];
  6982. var addRow = function ( r, k ) {
  6983. // Recursion to allow for arrays of jQuery objects
  6984. if ( $.isArray( r ) || r instanceof $ ) {
  6985. for ( var i=0, ien=r.length ; i<ien ; i++ ) {
  6986. addRow( r[i], k );
  6987. }
  6988. return;
  6989. }
  6990. // If we get a TR element, then just add it directly - up to the dev
  6991. // to add the correct number of columns etc
  6992. if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
  6993. rows.push( r );
  6994. }
  6995. else {
  6996. // Otherwise create a row with a wrapper
  6997. var created = $('<tr><td/></tr>').addClass( k );
  6998. $('td', created)
  6999. .addClass( k )
  7000. .html( r )
  7001. [0].colSpan = _fnVisbleColumns( ctx );
  7002. rows.push( created[0] );
  7003. }
  7004. };
  7005. addRow( data, klass );
  7006. if ( row._details ) {
  7007. row._details.detach();
  7008. }
  7009. row._details = $(rows);
  7010. // If the children were already shown, that state should be retained
  7011. if ( row._detailsShow ) {
  7012. row._details.insertAfter( row.nTr );
  7013. }
  7014. };
  7015. var __details_remove = function ( api, idx )
  7016. {
  7017. var ctx = api.context;
  7018. if ( ctx.length ) {
  7019. var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
  7020. if ( row && row._details ) {
  7021. row._details.remove();
  7022. row._detailsShow = undefined;
  7023. row._details = undefined;
  7024. }
  7025. }
  7026. };
  7027. var __details_display = function ( api, show ) {
  7028. var ctx = api.context;
  7029. if ( ctx.length && api.length ) {
  7030. var row = ctx[0].aoData[ api[0] ];
  7031. if ( row._details ) {
  7032. row._detailsShow = show;
  7033. if ( show ) {
  7034. row._details.insertAfter( row.nTr );
  7035. }
  7036. else {
  7037. row._details.detach();
  7038. }
  7039. __details_events( ctx[0] );
  7040. }
  7041. }
  7042. };
  7043. var __details_events = function ( settings )
  7044. {
  7045. var api = new _Api( settings );
  7046. var namespace = '.dt.DT_details';
  7047. var drawEvent = 'draw'+namespace;
  7048. var colvisEvent = 'column-visibility'+namespace;
  7049. var destroyEvent = 'destroy'+namespace;
  7050. var data = settings.aoData;
  7051. api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
  7052. if ( _pluck( data, '_details' ).length > 0 ) {
  7053. // On each draw, insert the required elements into the document
  7054. api.on( drawEvent, function ( e, ctx ) {
  7055. if ( settings !== ctx ) {
  7056. return;
  7057. }
  7058. api.rows( {page:'current'} ).eq(0).each( function (idx) {
  7059. // Internal data grab
  7060. var row = data[ idx ];
  7061. if ( row._detailsShow ) {
  7062. row._details.insertAfter( row.nTr );
  7063. }
  7064. } );
  7065. } );
  7066. // Column visibility change - update the colspan
  7067. api.on( colvisEvent, function ( e, ctx, idx, vis ) {
  7068. if ( settings !== ctx ) {
  7069. return;
  7070. }
  7071. // Update the colspan for the details rows (note, only if it already has
  7072. // a colspan)
  7073. var row, visible = _fnVisbleColumns( ctx );
  7074. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  7075. row = data[i];
  7076. if ( row._details ) {
  7077. row._details.children('td[colspan]').attr('colspan', visible );
  7078. }
  7079. }
  7080. } );
  7081. // Table destroyed - nuke any child rows
  7082. api.on( destroyEvent, function ( e, ctx ) {
  7083. if ( settings !== ctx ) {
  7084. return;
  7085. }
  7086. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  7087. if ( data[i]._details ) {
  7088. __details_remove( api, i );
  7089. }
  7090. }
  7091. } );
  7092. }
  7093. };
  7094. // Strings for the method names to help minification
  7095. var _emp = '';
  7096. var _child_obj = _emp+'row().child';
  7097. var _child_mth = _child_obj+'()';
  7098. // data can be:
  7099. // tr
  7100. // string
  7101. // jQuery or array of any of the above
  7102. _api_register( _child_mth, function ( data, klass ) {
  7103. var ctx = this.context;
  7104. if ( data === undefined ) {
  7105. // get
  7106. return ctx.length && this.length ?
  7107. ctx[0].aoData[ this[0] ]._details :
  7108. undefined;
  7109. }
  7110. else if ( data === true ) {
  7111. // show
  7112. this.child.show();
  7113. }
  7114. else if ( data === false ) {
  7115. // remove
  7116. __details_remove( this );
  7117. }
  7118. else if ( ctx.length && this.length ) {
  7119. // set
  7120. __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
  7121. }
  7122. return this;
  7123. } );
  7124. _api_register( [
  7125. _child_obj+'.show()',
  7126. _child_mth+'.show()' // only when `child()` was called with parameters (without
  7127. ], function ( show ) { // it returns an object and this method is not executed)
  7128. __details_display( this, true );
  7129. return this;
  7130. } );
  7131. _api_register( [
  7132. _child_obj+'.hide()',
  7133. _child_mth+'.hide()' // only when `child()` was called with parameters (without
  7134. ], function () { // it returns an object and this method is not executed)
  7135. __details_display( this, false );
  7136. return this;
  7137. } );
  7138. _api_register( [
  7139. _child_obj+'.remove()',
  7140. _child_mth+'.remove()' // only when `child()` was called with parameters (without
  7141. ], function () { // it returns an object and this method is not executed)
  7142. __details_remove( this );
  7143. return this;
  7144. } );
  7145. _api_register( _child_obj+'.isShown()', function () {
  7146. var ctx = this.context;
  7147. if ( ctx.length && this.length ) {
  7148. // _detailsShown as false or undefined will fall through to return false
  7149. return ctx[0].aoData[ this[0] ]._detailsShow || false;
  7150. }
  7151. return false;
  7152. } );
  7153. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7154. * Columns
  7155. *
  7156. * {integer} - column index (>=0 count from left, <0 count from right)
  7157. * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
  7158. * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
  7159. * "{string}:name" - column name
  7160. * "{string}" - jQuery selector on column header nodes
  7161. *
  7162. */
  7163. // can be an array of these items, comma separated list, or an array of comma
  7164. // separated lists
  7165. var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
  7166. // r1 and r2 are redundant - but it means that the parameters match for the
  7167. // iterator callback in columns().data()
  7168. var __columnData = function ( settings, column, r1, r2, rows ) {
  7169. var a = [];
  7170. for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
  7171. a.push( _fnGetCellData( settings, rows[row], column ) );
  7172. }
  7173. return a;
  7174. };
  7175. var __column_selector = function ( settings, selector, opts )
  7176. {
  7177. var
  7178. columns = settings.aoColumns,
  7179. names = _pluck( columns, 'sName' ),
  7180. nodes = _pluck( columns, 'nTh' );
  7181. var run = function ( s ) {
  7182. var selInt = _intVal( s );
  7183. // Selector - all
  7184. if ( s === '' ) {
  7185. return _range( columns.length );
  7186. }
  7187. // Selector - index
  7188. if ( selInt !== null ) {
  7189. return [ selInt >= 0 ?
  7190. selInt : // Count from left
  7191. columns.length + selInt // Count from right (+ because its a negative value)
  7192. ];
  7193. }
  7194. // Selector = function
  7195. if ( typeof s === 'function' ) {
  7196. var rows = _selector_row_indexes( settings, opts );
  7197. return $.map( columns, function (col, idx) {
  7198. return s(
  7199. idx,
  7200. __columnData( settings, idx, 0, 0, rows ),
  7201. nodes[ idx ]
  7202. ) ? idx : null;
  7203. } );
  7204. }
  7205. // jQuery or string selector
  7206. var match = typeof s === 'string' ?
  7207. s.match( __re_column_selector ) :
  7208. '';
  7209. if ( match ) {
  7210. switch( match[2] ) {
  7211. case 'visIdx':
  7212. case 'visible':
  7213. var idx = parseInt( match[1], 10 );
  7214. // Visible index given, convert to column index
  7215. if ( idx < 0 ) {
  7216. // Counting from the right
  7217. var visColumns = $.map( columns, function (col,i) {
  7218. return col.bVisible ? i : null;
  7219. } );
  7220. return [ visColumns[ visColumns.length + idx ] ];
  7221. }
  7222. // Counting from the left
  7223. return [ _fnVisibleToColumnIndex( settings, idx ) ];
  7224. case 'name':
  7225. // match by name. `names` is column index complete and in order
  7226. return $.map( names, function (name, i) {
  7227. return name === match[1] ? i : null;
  7228. } );
  7229. default:
  7230. return [];
  7231. }
  7232. }
  7233. // Cell in the table body
  7234. if ( s.nodeName && s._DT_CellIndex ) {
  7235. return [ s._DT_CellIndex.column ];
  7236. }
  7237. // jQuery selector on the TH elements for the columns
  7238. var jqResult = $( nodes )
  7239. .filter( s )
  7240. .map( function () {
  7241. return $.inArray( this, nodes ); // `nodes` is column index complete and in order
  7242. } )
  7243. .toArray();
  7244. if ( jqResult.length || ! s.nodeName ) {
  7245. return jqResult;
  7246. }
  7247. // Otherwise a node which might have a `dt-column` data attribute, or be
  7248. // a child or such an element
  7249. var host = $(s).closest('*[data-dt-column]');
  7250. return host.length ?
  7251. [ host.data('dt-column') ] :
  7252. [];
  7253. };
  7254. return _selector_run( 'column', selector, run, settings, opts );
  7255. };
  7256. var __setColumnVis = function ( settings, column, vis ) {
  7257. var
  7258. cols = settings.aoColumns,
  7259. col = cols[ column ],
  7260. data = settings.aoData,
  7261. row, cells, i, ien, tr;
  7262. // Get
  7263. if ( vis === undefined ) {
  7264. return col.bVisible;
  7265. }
  7266. // Set
  7267. // No change
  7268. if ( col.bVisible === vis ) {
  7269. return;
  7270. }
  7271. if ( vis ) {
  7272. // Insert column
  7273. // Need to decide if we should use appendChild or insertBefore
  7274. var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
  7275. for ( i=0, ien=data.length ; i<ien ; i++ ) {
  7276. tr = data[i].nTr;
  7277. cells = data[i].anCells;
  7278. if ( tr ) {
  7279. // insertBefore can act like appendChild if 2nd arg is null
  7280. tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
  7281. }
  7282. }
  7283. }
  7284. else {
  7285. // Remove column
  7286. $( _pluck( settings.aoData, 'anCells', column ) ).detach();
  7287. }
  7288. // Common actions
  7289. col.bVisible = vis;
  7290. _fnDrawHead( settings, settings.aoHeader );
  7291. _fnDrawHead( settings, settings.aoFooter );
  7292. // Update colspan for no records display. Child rows and extensions will use their own
  7293. // listeners to do this - only need to update the empty table item here
  7294. if ( ! settings.aiDisplay.length ) {
  7295. $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
  7296. }
  7297. _fnSaveState( settings );
  7298. };
  7299. _api_register( 'columns()', function ( selector, opts ) {
  7300. // argument shifting
  7301. if ( selector === undefined ) {
  7302. selector = '';
  7303. }
  7304. else if ( $.isPlainObject( selector ) ) {
  7305. opts = selector;
  7306. selector = '';
  7307. }
  7308. opts = _selector_opts( opts );
  7309. var inst = this.iterator( 'table', function ( settings ) {
  7310. return __column_selector( settings, selector, opts );
  7311. }, 1 );
  7312. // Want argument shifting here and in _row_selector?
  7313. inst.selector.cols = selector;
  7314. inst.selector.opts = opts;
  7315. return inst;
  7316. } );
  7317. _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
  7318. return this.iterator( 'column', function ( settings, column ) {
  7319. return settings.aoColumns[column].nTh;
  7320. }, 1 );
  7321. } );
  7322. _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
  7323. return this.iterator( 'column', function ( settings, column ) {
  7324. return settings.aoColumns[column].nTf;
  7325. }, 1 );
  7326. } );
  7327. _api_registerPlural( 'columns().data()', 'column().data()', function () {
  7328. return this.iterator( 'column-rows', __columnData, 1 );
  7329. } );
  7330. _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
  7331. return this.iterator( 'column', function ( settings, column ) {
  7332. return settings.aoColumns[column].mData;
  7333. }, 1 );
  7334. } );
  7335. _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
  7336. return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
  7337. return _pluck_order( settings.aoData, rows,
  7338. type === 'search' ? '_aFilterData' : '_aSortData', column
  7339. );
  7340. }, 1 );
  7341. } );
  7342. _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
  7343. return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
  7344. return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
  7345. }, 1 );
  7346. } );
  7347. _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
  7348. var ret = this.iterator( 'column', function ( settings, column ) {
  7349. if ( vis === undefined ) {
  7350. return settings.aoColumns[ column ].bVisible;
  7351. } // else
  7352. __setColumnVis( settings, column, vis );
  7353. } );
  7354. // Group the column visibility changes
  7355. if ( vis !== undefined ) {
  7356. // Second loop once the first is done for events
  7357. this.iterator( 'column', function ( settings, column ) {
  7358. _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
  7359. } );
  7360. if ( calc === undefined || calc ) {
  7361. this.columns.adjust();
  7362. }
  7363. }
  7364. return ret;
  7365. } );
  7366. _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
  7367. return this.iterator( 'column', function ( settings, column ) {
  7368. return type === 'visible' ?
  7369. _fnColumnIndexToVisible( settings, column ) :
  7370. column;
  7371. }, 1 );
  7372. } );
  7373. _api_register( 'columns.adjust()', function () {
  7374. return this.iterator( 'table', function ( settings ) {
  7375. _fnAdjustColumnSizing( settings );
  7376. }, 1 );
  7377. } );
  7378. _api_register( 'column.index()', function ( type, idx ) {
  7379. if ( this.context.length !== 0 ) {
  7380. var ctx = this.context[0];
  7381. if ( type === 'fromVisible' || type === 'toData' ) {
  7382. return _fnVisibleToColumnIndex( ctx, idx );
  7383. }
  7384. else if ( type === 'fromData' || type === 'toVisible' ) {
  7385. return _fnColumnIndexToVisible( ctx, idx );
  7386. }
  7387. }
  7388. } );
  7389. _api_register( 'column()', function ( selector, opts ) {
  7390. return _selector_first( this.columns( selector, opts ) );
  7391. } );
  7392. var __cell_selector = function ( settings, selector, opts )
  7393. {
  7394. var data = settings.aoData;
  7395. var rows = _selector_row_indexes( settings, opts );
  7396. var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
  7397. var allCells = $( [].concat.apply([], cells) );
  7398. var row;
  7399. var columns = settings.aoColumns.length;
  7400. var a, i, ien, j, o, host;
  7401. var run = function ( s ) {
  7402. var fnSelector = typeof s === 'function';
  7403. if ( s === null || s === undefined || fnSelector ) {
  7404. // All cells and function selectors
  7405. a = [];
  7406. for ( i=0, ien=rows.length ; i<ien ; i++ ) {
  7407. row = rows[i];
  7408. for ( j=0 ; j<columns ; j++ ) {
  7409. o = {
  7410. row: row,
  7411. column: j
  7412. };
  7413. if ( fnSelector ) {
  7414. // Selector - function
  7415. host = data[ row ];
  7416. if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
  7417. a.push( o );
  7418. }
  7419. }
  7420. else {
  7421. // Selector - all
  7422. a.push( o );
  7423. }
  7424. }
  7425. }
  7426. return a;
  7427. }
  7428. // Selector - index
  7429. if ( $.isPlainObject( s ) ) {
  7430. // Valid cell index and its in the array of selectable rows
  7431. return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
  7432. [s] :
  7433. [];
  7434. }
  7435. // Selector - jQuery filtered cells
  7436. var jqResult = allCells
  7437. .filter( s )
  7438. .map( function (i, el) {
  7439. return { // use a new object, in case someone changes the values
  7440. row: el._DT_CellIndex.row,
  7441. column: el._DT_CellIndex.column
  7442. };
  7443. } )
  7444. .toArray();
  7445. if ( jqResult.length || ! s.nodeName ) {
  7446. return jqResult;
  7447. }
  7448. // Otherwise the selector is a node, and there is one last option - the
  7449. // element might be a child of an element which has dt-row and dt-column
  7450. // data attributes
  7451. host = $(s).closest('*[data-dt-row]');
  7452. return host.length ?
  7453. [ {
  7454. row: host.data('dt-row'),
  7455. column: host.data('dt-column')
  7456. } ] :
  7457. [];
  7458. };
  7459. return _selector_run( 'cell', selector, run, settings, opts );
  7460. };
  7461. _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
  7462. // Argument shifting
  7463. if ( $.isPlainObject( rowSelector ) ) {
  7464. // Indexes
  7465. if ( rowSelector.row === undefined ) {
  7466. // Selector options in first parameter
  7467. opts = rowSelector;
  7468. rowSelector = null;
  7469. }
  7470. else {
  7471. // Cell index objects in first parameter
  7472. opts = columnSelector;
  7473. columnSelector = null;
  7474. }
  7475. }
  7476. if ( $.isPlainObject( columnSelector ) ) {
  7477. opts = columnSelector;
  7478. columnSelector = null;
  7479. }
  7480. // Cell selector
  7481. if ( columnSelector === null || columnSelector === undefined ) {
  7482. return this.iterator( 'table', function ( settings ) {
  7483. return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
  7484. } );
  7485. }
  7486. // Row + column selector
  7487. var columns = this.columns( columnSelector );
  7488. var rows = this.rows( rowSelector );
  7489. var a, i, ien, j, jen;
  7490. this.iterator( 'table', function ( settings, idx ) {
  7491. a = [];
  7492. for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
  7493. for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
  7494. a.push( {
  7495. row: rows[idx][i],
  7496. column: columns[idx][j]
  7497. } );
  7498. }
  7499. }
  7500. }, 1 );
  7501. // Now pass through the cell selector for options
  7502. var cells = this.cells( a, opts );
  7503. $.extend( cells.selector, {
  7504. cols: columnSelector,
  7505. rows: rowSelector,
  7506. opts: opts
  7507. } );
  7508. return cells;
  7509. } );
  7510. _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
  7511. return this.iterator( 'cell', function ( settings, row, column ) {
  7512. var data = settings.aoData[ row ];
  7513. return data && data.anCells ?
  7514. data.anCells[ column ] :
  7515. undefined;
  7516. }, 1 );
  7517. } );
  7518. _api_register( 'cells().data()', function () {
  7519. return this.iterator( 'cell', function ( settings, row, column ) {
  7520. return _fnGetCellData( settings, row, column );
  7521. }, 1 );
  7522. } );
  7523. _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
  7524. type = type === 'search' ? '_aFilterData' : '_aSortData';
  7525. return this.iterator( 'cell', function ( settings, row, column ) {
  7526. return settings.aoData[ row ][ type ][ column ];
  7527. }, 1 );
  7528. } );
  7529. _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
  7530. return this.iterator( 'cell', function ( settings, row, column ) {
  7531. return _fnGetCellData( settings, row, column, type );
  7532. }, 1 );
  7533. } );
  7534. _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
  7535. return this.iterator( 'cell', function ( settings, row, column ) {
  7536. return {
  7537. row: row,
  7538. column: column,
  7539. columnVisible: _fnColumnIndexToVisible( settings, column )
  7540. };
  7541. }, 1 );
  7542. } );
  7543. _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
  7544. return this.iterator( 'cell', function ( settings, row, column ) {
  7545. _fnInvalidate( settings, row, src, column );
  7546. } );
  7547. } );
  7548. _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
  7549. return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
  7550. } );
  7551. _api_register( 'cell().data()', function ( data ) {
  7552. var ctx = this.context;
  7553. var cell = this[0];
  7554. if ( data === undefined ) {
  7555. // Get
  7556. return ctx.length && cell.length ?
  7557. _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
  7558. undefined;
  7559. }
  7560. // Set
  7561. _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
  7562. _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
  7563. return this;
  7564. } );
  7565. /**
  7566. * Get current ordering (sorting) that has been applied to the table.
  7567. *
  7568. * @returns {array} 2D array containing the sorting information for the first
  7569. * table in the current context. Each element in the parent array represents
  7570. * a column being sorted upon (i.e. multi-sorting with two columns would have
  7571. * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
  7572. * the column index that the sorting condition applies to, the second is the
  7573. * direction of the sort (`desc` or `asc`) and, optionally, the third is the
  7574. * index of the sorting order from the `column.sorting` initialisation array.
  7575. *//**
  7576. * Set the ordering for the table.
  7577. *
  7578. * @param {integer} order Column index to sort upon.
  7579. * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
  7580. * @returns {DataTables.Api} this
  7581. *//**
  7582. * Set the ordering for the table.
  7583. *
  7584. * @param {array} order 1D array of sorting information to be applied.
  7585. * @param {array} [...] Optional additional sorting conditions
  7586. * @returns {DataTables.Api} this
  7587. *//**
  7588. * Set the ordering for the table.
  7589. *
  7590. * @param {array} order 2D array of sorting information to be applied.
  7591. * @returns {DataTables.Api} this
  7592. */
  7593. _api_register( 'order()', function ( order, dir ) {
  7594. var ctx = this.context;
  7595. if ( order === undefined ) {
  7596. // get
  7597. return ctx.length !== 0 ?
  7598. ctx[0].aaSorting :
  7599. undefined;
  7600. }
  7601. // set
  7602. if ( typeof order === 'number' ) {
  7603. // Simple column / direction passed in
  7604. order = [ [ order, dir ] ];
  7605. }
  7606. else if ( order.length && ! $.isArray( order[0] ) ) {
  7607. // Arguments passed in (list of 1D arrays)
  7608. order = Array.prototype.slice.call( arguments );
  7609. }
  7610. // otherwise a 2D array was passed in
  7611. return this.iterator( 'table', function ( settings ) {
  7612. settings.aaSorting = order.slice();
  7613. } );
  7614. } );
  7615. /**
  7616. * Attach a sort listener to an element for a given column
  7617. *
  7618. * @param {node|jQuery|string} node Identifier for the element(s) to attach the
  7619. * listener to. This can take the form of a single DOM node, a jQuery
  7620. * collection of nodes or a jQuery selector which will identify the node(s).
  7621. * @param {integer} column the column that a click on this node will sort on
  7622. * @param {function} [callback] callback function when sort is run
  7623. * @returns {DataTables.Api} this
  7624. */
  7625. _api_register( 'order.listener()', function ( node, column, callback ) {
  7626. return this.iterator( 'table', function ( settings ) {
  7627. _fnSortAttachListener( settings, node, column, callback );
  7628. } );
  7629. } );
  7630. _api_register( 'order.fixed()', function ( set ) {
  7631. if ( ! set ) {
  7632. var ctx = this.context;
  7633. var fixed = ctx.length ?
  7634. ctx[0].aaSortingFixed :
  7635. undefined;
  7636. return $.isArray( fixed ) ?
  7637. { pre: fixed } :
  7638. fixed;
  7639. }
  7640. return this.iterator( 'table', function ( settings ) {
  7641. settings.aaSortingFixed = $.extend( true, {}, set );
  7642. } );
  7643. } );
  7644. // Order by the selected column(s)
  7645. _api_register( [
  7646. 'columns().order()',
  7647. 'column().order()'
  7648. ], function ( dir ) {
  7649. var that = this;
  7650. return this.iterator( 'table', function ( settings, i ) {
  7651. var sort = [];
  7652. $.each( that[i], function (j, col) {
  7653. sort.push( [ col, dir ] );
  7654. } );
  7655. settings.aaSorting = sort;
  7656. } );
  7657. } );
  7658. _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
  7659. var ctx = this.context;
  7660. if ( input === undefined ) {
  7661. // get
  7662. return ctx.length !== 0 ?
  7663. ctx[0].oPreviousSearch.sSearch :
  7664. undefined;
  7665. }
  7666. // set
  7667. return this.iterator( 'table', function ( settings ) {
  7668. if ( ! settings.oFeatures.bFilter ) {
  7669. return;
  7670. }
  7671. _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
  7672. "sSearch": input+"",
  7673. "bRegex": regex === null ? false : regex,
  7674. "bSmart": smart === null ? true : smart,
  7675. "bCaseInsensitive": caseInsen === null ? true : caseInsen
  7676. } ), 1 );
  7677. } );
  7678. } );
  7679. _api_registerPlural(
  7680. 'columns().search()',
  7681. 'column().search()',
  7682. function ( input, regex, smart, caseInsen ) {
  7683. return this.iterator( 'column', function ( settings, column ) {
  7684. var preSearch = settings.aoPreSearchCols;
  7685. if ( input === undefined ) {
  7686. // get
  7687. return preSearch[ column ].sSearch;
  7688. }
  7689. // set
  7690. if ( ! settings.oFeatures.bFilter ) {
  7691. return;
  7692. }
  7693. $.extend( preSearch[ column ], {
  7694. "sSearch": input+"",
  7695. "bRegex": regex === null ? false : regex,
  7696. "bSmart": smart === null ? true : smart,
  7697. "bCaseInsensitive": caseInsen === null ? true : caseInsen
  7698. } );
  7699. _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
  7700. } );
  7701. }
  7702. );
  7703. /*
  7704. * State API methods
  7705. */
  7706. _api_register( 'state()', function () {
  7707. return this.context.length ?
  7708. this.context[0].oSavedState :
  7709. null;
  7710. } );
  7711. _api_register( 'state.clear()', function () {
  7712. return this.iterator( 'table', function ( settings ) {
  7713. // Save an empty object
  7714. settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
  7715. } );
  7716. } );
  7717. _api_register( 'state.loaded()', function () {
  7718. return this.context.length ?
  7719. this.context[0].oLoadedState :
  7720. null;
  7721. } );
  7722. _api_register( 'state.save()', function () {
  7723. return this.iterator( 'table', function ( settings ) {
  7724. _fnSaveState( settings );
  7725. } );
  7726. } );
  7727. /**
  7728. * Provide a common method for plug-ins to check the version of DataTables being
  7729. * used, in order to ensure compatibility.
  7730. *
  7731. * @param {string} version Version string to check for, in the format "X.Y.Z".
  7732. * Note that the formats "X" and "X.Y" are also acceptable.
  7733. * @returns {boolean} true if this version of DataTables is greater or equal to
  7734. * the required version, or false if this version of DataTales is not
  7735. * suitable
  7736. * @static
  7737. * @dtopt API-Static
  7738. *
  7739. * @example
  7740. * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
  7741. */
  7742. DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
  7743. {
  7744. var aThis = DataTable.version.split('.');
  7745. var aThat = version.split('.');
  7746. var iThis, iThat;
  7747. for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
  7748. iThis = parseInt( aThis[i], 10 ) || 0;
  7749. iThat = parseInt( aThat[i], 10 ) || 0;
  7750. // Parts are the same, keep comparing
  7751. if (iThis === iThat) {
  7752. continue;
  7753. }
  7754. // Parts are different, return immediately
  7755. return iThis > iThat;
  7756. }
  7757. return true;
  7758. };
  7759. /**
  7760. * Check if a `<table>` node is a DataTable table already or not.
  7761. *
  7762. * @param {node|jquery|string} table Table node, jQuery object or jQuery
  7763. * selector for the table to test. Note that if more than more than one
  7764. * table is passed on, only the first will be checked
  7765. * @returns {boolean} true the table given is a DataTable, or false otherwise
  7766. * @static
  7767. * @dtopt API-Static
  7768. *
  7769. * @example
  7770. * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
  7771. * $('#example').dataTable();
  7772. * }
  7773. */
  7774. DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
  7775. {
  7776. var t = $(table).get(0);
  7777. var is = false;
  7778. if ( table instanceof DataTable.Api ) {
  7779. return true;
  7780. }
  7781. $.each( DataTable.settings, function (i, o) {
  7782. var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
  7783. var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
  7784. if ( o.nTable === t || head === t || foot === t ) {
  7785. is = true;
  7786. }
  7787. } );
  7788. return is;
  7789. };
  7790. /**
  7791. * Get all DataTable tables that have been initialised - optionally you can
  7792. * select to get only currently visible tables.
  7793. *
  7794. * @param {boolean} [visible=false] Flag to indicate if you want all (default)
  7795. * or visible tables only.
  7796. * @returns {array} Array of `table` nodes (not DataTable instances) which are
  7797. * DataTables
  7798. * @static
  7799. * @dtopt API-Static
  7800. *
  7801. * @example
  7802. * $.each( $.fn.dataTable.tables(true), function () {
  7803. * $(table).DataTable().columns.adjust();
  7804. * } );
  7805. */
  7806. DataTable.tables = DataTable.fnTables = function ( visible )
  7807. {
  7808. var api = false;
  7809. if ( $.isPlainObject( visible ) ) {
  7810. api = visible.api;
  7811. visible = visible.visible;
  7812. }
  7813. var a = $.map( DataTable.settings, function (o) {
  7814. if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
  7815. return o.nTable;
  7816. }
  7817. } );
  7818. return api ?
  7819. new _Api( a ) :
  7820. a;
  7821. };
  7822. /**
  7823. * Convert from camel case parameters to Hungarian notation. This is made public
  7824. * for the extensions to provide the same ability as DataTables core to accept
  7825. * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
  7826. * parameters.
  7827. *
  7828. * @param {object} src The model object which holds all parameters that can be
  7829. * mapped.
  7830. * @param {object} user The object to convert from camel case to Hungarian.
  7831. * @param {boolean} force When set to `true`, properties which already have a
  7832. * Hungarian value in the `user` object will be overwritten. Otherwise they
  7833. * won't be.
  7834. */
  7835. DataTable.camelToHungarian = _fnCamelToHungarian;
  7836. /**
  7837. *
  7838. */
  7839. _api_register( '$()', function ( selector, opts ) {
  7840. var
  7841. rows = this.rows( opts ).nodes(), // Get all rows
  7842. jqRows = $(rows);
  7843. return $( [].concat(
  7844. jqRows.filter( selector ).toArray(),
  7845. jqRows.find( selector ).toArray()
  7846. ) );
  7847. } );
  7848. // jQuery functions to operate on the tables
  7849. $.each( [ 'on', 'one', 'off' ], function (i, key) {
  7850. _api_register( key+'()', function ( /* event, handler */ ) {
  7851. var args = Array.prototype.slice.call(arguments);
  7852. // Add the `dt` namespace automatically if it isn't already present
  7853. args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
  7854. return ! e.match(/\.dt\b/) ?
  7855. e+'.dt' :
  7856. e;
  7857. } ).join( ' ' );
  7858. var inst = $( this.tables().nodes() );
  7859. inst[key].apply( inst, args );
  7860. return this;
  7861. } );
  7862. } );
  7863. _api_register( 'clear()', function () {
  7864. return this.iterator( 'table', function ( settings ) {
  7865. _fnClearTable( settings );
  7866. } );
  7867. } );
  7868. _api_register( 'settings()', function () {
  7869. return new _Api( this.context, this.context );
  7870. } );
  7871. _api_register( 'init()', function () {
  7872. var ctx = this.context;
  7873. return ctx.length ? ctx[0].oInit : null;
  7874. } );
  7875. _api_register( 'data()', function () {
  7876. return this.iterator( 'table', function ( settings ) {
  7877. return _pluck( settings.aoData, '_aData' );
  7878. } ).flatten();
  7879. } );
  7880. _api_register( 'destroy()', function ( remove ) {
  7881. remove = remove || false;
  7882. return this.iterator( 'table', function ( settings ) {
  7883. var orig = settings.nTableWrapper.parentNode;
  7884. var classes = settings.oClasses;
  7885. var table = settings.nTable;
  7886. var tbody = settings.nTBody;
  7887. var thead = settings.nTHead;
  7888. var tfoot = settings.nTFoot;
  7889. var jqTable = $(table);
  7890. var jqTbody = $(tbody);
  7891. var jqWrapper = $(settings.nTableWrapper);
  7892. var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
  7893. var i, ien;
  7894. // Flag to note that the table is currently being destroyed - no action
  7895. // should be taken
  7896. settings.bDestroying = true;
  7897. // Fire off the destroy callbacks for plug-ins etc
  7898. _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
  7899. // If not being removed from the document, make all columns visible
  7900. if ( ! remove ) {
  7901. new _Api( settings ).columns().visible( true );
  7902. }
  7903. // Blitz all `DT` namespaced events (these are internal events, the
  7904. // lowercase, `dt` events are user subscribed and they are responsible
  7905. // for removing them
  7906. jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
  7907. $(window).off('.DT-'+settings.sInstance);
  7908. // When scrolling we had to break the table up - restore it
  7909. if ( table != thead.parentNode ) {
  7910. jqTable.children('thead').detach();
  7911. jqTable.append( thead );
  7912. }
  7913. if ( tfoot && table != tfoot.parentNode ) {
  7914. jqTable.children('tfoot').detach();
  7915. jqTable.append( tfoot );
  7916. }
  7917. settings.aaSorting = [];
  7918. settings.aaSortingFixed = [];
  7919. _fnSortingClasses( settings );
  7920. $( rows ).removeClass( settings.asStripeClasses.join(' ') );
  7921. $('th, td', thead).removeClass( classes.sSortable+' '+
  7922. classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
  7923. );
  7924. // Add the TR elements back into the table in their original order
  7925. jqTbody.children().detach();
  7926. jqTbody.append( rows );
  7927. // Remove the DataTables generated nodes, events and classes
  7928. var removedMethod = remove ? 'remove' : 'detach';
  7929. jqTable[ removedMethod ]();
  7930. jqWrapper[ removedMethod ]();
  7931. // If we need to reattach the table to the document
  7932. if ( ! remove && orig ) {
  7933. // insertBefore acts like appendChild if !arg[1]
  7934. orig.insertBefore( table, settings.nTableReinsertBefore );
  7935. // Restore the width of the original table - was read from the style property,
  7936. // so we can restore directly to that
  7937. jqTable
  7938. .css( 'width', settings.sDestroyWidth )
  7939. .removeClass( classes.sTable );
  7940. // If the were originally stripe classes - then we add them back here.
  7941. // Note this is not fool proof (for example if not all rows had stripe
  7942. // classes - but it's a good effort without getting carried away
  7943. ien = settings.asDestroyStripes.length;
  7944. if ( ien ) {
  7945. jqTbody.children().each( function (i) {
  7946. $(this).addClass( settings.asDestroyStripes[i % ien] );
  7947. } );
  7948. }
  7949. }
  7950. /* Remove the settings object from the settings array */
  7951. var idx = $.inArray( settings, DataTable.settings );
  7952. if ( idx !== -1 ) {
  7953. DataTable.settings.splice( idx, 1 );
  7954. }
  7955. } );
  7956. } );
  7957. // Add the `every()` method for rows, columns and cells in a compact form
  7958. $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
  7959. _api_register( type+'s().every()', function ( fn ) {
  7960. var opts = this.selector.opts;
  7961. var api = this;
  7962. return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
  7963. // Rows and columns:
  7964. // arg1 - index
  7965. // arg2 - table counter
  7966. // arg3 - loop counter
  7967. // arg4 - undefined
  7968. // Cells:
  7969. // arg1 - row index
  7970. // arg2 - column index
  7971. // arg3 - table counter
  7972. // arg4 - loop counter
  7973. fn.call(
  7974. api[ type ](
  7975. arg1,
  7976. type==='cell' ? arg2 : opts,
  7977. type==='cell' ? opts : undefined
  7978. ),
  7979. arg1, arg2, arg3, arg4
  7980. );
  7981. } );
  7982. } );
  7983. } );
  7984. // i18n method for extensions to be able to use the language object from the
  7985. // DataTable
  7986. _api_register( 'i18n()', function ( token, def, plural ) {
  7987. var ctx = this.context[0];
  7988. var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
  7989. if ( resolved === undefined ) {
  7990. resolved = def;
  7991. }
  7992. if ( plural !== undefined && $.isPlainObject( resolved ) ) {
  7993. resolved = resolved[ plural ] !== undefined ?
  7994. resolved[ plural ] :
  7995. resolved._;
  7996. }
  7997. return resolved.replace( '%d', plural ); // nb: plural might be undefined,
  7998. } );
  7999. /**
  8000. * Version string for plug-ins to check compatibility. Allowed format is
  8001. * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
  8002. * only for non-release builds. See http://semver.org/ for more information.
  8003. * @member
  8004. * @type string
  8005. * @default Version number
  8006. */
  8007. DataTable.version = "1.10.19";
  8008. /**
  8009. * Private data store, containing all of the settings objects that are
  8010. * created for the tables on a given page.
  8011. *
  8012. * Note that the `DataTable.settings` object is aliased to
  8013. * `jQuery.fn.dataTableExt` through which it may be accessed and
  8014. * manipulated, or `jQuery.fn.dataTable.settings`.
  8015. * @member
  8016. * @type array
  8017. * @default []
  8018. * @private
  8019. */
  8020. DataTable.settings = [];
  8021. /**
  8022. * Object models container, for the various models that DataTables has
  8023. * available to it. These models define the objects that are used to hold
  8024. * the active state and configuration of the table.
  8025. * @namespace
  8026. */
  8027. DataTable.models = {};
  8028. /**
  8029. * Template object for the way in which DataTables holds information about
  8030. * search information for the global filter and individual column filters.
  8031. * @namespace
  8032. */
  8033. DataTable.models.oSearch = {
  8034. /**
  8035. * Flag to indicate if the filtering should be case insensitive or not
  8036. * @type boolean
  8037. * @default true
  8038. */
  8039. "bCaseInsensitive": true,
  8040. /**
  8041. * Applied search term
  8042. * @type string
  8043. * @default <i>Empty string</i>
  8044. */
  8045. "sSearch": "",
  8046. /**
  8047. * Flag to indicate if the search term should be interpreted as a
  8048. * regular expression (true) or not (false) and therefore and special
  8049. * regex characters escaped.
  8050. * @type boolean
  8051. * @default false
  8052. */
  8053. "bRegex": false,
  8054. /**
  8055. * Flag to indicate if DataTables is to use its smart filtering or not.
  8056. * @type boolean
  8057. * @default true
  8058. */
  8059. "bSmart": true
  8060. };
  8061. /**
  8062. * Template object for the way in which DataTables holds information about
  8063. * each individual row. This is the object format used for the settings
  8064. * aoData array.
  8065. * @namespace
  8066. */
  8067. DataTable.models.oRow = {
  8068. /**
  8069. * TR element for the row
  8070. * @type node
  8071. * @default null
  8072. */
  8073. "nTr": null,
  8074. /**
  8075. * Array of TD elements for each row. This is null until the row has been
  8076. * created.
  8077. * @type array nodes
  8078. * @default []
  8079. */
  8080. "anCells": null,
  8081. /**
  8082. * Data object from the original data source for the row. This is either
  8083. * an array if using the traditional form of DataTables, or an object if
  8084. * using mData options. The exact type will depend on the passed in
  8085. * data from the data source, or will be an array if using DOM a data
  8086. * source.
  8087. * @type array|object
  8088. * @default []
  8089. */
  8090. "_aData": [],
  8091. /**
  8092. * Sorting data cache - this array is ostensibly the same length as the
  8093. * number of columns (although each index is generated only as it is
  8094. * needed), and holds the data that is used for sorting each column in the
  8095. * row. We do this cache generation at the start of the sort in order that
  8096. * the formatting of the sort data need be done only once for each cell
  8097. * per sort. This array should not be read from or written to by anything
  8098. * other than the master sorting methods.
  8099. * @type array
  8100. * @default null
  8101. * @private
  8102. */
  8103. "_aSortData": null,
  8104. /**
  8105. * Per cell filtering data cache. As per the sort data cache, used to
  8106. * increase the performance of the filtering in DataTables
  8107. * @type array
  8108. * @default null
  8109. * @private
  8110. */
  8111. "_aFilterData": null,
  8112. /**
  8113. * Filtering data cache. This is the same as the cell filtering cache, but
  8114. * in this case a string rather than an array. This is easily computed with
  8115. * a join on `_aFilterData`, but is provided as a cache so the join isn't
  8116. * needed on every search (memory traded for performance)
  8117. * @type array
  8118. * @default null
  8119. * @private
  8120. */
  8121. "_sFilterRow": null,
  8122. /**
  8123. * Cache of the class name that DataTables has applied to the row, so we
  8124. * can quickly look at this variable rather than needing to do a DOM check
  8125. * on className for the nTr property.
  8126. * @type string
  8127. * @default <i>Empty string</i>
  8128. * @private
  8129. */
  8130. "_sRowStripe": "",
  8131. /**
  8132. * Denote if the original data source was from the DOM, or the data source
  8133. * object. This is used for invalidating data, so DataTables can
  8134. * automatically read data from the original source, unless uninstructed
  8135. * otherwise.
  8136. * @type string
  8137. * @default null
  8138. * @private
  8139. */
  8140. "src": null,
  8141. /**
  8142. * Index in the aoData array. This saves an indexOf lookup when we have the
  8143. * object, but want to know the index
  8144. * @type integer
  8145. * @default -1
  8146. * @private
  8147. */
  8148. "idx": -1
  8149. };
  8150. /**
  8151. * Template object for the column information object in DataTables. This object
  8152. * is held in the settings aoColumns array and contains all the information that
  8153. * DataTables needs about each individual column.
  8154. *
  8155. * Note that this object is related to {@link DataTable.defaults.column}
  8156. * but this one is the internal data store for DataTables's cache of columns.
  8157. * It should NOT be manipulated outside of DataTables. Any configuration should
  8158. * be done through the initialisation options.
  8159. * @namespace
  8160. */
  8161. DataTable.models.oColumn = {
  8162. /**
  8163. * Column index. This could be worked out on-the-fly with $.inArray, but it
  8164. * is faster to just hold it as a variable
  8165. * @type integer
  8166. * @default null
  8167. */
  8168. "idx": null,
  8169. /**
  8170. * A list of the columns that sorting should occur on when this column
  8171. * is sorted. That this property is an array allows multi-column sorting
  8172. * to be defined for a column (for example first name / last name columns
  8173. * would benefit from this). The values are integers pointing to the
  8174. * columns to be sorted on (typically it will be a single integer pointing
  8175. * at itself, but that doesn't need to be the case).
  8176. * @type array
  8177. */
  8178. "aDataSort": null,
  8179. /**
  8180. * Define the sorting directions that are applied to the column, in sequence
  8181. * as the column is repeatedly sorted upon - i.e. the first value is used
  8182. * as the sorting direction when the column if first sorted (clicked on).
  8183. * Sort it again (click again) and it will move on to the next index.
  8184. * Repeat until loop.
  8185. * @type array
  8186. */
  8187. "asSorting": null,
  8188. /**
  8189. * Flag to indicate if the column is searchable, and thus should be included
  8190. * in the filtering or not.
  8191. * @type boolean
  8192. */
  8193. "bSearchable": null,
  8194. /**
  8195. * Flag to indicate if the column is sortable or not.
  8196. * @type boolean
  8197. */
  8198. "bSortable": null,
  8199. /**
  8200. * Flag to indicate if the column is currently visible in the table or not
  8201. * @type boolean
  8202. */
  8203. "bVisible": null,
  8204. /**
  8205. * Store for manual type assignment using the `column.type` option. This
  8206. * is held in store so we can manipulate the column's `sType` property.
  8207. * @type string
  8208. * @default null
  8209. * @private
  8210. */
  8211. "_sManualType": null,
  8212. /**
  8213. * Flag to indicate if HTML5 data attributes should be used as the data
  8214. * source for filtering or sorting. True is either are.
  8215. * @type boolean
  8216. * @default false
  8217. * @private
  8218. */
  8219. "_bAttrSrc": false,
  8220. /**
  8221. * Developer definable function that is called whenever a cell is created (Ajax source,
  8222. * etc) or processed for input (DOM source). This can be used as a compliment to mRender
  8223. * allowing you to modify the DOM element (add background colour for example) when the
  8224. * element is available.
  8225. * @type function
  8226. * @param {element} nTd The TD node that has been created
  8227. * @param {*} sData The Data for the cell
  8228. * @param {array|object} oData The data for the whole row
  8229. * @param {int} iRow The row index for the aoData data store
  8230. * @default null
  8231. */
  8232. "fnCreatedCell": null,
  8233. /**
  8234. * Function to get data from a cell in a column. You should <b>never</b>
  8235. * access data directly through _aData internally in DataTables - always use
  8236. * the method attached to this property. It allows mData to function as
  8237. * required. This function is automatically assigned by the column
  8238. * initialisation method
  8239. * @type function
  8240. * @param {array|object} oData The data array/object for the array
  8241. * (i.e. aoData[]._aData)
  8242. * @param {string} sSpecific The specific data type you want to get -
  8243. * 'display', 'type' 'filter' 'sort'
  8244. * @returns {*} The data for the cell from the given row's data
  8245. * @default null
  8246. */
  8247. "fnGetData": null,
  8248. /**
  8249. * Function to set data for a cell in the column. You should <b>never</b>
  8250. * set the data directly to _aData internally in DataTables - always use
  8251. * this method. It allows mData to function as required. This function
  8252. * is automatically assigned by the column initialisation method
  8253. * @type function
  8254. * @param {array|object} oData The data array/object for the array
  8255. * (i.e. aoData[]._aData)
  8256. * @param {*} sValue Value to set
  8257. * @default null
  8258. */
  8259. "fnSetData": null,
  8260. /**
  8261. * Property to read the value for the cells in the column from the data
  8262. * source array / object. If null, then the default content is used, if a
  8263. * function is given then the return from the function is used.
  8264. * @type function|int|string|null
  8265. * @default null
  8266. */
  8267. "mData": null,
  8268. /**
  8269. * Partner property to mData which is used (only when defined) to get
  8270. * the data - i.e. it is basically the same as mData, but without the
  8271. * 'set' option, and also the data fed to it is the result from mData.
  8272. * This is the rendering method to match the data method of mData.
  8273. * @type function|int|string|null
  8274. * @default null
  8275. */
  8276. "mRender": null,
  8277. /**
  8278. * Unique header TH/TD element for this column - this is what the sorting
  8279. * listener is attached to (if sorting is enabled.)
  8280. * @type node
  8281. * @default null
  8282. */
  8283. "nTh": null,
  8284. /**
  8285. * Unique footer TH/TD element for this column (if there is one). Not used
  8286. * in DataTables as such, but can be used for plug-ins to reference the
  8287. * footer for each column.
  8288. * @type node
  8289. * @default null
  8290. */
  8291. "nTf": null,
  8292. /**
  8293. * The class to apply to all TD elements in the table's TBODY for the column
  8294. * @type string
  8295. * @default null
  8296. */
  8297. "sClass": null,
  8298. /**
  8299. * When DataTables calculates the column widths to assign to each column,
  8300. * it finds the longest string in each column and then constructs a
  8301. * temporary table and reads the widths from that. The problem with this
  8302. * is that "mmm" is much wider then "iiii", but the latter is a longer
  8303. * string - thus the calculation can go wrong (doing it properly and putting
  8304. * it into an DOM object and measuring that is horribly(!) slow). Thus as
  8305. * a "work around" we provide this option. It will append its value to the
  8306. * text that is found to be the longest string for the column - i.e. padding.
  8307. * @type string
  8308. */
  8309. "sContentPadding": null,
  8310. /**
  8311. * Allows a default value to be given for a column's data, and will be used
  8312. * whenever a null data source is encountered (this can be because mData
  8313. * is set to null, or because the data source itself is null).
  8314. * @type string
  8315. * @default null
  8316. */
  8317. "sDefaultContent": null,
  8318. /**
  8319. * Name for the column, allowing reference to the column by name as well as
  8320. * by index (needs a lookup to work by name).
  8321. * @type string
  8322. */
  8323. "sName": null,
  8324. /**
  8325. * Custom sorting data type - defines which of the available plug-ins in
  8326. * afnSortData the custom sorting will use - if any is defined.
  8327. * @type string
  8328. * @default std
  8329. */
  8330. "sSortDataType": 'std',
  8331. /**
  8332. * Class to be applied to the header element when sorting on this column
  8333. * @type string
  8334. * @default null
  8335. */
  8336. "sSortingClass": null,
  8337. /**
  8338. * Class to be applied to the header element when sorting on this column -
  8339. * when jQuery UI theming is used.
  8340. * @type string
  8341. * @default null
  8342. */
  8343. "sSortingClassJUI": null,
  8344. /**
  8345. * Title of the column - what is seen in the TH element (nTh).
  8346. * @type string
  8347. */
  8348. "sTitle": null,
  8349. /**
  8350. * Column sorting and filtering type
  8351. * @type string
  8352. * @default null
  8353. */
  8354. "sType": null,
  8355. /**
  8356. * Width of the column
  8357. * @type string
  8358. * @default null
  8359. */
  8360. "sWidth": null,
  8361. /**
  8362. * Width of the column when it was first "encountered"
  8363. * @type string
  8364. * @default null
  8365. */
  8366. "sWidthOrig": null
  8367. };
  8368. /*
  8369. * Developer note: The properties of the object below are given in Hungarian
  8370. * notation, that was used as the interface for DataTables prior to v1.10, however
  8371. * from v1.10 onwards the primary interface is camel case. In order to avoid
  8372. * breaking backwards compatibility utterly with this change, the Hungarian
  8373. * version is still, internally the primary interface, but is is not documented
  8374. * - hence the @name tags in each doc comment. This allows a Javascript function
  8375. * to create a map from Hungarian notation to camel case (going the other direction
  8376. * would require each property to be listed, which would at around 3K to the size
  8377. * of DataTables, while this method is about a 0.5K hit.
  8378. *
  8379. * Ultimately this does pave the way for Hungarian notation to be dropped
  8380. * completely, but that is a massive amount of work and will break current
  8381. * installs (therefore is on-hold until v2).
  8382. */
  8383. /**
  8384. * Initialisation options that can be given to DataTables at initialisation
  8385. * time.
  8386. * @namespace
  8387. */
  8388. DataTable.defaults = {
  8389. /**
  8390. * An array of data to use for the table, passed in at initialisation which
  8391. * will be used in preference to any data which is already in the DOM. This is
  8392. * particularly useful for constructing tables purely in Javascript, for
  8393. * example with a custom Ajax call.
  8394. * @type array
  8395. * @default null
  8396. *
  8397. * @dtopt Option
  8398. * @name DataTable.defaults.data
  8399. *
  8400. * @example
  8401. * // Using a 2D array data source
  8402. * $(document).ready( function () {
  8403. * $('#example').dataTable( {
  8404. * "data": [
  8405. * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
  8406. * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
  8407. * ],
  8408. * "columns": [
  8409. * { "title": "Engine" },
  8410. * { "title": "Browser" },
  8411. * { "title": "Platform" },
  8412. * { "title": "Version" },
  8413. * { "title": "Grade" }
  8414. * ]
  8415. * } );
  8416. * } );
  8417. *
  8418. * @example
  8419. * // Using an array of objects as a data source (`data`)
  8420. * $(document).ready( function () {
  8421. * $('#example').dataTable( {
  8422. * "data": [
  8423. * {
  8424. * "engine": "Trident",
  8425. * "browser": "Internet Explorer 4.0",
  8426. * "platform": "Win 95+",
  8427. * "version": 4,
  8428. * "grade": "X"
  8429. * },
  8430. * {
  8431. * "engine": "Trident",
  8432. * "browser": "Internet Explorer 5.0",
  8433. * "platform": "Win 95+",
  8434. * "version": 5,
  8435. * "grade": "C"
  8436. * }
  8437. * ],
  8438. * "columns": [
  8439. * { "title": "Engine", "data": "engine" },
  8440. * { "title": "Browser", "data": "browser" },
  8441. * { "title": "Platform", "data": "platform" },
  8442. * { "title": "Version", "data": "version" },
  8443. * { "title": "Grade", "data": "grade" }
  8444. * ]
  8445. * } );
  8446. * } );
  8447. */
  8448. "aaData": null,
  8449. /**
  8450. * If ordering is enabled, then DataTables will perform a first pass sort on
  8451. * initialisation. You can define which column(s) the sort is performed
  8452. * upon, and the sorting direction, with this variable. The `sorting` array
  8453. * should contain an array for each column to be sorted initially containing
  8454. * the column's index and a direction string ('asc' or 'desc').
  8455. * @type array
  8456. * @default [[0,'asc']]
  8457. *
  8458. * @dtopt Option
  8459. * @name DataTable.defaults.order
  8460. *
  8461. * @example
  8462. * // Sort by 3rd column first, and then 4th column
  8463. * $(document).ready( function() {
  8464. * $('#example').dataTable( {
  8465. * "order": [[2,'asc'], [3,'desc']]
  8466. * } );
  8467. * } );
  8468. *
  8469. * // No initial sorting
  8470. * $(document).ready( function() {
  8471. * $('#example').dataTable( {
  8472. * "order": []
  8473. * } );
  8474. * } );
  8475. */
  8476. "aaSorting": [[0,'asc']],
  8477. /**
  8478. * This parameter is basically identical to the `sorting` parameter, but
  8479. * cannot be overridden by user interaction with the table. What this means
  8480. * is that you could have a column (visible or hidden) which the sorting
  8481. * will always be forced on first - any sorting after that (from the user)
  8482. * will then be performed as required. This can be useful for grouping rows
  8483. * together.
  8484. * @type array
  8485. * @default null
  8486. *
  8487. * @dtopt Option
  8488. * @name DataTable.defaults.orderFixed
  8489. *
  8490. * @example
  8491. * $(document).ready( function() {
  8492. * $('#example').dataTable( {
  8493. * "orderFixed": [[0,'asc']]
  8494. * } );
  8495. * } )
  8496. */
  8497. "aaSortingFixed": [],
  8498. /**
  8499. * DataTables can be instructed to load data to display in the table from a
  8500. * Ajax source. This option defines how that Ajax call is made and where to.
  8501. *
  8502. * The `ajax` property has three different modes of operation, depending on
  8503. * how it is defined. These are:
  8504. *
  8505. * * `string` - Set the URL from where the data should be loaded from.
  8506. * * `object` - Define properties for `jQuery.ajax`.
  8507. * * `function` - Custom data get function
  8508. *
  8509. * `string`
  8510. * --------
  8511. *
  8512. * As a string, the `ajax` property simply defines the URL from which
  8513. * DataTables will load data.
  8514. *
  8515. * `object`
  8516. * --------
  8517. *
  8518. * As an object, the parameters in the object are passed to
  8519. * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
  8520. * of the Ajax request. DataTables has a number of default parameters which
  8521. * you can override using this option. Please refer to the jQuery
  8522. * documentation for a full description of the options available, although
  8523. * the following parameters provide additional options in DataTables or
  8524. * require special consideration:
  8525. *
  8526. * * `data` - As with jQuery, `data` can be provided as an object, but it
  8527. * can also be used as a function to manipulate the data DataTables sends
  8528. * to the server. The function takes a single parameter, an object of
  8529. * parameters with the values that DataTables has readied for sending. An
  8530. * object may be returned which will be merged into the DataTables
  8531. * defaults, or you can add the items to the object that was passed in and
  8532. * not return anything from the function. This supersedes `fnServerParams`
  8533. * from DataTables 1.9-.
  8534. *
  8535. * * `dataSrc` - By default DataTables will look for the property `data` (or
  8536. * `aaData` for compatibility with DataTables 1.9-) when obtaining data
  8537. * from an Ajax source or for server-side processing - this parameter
  8538. * allows that property to be changed. You can use Javascript dotted
  8539. * object notation to get a data source for multiple levels of nesting, or
  8540. * it my be used as a function. As a function it takes a single parameter,
  8541. * the JSON returned from the server, which can be manipulated as
  8542. * required, with the returned value being that used by DataTables as the
  8543. * data source for the table. This supersedes `sAjaxDataProp` from
  8544. * DataTables 1.9-.
  8545. *
  8546. * * `success` - Should not be overridden it is used internally in
  8547. * DataTables. To manipulate / transform the data returned by the server
  8548. * use `ajax.dataSrc`, or use `ajax` as a function (see below).
  8549. *
  8550. * `function`
  8551. * ----------
  8552. *
  8553. * As a function, making the Ajax call is left up to yourself allowing
  8554. * complete control of the Ajax request. Indeed, if desired, a method other
  8555. * than Ajax could be used to obtain the required data, such as Web storage
  8556. * or an AIR database.
  8557. *
  8558. * The function is given four parameters and no return is required. The
  8559. * parameters are:
  8560. *
  8561. * 1. _object_ - Data to send to the server
  8562. * 2. _function_ - Callback function that must be executed when the required
  8563. * data has been obtained. That data should be passed into the callback
  8564. * as the only parameter
  8565. * 3. _object_ - DataTables settings object for the table
  8566. *
  8567. * Note that this supersedes `fnServerData` from DataTables 1.9-.
  8568. *
  8569. * @type string|object|function
  8570. * @default null
  8571. *
  8572. * @dtopt Option
  8573. * @name DataTable.defaults.ajax
  8574. * @since 1.10.0
  8575. *
  8576. * @example
  8577. * // Get JSON data from a file via Ajax.
  8578. * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
  8579. * $('#example').dataTable( {
  8580. * "ajax": "data.json"
  8581. * } );
  8582. *
  8583. * @example
  8584. * // Get JSON data from a file via Ajax, using `dataSrc` to change
  8585. * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
  8586. * $('#example').dataTable( {
  8587. * "ajax": {
  8588. * "url": "data.json",
  8589. * "dataSrc": "tableData"
  8590. * }
  8591. * } );
  8592. *
  8593. * @example
  8594. * // Get JSON data from a file via Ajax, using `dataSrc` to read data
  8595. * // from a plain array rather than an array in an object
  8596. * $('#example').dataTable( {
  8597. * "ajax": {
  8598. * "url": "data.json",
  8599. * "dataSrc": ""
  8600. * }
  8601. * } );
  8602. *
  8603. * @example
  8604. * // Manipulate the data returned from the server - add a link to data
  8605. * // (note this can, should, be done using `render` for the column - this
  8606. * // is just a simple example of how the data can be manipulated).
  8607. * $('#example').dataTable( {
  8608. * "ajax": {
  8609. * "url": "data.json",
  8610. * "dataSrc": function ( json ) {
  8611. * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
  8612. * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
  8613. * }
  8614. * return json;
  8615. * }
  8616. * }
  8617. * } );
  8618. *
  8619. * @example
  8620. * // Add data to the request
  8621. * $('#example').dataTable( {
  8622. * "ajax": {
  8623. * "url": "data.json",
  8624. * "data": function ( d ) {
  8625. * return {
  8626. * "extra_search": $('#extra').val()
  8627. * };
  8628. * }
  8629. * }
  8630. * } );
  8631. *
  8632. * @example
  8633. * // Send request as POST
  8634. * $('#example').dataTable( {
  8635. * "ajax": {
  8636. * "url": "data.json",
  8637. * "type": "POST"
  8638. * }
  8639. * } );
  8640. *
  8641. * @example
  8642. * // Get the data from localStorage (could interface with a form for
  8643. * // adding, editing and removing rows).
  8644. * $('#example').dataTable( {
  8645. * "ajax": function (data, callback, settings) {
  8646. * callback(
  8647. * JSON.parse( localStorage.getItem('dataTablesData') )
  8648. * );
  8649. * }
  8650. * } );
  8651. */
  8652. "ajax": null,
  8653. /**
  8654. * This parameter allows you to readily specify the entries in the length drop
  8655. * down menu that DataTables shows when pagination is enabled. It can be
  8656. * either a 1D array of options which will be used for both the displayed
  8657. * option and the value, or a 2D array which will use the array in the first
  8658. * position as the value, and the array in the second position as the
  8659. * displayed options (useful for language strings such as 'All').
  8660. *
  8661. * Note that the `pageLength` property will be automatically set to the
  8662. * first value given in this array, unless `pageLength` is also provided.
  8663. * @type array
  8664. * @default [ 10, 25, 50, 100 ]
  8665. *
  8666. * @dtopt Option
  8667. * @name DataTable.defaults.lengthMenu
  8668. *
  8669. * @example
  8670. * $(document).ready( function() {
  8671. * $('#example').dataTable( {
  8672. * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
  8673. * } );
  8674. * } );
  8675. */
  8676. "aLengthMenu": [ 10, 25, 50, 100 ],
  8677. /**
  8678. * The `columns` option in the initialisation parameter allows you to define
  8679. * details about the way individual columns behave. For a full list of
  8680. * column options that can be set, please see
  8681. * {@link DataTable.defaults.column}. Note that if you use `columns` to
  8682. * define your columns, you must have an entry in the array for every single
  8683. * column that you have in your table (these can be null if you don't which
  8684. * to specify any options).
  8685. * @member
  8686. *
  8687. * @name DataTable.defaults.column
  8688. */
  8689. "aoColumns": null,
  8690. /**
  8691. * Very similar to `columns`, `columnDefs` allows you to target a specific
  8692. * column, multiple columns, or all columns, using the `targets` property of
  8693. * each object in the array. This allows great flexibility when creating
  8694. * tables, as the `columnDefs` arrays can be of any length, targeting the
  8695. * columns you specifically want. `columnDefs` may use any of the column
  8696. * options available: {@link DataTable.defaults.column}, but it _must_
  8697. * have `targets` defined in each object in the array. Values in the `targets`
  8698. * array may be:
  8699. * <ul>
  8700. * <li>a string - class name will be matched on the TH for the column</li>
  8701. * <li>0 or a positive integer - column index counting from the left</li>
  8702. * <li>a negative integer - column index counting from the right</li>
  8703. * <li>the string "_all" - all columns (i.e. assign a default)</li>
  8704. * </ul>
  8705. * @member
  8706. *
  8707. * @name DataTable.defaults.columnDefs
  8708. */
  8709. "aoColumnDefs": null,
  8710. /**
  8711. * Basically the same as `search`, this parameter defines the individual column
  8712. * filtering state at initialisation time. The array must be of the same size
  8713. * as the number of columns, and each element be an object with the parameters
  8714. * `search` and `escapeRegex` (the latter is optional). 'null' is also
  8715. * accepted and the default will be used.
  8716. * @type array
  8717. * @default []
  8718. *
  8719. * @dtopt Option
  8720. * @name DataTable.defaults.searchCols
  8721. *
  8722. * @example
  8723. * $(document).ready( function() {
  8724. * $('#example').dataTable( {
  8725. * "searchCols": [
  8726. * null,
  8727. * { "search": "My filter" },
  8728. * null,
  8729. * { "search": "^[0-9]", "escapeRegex": false }
  8730. * ]
  8731. * } );
  8732. * } )
  8733. */
  8734. "aoSearchCols": [],
  8735. /**
  8736. * An array of CSS classes that should be applied to displayed rows. This
  8737. * array may be of any length, and DataTables will apply each class
  8738. * sequentially, looping when required.
  8739. * @type array
  8740. * @default null <i>Will take the values determined by the `oClasses.stripe*`
  8741. * options</i>
  8742. *
  8743. * @dtopt Option
  8744. * @name DataTable.defaults.stripeClasses
  8745. *
  8746. * @example
  8747. * $(document).ready( function() {
  8748. * $('#example').dataTable( {
  8749. * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
  8750. * } );
  8751. * } )
  8752. */
  8753. "asStripeClasses": null,
  8754. /**
  8755. * Enable or disable automatic column width calculation. This can be disabled
  8756. * as an optimisation (it takes some time to calculate the widths) if the
  8757. * tables widths are passed in using `columns`.
  8758. * @type boolean
  8759. * @default true
  8760. *
  8761. * @dtopt Features
  8762. * @name DataTable.defaults.autoWidth
  8763. *
  8764. * @example
  8765. * $(document).ready( function () {
  8766. * $('#example').dataTable( {
  8767. * "autoWidth": false
  8768. * } );
  8769. * } );
  8770. */
  8771. "bAutoWidth": true,
  8772. /**
  8773. * Deferred rendering can provide DataTables with a huge speed boost when you
  8774. * are using an Ajax or JS data source for the table. This option, when set to
  8775. * true, will cause DataTables to defer the creation of the table elements for
  8776. * each row until they are needed for a draw - saving a significant amount of
  8777. * time.
  8778. * @type boolean
  8779. * @default false
  8780. *
  8781. * @dtopt Features
  8782. * @name DataTable.defaults.deferRender
  8783. *
  8784. * @example
  8785. * $(document).ready( function() {
  8786. * $('#example').dataTable( {
  8787. * "ajax": "sources/arrays.txt",
  8788. * "deferRender": true
  8789. * } );
  8790. * } );
  8791. */
  8792. "bDeferRender": false,
  8793. /**
  8794. * Replace a DataTable which matches the given selector and replace it with
  8795. * one which has the properties of the new initialisation object passed. If no
  8796. * table matches the selector, then the new DataTable will be constructed as
  8797. * per normal.
  8798. * @type boolean
  8799. * @default false
  8800. *
  8801. * @dtopt Options
  8802. * @name DataTable.defaults.destroy
  8803. *
  8804. * @example
  8805. * $(document).ready( function() {
  8806. * $('#example').dataTable( {
  8807. * "srollY": "200px",
  8808. * "paginate": false
  8809. * } );
  8810. *
  8811. * // Some time later....
  8812. * $('#example').dataTable( {
  8813. * "filter": false,
  8814. * "destroy": true
  8815. * } );
  8816. * } );
  8817. */
  8818. "bDestroy": false,
  8819. /**
  8820. * Enable or disable filtering of data. Filtering in DataTables is "smart" in
  8821. * that it allows the end user to input multiple words (space separated) and
  8822. * will match a row containing those words, even if not in the order that was
  8823. * specified (this allow matching across multiple columns). Note that if you
  8824. * wish to use filtering in DataTables this must remain 'true' - to remove the
  8825. * default filtering input box and retain filtering abilities, please use
  8826. * {@link DataTable.defaults.dom}.
  8827. * @type boolean
  8828. * @default true
  8829. *
  8830. * @dtopt Features
  8831. * @name DataTable.defaults.searching
  8832. *
  8833. * @example
  8834. * $(document).ready( function () {
  8835. * $('#example').dataTable( {
  8836. * "searching": false
  8837. * } );
  8838. * } );
  8839. */
  8840. "bFilter": true,
  8841. /**
  8842. * Enable or disable the table information display. This shows information
  8843. * about the data that is currently visible on the page, including information
  8844. * about filtered data if that action is being performed.
  8845. * @type boolean
  8846. * @default true
  8847. *
  8848. * @dtopt Features
  8849. * @name DataTable.defaults.info
  8850. *
  8851. * @example
  8852. * $(document).ready( function () {
  8853. * $('#example').dataTable( {
  8854. * "info": false
  8855. * } );
  8856. * } );
  8857. */
  8858. "bInfo": true,
  8859. /**
  8860. * Allows the end user to select the size of a formatted page from a select
  8861. * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
  8862. * @type boolean
  8863. * @default true
  8864. *
  8865. * @dtopt Features
  8866. * @name DataTable.defaults.lengthChange
  8867. *
  8868. * @example
  8869. * $(document).ready( function () {
  8870. * $('#example').dataTable( {
  8871. * "lengthChange": false
  8872. * } );
  8873. * } );
  8874. */
  8875. "bLengthChange": true,
  8876. /**
  8877. * Enable or disable pagination.
  8878. * @type boolean
  8879. * @default true
  8880. *
  8881. * @dtopt Features
  8882. * @name DataTable.defaults.paging
  8883. *
  8884. * @example
  8885. * $(document).ready( function () {
  8886. * $('#example').dataTable( {
  8887. * "paging": false
  8888. * } );
  8889. * } );
  8890. */
  8891. "bPaginate": true,
  8892. /**
  8893. * Enable or disable the display of a 'processing' indicator when the table is
  8894. * being processed (e.g. a sort). This is particularly useful for tables with
  8895. * large amounts of data where it can take a noticeable amount of time to sort
  8896. * the entries.
  8897. * @type boolean
  8898. * @default false
  8899. *
  8900. * @dtopt Features
  8901. * @name DataTable.defaults.processing
  8902. *
  8903. * @example
  8904. * $(document).ready( function () {
  8905. * $('#example').dataTable( {
  8906. * "processing": true
  8907. * } );
  8908. * } );
  8909. */
  8910. "bProcessing": false,
  8911. /**
  8912. * Retrieve the DataTables object for the given selector. Note that if the
  8913. * table has already been initialised, this parameter will cause DataTables
  8914. * to simply return the object that has already been set up - it will not take
  8915. * account of any changes you might have made to the initialisation object
  8916. * passed to DataTables (setting this parameter to true is an acknowledgement
  8917. * that you understand this). `destroy` can be used to reinitialise a table if
  8918. * you need.
  8919. * @type boolean
  8920. * @default false
  8921. *
  8922. * @dtopt Options
  8923. * @name DataTable.defaults.retrieve
  8924. *
  8925. * @example
  8926. * $(document).ready( function() {
  8927. * initTable();
  8928. * tableActions();
  8929. * } );
  8930. *
  8931. * function initTable ()
  8932. * {
  8933. * return $('#example').dataTable( {
  8934. * "scrollY": "200px",
  8935. * "paginate": false,
  8936. * "retrieve": true
  8937. * } );
  8938. * }
  8939. *
  8940. * function tableActions ()
  8941. * {
  8942. * var table = initTable();
  8943. * // perform API operations with oTable
  8944. * }
  8945. */
  8946. "bRetrieve": false,
  8947. /**
  8948. * When vertical (y) scrolling is enabled, DataTables will force the height of
  8949. * the table's viewport to the given height at all times (useful for layout).
  8950. * However, this can look odd when filtering data down to a small data set,
  8951. * and the footer is left "floating" further down. This parameter (when
  8952. * enabled) will cause DataTables to collapse the table's viewport down when
  8953. * the result set will fit within the given Y height.
  8954. * @type boolean
  8955. * @default false
  8956. *
  8957. * @dtopt Options
  8958. * @name DataTable.defaults.scrollCollapse
  8959. *
  8960. * @example
  8961. * $(document).ready( function() {
  8962. * $('#example').dataTable( {
  8963. * "scrollY": "200",
  8964. * "scrollCollapse": true
  8965. * } );
  8966. * } );
  8967. */
  8968. "bScrollCollapse": false,
  8969. /**
  8970. * Configure DataTables to use server-side processing. Note that the
  8971. * `ajax` parameter must also be given in order to give DataTables a
  8972. * source to obtain the required data for each draw.
  8973. * @type boolean
  8974. * @default false
  8975. *
  8976. * @dtopt Features
  8977. * @dtopt Server-side
  8978. * @name DataTable.defaults.serverSide
  8979. *
  8980. * @example
  8981. * $(document).ready( function () {
  8982. * $('#example').dataTable( {
  8983. * "serverSide": true,
  8984. * "ajax": "xhr.php"
  8985. * } );
  8986. * } );
  8987. */
  8988. "bServerSide": false,
  8989. /**
  8990. * Enable or disable sorting of columns. Sorting of individual columns can be
  8991. * disabled by the `sortable` option for each column.
  8992. * @type boolean
  8993. * @default true
  8994. *
  8995. * @dtopt Features
  8996. * @name DataTable.defaults.ordering
  8997. *
  8998. * @example
  8999. * $(document).ready( function () {
  9000. * $('#example').dataTable( {
  9001. * "ordering": false
  9002. * } );
  9003. * } );
  9004. */
  9005. "bSort": true,
  9006. /**
  9007. * Enable or display DataTables' ability to sort multiple columns at the
  9008. * same time (activated by shift-click by the user).
  9009. * @type boolean
  9010. * @default true
  9011. *
  9012. * @dtopt Options
  9013. * @name DataTable.defaults.orderMulti
  9014. *
  9015. * @example
  9016. * // Disable multiple column sorting ability
  9017. * $(document).ready( function () {
  9018. * $('#example').dataTable( {
  9019. * "orderMulti": false
  9020. * } );
  9021. * } );
  9022. */
  9023. "bSortMulti": true,
  9024. /**
  9025. * Allows control over whether DataTables should use the top (true) unique
  9026. * cell that is found for a single column, or the bottom (false - default).
  9027. * This is useful when using complex headers.
  9028. * @type boolean
  9029. * @default false
  9030. *
  9031. * @dtopt Options
  9032. * @name DataTable.defaults.orderCellsTop
  9033. *
  9034. * @example
  9035. * $(document).ready( function() {
  9036. * $('#example').dataTable( {
  9037. * "orderCellsTop": true
  9038. * } );
  9039. * } );
  9040. */
  9041. "bSortCellsTop": false,
  9042. /**
  9043. * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
  9044. * `sorting\_3` to the columns which are currently being sorted on. This is
  9045. * presented as a feature switch as it can increase processing time (while
  9046. * classes are removed and added) so for large data sets you might want to
  9047. * turn this off.
  9048. * @type boolean
  9049. * @default true
  9050. *
  9051. * @dtopt Features
  9052. * @name DataTable.defaults.orderClasses
  9053. *
  9054. * @example
  9055. * $(document).ready( function () {
  9056. * $('#example').dataTable( {
  9057. * "orderClasses": false
  9058. * } );
  9059. * } );
  9060. */
  9061. "bSortClasses": true,
  9062. /**
  9063. * Enable or disable state saving. When enabled HTML5 `localStorage` will be
  9064. * used to save table display information such as pagination information,
  9065. * display length, filtering and sorting. As such when the end user reloads
  9066. * the page the display display will match what thy had previously set up.
  9067. *
  9068. * Due to the use of `localStorage` the default state saving is not supported
  9069. * in IE6 or 7. If state saving is required in those browsers, use
  9070. * `stateSaveCallback` to provide a storage solution such as cookies.
  9071. * @type boolean
  9072. * @default false
  9073. *
  9074. * @dtopt Features
  9075. * @name DataTable.defaults.stateSave
  9076. *
  9077. * @example
  9078. * $(document).ready( function () {
  9079. * $('#example').dataTable( {
  9080. * "stateSave": true
  9081. * } );
  9082. * } );
  9083. */
  9084. "bStateSave": false,
  9085. /**
  9086. * This function is called when a TR element is created (and all TD child
  9087. * elements have been inserted), or registered if using a DOM source, allowing
  9088. * manipulation of the TR element (adding classes etc).
  9089. * @type function
  9090. * @param {node} row "TR" element for the current row
  9091. * @param {array} data Raw data array for this row
  9092. * @param {int} dataIndex The index of this row in the internal aoData array
  9093. *
  9094. * @dtopt Callbacks
  9095. * @name DataTable.defaults.createdRow
  9096. *
  9097. * @example
  9098. * $(document).ready( function() {
  9099. * $('#example').dataTable( {
  9100. * "createdRow": function( row, data, dataIndex ) {
  9101. * // Bold the grade for all 'A' grade browsers
  9102. * if ( data[4] == "A" )
  9103. * {
  9104. * $('td:eq(4)', row).html( '<b>A</b>' );
  9105. * }
  9106. * }
  9107. * } );
  9108. * } );
  9109. */
  9110. "fnCreatedRow": null,
  9111. /**
  9112. * This function is called on every 'draw' event, and allows you to
  9113. * dynamically modify any aspect you want about the created DOM.
  9114. * @type function
  9115. * @param {object} settings DataTables settings object
  9116. *
  9117. * @dtopt Callbacks
  9118. * @name DataTable.defaults.drawCallback
  9119. *
  9120. * @example
  9121. * $(document).ready( function() {
  9122. * $('#example').dataTable( {
  9123. * "drawCallback": function( settings ) {
  9124. * alert( 'DataTables has redrawn the table' );
  9125. * }
  9126. * } );
  9127. * } );
  9128. */
  9129. "fnDrawCallback": null,
  9130. /**
  9131. * Identical to fnHeaderCallback() but for the table footer this function
  9132. * allows you to modify the table footer on every 'draw' event.
  9133. * @type function
  9134. * @param {node} foot "TR" element for the footer
  9135. * @param {array} data Full table data (as derived from the original HTML)
  9136. * @param {int} start Index for the current display starting point in the
  9137. * display array
  9138. * @param {int} end Index for the current display ending point in the
  9139. * display array
  9140. * @param {array int} display Index array to translate the visual position
  9141. * to the full data array
  9142. *
  9143. * @dtopt Callbacks
  9144. * @name DataTable.defaults.footerCallback
  9145. *
  9146. * @example
  9147. * $(document).ready( function() {
  9148. * $('#example').dataTable( {
  9149. * "footerCallback": function( tfoot, data, start, end, display ) {
  9150. * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
  9151. * }
  9152. * } );
  9153. * } )
  9154. */
  9155. "fnFooterCallback": null,
  9156. /**
  9157. * When rendering large numbers in the information element for the table
  9158. * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
  9159. * to have a comma separator for the 'thousands' units (e.g. 1 million is
  9160. * rendered as "1,000,000") to help readability for the end user. This
  9161. * function will override the default method DataTables uses.
  9162. * @type function
  9163. * @member
  9164. * @param {int} toFormat number to be formatted
  9165. * @returns {string} formatted string for DataTables to show the number
  9166. *
  9167. * @dtopt Callbacks
  9168. * @name DataTable.defaults.formatNumber
  9169. *
  9170. * @example
  9171. * // Format a number using a single quote for the separator (note that
  9172. * // this can also be done with the language.thousands option)
  9173. * $(document).ready( function() {
  9174. * $('#example').dataTable( {
  9175. * "formatNumber": function ( toFormat ) {
  9176. * return toFormat.toString().replace(
  9177. * /\B(?=(\d{3})+(?!\d))/g, "'"
  9178. * );
  9179. * };
  9180. * } );
  9181. * } );
  9182. */
  9183. "fnFormatNumber": function ( toFormat ) {
  9184. return toFormat.toString().replace(
  9185. /\B(?=(\d{3})+(?!\d))/g,
  9186. this.oLanguage.sThousands
  9187. );
  9188. },
  9189. /**
  9190. * This function is called on every 'draw' event, and allows you to
  9191. * dynamically modify the header row. This can be used to calculate and
  9192. * display useful information about the table.
  9193. * @type function
  9194. * @param {node} head "TR" element for the header
  9195. * @param {array} data Full table data (as derived from the original HTML)
  9196. * @param {int} start Index for the current display starting point in the
  9197. * display array
  9198. * @param {int} end Index for the current display ending point in the
  9199. * display array
  9200. * @param {array int} display Index array to translate the visual position
  9201. * to the full data array
  9202. *
  9203. * @dtopt Callbacks
  9204. * @name DataTable.defaults.headerCallback
  9205. *
  9206. * @example
  9207. * $(document).ready( function() {
  9208. * $('#example').dataTable( {
  9209. * "fheaderCallback": function( head, data, start, end, display ) {
  9210. * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
  9211. * }
  9212. * } );
  9213. * } )
  9214. */
  9215. "fnHeaderCallback": null,
  9216. /**
  9217. * The information element can be used to convey information about the current
  9218. * state of the table. Although the internationalisation options presented by
  9219. * DataTables are quite capable of dealing with most customisations, there may
  9220. * be times where you wish to customise the string further. This callback
  9221. * allows you to do exactly that.
  9222. * @type function
  9223. * @param {object} oSettings DataTables settings object
  9224. * @param {int} start Starting position in data for the draw
  9225. * @param {int} end End position in data for the draw
  9226. * @param {int} max Total number of rows in the table (regardless of
  9227. * filtering)
  9228. * @param {int} total Total number of rows in the data set, after filtering
  9229. * @param {string} pre The string that DataTables has formatted using it's
  9230. * own rules
  9231. * @returns {string} The string to be displayed in the information element.
  9232. *
  9233. * @dtopt Callbacks
  9234. * @name DataTable.defaults.infoCallback
  9235. *
  9236. * @example
  9237. * $('#example').dataTable( {
  9238. * "infoCallback": function( settings, start, end, max, total, pre ) {
  9239. * return start +" to "+ end;
  9240. * }
  9241. * } );
  9242. */
  9243. "fnInfoCallback": null,
  9244. /**
  9245. * Called when the table has been initialised. Normally DataTables will
  9246. * initialise sequentially and there will be no need for this function,
  9247. * however, this does not hold true when using external language information
  9248. * since that is obtained using an async XHR call.
  9249. * @type function
  9250. * @param {object} settings DataTables settings object
  9251. * @param {object} json The JSON object request from the server - only
  9252. * present if client-side Ajax sourced data is used
  9253. *
  9254. * @dtopt Callbacks
  9255. * @name DataTable.defaults.initComplete
  9256. *
  9257. * @example
  9258. * $(document).ready( function() {
  9259. * $('#example').dataTable( {
  9260. * "initComplete": function(settings, json) {
  9261. * alert( 'DataTables has finished its initialisation.' );
  9262. * }
  9263. * } );
  9264. * } )
  9265. */
  9266. "fnInitComplete": null,
  9267. /**
  9268. * Called at the very start of each table draw and can be used to cancel the
  9269. * draw by returning false, any other return (including undefined) results in
  9270. * the full draw occurring).
  9271. * @type function
  9272. * @param {object} settings DataTables settings object
  9273. * @returns {boolean} False will cancel the draw, anything else (including no
  9274. * return) will allow it to complete.
  9275. *
  9276. * @dtopt Callbacks
  9277. * @name DataTable.defaults.preDrawCallback
  9278. *
  9279. * @example
  9280. * $(document).ready( function() {
  9281. * $('#example').dataTable( {
  9282. * "preDrawCallback": function( settings ) {
  9283. * if ( $('#test').val() == 1 ) {
  9284. * return false;
  9285. * }
  9286. * }
  9287. * } );
  9288. * } );
  9289. */
  9290. "fnPreDrawCallback": null,
  9291. /**
  9292. * This function allows you to 'post process' each row after it have been
  9293. * generated for each table draw, but before it is rendered on screen. This
  9294. * function might be used for setting the row class name etc.
  9295. * @type function
  9296. * @param {node} row "TR" element for the current row
  9297. * @param {array} data Raw data array for this row
  9298. * @param {int} displayIndex The display index for the current table draw
  9299. * @param {int} displayIndexFull The index of the data in the full list of
  9300. * rows (after filtering)
  9301. *
  9302. * @dtopt Callbacks
  9303. * @name DataTable.defaults.rowCallback
  9304. *
  9305. * @example
  9306. * $(document).ready( function() {
  9307. * $('#example').dataTable( {
  9308. * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
  9309. * // Bold the grade for all 'A' grade browsers
  9310. * if ( data[4] == "A" ) {
  9311. * $('td:eq(4)', row).html( '<b>A</b>' );
  9312. * }
  9313. * }
  9314. * } );
  9315. * } );
  9316. */
  9317. "fnRowCallback": null,
  9318. /**
  9319. * __Deprecated__ The functionality provided by this parameter has now been
  9320. * superseded by that provided through `ajax`, which should be used instead.
  9321. *
  9322. * This parameter allows you to override the default function which obtains
  9323. * the data from the server so something more suitable for your application.
  9324. * For example you could use POST data, or pull information from a Gears or
  9325. * AIR database.
  9326. * @type function
  9327. * @member
  9328. * @param {string} source HTTP source to obtain the data from (`ajax`)
  9329. * @param {array} data A key/value pair object containing the data to send
  9330. * to the server
  9331. * @param {function} callback to be called on completion of the data get
  9332. * process that will draw the data on the page.
  9333. * @param {object} settings DataTables settings object
  9334. *
  9335. * @dtopt Callbacks
  9336. * @dtopt Server-side
  9337. * @name DataTable.defaults.serverData
  9338. *
  9339. * @deprecated 1.10. Please use `ajax` for this functionality now.
  9340. */
  9341. "fnServerData": null,
  9342. /**
  9343. * __Deprecated__ The functionality provided by this parameter has now been
  9344. * superseded by that provided through `ajax`, which should be used instead.
  9345. *
  9346. * It is often useful to send extra data to the server when making an Ajax
  9347. * request - for example custom filtering information, and this callback
  9348. * function makes it trivial to send extra information to the server. The
  9349. * passed in parameter is the data set that has been constructed by
  9350. * DataTables, and you can add to this or modify it as you require.
  9351. * @type function
  9352. * @param {array} data Data array (array of objects which are name/value
  9353. * pairs) that has been constructed by DataTables and will be sent to the
  9354. * server. In the case of Ajax sourced data with server-side processing
  9355. * this will be an empty array, for server-side processing there will be a
  9356. * significant number of parameters!
  9357. * @returns {undefined} Ensure that you modify the data array passed in,
  9358. * as this is passed by reference.
  9359. *
  9360. * @dtopt Callbacks
  9361. * @dtopt Server-side
  9362. * @name DataTable.defaults.serverParams
  9363. *
  9364. * @deprecated 1.10. Please use `ajax` for this functionality now.
  9365. */
  9366. "fnServerParams": null,
  9367. /**
  9368. * Load the table state. With this function you can define from where, and how, the
  9369. * state of a table is loaded. By default DataTables will load from `localStorage`
  9370. * but you might wish to use a server-side database or cookies.
  9371. * @type function
  9372. * @member
  9373. * @param {object} settings DataTables settings object
  9374. * @param {object} callback Callback that can be executed when done. It
  9375. * should be passed the loaded state object.
  9376. * @return {object} The DataTables state object to be loaded
  9377. *
  9378. * @dtopt Callbacks
  9379. * @name DataTable.defaults.stateLoadCallback
  9380. *
  9381. * @example
  9382. * $(document).ready( function() {
  9383. * $('#example').dataTable( {
  9384. * "stateSave": true,
  9385. * "stateLoadCallback": function (settings, callback) {
  9386. * $.ajax( {
  9387. * "url": "/state_load",
  9388. * "dataType": "json",
  9389. * "success": function (json) {
  9390. * callback( json );
  9391. * }
  9392. * } );
  9393. * }
  9394. * } );
  9395. * } );
  9396. */
  9397. "fnStateLoadCallback": function ( settings ) {
  9398. try {
  9399. return JSON.parse(
  9400. (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
  9401. 'DataTables_'+settings.sInstance+'_'+location.pathname
  9402. )
  9403. );
  9404. } catch (e) {}
  9405. },
  9406. /**
  9407. * Callback which allows modification of the saved state prior to loading that state.
  9408. * This callback is called when the table is loading state from the stored data, but
  9409. * prior to the settings object being modified by the saved state. Note that for
  9410. * plug-in authors, you should use the `stateLoadParams` event to load parameters for
  9411. * a plug-in.
  9412. * @type function
  9413. * @param {object} settings DataTables settings object
  9414. * @param {object} data The state object that is to be loaded
  9415. *
  9416. * @dtopt Callbacks
  9417. * @name DataTable.defaults.stateLoadParams
  9418. *
  9419. * @example
  9420. * // Remove a saved filter, so filtering is never loaded
  9421. * $(document).ready( function() {
  9422. * $('#example').dataTable( {
  9423. * "stateSave": true,
  9424. * "stateLoadParams": function (settings, data) {
  9425. * data.oSearch.sSearch = "";
  9426. * }
  9427. * } );
  9428. * } );
  9429. *
  9430. * @example
  9431. * // Disallow state loading by returning false
  9432. * $(document).ready( function() {
  9433. * $('#example').dataTable( {
  9434. * "stateSave": true,
  9435. * "stateLoadParams": function (settings, data) {
  9436. * return false;
  9437. * }
  9438. * } );
  9439. * } );
  9440. */
  9441. "fnStateLoadParams": null,
  9442. /**
  9443. * Callback that is called when the state has been loaded from the state saving method
  9444. * and the DataTables settings object has been modified as a result of the loaded state.
  9445. * @type function
  9446. * @param {object} settings DataTables settings object
  9447. * @param {object} data The state object that was loaded
  9448. *
  9449. * @dtopt Callbacks
  9450. * @name DataTable.defaults.stateLoaded
  9451. *
  9452. * @example
  9453. * // Show an alert with the filtering value that was saved
  9454. * $(document).ready( function() {
  9455. * $('#example').dataTable( {
  9456. * "stateSave": true,
  9457. * "stateLoaded": function (settings, data) {
  9458. * alert( 'Saved filter was: '+data.oSearch.sSearch );
  9459. * }
  9460. * } );
  9461. * } );
  9462. */
  9463. "fnStateLoaded": null,
  9464. /**
  9465. * Save the table state. This function allows you to define where and how the state
  9466. * information for the table is stored By default DataTables will use `localStorage`
  9467. * but you might wish to use a server-side database or cookies.
  9468. * @type function
  9469. * @member
  9470. * @param {object} settings DataTables settings object
  9471. * @param {object} data The state object to be saved
  9472. *
  9473. * @dtopt Callbacks
  9474. * @name DataTable.defaults.stateSaveCallback
  9475. *
  9476. * @example
  9477. * $(document).ready( function() {
  9478. * $('#example').dataTable( {
  9479. * "stateSave": true,
  9480. * "stateSaveCallback": function (settings, data) {
  9481. * // Send an Ajax request to the server with the state object
  9482. * $.ajax( {
  9483. * "url": "/state_save",
  9484. * "data": data,
  9485. * "dataType": "json",
  9486. * "method": "POST"
  9487. * "success": function () {}
  9488. * } );
  9489. * }
  9490. * } );
  9491. * } );
  9492. */
  9493. "fnStateSaveCallback": function ( settings, data ) {
  9494. try {
  9495. (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
  9496. 'DataTables_'+settings.sInstance+'_'+location.pathname,
  9497. JSON.stringify( data )
  9498. );
  9499. } catch (e) {}
  9500. },
  9501. /**
  9502. * Callback which allows modification of the state to be saved. Called when the table
  9503. * has changed state a new state save is required. This method allows modification of
  9504. * the state saving object prior to actually doing the save, including addition or
  9505. * other state properties or modification. Note that for plug-in authors, you should
  9506. * use the `stateSaveParams` event to save parameters for a plug-in.
  9507. * @type function
  9508. * @param {object} settings DataTables settings object
  9509. * @param {object} data The state object to be saved
  9510. *
  9511. * @dtopt Callbacks
  9512. * @name DataTable.defaults.stateSaveParams
  9513. *
  9514. * @example
  9515. * // Remove a saved filter, so filtering is never saved
  9516. * $(document).ready( function() {
  9517. * $('#example').dataTable( {
  9518. * "stateSave": true,
  9519. * "stateSaveParams": function (settings, data) {
  9520. * data.oSearch.sSearch = "";
  9521. * }
  9522. * } );
  9523. * } );
  9524. */
  9525. "fnStateSaveParams": null,
  9526. /**
  9527. * Duration for which the saved state information is considered valid. After this period
  9528. * has elapsed the state will be returned to the default.
  9529. * Value is given in seconds.
  9530. * @type int
  9531. * @default 7200 <i>(2 hours)</i>
  9532. *
  9533. * @dtopt Options
  9534. * @name DataTable.defaults.stateDuration
  9535. *
  9536. * @example
  9537. * $(document).ready( function() {
  9538. * $('#example').dataTable( {
  9539. * "stateDuration": 60*60*24; // 1 day
  9540. * } );
  9541. * } )
  9542. */
  9543. "iStateDuration": 7200,
  9544. /**
  9545. * When enabled DataTables will not make a request to the server for the first
  9546. * page draw - rather it will use the data already on the page (no sorting etc
  9547. * will be applied to it), thus saving on an XHR at load time. `deferLoading`
  9548. * is used to indicate that deferred loading is required, but it is also used
  9549. * to tell DataTables how many records there are in the full table (allowing
  9550. * the information element and pagination to be displayed correctly). In the case
  9551. * where a filtering is applied to the table on initial load, this can be
  9552. * indicated by giving the parameter as an array, where the first element is
  9553. * the number of records available after filtering and the second element is the
  9554. * number of records without filtering (allowing the table information element
  9555. * to be shown correctly).
  9556. * @type int | array
  9557. * @default null
  9558. *
  9559. * @dtopt Options
  9560. * @name DataTable.defaults.deferLoading
  9561. *
  9562. * @example
  9563. * // 57 records available in the table, no filtering applied
  9564. * $(document).ready( function() {
  9565. * $('#example').dataTable( {
  9566. * "serverSide": true,
  9567. * "ajax": "scripts/server_processing.php",
  9568. * "deferLoading": 57
  9569. * } );
  9570. * } );
  9571. *
  9572. * @example
  9573. * // 57 records after filtering, 100 without filtering (an initial filter applied)
  9574. * $(document).ready( function() {
  9575. * $('#example').dataTable( {
  9576. * "serverSide": true,
  9577. * "ajax": "scripts/server_processing.php",
  9578. * "deferLoading": [ 57, 100 ],
  9579. * "search": {
  9580. * "search": "my_filter"
  9581. * }
  9582. * } );
  9583. * } );
  9584. */
  9585. "iDeferLoading": null,
  9586. /**
  9587. * Number of rows to display on a single page when using pagination. If
  9588. * feature enabled (`lengthChange`) then the end user will be able to override
  9589. * this to a custom setting using a pop-up menu.
  9590. * @type int
  9591. * @default 10
  9592. *
  9593. * @dtopt Options
  9594. * @name DataTable.defaults.pageLength
  9595. *
  9596. * @example
  9597. * $(document).ready( function() {
  9598. * $('#example').dataTable( {
  9599. * "pageLength": 50
  9600. * } );
  9601. * } )
  9602. */
  9603. "iDisplayLength": 10,
  9604. /**
  9605. * Define the starting point for data display when using DataTables with
  9606. * pagination. Note that this parameter is the number of records, rather than
  9607. * the page number, so if you have 10 records per page and want to start on
  9608. * the third page, it should be "20".
  9609. * @type int
  9610. * @default 0
  9611. *
  9612. * @dtopt Options
  9613. * @name DataTable.defaults.displayStart
  9614. *
  9615. * @example
  9616. * $(document).ready( function() {
  9617. * $('#example').dataTable( {
  9618. * "displayStart": 20
  9619. * } );
  9620. * } )
  9621. */
  9622. "iDisplayStart": 0,
  9623. /**
  9624. * By default DataTables allows keyboard navigation of the table (sorting, paging,
  9625. * and filtering) by adding a `tabindex` attribute to the required elements. This
  9626. * allows you to tab through the controls and press the enter key to activate them.
  9627. * The tabindex is default 0, meaning that the tab follows the flow of the document.
  9628. * You can overrule this using this parameter if you wish. Use a value of -1 to
  9629. * disable built-in keyboard navigation.
  9630. * @type int
  9631. * @default 0
  9632. *
  9633. * @dtopt Options
  9634. * @name DataTable.defaults.tabIndex
  9635. *
  9636. * @example
  9637. * $(document).ready( function() {
  9638. * $('#example').dataTable( {
  9639. * "tabIndex": 1
  9640. * } );
  9641. * } );
  9642. */
  9643. "iTabIndex": 0,
  9644. /**
  9645. * Classes that DataTables assigns to the various components and features
  9646. * that it adds to the HTML table. This allows classes to be configured
  9647. * during initialisation in addition to through the static
  9648. * {@link DataTable.ext.oStdClasses} object).
  9649. * @namespace
  9650. * @name DataTable.defaults.classes
  9651. */
  9652. "oClasses": {},
  9653. /**
  9654. * All strings that DataTables uses in the user interface that it creates
  9655. * are defined in this object, allowing you to modified them individually or
  9656. * completely replace them all as required.
  9657. * @namespace
  9658. * @name DataTable.defaults.language
  9659. */
  9660. "oLanguage": {
  9661. /**
  9662. * Strings that are used for WAI-ARIA labels and controls only (these are not
  9663. * actually visible on the page, but will be read by screenreaders, and thus
  9664. * must be internationalised as well).
  9665. * @namespace
  9666. * @name DataTable.defaults.language.aria
  9667. */
  9668. "oAria": {
  9669. /**
  9670. * ARIA label that is added to the table headers when the column may be
  9671. * sorted ascending by activing the column (click or return when focused).
  9672. * Note that the column header is prefixed to this string.
  9673. * @type string
  9674. * @default : activate to sort column ascending
  9675. *
  9676. * @dtopt Language
  9677. * @name DataTable.defaults.language.aria.sortAscending
  9678. *
  9679. * @example
  9680. * $(document).ready( function() {
  9681. * $('#example').dataTable( {
  9682. * "language": {
  9683. * "aria": {
  9684. * "sortAscending": " - click/return to sort ascending"
  9685. * }
  9686. * }
  9687. * } );
  9688. * } );
  9689. */
  9690. "sSortAscending": ": activate to sort column ascending",
  9691. /**
  9692. * ARIA label that is added to the table headers when the column may be
  9693. * sorted descending by activing the column (click or return when focused).
  9694. * Note that the column header is prefixed to this string.
  9695. * @type string
  9696. * @default : activate to sort column ascending
  9697. *
  9698. * @dtopt Language
  9699. * @name DataTable.defaults.language.aria.sortDescending
  9700. *
  9701. * @example
  9702. * $(document).ready( function() {
  9703. * $('#example').dataTable( {
  9704. * "language": {
  9705. * "aria": {
  9706. * "sortDescending": " - click/return to sort descending"
  9707. * }
  9708. * }
  9709. * } );
  9710. * } );
  9711. */
  9712. "sSortDescending": ": activate to sort column descending"
  9713. },
  9714. /**
  9715. * Pagination string used by DataTables for the built-in pagination
  9716. * control types.
  9717. * @namespace
  9718. * @name DataTable.defaults.language.paginate
  9719. */
  9720. "oPaginate": {
  9721. /**
  9722. * Text to use when using the 'full_numbers' type of pagination for the
  9723. * button to take the user to the first page.
  9724. * @type string
  9725. * @default First
  9726. *
  9727. * @dtopt Language
  9728. * @name DataTable.defaults.language.paginate.first
  9729. *
  9730. * @example
  9731. * $(document).ready( function() {
  9732. * $('#example').dataTable( {
  9733. * "language": {
  9734. * "paginate": {
  9735. * "first": "First page"
  9736. * }
  9737. * }
  9738. * } );
  9739. * } );
  9740. */
  9741. "sFirst": "First",
  9742. /**
  9743. * Text to use when using the 'full_numbers' type of pagination for the
  9744. * button to take the user to the last page.
  9745. * @type string
  9746. * @default Last
  9747. *
  9748. * @dtopt Language
  9749. * @name DataTable.defaults.language.paginate.last
  9750. *
  9751. * @example
  9752. * $(document).ready( function() {
  9753. * $('#example').dataTable( {
  9754. * "language": {
  9755. * "paginate": {
  9756. * "last": "Last page"
  9757. * }
  9758. * }
  9759. * } );
  9760. * } );
  9761. */
  9762. "sLast": "Last",
  9763. /**
  9764. * Text to use for the 'next' pagination button (to take the user to the
  9765. * next page).
  9766. * @type string
  9767. * @default Next
  9768. *
  9769. * @dtopt Language
  9770. * @name DataTable.defaults.language.paginate.next
  9771. *
  9772. * @example
  9773. * $(document).ready( function() {
  9774. * $('#example').dataTable( {
  9775. * "language": {
  9776. * "paginate": {
  9777. * "next": "Next page"
  9778. * }
  9779. * }
  9780. * } );
  9781. * } );
  9782. */
  9783. "sNext": "Next",
  9784. /**
  9785. * Text to use for the 'previous' pagination button (to take the user to
  9786. * the previous page).
  9787. * @type string
  9788. * @default Previous
  9789. *
  9790. * @dtopt Language
  9791. * @name DataTable.defaults.language.paginate.previous
  9792. *
  9793. * @example
  9794. * $(document).ready( function() {
  9795. * $('#example').dataTable( {
  9796. * "language": {
  9797. * "paginate": {
  9798. * "previous": "Previous page"
  9799. * }
  9800. * }
  9801. * } );
  9802. * } );
  9803. */
  9804. "sPrevious": "Previous"
  9805. },
  9806. /**
  9807. * This string is shown in preference to `zeroRecords` when the table is
  9808. * empty of data (regardless of filtering). Note that this is an optional
  9809. * parameter - if it is not given, the value of `zeroRecords` will be used
  9810. * instead (either the default or given value).
  9811. * @type string
  9812. * @default No data available in table
  9813. *
  9814. * @dtopt Language
  9815. * @name DataTable.defaults.language.emptyTable
  9816. *
  9817. * @example
  9818. * $(document).ready( function() {
  9819. * $('#example').dataTable( {
  9820. * "language": {
  9821. * "emptyTable": "No data available in table"
  9822. * }
  9823. * } );
  9824. * } );
  9825. */
  9826. "sEmptyTable": "No data available in table",
  9827. /**
  9828. * This string gives information to the end user about the information
  9829. * that is current on display on the page. The following tokens can be
  9830. * used in the string and will be dynamically replaced as the table
  9831. * display updates. This tokens can be placed anywhere in the string, or
  9832. * removed as needed by the language requires:
  9833. *
  9834. * * `\_START\_` - Display index of the first record on the current page
  9835. * * `\_END\_` - Display index of the last record on the current page
  9836. * * `\_TOTAL\_` - Number of records in the table after filtering
  9837. * * `\_MAX\_` - Number of records in the table without filtering
  9838. * * `\_PAGE\_` - Current page number
  9839. * * `\_PAGES\_` - Total number of pages of data in the table
  9840. *
  9841. * @type string
  9842. * @default Showing _START_ to _END_ of _TOTAL_ entries
  9843. *
  9844. * @dtopt Language
  9845. * @name DataTable.defaults.language.info
  9846. *
  9847. * @example
  9848. * $(document).ready( function() {
  9849. * $('#example').dataTable( {
  9850. * "language": {
  9851. * "info": "Showing page _PAGE_ of _PAGES_"
  9852. * }
  9853. * } );
  9854. * } );
  9855. */
  9856. "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
  9857. /**
  9858. * Display information string for when the table is empty. Typically the
  9859. * format of this string should match `info`.
  9860. * @type string
  9861. * @default Showing 0 to 0 of 0 entries
  9862. *
  9863. * @dtopt Language
  9864. * @name DataTable.defaults.language.infoEmpty
  9865. *
  9866. * @example
  9867. * $(document).ready( function() {
  9868. * $('#example').dataTable( {
  9869. * "language": {
  9870. * "infoEmpty": "No entries to show"
  9871. * }
  9872. * } );
  9873. * } );
  9874. */
  9875. "sInfoEmpty": "Showing 0 to 0 of 0 entries",
  9876. /**
  9877. * When a user filters the information in a table, this string is appended
  9878. * to the information (`info`) to give an idea of how strong the filtering
  9879. * is. The variable _MAX_ is dynamically updated.
  9880. * @type string
  9881. * @default (filtered from _MAX_ total entries)
  9882. *
  9883. * @dtopt Language
  9884. * @name DataTable.defaults.language.infoFiltered
  9885. *
  9886. * @example
  9887. * $(document).ready( function() {
  9888. * $('#example').dataTable( {
  9889. * "language": {
  9890. * "infoFiltered": " - filtering from _MAX_ records"
  9891. * }
  9892. * } );
  9893. * } );
  9894. */
  9895. "sInfoFiltered": "(filtered from _MAX_ total entries)",
  9896. /**
  9897. * If can be useful to append extra information to the info string at times,
  9898. * and this variable does exactly that. This information will be appended to
  9899. * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
  9900. * being used) at all times.
  9901. * @type string
  9902. * @default <i>Empty string</i>
  9903. *
  9904. * @dtopt Language
  9905. * @name DataTable.defaults.language.infoPostFix
  9906. *
  9907. * @example
  9908. * $(document).ready( function() {
  9909. * $('#example').dataTable( {
  9910. * "language": {
  9911. * "infoPostFix": "All records shown are derived from real information."
  9912. * }
  9913. * } );
  9914. * } );
  9915. */
  9916. "sInfoPostFix": "",
  9917. /**
  9918. * This decimal place operator is a little different from the other
  9919. * language options since DataTables doesn't output floating point
  9920. * numbers, so it won't ever use this for display of a number. Rather,
  9921. * what this parameter does is modify the sort methods of the table so
  9922. * that numbers which are in a format which has a character other than
  9923. * a period (`.`) as a decimal place will be sorted numerically.
  9924. *
  9925. * Note that numbers with different decimal places cannot be shown in
  9926. * the same table and still be sortable, the table must be consistent.
  9927. * However, multiple different tables on the page can use different
  9928. * decimal place characters.
  9929. * @type string
  9930. * @default
  9931. *
  9932. * @dtopt Language
  9933. * @name DataTable.defaults.language.decimal
  9934. *
  9935. * @example
  9936. * $(document).ready( function() {
  9937. * $('#example').dataTable( {
  9938. * "language": {
  9939. * "decimal": ","
  9940. * "thousands": "."
  9941. * }
  9942. * } );
  9943. * } );
  9944. */
  9945. "sDecimal": "",
  9946. /**
  9947. * DataTables has a build in number formatter (`formatNumber`) which is
  9948. * used to format large numbers that are used in the table information.
  9949. * By default a comma is used, but this can be trivially changed to any
  9950. * character you wish with this parameter.
  9951. * @type string
  9952. * @default ,
  9953. *
  9954. * @dtopt Language
  9955. * @name DataTable.defaults.language.thousands
  9956. *
  9957. * @example
  9958. * $(document).ready( function() {
  9959. * $('#example').dataTable( {
  9960. * "language": {
  9961. * "thousands": "'"
  9962. * }
  9963. * } );
  9964. * } );
  9965. */
  9966. "sThousands": ",",
  9967. /**
  9968. * Detail the action that will be taken when the drop down menu for the
  9969. * pagination length option is changed. The '_MENU_' variable is replaced
  9970. * with a default select list of 10, 25, 50 and 100, and can be replaced
  9971. * with a custom select box if required.
  9972. * @type string
  9973. * @default Show _MENU_ entries
  9974. *
  9975. * @dtopt Language
  9976. * @name DataTable.defaults.language.lengthMenu
  9977. *
  9978. * @example
  9979. * // Language change only
  9980. * $(document).ready( function() {
  9981. * $('#example').dataTable( {
  9982. * "language": {
  9983. * "lengthMenu": "Display _MENU_ records"
  9984. * }
  9985. * } );
  9986. * } );
  9987. *
  9988. * @example
  9989. * // Language and options change
  9990. * $(document).ready( function() {
  9991. * $('#example').dataTable( {
  9992. * "language": {
  9993. * "lengthMenu": 'Display <select>'+
  9994. * '<option value="10">10</option>'+
  9995. * '<option value="20">20</option>'+
  9996. * '<option value="30">30</option>'+
  9997. * '<option value="40">40</option>'+
  9998. * '<option value="50">50</option>'+
  9999. * '<option value="-1">All</option>'+
  10000. * '</select> records'
  10001. * }
  10002. * } );
  10003. * } );
  10004. */
  10005. "sLengthMenu": "Show _MENU_ entries",
  10006. /**
  10007. * When using Ajax sourced data and during the first draw when DataTables is
  10008. * gathering the data, this message is shown in an empty row in the table to
  10009. * indicate to the end user the the data is being loaded. Note that this
  10010. * parameter is not used when loading data by server-side processing, just
  10011. * Ajax sourced data with client-side processing.
  10012. * @type string
  10013. * @default Loading...
  10014. *
  10015. * @dtopt Language
  10016. * @name DataTable.defaults.language.loadingRecords
  10017. *
  10018. * @example
  10019. * $(document).ready( function() {
  10020. * $('#example').dataTable( {
  10021. * "language": {
  10022. * "loadingRecords": "Please wait - loading..."
  10023. * }
  10024. * } );
  10025. * } );
  10026. */
  10027. "sLoadingRecords": "Loading...",
  10028. /**
  10029. * Text which is displayed when the table is processing a user action
  10030. * (usually a sort command or similar).
  10031. * @type string
  10032. * @default Processing...
  10033. *
  10034. * @dtopt Language
  10035. * @name DataTable.defaults.language.processing
  10036. *
  10037. * @example
  10038. * $(document).ready( function() {
  10039. * $('#example').dataTable( {
  10040. * "language": {
  10041. * "processing": "DataTables is currently busy"
  10042. * }
  10043. * } );
  10044. * } );
  10045. */
  10046. "sProcessing": "Processing...",
  10047. /**
  10048. * Details the actions that will be taken when the user types into the
  10049. * filtering input text box. The variable "_INPUT_", if used in the string,
  10050. * is replaced with the HTML text box for the filtering input allowing
  10051. * control over where it appears in the string. If "_INPUT_" is not given
  10052. * then the input box is appended to the string automatically.
  10053. * @type string
  10054. * @default Search:
  10055. *
  10056. * @dtopt Language
  10057. * @name DataTable.defaults.language.search
  10058. *
  10059. * @example
  10060. * // Input text box will be appended at the end automatically
  10061. * $(document).ready( function() {
  10062. * $('#example').dataTable( {
  10063. * "language": {
  10064. * "search": "Filter records:"
  10065. * }
  10066. * } );
  10067. * } );
  10068. *
  10069. * @example
  10070. * // Specify where the filter should appear
  10071. * $(document).ready( function() {
  10072. * $('#example').dataTable( {
  10073. * "language": {
  10074. * "search": "Apply filter _INPUT_ to table"
  10075. * }
  10076. * } );
  10077. * } );
  10078. */
  10079. "sSearch": "Search:",
  10080. /**
  10081. * Assign a `placeholder` attribute to the search `input` element
  10082. * @type string
  10083. * @default
  10084. *
  10085. * @dtopt Language
  10086. * @name DataTable.defaults.language.searchPlaceholder
  10087. */
  10088. "sSearchPlaceholder": "",
  10089. /**
  10090. * All of the language information can be stored in a file on the
  10091. * server-side, which DataTables will look up if this parameter is passed.
  10092. * It must store the URL of the language file, which is in a JSON format,
  10093. * and the object has the same properties as the oLanguage object in the
  10094. * initialiser object (i.e. the above parameters). Please refer to one of
  10095. * the example language files to see how this works in action.
  10096. * @type string
  10097. * @default <i>Empty string - i.e. disabled</i>
  10098. *
  10099. * @dtopt Language
  10100. * @name DataTable.defaults.language.url
  10101. *
  10102. * @example
  10103. * $(document).ready( function() {
  10104. * $('#example').dataTable( {
  10105. * "language": {
  10106. * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
  10107. * }
  10108. * } );
  10109. * } );
  10110. */
  10111. "sUrl": "",
  10112. /**
  10113. * Text shown inside the table records when the is no information to be
  10114. * displayed after filtering. `emptyTable` is shown when there is simply no
  10115. * information in the table at all (regardless of filtering).
  10116. * @type string
  10117. * @default No matching records found
  10118. *
  10119. * @dtopt Language
  10120. * @name DataTable.defaults.language.zeroRecords
  10121. *
  10122. * @example
  10123. * $(document).ready( function() {
  10124. * $('#example').dataTable( {
  10125. * "language": {
  10126. * "zeroRecords": "No records to display"
  10127. * }
  10128. * } );
  10129. * } );
  10130. */
  10131. "sZeroRecords": "No matching records found"
  10132. },
  10133. /**
  10134. * This parameter allows you to have define the global filtering state at
  10135. * initialisation time. As an object the `search` parameter must be
  10136. * defined, but all other parameters are optional. When `regex` is true,
  10137. * the search string will be treated as a regular expression, when false
  10138. * (default) it will be treated as a straight string. When `smart`
  10139. * DataTables will use it's smart filtering methods (to word match at
  10140. * any point in the data), when false this will not be done.
  10141. * @namespace
  10142. * @extends DataTable.models.oSearch
  10143. *
  10144. * @dtopt Options
  10145. * @name DataTable.defaults.search
  10146. *
  10147. * @example
  10148. * $(document).ready( function() {
  10149. * $('#example').dataTable( {
  10150. * "search": {"search": "Initial search"}
  10151. * } );
  10152. * } )
  10153. */
  10154. "oSearch": $.extend( {}, DataTable.models.oSearch ),
  10155. /**
  10156. * __Deprecated__ The functionality provided by this parameter has now been
  10157. * superseded by that provided through `ajax`, which should be used instead.
  10158. *
  10159. * By default DataTables will look for the property `data` (or `aaData` for
  10160. * compatibility with DataTables 1.9-) when obtaining data from an Ajax
  10161. * source or for server-side processing - this parameter allows that
  10162. * property to be changed. You can use Javascript dotted object notation to
  10163. * get a data source for multiple levels of nesting.
  10164. * @type string
  10165. * @default data
  10166. *
  10167. * @dtopt Options
  10168. * @dtopt Server-side
  10169. * @name DataTable.defaults.ajaxDataProp
  10170. *
  10171. * @deprecated 1.10. Please use `ajax` for this functionality now.
  10172. */
  10173. "sAjaxDataProp": "data",
  10174. /**
  10175. * __Deprecated__ The functionality provided by this parameter has now been
  10176. * superseded by that provided through `ajax`, which should be used instead.
  10177. *
  10178. * You can instruct DataTables to load data from an external
  10179. * source using this parameter (use aData if you want to pass data in you
  10180. * already have). Simply provide a url a JSON object can be obtained from.
  10181. * @type string
  10182. * @default null
  10183. *
  10184. * @dtopt Options
  10185. * @dtopt Server-side
  10186. * @name DataTable.defaults.ajaxSource
  10187. *
  10188. * @deprecated 1.10. Please use `ajax` for this functionality now.
  10189. */
  10190. "sAjaxSource": null,
  10191. /**
  10192. * This initialisation variable allows you to specify exactly where in the
  10193. * DOM you want DataTables to inject the various controls it adds to the page
  10194. * (for example you might want the pagination controls at the top of the
  10195. * table). DIV elements (with or without a custom class) can also be added to
  10196. * aid styling. The follow syntax is used:
  10197. * <ul>
  10198. * <li>The following options are allowed:
  10199. * <ul>
  10200. * <li>'l' - Length changing</li>
  10201. * <li>'f' - Filtering input</li>
  10202. * <li>'t' - The table!</li>
  10203. * <li>'i' - Information</li>
  10204. * <li>'p' - Pagination</li>
  10205. * <li>'r' - pRocessing</li>
  10206. * </ul>
  10207. * </li>
  10208. * <li>The following constants are allowed:
  10209. * <ul>
  10210. * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
  10211. * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
  10212. * </ul>
  10213. * </li>
  10214. * <li>The following syntax is expected:
  10215. * <ul>
  10216. * <li>'&lt;' and '&gt;' - div elements</li>
  10217. * <li>'&lt;"class" and '&gt;' - div with a class</li>
  10218. * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
  10219. * </ul>
  10220. * </li>
  10221. * <li>Examples:
  10222. * <ul>
  10223. * <li>'&lt;"wrapper"flipt&gt;'</li>
  10224. * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
  10225. * </ul>
  10226. * </li>
  10227. * </ul>
  10228. * @type string
  10229. * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
  10230. * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
  10231. *
  10232. * @dtopt Options
  10233. * @name DataTable.defaults.dom
  10234. *
  10235. * @example
  10236. * $(document).ready( function() {
  10237. * $('#example').dataTable( {
  10238. * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
  10239. * } );
  10240. * } );
  10241. */
  10242. "sDom": "lfrtip",
  10243. /**
  10244. * Search delay option. This will throttle full table searches that use the
  10245. * DataTables provided search input element (it does not effect calls to
  10246. * `dt-api search()`, providing a delay before the search is made.
  10247. * @type integer
  10248. * @default 0
  10249. *
  10250. * @dtopt Options
  10251. * @name DataTable.defaults.searchDelay
  10252. *
  10253. * @example
  10254. * $(document).ready( function() {
  10255. * $('#example').dataTable( {
  10256. * "searchDelay": 200
  10257. * } );
  10258. * } )
  10259. */
  10260. "searchDelay": null,
  10261. /**
  10262. * DataTables features six different built-in options for the buttons to
  10263. * display for pagination control:
  10264. *
  10265. * * `numbers` - Page number buttons only
  10266. * * `simple` - 'Previous' and 'Next' buttons only
  10267. * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
  10268. * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
  10269. * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
  10270. * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
  10271. *
  10272. * Further methods can be added using {@link DataTable.ext.oPagination}.
  10273. * @type string
  10274. * @default simple_numbers
  10275. *
  10276. * @dtopt Options
  10277. * @name DataTable.defaults.pagingType
  10278. *
  10279. * @example
  10280. * $(document).ready( function() {
  10281. * $('#example').dataTable( {
  10282. * "pagingType": "full_numbers"
  10283. * } );
  10284. * } )
  10285. */
  10286. "sPaginationType": "simple_numbers",
  10287. /**
  10288. * Enable horizontal scrolling. When a table is too wide to fit into a
  10289. * certain layout, or you have a large number of columns in the table, you
  10290. * can enable x-scrolling to show the table in a viewport, which can be
  10291. * scrolled. This property can be `true` which will allow the table to
  10292. * scroll horizontally when needed, or any CSS unit, or a number (in which
  10293. * case it will be treated as a pixel measurement). Setting as simply `true`
  10294. * is recommended.
  10295. * @type boolean|string
  10296. * @default <i>blank string - i.e. disabled</i>
  10297. *
  10298. * @dtopt Features
  10299. * @name DataTable.defaults.scrollX
  10300. *
  10301. * @example
  10302. * $(document).ready( function() {
  10303. * $('#example').dataTable( {
  10304. * "scrollX": true,
  10305. * "scrollCollapse": true
  10306. * } );
  10307. * } );
  10308. */
  10309. "sScrollX": "",
  10310. /**
  10311. * This property can be used to force a DataTable to use more width than it
  10312. * might otherwise do when x-scrolling is enabled. For example if you have a
  10313. * table which requires to be well spaced, this parameter is useful for
  10314. * "over-sizing" the table, and thus forcing scrolling. This property can by
  10315. * any CSS unit, or a number (in which case it will be treated as a pixel
  10316. * measurement).
  10317. * @type string
  10318. * @default <i>blank string - i.e. disabled</i>
  10319. *
  10320. * @dtopt Options
  10321. * @name DataTable.defaults.scrollXInner
  10322. *
  10323. * @example
  10324. * $(document).ready( function() {
  10325. * $('#example').dataTable( {
  10326. * "scrollX": "100%",
  10327. * "scrollXInner": "110%"
  10328. * } );
  10329. * } );
  10330. */
  10331. "sScrollXInner": "",
  10332. /**
  10333. * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
  10334. * to the given height, and enable scrolling for any data which overflows the
  10335. * current viewport. This can be used as an alternative to paging to display
  10336. * a lot of data in a small area (although paging and scrolling can both be
  10337. * enabled at the same time). This property can be any CSS unit, or a number
  10338. * (in which case it will be treated as a pixel measurement).
  10339. * @type string
  10340. * @default <i>blank string - i.e. disabled</i>
  10341. *
  10342. * @dtopt Features
  10343. * @name DataTable.defaults.scrollY
  10344. *
  10345. * @example
  10346. * $(document).ready( function() {
  10347. * $('#example').dataTable( {
  10348. * "scrollY": "200px",
  10349. * "paginate": false
  10350. * } );
  10351. * } );
  10352. */
  10353. "sScrollY": "",
  10354. /**
  10355. * __Deprecated__ The functionality provided by this parameter has now been
  10356. * superseded by that provided through `ajax`, which should be used instead.
  10357. *
  10358. * Set the HTTP method that is used to make the Ajax call for server-side
  10359. * processing or Ajax sourced data.
  10360. * @type string
  10361. * @default GET
  10362. *
  10363. * @dtopt Options
  10364. * @dtopt Server-side
  10365. * @name DataTable.defaults.serverMethod
  10366. *
  10367. * @deprecated 1.10. Please use `ajax` for this functionality now.
  10368. */
  10369. "sServerMethod": "GET",
  10370. /**
  10371. * DataTables makes use of renderers when displaying HTML elements for
  10372. * a table. These renderers can be added or modified by plug-ins to
  10373. * generate suitable mark-up for a site. For example the Bootstrap
  10374. * integration plug-in for DataTables uses a paging button renderer to
  10375. * display pagination buttons in the mark-up required by Bootstrap.
  10376. *
  10377. * For further information about the renderers available see
  10378. * DataTable.ext.renderer
  10379. * @type string|object
  10380. * @default null
  10381. *
  10382. * @name DataTable.defaults.renderer
  10383. *
  10384. */
  10385. "renderer": null,
  10386. /**
  10387. * Set the data property name that DataTables should use to get a row's id
  10388. * to set as the `id` property in the node.
  10389. * @type string
  10390. * @default DT_RowId
  10391. *
  10392. * @name DataTable.defaults.rowId
  10393. */
  10394. "rowId": "DT_RowId"
  10395. };
  10396. _fnHungarianMap( DataTable.defaults );
  10397. /*
  10398. * Developer note - See note in model.defaults.js about the use of Hungarian
  10399. * notation and camel case.
  10400. */
  10401. /**
  10402. * Column options that can be given to DataTables at initialisation time.
  10403. * @namespace
  10404. */
  10405. DataTable.defaults.column = {
  10406. /**
  10407. * Define which column(s) an order will occur on for this column. This
  10408. * allows a column's ordering to take multiple columns into account when
  10409. * doing a sort or use the data from a different column. For example first
  10410. * name / last name columns make sense to do a multi-column sort over the
  10411. * two columns.
  10412. * @type array|int
  10413. * @default null <i>Takes the value of the column index automatically</i>
  10414. *
  10415. * @name DataTable.defaults.column.orderData
  10416. * @dtopt Columns
  10417. *
  10418. * @example
  10419. * // Using `columnDefs`
  10420. * $(document).ready( function() {
  10421. * $('#example').dataTable( {
  10422. * "columnDefs": [
  10423. * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
  10424. * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
  10425. * { "orderData": 2, "targets": [ 2 ] }
  10426. * ]
  10427. * } );
  10428. * } );
  10429. *
  10430. * @example
  10431. * // Using `columns`
  10432. * $(document).ready( function() {
  10433. * $('#example').dataTable( {
  10434. * "columns": [
  10435. * { "orderData": [ 0, 1 ] },
  10436. * { "orderData": [ 1, 0 ] },
  10437. * { "orderData": 2 },
  10438. * null,
  10439. * null
  10440. * ]
  10441. * } );
  10442. * } );
  10443. */
  10444. "aDataSort": null,
  10445. "iDataSort": -1,
  10446. /**
  10447. * You can control the default ordering direction, and even alter the
  10448. * behaviour of the sort handler (i.e. only allow ascending ordering etc)
  10449. * using this parameter.
  10450. * @type array
  10451. * @default [ 'asc', 'desc' ]
  10452. *
  10453. * @name DataTable.defaults.column.orderSequence
  10454. * @dtopt Columns
  10455. *
  10456. * @example
  10457. * // Using `columnDefs`
  10458. * $(document).ready( function() {
  10459. * $('#example').dataTable( {
  10460. * "columnDefs": [
  10461. * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
  10462. * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
  10463. * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
  10464. * ]
  10465. * } );
  10466. * } );
  10467. *
  10468. * @example
  10469. * // Using `columns`
  10470. * $(document).ready( function() {
  10471. * $('#example').dataTable( {
  10472. * "columns": [
  10473. * null,
  10474. * { "orderSequence": [ "asc" ] },
  10475. * { "orderSequence": [ "desc", "asc", "asc" ] },
  10476. * { "orderSequence": [ "desc" ] },
  10477. * null
  10478. * ]
  10479. * } );
  10480. * } );
  10481. */
  10482. "asSorting": [ 'asc', 'desc' ],
  10483. /**
  10484. * Enable or disable filtering on the data in this column.
  10485. * @type boolean
  10486. * @default true
  10487. *
  10488. * @name DataTable.defaults.column.searchable
  10489. * @dtopt Columns
  10490. *
  10491. * @example
  10492. * // Using `columnDefs`
  10493. * $(document).ready( function() {
  10494. * $('#example').dataTable( {
  10495. * "columnDefs": [
  10496. * { "searchable": false, "targets": [ 0 ] }
  10497. * ] } );
  10498. * } );
  10499. *
  10500. * @example
  10501. * // Using `columns`
  10502. * $(document).ready( function() {
  10503. * $('#example').dataTable( {
  10504. * "columns": [
  10505. * { "searchable": false },
  10506. * null,
  10507. * null,
  10508. * null,
  10509. * null
  10510. * ] } );
  10511. * } );
  10512. */
  10513. "bSearchable": true,
  10514. /**
  10515. * Enable or disable ordering on this column.
  10516. * @type boolean
  10517. * @default true
  10518. *
  10519. * @name DataTable.defaults.column.orderable
  10520. * @dtopt Columns
  10521. *
  10522. * @example
  10523. * // Using `columnDefs`
  10524. * $(document).ready( function() {
  10525. * $('#example').dataTable( {
  10526. * "columnDefs": [
  10527. * { "orderable": false, "targets": [ 0 ] }
  10528. * ] } );
  10529. * } );
  10530. *
  10531. * @example
  10532. * // Using `columns`
  10533. * $(document).ready( function() {
  10534. * $('#example').dataTable( {
  10535. * "columns": [
  10536. * { "orderable": false },
  10537. * null,
  10538. * null,
  10539. * null,
  10540. * null
  10541. * ] } );
  10542. * } );
  10543. */
  10544. "bSortable": true,
  10545. /**
  10546. * Enable or disable the display of this column.
  10547. * @type boolean
  10548. * @default true
  10549. *
  10550. * @name DataTable.defaults.column.visible
  10551. * @dtopt Columns
  10552. *
  10553. * @example
  10554. * // Using `columnDefs`
  10555. * $(document).ready( function() {
  10556. * $('#example').dataTable( {
  10557. * "columnDefs": [
  10558. * { "visible": false, "targets": [ 0 ] }
  10559. * ] } );
  10560. * } );
  10561. *
  10562. * @example
  10563. * // Using `columns`
  10564. * $(document).ready( function() {
  10565. * $('#example').dataTable( {
  10566. * "columns": [
  10567. * { "visible": false },
  10568. * null,
  10569. * null,
  10570. * null,
  10571. * null
  10572. * ] } );
  10573. * } );
  10574. */
  10575. "bVisible": true,
  10576. /**
  10577. * Developer definable function that is called whenever a cell is created (Ajax source,
  10578. * etc) or processed for input (DOM source). This can be used as a compliment to mRender
  10579. * allowing you to modify the DOM element (add background colour for example) when the
  10580. * element is available.
  10581. * @type function
  10582. * @param {element} td The TD node that has been created
  10583. * @param {*} cellData The Data for the cell
  10584. * @param {array|object} rowData The data for the whole row
  10585. * @param {int} row The row index for the aoData data store
  10586. * @param {int} col The column index for aoColumns
  10587. *
  10588. * @name DataTable.defaults.column.createdCell
  10589. * @dtopt Columns
  10590. *
  10591. * @example
  10592. * $(document).ready( function() {
  10593. * $('#example').dataTable( {
  10594. * "columnDefs": [ {
  10595. * "targets": [3],
  10596. * "createdCell": function (td, cellData, rowData, row, col) {
  10597. * if ( cellData == "1.7" ) {
  10598. * $(td).css('color', 'blue')
  10599. * }
  10600. * }
  10601. * } ]
  10602. * });
  10603. * } );
  10604. */
  10605. "fnCreatedCell": null,
  10606. /**
  10607. * This parameter has been replaced by `data` in DataTables to ensure naming
  10608. * consistency. `dataProp` can still be used, as there is backwards
  10609. * compatibility in DataTables for this option, but it is strongly
  10610. * recommended that you use `data` in preference to `dataProp`.
  10611. * @name DataTable.defaults.column.dataProp
  10612. */
  10613. /**
  10614. * This property can be used to read data from any data source property,
  10615. * including deeply nested objects / properties. `data` can be given in a
  10616. * number of different ways which effect its behaviour:
  10617. *
  10618. * * `integer` - treated as an array index for the data source. This is the
  10619. * default that DataTables uses (incrementally increased for each column).
  10620. * * `string` - read an object property from the data source. There are
  10621. * three 'special' options that can be used in the string to alter how
  10622. * DataTables reads the data from the source object:
  10623. * * `.` - Dotted Javascript notation. Just as you use a `.` in
  10624. * Javascript to read from nested objects, so to can the options
  10625. * specified in `data`. For example: `browser.version` or
  10626. * `browser.name`. If your object parameter name contains a period, use
  10627. * `\\` to escape it - i.e. `first\\.name`.
  10628. * * `[]` - Array notation. DataTables can automatically combine data
  10629. * from and array source, joining the data with the characters provided
  10630. * between the two brackets. For example: `name[, ]` would provide a
  10631. * comma-space separated list from the source array. If no characters
  10632. * are provided between the brackets, the original array source is
  10633. * returned.
  10634. * * `()` - Function notation. Adding `()` to the end of a parameter will
  10635. * execute a function of the name given. For example: `browser()` for a
  10636. * simple function on the data source, `browser.version()` for a
  10637. * function in a nested property or even `browser().version` to get an
  10638. * object property if the function called returns an object. Note that
  10639. * function notation is recommended for use in `render` rather than
  10640. * `data` as it is much simpler to use as a renderer.
  10641. * * `null` - use the original data source for the row rather than plucking
  10642. * data directly from it. This action has effects on two other
  10643. * initialisation options:
  10644. * * `defaultContent` - When null is given as the `data` option and
  10645. * `defaultContent` is specified for the column, the value defined by
  10646. * `defaultContent` will be used for the cell.
  10647. * * `render` - When null is used for the `data` option and the `render`
  10648. * option is specified for the column, the whole data source for the
  10649. * row is used for the renderer.
  10650. * * `function` - the function given will be executed whenever DataTables
  10651. * needs to set or get the data for a cell in the column. The function
  10652. * takes three parameters:
  10653. * * Parameters:
  10654. * * `{array|object}` The data source for the row
  10655. * * `{string}` The type call data requested - this will be 'set' when
  10656. * setting data or 'filter', 'display', 'type', 'sort' or undefined
  10657. * when gathering data. Note that when `undefined` is given for the
  10658. * type DataTables expects to get the raw data for the object back<
  10659. * * `{*}` Data to set when the second parameter is 'set'.
  10660. * * Return:
  10661. * * The return value from the function is not required when 'set' is
  10662. * the type of call, but otherwise the return is what will be used
  10663. * for the data requested.
  10664. *
  10665. * Note that `data` is a getter and setter option. If you just require
  10666. * formatting of data for output, you will likely want to use `render` which
  10667. * is simply a getter and thus simpler to use.
  10668. *
  10669. * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
  10670. * name change reflects the flexibility of this property and is consistent
  10671. * with the naming of mRender. If 'mDataProp' is given, then it will still
  10672. * be used by DataTables, as it automatically maps the old name to the new
  10673. * if required.
  10674. *
  10675. * @type string|int|function|null
  10676. * @default null <i>Use automatically calculated column index</i>
  10677. *
  10678. * @name DataTable.defaults.column.data
  10679. * @dtopt Columns
  10680. *
  10681. * @example
  10682. * // Read table data from objects
  10683. * // JSON structure for each row:
  10684. * // {
  10685. * // "engine": {value},
  10686. * // "browser": {value},
  10687. * // "platform": {value},
  10688. * // "version": {value},
  10689. * // "grade": {value}
  10690. * // }
  10691. * $(document).ready( function() {
  10692. * $('#example').dataTable( {
  10693. * "ajaxSource": "sources/objects.txt",
  10694. * "columns": [
  10695. * { "data": "engine" },
  10696. * { "data": "browser" },
  10697. * { "data": "platform" },
  10698. * { "data": "version" },
  10699. * { "data": "grade" }
  10700. * ]
  10701. * } );
  10702. * } );
  10703. *
  10704. * @example
  10705. * // Read information from deeply nested objects
  10706. * // JSON structure for each row:
  10707. * // {
  10708. * // "engine": {value},
  10709. * // "browser": {value},
  10710. * // "platform": {
  10711. * // "inner": {value}
  10712. * // },
  10713. * // "details": [
  10714. * // {value}, {value}
  10715. * // ]
  10716. * // }
  10717. * $(document).ready( function() {
  10718. * $('#example').dataTable( {
  10719. * "ajaxSource": "sources/deep.txt",
  10720. * "columns": [
  10721. * { "data": "engine" },
  10722. * { "data": "browser" },
  10723. * { "data": "platform.inner" },
  10724. * { "data": "details.0" },
  10725. * { "data": "details.1" }
  10726. * ]
  10727. * } );
  10728. * } );
  10729. *
  10730. * @example
  10731. * // Using `data` as a function to provide different information for
  10732. * // sorting, filtering and display. In this case, currency (price)
  10733. * $(document).ready( function() {
  10734. * $('#example').dataTable( {
  10735. * "columnDefs": [ {
  10736. * "targets": [ 0 ],
  10737. * "data": function ( source, type, val ) {
  10738. * if (type === 'set') {
  10739. * source.price = val;
  10740. * // Store the computed dislay and filter values for efficiency
  10741. * source.price_display = val=="" ? "" : "$"+numberFormat(val);
  10742. * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
  10743. * return;
  10744. * }
  10745. * else if (type === 'display') {
  10746. * return source.price_display;
  10747. * }
  10748. * else if (type === 'filter') {
  10749. * return source.price_filter;
  10750. * }
  10751. * // 'sort', 'type' and undefined all just use the integer
  10752. * return source.price;
  10753. * }
  10754. * } ]
  10755. * } );
  10756. * } );
  10757. *
  10758. * @example
  10759. * // Using default content
  10760. * $(document).ready( function() {
  10761. * $('#example').dataTable( {
  10762. * "columnDefs": [ {
  10763. * "targets": [ 0 ],
  10764. * "data": null,
  10765. * "defaultContent": "Click to edit"
  10766. * } ]
  10767. * } );
  10768. * } );
  10769. *
  10770. * @example
  10771. * // Using array notation - outputting a list from an array
  10772. * $(document).ready( function() {
  10773. * $('#example').dataTable( {
  10774. * "columnDefs": [ {
  10775. * "targets": [ 0 ],
  10776. * "data": "name[, ]"
  10777. * } ]
  10778. * } );
  10779. * } );
  10780. *
  10781. */
  10782. "mData": null,
  10783. /**
  10784. * This property is the rendering partner to `data` and it is suggested that
  10785. * when you want to manipulate data for display (including filtering,
  10786. * sorting etc) without altering the underlying data for the table, use this
  10787. * property. `render` can be considered to be the the read only companion to
  10788. * `data` which is read / write (then as such more complex). Like `data`
  10789. * this option can be given in a number of different ways to effect its
  10790. * behaviour:
  10791. *
  10792. * * `integer` - treated as an array index for the data source. This is the
  10793. * default that DataTables uses (incrementally increased for each column).
  10794. * * `string` - read an object property from the data source. There are
  10795. * three 'special' options that can be used in the string to alter how
  10796. * DataTables reads the data from the source object:
  10797. * * `.` - Dotted Javascript notation. Just as you use a `.` in
  10798. * Javascript to read from nested objects, so to can the options
  10799. * specified in `data`. For example: `browser.version` or
  10800. * `browser.name`. If your object parameter name contains a period, use
  10801. * `\\` to escape it - i.e. `first\\.name`.
  10802. * * `[]` - Array notation. DataTables can automatically combine data
  10803. * from and array source, joining the data with the characters provided
  10804. * between the two brackets. For example: `name[, ]` would provide a
  10805. * comma-space separated list from the source array. If no characters
  10806. * are provided between the brackets, the original array source is
  10807. * returned.
  10808. * * `()` - Function notation. Adding `()` to the end of a parameter will
  10809. * execute a function of the name given. For example: `browser()` for a
  10810. * simple function on the data source, `browser.version()` for a
  10811. * function in a nested property or even `browser().version` to get an
  10812. * object property if the function called returns an object.
  10813. * * `object` - use different data for the different data types requested by
  10814. * DataTables ('filter', 'display', 'type' or 'sort'). The property names
  10815. * of the object is the data type the property refers to and the value can
  10816. * defined using an integer, string or function using the same rules as
  10817. * `render` normally does. Note that an `_` option _must_ be specified.
  10818. * This is the default value to use if you haven't specified a value for
  10819. * the data type requested by DataTables.
  10820. * * `function` - the function given will be executed whenever DataTables
  10821. * needs to set or get the data for a cell in the column. The function
  10822. * takes three parameters:
  10823. * * Parameters:
  10824. * * {array|object} The data source for the row (based on `data`)
  10825. * * {string} The type call data requested - this will be 'filter',
  10826. * 'display', 'type' or 'sort'.
  10827. * * {array|object} The full data source for the row (not based on
  10828. * `data`)
  10829. * * Return:
  10830. * * The return value from the function is what will be used for the
  10831. * data requested.
  10832. *
  10833. * @type string|int|function|object|null
  10834. * @default null Use the data source value.
  10835. *
  10836. * @name DataTable.defaults.column.render
  10837. * @dtopt Columns
  10838. *
  10839. * @example
  10840. * // Create a comma separated list from an array of objects
  10841. * $(document).ready( function() {
  10842. * $('#example').dataTable( {
  10843. * "ajaxSource": "sources/deep.txt",
  10844. * "columns": [
  10845. * { "data": "engine" },
  10846. * { "data": "browser" },
  10847. * {
  10848. * "data": "platform",
  10849. * "render": "[, ].name"
  10850. * }
  10851. * ]
  10852. * } );
  10853. * } );
  10854. *
  10855. * @example
  10856. * // Execute a function to obtain data
  10857. * $(document).ready( function() {
  10858. * $('#example').dataTable( {
  10859. * "columnDefs": [ {
  10860. * "targets": [ 0 ],
  10861. * "data": null, // Use the full data source object for the renderer's source
  10862. * "render": "browserName()"
  10863. * } ]
  10864. * } );
  10865. * } );
  10866. *
  10867. * @example
  10868. * // As an object, extracting different data for the different types
  10869. * // This would be used with a data source such as:
  10870. * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
  10871. * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
  10872. * // (which has both forms) is used for filtering for if a user inputs either format, while
  10873. * // the formatted phone number is the one that is shown in the table.
  10874. * $(document).ready( function() {
  10875. * $('#example').dataTable( {
  10876. * "columnDefs": [ {
  10877. * "targets": [ 0 ],
  10878. * "data": null, // Use the full data source object for the renderer's source
  10879. * "render": {
  10880. * "_": "phone",
  10881. * "filter": "phone_filter",
  10882. * "display": "phone_display"
  10883. * }
  10884. * } ]
  10885. * } );
  10886. * } );
  10887. *
  10888. * @example
  10889. * // Use as a function to create a link from the data source
  10890. * $(document).ready( function() {
  10891. * $('#example').dataTable( {
  10892. * "columnDefs": [ {
  10893. * "targets": [ 0 ],
  10894. * "data": "download_link",
  10895. * "render": function ( data, type, full ) {
  10896. * return '<a href="'+data+'">Download</a>';
  10897. * }
  10898. * } ]
  10899. * } );
  10900. * } );
  10901. */
  10902. "mRender": null,
  10903. /**
  10904. * Change the cell type created for the column - either TD cells or TH cells. This
  10905. * can be useful as TH cells have semantic meaning in the table body, allowing them
  10906. * to act as a header for a row (you may wish to add scope='row' to the TH elements).
  10907. * @type string
  10908. * @default td
  10909. *
  10910. * @name DataTable.defaults.column.cellType
  10911. * @dtopt Columns
  10912. *
  10913. * @example
  10914. * // Make the first column use TH cells
  10915. * $(document).ready( function() {
  10916. * $('#example').dataTable( {
  10917. * "columnDefs": [ {
  10918. * "targets": [ 0 ],
  10919. * "cellType": "th"
  10920. * } ]
  10921. * } );
  10922. * } );
  10923. */
  10924. "sCellType": "td",
  10925. /**
  10926. * Class to give to each cell in this column.
  10927. * @type string
  10928. * @default <i>Empty string</i>
  10929. *
  10930. * @name DataTable.defaults.column.class
  10931. * @dtopt Columns
  10932. *
  10933. * @example
  10934. * // Using `columnDefs`
  10935. * $(document).ready( function() {
  10936. * $('#example').dataTable( {
  10937. * "columnDefs": [
  10938. * { "class": "my_class", "targets": [ 0 ] }
  10939. * ]
  10940. * } );
  10941. * } );
  10942. *
  10943. * @example
  10944. * // Using `columns`
  10945. * $(document).ready( function() {
  10946. * $('#example').dataTable( {
  10947. * "columns": [
  10948. * { "class": "my_class" },
  10949. * null,
  10950. * null,
  10951. * null,
  10952. * null
  10953. * ]
  10954. * } );
  10955. * } );
  10956. */
  10957. "sClass": "",
  10958. /**
  10959. * When DataTables calculates the column widths to assign to each column,
  10960. * it finds the longest string in each column and then constructs a
  10961. * temporary table and reads the widths from that. The problem with this
  10962. * is that "mmm" is much wider then "iiii", but the latter is a longer
  10963. * string - thus the calculation can go wrong (doing it properly and putting
  10964. * it into an DOM object and measuring that is horribly(!) slow). Thus as
  10965. * a "work around" we provide this option. It will append its value to the
  10966. * text that is found to be the longest string for the column - i.e. padding.
  10967. * Generally you shouldn't need this!
  10968. * @type string
  10969. * @default <i>Empty string<i>
  10970. *
  10971. * @name DataTable.defaults.column.contentPadding
  10972. * @dtopt Columns
  10973. *
  10974. * @example
  10975. * // Using `columns`
  10976. * $(document).ready( function() {
  10977. * $('#example').dataTable( {
  10978. * "columns": [
  10979. * null,
  10980. * null,
  10981. * null,
  10982. * {
  10983. * "contentPadding": "mmm"
  10984. * }
  10985. * ]
  10986. * } );
  10987. * } );
  10988. */
  10989. "sContentPadding": "",
  10990. /**
  10991. * Allows a default value to be given for a column's data, and will be used
  10992. * whenever a null data source is encountered (this can be because `data`
  10993. * is set to null, or because the data source itself is null).
  10994. * @type string
  10995. * @default null
  10996. *
  10997. * @name DataTable.defaults.column.defaultContent
  10998. * @dtopt Columns
  10999. *
  11000. * @example
  11001. * // Using `columnDefs`
  11002. * $(document).ready( function() {
  11003. * $('#example').dataTable( {
  11004. * "columnDefs": [
  11005. * {
  11006. * "data": null,
  11007. * "defaultContent": "Edit",
  11008. * "targets": [ -1 ]
  11009. * }
  11010. * ]
  11011. * } );
  11012. * } );
  11013. *
  11014. * @example
  11015. * // Using `columns`
  11016. * $(document).ready( function() {
  11017. * $('#example').dataTable( {
  11018. * "columns": [
  11019. * null,
  11020. * null,
  11021. * null,
  11022. * {
  11023. * "data": null,
  11024. * "defaultContent": "Edit"
  11025. * }
  11026. * ]
  11027. * } );
  11028. * } );
  11029. */
  11030. "sDefaultContent": null,
  11031. /**
  11032. * This parameter is only used in DataTables' server-side processing. It can
  11033. * be exceptionally useful to know what columns are being displayed on the
  11034. * client side, and to map these to database fields. When defined, the names
  11035. * also allow DataTables to reorder information from the server if it comes
  11036. * back in an unexpected order (i.e. if you switch your columns around on the
  11037. * client-side, your server-side code does not also need updating).
  11038. * @type string
  11039. * @default <i>Empty string</i>
  11040. *
  11041. * @name DataTable.defaults.column.name
  11042. * @dtopt Columns
  11043. *
  11044. * @example
  11045. * // Using `columnDefs`
  11046. * $(document).ready( function() {
  11047. * $('#example').dataTable( {
  11048. * "columnDefs": [
  11049. * { "name": "engine", "targets": [ 0 ] },
  11050. * { "name": "browser", "targets": [ 1 ] },
  11051. * { "name": "platform", "targets": [ 2 ] },
  11052. * { "name": "version", "targets": [ 3 ] },
  11053. * { "name": "grade", "targets": [ 4 ] }
  11054. * ]
  11055. * } );
  11056. * } );
  11057. *
  11058. * @example
  11059. * // Using `columns`
  11060. * $(document).ready( function() {
  11061. * $('#example').dataTable( {
  11062. * "columns": [
  11063. * { "name": "engine" },
  11064. * { "name": "browser" },
  11065. * { "name": "platform" },
  11066. * { "name": "version" },
  11067. * { "name": "grade" }
  11068. * ]
  11069. * } );
  11070. * } );
  11071. */
  11072. "sName": "",
  11073. /**
  11074. * Defines a data source type for the ordering which can be used to read
  11075. * real-time information from the table (updating the internally cached
  11076. * version) prior to ordering. This allows ordering to occur on user
  11077. * editable elements such as form inputs.
  11078. * @type string
  11079. * @default std
  11080. *
  11081. * @name DataTable.defaults.column.orderDataType
  11082. * @dtopt Columns
  11083. *
  11084. * @example
  11085. * // Using `columnDefs`
  11086. * $(document).ready( function() {
  11087. * $('#example').dataTable( {
  11088. * "columnDefs": [
  11089. * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
  11090. * { "type": "numeric", "targets": [ 3 ] },
  11091. * { "orderDataType": "dom-select", "targets": [ 4 ] },
  11092. * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
  11093. * ]
  11094. * } );
  11095. * } );
  11096. *
  11097. * @example
  11098. * // Using `columns`
  11099. * $(document).ready( function() {
  11100. * $('#example').dataTable( {
  11101. * "columns": [
  11102. * null,
  11103. * null,
  11104. * { "orderDataType": "dom-text" },
  11105. * { "orderDataType": "dom-text", "type": "numeric" },
  11106. * { "orderDataType": "dom-select" },
  11107. * { "orderDataType": "dom-checkbox" }
  11108. * ]
  11109. * } );
  11110. * } );
  11111. */
  11112. "sSortDataType": "std",
  11113. /**
  11114. * The title of this column.
  11115. * @type string
  11116. * @default null <i>Derived from the 'TH' value for this column in the
  11117. * original HTML table.</i>
  11118. *
  11119. * @name DataTable.defaults.column.title
  11120. * @dtopt Columns
  11121. *
  11122. * @example
  11123. * // Using `columnDefs`
  11124. * $(document).ready( function() {
  11125. * $('#example').dataTable( {
  11126. * "columnDefs": [
  11127. * { "title": "My column title", "targets": [ 0 ] }
  11128. * ]
  11129. * } );
  11130. * } );
  11131. *
  11132. * @example
  11133. * // Using `columns`
  11134. * $(document).ready( function() {
  11135. * $('#example').dataTable( {
  11136. * "columns": [
  11137. * { "title": "My column title" },
  11138. * null,
  11139. * null,
  11140. * null,
  11141. * null
  11142. * ]
  11143. * } );
  11144. * } );
  11145. */
  11146. "sTitle": null,
  11147. /**
  11148. * The type allows you to specify how the data for this column will be
  11149. * ordered. Four types (string, numeric, date and html (which will strip
  11150. * HTML tags before ordering)) are currently available. Note that only date
  11151. * formats understood by Javascript's Date() object will be accepted as type
  11152. * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
  11153. * 'numeric', 'date' or 'html' (by default). Further types can be adding
  11154. * through plug-ins.
  11155. * @type string
  11156. * @default null <i>Auto-detected from raw data</i>
  11157. *
  11158. * @name DataTable.defaults.column.type
  11159. * @dtopt Columns
  11160. *
  11161. * @example
  11162. * // Using `columnDefs`
  11163. * $(document).ready( function() {
  11164. * $('#example').dataTable( {
  11165. * "columnDefs": [
  11166. * { "type": "html", "targets": [ 0 ] }
  11167. * ]
  11168. * } );
  11169. * } );
  11170. *
  11171. * @example
  11172. * // Using `columns`
  11173. * $(document).ready( function() {
  11174. * $('#example').dataTable( {
  11175. * "columns": [
  11176. * { "type": "html" },
  11177. * null,
  11178. * null,
  11179. * null,
  11180. * null
  11181. * ]
  11182. * } );
  11183. * } );
  11184. */
  11185. "sType": null,
  11186. /**
  11187. * Defining the width of the column, this parameter may take any CSS value
  11188. * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
  11189. * been given a specific width through this interface ensuring that the table
  11190. * remains readable.
  11191. * @type string
  11192. * @default null <i>Automatic</i>
  11193. *
  11194. * @name DataTable.defaults.column.width
  11195. * @dtopt Columns
  11196. *
  11197. * @example
  11198. * // Using `columnDefs`
  11199. * $(document).ready( function() {
  11200. * $('#example').dataTable( {
  11201. * "columnDefs": [
  11202. * { "width": "20%", "targets": [ 0 ] }
  11203. * ]
  11204. * } );
  11205. * } );
  11206. *
  11207. * @example
  11208. * // Using `columns`
  11209. * $(document).ready( function() {
  11210. * $('#example').dataTable( {
  11211. * "columns": [
  11212. * { "width": "20%" },
  11213. * null,
  11214. * null,
  11215. * null,
  11216. * null
  11217. * ]
  11218. * } );
  11219. * } );
  11220. */
  11221. "sWidth": null
  11222. };
  11223. _fnHungarianMap( DataTable.defaults.column );
  11224. /**
  11225. * DataTables settings object - this holds all the information needed for a
  11226. * given table, including configuration, data and current application of the
  11227. * table options. DataTables does not have a single instance for each DataTable
  11228. * with the settings attached to that instance, but rather instances of the
  11229. * DataTable "class" are created on-the-fly as needed (typically by a
  11230. * $().dataTable() call) and the settings object is then applied to that
  11231. * instance.
  11232. *
  11233. * Note that this object is related to {@link DataTable.defaults} but this
  11234. * one is the internal data store for DataTables's cache of columns. It should
  11235. * NOT be manipulated outside of DataTables. Any configuration should be done
  11236. * through the initialisation options.
  11237. * @namespace
  11238. * @todo Really should attach the settings object to individual instances so we
  11239. * don't need to create new instances on each $().dataTable() call (if the
  11240. * table already exists). It would also save passing oSettings around and
  11241. * into every single function. However, this is a very significant
  11242. * architecture change for DataTables and will almost certainly break
  11243. * backwards compatibility with older installations. This is something that
  11244. * will be done in 2.0.
  11245. */
  11246. DataTable.models.oSettings = {
  11247. /**
  11248. * Primary features of DataTables and their enablement state.
  11249. * @namespace
  11250. */
  11251. "oFeatures": {
  11252. /**
  11253. * Flag to say if DataTables should automatically try to calculate the
  11254. * optimum table and columns widths (true) or not (false).
  11255. * Note that this parameter will be set by the initialisation routine. To
  11256. * set a default use {@link DataTable.defaults}.
  11257. * @type boolean
  11258. */
  11259. "bAutoWidth": null,
  11260. /**
  11261. * Delay the creation of TR and TD elements until they are actually
  11262. * needed by a driven page draw. This can give a significant speed
  11263. * increase for Ajax source and Javascript source data, but makes no
  11264. * difference at all fro DOM and server-side processing tables.
  11265. * Note that this parameter will be set by the initialisation routine. To
  11266. * set a default use {@link DataTable.defaults}.
  11267. * @type boolean
  11268. */
  11269. "bDeferRender": null,
  11270. /**
  11271. * Enable filtering on the table or not. Note that if this is disabled
  11272. * then there is no filtering at all on the table, including fnFilter.
  11273. * To just remove the filtering input use sDom and remove the 'f' option.
  11274. * Note that this parameter will be set by the initialisation routine. To
  11275. * set a default use {@link DataTable.defaults}.
  11276. * @type boolean
  11277. */
  11278. "bFilter": null,
  11279. /**
  11280. * Table information element (the 'Showing x of y records' div) enable
  11281. * flag.
  11282. * Note that this parameter will be set by the initialisation routine. To
  11283. * set a default use {@link DataTable.defaults}.
  11284. * @type boolean
  11285. */
  11286. "bInfo": null,
  11287. /**
  11288. * Present a user control allowing the end user to change the page size
  11289. * when pagination is enabled.
  11290. * Note that this parameter will be set by the initialisation routine. To
  11291. * set a default use {@link DataTable.defaults}.
  11292. * @type boolean
  11293. */
  11294. "bLengthChange": null,
  11295. /**
  11296. * Pagination enabled or not. Note that if this is disabled then length
  11297. * changing must also be disabled.
  11298. * Note that this parameter will be set by the initialisation routine. To
  11299. * set a default use {@link DataTable.defaults}.
  11300. * @type boolean
  11301. */
  11302. "bPaginate": null,
  11303. /**
  11304. * Processing indicator enable flag whenever DataTables is enacting a
  11305. * user request - typically an Ajax request for server-side processing.
  11306. * Note that this parameter will be set by the initialisation routine. To
  11307. * set a default use {@link DataTable.defaults}.
  11308. * @type boolean
  11309. */
  11310. "bProcessing": null,
  11311. /**
  11312. * Server-side processing enabled flag - when enabled DataTables will
  11313. * get all data from the server for every draw - there is no filtering,
  11314. * sorting or paging done on the client-side.
  11315. * Note that this parameter will be set by the initialisation routine. To
  11316. * set a default use {@link DataTable.defaults}.
  11317. * @type boolean
  11318. */
  11319. "bServerSide": null,
  11320. /**
  11321. * Sorting enablement flag.
  11322. * Note that this parameter will be set by the initialisation routine. To
  11323. * set a default use {@link DataTable.defaults}.
  11324. * @type boolean
  11325. */
  11326. "bSort": null,
  11327. /**
  11328. * Multi-column sorting
  11329. * Note that this parameter will be set by the initialisation routine. To
  11330. * set a default use {@link DataTable.defaults}.
  11331. * @type boolean
  11332. */
  11333. "bSortMulti": null,
  11334. /**
  11335. * Apply a class to the columns which are being sorted to provide a
  11336. * visual highlight or not. This can slow things down when enabled since
  11337. * there is a lot of DOM interaction.
  11338. * Note that this parameter will be set by the initialisation routine. To
  11339. * set a default use {@link DataTable.defaults}.
  11340. * @type boolean
  11341. */
  11342. "bSortClasses": null,
  11343. /**
  11344. * State saving enablement flag.
  11345. * Note that this parameter will be set by the initialisation routine. To
  11346. * set a default use {@link DataTable.defaults}.
  11347. * @type boolean
  11348. */
  11349. "bStateSave": null
  11350. },
  11351. /**
  11352. * Scrolling settings for a table.
  11353. * @namespace
  11354. */
  11355. "oScroll": {
  11356. /**
  11357. * When the table is shorter in height than sScrollY, collapse the
  11358. * table container down to the height of the table (when true).
  11359. * Note that this parameter will be set by the initialisation routine. To
  11360. * set a default use {@link DataTable.defaults}.
  11361. * @type boolean
  11362. */
  11363. "bCollapse": null,
  11364. /**
  11365. * Width of the scrollbar for the web-browser's platform. Calculated
  11366. * during table initialisation.
  11367. * @type int
  11368. * @default 0
  11369. */
  11370. "iBarWidth": 0,
  11371. /**
  11372. * Viewport width for horizontal scrolling. Horizontal scrolling is
  11373. * disabled if an empty string.
  11374. * Note that this parameter will be set by the initialisation routine. To
  11375. * set a default use {@link DataTable.defaults}.
  11376. * @type string
  11377. */
  11378. "sX": null,
  11379. /**
  11380. * Width to expand the table to when using x-scrolling. Typically you
  11381. * should not need to use this.
  11382. * Note that this parameter will be set by the initialisation routine. To
  11383. * set a default use {@link DataTable.defaults}.
  11384. * @type string
  11385. * @deprecated
  11386. */
  11387. "sXInner": null,
  11388. /**
  11389. * Viewport height for vertical scrolling. Vertical scrolling is disabled
  11390. * if an empty string.
  11391. * Note that this parameter will be set by the initialisation routine. To
  11392. * set a default use {@link DataTable.defaults}.
  11393. * @type string
  11394. */
  11395. "sY": null
  11396. },
  11397. /**
  11398. * Language information for the table.
  11399. * @namespace
  11400. * @extends DataTable.defaults.oLanguage
  11401. */
  11402. "oLanguage": {
  11403. /**
  11404. * Information callback function. See
  11405. * {@link DataTable.defaults.fnInfoCallback}
  11406. * @type function
  11407. * @default null
  11408. */
  11409. "fnInfoCallback": null
  11410. },
  11411. /**
  11412. * Browser support parameters
  11413. * @namespace
  11414. */
  11415. "oBrowser": {
  11416. /**
  11417. * Indicate if the browser incorrectly calculates width:100% inside a
  11418. * scrolling element (IE6/7)
  11419. * @type boolean
  11420. * @default false
  11421. */
  11422. "bScrollOversize": false,
  11423. /**
  11424. * Determine if the vertical scrollbar is on the right or left of the
  11425. * scrolling container - needed for rtl language layout, although not
  11426. * all browsers move the scrollbar (Safari).
  11427. * @type boolean
  11428. * @default false
  11429. */
  11430. "bScrollbarLeft": false,
  11431. /**
  11432. * Flag for if `getBoundingClientRect` is fully supported or not
  11433. * @type boolean
  11434. * @default false
  11435. */
  11436. "bBounding": false,
  11437. /**
  11438. * Browser scrollbar width
  11439. * @type integer
  11440. * @default 0
  11441. */
  11442. "barWidth": 0
  11443. },
  11444. "ajax": null,
  11445. /**
  11446. * Array referencing the nodes which are used for the features. The
  11447. * parameters of this object match what is allowed by sDom - i.e.
  11448. * <ul>
  11449. * <li>'l' - Length changing</li>
  11450. * <li>'f' - Filtering input</li>
  11451. * <li>'t' - The table!</li>
  11452. * <li>'i' - Information</li>
  11453. * <li>'p' - Pagination</li>
  11454. * <li>'r' - pRocessing</li>
  11455. * </ul>
  11456. * @type array
  11457. * @default []
  11458. */
  11459. "aanFeatures": [],
  11460. /**
  11461. * Store data information - see {@link DataTable.models.oRow} for detailed
  11462. * information.
  11463. * @type array
  11464. * @default []
  11465. */
  11466. "aoData": [],
  11467. /**
  11468. * Array of indexes which are in the current display (after filtering etc)
  11469. * @type array
  11470. * @default []
  11471. */
  11472. "aiDisplay": [],
  11473. /**
  11474. * Array of indexes for display - no filtering
  11475. * @type array
  11476. * @default []
  11477. */
  11478. "aiDisplayMaster": [],
  11479. /**
  11480. * Map of row ids to data indexes
  11481. * @type object
  11482. * @default {}
  11483. */
  11484. "aIds": {},
  11485. /**
  11486. * Store information about each column that is in use
  11487. * @type array
  11488. * @default []
  11489. */
  11490. "aoColumns": [],
  11491. /**
  11492. * Store information about the table's header
  11493. * @type array
  11494. * @default []
  11495. */
  11496. "aoHeader": [],
  11497. /**
  11498. * Store information about the table's footer
  11499. * @type array
  11500. * @default []
  11501. */
  11502. "aoFooter": [],
  11503. /**
  11504. * Store the applied global search information in case we want to force a
  11505. * research or compare the old search to a new one.
  11506. * Note that this parameter will be set by the initialisation routine. To
  11507. * set a default use {@link DataTable.defaults}.
  11508. * @namespace
  11509. * @extends DataTable.models.oSearch
  11510. */
  11511. "oPreviousSearch": {},
  11512. /**
  11513. * Store the applied search for each column - see
  11514. * {@link DataTable.models.oSearch} for the format that is used for the
  11515. * filtering information for each column.
  11516. * @type array
  11517. * @default []
  11518. */
  11519. "aoPreSearchCols": [],
  11520. /**
  11521. * Sorting that is applied to the table. Note that the inner arrays are
  11522. * used in the following manner:
  11523. * <ul>
  11524. * <li>Index 0 - column number</li>
  11525. * <li>Index 1 - current sorting direction</li>
  11526. * </ul>
  11527. * Note that this parameter will be set by the initialisation routine. To
  11528. * set a default use {@link DataTable.defaults}.
  11529. * @type array
  11530. * @todo These inner arrays should really be objects
  11531. */
  11532. "aaSorting": null,
  11533. /**
  11534. * Sorting that is always applied to the table (i.e. prefixed in front of
  11535. * aaSorting).
  11536. * Note that this parameter will be set by the initialisation routine. To
  11537. * set a default use {@link DataTable.defaults}.
  11538. * @type array
  11539. * @default []
  11540. */
  11541. "aaSortingFixed": [],
  11542. /**
  11543. * Classes to use for the striping of a table.
  11544. * Note that this parameter will be set by the initialisation routine. To
  11545. * set a default use {@link DataTable.defaults}.
  11546. * @type array
  11547. * @default []
  11548. */
  11549. "asStripeClasses": null,
  11550. /**
  11551. * If restoring a table - we should restore its striping classes as well
  11552. * @type array
  11553. * @default []
  11554. */
  11555. "asDestroyStripes": [],
  11556. /**
  11557. * If restoring a table - we should restore its width
  11558. * @type int
  11559. * @default 0
  11560. */
  11561. "sDestroyWidth": 0,
  11562. /**
  11563. * Callback functions array for every time a row is inserted (i.e. on a draw).
  11564. * @type array
  11565. * @default []
  11566. */
  11567. "aoRowCallback": [],
  11568. /**
  11569. * Callback functions for the header on each draw.
  11570. * @type array
  11571. * @default []
  11572. */
  11573. "aoHeaderCallback": [],
  11574. /**
  11575. * Callback function for the footer on each draw.
  11576. * @type array
  11577. * @default []
  11578. */
  11579. "aoFooterCallback": [],
  11580. /**
  11581. * Array of callback functions for draw callback functions
  11582. * @type array
  11583. * @default []
  11584. */
  11585. "aoDrawCallback": [],
  11586. /**
  11587. * Array of callback functions for row created function
  11588. * @type array
  11589. * @default []
  11590. */
  11591. "aoRowCreatedCallback": [],
  11592. /**
  11593. * Callback functions for just before the table is redrawn. A return of
  11594. * false will be used to cancel the draw.
  11595. * @type array
  11596. * @default []
  11597. */
  11598. "aoPreDrawCallback": [],
  11599. /**
  11600. * Callback functions for when the table has been initialised.
  11601. * @type array
  11602. * @default []
  11603. */
  11604. "aoInitComplete": [],
  11605. /**
  11606. * Callbacks for modifying the settings to be stored for state saving, prior to
  11607. * saving state.
  11608. * @type array
  11609. * @default []
  11610. */
  11611. "aoStateSaveParams": [],
  11612. /**
  11613. * Callbacks for modifying the settings that have been stored for state saving
  11614. * prior to using the stored values to restore the state.
  11615. * @type array
  11616. * @default []
  11617. */
  11618. "aoStateLoadParams": [],
  11619. /**
  11620. * Callbacks for operating on the settings object once the saved state has been
  11621. * loaded
  11622. * @type array
  11623. * @default []
  11624. */
  11625. "aoStateLoaded": [],
  11626. /**
  11627. * Cache the table ID for quick access
  11628. * @type string
  11629. * @default <i>Empty string</i>
  11630. */
  11631. "sTableId": "",
  11632. /**
  11633. * The TABLE node for the main table
  11634. * @type node
  11635. * @default null
  11636. */
  11637. "nTable": null,
  11638. /**
  11639. * Permanent ref to the thead element
  11640. * @type node
  11641. * @default null
  11642. */
  11643. "nTHead": null,
  11644. /**
  11645. * Permanent ref to the tfoot element - if it exists
  11646. * @type node
  11647. * @default null
  11648. */
  11649. "nTFoot": null,
  11650. /**
  11651. * Permanent ref to the tbody element
  11652. * @type node
  11653. * @default null
  11654. */
  11655. "nTBody": null,
  11656. /**
  11657. * Cache the wrapper node (contains all DataTables controlled elements)
  11658. * @type node
  11659. * @default null
  11660. */
  11661. "nTableWrapper": null,
  11662. /**
  11663. * Indicate if when using server-side processing the loading of data
  11664. * should be deferred until the second draw.
  11665. * Note that this parameter will be set by the initialisation routine. To
  11666. * set a default use {@link DataTable.defaults}.
  11667. * @type boolean
  11668. * @default false
  11669. */
  11670. "bDeferLoading": false,
  11671. /**
  11672. * Indicate if all required information has been read in
  11673. * @type boolean
  11674. * @default false
  11675. */
  11676. "bInitialised": false,
  11677. /**
  11678. * Information about open rows. Each object in the array has the parameters
  11679. * 'nTr' and 'nParent'
  11680. * @type array
  11681. * @default []
  11682. */
  11683. "aoOpenRows": [],
  11684. /**
  11685. * Dictate the positioning of DataTables' control elements - see
  11686. * {@link DataTable.model.oInit.sDom}.
  11687. * Note that this parameter will be set by the initialisation routine. To
  11688. * set a default use {@link DataTable.defaults}.
  11689. * @type string
  11690. * @default null
  11691. */
  11692. "sDom": null,
  11693. /**
  11694. * Search delay (in mS)
  11695. * @type integer
  11696. * @default null
  11697. */
  11698. "searchDelay": null,
  11699. /**
  11700. * Which type of pagination should be used.
  11701. * Note that this parameter will be set by the initialisation routine. To
  11702. * set a default use {@link DataTable.defaults}.
  11703. * @type string
  11704. * @default two_button
  11705. */
  11706. "sPaginationType": "two_button",
  11707. /**
  11708. * The state duration (for `stateSave`) in seconds.
  11709. * Note that this parameter will be set by the initialisation routine. To
  11710. * set a default use {@link DataTable.defaults}.
  11711. * @type int
  11712. * @default 0
  11713. */
  11714. "iStateDuration": 0,
  11715. /**
  11716. * Array of callback functions for state saving. Each array element is an
  11717. * object with the following parameters:
  11718. * <ul>
  11719. * <li>function:fn - function to call. Takes two parameters, oSettings
  11720. * and the JSON string to save that has been thus far created. Returns
  11721. * a JSON string to be inserted into a json object
  11722. * (i.e. '"param": [ 0, 1, 2]')</li>
  11723. * <li>string:sName - name of callback</li>
  11724. * </ul>
  11725. * @type array
  11726. * @default []
  11727. */
  11728. "aoStateSave": [],
  11729. /**
  11730. * Array of callback functions for state loading. Each array element is an
  11731. * object with the following parameters:
  11732. * <ul>
  11733. * <li>function:fn - function to call. Takes two parameters, oSettings
  11734. * and the object stored. May return false to cancel state loading</li>
  11735. * <li>string:sName - name of callback</li>
  11736. * </ul>
  11737. * @type array
  11738. * @default []
  11739. */
  11740. "aoStateLoad": [],
  11741. /**
  11742. * State that was saved. Useful for back reference
  11743. * @type object
  11744. * @default null
  11745. */
  11746. "oSavedState": null,
  11747. /**
  11748. * State that was loaded. Useful for back reference
  11749. * @type object
  11750. * @default null
  11751. */
  11752. "oLoadedState": null,
  11753. /**
  11754. * Source url for AJAX data for the table.
  11755. * Note that this parameter will be set by the initialisation routine. To
  11756. * set a default use {@link DataTable.defaults}.
  11757. * @type string
  11758. * @default null
  11759. */
  11760. "sAjaxSource": null,
  11761. /**
  11762. * Property from a given object from which to read the table data from. This
  11763. * can be an empty string (when not server-side processing), in which case
  11764. * it is assumed an an array is given directly.
  11765. * Note that this parameter will be set by the initialisation routine. To
  11766. * set a default use {@link DataTable.defaults}.
  11767. * @type string
  11768. */
  11769. "sAjaxDataProp": null,
  11770. /**
  11771. * Note if draw should be blocked while getting data
  11772. * @type boolean
  11773. * @default true
  11774. */
  11775. "bAjaxDataGet": true,
  11776. /**
  11777. * The last jQuery XHR object that was used for server-side data gathering.
  11778. * This can be used for working with the XHR information in one of the
  11779. * callbacks
  11780. * @type object
  11781. * @default null
  11782. */
  11783. "jqXHR": null,
  11784. /**
  11785. * JSON returned from the server in the last Ajax request
  11786. * @type object
  11787. * @default undefined
  11788. */
  11789. "json": undefined,
  11790. /**
  11791. * Data submitted as part of the last Ajax request
  11792. * @type object
  11793. * @default undefined
  11794. */
  11795. "oAjaxData": undefined,
  11796. /**
  11797. * Function to get the server-side data.
  11798. * Note that this parameter will be set by the initialisation routine. To
  11799. * set a default use {@link DataTable.defaults}.
  11800. * @type function
  11801. */
  11802. "fnServerData": null,
  11803. /**
  11804. * Functions which are called prior to sending an Ajax request so extra
  11805. * parameters can easily be sent to the server
  11806. * @type array
  11807. * @default []
  11808. */
  11809. "aoServerParams": [],
  11810. /**
  11811. * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
  11812. * required).
  11813. * Note that this parameter will be set by the initialisation routine. To
  11814. * set a default use {@link DataTable.defaults}.
  11815. * @type string
  11816. */
  11817. "sServerMethod": null,
  11818. /**
  11819. * Format numbers for display.
  11820. * Note that this parameter will be set by the initialisation routine. To
  11821. * set a default use {@link DataTable.defaults}.
  11822. * @type function
  11823. */
  11824. "fnFormatNumber": null,
  11825. /**
  11826. * List of options that can be used for the user selectable length menu.
  11827. * Note that this parameter will be set by the initialisation routine. To
  11828. * set a default use {@link DataTable.defaults}.
  11829. * @type array
  11830. * @default []
  11831. */
  11832. "aLengthMenu": null,
  11833. /**
  11834. * Counter for the draws that the table does. Also used as a tracker for
  11835. * server-side processing
  11836. * @type int
  11837. * @default 0
  11838. */
  11839. "iDraw": 0,
  11840. /**
  11841. * Indicate if a redraw is being done - useful for Ajax
  11842. * @type boolean
  11843. * @default false
  11844. */
  11845. "bDrawing": false,
  11846. /**
  11847. * Draw index (iDraw) of the last error when parsing the returned data
  11848. * @type int
  11849. * @default -1
  11850. */
  11851. "iDrawError": -1,
  11852. /**
  11853. * Paging display length
  11854. * @type int
  11855. * @default 10
  11856. */
  11857. "_iDisplayLength": 10,
  11858. /**
  11859. * Paging start point - aiDisplay index
  11860. * @type int
  11861. * @default 0
  11862. */
  11863. "_iDisplayStart": 0,
  11864. /**
  11865. * Server-side processing - number of records in the result set
  11866. * (i.e. before filtering), Use fnRecordsTotal rather than
  11867. * this property to get the value of the number of records, regardless of
  11868. * the server-side processing setting.
  11869. * @type int
  11870. * @default 0
  11871. * @private
  11872. */
  11873. "_iRecordsTotal": 0,
  11874. /**
  11875. * Server-side processing - number of records in the current display set
  11876. * (i.e. after filtering). Use fnRecordsDisplay rather than
  11877. * this property to get the value of the number of records, regardless of
  11878. * the server-side processing setting.
  11879. * @type boolean
  11880. * @default 0
  11881. * @private
  11882. */
  11883. "_iRecordsDisplay": 0,
  11884. /**
  11885. * The classes to use for the table
  11886. * @type object
  11887. * @default {}
  11888. */
  11889. "oClasses": {},
  11890. /**
  11891. * Flag attached to the settings object so you can check in the draw
  11892. * callback if filtering has been done in the draw. Deprecated in favour of
  11893. * events.
  11894. * @type boolean
  11895. * @default false
  11896. * @deprecated
  11897. */
  11898. "bFiltered": false,
  11899. /**
  11900. * Flag attached to the settings object so you can check in the draw
  11901. * callback if sorting has been done in the draw. Deprecated in favour of
  11902. * events.
  11903. * @type boolean
  11904. * @default false
  11905. * @deprecated
  11906. */
  11907. "bSorted": false,
  11908. /**
  11909. * Indicate that if multiple rows are in the header and there is more than
  11910. * one unique cell per column, if the top one (true) or bottom one (false)
  11911. * should be used for sorting / title by DataTables.
  11912. * Note that this parameter will be set by the initialisation routine. To
  11913. * set a default use {@link DataTable.defaults}.
  11914. * @type boolean
  11915. */
  11916. "bSortCellsTop": null,
  11917. /**
  11918. * Initialisation object that is used for the table
  11919. * @type object
  11920. * @default null
  11921. */
  11922. "oInit": null,
  11923. /**
  11924. * Destroy callback functions - for plug-ins to attach themselves to the
  11925. * destroy so they can clean up markup and events.
  11926. * @type array
  11927. * @default []
  11928. */
  11929. "aoDestroyCallback": [],
  11930. /**
  11931. * Get the number of records in the current record set, before filtering
  11932. * @type function
  11933. */
  11934. "fnRecordsTotal": function ()
  11935. {
  11936. return _fnDataSource( this ) == 'ssp' ?
  11937. this._iRecordsTotal * 1 :
  11938. this.aiDisplayMaster.length;
  11939. },
  11940. /**
  11941. * Get the number of records in the current record set, after filtering
  11942. * @type function
  11943. */
  11944. "fnRecordsDisplay": function ()
  11945. {
  11946. return _fnDataSource( this ) == 'ssp' ?
  11947. this._iRecordsDisplay * 1 :
  11948. this.aiDisplay.length;
  11949. },
  11950. /**
  11951. * Get the display end point - aiDisplay index
  11952. * @type function
  11953. */
  11954. "fnDisplayEnd": function ()
  11955. {
  11956. var
  11957. len = this._iDisplayLength,
  11958. start = this._iDisplayStart,
  11959. calc = start + len,
  11960. records = this.aiDisplay.length,
  11961. features = this.oFeatures,
  11962. paginate = features.bPaginate;
  11963. if ( features.bServerSide ) {
  11964. return paginate === false || len === -1 ?
  11965. start + records :
  11966. Math.min( start+len, this._iRecordsDisplay );
  11967. }
  11968. else {
  11969. return ! paginate || calc>records || len===-1 ?
  11970. records :
  11971. calc;
  11972. }
  11973. },
  11974. /**
  11975. * The DataTables object for this table
  11976. * @type object
  11977. * @default null
  11978. */
  11979. "oInstance": null,
  11980. /**
  11981. * Unique identifier for each instance of the DataTables object. If there
  11982. * is an ID on the table node, then it takes that value, otherwise an
  11983. * incrementing internal counter is used.
  11984. * @type string
  11985. * @default null
  11986. */
  11987. "sInstance": null,
  11988. /**
  11989. * tabindex attribute value that is added to DataTables control elements, allowing
  11990. * keyboard navigation of the table and its controls.
  11991. */
  11992. "iTabIndex": 0,
  11993. /**
  11994. * DIV container for the footer scrolling table if scrolling
  11995. */
  11996. "nScrollHead": null,
  11997. /**
  11998. * DIV container for the footer scrolling table if scrolling
  11999. */
  12000. "nScrollFoot": null,
  12001. /**
  12002. * Last applied sort
  12003. * @type array
  12004. * @default []
  12005. */
  12006. "aLastSort": [],
  12007. /**
  12008. * Stored plug-in instances
  12009. * @type object
  12010. * @default {}
  12011. */
  12012. "oPlugins": {},
  12013. /**
  12014. * Function used to get a row's id from the row's data
  12015. * @type function
  12016. * @default null
  12017. */
  12018. "rowIdFn": null,
  12019. /**
  12020. * Data location where to store a row's id
  12021. * @type string
  12022. * @default null
  12023. */
  12024. "rowId": null
  12025. };
  12026. /**
  12027. * Extension object for DataTables that is used to provide all extension
  12028. * options.
  12029. *
  12030. * Note that the `DataTable.ext` object is available through
  12031. * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
  12032. * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
  12033. * @namespace
  12034. * @extends DataTable.models.ext
  12035. */
  12036. /**
  12037. * DataTables extensions
  12038. *
  12039. * This namespace acts as a collection area for plug-ins that can be used to
  12040. * extend DataTables capabilities. Indeed many of the build in methods
  12041. * use this method to provide their own capabilities (sorting methods for
  12042. * example).
  12043. *
  12044. * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
  12045. * reasons
  12046. *
  12047. * @namespace
  12048. */
  12049. DataTable.ext = _ext = {
  12050. /**
  12051. * Buttons. For use with the Buttons extension for DataTables. This is
  12052. * defined here so other extensions can define buttons regardless of load
  12053. * order. It is _not_ used by DataTables core.
  12054. *
  12055. * @type object
  12056. * @default {}
  12057. */
  12058. buttons: {},
  12059. /**
  12060. * Element class names
  12061. *
  12062. * @type object
  12063. * @default {}
  12064. */
  12065. classes: {},
  12066. /**
  12067. * DataTables build type (expanded by the download builder)
  12068. *
  12069. * @type string
  12070. */
  12071. builder: "-source-",
  12072. /**
  12073. * Error reporting.
  12074. *
  12075. * How should DataTables report an error. Can take the value 'alert',
  12076. * 'throw', 'none' or a function.
  12077. *
  12078. * @type string|function
  12079. * @default alert
  12080. */
  12081. errMode: "alert",
  12082. /**
  12083. * Feature plug-ins.
  12084. *
  12085. * This is an array of objects which describe the feature plug-ins that are
  12086. * available to DataTables. These feature plug-ins are then available for
  12087. * use through the `dom` initialisation option.
  12088. *
  12089. * Each feature plug-in is described by an object which must have the
  12090. * following properties:
  12091. *
  12092. * * `fnInit` - function that is used to initialise the plug-in,
  12093. * * `cFeature` - a character so the feature can be enabled by the `dom`
  12094. * instillation option. This is case sensitive.
  12095. *
  12096. * The `fnInit` function has the following input parameters:
  12097. *
  12098. * 1. `{object}` DataTables settings object: see
  12099. * {@link DataTable.models.oSettings}
  12100. *
  12101. * And the following return is expected:
  12102. *
  12103. * * {node|null} The element which contains your feature. Note that the
  12104. * return may also be void if your plug-in does not require to inject any
  12105. * DOM elements into DataTables control (`dom`) - for example this might
  12106. * be useful when developing a plug-in which allows table control via
  12107. * keyboard entry
  12108. *
  12109. * @type array
  12110. *
  12111. * @example
  12112. * $.fn.dataTable.ext.features.push( {
  12113. * "fnInit": function( oSettings ) {
  12114. * return new TableTools( { "oDTSettings": oSettings } );
  12115. * },
  12116. * "cFeature": "T"
  12117. * } );
  12118. */
  12119. feature: [],
  12120. /**
  12121. * Row searching.
  12122. *
  12123. * This method of searching is complimentary to the default type based
  12124. * searching, and a lot more comprehensive as it allows you complete control
  12125. * over the searching logic. Each element in this array is a function
  12126. * (parameters described below) that is called for every row in the table,
  12127. * and your logic decides if it should be included in the searching data set
  12128. * or not.
  12129. *
  12130. * Searching functions have the following input parameters:
  12131. *
  12132. * 1. `{object}` DataTables settings object: see
  12133. * {@link DataTable.models.oSettings}
  12134. * 2. `{array|object}` Data for the row to be processed (same as the
  12135. * original format that was passed in as the data source, or an array
  12136. * from a DOM data source
  12137. * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
  12138. * can be useful to retrieve the `TR` element if you need DOM interaction.
  12139. *
  12140. * And the following return is expected:
  12141. *
  12142. * * {boolean} Include the row in the searched result set (true) or not
  12143. * (false)
  12144. *
  12145. * Note that as with the main search ability in DataTables, technically this
  12146. * is "filtering", since it is subtractive. However, for consistency in
  12147. * naming we call it searching here.
  12148. *
  12149. * @type array
  12150. * @default []
  12151. *
  12152. * @example
  12153. * // The following example shows custom search being applied to the
  12154. * // fourth column (i.e. the data[3] index) based on two input values
  12155. * // from the end-user, matching the data in a certain range.
  12156. * $.fn.dataTable.ext.search.push(
  12157. * function( settings, data, dataIndex ) {
  12158. * var min = document.getElementById('min').value * 1;
  12159. * var max = document.getElementById('max').value * 1;
  12160. * var version = data[3] == "-" ? 0 : data[3]*1;
  12161. *
  12162. * if ( min == "" && max == "" ) {
  12163. * return true;
  12164. * }
  12165. * else if ( min == "" && version < max ) {
  12166. * return true;
  12167. * }
  12168. * else if ( min < version && "" == max ) {
  12169. * return true;
  12170. * }
  12171. * else if ( min < version && version < max ) {
  12172. * return true;
  12173. * }
  12174. * return false;
  12175. * }
  12176. * );
  12177. */
  12178. search: [],
  12179. /**
  12180. * Selector extensions
  12181. *
  12182. * The `selector` option can be used to extend the options available for the
  12183. * selector modifier options (`selector-modifier` object data type) that
  12184. * each of the three built in selector types offer (row, column and cell +
  12185. * their plural counterparts). For example the Select extension uses this
  12186. * mechanism to provide an option to select only rows, columns and cells
  12187. * that have been marked as selected by the end user (`{selected: true}`),
  12188. * which can be used in conjunction with the existing built in selector
  12189. * options.
  12190. *
  12191. * Each property is an array to which functions can be pushed. The functions
  12192. * take three attributes:
  12193. *
  12194. * * Settings object for the host table
  12195. * * Options object (`selector-modifier` object type)
  12196. * * Array of selected item indexes
  12197. *
  12198. * The return is an array of the resulting item indexes after the custom
  12199. * selector has been applied.
  12200. *
  12201. * @type object
  12202. */
  12203. selector: {
  12204. cell: [],
  12205. column: [],
  12206. row: []
  12207. },
  12208. /**
  12209. * Internal functions, exposed for used in plug-ins.
  12210. *
  12211. * Please note that you should not need to use the internal methods for
  12212. * anything other than a plug-in (and even then, try to avoid if possible).
  12213. * The internal function may change between releases.
  12214. *
  12215. * @type object
  12216. * @default {}
  12217. */
  12218. internal: {},
  12219. /**
  12220. * Legacy configuration options. Enable and disable legacy options that
  12221. * are available in DataTables.
  12222. *
  12223. * @type object
  12224. */
  12225. legacy: {
  12226. /**
  12227. * Enable / disable DataTables 1.9 compatible server-side processing
  12228. * requests
  12229. *
  12230. * @type boolean
  12231. * @default null
  12232. */
  12233. ajax: null
  12234. },
  12235. /**
  12236. * Pagination plug-in methods.
  12237. *
  12238. * Each entry in this object is a function and defines which buttons should
  12239. * be shown by the pagination rendering method that is used for the table:
  12240. * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
  12241. * buttons are displayed in the document, while the functions here tell it
  12242. * what buttons to display. This is done by returning an array of button
  12243. * descriptions (what each button will do).
  12244. *
  12245. * Pagination types (the four built in options and any additional plug-in
  12246. * options defined here) can be used through the `paginationType`
  12247. * initialisation parameter.
  12248. *
  12249. * The functions defined take two parameters:
  12250. *
  12251. * 1. `{int} page` The current page index
  12252. * 2. `{int} pages` The number of pages in the table
  12253. *
  12254. * Each function is expected to return an array where each element of the
  12255. * array can be one of:
  12256. *
  12257. * * `first` - Jump to first page when activated
  12258. * * `last` - Jump to last page when activated
  12259. * * `previous` - Show previous page when activated
  12260. * * `next` - Show next page when activated
  12261. * * `{int}` - Show page of the index given
  12262. * * `{array}` - A nested array containing the above elements to add a
  12263. * containing 'DIV' element (might be useful for styling).
  12264. *
  12265. * Note that DataTables v1.9- used this object slightly differently whereby
  12266. * an object with two functions would be defined for each plug-in. That
  12267. * ability is still supported by DataTables 1.10+ to provide backwards
  12268. * compatibility, but this option of use is now decremented and no longer
  12269. * documented in DataTables 1.10+.
  12270. *
  12271. * @type object
  12272. * @default {}
  12273. *
  12274. * @example
  12275. * // Show previous, next and current page buttons only
  12276. * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
  12277. * return [ 'previous', page, 'next' ];
  12278. * };
  12279. */
  12280. pager: {},
  12281. renderer: {
  12282. pageButton: {},
  12283. header: {}
  12284. },
  12285. /**
  12286. * Ordering plug-ins - custom data source
  12287. *
  12288. * The extension options for ordering of data available here is complimentary
  12289. * to the default type based ordering that DataTables typically uses. It
  12290. * allows much greater control over the the data that is being used to
  12291. * order a column, but is necessarily therefore more complex.
  12292. *
  12293. * This type of ordering is useful if you want to do ordering based on data
  12294. * live from the DOM (for example the contents of an 'input' element) rather
  12295. * than just the static string that DataTables knows of.
  12296. *
  12297. * The way these plug-ins work is that you create an array of the values you
  12298. * wish to be ordering for the column in question and then return that
  12299. * array. The data in the array much be in the index order of the rows in
  12300. * the table (not the currently ordering order!). Which order data gathering
  12301. * function is run here depends on the `dt-init columns.orderDataType`
  12302. * parameter that is used for the column (if any).
  12303. *
  12304. * The functions defined take two parameters:
  12305. *
  12306. * 1. `{object}` DataTables settings object: see
  12307. * {@link DataTable.models.oSettings}
  12308. * 2. `{int}` Target column index
  12309. *
  12310. * Each function is expected to return an array:
  12311. *
  12312. * * `{array}` Data for the column to be ordering upon
  12313. *
  12314. * @type array
  12315. *
  12316. * @example
  12317. * // Ordering using `input` node values
  12318. * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
  12319. * {
  12320. * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
  12321. * return $('input', td).val();
  12322. * } );
  12323. * }
  12324. */
  12325. order: {},
  12326. /**
  12327. * Type based plug-ins.
  12328. *
  12329. * Each column in DataTables has a type assigned to it, either by automatic
  12330. * detection or by direct assignment using the `type` option for the column.
  12331. * The type of a column will effect how it is ordering and search (plug-ins
  12332. * can also make use of the column type if required).
  12333. *
  12334. * @namespace
  12335. */
  12336. type: {
  12337. /**
  12338. * Type detection functions.
  12339. *
  12340. * The functions defined in this object are used to automatically detect
  12341. * a column's type, making initialisation of DataTables super easy, even
  12342. * when complex data is in the table.
  12343. *
  12344. * The functions defined take two parameters:
  12345. *
  12346. * 1. `{*}` Data from the column cell to be analysed
  12347. * 2. `{settings}` DataTables settings object. This can be used to
  12348. * perform context specific type detection - for example detection
  12349. * based on language settings such as using a comma for a decimal
  12350. * place. Generally speaking the options from the settings will not
  12351. * be required
  12352. *
  12353. * Each function is expected to return:
  12354. *
  12355. * * `{string|null}` Data type detected, or null if unknown (and thus
  12356. * pass it on to the other type detection functions.
  12357. *
  12358. * @type array
  12359. *
  12360. * @example
  12361. * // Currency type detection plug-in:
  12362. * $.fn.dataTable.ext.type.detect.push(
  12363. * function ( data, settings ) {
  12364. * // Check the numeric part
  12365. * if ( ! data.substring(1).match(/[0-9]/) ) {
  12366. * return null;
  12367. * }
  12368. *
  12369. * // Check prefixed by currency
  12370. * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
  12371. * return 'currency';
  12372. * }
  12373. * return null;
  12374. * }
  12375. * );
  12376. */
  12377. detect: [],
  12378. /**
  12379. * Type based search formatting.
  12380. *
  12381. * The type based searching functions can be used to pre-format the
  12382. * data to be search on. For example, it can be used to strip HTML
  12383. * tags or to de-format telephone numbers for numeric only searching.
  12384. *
  12385. * Note that is a search is not defined for a column of a given type,
  12386. * no search formatting will be performed.
  12387. *
  12388. * Pre-processing of searching data plug-ins - When you assign the sType
  12389. * for a column (or have it automatically detected for you by DataTables
  12390. * or a type detection plug-in), you will typically be using this for
  12391. * custom sorting, but it can also be used to provide custom searching
  12392. * by allowing you to pre-processing the data and returning the data in
  12393. * the format that should be searched upon. This is done by adding
  12394. * functions this object with a parameter name which matches the sType
  12395. * for that target column. This is the corollary of <i>afnSortData</i>
  12396. * for searching data.
  12397. *
  12398. * The functions defined take a single parameter:
  12399. *
  12400. * 1. `{*}` Data from the column cell to be prepared for searching
  12401. *
  12402. * Each function is expected to return:
  12403. *
  12404. * * `{string|null}` Formatted string that will be used for the searching.
  12405. *
  12406. * @type object
  12407. * @default {}
  12408. *
  12409. * @example
  12410. * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
  12411. * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
  12412. * }
  12413. */
  12414. search: {},
  12415. /**
  12416. * Type based ordering.
  12417. *
  12418. * The column type tells DataTables what ordering to apply to the table
  12419. * when a column is sorted upon. The order for each type that is defined,
  12420. * is defined by the functions available in this object.
  12421. *
  12422. * Each ordering option can be described by three properties added to
  12423. * this object:
  12424. *
  12425. * * `{type}-pre` - Pre-formatting function
  12426. * * `{type}-asc` - Ascending order function
  12427. * * `{type}-desc` - Descending order function
  12428. *
  12429. * All three can be used together, only `{type}-pre` or only
  12430. * `{type}-asc` and `{type}-desc` together. It is generally recommended
  12431. * that only `{type}-pre` is used, as this provides the optimal
  12432. * implementation in terms of speed, although the others are provided
  12433. * for compatibility with existing Javascript sort functions.
  12434. *
  12435. * `{type}-pre`: Functions defined take a single parameter:
  12436. *
  12437. * 1. `{*}` Data from the column cell to be prepared for ordering
  12438. *
  12439. * And return:
  12440. *
  12441. * * `{*}` Data to be sorted upon
  12442. *
  12443. * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
  12444. * functions, taking two parameters:
  12445. *
  12446. * 1. `{*}` Data to compare to the second parameter
  12447. * 2. `{*}` Data to compare to the first parameter
  12448. *
  12449. * And returning:
  12450. *
  12451. * * `{*}` Ordering match: <0 if first parameter should be sorted lower
  12452. * than the second parameter, ===0 if the two parameters are equal and
  12453. * >0 if the first parameter should be sorted height than the second
  12454. * parameter.
  12455. *
  12456. * @type object
  12457. * @default {}
  12458. *
  12459. * @example
  12460. * // Numeric ordering of formatted numbers with a pre-formatter
  12461. * $.extend( $.fn.dataTable.ext.type.order, {
  12462. * "string-pre": function(x) {
  12463. * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
  12464. * return parseFloat( a );
  12465. * }
  12466. * } );
  12467. *
  12468. * @example
  12469. * // Case-sensitive string ordering, with no pre-formatting method
  12470. * $.extend( $.fn.dataTable.ext.order, {
  12471. * "string-case-asc": function(x,y) {
  12472. * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  12473. * },
  12474. * "string-case-desc": function(x,y) {
  12475. * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  12476. * }
  12477. * } );
  12478. */
  12479. order: {}
  12480. },
  12481. /**
  12482. * Unique DataTables instance counter
  12483. *
  12484. * @type int
  12485. * @private
  12486. */
  12487. _unique: 0,
  12488. //
  12489. // Depreciated
  12490. // The following properties are retained for backwards compatiblity only.
  12491. // The should not be used in new projects and will be removed in a future
  12492. // version
  12493. //
  12494. /**
  12495. * Version check function.
  12496. * @type function
  12497. * @depreciated Since 1.10
  12498. */
  12499. fnVersionCheck: DataTable.fnVersionCheck,
  12500. /**
  12501. * Index for what 'this' index API functions should use
  12502. * @type int
  12503. * @deprecated Since v1.10
  12504. */
  12505. iApiIndex: 0,
  12506. /**
  12507. * jQuery UI class container
  12508. * @type object
  12509. * @deprecated Since v1.10
  12510. */
  12511. oJUIClasses: {},
  12512. /**
  12513. * Software version
  12514. * @type string
  12515. * @deprecated Since v1.10
  12516. */
  12517. sVersion: DataTable.version
  12518. };
  12519. //
  12520. // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
  12521. //
  12522. $.extend( _ext, {
  12523. afnFiltering: _ext.search,
  12524. aTypes: _ext.type.detect,
  12525. ofnSearch: _ext.type.search,
  12526. oSort: _ext.type.order,
  12527. afnSortData: _ext.order,
  12528. aoFeatures: _ext.feature,
  12529. oApi: _ext.internal,
  12530. oStdClasses: _ext.classes,
  12531. oPagination: _ext.pager
  12532. } );
  12533. $.extend( DataTable.ext.classes, {
  12534. "sTable": "dataTable",
  12535. "sNoFooter": "no-footer",
  12536. /* Paging buttons */
  12537. "sPageButton": "paginate_button",
  12538. "sPageButtonActive": "current",
  12539. "sPageButtonDisabled": "disabled",
  12540. /* Striping classes */
  12541. "sStripeOdd": "odd",
  12542. "sStripeEven": "even",
  12543. /* Empty row */
  12544. "sRowEmpty": "dataTables_empty",
  12545. /* Features */
  12546. "sWrapper": "dataTables_wrapper",
  12547. "sFilter": "dataTables_filter",
  12548. "sInfo": "dataTables_info",
  12549. "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
  12550. "sLength": "dataTables_length",
  12551. "sProcessing": "dataTables_processing",
  12552. /* Sorting */
  12553. "sSortAsc": "sorting_asc",
  12554. "sSortDesc": "sorting_desc",
  12555. "sSortable": "sorting", /* Sortable in both directions */
  12556. "sSortableAsc": "sorting_asc_disabled",
  12557. "sSortableDesc": "sorting_desc_disabled",
  12558. "sSortableNone": "sorting_disabled",
  12559. "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
  12560. /* Filtering */
  12561. "sFilterInput": "",
  12562. /* Page length */
  12563. "sLengthSelect": "",
  12564. /* Scrolling */
  12565. "sScrollWrapper": "dataTables_scroll",
  12566. "sScrollHead": "dataTables_scrollHead",
  12567. "sScrollHeadInner": "dataTables_scrollHeadInner",
  12568. "sScrollBody": "dataTables_scrollBody",
  12569. "sScrollFoot": "dataTables_scrollFoot",
  12570. "sScrollFootInner": "dataTables_scrollFootInner",
  12571. /* Misc */
  12572. "sHeaderTH": "",
  12573. "sFooterTH": "",
  12574. // Deprecated
  12575. "sSortJUIAsc": "",
  12576. "sSortJUIDesc": "",
  12577. "sSortJUI": "",
  12578. "sSortJUIAscAllowed": "",
  12579. "sSortJUIDescAllowed": "",
  12580. "sSortJUIWrapper": "",
  12581. "sSortIcon": "",
  12582. "sJUIHeader": "",
  12583. "sJUIFooter": ""
  12584. } );
  12585. var extPagination = DataTable.ext.pager;
  12586. function _numbers ( page, pages ) {
  12587. var
  12588. numbers = [],
  12589. buttons = extPagination.numbers_length,
  12590. half = Math.floor( buttons / 2 ),
  12591. i = 1;
  12592. if ( pages <= buttons ) {
  12593. numbers = _range( 0, pages );
  12594. }
  12595. else if ( page <= half ) {
  12596. numbers = _range( 0, buttons-2 );
  12597. numbers.push( 'ellipsis' );
  12598. numbers.push( pages-1 );
  12599. }
  12600. else if ( page >= pages - 1 - half ) {
  12601. numbers = _range( pages-(buttons-2), pages );
  12602. numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
  12603. numbers.splice( 0, 0, 0 );
  12604. }
  12605. else {
  12606. numbers = _range( page-half+2, page+half-1 );
  12607. numbers.push( 'ellipsis' );
  12608. numbers.push( pages-1 );
  12609. numbers.splice( 0, 0, 'ellipsis' );
  12610. numbers.splice( 0, 0, 0 );
  12611. }
  12612. numbers.DT_el = 'span';
  12613. return numbers;
  12614. }
  12615. $.extend( extPagination, {
  12616. simple: function ( page, pages ) {
  12617. return [ 'previous', 'next' ];
  12618. },
  12619. full: function ( page, pages ) {
  12620. return [ 'first', 'previous', 'next', 'last' ];
  12621. },
  12622. numbers: function ( page, pages ) {
  12623. return [ _numbers(page, pages) ];
  12624. },
  12625. simple_numbers: function ( page, pages ) {
  12626. return [ 'previous', _numbers(page, pages), 'next' ];
  12627. },
  12628. full_numbers: function ( page, pages ) {
  12629. return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
  12630. },
  12631. first_last_numbers: function (page, pages) {
  12632. return ['first', _numbers(page, pages), 'last'];
  12633. },
  12634. // For testing and plug-ins to use
  12635. _numbers: _numbers,
  12636. // Number of number buttons (including ellipsis) to show. _Must be odd!_
  12637. numbers_length: 7
  12638. } );
  12639. $.extend( true, DataTable.ext.renderer, {
  12640. pageButton: {
  12641. _: function ( settings, host, idx, buttons, page, pages ) {
  12642. var classes = settings.oClasses;
  12643. var lang = settings.oLanguage.oPaginate;
  12644. var aria = settings.oLanguage.oAria.paginate || {};
  12645. var btnDisplay, btnClass, counter=0;
  12646. var attach = function( container, buttons ) {
  12647. var i, ien, node, button;
  12648. var clickHandler = function ( e ) {
  12649. _fnPageChange( settings, e.data.action, true );
  12650. };
  12651. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  12652. button = buttons[i];
  12653. if ( $.isArray( button ) ) {
  12654. var inner = $( '<'+(button.DT_el || 'div')+'/>' )
  12655. .appendTo( container );
  12656. attach( inner, button );
  12657. }
  12658. else {
  12659. btnDisplay = null;
  12660. btnClass = '';
  12661. switch ( button ) {
  12662. case 'ellipsis':
  12663. container.append('<span class="ellipsis">&#x2026;</span>');
  12664. break;
  12665. case 'first':
  12666. btnDisplay = lang.sFirst;
  12667. btnClass = button + (page > 0 ?
  12668. '' : ' '+classes.sPageButtonDisabled);
  12669. break;
  12670. case 'previous':
  12671. btnDisplay = lang.sPrevious;
  12672. btnClass = button + (page > 0 ?
  12673. '' : ' '+classes.sPageButtonDisabled);
  12674. break;
  12675. case 'next':
  12676. btnDisplay = lang.sNext;
  12677. btnClass = button + (page < pages-1 ?
  12678. '' : ' '+classes.sPageButtonDisabled);
  12679. break;
  12680. case 'last':
  12681. btnDisplay = lang.sLast;
  12682. btnClass = button + (page < pages-1 ?
  12683. '' : ' '+classes.sPageButtonDisabled);
  12684. break;
  12685. default:
  12686. btnDisplay = button + 1;
  12687. btnClass = page === button ?
  12688. classes.sPageButtonActive : '';
  12689. break;
  12690. }
  12691. if ( btnDisplay !== null ) {
  12692. node = $('<a>', {
  12693. 'class': classes.sPageButton+' '+btnClass,
  12694. 'aria-controls': settings.sTableId,
  12695. 'aria-label': aria[ button ],
  12696. 'data-dt-idx': counter,
  12697. 'tabindex': settings.iTabIndex,
  12698. 'id': idx === 0 && typeof button === 'string' ?
  12699. settings.sTableId +'_'+ button :
  12700. null
  12701. } )
  12702. .html( btnDisplay )
  12703. .appendTo( container );
  12704. _fnBindAction(
  12705. node, {action: button}, clickHandler
  12706. );
  12707. counter++;
  12708. }
  12709. }
  12710. }
  12711. };
  12712. // IE9 throws an 'unknown error' if document.activeElement is used
  12713. // inside an iframe or frame. Try / catch the error. Not good for
  12714. // accessibility, but neither are frames.
  12715. var activeEl;
  12716. try {
  12717. // Because this approach is destroying and recreating the paging
  12718. // elements, focus is lost on the select button which is bad for
  12719. // accessibility. So we want to restore focus once the draw has
  12720. // completed
  12721. activeEl = $(host).find(document.activeElement).data('dt-idx');
  12722. }
  12723. catch (e) {}
  12724. attach( $(host).empty(), buttons );
  12725. if ( activeEl !== undefined ) {
  12726. $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
  12727. }
  12728. }
  12729. }
  12730. } );
  12731. // Built in type detection. See model.ext.aTypes for information about
  12732. // what is required from this methods.
  12733. $.extend( DataTable.ext.type.detect, [
  12734. // Plain numbers - first since V8 detects some plain numbers as dates
  12735. // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
  12736. function ( d, settings )
  12737. {
  12738. var decimal = settings.oLanguage.sDecimal;
  12739. return _isNumber( d, decimal ) ? 'num'+decimal : null;
  12740. },
  12741. // Dates (only those recognised by the browser's Date.parse)
  12742. function ( d, settings )
  12743. {
  12744. // V8 tries _very_ hard to make a string passed into `Date.parse()`
  12745. // valid, so we need to use a regex to restrict date formats. Use a
  12746. // plug-in for anything other than ISO8601 style strings
  12747. if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
  12748. return null;
  12749. }
  12750. var parsed = Date.parse(d);
  12751. return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
  12752. },
  12753. // Formatted numbers
  12754. function ( d, settings )
  12755. {
  12756. var decimal = settings.oLanguage.sDecimal;
  12757. return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
  12758. },
  12759. // HTML numeric
  12760. function ( d, settings )
  12761. {
  12762. var decimal = settings.oLanguage.sDecimal;
  12763. return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
  12764. },
  12765. // HTML numeric, formatted
  12766. function ( d, settings )
  12767. {
  12768. var decimal = settings.oLanguage.sDecimal;
  12769. return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
  12770. },
  12771. // HTML (this is strict checking - there must be html)
  12772. function ( d, settings )
  12773. {
  12774. return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
  12775. 'html' : null;
  12776. }
  12777. ] );
  12778. // Filter formatting functions. See model.ext.ofnSearch for information about
  12779. // what is required from these methods.
  12780. //
  12781. // Note that additional search methods are added for the html numbers and
  12782. // html formatted numbers by `_addNumericSort()` when we know what the decimal
  12783. // place is
  12784. $.extend( DataTable.ext.type.search, {
  12785. html: function ( data ) {
  12786. return _empty(data) ?
  12787. data :
  12788. typeof data === 'string' ?
  12789. data
  12790. .replace( _re_new_lines, " " )
  12791. .replace( _re_html, "" ) :
  12792. '';
  12793. },
  12794. string: function ( data ) {
  12795. return _empty(data) ?
  12796. data :
  12797. typeof data === 'string' ?
  12798. data.replace( _re_new_lines, " " ) :
  12799. data;
  12800. }
  12801. } );
  12802. var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
  12803. if ( d !== 0 && (!d || d === '-') ) {
  12804. return -Infinity;
  12805. }
  12806. // If a decimal place other than `.` is used, it needs to be given to the
  12807. // function so we can detect it and replace with a `.` which is the only
  12808. // decimal place Javascript recognises - it is not locale aware.
  12809. if ( decimalPlace ) {
  12810. d = _numToDecimal( d, decimalPlace );
  12811. }
  12812. if ( d.replace ) {
  12813. if ( re1 ) {
  12814. d = d.replace( re1, '' );
  12815. }
  12816. if ( re2 ) {
  12817. d = d.replace( re2, '' );
  12818. }
  12819. }
  12820. return d * 1;
  12821. };
  12822. // Add the numeric 'deformatting' functions for sorting and search. This is done
  12823. // in a function to provide an easy ability for the language options to add
  12824. // additional methods if a non-period decimal place is used.
  12825. function _addNumericSort ( decimalPlace ) {
  12826. $.each(
  12827. {
  12828. // Plain numbers
  12829. "num": function ( d ) {
  12830. return __numericReplace( d, decimalPlace );
  12831. },
  12832. // Formatted numbers
  12833. "num-fmt": function ( d ) {
  12834. return __numericReplace( d, decimalPlace, _re_formatted_numeric );
  12835. },
  12836. // HTML numeric
  12837. "html-num": function ( d ) {
  12838. return __numericReplace( d, decimalPlace, _re_html );
  12839. },
  12840. // HTML numeric, formatted
  12841. "html-num-fmt": function ( d ) {
  12842. return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
  12843. }
  12844. },
  12845. function ( key, fn ) {
  12846. // Add the ordering method
  12847. _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
  12848. // For HTML types add a search formatter that will strip the HTML
  12849. if ( key.match(/^html\-/) ) {
  12850. _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
  12851. }
  12852. }
  12853. );
  12854. }
  12855. // Default sort methods
  12856. $.extend( _ext.type.order, {
  12857. // Dates
  12858. "date-pre": function ( d ) {
  12859. var ts = Date.parse( d );
  12860. return isNaN(ts) ? -Infinity : ts;
  12861. },
  12862. // html
  12863. "html-pre": function ( a ) {
  12864. return _empty(a) ?
  12865. '' :
  12866. a.replace ?
  12867. a.replace( /<.*?>/g, "" ).toLowerCase() :
  12868. a+'';
  12869. },
  12870. // string
  12871. "string-pre": function ( a ) {
  12872. // This is a little complex, but faster than always calling toString,
  12873. // http://jsperf.com/tostring-v-check
  12874. return _empty(a) ?
  12875. '' :
  12876. typeof a === 'string' ?
  12877. a.toLowerCase() :
  12878. ! a.toString ?
  12879. '' :
  12880. a.toString();
  12881. },
  12882. // string-asc and -desc are retained only for compatibility with the old
  12883. // sort methods
  12884. "string-asc": function ( x, y ) {
  12885. return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  12886. },
  12887. "string-desc": function ( x, y ) {
  12888. return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  12889. }
  12890. } );
  12891. // Numeric sorting types - order doesn't matter here
  12892. _addNumericSort( '' );
  12893. $.extend( true, DataTable.ext.renderer, {
  12894. header: {
  12895. _: function ( settings, cell, column, classes ) {
  12896. // No additional mark-up required
  12897. // Attach a sort listener to update on sort - note that using the
  12898. // `DT` namespace will allow the event to be removed automatically
  12899. // on destroy, while the `dt` namespaced event is the one we are
  12900. // listening for
  12901. $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
  12902. if ( settings !== ctx ) { // need to check this this is the host
  12903. return; // table, not a nested one
  12904. }
  12905. var colIdx = column.idx;
  12906. cell
  12907. .removeClass(
  12908. column.sSortingClass +' '+
  12909. classes.sSortAsc +' '+
  12910. classes.sSortDesc
  12911. )
  12912. .addClass( columns[ colIdx ] == 'asc' ?
  12913. classes.sSortAsc : columns[ colIdx ] == 'desc' ?
  12914. classes.sSortDesc :
  12915. column.sSortingClass
  12916. );
  12917. } );
  12918. },
  12919. jqueryui: function ( settings, cell, column, classes ) {
  12920. $('<div/>')
  12921. .addClass( classes.sSortJUIWrapper )
  12922. .append( cell.contents() )
  12923. .append( $('<span/>')
  12924. .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
  12925. )
  12926. .appendTo( cell );
  12927. // Attach a sort listener to update on sort
  12928. $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
  12929. if ( settings !== ctx ) {
  12930. return;
  12931. }
  12932. var colIdx = column.idx;
  12933. cell
  12934. .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
  12935. .addClass( columns[ colIdx ] == 'asc' ?
  12936. classes.sSortAsc : columns[ colIdx ] == 'desc' ?
  12937. classes.sSortDesc :
  12938. column.sSortingClass
  12939. );
  12940. cell
  12941. .find( 'span.'+classes.sSortIcon )
  12942. .removeClass(
  12943. classes.sSortJUIAsc +" "+
  12944. classes.sSortJUIDesc +" "+
  12945. classes.sSortJUI +" "+
  12946. classes.sSortJUIAscAllowed +" "+
  12947. classes.sSortJUIDescAllowed
  12948. )
  12949. .addClass( columns[ colIdx ] == 'asc' ?
  12950. classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
  12951. classes.sSortJUIDesc :
  12952. column.sSortingClassJUI
  12953. );
  12954. } );
  12955. }
  12956. }
  12957. } );
  12958. /*
  12959. * Public helper functions. These aren't used internally by DataTables, or
  12960. * called by any of the options passed into DataTables, but they can be used
  12961. * externally by developers working with DataTables. They are helper functions
  12962. * to make working with DataTables a little bit easier.
  12963. */
  12964. var __htmlEscapeEntities = function ( d ) {
  12965. return typeof d === 'string' ?
  12966. d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
  12967. d;
  12968. };
  12969. /**
  12970. * Helpers for `columns.render`.
  12971. *
  12972. * The options defined here can be used with the `columns.render` initialisation
  12973. * option to provide a display renderer. The following functions are defined:
  12974. *
  12975. * * `number` - Will format numeric data (defined by `columns.data`) for
  12976. * display, retaining the original unformatted data for sorting and filtering.
  12977. * It takes 5 parameters:
  12978. * * `string` - Thousands grouping separator
  12979. * * `string` - Decimal point indicator
  12980. * * `integer` - Number of decimal points to show
  12981. * * `string` (optional) - Prefix.
  12982. * * `string` (optional) - Postfix (/suffix).
  12983. * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
  12984. * parameters.
  12985. *
  12986. * @example
  12987. * // Column definition using the number renderer
  12988. * {
  12989. * data: "salary",
  12990. * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
  12991. * }
  12992. *
  12993. * @namespace
  12994. */
  12995. DataTable.render = {
  12996. number: function ( thousands, decimal, precision, prefix, postfix ) {
  12997. return {
  12998. display: function ( d ) {
  12999. if ( typeof d !== 'number' && typeof d !== 'string' ) {
  13000. return d;
  13001. }
  13002. var negative = d < 0 ? '-' : '';
  13003. var flo = parseFloat( d );
  13004. // If NaN then there isn't much formatting that we can do - just
  13005. // return immediately, escaping any HTML (this was supposed to
  13006. // be a number after all)
  13007. if ( isNaN( flo ) ) {
  13008. return __htmlEscapeEntities( d );
  13009. }
  13010. flo = flo.toFixed( precision );
  13011. d = Math.abs( flo );
  13012. var intPart = parseInt( d, 10 );
  13013. var floatPart = precision ?
  13014. decimal+(d - intPart).toFixed( precision ).substring( 2 ):
  13015. '';
  13016. return negative + (prefix||'') +
  13017. intPart.toString().replace(
  13018. /\B(?=(\d{3})+(?!\d))/g, thousands
  13019. ) +
  13020. floatPart +
  13021. (postfix||'');
  13022. }
  13023. };
  13024. },
  13025. text: function () {
  13026. return {
  13027. display: __htmlEscapeEntities,
  13028. filter: __htmlEscapeEntities
  13029. };
  13030. }
  13031. };
  13032. /*
  13033. * This is really a good bit rubbish this method of exposing the internal methods
  13034. * publicly... - To be fixed in 2.0 using methods on the prototype
  13035. */
  13036. /**
  13037. * Create a wrapper function for exporting an internal functions to an external API.
  13038. * @param {string} fn API function name
  13039. * @returns {function} wrapped function
  13040. * @memberof DataTable#internal
  13041. */
  13042. function _fnExternApiFunc (fn)
  13043. {
  13044. return function() {
  13045. var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
  13046. Array.prototype.slice.call(arguments)
  13047. );
  13048. return DataTable.ext.internal[fn].apply( this, args );
  13049. };
  13050. }
  13051. /**
  13052. * Reference to internal functions for use by plug-in developers. Note that
  13053. * these methods are references to internal functions and are considered to be
  13054. * private. If you use these methods, be aware that they are liable to change
  13055. * between versions.
  13056. * @namespace
  13057. */
  13058. $.extend( DataTable.ext.internal, {
  13059. _fnExternApiFunc: _fnExternApiFunc,
  13060. _fnBuildAjax: _fnBuildAjax,
  13061. _fnAjaxUpdate: _fnAjaxUpdate,
  13062. _fnAjaxParameters: _fnAjaxParameters,
  13063. _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
  13064. _fnAjaxDataSrc: _fnAjaxDataSrc,
  13065. _fnAddColumn: _fnAddColumn,
  13066. _fnColumnOptions: _fnColumnOptions,
  13067. _fnAdjustColumnSizing: _fnAdjustColumnSizing,
  13068. _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
  13069. _fnColumnIndexToVisible: _fnColumnIndexToVisible,
  13070. _fnVisbleColumns: _fnVisbleColumns,
  13071. _fnGetColumns: _fnGetColumns,
  13072. _fnColumnTypes: _fnColumnTypes,
  13073. _fnApplyColumnDefs: _fnApplyColumnDefs,
  13074. _fnHungarianMap: _fnHungarianMap,
  13075. _fnCamelToHungarian: _fnCamelToHungarian,
  13076. _fnLanguageCompat: _fnLanguageCompat,
  13077. _fnBrowserDetect: _fnBrowserDetect,
  13078. _fnAddData: _fnAddData,
  13079. _fnAddTr: _fnAddTr,
  13080. _fnNodeToDataIndex: _fnNodeToDataIndex,
  13081. _fnNodeToColumnIndex: _fnNodeToColumnIndex,
  13082. _fnGetCellData: _fnGetCellData,
  13083. _fnSetCellData: _fnSetCellData,
  13084. _fnSplitObjNotation: _fnSplitObjNotation,
  13085. _fnGetObjectDataFn: _fnGetObjectDataFn,
  13086. _fnSetObjectDataFn: _fnSetObjectDataFn,
  13087. _fnGetDataMaster: _fnGetDataMaster,
  13088. _fnClearTable: _fnClearTable,
  13089. _fnDeleteIndex: _fnDeleteIndex,
  13090. _fnInvalidate: _fnInvalidate,
  13091. _fnGetRowElements: _fnGetRowElements,
  13092. _fnCreateTr: _fnCreateTr,
  13093. _fnBuildHead: _fnBuildHead,
  13094. _fnDrawHead: _fnDrawHead,
  13095. _fnDraw: _fnDraw,
  13096. _fnReDraw: _fnReDraw,
  13097. _fnAddOptionsHtml: _fnAddOptionsHtml,
  13098. _fnDetectHeader: _fnDetectHeader,
  13099. _fnGetUniqueThs: _fnGetUniqueThs,
  13100. _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
  13101. _fnFilterComplete: _fnFilterComplete,
  13102. _fnFilterCustom: _fnFilterCustom,
  13103. _fnFilterColumn: _fnFilterColumn,
  13104. _fnFilter: _fnFilter,
  13105. _fnFilterCreateSearch: _fnFilterCreateSearch,
  13106. _fnEscapeRegex: _fnEscapeRegex,
  13107. _fnFilterData: _fnFilterData,
  13108. _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
  13109. _fnUpdateInfo: _fnUpdateInfo,
  13110. _fnInfoMacros: _fnInfoMacros,
  13111. _fnInitialise: _fnInitialise,
  13112. _fnInitComplete: _fnInitComplete,
  13113. _fnLengthChange: _fnLengthChange,
  13114. _fnFeatureHtmlLength: _fnFeatureHtmlLength,
  13115. _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
  13116. _fnPageChange: _fnPageChange,
  13117. _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
  13118. _fnProcessingDisplay: _fnProcessingDisplay,
  13119. _fnFeatureHtmlTable: _fnFeatureHtmlTable,
  13120. _fnScrollDraw: _fnScrollDraw,
  13121. _fnApplyToChildren: _fnApplyToChildren,
  13122. _fnCalculateColumnWidths: _fnCalculateColumnWidths,
  13123. _fnThrottle: _fnThrottle,
  13124. _fnConvertToWidth: _fnConvertToWidth,
  13125. _fnGetWidestNode: _fnGetWidestNode,
  13126. _fnGetMaxLenString: _fnGetMaxLenString,
  13127. _fnStringToCss: _fnStringToCss,
  13128. _fnSortFlatten: _fnSortFlatten,
  13129. _fnSort: _fnSort,
  13130. _fnSortAria: _fnSortAria,
  13131. _fnSortListener: _fnSortListener,
  13132. _fnSortAttachListener: _fnSortAttachListener,
  13133. _fnSortingClasses: _fnSortingClasses,
  13134. _fnSortData: _fnSortData,
  13135. _fnSaveState: _fnSaveState,
  13136. _fnLoadState: _fnLoadState,
  13137. _fnSettingsFromNode: _fnSettingsFromNode,
  13138. _fnLog: _fnLog,
  13139. _fnMap: _fnMap,
  13140. _fnBindAction: _fnBindAction,
  13141. _fnCallbackReg: _fnCallbackReg,
  13142. _fnCallbackFire: _fnCallbackFire,
  13143. _fnLengthOverflow: _fnLengthOverflow,
  13144. _fnRenderer: _fnRenderer,
  13145. _fnDataSource: _fnDataSource,
  13146. _fnRowAttributes: _fnRowAttributes,
  13147. _fnExtend: _fnExtend,
  13148. _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
  13149. // in 1.10, so this dead-end function is
  13150. // added to prevent errors
  13151. } );
  13152. // jQuery access
  13153. $.fn.dataTable = DataTable;
  13154. // Provide access to the host jQuery object (circular reference)
  13155. DataTable.$ = $;
  13156. // Legacy aliases
  13157. $.fn.dataTableSettings = DataTable.settings;
  13158. $.fn.dataTableExt = DataTable.ext;
  13159. // With a capital `D` we return a DataTables API instance rather than a
  13160. // jQuery object
  13161. $.fn.DataTable = function ( opts ) {
  13162. return $(this).dataTable( opts ).api();
  13163. };
  13164. // All properties that are available to $.fn.dataTable should also be
  13165. // available on $.fn.DataTable
  13166. $.each( DataTable, function ( prop, val ) {
  13167. $.fn.DataTable[ prop ] = val;
  13168. } );
  13169. // Information about events fired by DataTables - for documentation.
  13170. /**
  13171. * Draw event, fired whenever the table is redrawn on the page, at the same
  13172. * point as fnDrawCallback. This may be useful for binding events or
  13173. * performing calculations when the table is altered at all.
  13174. * @name DataTable#draw.dt
  13175. * @event
  13176. * @param {event} e jQuery event object
  13177. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13178. */
  13179. /**
  13180. * Search event, fired when the searching applied to the table (using the
  13181. * built-in global search, or column filters) is altered.
  13182. * @name DataTable#search.dt
  13183. * @event
  13184. * @param {event} e jQuery event object
  13185. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13186. */
  13187. /**
  13188. * Page change event, fired when the paging of the table is altered.
  13189. * @name DataTable#page.dt
  13190. * @event
  13191. * @param {event} e jQuery event object
  13192. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13193. */
  13194. /**
  13195. * Order event, fired when the ordering applied to the table is altered.
  13196. * @name DataTable#order.dt
  13197. * @event
  13198. * @param {event} e jQuery event object
  13199. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13200. */
  13201. /**
  13202. * DataTables initialisation complete event, fired when the table is fully
  13203. * drawn, including Ajax data loaded, if Ajax data is required.
  13204. * @name DataTable#init.dt
  13205. * @event
  13206. * @param {event} e jQuery event object
  13207. * @param {object} oSettings DataTables settings object
  13208. * @param {object} json The JSON object request from the server - only
  13209. * present if client-side Ajax sourced data is used</li></ol>
  13210. */
  13211. /**
  13212. * State save event, fired when the table has changed state a new state save
  13213. * is required. This event allows modification of the state saving object
  13214. * prior to actually doing the save, including addition or other state
  13215. * properties (for plug-ins) or modification of a DataTables core property.
  13216. * @name DataTable#stateSaveParams.dt
  13217. * @event
  13218. * @param {event} e jQuery event object
  13219. * @param {object} oSettings DataTables settings object
  13220. * @param {object} json The state information to be saved
  13221. */
  13222. /**
  13223. * State load event, fired when the table is loading state from the stored
  13224. * data, but prior to the settings object being modified by the saved state
  13225. * - allowing modification of the saved state is required or loading of
  13226. * state for a plug-in.
  13227. * @name DataTable#stateLoadParams.dt
  13228. * @event
  13229. * @param {event} e jQuery event object
  13230. * @param {object} oSettings DataTables settings object
  13231. * @param {object} json The saved state information
  13232. */
  13233. /**
  13234. * State loaded event, fired when state has been loaded from stored data and
  13235. * the settings object has been modified by the loaded data.
  13236. * @name DataTable#stateLoaded.dt
  13237. * @event
  13238. * @param {event} e jQuery event object
  13239. * @param {object} oSettings DataTables settings object
  13240. * @param {object} json The saved state information
  13241. */
  13242. /**
  13243. * Processing event, fired when DataTables is doing some kind of processing
  13244. * (be it, order, searcg or anything else). It can be used to indicate to
  13245. * the end user that there is something happening, or that something has
  13246. * finished.
  13247. * @name DataTable#processing.dt
  13248. * @event
  13249. * @param {event} e jQuery event object
  13250. * @param {object} oSettings DataTables settings object
  13251. * @param {boolean} bShow Flag for if DataTables is doing processing or not
  13252. */
  13253. /**
  13254. * Ajax (XHR) event, fired whenever an Ajax request is completed from a
  13255. * request to made to the server for new data. This event is called before
  13256. * DataTables processed the returned data, so it can also be used to pre-
  13257. * process the data returned from the server, if needed.
  13258. *
  13259. * Note that this trigger is called in `fnServerData`, if you override
  13260. * `fnServerData` and which to use this event, you need to trigger it in you
  13261. * success function.
  13262. * @name DataTable#xhr.dt
  13263. * @event
  13264. * @param {event} e jQuery event object
  13265. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13266. * @param {object} json JSON returned from the server
  13267. *
  13268. * @example
  13269. * // Use a custom property returned from the server in another DOM element
  13270. * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
  13271. * $('#status').html( json.status );
  13272. * } );
  13273. *
  13274. * @example
  13275. * // Pre-process the data returned from the server
  13276. * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
  13277. * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
  13278. * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
  13279. * }
  13280. * // Note no return - manipulate the data directly in the JSON object.
  13281. * } );
  13282. */
  13283. /**
  13284. * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
  13285. * or passing the bDestroy:true parameter in the initialisation object. This
  13286. * can be used to remove bound events, added DOM nodes, etc.
  13287. * @name DataTable#destroy.dt
  13288. * @event
  13289. * @param {event} e jQuery event object
  13290. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13291. */
  13292. /**
  13293. * Page length change event, fired when number of records to show on each
  13294. * page (the length) is changed.
  13295. * @name DataTable#length.dt
  13296. * @event
  13297. * @param {event} e jQuery event object
  13298. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13299. * @param {integer} len New length
  13300. */
  13301. /**
  13302. * Column sizing has changed.
  13303. * @name DataTable#column-sizing.dt
  13304. * @event
  13305. * @param {event} e jQuery event object
  13306. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13307. */
  13308. /**
  13309. * Column visibility has changed.
  13310. * @name DataTable#column-visibility.dt
  13311. * @event
  13312. * @param {event} e jQuery event object
  13313. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13314. * @param {int} column Column index
  13315. * @param {bool} vis `false` if column now hidden, or `true` if visible
  13316. */
  13317. return $.fn.dataTable;
  13318. }));
  13319. /*! DataTables Bootstrap 4 integration
  13320. * ©2011-2017 SpryMedia Ltd - datatables.net/license
  13321. */
  13322. /**
  13323. * DataTables integration for Bootstrap 4. This requires Bootstrap 4 and
  13324. * DataTables 1.10 or newer.
  13325. *
  13326. * This file sets the defaults and adds options to DataTables to style its
  13327. * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
  13328. * for further information.
  13329. */
  13330. (function( factory ){
  13331. if ( typeof define === 'function' && define.amd ) {
  13332. // AMD
  13333. define( ['jquery', 'datatables.net'], function ( $ ) {
  13334. return factory( $, window, document );
  13335. } );
  13336. }
  13337. else if ( typeof exports === 'object' ) {
  13338. // CommonJS
  13339. module.exports = function (root, $) {
  13340. if ( ! root ) {
  13341. root = window;
  13342. }
  13343. if ( ! $ || ! $.fn.dataTable ) {
  13344. // Require DataTables, which attaches to jQuery, including
  13345. // jQuery if needed and have a $ property so we can access the
  13346. // jQuery object that is used
  13347. $ = require('datatables.net')(root, $).$;
  13348. }
  13349. return factory( $, root, root.document );
  13350. };
  13351. }
  13352. else {
  13353. // Browser
  13354. factory( jQuery, window, document );
  13355. }
  13356. }(function( $, window, document, undefined ) {
  13357. 'use strict';
  13358. var DataTable = $.fn.dataTable;
  13359. /* Set the defaults for DataTables initialisation */
  13360. $.extend( true, DataTable.defaults, {
  13361. dom:
  13362. "<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" +
  13363. "<'row'<'col-sm-12'tr>>" +
  13364. "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
  13365. renderer: 'bootstrap'
  13366. } );
  13367. /* Default class modification */
  13368. $.extend( DataTable.ext.classes, {
  13369. sWrapper: "dataTables_wrapper dt-bootstrap4",
  13370. sFilterInput: "form-control form-control-sm",
  13371. sLengthSelect: "custom-select custom-select-sm form-control form-control-sm",
  13372. sProcessing: "dataTables_processing card",
  13373. sPageButton: "paginate_button page-item"
  13374. } );
  13375. /* Bootstrap paging button renderer */
  13376. DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {
  13377. var api = new DataTable.Api( settings );
  13378. var classes = settings.oClasses;
  13379. var lang = settings.oLanguage.oPaginate;
  13380. var aria = settings.oLanguage.oAria.paginate || {};
  13381. var btnDisplay, btnClass, counter=0;
  13382. var attach = function( container, buttons ) {
  13383. var i, ien, node, button;
  13384. var clickHandler = function ( e ) {
  13385. e.preventDefault();
  13386. if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {
  13387. api.page( e.data.action ).draw( 'page' );
  13388. }
  13389. };
  13390. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  13391. button = buttons[i];
  13392. if ( $.isArray( button ) ) {
  13393. attach( container, button );
  13394. }
  13395. else {
  13396. btnDisplay = '';
  13397. btnClass = '';
  13398. switch ( button ) {
  13399. case 'ellipsis':
  13400. btnDisplay = '&#x2026;';
  13401. btnClass = 'disabled';
  13402. break;
  13403. case 'first':
  13404. btnDisplay = lang.sFirst;
  13405. btnClass = button + (page > 0 ?
  13406. '' : ' disabled');
  13407. break;
  13408. case 'previous':
  13409. btnDisplay = lang.sPrevious;
  13410. btnClass = button + (page > 0 ?
  13411. '' : ' disabled');
  13412. break;
  13413. case 'next':
  13414. btnDisplay = lang.sNext;
  13415. btnClass = button + (page < pages-1 ?
  13416. '' : ' disabled');
  13417. break;
  13418. case 'last':
  13419. btnDisplay = lang.sLast;
  13420. btnClass = button + (page < pages-1 ?
  13421. '' : ' disabled');
  13422. break;
  13423. default:
  13424. btnDisplay = button + 1;
  13425. btnClass = page === button ?
  13426. 'active' : '';
  13427. break;
  13428. }
  13429. if ( btnDisplay ) {
  13430. node = $('<li>', {
  13431. 'class': classes.sPageButton+' '+btnClass,
  13432. 'id': idx === 0 && typeof button === 'string' ?
  13433. settings.sTableId +'_'+ button :
  13434. null
  13435. } )
  13436. .append( $('<a>', {
  13437. 'href': '#',
  13438. 'aria-controls': settings.sTableId,
  13439. 'aria-label': aria[ button ],
  13440. 'data-dt-idx': counter,
  13441. 'tabindex': settings.iTabIndex,
  13442. 'class': 'page-link'
  13443. } )
  13444. .html( btnDisplay )
  13445. )
  13446. .appendTo( container );
  13447. settings.oApi._fnBindAction(
  13448. node, {action: button}, clickHandler
  13449. );
  13450. counter++;
  13451. }
  13452. }
  13453. }
  13454. };
  13455. // IE9 throws an 'unknown error' if document.activeElement is used
  13456. // inside an iframe or frame.
  13457. var activeEl;
  13458. try {
  13459. // Because this approach is destroying and recreating the paging
  13460. // elements, focus is lost on the select button which is bad for
  13461. // accessibility. So we want to restore focus once the draw has
  13462. // completed
  13463. activeEl = $(host).find(document.activeElement).data('dt-idx');
  13464. }
  13465. catch (e) {}
  13466. attach(
  13467. $(host).empty().html('<ul class="pagination"/>').children('ul'),
  13468. buttons
  13469. );
  13470. if ( activeEl !== undefined ) {
  13471. $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
  13472. }
  13473. };
  13474. return DataTable;
  13475. }));
  13476. /* Set the defaults for DataTables extended classes */
  13477. $.extend(true, $.fn.dataTableExt.oStdClasses, {
  13478. "sFilterInput": "form-control border-top-left-radius-0 border-bottom-left-radius-0 ml-0 width-lg shadow-inset-1",
  13479. "sLengthSelect": "form-control custom-select"
  13480. });
  13481. /* Set the defaults for DataTables initialisation */
  13482. $.extend(true, $.fn.dataTable.defaults, {
  13483. /* --- Layout Structure
  13484. --- Options
  13485. l - length changing input control
  13486. f - filtering input
  13487. t - The table!
  13488. i - Table information summary
  13489. p - pagination control
  13490. r - processing display element
  13491. B - buttons
  13492. R - ColReorder
  13493. S - Select
  13494. --- Markup
  13495. < and > - div element
  13496. <"class" and > - div with a class
  13497. <"#id" and > - div with an ID
  13498. <"#id.class" and > - div with an ID and a class
  13499. --- Further reading
  13500. https://datatables.net/reference/option/dom
  13501. --------------------------------------
  13502. */
  13503. dom: "<'row mb-3'<'col-sm-12 col-md-6 d-flex align-items-center justify-content-start'f><'col-sm-12 col-md-6 d-flex align-items-center justify-content-end'l>>" +
  13504. "<'row'<'col-sm-12'tr>>" +
  13505. "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
  13506. lengthMenu: [[10, 15, 25, 50, 100, -1], [10, 15, 25, 50, 100, "All"]],
  13507. language: {
  13508. /* change the default text for 'next' and 'previous' with icons */
  13509. paginate: {
  13510. previous: "<i class='fal fa-chevron-left'></i>",
  13511. next: "<i class='fal fa-chevron-right'></i>"
  13512. },
  13513. processing: '<div class="d-flex align-items-center justify-content-center fs-lg"><div class="spinner-border spinner-border-sm text-primary mr-2" role="status"><span class="sr-only"> Loading...</span></div> Processing...</div>',
  13514. /* replace the default search lable text with a nice icon */
  13515. search: '<div class="input-group-text d-inline-flex width-3 align-items-center justify-content-center border-bottom-right-radius-0 border-top-right-radius-0 border-right-0"><i class="fal fa-search"></i></div>',
  13516. /* add search filter */
  13517. searchPlaceholder: "Search",
  13518. /* change text for zero records */
  13519. zeroRecords: "No records to display"
  13520. },
  13521. initComplete: function(settings, json) {
  13522. initApp.appForms('.dataTables_filter', 'has-length', 'has-disabled');
  13523. }
  13524. });
  13525. /*! AutoFill 2.3.4
  13526. * ©2008-2019 SpryMedia Ltd - datatables.net/license
  13527. */
  13528. /**
  13529. * @summary AutoFill
  13530. * @description Add Excel like click and drag auto-fill options to DataTables
  13531. * @version 2.3.4
  13532. * @file dataTables.autoFill.js
  13533. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  13534. * @contact www.sprymedia.co.uk/contact
  13535. * @copyright Copyright 2010-2019 SpryMedia Ltd.
  13536. *
  13537. * This source file is free software, available under the following license:
  13538. * MIT license - http://datatables.net/license/mit
  13539. *
  13540. * This source file is distributed in the hope that it will be useful, but
  13541. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13542. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  13543. *
  13544. * For details please refer to: http://www.datatables.net
  13545. */
  13546. (function( factory ){
  13547. if ( typeof define === 'function' && define.amd ) {
  13548. // AMD
  13549. define( ['jquery', 'datatables.net'], function ( $ ) {
  13550. return factory( $, window, document );
  13551. } );
  13552. }
  13553. else if ( typeof exports === 'object' ) {
  13554. // CommonJS
  13555. module.exports = function (root, $) {
  13556. if ( ! root ) {
  13557. root = window;
  13558. }
  13559. if ( ! $ || ! $.fn.dataTable ) {
  13560. $ = require('datatables.net')(root, $).$;
  13561. }
  13562. return factory( $, root, root.document );
  13563. };
  13564. }
  13565. else {
  13566. // Browser
  13567. factory( jQuery, window, document );
  13568. }
  13569. }(function( $, window, document, undefined ) {
  13570. 'use strict';
  13571. var DataTable = $.fn.dataTable;
  13572. var _instance = 0;
  13573. /**
  13574. * AutoFill provides Excel like auto-fill features for a DataTable
  13575. *
  13576. * @class AutoFill
  13577. * @constructor
  13578. * @param {object} oTD DataTables settings object
  13579. * @param {object} oConfig Configuration object for AutoFill
  13580. */
  13581. var AutoFill = function( dt, opts )
  13582. {
  13583. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
  13584. throw( "Warning: AutoFill requires DataTables 1.10.8 or greater");
  13585. }
  13586. // User and defaults configuration object
  13587. this.c = $.extend( true, {},
  13588. DataTable.defaults.autoFill,
  13589. AutoFill.defaults,
  13590. opts
  13591. );
  13592. /**
  13593. * @namespace Settings object which contains customisable information for AutoFill instance
  13594. */
  13595. this.s = {
  13596. /** @type {DataTable.Api} DataTables' API instance */
  13597. dt: new DataTable.Api( dt ),
  13598. /** @type {String} Unique namespace for events attached to the document */
  13599. namespace: '.autoFill'+(_instance++),
  13600. /** @type {Object} Cached dimension information for use in the mouse move event handler */
  13601. scroll: {},
  13602. /** @type {integer} Interval object used for smooth scrolling */
  13603. scrollInterval: null,
  13604. handle: {
  13605. height: 0,
  13606. width: 0
  13607. },
  13608. /**
  13609. * Enabled setting
  13610. * @type {Boolean}
  13611. */
  13612. enabled: false
  13613. };
  13614. /**
  13615. * @namespace Common and useful DOM elements for the class instance
  13616. */
  13617. this.dom = {
  13618. /** @type {jQuery} AutoFill handle */
  13619. handle: $('<div class="dt-autofill-handle"/>'),
  13620. /**
  13621. * @type {Object} Selected cells outline - Need to use 4 elements,
  13622. * otherwise the mouse over if you back into the selected rectangle
  13623. * will be over that element, rather than the cells!
  13624. */
  13625. select: {
  13626. top: $('<div class="dt-autofill-select top"/>'),
  13627. right: $('<div class="dt-autofill-select right"/>'),
  13628. bottom: $('<div class="dt-autofill-select bottom"/>'),
  13629. left: $('<div class="dt-autofill-select left"/>')
  13630. },
  13631. /** @type {jQuery} Fill type chooser background */
  13632. background: $('<div class="dt-autofill-background"/>'),
  13633. /** @type {jQuery} Fill type chooser */
  13634. list: $('<div class="dt-autofill-list">'+this.s.dt.i18n('autoFill.info', '')+'<ul/></div>'),
  13635. /** @type {jQuery} DataTables scrolling container */
  13636. dtScroll: null,
  13637. /** @type {jQuery} Offset parent element */
  13638. offsetParent: null
  13639. };
  13640. /* Constructor logic */
  13641. this._constructor();
  13642. };
  13643. $.extend( AutoFill.prototype, {
  13644. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13645. * Public methods (exposed via the DataTables API below)
  13646. */
  13647. enabled: function ()
  13648. {
  13649. return this.s.enabled;
  13650. },
  13651. enable: function ( flag )
  13652. {
  13653. var that = this;
  13654. if ( flag === false ) {
  13655. return this.disable();
  13656. }
  13657. this.s.enabled = true;
  13658. this._focusListener();
  13659. this.dom.handle.on( 'mousedown', function (e) {
  13660. that._mousedown( e );
  13661. return false;
  13662. } );
  13663. return this;
  13664. },
  13665. disable: function ()
  13666. {
  13667. this.s.enabled = false;
  13668. this._focusListenerRemove();
  13669. return this;
  13670. },
  13671. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13672. * Constructor
  13673. */
  13674. /**
  13675. * Initialise the RowReorder instance
  13676. *
  13677. * @private
  13678. */
  13679. _constructor: function ()
  13680. {
  13681. var that = this;
  13682. var dt = this.s.dt;
  13683. var dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container());
  13684. // Make the instance accessible to the API
  13685. dt.settings()[0].autoFill = this;
  13686. if ( dtScroll.length ) {
  13687. this.dom.dtScroll = dtScroll;
  13688. // Need to scroll container to be the offset parent
  13689. if ( dtScroll.css('position') === 'static' ) {
  13690. dtScroll.css( 'position', 'relative' );
  13691. }
  13692. }
  13693. if ( this.c.enable !== false ) {
  13694. this.enable();
  13695. }
  13696. dt.on( 'destroy.autoFill', function () {
  13697. that._focusListenerRemove();
  13698. } );
  13699. },
  13700. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13701. * Private methods
  13702. */
  13703. /**
  13704. * Display the AutoFill drag handle by appending it to a table cell. This
  13705. * is the opposite of the _detach method.
  13706. *
  13707. * @param {node} node TD/TH cell to insert the handle into
  13708. * @private
  13709. */
  13710. _attach: function ( node )
  13711. {
  13712. var dt = this.s.dt;
  13713. var idx = dt.cell( node ).index();
  13714. var handle = this.dom.handle;
  13715. var handleDim = this.s.handle;
  13716. if ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {
  13717. this._detach();
  13718. return;
  13719. }
  13720. if ( ! this.dom.offsetParent ) {
  13721. // We attach to the table's offset parent
  13722. this.dom.offsetParent = $( dt.table().node() ).offsetParent();
  13723. }
  13724. if ( ! handleDim.height || ! handleDim.width ) {
  13725. // Append to document so we can get its size. Not expecting it to
  13726. // change during the life time of the page
  13727. handle.appendTo( 'body' );
  13728. handleDim.height = handle.outerHeight();
  13729. handleDim.width = handle.outerWidth();
  13730. }
  13731. // Might need to go through multiple offset parents
  13732. var offset = this._getPosition( node, this.dom.offsetParent );
  13733. this.dom.attachedTo = node;
  13734. handle
  13735. .css( {
  13736. top: offset.top + node.offsetHeight - handleDim.height,
  13737. left: offset.left + node.offsetWidth - handleDim.width
  13738. } )
  13739. .appendTo( this.dom.offsetParent );
  13740. },
  13741. /**
  13742. * Determine can the fill type should be. This can be automatic, or ask the
  13743. * end user.
  13744. *
  13745. * @param {array} cells Information about the selected cells from the key
  13746. * up function
  13747. * @private
  13748. */
  13749. _actionSelector: function ( cells )
  13750. {
  13751. var that = this;
  13752. var dt = this.s.dt;
  13753. var actions = AutoFill.actions;
  13754. var available = [];
  13755. // "Ask" each plug-in if it wants to handle this data
  13756. $.each( actions, function ( key, action ) {
  13757. if ( action.available( dt, cells ) ) {
  13758. available.push( key );
  13759. }
  13760. } );
  13761. if ( available.length === 1 && this.c.alwaysAsk === false ) {
  13762. // Only one action available - enact it immediately
  13763. var result = actions[ available[0] ].execute( dt, cells );
  13764. this._update( result, cells );
  13765. }
  13766. else {
  13767. // Multiple actions available - ask the end user what they want to do
  13768. var list = this.dom.list.children('ul').empty();
  13769. // Add a cancel option
  13770. available.push( 'cancel' );
  13771. $.each( available, function ( i, name ) {
  13772. list.append( $('<li/>')
  13773. .append(
  13774. '<div class="dt-autofill-question">'+
  13775. actions[ name ].option( dt, cells )+
  13776. '<div>'
  13777. )
  13778. .append( $('<div class="dt-autofill-button">' )
  13779. .append( $('<button class="'+AutoFill.classes.btn+'">'+dt.i18n('autoFill.button', '&gt;')+'</button>')
  13780. .on( 'click', function () {
  13781. var result = actions[ name ].execute(
  13782. dt, cells, $(this).closest('li')
  13783. );
  13784. that._update( result, cells );
  13785. that.dom.background.remove();
  13786. that.dom.list.remove();
  13787. } )
  13788. )
  13789. )
  13790. );
  13791. } );
  13792. this.dom.background.appendTo( 'body' );
  13793. this.dom.list.appendTo( 'body' );
  13794. this.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );
  13795. }
  13796. },
  13797. /**
  13798. * Remove the AutoFill handle from the document
  13799. *
  13800. * @private
  13801. */
  13802. _detach: function ()
  13803. {
  13804. this.dom.attachedTo = null;
  13805. this.dom.handle.detach();
  13806. },
  13807. /**
  13808. * Draw the selection outline by calculating the range between the start
  13809. * and end cells, then placing the highlighting elements to draw a rectangle
  13810. *
  13811. * @param {node} target End cell
  13812. * @param {object} e Originating event
  13813. * @private
  13814. */
  13815. _drawSelection: function ( target, e )
  13816. {
  13817. // Calculate boundary for start cell to this one
  13818. var dt = this.s.dt;
  13819. var start = this.s.start;
  13820. var startCell = $(this.dom.start);
  13821. var end = {
  13822. row: this.c.vertical ?
  13823. dt.rows( { page: 'current' } ).nodes().indexOf( target.parentNode ) :
  13824. start.row,
  13825. column: this.c.horizontal ?
  13826. $(target).index() :
  13827. start.column
  13828. };
  13829. var colIndx = dt.column.index( 'toData', end.column );
  13830. var endRow = dt.row( ':eq('+end.row+')', { page: 'current' } ); // Workaround for M581
  13831. var endCell = $( dt.cell( endRow.index(), colIndx ).node() );
  13832. // Be sure that is a DataTables controlled cell
  13833. if ( ! dt.cell( endCell ).any() ) {
  13834. return;
  13835. }
  13836. // if target is not in the columns available - do nothing
  13837. if ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 ) {
  13838. return;
  13839. }
  13840. this.s.end = end;
  13841. var top, bottom, left, right, height, width;
  13842. top = start.row < end.row ? startCell : endCell;
  13843. bottom = start.row < end.row ? endCell : startCell;
  13844. left = start.column < end.column ? startCell : endCell;
  13845. right = start.column < end.column ? endCell : startCell;
  13846. top = this._getPosition( top.get(0) ).top;
  13847. left = this._getPosition( left.get(0) ).left;
  13848. height = this._getPosition( bottom.get(0) ).top + bottom.outerHeight() - top;
  13849. width = this._getPosition( right.get(0) ).left + right.outerWidth() - left;
  13850. var select = this.dom.select;
  13851. select.top.css( {
  13852. top: top,
  13853. left: left,
  13854. width: width
  13855. } );
  13856. select.left.css( {
  13857. top: top,
  13858. left: left,
  13859. height: height
  13860. } );
  13861. select.bottom.css( {
  13862. top: top + height,
  13863. left: left,
  13864. width: width
  13865. } );
  13866. select.right.css( {
  13867. top: top,
  13868. left: left + width,
  13869. height: height
  13870. } );
  13871. },
  13872. /**
  13873. * Use the Editor API to perform an update based on the new data for the
  13874. * cells
  13875. *
  13876. * @param {array} cells Information about the selected cells from the key
  13877. * up function
  13878. * @private
  13879. */
  13880. _editor: function ( cells )
  13881. {
  13882. var dt = this.s.dt;
  13883. var editor = this.c.editor;
  13884. if ( ! editor ) {
  13885. return;
  13886. }
  13887. // Build the object structure for Editor's multi-row editing
  13888. var idValues = {};
  13889. var nodes = [];
  13890. var fields = editor.fields();
  13891. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  13892. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  13893. var cell = cells[i][j];
  13894. // Determine the field name for the cell being edited
  13895. var col = dt.settings()[0].aoColumns[ cell.index.column ];
  13896. var fieldName = col.editField;
  13897. if ( fieldName === undefined ) {
  13898. var dataSrc = col.mData;
  13899. // dataSrc is the `field.data` property, but we need to set
  13900. // using the field name, so we need to translate from the
  13901. // data to the name
  13902. for ( var k=0, ken=fields.length ; k<ken ; k++ ) {
  13903. var field = editor.field( fields[k] );
  13904. if ( field.dataSrc() === dataSrc ) {
  13905. fieldName = field.name();
  13906. break;
  13907. }
  13908. }
  13909. }
  13910. if ( ! fieldName ) {
  13911. throw 'Could not automatically determine field data. '+
  13912. 'Please see https://datatables.net/tn/11';
  13913. }
  13914. if ( ! idValues[ fieldName ] ) {
  13915. idValues[ fieldName ] = {};
  13916. }
  13917. var id = dt.row( cell.index.row ).id();
  13918. idValues[ fieldName ][ id ] = cell.set;
  13919. // Keep a list of cells so we can activate the bubble editing
  13920. // with them
  13921. nodes.push( cell.index );
  13922. }
  13923. }
  13924. // Perform the edit using bubble editing as it allows us to specify
  13925. // the cells to be edited, rather than using full rows
  13926. editor
  13927. .bubble( nodes, false )
  13928. .multiSet( idValues )
  13929. .submit();
  13930. },
  13931. /**
  13932. * Emit an event on the DataTable for listeners
  13933. *
  13934. * @param {string} name Event name
  13935. * @param {array} args Event arguments
  13936. * @private
  13937. */
  13938. _emitEvent: function ( name, args )
  13939. {
  13940. this.s.dt.iterator( 'table', function ( ctx, i ) {
  13941. $(ctx.nTable).triggerHandler( name+'.dt', args );
  13942. } );
  13943. },
  13944. /**
  13945. * Attach suitable listeners (based on the configuration) that will attach
  13946. * and detach the AutoFill handle in the document.
  13947. *
  13948. * @private
  13949. */
  13950. _focusListener: function ()
  13951. {
  13952. var that = this;
  13953. var dt = this.s.dt;
  13954. var namespace = this.s.namespace;
  13955. var focus = this.c.focus !== null ?
  13956. this.c.focus :
  13957. dt.init().keys || dt.settings()[0].keytable ?
  13958. 'focus' :
  13959. 'hover';
  13960. // All event listeners attached here are removed in the `destroy`
  13961. // callback in the constructor
  13962. if ( focus === 'focus' ) {
  13963. dt
  13964. .on( 'key-focus.autoFill', function ( e, dt, cell ) {
  13965. that._attach( cell.node() );
  13966. } )
  13967. .on( 'key-blur.autoFill', function ( e, dt, cell ) {
  13968. that._detach();
  13969. } );
  13970. }
  13971. else if ( focus === 'click' ) {
  13972. $(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {
  13973. that._attach( this );
  13974. } );
  13975. $(document.body).on( 'click'+namespace, function (e) {
  13976. if ( ! $(e.target).parents().filter( dt.table().body() ).length ) {
  13977. that._detach();
  13978. }
  13979. } );
  13980. }
  13981. else {
  13982. $(dt.table().body())
  13983. .on( 'mouseenter'+namespace, 'td, th', function (e) {
  13984. that._attach( this );
  13985. } )
  13986. .on( 'mouseleave'+namespace, function (e) {
  13987. if ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {
  13988. return;
  13989. }
  13990. that._detach();
  13991. } );
  13992. }
  13993. },
  13994. _focusListenerRemove: function ()
  13995. {
  13996. var dt = this.s.dt;
  13997. dt.off( '.autoFill' );
  13998. $(dt.table().body()).off( this.s.namespace );
  13999. $(document.body).off( this.s.namespace );
  14000. },
  14001. /**
  14002. * Get the position of a node, relative to another, including any scrolling
  14003. * offsets.
  14004. * @param {Node} node Node to get the position of
  14005. * @param {jQuery} targetParent Node to use as the parent
  14006. * @return {object} Offset calculation
  14007. * @private
  14008. */
  14009. _getPosition: function ( node, targetParent )
  14010. {
  14011. var
  14012. currNode = node,
  14013. currOffsetParent,
  14014. top = 0,
  14015. left = 0;
  14016. if ( ! targetParent ) {
  14017. targetParent = $( $( this.s.dt.table().node() )[0].offsetParent );
  14018. }
  14019. do {
  14020. // Don't use jQuery().position() the behaviour changes between 1.x and 3.x for
  14021. // tables
  14022. var positionTop = currNode.offsetTop;
  14023. var positionLeft = currNode.offsetLeft;
  14024. // jQuery doesn't give a `table` as the offset parent oddly, so use DOM directly
  14025. currOffsetParent = $( currNode.offsetParent );
  14026. top += positionTop + parseInt( currOffsetParent.css('border-top-width') ) * 1;
  14027. left += positionLeft + parseInt( currOffsetParent.css('border-left-width') ) * 1;
  14028. // Emergency fall back. Shouldn't happen, but just in case!
  14029. if ( currNode.nodeName.toLowerCase() === 'body' ) {
  14030. break;
  14031. }
  14032. currNode = currOffsetParent.get(0); // for next loop
  14033. }
  14034. while ( currOffsetParent.get(0) !== targetParent.get(0) )
  14035. return {
  14036. top: top,
  14037. left: left
  14038. };
  14039. },
  14040. /**
  14041. * Start mouse drag - selects the start cell
  14042. *
  14043. * @param {object} e Mouse down event
  14044. * @private
  14045. */
  14046. _mousedown: function ( e )
  14047. {
  14048. var that = this;
  14049. var dt = this.s.dt;
  14050. this.dom.start = this.dom.attachedTo;
  14051. this.s.start = {
  14052. row: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),
  14053. column: $(this.dom.start).index()
  14054. };
  14055. $(document.body)
  14056. .on( 'mousemove.autoFill', function (e) {
  14057. that._mousemove( e );
  14058. } )
  14059. .on( 'mouseup.autoFill', function (e) {
  14060. that._mouseup( e );
  14061. } );
  14062. var select = this.dom.select;
  14063. var offsetParent = $( dt.table().node() ).offsetParent();
  14064. select.top.appendTo( offsetParent );
  14065. select.left.appendTo( offsetParent );
  14066. select.right.appendTo( offsetParent );
  14067. select.bottom.appendTo( offsetParent );
  14068. this._drawSelection( this.dom.start, e );
  14069. this.dom.handle.css( 'display', 'none' );
  14070. // Cache scrolling information so mouse move doesn't need to read.
  14071. // This assumes that the window and DT scroller will not change size
  14072. // during an AutoFill drag, which I think is a fair assumption
  14073. var scrollWrapper = this.dom.dtScroll;
  14074. this.s.scroll = {
  14075. windowHeight: $(window).height(),
  14076. windowWidth: $(window).width(),
  14077. dtTop: scrollWrapper ? scrollWrapper.offset().top : null,
  14078. dtLeft: scrollWrapper ? scrollWrapper.offset().left : null,
  14079. dtHeight: scrollWrapper ? scrollWrapper.outerHeight() : null,
  14080. dtWidth: scrollWrapper ? scrollWrapper.outerWidth() : null
  14081. };
  14082. },
  14083. /**
  14084. * Mouse drag - selects the end cell and update the selection display for
  14085. * the end user
  14086. *
  14087. * @param {object} e Mouse move event
  14088. * @private
  14089. */
  14090. _mousemove: function ( e )
  14091. {
  14092. var that = this;
  14093. var dt = this.s.dt;
  14094. var name = e.target.nodeName.toLowerCase();
  14095. if ( name !== 'td' && name !== 'th' ) {
  14096. return;
  14097. }
  14098. this._drawSelection( e.target, e );
  14099. this._shiftScroll( e );
  14100. },
  14101. /**
  14102. * End mouse drag - perform the update actions
  14103. *
  14104. * @param {object} e Mouse up event
  14105. * @private
  14106. */
  14107. _mouseup: function ( e )
  14108. {
  14109. $(document.body).off( '.autoFill' );
  14110. var that = this;
  14111. var dt = this.s.dt;
  14112. var select = this.dom.select;
  14113. select.top.remove();
  14114. select.left.remove();
  14115. select.right.remove();
  14116. select.bottom.remove();
  14117. this.dom.handle.css( 'display', 'block' );
  14118. // Display complete - now do something useful with the selection!
  14119. var start = this.s.start;
  14120. var end = this.s.end;
  14121. // Haven't selected multiple cells, so nothing to do
  14122. if ( start.row === end.row && start.column === end.column ) {
  14123. return;
  14124. }
  14125. var startDt = dt.cell( ':eq('+start.row+')', start.column+':visible', {page:'current'} );
  14126. // If Editor is active inside this cell (inline editing) we need to wait for Editor to
  14127. // submit and then we can loop back and trigger the fill.
  14128. if ( $('div.DTE', startDt.node()).length ) {
  14129. var editor = dt.editor();
  14130. editor
  14131. .on( 'submitSuccess.dtaf close.dtaf', function () {
  14132. editor.off( '.dtaf');
  14133. setTimeout( function () {
  14134. that._mouseup( e );
  14135. }, 100 );
  14136. } )
  14137. .on( 'submitComplete.dtaf preSubmitCancelled.dtaf close.dtaf', function () {
  14138. editor.off( '.dtaf');
  14139. } );
  14140. // Make the current input submit
  14141. editor.submit();
  14142. return;
  14143. }
  14144. // Build a matrix representation of the selected rows
  14145. var rows = this._range( start.row, end.row );
  14146. var columns = this._range( start.column, end.column );
  14147. var selected = [];
  14148. var dtSettings = dt.settings()[0];
  14149. var dtColumns = dtSettings.aoColumns;
  14150. var enabledColumns = dt.columns( this.c.columns ).indexes();
  14151. // Can't use Array.prototype.map as IE8 doesn't support it
  14152. // Can't use $.map as jQuery flattens 2D arrays
  14153. // Need to use a good old fashioned for loop
  14154. for ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {
  14155. selected.push(
  14156. $.map( columns, function (column) {
  14157. var row = dt.row( ':eq('+rows[rowIdx]+')', {page:'current'} ); // Workaround for M581
  14158. var cell = dt.cell( row.index(), column+':visible' );
  14159. var data = cell.data();
  14160. var cellIndex = cell.index();
  14161. var editField = dtColumns[ cellIndex.column ].editField;
  14162. if ( editField !== undefined ) {
  14163. data = dtSettings.oApi._fnGetObjectDataFn( editField )( dt.row( cellIndex.row ).data() );
  14164. }
  14165. if ( enabledColumns.indexOf(cellIndex.column) === -1 ) {
  14166. return;
  14167. }
  14168. return {
  14169. cell: cell,
  14170. data: data,
  14171. label: cell.data(),
  14172. index: cellIndex
  14173. };
  14174. } )
  14175. );
  14176. }
  14177. this._actionSelector( selected );
  14178. // Stop shiftScroll
  14179. clearInterval( this.s.scrollInterval );
  14180. this.s.scrollInterval = null;
  14181. },
  14182. /**
  14183. * Create an array with a range of numbers defined by the start and end
  14184. * parameters passed in (inclusive!).
  14185. *
  14186. * @param {integer} start Start
  14187. * @param {integer} end End
  14188. * @private
  14189. */
  14190. _range: function ( start, end )
  14191. {
  14192. var out = [];
  14193. var i;
  14194. if ( start <= end ) {
  14195. for ( i=start ; i<=end ; i++ ) {
  14196. out.push( i );
  14197. }
  14198. }
  14199. else {
  14200. for ( i=start ; i>=end ; i-- ) {
  14201. out.push( i );
  14202. }
  14203. }
  14204. return out;
  14205. },
  14206. /**
  14207. * Move the window and DataTables scrolling during a drag to scroll new
  14208. * content into view. This is done by proximity to the edge of the scrolling
  14209. * container of the mouse - for example near the top edge of the window
  14210. * should scroll up. This is a little complicated as there are two elements
  14211. * that can be scrolled - the window and the DataTables scrolling view port
  14212. * (if scrollX and / or scrollY is enabled).
  14213. *
  14214. * @param {object} e Mouse move event object
  14215. * @private
  14216. */
  14217. _shiftScroll: function ( e )
  14218. {
  14219. var that = this;
  14220. var dt = this.s.dt;
  14221. var scroll = this.s.scroll;
  14222. var runInterval = false;
  14223. var scrollSpeed = 5;
  14224. var buffer = 65;
  14225. var
  14226. windowY = e.pageY - document.body.scrollTop,
  14227. windowX = e.pageX - document.body.scrollLeft,
  14228. windowVert, windowHoriz,
  14229. dtVert, dtHoriz;
  14230. // Window calculations - based on the mouse position in the window,
  14231. // regardless of scrolling
  14232. if ( windowY < buffer ) {
  14233. windowVert = scrollSpeed * -1;
  14234. }
  14235. else if ( windowY > scroll.windowHeight - buffer ) {
  14236. windowVert = scrollSpeed;
  14237. }
  14238. if ( windowX < buffer ) {
  14239. windowHoriz = scrollSpeed * -1;
  14240. }
  14241. else if ( windowX > scroll.windowWidth - buffer ) {
  14242. windowHoriz = scrollSpeed;
  14243. }
  14244. // DataTables scrolling calculations - based on the table's position in
  14245. // the document and the mouse position on the page
  14246. if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {
  14247. dtVert = scrollSpeed * -1;
  14248. }
  14249. else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
  14250. dtVert = scrollSpeed;
  14251. }
  14252. if ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) {
  14253. dtHoriz = scrollSpeed * -1;
  14254. }
  14255. else if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {
  14256. dtHoriz = scrollSpeed;
  14257. }
  14258. // This is where it gets interesting. We want to continue scrolling
  14259. // without requiring a mouse move, so we need an interval to be
  14260. // triggered. The interval should continue until it is no longer needed,
  14261. // but it must also use the latest scroll commands (for example consider
  14262. // that the mouse might move from scrolling up to scrolling left, all
  14263. // with the same interval running. We use the `scroll` object to "pass"
  14264. // this information to the interval. Can't use local variables as they
  14265. // wouldn't be the ones that are used by an already existing interval!
  14266. if ( windowVert || windowHoriz || dtVert || dtHoriz ) {
  14267. scroll.windowVert = windowVert;
  14268. scroll.windowHoriz = windowHoriz;
  14269. scroll.dtVert = dtVert;
  14270. scroll.dtHoriz = dtHoriz;
  14271. runInterval = true;
  14272. }
  14273. else if ( this.s.scrollInterval ) {
  14274. // Don't need to scroll - remove any existing timer
  14275. clearInterval( this.s.scrollInterval );
  14276. this.s.scrollInterval = null;
  14277. }
  14278. // If we need to run the interval to scroll and there is no existing
  14279. // interval (if there is an existing one, it will continue to run)
  14280. if ( ! this.s.scrollInterval && runInterval ) {
  14281. this.s.scrollInterval = setInterval( function () {
  14282. // Don't need to worry about setting scroll <0 or beyond the
  14283. // scroll bound as the browser will just reject that.
  14284. if ( scroll.windowVert ) {
  14285. document.body.scrollTop += scroll.windowVert;
  14286. }
  14287. if ( scroll.windowHoriz ) {
  14288. document.body.scrollLeft += scroll.windowHoriz;
  14289. }
  14290. // DataTables scrolling
  14291. if ( scroll.dtVert || scroll.dtHoriz ) {
  14292. var scroller = that.dom.dtScroll[0];
  14293. if ( scroll.dtVert ) {
  14294. scroller.scrollTop += scroll.dtVert;
  14295. }
  14296. if ( scroll.dtHoriz ) {
  14297. scroller.scrollLeft += scroll.dtHoriz;
  14298. }
  14299. }
  14300. }, 20 );
  14301. }
  14302. },
  14303. /**
  14304. * Update the DataTable after the user has selected what they want to do
  14305. *
  14306. * @param {false|undefined} result Return from the `execute` method - can
  14307. * be false internally to do nothing. This is not documented for plug-ins
  14308. * and is used only by the cancel option.
  14309. * @param {array} cells Information about the selected cells from the key
  14310. * up function, argumented with the set values
  14311. * @private
  14312. */
  14313. _update: function ( result, cells )
  14314. {
  14315. // Do nothing on `false` return from an execute function
  14316. if ( result === false ) {
  14317. return;
  14318. }
  14319. var dt = this.s.dt;
  14320. var cell;
  14321. var columns = dt.columns( this.c.columns ).indexes();
  14322. // Potentially allow modifications to the cells matrix
  14323. this._emitEvent( 'preAutoFill', [ dt, cells ] );
  14324. this._editor( cells );
  14325. // Automatic updates are not performed if `update` is null and the
  14326. // `editor` parameter is passed in - the reason being that Editor will
  14327. // update the data once submitted
  14328. var update = this.c.update !== null ?
  14329. this.c.update :
  14330. this.c.editor ?
  14331. false :
  14332. true;
  14333. if ( update ) {
  14334. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14335. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14336. cell = cells[i][j];
  14337. if ( columns.indexOf(cell.index.column) !== -1 ) {
  14338. cell.cell.data( cell.set );
  14339. }
  14340. }
  14341. }
  14342. dt.draw(false);
  14343. }
  14344. this._emitEvent( 'autoFill', [ dt, cells ] );
  14345. }
  14346. } );
  14347. /**
  14348. * AutoFill actions. The options here determine how AutoFill will fill the data
  14349. * in the table when the user has selected a range of cells. Please see the
  14350. * documentation on the DataTables site for full details on how to create plug-
  14351. * ins.
  14352. *
  14353. * @type {Object}
  14354. */
  14355. AutoFill.actions = {
  14356. increment: {
  14357. available: function ( dt, cells ) {
  14358. var d = cells[0][0].label;
  14359. // is numeric test based on jQuery's old `isNumeric` function
  14360. return !isNaN( d - parseFloat( d ) );
  14361. },
  14362. option: function ( dt, cells ) {
  14363. return dt.i18n(
  14364. 'autoFill.increment',
  14365. 'Increment / decrement each cell by: <input type="number" value="1">'
  14366. );
  14367. },
  14368. execute: function ( dt, cells, node ) {
  14369. var value = cells[0][0].data * 1;
  14370. var increment = $('input', node).val() * 1;
  14371. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14372. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14373. cells[i][j].set = value;
  14374. value += increment;
  14375. }
  14376. }
  14377. }
  14378. },
  14379. fill: {
  14380. available: function ( dt, cells ) {
  14381. return true;
  14382. },
  14383. option: function ( dt, cells ) {
  14384. return dt.i18n('autoFill.fill', 'Fill all cells with <i>'+cells[0][0].label+'</i>' );
  14385. },
  14386. execute: function ( dt, cells, node ) {
  14387. var value = cells[0][0].data;
  14388. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14389. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14390. cells[i][j].set = value;
  14391. }
  14392. }
  14393. }
  14394. },
  14395. fillHorizontal: {
  14396. available: function ( dt, cells ) {
  14397. return cells.length > 1 && cells[0].length > 1;
  14398. },
  14399. option: function ( dt, cells ) {
  14400. return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );
  14401. },
  14402. execute: function ( dt, cells, node ) {
  14403. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14404. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14405. cells[i][j].set = cells[i][0].data;
  14406. }
  14407. }
  14408. }
  14409. },
  14410. fillVertical: {
  14411. available: function ( dt, cells ) {
  14412. return cells.length > 1 && cells[0].length > 1;
  14413. },
  14414. option: function ( dt, cells ) {
  14415. return dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );
  14416. },
  14417. execute: function ( dt, cells, node ) {
  14418. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14419. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14420. cells[i][j].set = cells[0][j].data;
  14421. }
  14422. }
  14423. }
  14424. },
  14425. // Special type that does not make itself available, but is added
  14426. // automatically by AutoFill if a multi-choice list is shown. This allows
  14427. // sensible code reuse
  14428. cancel: {
  14429. available: function () {
  14430. return false;
  14431. },
  14432. option: function ( dt ) {
  14433. return dt.i18n('autoFill.cancel', 'Cancel' );
  14434. },
  14435. execute: function () {
  14436. return false;
  14437. }
  14438. }
  14439. };
  14440. /**
  14441. * AutoFill version
  14442. *
  14443. * @static
  14444. * @type String
  14445. */
  14446. AutoFill.version = '2.3.4';
  14447. /**
  14448. * AutoFill defaults
  14449. *
  14450. * @namespace
  14451. */
  14452. AutoFill.defaults = {
  14453. /** @type {Boolean} Ask user what they want to do, even for a single option */
  14454. alwaysAsk: false,
  14455. /** @type {string|null} What will trigger a focus */
  14456. focus: null, // focus, click, hover
  14457. /** @type {column-selector} Columns to provide auto fill for */
  14458. columns: '', // all
  14459. /** @type {Boolean} Enable AutoFill on load */
  14460. enable: true,
  14461. /** @type {boolean|null} Update the cells after a drag */
  14462. update: null, // false is editor given, true otherwise
  14463. /** @type {DataTable.Editor} Editor instance for automatic submission */
  14464. editor: null,
  14465. /** @type {boolean} Enable vertical fill */
  14466. vertical: true,
  14467. /** @type {boolean} Enable horizontal fill */
  14468. horizontal: true
  14469. };
  14470. /**
  14471. * Classes used by AutoFill that are configurable
  14472. *
  14473. * @namespace
  14474. */
  14475. AutoFill.classes = {
  14476. /** @type {String} Class used by the selection button */
  14477. btn: 'btn'
  14478. };
  14479. /*
  14480. * API
  14481. */
  14482. var Api = $.fn.dataTable.Api;
  14483. // Doesn't do anything - Not documented
  14484. Api.register( 'autoFill()', function () {
  14485. return this;
  14486. } );
  14487. Api.register( 'autoFill().enabled()', function () {
  14488. var ctx = this.context[0];
  14489. return ctx.autoFill ?
  14490. ctx.autoFill.enabled() :
  14491. false;
  14492. } );
  14493. Api.register( 'autoFill().enable()', function ( flag ) {
  14494. return this.iterator( 'table', function ( ctx ) {
  14495. if ( ctx.autoFill ) {
  14496. ctx.autoFill.enable( flag );
  14497. }
  14498. } );
  14499. } );
  14500. Api.register( 'autoFill().disable()', function () {
  14501. return this.iterator( 'table', function ( ctx ) {
  14502. if ( ctx.autoFill ) {
  14503. ctx.autoFill.disable();
  14504. }
  14505. } );
  14506. } );
  14507. // Attach a listener to the document which listens for DataTables initialisation
  14508. // events so we can automatically initialise
  14509. $(document).on( 'preInit.dt.autofill', function (e, settings, json) {
  14510. if ( e.namespace !== 'dt' ) {
  14511. return;
  14512. }
  14513. var init = settings.oInit.autoFill;
  14514. var defaults = DataTable.defaults.autoFill;
  14515. if ( init || defaults ) {
  14516. var opts = $.extend( {}, init, defaults );
  14517. if ( init !== false ) {
  14518. new AutoFill( settings, opts );
  14519. }
  14520. }
  14521. } );
  14522. // Alias for access
  14523. DataTable.AutoFill = AutoFill;
  14524. DataTable.AutoFill = AutoFill;
  14525. return AutoFill;
  14526. }));
  14527. /*! Bootstrap integration for DataTables' AutoFill
  14528. * ©2015 SpryMedia Ltd - datatables.net/license
  14529. */
  14530. (function( factory ){
  14531. if ( typeof define === 'function' && define.amd ) {
  14532. // AMD
  14533. define( ['jquery', 'datatables.net-bs4', 'datatables.net-autofill'], function ( $ ) {
  14534. return factory( $, window, document );
  14535. } );
  14536. }
  14537. else if ( typeof exports === 'object' ) {
  14538. // CommonJS
  14539. module.exports = function (root, $) {
  14540. if ( ! root ) {
  14541. root = window;
  14542. }
  14543. if ( ! $ || ! $.fn.dataTable ) {
  14544. $ = require('datatables.net-bs4')(root, $).$;
  14545. }
  14546. if ( ! $.fn.dataTable.AutoFill ) {
  14547. require('datatables.net-autofill')(root, $);
  14548. }
  14549. return factory( $, root, root.document );
  14550. };
  14551. }
  14552. else {
  14553. // Browser
  14554. factory( jQuery, window, document );
  14555. }
  14556. }(function( $, window, document, undefined ) {
  14557. 'use strict';
  14558. var DataTable = $.fn.dataTable;
  14559. DataTable.AutoFill.classes.btn = 'btn btn-primary';
  14560. return DataTable;
  14561. }));
  14562. /*! Buttons for DataTables 1.6.1
  14563. * ©2016-2019 SpryMedia Ltd - datatables.net/license
  14564. */
  14565. (function( factory ){
  14566. if ( typeof define === 'function' && define.amd ) {
  14567. // AMD
  14568. define( ['jquery', 'datatables.net'], function ( $ ) {
  14569. return factory( $, window, document );
  14570. } );
  14571. }
  14572. else if ( typeof exports === 'object' ) {
  14573. // CommonJS
  14574. module.exports = function (root, $) {
  14575. if ( ! root ) {
  14576. root = window;
  14577. }
  14578. if ( ! $ || ! $.fn.dataTable ) {
  14579. $ = require('datatables.net')(root, $).$;
  14580. }
  14581. return factory( $, root, root.document );
  14582. };
  14583. }
  14584. else {
  14585. // Browser
  14586. factory( jQuery, window, document );
  14587. }
  14588. }(function( $, window, document, undefined ) {
  14589. 'use strict';
  14590. var DataTable = $.fn.dataTable;
  14591. // Used for namespacing events added to the document by each instance, so they
  14592. // can be removed on destroy
  14593. var _instCounter = 0;
  14594. // Button namespacing counter for namespacing events on individual buttons
  14595. var _buttonCounter = 0;
  14596. var _dtButtons = DataTable.ext.buttons;
  14597. /**
  14598. * [Buttons description]
  14599. * @param {[type]}
  14600. * @param {[type]}
  14601. */
  14602. var Buttons = function( dt, config )
  14603. {
  14604. // If not created with a `new` keyword then we return a wrapper function that
  14605. // will take the settings object for a DT. This allows easy use of new instances
  14606. // with the `layout` option - e.g. `topLeft: $.fn.dataTable.Buttons( ... )`.
  14607. if ( !(this instanceof Buttons) ) {
  14608. return function (settings) {
  14609. return new Buttons( settings, dt ).container();
  14610. };
  14611. }
  14612. // If there is no config set it to an empty object
  14613. if ( typeof( config ) === 'undefined' ) {
  14614. config = {};
  14615. }
  14616. // Allow a boolean true for defaults
  14617. if ( config === true ) {
  14618. config = {};
  14619. }
  14620. // For easy configuration of buttons an array can be given
  14621. if ( $.isArray( config ) ) {
  14622. config = { buttons: config };
  14623. }
  14624. this.c = $.extend( true, {}, Buttons.defaults, config );
  14625. // Don't want a deep copy for the buttons
  14626. if ( config.buttons ) {
  14627. this.c.buttons = config.buttons;
  14628. }
  14629. this.s = {
  14630. dt: new DataTable.Api( dt ),
  14631. buttons: [],
  14632. listenKeys: '',
  14633. namespace: 'dtb'+(_instCounter++)
  14634. };
  14635. this.dom = {
  14636. container: $('<'+this.c.dom.container.tag+'/>')
  14637. .addClass( this.c.dom.container.className )
  14638. };
  14639. this._constructor();
  14640. };
  14641. $.extend( Buttons.prototype, {
  14642. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14643. * Public methods
  14644. */
  14645. /**
  14646. * Get the action of a button
  14647. * @param {int|string} Button index
  14648. * @return {function}
  14649. *//**
  14650. * Set the action of a button
  14651. * @param {node} node Button element
  14652. * @param {function} action Function to set
  14653. * @return {Buttons} Self for chaining
  14654. */
  14655. action: function ( node, action )
  14656. {
  14657. var button = this._nodeToButton( node );
  14658. if ( action === undefined ) {
  14659. return button.conf.action;
  14660. }
  14661. button.conf.action = action;
  14662. return this;
  14663. },
  14664. /**
  14665. * Add an active class to the button to make to look active or get current
  14666. * active state.
  14667. * @param {node} node Button element
  14668. * @param {boolean} [flag] Enable / disable flag
  14669. * @return {Buttons} Self for chaining or boolean for getter
  14670. */
  14671. active: function ( node, flag ) {
  14672. var button = this._nodeToButton( node );
  14673. var klass = this.c.dom.button.active;
  14674. var jqNode = $(button.node);
  14675. if ( flag === undefined ) {
  14676. return jqNode.hasClass( klass );
  14677. }
  14678. jqNode.toggleClass( klass, flag === undefined ? true : flag );
  14679. return this;
  14680. },
  14681. /**
  14682. * Add a new button
  14683. * @param {object} config Button configuration object, base string name or function
  14684. * @param {int|string} [idx] Button index for where to insert the button
  14685. * @return {Buttons} Self for chaining
  14686. */
  14687. add: function ( config, idx )
  14688. {
  14689. var buttons = this.s.buttons;
  14690. if ( typeof idx === 'string' ) {
  14691. var split = idx.split('-');
  14692. var base = this.s;
  14693. for ( var i=0, ien=split.length-1 ; i<ien ; i++ ) {
  14694. base = base.buttons[ split[i]*1 ];
  14695. }
  14696. buttons = base.buttons;
  14697. idx = split[ split.length-1 ]*1;
  14698. }
  14699. this._expandButton( buttons, config, base !== undefined, idx );
  14700. this._draw();
  14701. return this;
  14702. },
  14703. /**
  14704. * Get the container node for the buttons
  14705. * @return {jQuery} Buttons node
  14706. */
  14707. container: function ()
  14708. {
  14709. return this.dom.container;
  14710. },
  14711. /**
  14712. * Disable a button
  14713. * @param {node} node Button node
  14714. * @return {Buttons} Self for chaining
  14715. */
  14716. disable: function ( node ) {
  14717. var button = this._nodeToButton( node );
  14718. $(button.node).addClass( this.c.dom.button.disabled );
  14719. return this;
  14720. },
  14721. /**
  14722. * Destroy the instance, cleaning up event handlers and removing DOM
  14723. * elements
  14724. * @return {Buttons} Self for chaining
  14725. */
  14726. destroy: function ()
  14727. {
  14728. // Key event listener
  14729. $('body').off( 'keyup.'+this.s.namespace );
  14730. // Individual button destroy (so they can remove their own events if
  14731. // needed). Take a copy as the array is modified by `remove`
  14732. var buttons = this.s.buttons.slice();
  14733. var i, ien;
  14734. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  14735. this.remove( buttons[i].node );
  14736. }
  14737. // Container
  14738. this.dom.container.remove();
  14739. // Remove from the settings object collection
  14740. var buttonInsts = this.s.dt.settings()[0];
  14741. for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {
  14742. if ( buttonInsts.inst === this ) {
  14743. buttonInsts.splice( i, 1 );
  14744. break;
  14745. }
  14746. }
  14747. return this;
  14748. },
  14749. /**
  14750. * Enable / disable a button
  14751. * @param {node} node Button node
  14752. * @param {boolean} [flag=true] Enable / disable flag
  14753. * @return {Buttons} Self for chaining
  14754. */
  14755. enable: function ( node, flag )
  14756. {
  14757. if ( flag === false ) {
  14758. return this.disable( node );
  14759. }
  14760. var button = this._nodeToButton( node );
  14761. $(button.node).removeClass( this.c.dom.button.disabled );
  14762. return this;
  14763. },
  14764. /**
  14765. * Get the instance name for the button set selector
  14766. * @return {string} Instance name
  14767. */
  14768. name: function ()
  14769. {
  14770. return this.c.name;
  14771. },
  14772. /**
  14773. * Get a button's node of the buttons container if no button is given
  14774. * @param {node} [node] Button node
  14775. * @return {jQuery} Button element, or container
  14776. */
  14777. node: function ( node )
  14778. {
  14779. if ( ! node ) {
  14780. return this.dom.container;
  14781. }
  14782. var button = this._nodeToButton( node );
  14783. return $(button.node);
  14784. },
  14785. /**
  14786. * Set / get a processing class on the selected button
  14787. * @param {element} node Triggering button node
  14788. * @param {boolean} flag true to add, false to remove, undefined to get
  14789. * @return {boolean|Buttons} Getter value or this if a setter.
  14790. */
  14791. processing: function ( node, flag )
  14792. {
  14793. var dt = this.s.dt;
  14794. var button = this._nodeToButton( node );
  14795. if ( flag === undefined ) {
  14796. return $(button.node).hasClass( 'processing' );
  14797. }
  14798. $(button.node).toggleClass( 'processing', flag );
  14799. $(dt.table().node()).triggerHandler( 'buttons-processing.dt', [
  14800. flag, dt.button( node ), dt, $(node), button.conf
  14801. ] );
  14802. return this;
  14803. },
  14804. /**
  14805. * Remove a button.
  14806. * @param {node} node Button node
  14807. * @return {Buttons} Self for chaining
  14808. */
  14809. remove: function ( node )
  14810. {
  14811. var button = this._nodeToButton( node );
  14812. var host = this._nodeToHost( node );
  14813. var dt = this.s.dt;
  14814. // Remove any child buttons first
  14815. if ( button.buttons.length ) {
  14816. for ( var i=button.buttons.length-1 ; i>=0 ; i-- ) {
  14817. this.remove( button.buttons[i].node );
  14818. }
  14819. }
  14820. // Allow the button to remove event handlers, etc
  14821. if ( button.conf.destroy ) {
  14822. button.conf.destroy.call( dt.button(node), dt, $(node), button.conf );
  14823. }
  14824. this._removeKey( button.conf );
  14825. $(button.node).remove();
  14826. var idx = $.inArray( button, host );
  14827. host.splice( idx, 1 );
  14828. return this;
  14829. },
  14830. /**
  14831. * Get the text for a button
  14832. * @param {int|string} node Button index
  14833. * @return {string} Button text
  14834. *//**
  14835. * Set the text for a button
  14836. * @param {int|string|function} node Button index
  14837. * @param {string} label Text
  14838. * @return {Buttons} Self for chaining
  14839. */
  14840. text: function ( node, label )
  14841. {
  14842. var button = this._nodeToButton( node );
  14843. var buttonLiner = this.c.dom.collection.buttonLiner;
  14844. var linerTag = button.inCollection && buttonLiner && buttonLiner.tag ?
  14845. buttonLiner.tag :
  14846. this.c.dom.buttonLiner.tag;
  14847. var dt = this.s.dt;
  14848. var jqNode = $(button.node);
  14849. var text = function ( opt ) {
  14850. return typeof opt === 'function' ?
  14851. opt( dt, jqNode, button.conf ) :
  14852. opt;
  14853. };
  14854. if ( label === undefined ) {
  14855. return text( button.conf.text );
  14856. }
  14857. button.conf.text = label;
  14858. if ( linerTag ) {
  14859. jqNode.children( linerTag ).html( text(label) );
  14860. }
  14861. else {
  14862. jqNode.html( text(label) );
  14863. }
  14864. return this;
  14865. },
  14866. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14867. * Constructor
  14868. */
  14869. /**
  14870. * Buttons constructor
  14871. * @private
  14872. */
  14873. _constructor: function ()
  14874. {
  14875. var that = this;
  14876. var dt = this.s.dt;
  14877. var dtSettings = dt.settings()[0];
  14878. var buttons = this.c.buttons;
  14879. if ( ! dtSettings._buttons ) {
  14880. dtSettings._buttons = [];
  14881. }
  14882. dtSettings._buttons.push( {
  14883. inst: this,
  14884. name: this.c.name
  14885. } );
  14886. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14887. this.add( buttons[i] );
  14888. }
  14889. dt.on( 'destroy', function ( e, settings ) {
  14890. if ( settings === dtSettings ) {
  14891. that.destroy();
  14892. }
  14893. } );
  14894. // Global key event binding to listen for button keys
  14895. $('body').on( 'keyup.'+this.s.namespace, function ( e ) {
  14896. if ( ! document.activeElement || document.activeElement === document.body ) {
  14897. // SUse a string of characters for fast lookup of if we need to
  14898. // handle this
  14899. var character = String.fromCharCode(e.keyCode).toLowerCase();
  14900. if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {
  14901. that._keypress( character, e );
  14902. }
  14903. }
  14904. } );
  14905. },
  14906. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14907. * Private methods
  14908. */
  14909. /**
  14910. * Add a new button to the key press listener
  14911. * @param {object} conf Resolved button configuration object
  14912. * @private
  14913. */
  14914. _addKey: function ( conf )
  14915. {
  14916. if ( conf.key ) {
  14917. this.s.listenKeys += $.isPlainObject( conf.key ) ?
  14918. conf.key.key :
  14919. conf.key;
  14920. }
  14921. },
  14922. /**
  14923. * Insert the buttons into the container. Call without parameters!
  14924. * @param {node} [container] Recursive only - Insert point
  14925. * @param {array} [buttons] Recursive only - Buttons array
  14926. * @private
  14927. */
  14928. _draw: function ( container, buttons )
  14929. {
  14930. if ( ! container ) {
  14931. container = this.dom.container;
  14932. buttons = this.s.buttons;
  14933. }
  14934. container.children().detach();
  14935. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14936. container.append( buttons[i].inserter );
  14937. container.append( ' ' );
  14938. if ( buttons[i].buttons && buttons[i].buttons.length ) {
  14939. this._draw( buttons[i].collection, buttons[i].buttons );
  14940. }
  14941. }
  14942. },
  14943. /**
  14944. * Create buttons from an array of buttons
  14945. * @param {array} attachTo Buttons array to attach to
  14946. * @param {object} button Button definition
  14947. * @param {boolean} inCollection true if the button is in a collection
  14948. * @private
  14949. */
  14950. _expandButton: function ( attachTo, button, inCollection, attachPoint )
  14951. {
  14952. var dt = this.s.dt;
  14953. var buttonCounter = 0;
  14954. var buttons = ! $.isArray( button ) ?
  14955. [ button ] :
  14956. button;
  14957. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14958. var conf = this._resolveExtends( buttons[i] );
  14959. if ( ! conf ) {
  14960. continue;
  14961. }
  14962. // If the configuration is an array, then expand the buttons at this
  14963. // point
  14964. if ( $.isArray( conf ) ) {
  14965. this._expandButton( attachTo, conf, inCollection, attachPoint );
  14966. continue;
  14967. }
  14968. var built = this._buildButton( conf, inCollection );
  14969. if ( ! built ) {
  14970. continue;
  14971. }
  14972. if ( attachPoint !== undefined ) {
  14973. attachTo.splice( attachPoint, 0, built );
  14974. attachPoint++;
  14975. }
  14976. else {
  14977. attachTo.push( built );
  14978. }
  14979. if ( built.conf.buttons ) {
  14980. built.collection = $('<'+this.c.dom.collection.tag+'/>');
  14981. built.conf._collection = built.collection;
  14982. this._expandButton( built.buttons, built.conf.buttons, true, attachPoint );
  14983. }
  14984. // init call is made here, rather than buildButton as it needs to
  14985. // be selectable, and for that it needs to be in the buttons array
  14986. if ( conf.init ) {
  14987. conf.init.call( dt.button( built.node ), dt, $(built.node), conf );
  14988. }
  14989. buttonCounter++;
  14990. }
  14991. },
  14992. /**
  14993. * Create an individual button
  14994. * @param {object} config Resolved button configuration
  14995. * @param {boolean} inCollection `true` if a collection button
  14996. * @return {jQuery} Created button node (jQuery)
  14997. * @private
  14998. */
  14999. _buildButton: function ( config, inCollection )
  15000. {
  15001. var buttonDom = this.c.dom.button;
  15002. var linerDom = this.c.dom.buttonLiner;
  15003. var collectionDom = this.c.dom.collection;
  15004. var dt = this.s.dt;
  15005. var text = function ( opt ) {
  15006. return typeof opt === 'function' ?
  15007. opt( dt, button, config ) :
  15008. opt;
  15009. };
  15010. if ( inCollection && collectionDom.button ) {
  15011. buttonDom = collectionDom.button;
  15012. }
  15013. if ( inCollection && collectionDom.buttonLiner ) {
  15014. linerDom = collectionDom.buttonLiner;
  15015. }
  15016. // Make sure that the button is available based on whatever requirements
  15017. // it has. For example, Flash buttons require Flash
  15018. if ( config.available && ! config.available( dt, config ) ) {
  15019. return false;
  15020. }
  15021. var action = function ( e, dt, button, config ) {
  15022. config.action.call( dt.button( button ), e, dt, button, config );
  15023. $(dt.table().node()).triggerHandler( 'buttons-action.dt', [
  15024. dt.button( button ), dt, button, config
  15025. ] );
  15026. };
  15027. var tag = config.tag || buttonDom.tag;
  15028. var clickBlurs = config.clickBlurs === undefined ? true : config.clickBlurs
  15029. var button = $('<'+tag+'/>')
  15030. .addClass( buttonDom.className )
  15031. .attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
  15032. .attr( 'aria-controls', this.s.dt.table().node().id )
  15033. .on( 'click.dtb', function (e) {
  15034. e.preventDefault();
  15035. if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
  15036. action( e, dt, button, config );
  15037. }
  15038. if( clickBlurs ) {
  15039. button.blur();
  15040. }
  15041. } )
  15042. .on( 'keyup.dtb', function (e) {
  15043. if ( e.keyCode === 13 ) {
  15044. if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
  15045. action( e, dt, button, config );
  15046. }
  15047. }
  15048. } );
  15049. // Make `a` tags act like a link
  15050. if ( tag.toLowerCase() === 'a' ) {
  15051. button.attr( 'href', '#' );
  15052. }
  15053. // Button tags should have `type=button` so they don't have any default behaviour
  15054. if ( tag.toLowerCase() === 'button' ) {
  15055. button.attr( 'type', 'button' );
  15056. }
  15057. if ( linerDom.tag ) {
  15058. var liner = $('<'+linerDom.tag+'/>')
  15059. .html( text( config.text ) )
  15060. .addClass( linerDom.className );
  15061. if ( linerDom.tag.toLowerCase() === 'a' ) {
  15062. liner.attr( 'href', '#' );
  15063. }
  15064. button.append( liner );
  15065. }
  15066. else {
  15067. button.html( text( config.text ) );
  15068. }
  15069. if ( config.enabled === false ) {
  15070. button.addClass( buttonDom.disabled );
  15071. }
  15072. if ( config.className ) {
  15073. button.addClass( config.className );
  15074. }
  15075. if ( config.titleAttr ) {
  15076. button.attr( 'title', text( config.titleAttr ) );
  15077. }
  15078. if ( config.attr ) {
  15079. button.attr( config.attr );
  15080. }
  15081. if ( ! config.namespace ) {
  15082. config.namespace = '.dt-button-'+(_buttonCounter++);
  15083. }
  15084. var buttonContainer = this.c.dom.buttonContainer;
  15085. var inserter;
  15086. if ( buttonContainer && buttonContainer.tag ) {
  15087. inserter = $('<'+buttonContainer.tag+'/>')
  15088. .addClass( buttonContainer.className )
  15089. .append( button );
  15090. }
  15091. else {
  15092. inserter = button;
  15093. }
  15094. this._addKey( config );
  15095. // Style integration callback for DOM manipulation
  15096. // Note that this is _not_ documented. It is currently
  15097. // for style integration only
  15098. if( this.c.buttonCreated ) {
  15099. inserter = this.c.buttonCreated( config, inserter );
  15100. }
  15101. return {
  15102. conf: config,
  15103. node: button.get(0),
  15104. inserter: inserter,
  15105. buttons: [],
  15106. inCollection: inCollection,
  15107. collection: null
  15108. };
  15109. },
  15110. /**
  15111. * Get the button object from a node (recursive)
  15112. * @param {node} node Button node
  15113. * @param {array} [buttons] Button array, uses base if not defined
  15114. * @return {object} Button object
  15115. * @private
  15116. */
  15117. _nodeToButton: function ( node, buttons )
  15118. {
  15119. if ( ! buttons ) {
  15120. buttons = this.s.buttons;
  15121. }
  15122. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  15123. if ( buttons[i].node === node ) {
  15124. return buttons[i];
  15125. }
  15126. if ( buttons[i].buttons.length ) {
  15127. var ret = this._nodeToButton( node, buttons[i].buttons );
  15128. if ( ret ) {
  15129. return ret;
  15130. }
  15131. }
  15132. }
  15133. },
  15134. /**
  15135. * Get container array for a button from a button node (recursive)
  15136. * @param {node} node Button node
  15137. * @param {array} [buttons] Button array, uses base if not defined
  15138. * @return {array} Button's host array
  15139. * @private
  15140. */
  15141. _nodeToHost: function ( node, buttons )
  15142. {
  15143. if ( ! buttons ) {
  15144. buttons = this.s.buttons;
  15145. }
  15146. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  15147. if ( buttons[i].node === node ) {
  15148. return buttons;
  15149. }
  15150. if ( buttons[i].buttons.length ) {
  15151. var ret = this._nodeToHost( node, buttons[i].buttons );
  15152. if ( ret ) {
  15153. return ret;
  15154. }
  15155. }
  15156. }
  15157. },
  15158. /**
  15159. * Handle a key press - determine if any button's key configured matches
  15160. * what was typed and trigger the action if so.
  15161. * @param {string} character The character pressed
  15162. * @param {object} e Key event that triggered this call
  15163. * @private
  15164. */
  15165. _keypress: function ( character, e )
  15166. {
  15167. // Check if this button press already activated on another instance of Buttons
  15168. if ( e._buttonsHandled ) {
  15169. return;
  15170. }
  15171. var run = function ( conf, node ) {
  15172. if ( ! conf.key ) {
  15173. return;
  15174. }
  15175. if ( conf.key === character ) {
  15176. e._buttonsHandled = true;
  15177. $(node).click();
  15178. }
  15179. else if ( $.isPlainObject( conf.key ) ) {
  15180. if ( conf.key.key !== character ) {
  15181. return;
  15182. }
  15183. if ( conf.key.shiftKey && ! e.shiftKey ) {
  15184. return;
  15185. }
  15186. if ( conf.key.altKey && ! e.altKey ) {
  15187. return;
  15188. }
  15189. if ( conf.key.ctrlKey && ! e.ctrlKey ) {
  15190. return;
  15191. }
  15192. if ( conf.key.metaKey && ! e.metaKey ) {
  15193. return;
  15194. }
  15195. // Made it this far - it is good
  15196. e._buttonsHandled = true;
  15197. $(node).click();
  15198. }
  15199. };
  15200. var recurse = function ( a ) {
  15201. for ( var i=0, ien=a.length ; i<ien ; i++ ) {
  15202. run( a[i].conf, a[i].node );
  15203. if ( a[i].buttons.length ) {
  15204. recurse( a[i].buttons );
  15205. }
  15206. }
  15207. };
  15208. recurse( this.s.buttons );
  15209. },
  15210. /**
  15211. * Remove a key from the key listener for this instance (to be used when a
  15212. * button is removed)
  15213. * @param {object} conf Button configuration
  15214. * @private
  15215. */
  15216. _removeKey: function ( conf )
  15217. {
  15218. if ( conf.key ) {
  15219. var character = $.isPlainObject( conf.key ) ?
  15220. conf.key.key :
  15221. conf.key;
  15222. // Remove only one character, as multiple buttons could have the
  15223. // same listening key
  15224. var a = this.s.listenKeys.split('');
  15225. var idx = $.inArray( character, a );
  15226. a.splice( idx, 1 );
  15227. this.s.listenKeys = a.join('');
  15228. }
  15229. },
  15230. /**
  15231. * Resolve a button configuration
  15232. * @param {string|function|object} conf Button config to resolve
  15233. * @return {object} Button configuration
  15234. * @private
  15235. */
  15236. _resolveExtends: function ( conf )
  15237. {
  15238. var dt = this.s.dt;
  15239. var i, ien;
  15240. var toConfObject = function ( base ) {
  15241. var loop = 0;
  15242. // Loop until we have resolved to a button configuration, or an
  15243. // array of button configurations (which will be iterated
  15244. // separately)
  15245. while ( ! $.isPlainObject(base) && ! $.isArray(base) ) {
  15246. if ( base === undefined ) {
  15247. return;
  15248. }
  15249. if ( typeof base === 'function' ) {
  15250. base = base( dt, conf );
  15251. if ( ! base ) {
  15252. return false;
  15253. }
  15254. }
  15255. else if ( typeof base === 'string' ) {
  15256. if ( ! _dtButtons[ base ] ) {
  15257. throw 'Unknown button type: '+base;
  15258. }
  15259. base = _dtButtons[ base ];
  15260. }
  15261. loop++;
  15262. if ( loop > 30 ) {
  15263. // Protect against misconfiguration killing the browser
  15264. throw 'Buttons: Too many iterations';
  15265. }
  15266. }
  15267. return $.isArray( base ) ?
  15268. base :
  15269. $.extend( {}, base );
  15270. };
  15271. conf = toConfObject( conf );
  15272. while ( conf && conf.extend ) {
  15273. // Use `toConfObject` in case the button definition being extended
  15274. // is itself a string or a function
  15275. if ( ! _dtButtons[ conf.extend ] ) {
  15276. throw 'Cannot extend unknown button type: '+conf.extend;
  15277. }
  15278. var objArray = toConfObject( _dtButtons[ conf.extend ] );
  15279. if ( $.isArray( objArray ) ) {
  15280. return objArray;
  15281. }
  15282. else if ( ! objArray ) {
  15283. // This is a little brutal as it might be possible to have a
  15284. // valid button without the extend, but if there is no extend
  15285. // then the host button would be acting in an undefined state
  15286. return false;
  15287. }
  15288. // Stash the current class name
  15289. var originalClassName = objArray.className;
  15290. conf = $.extend( {}, objArray, conf );
  15291. // The extend will have overwritten the original class name if the
  15292. // `conf` object also assigned a class, but we want to concatenate
  15293. // them so they are list that is combined from all extended buttons
  15294. if ( originalClassName && conf.className !== originalClassName ) {
  15295. conf.className = originalClassName+' '+conf.className;
  15296. }
  15297. // Buttons to be added to a collection -gives the ability to define
  15298. // if buttons should be added to the start or end of a collection
  15299. var postfixButtons = conf.postfixButtons;
  15300. if ( postfixButtons ) {
  15301. if ( ! conf.buttons ) {
  15302. conf.buttons = [];
  15303. }
  15304. for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {
  15305. conf.buttons.push( postfixButtons[i] );
  15306. }
  15307. conf.postfixButtons = null;
  15308. }
  15309. var prefixButtons = conf.prefixButtons;
  15310. if ( prefixButtons ) {
  15311. if ( ! conf.buttons ) {
  15312. conf.buttons = [];
  15313. }
  15314. for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {
  15315. conf.buttons.splice( i, 0, prefixButtons[i] );
  15316. }
  15317. conf.prefixButtons = null;
  15318. }
  15319. // Although we want the `conf` object to overwrite almost all of
  15320. // the properties of the object being extended, the `extend`
  15321. // property should come from the object being extended
  15322. conf.extend = objArray.extend;
  15323. }
  15324. return conf;
  15325. },
  15326. /**
  15327. * Display (and replace if there is an existing one) a popover attached to a button
  15328. * @param {string|node} content Content to show
  15329. * @param {DataTable.Api} hostButton DT API instance of the button
  15330. * @param {object} inOpts Options (see object below for all options)
  15331. */
  15332. _popover: function ( content, hostButton, inOpts ) {
  15333. var dt = hostButton;
  15334. var buttonsSettings = this.c;
  15335. var options = $.extend( {
  15336. align: 'button-left', // button-right, dt-container
  15337. autoClose: false,
  15338. background: true,
  15339. backgroundClassName: 'dt-button-background',
  15340. contentClassName: buttonsSettings.dom.collection.className,
  15341. collectionLayout: '',
  15342. collectionTitle: '',
  15343. dropup: false,
  15344. fade: 400,
  15345. rightAlignClassName: 'dt-button-right',
  15346. tag: buttonsSettings.dom.collection.tag
  15347. }, inOpts );
  15348. var hostNode = hostButton.node();
  15349. var close = function () {
  15350. $('.dt-button-collection').stop().fadeOut( options.fade, function () {
  15351. $(this).detach();
  15352. } );
  15353. $(dt.buttons( '[aria-haspopup="true"][aria-expanded="true"]' ).nodes())
  15354. .attr('aria-expanded', 'false');
  15355. $('div.dt-button-background').off( 'click.dtb-collection' );
  15356. Buttons.background( false, options.backgroundClassName, options.fade, hostNode );
  15357. $('body').off( '.dtb-collection' );
  15358. dt.off( 'buttons-action.b-internal' );
  15359. };
  15360. if (content === false) {
  15361. close();
  15362. }
  15363. var existingExpanded = $(dt.buttons( '[aria-haspopup="true"][aria-expanded="true"]' ).nodes());
  15364. if ( existingExpanded.length ) {
  15365. hostNode = existingExpanded.eq(0);
  15366. close();
  15367. }
  15368. var display = $('<div/>')
  15369. .addClass('dt-button-collection')
  15370. .addClass(options.collectionLayout)
  15371. .css('display', 'none');
  15372. content = $(content)
  15373. .addClass(options.contentClassName)
  15374. .attr('role', 'menu')
  15375. .appendTo(display);
  15376. hostNode.attr( 'aria-expanded', 'true' );
  15377. if ( hostNode.parents('body')[0] !== document.body ) {
  15378. hostNode = document.body.lastChild;
  15379. }
  15380. if ( options.collectionTitle ) {
  15381. display.prepend('<div class="dt-button-collection-title">'+options.collectionTitle+'</div>');
  15382. }
  15383. display
  15384. .insertAfter( hostNode )
  15385. .fadeIn( options.fade );
  15386. var tableContainer = $( hostButton.table().container() );
  15387. var position = display.css( 'position' );
  15388. if ( options.align === 'dt-container' ) {
  15389. hostNode = hostNode.parent();
  15390. display.css('width', tableContainer.width());
  15391. }
  15392. if ( position === 'absolute' ) {
  15393. var hostPosition = hostNode.position();
  15394. display.css( {
  15395. top: hostPosition.top + hostNode.outerHeight(),
  15396. left: hostPosition.left
  15397. } );
  15398. // calculate overflow when positioned beneath
  15399. var collectionHeight = display.outerHeight();
  15400. var collectionWidth = display.outerWidth();
  15401. var tableBottom = tableContainer.offset().top + tableContainer.height();
  15402. var listBottom = hostPosition.top + hostNode.outerHeight() + collectionHeight;
  15403. var bottomOverflow = listBottom - tableBottom;
  15404. // calculate overflow when positioned above
  15405. var listTop = hostPosition.top - collectionHeight;
  15406. var tableTop = tableContainer.offset().top;
  15407. var topOverflow = tableTop - listTop;
  15408. // if bottom overflow is larger, move to the top because it fits better, or if dropup is requested
  15409. var moveTop = hostPosition.top - collectionHeight - 5;
  15410. if ( (bottomOverflow > topOverflow || options.dropup) && -moveTop < tableTop ) {
  15411. display.css( 'top', moveTop);
  15412. }
  15413. // Right alignment is enabled on a class, e.g. bootstrap:
  15414. // $.fn.dataTable.Buttons.defaults.dom.collection.className += " dropdown-menu-right";
  15415. if ( display.hasClass( options.rightAlignClassName ) || options.align === 'button-right' ) {
  15416. display.css( 'left', hostPosition.left + hostNode.outerWidth() - collectionWidth );
  15417. }
  15418. // Right alignment in table container
  15419. var listRight = hostPosition.left + collectionWidth;
  15420. var tableRight = tableContainer.offset().left + tableContainer.width();
  15421. if ( listRight > tableRight ) {
  15422. display.css( 'left', hostPosition.left - ( listRight - tableRight ) );
  15423. }
  15424. // Right alignment to window
  15425. var listOffsetRight = hostNode.offset().left + collectionWidth;
  15426. if ( listOffsetRight > $(window).width() ) {
  15427. display.css( 'left', hostPosition.left - (listOffsetRight-$(window).width()) );
  15428. }
  15429. }
  15430. else {
  15431. // Fix position - centre on screen
  15432. var top = display.height() / 2;
  15433. if ( top > $(window).height() / 2 ) {
  15434. top = $(window).height() / 2;
  15435. }
  15436. display.css( 'marginTop', top*-1 );
  15437. }
  15438. if ( options.background ) {
  15439. Buttons.background( true, options.backgroundClassName, options.fade, hostNode );
  15440. }
  15441. // This is bonkers, but if we don't have a click listener on the
  15442. // background element, iOS Safari will ignore the body click
  15443. // listener below. An empty function here is all that is
  15444. // required to make it work...
  15445. $('div.dt-button-background').on( 'click.dtb-collection', function () {} );
  15446. $('body')
  15447. .on( 'click.dtb-collection', function (e) {
  15448. // andSelf is deprecated in jQ1.8, but we want 1.7 compat
  15449. var back = $.fn.addBack ? 'addBack' : 'andSelf';
  15450. if ( ! $(e.target).parents()[back]().filter( content ).length ) {
  15451. close();
  15452. }
  15453. } )
  15454. .on( 'keyup.dtb-collection', function (e) {
  15455. if ( e.keyCode === 27 ) {
  15456. close();
  15457. }
  15458. } );
  15459. if ( options.autoClose ) {
  15460. setTimeout( function () {
  15461. dt.on( 'buttons-action.b-internal', function (e, btn, dt, node) {
  15462. if ( node[0] === hostNode[0] ) {
  15463. return;
  15464. }
  15465. close();
  15466. } );
  15467. }, 0);
  15468. }
  15469. }
  15470. } );
  15471. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15472. * Statics
  15473. */
  15474. /**
  15475. * Show / hide a background layer behind a collection
  15476. * @param {boolean} Flag to indicate if the background should be shown or
  15477. * hidden
  15478. * @param {string} Class to assign to the background
  15479. * @static
  15480. */
  15481. Buttons.background = function ( show, className, fade, insertPoint ) {
  15482. if ( fade === undefined ) {
  15483. fade = 400;
  15484. }
  15485. if ( ! insertPoint ) {
  15486. insertPoint = document.body;
  15487. }
  15488. if ( show ) {
  15489. $('<div/>')
  15490. .addClass( className )
  15491. .css( 'display', 'none' )
  15492. .insertAfter( insertPoint )
  15493. .stop()
  15494. .fadeIn( fade );
  15495. }
  15496. else {
  15497. $('div.'+className)
  15498. .stop()
  15499. .fadeOut( fade, function () {
  15500. $(this)
  15501. .removeClass( className )
  15502. .remove();
  15503. } );
  15504. }
  15505. };
  15506. /**
  15507. * Instance selector - select Buttons instances based on an instance selector
  15508. * value from the buttons assigned to a DataTable. This is only useful if
  15509. * multiple instances are attached to a DataTable.
  15510. * @param {string|int|array} Instance selector - see `instance-selector`
  15511. * documentation on the DataTables site
  15512. * @param {array} Button instance array that was attached to the DataTables
  15513. * settings object
  15514. * @return {array} Buttons instances
  15515. * @static
  15516. */
  15517. Buttons.instanceSelector = function ( group, buttons )
  15518. {
  15519. if ( group === undefined || group === null ) {
  15520. return $.map( buttons, function ( v ) {
  15521. return v.inst;
  15522. } );
  15523. }
  15524. var ret = [];
  15525. var names = $.map( buttons, function ( v ) {
  15526. return v.name;
  15527. } );
  15528. // Flatten the group selector into an array of single options
  15529. var process = function ( input ) {
  15530. if ( $.isArray( input ) ) {
  15531. for ( var i=0, ien=input.length ; i<ien ; i++ ) {
  15532. process( input[i] );
  15533. }
  15534. return;
  15535. }
  15536. if ( typeof input === 'string' ) {
  15537. if ( input.indexOf( ',' ) !== -1 ) {
  15538. // String selector, list of names
  15539. process( input.split(',') );
  15540. }
  15541. else {
  15542. // String selector individual name
  15543. var idx = $.inArray( $.trim(input), names );
  15544. if ( idx !== -1 ) {
  15545. ret.push( buttons[ idx ].inst );
  15546. }
  15547. }
  15548. }
  15549. else if ( typeof input === 'number' ) {
  15550. // Index selector
  15551. ret.push( buttons[ input ].inst );
  15552. }
  15553. };
  15554. process( group );
  15555. return ret;
  15556. };
  15557. /**
  15558. * Button selector - select one or more buttons from a selector input so some
  15559. * operation can be performed on them.
  15560. * @param {array} Button instances array that the selector should operate on
  15561. * @param {string|int|node|jQuery|array} Button selector - see
  15562. * `button-selector` documentation on the DataTables site
  15563. * @return {array} Array of objects containing `inst` and `idx` properties of
  15564. * the selected buttons so you know which instance each button belongs to.
  15565. * @static
  15566. */
  15567. Buttons.buttonSelector = function ( insts, selector )
  15568. {
  15569. var ret = [];
  15570. var nodeBuilder = function ( a, buttons, baseIdx ) {
  15571. var button;
  15572. var idx;
  15573. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  15574. button = buttons[i];
  15575. if ( button ) {
  15576. idx = baseIdx !== undefined ?
  15577. baseIdx+i :
  15578. i+'';
  15579. a.push( {
  15580. node: button.node,
  15581. name: button.conf.name,
  15582. idx: idx
  15583. } );
  15584. if ( button.buttons ) {
  15585. nodeBuilder( a, button.buttons, idx+'-' );
  15586. }
  15587. }
  15588. }
  15589. };
  15590. var run = function ( selector, inst ) {
  15591. var i, ien;
  15592. var buttons = [];
  15593. nodeBuilder( buttons, inst.s.buttons );
  15594. var nodes = $.map( buttons, function (v) {
  15595. return v.node;
  15596. } );
  15597. if ( $.isArray( selector ) || selector instanceof $ ) {
  15598. for ( i=0, ien=selector.length ; i<ien ; i++ ) {
  15599. run( selector[i], inst );
  15600. }
  15601. return;
  15602. }
  15603. if ( selector === null || selector === undefined || selector === '*' ) {
  15604. // Select all
  15605. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  15606. ret.push( {
  15607. inst: inst,
  15608. node: buttons[i].node
  15609. } );
  15610. }
  15611. }
  15612. else if ( typeof selector === 'number' ) {
  15613. // Main button index selector
  15614. ret.push( {
  15615. inst: inst,
  15616. node: inst.s.buttons[ selector ].node
  15617. } );
  15618. }
  15619. else if ( typeof selector === 'string' ) {
  15620. if ( selector.indexOf( ',' ) !== -1 ) {
  15621. // Split
  15622. var a = selector.split(',');
  15623. for ( i=0, ien=a.length ; i<ien ; i++ ) {
  15624. run( $.trim(a[i]), inst );
  15625. }
  15626. }
  15627. else if ( selector.match( /^\d+(\-\d+)*$/ ) ) {
  15628. // Sub-button index selector
  15629. var indexes = $.map( buttons, function (v) {
  15630. return v.idx;
  15631. } );
  15632. ret.push( {
  15633. inst: inst,
  15634. node: buttons[ $.inArray( selector, indexes ) ].node
  15635. } );
  15636. }
  15637. else if ( selector.indexOf( ':name' ) !== -1 ) {
  15638. // Button name selector
  15639. var name = selector.replace( ':name', '' );
  15640. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  15641. if ( buttons[i].name === name ) {
  15642. ret.push( {
  15643. inst: inst,
  15644. node: buttons[i].node
  15645. } );
  15646. }
  15647. }
  15648. }
  15649. else {
  15650. // jQuery selector on the nodes
  15651. $( nodes ).filter( selector ).each( function () {
  15652. ret.push( {
  15653. inst: inst,
  15654. node: this
  15655. } );
  15656. } );
  15657. }
  15658. }
  15659. else if ( typeof selector === 'object' && selector.nodeName ) {
  15660. // Node selector
  15661. var idx = $.inArray( selector, nodes );
  15662. if ( idx !== -1 ) {
  15663. ret.push( {
  15664. inst: inst,
  15665. node: nodes[ idx ]
  15666. } );
  15667. }
  15668. }
  15669. };
  15670. for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
  15671. var inst = insts[i];
  15672. run( selector, inst );
  15673. }
  15674. return ret;
  15675. };
  15676. /**
  15677. * Buttons defaults. For full documentation, please refer to the docs/option
  15678. * directory or the DataTables site.
  15679. * @type {Object}
  15680. * @static
  15681. */
  15682. Buttons.defaults = {
  15683. buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],
  15684. name: 'main',
  15685. tabIndex: 0,
  15686. dom: {
  15687. container: {
  15688. tag: 'div',
  15689. className: 'dt-buttons'
  15690. },
  15691. collection: {
  15692. tag: 'div',
  15693. className: ''
  15694. },
  15695. button: {
  15696. // Flash buttons will not work with `<button>` in IE - it has to be `<a>`
  15697. tag: 'ActiveXObject' in window ?
  15698. 'a' :
  15699. 'button',
  15700. className: 'dt-button',
  15701. active: 'active',
  15702. disabled: 'disabled'
  15703. },
  15704. buttonLiner: {
  15705. tag: 'span',
  15706. className: ''
  15707. }
  15708. }
  15709. };
  15710. /**
  15711. * Version information
  15712. * @type {string}
  15713. * @static
  15714. */
  15715. Buttons.version = '1.6.1';
  15716. $.extend( _dtButtons, {
  15717. collection: {
  15718. text: function ( dt ) {
  15719. return dt.i18n( 'buttons.collection', 'Collection' );
  15720. },
  15721. className: 'buttons-collection',
  15722. init: function ( dt, button, config ) {
  15723. button.attr( 'aria-expanded', false );
  15724. },
  15725. action: function ( e, dt, button, config ) {
  15726. e.stopPropagation();
  15727. if ( config._collection.parents('body').length ) {
  15728. this.popover(false, config);
  15729. }
  15730. else {
  15731. this.popover(config._collection, config);
  15732. }
  15733. },
  15734. attr: {
  15735. 'aria-haspopup': true
  15736. }
  15737. // Also the popover options, defined in Buttons.popover
  15738. },
  15739. copy: function ( dt, conf ) {
  15740. if ( _dtButtons.copyHtml5 ) {
  15741. return 'copyHtml5';
  15742. }
  15743. if ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {
  15744. return 'copyFlash';
  15745. }
  15746. },
  15747. csv: function ( dt, conf ) {
  15748. // Common option that will use the HTML5 or Flash export buttons
  15749. if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {
  15750. return 'csvHtml5';
  15751. }
  15752. if ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {
  15753. return 'csvFlash';
  15754. }
  15755. },
  15756. excel: function ( dt, conf ) {
  15757. // Common option that will use the HTML5 or Flash export buttons
  15758. if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {
  15759. return 'excelHtml5';
  15760. }
  15761. if ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {
  15762. return 'excelFlash';
  15763. }
  15764. },
  15765. pdf: function ( dt, conf ) {
  15766. // Common option that will use the HTML5 or Flash export buttons
  15767. if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {
  15768. return 'pdfHtml5';
  15769. }
  15770. if ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {
  15771. return 'pdfFlash';
  15772. }
  15773. },
  15774. pageLength: function ( dt ) {
  15775. var lengthMenu = dt.settings()[0].aLengthMenu;
  15776. var vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;
  15777. var lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;
  15778. var text = function ( dt ) {
  15779. return dt.i18n( 'buttons.pageLength', {
  15780. "-1": 'Show all rows',
  15781. _: 'Show %d rows'
  15782. }, dt.page.len() );
  15783. };
  15784. return {
  15785. extend: 'collection',
  15786. text: text,
  15787. className: 'buttons-page-length',
  15788. autoClose: true,
  15789. buttons: $.map( vals, function ( val, i ) {
  15790. return {
  15791. text: lang[i],
  15792. className: 'button-page-length',
  15793. action: function ( e, dt ) {
  15794. dt.page.len( val ).draw();
  15795. },
  15796. init: function ( dt, node, conf ) {
  15797. var that = this;
  15798. var fn = function () {
  15799. that.active( dt.page.len() === val );
  15800. };
  15801. dt.on( 'length.dt'+conf.namespace, fn );
  15802. fn();
  15803. },
  15804. destroy: function ( dt, node, conf ) {
  15805. dt.off( 'length.dt'+conf.namespace );
  15806. }
  15807. };
  15808. } ),
  15809. init: function ( dt, node, conf ) {
  15810. var that = this;
  15811. dt.on( 'length.dt'+conf.namespace, function () {
  15812. that.text( conf.text );
  15813. } );
  15814. },
  15815. destroy: function ( dt, node, conf ) {
  15816. dt.off( 'length.dt'+conf.namespace );
  15817. }
  15818. };
  15819. }
  15820. } );
  15821. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15822. * DataTables API
  15823. *
  15824. * For complete documentation, please refer to the docs/api directory or the
  15825. * DataTables site
  15826. */
  15827. // Buttons group and individual button selector
  15828. DataTable.Api.register( 'buttons()', function ( group, selector ) {
  15829. // Argument shifting
  15830. if ( selector === undefined ) {
  15831. selector = group;
  15832. group = undefined;
  15833. }
  15834. this.selector.buttonGroup = group;
  15835. var res = this.iterator( true, 'table', function ( ctx ) {
  15836. if ( ctx._buttons ) {
  15837. return Buttons.buttonSelector(
  15838. Buttons.instanceSelector( group, ctx._buttons ),
  15839. selector
  15840. );
  15841. }
  15842. }, true );
  15843. res._groupSelector = group;
  15844. return res;
  15845. } );
  15846. // Individual button selector
  15847. DataTable.Api.register( 'button()', function ( group, selector ) {
  15848. // just run buttons() and truncate
  15849. var buttons = this.buttons( group, selector );
  15850. if ( buttons.length > 1 ) {
  15851. buttons.splice( 1, buttons.length );
  15852. }
  15853. return buttons;
  15854. } );
  15855. // Active buttons
  15856. DataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {
  15857. if ( flag === undefined ) {
  15858. return this.map( function ( set ) {
  15859. return set.inst.active( set.node );
  15860. } );
  15861. }
  15862. return this.each( function ( set ) {
  15863. set.inst.active( set.node, flag );
  15864. } );
  15865. } );
  15866. // Get / set button action
  15867. DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {
  15868. if ( action === undefined ) {
  15869. return this.map( function ( set ) {
  15870. return set.inst.action( set.node );
  15871. } );
  15872. }
  15873. return this.each( function ( set ) {
  15874. set.inst.action( set.node, action );
  15875. } );
  15876. } );
  15877. // Enable / disable buttons
  15878. DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {
  15879. return this.each( function ( set ) {
  15880. set.inst.enable( set.node, flag );
  15881. } );
  15882. } );
  15883. // Disable buttons
  15884. DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {
  15885. return this.each( function ( set ) {
  15886. set.inst.disable( set.node );
  15887. } );
  15888. } );
  15889. // Get button nodes
  15890. DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {
  15891. var jq = $();
  15892. // jQuery will automatically reduce duplicates to a single entry
  15893. $( this.each( function ( set ) {
  15894. jq = jq.add( set.inst.node( set.node ) );
  15895. } ) );
  15896. return jq;
  15897. } );
  15898. // Get / set button processing state
  15899. DataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {
  15900. if ( flag === undefined ) {
  15901. return this.map( function ( set ) {
  15902. return set.inst.processing( set.node );
  15903. } );
  15904. }
  15905. return this.each( function ( set ) {
  15906. set.inst.processing( set.node, flag );
  15907. } );
  15908. } );
  15909. // Get / set button text (i.e. the button labels)
  15910. DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
  15911. if ( label === undefined ) {
  15912. return this.map( function ( set ) {
  15913. return set.inst.text( set.node );
  15914. } );
  15915. }
  15916. return this.each( function ( set ) {
  15917. set.inst.text( set.node, label );
  15918. } );
  15919. } );
  15920. // Trigger a button's action
  15921. DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {
  15922. return this.each( function ( set ) {
  15923. set.inst.node( set.node ).trigger( 'click' );
  15924. } );
  15925. } );
  15926. // Button resolver to the popover
  15927. DataTable.Api.register( 'button().popover()', function (content, options) {
  15928. return this.map( function ( set ) {
  15929. return set.inst._popover( content, this.button(this[0].node), options );
  15930. } );
  15931. } );
  15932. // Get the container elements
  15933. DataTable.Api.register( 'buttons().containers()', function () {
  15934. var jq = $();
  15935. var groupSelector = this._groupSelector;
  15936. // We need to use the group selector directly, since if there are no buttons
  15937. // the result set will be empty
  15938. this.iterator( true, 'table', function ( ctx ) {
  15939. if ( ctx._buttons ) {
  15940. var insts = Buttons.instanceSelector( groupSelector, ctx._buttons );
  15941. for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
  15942. jq = jq.add( insts[i].container() );
  15943. }
  15944. }
  15945. } );
  15946. return jq;
  15947. } );
  15948. DataTable.Api.register( 'buttons().container()', function () {
  15949. // API level of nesting is `buttons()` so we can zip into the containers method
  15950. return this.containers().eq(0);
  15951. } );
  15952. // Add a new button
  15953. DataTable.Api.register( 'button().add()', function ( idx, conf ) {
  15954. var ctx = this.context;
  15955. // Don't use `this` as it could be empty - select the instances directly
  15956. if ( ctx.length ) {
  15957. var inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons );
  15958. if ( inst.length ) {
  15959. inst[0].add( conf, idx );
  15960. }
  15961. }
  15962. return this.button( this._groupSelector, idx );
  15963. } );
  15964. // Destroy the button sets selected
  15965. DataTable.Api.register( 'buttons().destroy()', function () {
  15966. this.pluck( 'inst' ).unique().each( function ( inst ) {
  15967. inst.destroy();
  15968. } );
  15969. return this;
  15970. } );
  15971. // Remove a button
  15972. DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {
  15973. this.each( function ( set ) {
  15974. set.inst.remove( set.node );
  15975. } );
  15976. return this;
  15977. } );
  15978. // Information box that can be used by buttons
  15979. var _infoTimer;
  15980. DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
  15981. var that = this;
  15982. if ( title === false ) {
  15983. this.off('destroy.btn-info');
  15984. $('#datatables_buttons_info').fadeOut( function () {
  15985. $(this).remove();
  15986. } );
  15987. clearTimeout( _infoTimer );
  15988. _infoTimer = null;
  15989. return this;
  15990. }
  15991. if ( _infoTimer ) {
  15992. clearTimeout( _infoTimer );
  15993. }
  15994. if ( $('#datatables_buttons_info').length ) {
  15995. $('#datatables_buttons_info').remove();
  15996. }
  15997. title = title ? '<h2>'+title+'</h2>' : '';
  15998. $('<div id="datatables_buttons_info" class="dt-button-info"/>')
  15999. .html( title )
  16000. .append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )
  16001. .css( 'display', 'none' )
  16002. .appendTo( 'body' )
  16003. .fadeIn();
  16004. if ( time !== undefined && time !== 0 ) {
  16005. _infoTimer = setTimeout( function () {
  16006. that.buttons.info( false );
  16007. }, time );
  16008. }
  16009. this.on('destroy.btn-info', function () {
  16010. that.buttons.info(false);
  16011. });
  16012. return this;
  16013. } );
  16014. // Get data from the table for export - this is common to a number of plug-in
  16015. // buttons so it is included in the Buttons core library
  16016. DataTable.Api.register( 'buttons.exportData()', function ( options ) {
  16017. if ( this.context.length ) {
  16018. return _exportData( new DataTable.Api( this.context[0] ), options );
  16019. }
  16020. } );
  16021. // Get information about the export that is common to many of the export data
  16022. // types (DRY)
  16023. DataTable.Api.register( 'buttons.exportInfo()', function ( conf ) {
  16024. if ( ! conf ) {
  16025. conf = {};
  16026. }
  16027. return {
  16028. filename: _filename( conf ),
  16029. title: _title( conf ),
  16030. messageTop: _message(this, conf.message || conf.messageTop, 'top'),
  16031. messageBottom: _message(this, conf.messageBottom, 'bottom')
  16032. };
  16033. } );
  16034. /**
  16035. * Get the file name for an exported file.
  16036. *
  16037. * @param {object} config Button configuration
  16038. * @param {boolean} incExtension Include the file name extension
  16039. */
  16040. var _filename = function ( config )
  16041. {
  16042. // Backwards compatibility
  16043. var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ?
  16044. config.title :
  16045. config.filename;
  16046. if ( typeof filename === 'function' ) {
  16047. filename = filename();
  16048. }
  16049. if ( filename === undefined || filename === null ) {
  16050. return null;
  16051. }
  16052. if ( filename.indexOf( '*' ) !== -1 ) {
  16053. filename = $.trim( filename.replace( '*', $('head > title').text() ) );
  16054. }
  16055. // Strip characters which the OS will object to
  16056. filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
  16057. var extension = _stringOrFunction( config.extension );
  16058. if ( ! extension ) {
  16059. extension = '';
  16060. }
  16061. return filename + extension;
  16062. };
  16063. /**
  16064. * Simply utility method to allow parameters to be given as a function
  16065. *
  16066. * @param {undefined|string|function} option Option
  16067. * @return {null|string} Resolved value
  16068. */
  16069. var _stringOrFunction = function ( option )
  16070. {
  16071. if ( option === null || option === undefined ) {
  16072. return null;
  16073. }
  16074. else if ( typeof option === 'function' ) {
  16075. return option();
  16076. }
  16077. return option;
  16078. };
  16079. /**
  16080. * Get the title for an exported file.
  16081. *
  16082. * @param {object} config Button configuration
  16083. */
  16084. var _title = function ( config )
  16085. {
  16086. var title = _stringOrFunction( config.title );
  16087. return title === null ?
  16088. null : title.indexOf( '*' ) !== -1 ?
  16089. title.replace( '*', $('head > title').text() || 'Exported data' ) :
  16090. title;
  16091. };
  16092. var _message = function ( dt, option, position )
  16093. {
  16094. var message = _stringOrFunction( option );
  16095. if ( message === null ) {
  16096. return null;
  16097. }
  16098. var caption = $('caption', dt.table().container()).eq(0);
  16099. if ( message === '*' ) {
  16100. var side = caption.css( 'caption-side' );
  16101. if ( side !== position ) {
  16102. return null;
  16103. }
  16104. return caption.length ?
  16105. caption.text() :
  16106. '';
  16107. }
  16108. return message;
  16109. };
  16110. var _exportTextarea = $('<textarea/>')[0];
  16111. var _exportData = function ( dt, inOpts )
  16112. {
  16113. var config = $.extend( true, {}, {
  16114. rows: null,
  16115. columns: '',
  16116. modifier: {
  16117. search: 'applied',
  16118. order: 'applied'
  16119. },
  16120. orthogonal: 'display',
  16121. stripHtml: true,
  16122. stripNewlines: true,
  16123. decodeEntities: true,
  16124. trim: true,
  16125. format: {
  16126. header: function ( d ) {
  16127. return strip( d );
  16128. },
  16129. footer: function ( d ) {
  16130. return strip( d );
  16131. },
  16132. body: function ( d ) {
  16133. return strip( d );
  16134. }
  16135. },
  16136. customizeData: null
  16137. }, inOpts );
  16138. var strip = function ( str ) {
  16139. if ( typeof str !== 'string' ) {
  16140. return str;
  16141. }
  16142. // Always remove script tags
  16143. str = str.replace( /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '' );
  16144. // Always remove comments
  16145. str = str.replace( /<!\-\-.*?\-\->/g, '' );
  16146. if ( config.stripHtml ) {
  16147. str = str.replace( /<[^>]*>/g, '' );
  16148. }
  16149. if ( config.trim ) {
  16150. str = str.replace( /^\s+|\s+$/g, '' );
  16151. }
  16152. if ( config.stripNewlines ) {
  16153. str = str.replace( /\n/g, ' ' );
  16154. }
  16155. if ( config.decodeEntities ) {
  16156. _exportTextarea.innerHTML = str;
  16157. str = _exportTextarea.value;
  16158. }
  16159. return str;
  16160. };
  16161. var header = dt.columns( config.columns ).indexes().map( function (idx) {
  16162. var el = dt.column( idx ).header();
  16163. return config.format.header( el.innerHTML, idx, el );
  16164. } ).toArray();
  16165. var footer = dt.table().footer() ?
  16166. dt.columns( config.columns ).indexes().map( function (idx) {
  16167. var el = dt.column( idx ).footer();
  16168. return config.format.footer( el ? el.innerHTML : '', idx, el );
  16169. } ).toArray() :
  16170. null;
  16171. // If Select is available on this table, and any rows are selected, limit the export
  16172. // to the selected rows. If no rows are selected, all rows will be exported. Specify
  16173. // a `selected` modifier to control directly.
  16174. var modifier = $.extend( {}, config.modifier );
  16175. if ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) {
  16176. if ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) {
  16177. $.extend( modifier, { selected: true } )
  16178. }
  16179. }
  16180. var rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray();
  16181. var selectedCells = dt.cells( rowIndexes, config.columns );
  16182. var cells = selectedCells
  16183. .render( config.orthogonal )
  16184. .toArray();
  16185. var cellNodes = selectedCells
  16186. .nodes()
  16187. .toArray();
  16188. var columns = header.length;
  16189. var rows = columns > 0 ? cells.length / columns : 0;
  16190. var body = [];
  16191. var cellCounter = 0;
  16192. for ( var i=0, ien=rows ; i<ien ; i++ ) {
  16193. var row = [ columns ];
  16194. for ( var j=0 ; j<columns ; j++ ) {
  16195. row[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] );
  16196. cellCounter++;
  16197. }
  16198. body[i] = row;
  16199. }
  16200. var data = {
  16201. header: header,
  16202. footer: footer,
  16203. body: body
  16204. };
  16205. if ( config.customizeData ) {
  16206. config.customizeData( data );
  16207. }
  16208. return data;
  16209. };
  16210. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16211. * DataTables interface
  16212. */
  16213. // Attach to DataTables objects for global access
  16214. $.fn.dataTable.Buttons = Buttons;
  16215. $.fn.DataTable.Buttons = Buttons;
  16216. // DataTables creation - check if the buttons have been defined for this table,
  16217. // they will have been if the `B` option was used in `dom`, otherwise we should
  16218. // create the buttons instance here so they can be inserted into the document
  16219. // using the API. Listen for `init` for compatibility with pre 1.10.10, but to
  16220. // be removed in future.
  16221. $(document).on( 'init.dt plugin-init.dt', function (e, settings) {
  16222. if ( e.namespace !== 'dt' ) {
  16223. return;
  16224. }
  16225. var opts = settings.oInit.buttons || DataTable.defaults.buttons;
  16226. if ( opts && ! settings._buttons ) {
  16227. new Buttons( settings, opts ).container();
  16228. }
  16229. } );
  16230. function _init ( settings ) {
  16231. var api = new DataTable.Api( settings );
  16232. var opts = api.init().buttons || DataTable.defaults.buttons;
  16233. return new Buttons( api, opts ).container();
  16234. }
  16235. // DataTables `dom` feature option
  16236. DataTable.ext.feature.push( {
  16237. fnInit: _init,
  16238. cFeature: "B"
  16239. } );
  16240. // DataTables 2 layout feature
  16241. if ( DataTable.ext.features ) {
  16242. DataTable.ext.features.register( 'buttons', _init );
  16243. }
  16244. return Buttons;
  16245. }));
  16246. /*! Bootstrap integration for DataTables' Buttons
  16247. * ©2016 SpryMedia Ltd - datatables.net/license
  16248. */
  16249. (function( factory ){
  16250. if ( typeof define === 'function' && define.amd ) {
  16251. // AMD
  16252. define( ['jquery', 'datatables.net-bs4', 'datatables.net-buttons'], function ( $ ) {
  16253. return factory( $, window, document );
  16254. } );
  16255. }
  16256. else if ( typeof exports === 'object' ) {
  16257. // CommonJS
  16258. module.exports = function (root, $) {
  16259. if ( ! root ) {
  16260. root = window;
  16261. }
  16262. if ( ! $ || ! $.fn.dataTable ) {
  16263. $ = require('datatables.net-bs4')(root, $).$;
  16264. }
  16265. if ( ! $.fn.dataTable.Buttons ) {
  16266. require('datatables.net-buttons')(root, $);
  16267. }
  16268. return factory( $, root, root.document );
  16269. };
  16270. }
  16271. else {
  16272. // Browser
  16273. factory( jQuery, window, document );
  16274. }
  16275. }(function( $, window, document, undefined ) {
  16276. 'use strict';
  16277. var DataTable = $.fn.dataTable;
  16278. $.extend( true, DataTable.Buttons.defaults, {
  16279. dom: {
  16280. container: {
  16281. className: 'dt-buttons btn-group flex-wrap'
  16282. },
  16283. button: {
  16284. className: 'btn btn-secondary'
  16285. },
  16286. collection: {
  16287. tag: 'div',
  16288. className: 'dropdown-menu',
  16289. button: {
  16290. tag: 'a',
  16291. className: 'dt-button dropdown-item',
  16292. active: 'active',
  16293. disabled: 'disabled'
  16294. }
  16295. }
  16296. },
  16297. buttonCreated: function ( config, button ) {
  16298. return config.buttons ?
  16299. $('<div class="btn-group"/>').append(button) :
  16300. button;
  16301. }
  16302. } );
  16303. DataTable.ext.buttons.collection.className += ' dropdown-toggle';
  16304. DataTable.ext.buttons.collection.rightAlignClassName = 'dropdown-menu-right';
  16305. return DataTable.Buttons;
  16306. }));
  16307. /*!
  16308. * HTML5 export buttons for Buttons and DataTables.
  16309. * 2016 SpryMedia Ltd - datatables.net/license
  16310. *
  16311. * FileSaver.js (1.3.3) - MIT license
  16312. * Copyright © 2016 Eli Grey - http://eligrey.com
  16313. */
  16314. (function( factory ){
  16315. if ( typeof define === 'function' && define.amd ) {
  16316. // AMD
  16317. define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
  16318. return factory( $, window, document );
  16319. } );
  16320. }
  16321. else if ( typeof exports === 'object' ) {
  16322. // CommonJS
  16323. module.exports = function (root, $, jszip, pdfmake) {
  16324. if ( ! root ) {
  16325. root = window;
  16326. }
  16327. if ( ! $ || ! $.fn.dataTable ) {
  16328. $ = require('datatables.net')(root, $).$;
  16329. }
  16330. if ( ! $.fn.dataTable.Buttons ) {
  16331. require('datatables.net-buttons')(root, $);
  16332. }
  16333. return factory( $, root, root.document, jszip, pdfmake );
  16334. };
  16335. }
  16336. else {
  16337. // Browser
  16338. factory( jQuery, window, document );
  16339. }
  16340. }(function( $, window, document, jszip, pdfmake, undefined ) {
  16341. 'use strict';
  16342. var DataTable = $.fn.dataTable;
  16343. // Allow the constructor to pass in JSZip and PDFMake from external requires.
  16344. // Otherwise, use globally defined variables, if they are available.
  16345. function _jsZip () {
  16346. return jszip || window.JSZip;
  16347. }
  16348. function _pdfMake () {
  16349. return pdfmake || window.pdfMake;
  16350. }
  16351. DataTable.Buttons.pdfMake = function (_) {
  16352. if ( ! _ ) {
  16353. return _pdfMake();
  16354. }
  16355. pdfmake = m_ake;
  16356. }
  16357. DataTable.Buttons.jszip = function (_) {
  16358. if ( ! _ ) {
  16359. return _jsZip();
  16360. }
  16361. jszip = _;
  16362. }
  16363. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16364. * FileSaver.js dependency
  16365. */
  16366. /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
  16367. var _saveAs = (function(view) {
  16368. "use strict";
  16369. // IE <10 is explicitly unsupported
  16370. if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
  16371. return;
  16372. }
  16373. var
  16374. doc = view.document
  16375. // only get URL when necessary in case Blob.js hasn't overridden it yet
  16376. , get_URL = function() {
  16377. return view.URL || view.webkitURL || view;
  16378. }
  16379. , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
  16380. , can_use_save_link = "download" in save_link
  16381. , click = function(node) {
  16382. var event = new MouseEvent("click");
  16383. node.dispatchEvent(event);
  16384. }
  16385. , is_safari = /constructor/i.test(view.HTMLElement) || view.safari
  16386. , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
  16387. , throw_outside = function(ex) {
  16388. (view.setImmediate || view.setTimeout)(function() {
  16389. throw ex;
  16390. }, 0);
  16391. }
  16392. , force_saveable_type = "application/octet-stream"
  16393. // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
  16394. , arbitrary_revoke_timeout = 1000 * 40 // in ms
  16395. , revoke = function(file) {
  16396. var revoker = function() {
  16397. if (typeof file === "string") { // file is an object URL
  16398. get_URL().revokeObjectURL(file);
  16399. } else { // file is a File
  16400. file.remove();
  16401. }
  16402. };
  16403. setTimeout(revoker, arbitrary_revoke_timeout);
  16404. }
  16405. , dispatch = function(filesaver, event_types, event) {
  16406. event_types = [].concat(event_types);
  16407. var i = event_types.length;
  16408. while (i--) {
  16409. var listener = filesaver["on" + event_types[i]];
  16410. if (typeof listener === "function") {
  16411. try {
  16412. listener.call(filesaver, event || filesaver);
  16413. } catch (ex) {
  16414. throw_outside(ex);
  16415. }
  16416. }
  16417. }
  16418. }
  16419. , auto_bom = function(blob) {
  16420. // prepend BOM for UTF-8 XML and text/* types (including HTML)
  16421. // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
  16422. if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
  16423. return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
  16424. }
  16425. return blob;
  16426. }
  16427. , FileSaver = function(blob, name, no_auto_bom) {
  16428. if (!no_auto_bom) {
  16429. blob = auto_bom(blob);
  16430. }
  16431. // First try a.download, then web filesystem, then object URLs
  16432. var
  16433. filesaver = this
  16434. , type = blob.type
  16435. , force = type === force_saveable_type
  16436. , object_url
  16437. , dispatch_all = function() {
  16438. dispatch(filesaver, "writestart progress write writeend".split(" "));
  16439. }
  16440. // on any filesys errors revert to saving with object URLs
  16441. , fs_error = function() {
  16442. if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
  16443. // Safari doesn't allow downloading of blob urls
  16444. var reader = new FileReader();
  16445. reader.onloadend = function() {
  16446. var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
  16447. var popup = view.open(url, '_blank');
  16448. if(!popup) view.location.href = url;
  16449. url=undefined; // release reference before dispatching
  16450. filesaver.readyState = filesaver.DONE;
  16451. dispatch_all();
  16452. };
  16453. reader.readAsDataURL(blob);
  16454. filesaver.readyState = filesaver.INIT;
  16455. return;
  16456. }
  16457. // don't create more object URLs than needed
  16458. if (!object_url) {
  16459. object_url = get_URL().createObjectURL(blob);
  16460. }
  16461. if (force) {
  16462. view.location.href = object_url;
  16463. } else {
  16464. var opened = view.open(object_url, "_blank");
  16465. if (!opened) {
  16466. // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
  16467. view.location.href = object_url;
  16468. }
  16469. }
  16470. filesaver.readyState = filesaver.DONE;
  16471. dispatch_all();
  16472. revoke(object_url);
  16473. }
  16474. ;
  16475. filesaver.readyState = filesaver.INIT;
  16476. if (can_use_save_link) {
  16477. object_url = get_URL().createObjectURL(blob);
  16478. setTimeout(function() {
  16479. save_link.href = object_url;
  16480. save_link.download = name;
  16481. click(save_link);
  16482. dispatch_all();
  16483. revoke(object_url);
  16484. filesaver.readyState = filesaver.DONE;
  16485. });
  16486. return;
  16487. }
  16488. fs_error();
  16489. }
  16490. , FS_proto = FileSaver.prototype
  16491. , saveAs = function(blob, name, no_auto_bom) {
  16492. return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
  16493. }
  16494. ;
  16495. // IE 10+ (native saveAs)
  16496. if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
  16497. return function(blob, name, no_auto_bom) {
  16498. name = name || blob.name || "download";
  16499. if (!no_auto_bom) {
  16500. blob = auto_bom(blob);
  16501. }
  16502. return navigator.msSaveOrOpenBlob(blob, name);
  16503. };
  16504. }
  16505. FS_proto.abort = function(){};
  16506. FS_proto.readyState = FS_proto.INIT = 0;
  16507. FS_proto.WRITING = 1;
  16508. FS_proto.DONE = 2;
  16509. FS_proto.error =
  16510. FS_proto.onwritestart =
  16511. FS_proto.onprogress =
  16512. FS_proto.onwrite =
  16513. FS_proto.onabort =
  16514. FS_proto.onerror =
  16515. FS_proto.onwriteend =
  16516. null;
  16517. return saveAs;
  16518. }(
  16519. typeof self !== "undefined" && self
  16520. || typeof window !== "undefined" && window
  16521. || this.content
  16522. ));
  16523. // Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons`
  16524. // since this file can be loaded before Button's core!
  16525. DataTable.fileSave = _saveAs;
  16526. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16527. * Local (private) functions
  16528. */
  16529. /**
  16530. * Get the sheet name for Excel exports.
  16531. *
  16532. * @param {object} config Button configuration
  16533. */
  16534. var _sheetname = function ( config )
  16535. {
  16536. var sheetName = 'Sheet1';
  16537. if ( config.sheetName ) {
  16538. sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
  16539. }
  16540. return sheetName;
  16541. };
  16542. /**
  16543. * Get the newline character(s)
  16544. *
  16545. * @param {object} config Button configuration
  16546. * @return {string} Newline character
  16547. */
  16548. var _newLine = function ( config )
  16549. {
  16550. return config.newline ?
  16551. config.newline :
  16552. navigator.userAgent.match(/Windows/) ?
  16553. '\r\n' :
  16554. '\n';
  16555. };
  16556. /**
  16557. * Combine the data from the `buttons.exportData` method into a string that
  16558. * will be used in the export file.
  16559. *
  16560. * @param {DataTable.Api} dt DataTables API instance
  16561. * @param {object} config Button configuration
  16562. * @return {object} The data to export
  16563. */
  16564. var _exportData = function ( dt, config )
  16565. {
  16566. var newLine = _newLine( config );
  16567. var data = dt.buttons.exportData( config.exportOptions );
  16568. var boundary = config.fieldBoundary;
  16569. var separator = config.fieldSeparator;
  16570. var reBoundary = new RegExp( boundary, 'g' );
  16571. var escapeChar = config.escapeChar !== undefined ?
  16572. config.escapeChar :
  16573. '\\';
  16574. var join = function ( a ) {
  16575. var s = '';
  16576. // If there is a field boundary, then we might need to escape it in
  16577. // the source data
  16578. for ( var i=0, ien=a.length ; i<ien ; i++ ) {
  16579. if ( i > 0 ) {
  16580. s += separator;
  16581. }
  16582. s += boundary ?
  16583. boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :
  16584. a[i];
  16585. }
  16586. return s;
  16587. };
  16588. var header = config.header ? join( data.header )+newLine : '';
  16589. var footer = config.footer && data.footer ? newLine+join( data.footer ) : '';
  16590. var body = [];
  16591. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  16592. body.push( join( data.body[i] ) );
  16593. }
  16594. return {
  16595. str: header + body.join( newLine ) + footer,
  16596. rows: body.length
  16597. };
  16598. };
  16599. /**
  16600. * Older versions of Safari (prior to tech preview 18) don't support the
  16601. * download option required.
  16602. *
  16603. * @return {Boolean} `true` if old Safari
  16604. */
  16605. var _isDuffSafari = function ()
  16606. {
  16607. var safari = navigator.userAgent.indexOf('Safari') !== -1 &&
  16608. navigator.userAgent.indexOf('Chrome') === -1 &&
  16609. navigator.userAgent.indexOf('Opera') === -1;
  16610. if ( ! safari ) {
  16611. return false;
  16612. }
  16613. var version = navigator.userAgent.match( /AppleWebKit\/(\d+\.\d+)/ );
  16614. if ( version && version.length > 1 && version[1]*1 < 603.1 ) {
  16615. return true;
  16616. }
  16617. return false;
  16618. };
  16619. /**
  16620. * Convert from numeric position to letter for column names in Excel
  16621. * @param {int} n Column number
  16622. * @return {string} Column letter(s) name
  16623. */
  16624. function createCellPos( n ){
  16625. var ordA = 'A'.charCodeAt(0);
  16626. var ordZ = 'Z'.charCodeAt(0);
  16627. var len = ordZ - ordA + 1;
  16628. var s = "";
  16629. while( n >= 0 ) {
  16630. s = String.fromCharCode(n % len + ordA) + s;
  16631. n = Math.floor(n / len) - 1;
  16632. }
  16633. return s;
  16634. }
  16635. try {
  16636. var _serialiser = new XMLSerializer();
  16637. var _ieExcel;
  16638. }
  16639. catch (t) {}
  16640. /**
  16641. * Recursively add XML files from an object's structure to a ZIP file. This
  16642. * allows the XSLX file to be easily defined with an object's structure matching
  16643. * the files structure.
  16644. *
  16645. * @param {JSZip} zip ZIP package
  16646. * @param {object} obj Object to add (recursive)
  16647. */
  16648. function _addToZip( zip, obj ) {
  16649. if ( _ieExcel === undefined ) {
  16650. // Detect if we are dealing with IE's _awful_ serialiser by seeing if it
  16651. // drop attributes
  16652. _ieExcel = _serialiser
  16653. .serializeToString(
  16654. $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )
  16655. )
  16656. .indexOf( 'xmlns:r' ) === -1;
  16657. }
  16658. $.each( obj, function ( name, val ) {
  16659. if ( $.isPlainObject( val ) ) {
  16660. var newDir = zip.folder( name );
  16661. _addToZip( newDir, val );
  16662. }
  16663. else {
  16664. if ( _ieExcel ) {
  16665. // IE's XML serialiser will drop some name space attributes from
  16666. // from the root node, so we need to save them. Do this by
  16667. // replacing the namespace nodes with a regular attribute that
  16668. // we convert back when serialised. Edge does not have this
  16669. // issue
  16670. var worksheet = val.childNodes[0];
  16671. var i, ien;
  16672. var attrs = [];
  16673. for ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {
  16674. var attrName = worksheet.attributes[i].nodeName;
  16675. var attrValue = worksheet.attributes[i].nodeValue;
  16676. if ( attrName.indexOf( ':' ) !== -1 ) {
  16677. attrs.push( { name: attrName, value: attrValue } );
  16678. worksheet.removeAttribute( attrName );
  16679. }
  16680. }
  16681. for ( i=0, ien=attrs.length ; i<ien ; i++ ) {
  16682. var attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );
  16683. attr.value = attrs[i].value;
  16684. worksheet.setAttributeNode( attr );
  16685. }
  16686. }
  16687. var str = _serialiser.serializeToString(val);
  16688. // Fix IE's XML
  16689. if ( _ieExcel ) {
  16690. // IE doesn't include the XML declaration
  16691. if ( str.indexOf( '<?xml' ) === -1 ) {
  16692. str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+str;
  16693. }
  16694. // Return namespace attributes to being as such
  16695. str = str.replace( /_dt_b_namespace_token_/g, ':' );
  16696. // Remove testing name space that IE puts into the space preserve attr
  16697. str = str.replace( /xmlns:NS[\d]+="" NS[\d]+:/g, '' );
  16698. }
  16699. // Safari, IE and Edge will put empty name space attributes onto
  16700. // various elements making them useless. This strips them out
  16701. str = str.replace( /<([^<>]*?) xmlns=""([^<>]*?)>/g, '<$1 $2>' );
  16702. zip.file( name, str );
  16703. }
  16704. } );
  16705. }
  16706. /**
  16707. * Create an XML node and add any children, attributes, etc without needing to
  16708. * be verbose in the DOM.
  16709. *
  16710. * @param {object} doc XML document
  16711. * @param {string} nodeName Node name
  16712. * @param {object} opts Options - can be `attr` (attributes), `children`
  16713. * (child nodes) and `text` (text content)
  16714. * @return {node} Created node
  16715. */
  16716. function _createNode( doc, nodeName, opts ) {
  16717. var tempNode = doc.createElement( nodeName );
  16718. if ( opts ) {
  16719. if ( opts.attr ) {
  16720. $(tempNode).attr( opts.attr );
  16721. }
  16722. if ( opts.children ) {
  16723. $.each( opts.children, function ( key, value ) {
  16724. tempNode.appendChild( value );
  16725. } );
  16726. }
  16727. if ( opts.text !== null && opts.text !== undefined ) {
  16728. tempNode.appendChild( doc.createTextNode( opts.text ) );
  16729. }
  16730. }
  16731. return tempNode;
  16732. }
  16733. /**
  16734. * Get the width for an Excel column based on the contents of that column
  16735. * @param {object} data Data for export
  16736. * @param {int} col Column index
  16737. * @return {int} Column width
  16738. */
  16739. function _excelColWidth( data, col ) {
  16740. var max = data.header[col].length;
  16741. var len, lineSplit, str;
  16742. if ( data.footer && data.footer[col].length > max ) {
  16743. max = data.footer[col].length;
  16744. }
  16745. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  16746. var point = data.body[i][col];
  16747. str = point !== null && point !== undefined ?
  16748. point.toString() :
  16749. '';
  16750. // If there is a newline character, workout the width of the column
  16751. // based on the longest line in the string
  16752. if ( str.indexOf('\n') !== -1 ) {
  16753. lineSplit = str.split('\n');
  16754. lineSplit.sort( function (a, b) {
  16755. return b.length - a.length;
  16756. } );
  16757. len = lineSplit[0].length;
  16758. }
  16759. else {
  16760. len = str.length;
  16761. }
  16762. if ( len > max ) {
  16763. max = len;
  16764. }
  16765. // Max width rather than having potentially massive column widths
  16766. if ( max > 40 ) {
  16767. return 54; // 40 * 1.35
  16768. }
  16769. }
  16770. max *= 1.35;
  16771. // And a min width
  16772. return max > 6 ? max : 6;
  16773. }
  16774. // Excel - Pre-defined strings to build a basic XLSX file
  16775. var excelStrings = {
  16776. "_rels/.rels":
  16777. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  16778. '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
  16779. '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'+
  16780. '</Relationships>',
  16781. "xl/_rels/workbook.xml.rels":
  16782. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  16783. '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
  16784. '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'+
  16785. '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'+
  16786. '</Relationships>',
  16787. "[Content_Types].xml":
  16788. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  16789. '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'+
  16790. '<Default Extension="xml" ContentType="application/xml" />'+
  16791. '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />'+
  16792. '<Default Extension="jpeg" ContentType="image/jpeg" />'+
  16793. '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />'+
  16794. '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />'+
  16795. '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />'+
  16796. '</Types>',
  16797. "xl/workbook.xml":
  16798. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  16799. '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'+
  16800. '<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>'+
  16801. '<workbookPr showInkAnnotation="0" autoCompressPictures="0"/>'+
  16802. '<bookViews>'+
  16803. '<workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>'+
  16804. '</bookViews>'+
  16805. '<sheets>'+
  16806. '<sheet name="Sheet1" sheetId="1" r:id="rId1"/>'+
  16807. '</sheets>'+
  16808. '<definedNames/>'+
  16809. '</workbook>',
  16810. "xl/worksheets/sheet1.xml":
  16811. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  16812. '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+
  16813. '<sheetData/>'+
  16814. '<mergeCells count="0"/>'+
  16815. '</worksheet>',
  16816. "xl/styles.xml":
  16817. '<?xml version="1.0" encoding="UTF-8"?>'+
  16818. '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+
  16819. '<numFmts count="6">'+
  16820. '<numFmt numFmtId="164" formatCode="#,##0.00_-\ [$$-45C]"/>'+
  16821. '<numFmt numFmtId="165" formatCode="&quot;£&quot;#,##0.00"/>'+
  16822. '<numFmt numFmtId="166" formatCode="[$€-2]\ #,##0.00"/>'+
  16823. '<numFmt numFmtId="167" formatCode="0.0%"/>'+
  16824. '<numFmt numFmtId="168" formatCode="#,##0;(#,##0)"/>'+
  16825. '<numFmt numFmtId="169" formatCode="#,##0.00;(#,##0.00)"/>'+
  16826. '</numFmts>'+
  16827. '<fonts count="5" x14ac:knownFonts="1">'+
  16828. '<font>'+
  16829. '<sz val="11" />'+
  16830. '<name val="Calibri" />'+
  16831. '</font>'+
  16832. '<font>'+
  16833. '<sz val="11" />'+
  16834. '<name val="Calibri" />'+
  16835. '<color rgb="FFFFFFFF" />'+
  16836. '</font>'+
  16837. '<font>'+
  16838. '<sz val="11" />'+
  16839. '<name val="Calibri" />'+
  16840. '<b />'+
  16841. '</font>'+
  16842. '<font>'+
  16843. '<sz val="11" />'+
  16844. '<name val="Calibri" />'+
  16845. '<i />'+
  16846. '</font>'+
  16847. '<font>'+
  16848. '<sz val="11" />'+
  16849. '<name val="Calibri" />'+
  16850. '<u />'+
  16851. '</font>'+
  16852. '</fonts>'+
  16853. '<fills count="6">'+
  16854. '<fill>'+
  16855. '<patternFill patternType="none" />'+
  16856. '</fill>'+
  16857. '<fill>'+ // Excel appears to use this as a dotted background regardless of values but
  16858. '<patternFill patternType="none" />'+ // to be valid to the schema, use a patternFill
  16859. '</fill>'+
  16860. '<fill>'+
  16861. '<patternFill patternType="solid">'+
  16862. '<fgColor rgb="FFD9D9D9" />'+
  16863. '<bgColor indexed="64" />'+
  16864. '</patternFill>'+
  16865. '</fill>'+
  16866. '<fill>'+
  16867. '<patternFill patternType="solid">'+
  16868. '<fgColor rgb="FFD99795" />'+
  16869. '<bgColor indexed="64" />'+
  16870. '</patternFill>'+
  16871. '</fill>'+
  16872. '<fill>'+
  16873. '<patternFill patternType="solid">'+
  16874. '<fgColor rgb="ffc6efce" />'+
  16875. '<bgColor indexed="64" />'+
  16876. '</patternFill>'+
  16877. '</fill>'+
  16878. '<fill>'+
  16879. '<patternFill patternType="solid">'+
  16880. '<fgColor rgb="ffc6cfef" />'+
  16881. '<bgColor indexed="64" />'+
  16882. '</patternFill>'+
  16883. '</fill>'+
  16884. '</fills>'+
  16885. '<borders count="2">'+
  16886. '<border>'+
  16887. '<left />'+
  16888. '<right />'+
  16889. '<top />'+
  16890. '<bottom />'+
  16891. '<diagonal />'+
  16892. '</border>'+
  16893. '<border diagonalUp="false" diagonalDown="false">'+
  16894. '<left style="thin">'+
  16895. '<color auto="1" />'+
  16896. '</left>'+
  16897. '<right style="thin">'+
  16898. '<color auto="1" />'+
  16899. '</right>'+
  16900. '<top style="thin">'+
  16901. '<color auto="1" />'+
  16902. '</top>'+
  16903. '<bottom style="thin">'+
  16904. '<color auto="1" />'+
  16905. '</bottom>'+
  16906. '<diagonal />'+
  16907. '</border>'+
  16908. '</borders>'+
  16909. '<cellStyleXfs count="1">'+
  16910. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />'+
  16911. '</cellStyleXfs>'+
  16912. '<cellXfs count="67">'+
  16913. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16914. '<xf numFmtId="0" fontId="1" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16915. '<xf numFmtId="0" fontId="2" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16916. '<xf numFmtId="0" fontId="3" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16917. '<xf numFmtId="0" fontId="4" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16918. '<xf numFmtId="0" fontId="0" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16919. '<xf numFmtId="0" fontId="1" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16920. '<xf numFmtId="0" fontId="2" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16921. '<xf numFmtId="0" fontId="3" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16922. '<xf numFmtId="0" fontId="4" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16923. '<xf numFmtId="0" fontId="0" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16924. '<xf numFmtId="0" fontId="1" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16925. '<xf numFmtId="0" fontId="2" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16926. '<xf numFmtId="0" fontId="3" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16927. '<xf numFmtId="0" fontId="4" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16928. '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16929. '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16930. '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16931. '<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16932. '<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16933. '<xf numFmtId="0" fontId="0" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16934. '<xf numFmtId="0" fontId="1" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16935. '<xf numFmtId="0" fontId="2" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16936. '<xf numFmtId="0" fontId="3" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16937. '<xf numFmtId="0" fontId="4" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16938. '<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16939. '<xf numFmtId="0" fontId="1" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16940. '<xf numFmtId="0" fontId="2" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16941. '<xf numFmtId="0" fontId="3" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16942. '<xf numFmtId="0" fontId="4" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16943. '<xf numFmtId="0" fontId="0" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16944. '<xf numFmtId="0" fontId="1" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16945. '<xf numFmtId="0" fontId="2" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16946. '<xf numFmtId="0" fontId="3" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16947. '<xf numFmtId="0" fontId="4" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16948. '<xf numFmtId="0" fontId="0" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16949. '<xf numFmtId="0" fontId="1" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16950. '<xf numFmtId="0" fontId="2" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16951. '<xf numFmtId="0" fontId="3" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16952. '<xf numFmtId="0" fontId="4" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16953. '<xf numFmtId="0" fontId="0" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16954. '<xf numFmtId="0" fontId="1" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16955. '<xf numFmtId="0" fontId="2" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16956. '<xf numFmtId="0" fontId="3" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16957. '<xf numFmtId="0" fontId="4" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16958. '<xf numFmtId="0" fontId="0" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16959. '<xf numFmtId="0" fontId="1" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16960. '<xf numFmtId="0" fontId="2" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16961. '<xf numFmtId="0" fontId="3" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16962. '<xf numFmtId="0" fontId="4" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  16963. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  16964. '<alignment horizontal="left"/>'+
  16965. '</xf>'+
  16966. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  16967. '<alignment horizontal="center"/>'+
  16968. '</xf>'+
  16969. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  16970. '<alignment horizontal="right"/>'+
  16971. '</xf>'+
  16972. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  16973. '<alignment horizontal="fill"/>'+
  16974. '</xf>'+
  16975. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  16976. '<alignment textRotation="90"/>'+
  16977. '</xf>'+
  16978. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  16979. '<alignment wrapText="1"/>'+
  16980. '</xf>'+
  16981. '<xf numFmtId="9" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16982. '<xf numFmtId="164" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16983. '<xf numFmtId="165" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16984. '<xf numFmtId="166" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16985. '<xf numFmtId="167" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16986. '<xf numFmtId="168" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16987. '<xf numFmtId="169" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16988. '<xf numFmtId="3" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16989. '<xf numFmtId="4" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16990. '<xf numFmtId="1" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16991. '<xf numFmtId="2" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
  16992. '</cellXfs>'+
  16993. '<cellStyles count="1">'+
  16994. '<cellStyle name="Normal" xfId="0" builtinId="0" />'+
  16995. '</cellStyles>'+
  16996. '<dxfs count="0" />'+
  16997. '<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4" />'+
  16998. '</styleSheet>'
  16999. };
  17000. // Note we could use 3 `for` loops for the styles, but when gzipped there is
  17001. // virtually no difference in size, since the above can be easily compressed
  17002. // Pattern matching for special number formats. Perhaps this should be exposed
  17003. // via an API in future?
  17004. // Ref: section 3.8.30 - built in formatters in open spreadsheet
  17005. // https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf
  17006. var _excelSpecials = [
  17007. { match: /^\-?\d+\.\d%$/, style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p.
  17008. { match: /^\-?\d+\.?\d*%$/, style: 56, fmt: function (d) { return d/100; } }, // Percent
  17009. { match: /^\-?\$[\d,]+.?\d*$/, style: 57 }, // Dollars
  17010. { match: /^\-?£[\d,]+.?\d*$/, style: 58 }, // Pounds
  17011. { match: /^\-?€[\d,]+.?\d*$/, style: 59 }, // Euros
  17012. { match: /^\-?\d+$/, style: 65 }, // Numbers without thousand separators
  17013. { match: /^\-?\d+\.\d{2}$/, style: 66 }, // Numbers 2 d.p. without thousands separators
  17014. { match: /^\([\d,]+\)$/, style: 61, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets
  17015. { match: /^\([\d,]+\.\d{2}\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets - 2d.p.
  17016. { match: /^\-?[\d,]+$/, style: 63 }, // Numbers with thousand separators
  17017. { match: /^\-?[\d,]+\.\d{2}$/, style: 64 } // Numbers with 2 d.p. and thousands separators
  17018. ];
  17019. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17020. * Buttons
  17021. */
  17022. //
  17023. // Copy to clipboard
  17024. //
  17025. DataTable.ext.buttons.copyHtml5 = {
  17026. className: 'buttons-copy buttons-html5',
  17027. text: function ( dt ) {
  17028. return dt.i18n( 'buttons.copy', 'Copy' );
  17029. },
  17030. action: function ( e, dt, button, config ) {
  17031. this.processing( true );
  17032. var that = this;
  17033. var exportData = _exportData( dt, config );
  17034. var info = dt.buttons.exportInfo( config );
  17035. var newline = _newLine(config);
  17036. var output = exportData.str;
  17037. var hiddenDiv = $('<div/>')
  17038. .css( {
  17039. height: 1,
  17040. width: 1,
  17041. overflow: 'hidden',
  17042. position: 'fixed',
  17043. top: 0,
  17044. left: 0
  17045. } );
  17046. if ( info.title ) {
  17047. output = info.title + newline + newline + output;
  17048. }
  17049. if ( info.messageTop ) {
  17050. output = info.messageTop + newline + newline + output;
  17051. }
  17052. if ( info.messageBottom ) {
  17053. output = output + newline + newline + info.messageBottom;
  17054. }
  17055. if ( config.customize ) {
  17056. output = config.customize( output, config, dt );
  17057. }
  17058. var textarea = $('<textarea readonly/>')
  17059. .val( output )
  17060. .appendTo( hiddenDiv );
  17061. // For browsers that support the copy execCommand, try to use it
  17062. if ( document.queryCommandSupported('copy') ) {
  17063. hiddenDiv.appendTo( dt.table().container() );
  17064. textarea[0].focus();
  17065. textarea[0].select();
  17066. try {
  17067. var successful = document.execCommand( 'copy' );
  17068. hiddenDiv.remove();
  17069. if (successful) {
  17070. dt.buttons.info(
  17071. dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
  17072. dt.i18n( 'buttons.copySuccess', {
  17073. 1: 'Copied one row to clipboard',
  17074. _: 'Copied %d rows to clipboard'
  17075. }, exportData.rows ),
  17076. 2000
  17077. );
  17078. this.processing( false );
  17079. return;
  17080. }
  17081. }
  17082. catch (t) {}
  17083. }
  17084. // Otherwise we show the text box and instruct the user to use it
  17085. var message = $('<span>'+dt.i18n( 'buttons.copyKeys',
  17086. 'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+
  17087. 'To cancel, click this message or press escape.' )+'</span>'
  17088. )
  17089. .append( hiddenDiv );
  17090. dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );
  17091. // Select the text so when the user activates their system clipboard
  17092. // it will copy that text
  17093. textarea[0].focus();
  17094. textarea[0].select();
  17095. // Event to hide the message when the user is done
  17096. var container = $(message).closest('.dt-button-info');
  17097. var close = function () {
  17098. container.off( 'click.buttons-copy' );
  17099. $(document).off( '.buttons-copy' );
  17100. dt.buttons.info( false );
  17101. };
  17102. container.on( 'click.buttons-copy', close );
  17103. $(document)
  17104. .on( 'keydown.buttons-copy', function (e) {
  17105. if ( e.keyCode === 27 ) { // esc
  17106. close();
  17107. that.processing( false );
  17108. }
  17109. } )
  17110. .on( 'copy.buttons-copy cut.buttons-copy', function () {
  17111. close();
  17112. that.processing( false );
  17113. } );
  17114. },
  17115. exportOptions: {},
  17116. fieldSeparator: '\t',
  17117. fieldBoundary: '',
  17118. header: true,
  17119. footer: false,
  17120. title: '*',
  17121. messageTop: '*',
  17122. messageBottom: '*'
  17123. };
  17124. //
  17125. // CSV export
  17126. //
  17127. DataTable.ext.buttons.csvHtml5 = {
  17128. bom: false,
  17129. className: 'buttons-csv buttons-html5',
  17130. available: function () {
  17131. return window.FileReader !== undefined && window.Blob;
  17132. },
  17133. text: function ( dt ) {
  17134. return dt.i18n( 'buttons.csv', 'CSV' );
  17135. },
  17136. action: function ( e, dt, button, config ) {
  17137. this.processing( true );
  17138. // Set the text
  17139. var output = _exportData( dt, config ).str;
  17140. var info = dt.buttons.exportInfo(config);
  17141. var charset = config.charset;
  17142. if ( config.customize ) {
  17143. output = config.customize( output, config, dt );
  17144. }
  17145. if ( charset !== false ) {
  17146. if ( ! charset ) {
  17147. charset = document.characterSet || document.charset;
  17148. }
  17149. if ( charset ) {
  17150. charset = ';charset='+charset;
  17151. }
  17152. }
  17153. else {
  17154. charset = '';
  17155. }
  17156. if ( config.bom ) {
  17157. output = '\ufeff' + output;
  17158. }
  17159. _saveAs(
  17160. new Blob( [output], {type: 'text/csv'+charset} ),
  17161. info.filename,
  17162. true
  17163. );
  17164. this.processing( false );
  17165. },
  17166. filename: '*',
  17167. extension: '.csv',
  17168. exportOptions: {},
  17169. fieldSeparator: ',',
  17170. fieldBoundary: '"',
  17171. escapeChar: '"',
  17172. charset: null,
  17173. header: true,
  17174. footer: false
  17175. };
  17176. //
  17177. // Excel (xlsx) export
  17178. //
  17179. DataTable.ext.buttons.excelHtml5 = {
  17180. className: 'buttons-excel buttons-html5',
  17181. available: function () {
  17182. return window.FileReader !== undefined && _jsZip() !== undefined && ! _isDuffSafari() && _serialiser;
  17183. },
  17184. text: function ( dt ) {
  17185. return dt.i18n( 'buttons.excel', 'Excel' );
  17186. },
  17187. action: function ( e, dt, button, config ) {
  17188. this.processing( true );
  17189. var that = this;
  17190. var rowPos = 0;
  17191. var dataStartRow, dataEndRow;
  17192. var getXml = function ( type ) {
  17193. var str = excelStrings[ type ];
  17194. //str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' );
  17195. return $.parseXML( str );
  17196. };
  17197. var rels = getXml('xl/worksheets/sheet1.xml');
  17198. var relsGet = rels.getElementsByTagName( "sheetData" )[0];
  17199. var xlsx = {
  17200. _rels: {
  17201. ".rels": getXml('_rels/.rels')
  17202. },
  17203. xl: {
  17204. _rels: {
  17205. "workbook.xml.rels": getXml('xl/_rels/workbook.xml.rels')
  17206. },
  17207. "workbook.xml": getXml('xl/workbook.xml'),
  17208. "styles.xml": getXml('xl/styles.xml'),
  17209. "worksheets": {
  17210. "sheet1.xml": rels
  17211. }
  17212. },
  17213. "[Content_Types].xml": getXml('[Content_Types].xml')
  17214. };
  17215. var data = dt.buttons.exportData( config.exportOptions );
  17216. var currentRow, rowNode;
  17217. var addRow = function ( row ) {
  17218. currentRow = rowPos+1;
  17219. rowNode = _createNode( rels, "row", { attr: {r:currentRow} } );
  17220. for ( var i=0, ien=row.length ; i<ien ; i++ ) {
  17221. // Concat both the Cell Columns as a letter and the Row of the cell.
  17222. var cellId = createCellPos(i) + '' + currentRow;
  17223. var cell = null;
  17224. // For null, undefined of blank cell, continue so it doesn't create the _createNode
  17225. if ( row[i] === null || row[i] === undefined || row[i] === '' ) {
  17226. if ( config.createEmptyCells === true ) {
  17227. row[i] = '';
  17228. }
  17229. else {
  17230. continue;
  17231. }
  17232. }
  17233. var originalContent = row[i];
  17234. row[i] = $.trim( row[i] );
  17235. // Special number formatting options
  17236. for ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {
  17237. var special = _excelSpecials[j];
  17238. // TODO Need to provide the ability for the specials to say
  17239. // if they are returning a string, since at the moment it is
  17240. // assumed to be a number
  17241. if ( row[i].match && ! row[i].match(/^0\d+/) && row[i].match( special.match ) ) {
  17242. var val = row[i].replace(/[^\d\.\-]/g, '');
  17243. if ( special.fmt ) {
  17244. val = special.fmt( val );
  17245. }
  17246. cell = _createNode( rels, 'c', {
  17247. attr: {
  17248. r: cellId,
  17249. s: special.style
  17250. },
  17251. children: [
  17252. _createNode( rels, 'v', { text: val } )
  17253. ]
  17254. } );
  17255. break;
  17256. }
  17257. }
  17258. if ( ! cell ) {
  17259. if ( typeof row[i] === 'number' || (
  17260. row[i].match &&
  17261. row[i].match(/^-?\d+(\.\d+)?$/) &&
  17262. ! row[i].match(/^0\d+/) )
  17263. ) {
  17264. // Detect numbers - don't match numbers with leading zeros
  17265. // or a negative anywhere but the start
  17266. cell = _createNode( rels, 'c', {
  17267. attr: {
  17268. t: 'n',
  17269. r: cellId
  17270. },
  17271. children: [
  17272. _createNode( rels, 'v', { text: row[i] } )
  17273. ]
  17274. } );
  17275. }
  17276. else {
  17277. // String output - replace non standard characters for text output
  17278. var text = ! originalContent.replace ?
  17279. originalContent :
  17280. originalContent.replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
  17281. cell = _createNode( rels, 'c', {
  17282. attr: {
  17283. t: 'inlineStr',
  17284. r: cellId
  17285. },
  17286. children:{
  17287. row: _createNode( rels, 'is', {
  17288. children: {
  17289. row: _createNode( rels, 't', {
  17290. text: text,
  17291. attr: {
  17292. 'xml:space': 'preserve'
  17293. }
  17294. } )
  17295. }
  17296. } )
  17297. }
  17298. } );
  17299. }
  17300. }
  17301. rowNode.appendChild( cell );
  17302. }
  17303. relsGet.appendChild(rowNode);
  17304. rowPos++;
  17305. };
  17306. if ( config.customizeData ) {
  17307. config.customizeData( data );
  17308. }
  17309. var mergeCells = function ( row, colspan ) {
  17310. var mergeCells = $('mergeCells', rels);
  17311. mergeCells[0].appendChild( _createNode( rels, 'mergeCell', {
  17312. attr: {
  17313. ref: 'A'+row+':'+createCellPos(colspan)+row
  17314. }
  17315. } ) );
  17316. mergeCells.attr( 'count', parseFloat(mergeCells.attr( 'count' ))+1 );
  17317. $('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre
  17318. };
  17319. // Title and top messages
  17320. var exportInfo = dt.buttons.exportInfo( config );
  17321. if ( exportInfo.title ) {
  17322. addRow( [exportInfo.title], rowPos );
  17323. mergeCells( rowPos, data.header.length-1 );
  17324. }
  17325. if ( exportInfo.messageTop ) {
  17326. addRow( [exportInfo.messageTop], rowPos );
  17327. mergeCells( rowPos, data.header.length-1 );
  17328. }
  17329. // Table itself
  17330. if ( config.header ) {
  17331. addRow( data.header, rowPos );
  17332. $('row:last c', rels).attr( 's', '2' ); // bold
  17333. }
  17334. dataStartRow = rowPos;
  17335. for ( var n=0, ie=data.body.length ; n<ie ; n++ ) {
  17336. addRow( data.body[n], rowPos );
  17337. }
  17338. dataEndRow = rowPos;
  17339. if ( config.footer && data.footer ) {
  17340. addRow( data.footer, rowPos);
  17341. $('row:last c', rels).attr( 's', '2' ); // bold
  17342. }
  17343. // Below the table
  17344. if ( exportInfo.messageBottom ) {
  17345. addRow( [exportInfo.messageBottom], rowPos );
  17346. mergeCells( rowPos, data.header.length-1 );
  17347. }
  17348. // Set column widths
  17349. var cols = _createNode( rels, 'cols' );
  17350. $('worksheet', rels).prepend( cols );
  17351. for ( var i=0, ien=data.header.length ; i<ien ; i++ ) {
  17352. cols.appendChild( _createNode( rels, 'col', {
  17353. attr: {
  17354. min: i+1,
  17355. max: i+1,
  17356. width: _excelColWidth( data, i ),
  17357. customWidth: 1
  17358. }
  17359. } ) );
  17360. }
  17361. // Workbook modifications
  17362. var workbook = xlsx.xl['workbook.xml'];
  17363. $( 'sheets sheet', workbook ).attr( 'name', _sheetname( config ) );
  17364. // Auto filter for columns
  17365. if ( config.autoFilter ) {
  17366. $('mergeCells', rels).before( _createNode( rels, 'autoFilter', {
  17367. attr: {
  17368. ref: 'A'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow
  17369. }
  17370. } ) );
  17371. $('definedNames', workbook).append( _createNode( workbook, 'definedName', {
  17372. attr: {
  17373. name: '_xlnm._FilterDatabase',
  17374. localSheetId: '0',
  17375. hidden: 1
  17376. },
  17377. text: _sheetname(config)+'!$A$'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow
  17378. } ) );
  17379. }
  17380. // Let the developer customise the document if they want to
  17381. if ( config.customize ) {
  17382. config.customize( xlsx, config, dt );
  17383. }
  17384. // Excel doesn't like an empty mergeCells tag
  17385. if ( $('mergeCells', rels).children().length === 0 ) {
  17386. $('mergeCells', rels).remove();
  17387. }
  17388. var jszip = _jsZip();
  17389. var zip = new jszip();
  17390. var zipConfig = {
  17391. type: 'blob',
  17392. mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  17393. };
  17394. _addToZip( zip, xlsx );
  17395. if ( zip.generateAsync ) {
  17396. // JSZip 3+
  17397. zip
  17398. .generateAsync( zipConfig )
  17399. .then( function ( blob ) {
  17400. _saveAs( blob, exportInfo.filename );
  17401. that.processing( false );
  17402. } );
  17403. }
  17404. else {
  17405. // JSZip 2.5
  17406. _saveAs(
  17407. zip.generate( zipConfig ),
  17408. exportInfo.filename
  17409. );
  17410. this.processing( false );
  17411. }
  17412. },
  17413. filename: '*',
  17414. extension: '.xlsx',
  17415. exportOptions: {},
  17416. header: true,
  17417. footer: false,
  17418. title: '*',
  17419. messageTop: '*',
  17420. messageBottom: '*',
  17421. createEmptyCells: false,
  17422. autoFilter: false,
  17423. sheetName: ''
  17424. };
  17425. //
  17426. // PDF export - using pdfMake - http://pdfmake.org
  17427. //
  17428. DataTable.ext.buttons.pdfHtml5 = {
  17429. className: 'buttons-pdf buttons-html5',
  17430. available: function () {
  17431. return window.FileReader !== undefined && _pdfMake();
  17432. },
  17433. text: function ( dt ) {
  17434. return dt.i18n( 'buttons.pdf', 'PDF' );
  17435. },
  17436. action: function ( e, dt, button, config ) {
  17437. this.processing( true );
  17438. var that = this;
  17439. var data = dt.buttons.exportData( config.exportOptions );
  17440. var info = dt.buttons.exportInfo( config );
  17441. var rows = [];
  17442. if ( config.header ) {
  17443. rows.push( $.map( data.header, function ( d ) {
  17444. return {
  17445. text: typeof d === 'string' ? d : d+'',
  17446. style: 'tableHeader'
  17447. };
  17448. } ) );
  17449. }
  17450. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  17451. rows.push( $.map( data.body[i], function ( d ) {
  17452. if ( d === null || d === undefined ) {
  17453. d = '';
  17454. }
  17455. return {
  17456. text: typeof d === 'string' ? d : d+'',
  17457. style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'
  17458. };
  17459. } ) );
  17460. }
  17461. if ( config.footer && data.footer) {
  17462. rows.push( $.map( data.footer, function ( d ) {
  17463. return {
  17464. text: typeof d === 'string' ? d : d+'',
  17465. style: 'tableFooter'
  17466. };
  17467. } ) );
  17468. }
  17469. var doc = {
  17470. pageSize: config.pageSize,
  17471. pageOrientation: config.orientation,
  17472. content: [
  17473. {
  17474. table: {
  17475. headerRows: 1,
  17476. body: rows
  17477. },
  17478. layout: 'noBorders'
  17479. }
  17480. ],
  17481. styles: {
  17482. tableHeader: {
  17483. bold: true,
  17484. fontSize: 11,
  17485. color: 'white',
  17486. fillColor: '#2d4154',
  17487. alignment: 'center'
  17488. },
  17489. tableBodyEven: {},
  17490. tableBodyOdd: {
  17491. fillColor: '#f3f3f3'
  17492. },
  17493. tableFooter: {
  17494. bold: true,
  17495. fontSize: 11,
  17496. color: 'white',
  17497. fillColor: '#2d4154'
  17498. },
  17499. title: {
  17500. alignment: 'center',
  17501. fontSize: 15
  17502. },
  17503. message: {}
  17504. },
  17505. defaultStyle: {
  17506. fontSize: 10
  17507. }
  17508. };
  17509. if ( info.messageTop ) {
  17510. doc.content.unshift( {
  17511. text: info.messageTop,
  17512. style: 'message',
  17513. margin: [ 0, 0, 0, 12 ]
  17514. } );
  17515. }
  17516. if ( info.messageBottom ) {
  17517. doc.content.push( {
  17518. text: info.messageBottom,
  17519. style: 'message',
  17520. margin: [ 0, 0, 0, 12 ]
  17521. } );
  17522. }
  17523. if ( info.title ) {
  17524. doc.content.unshift( {
  17525. text: info.title,
  17526. style: 'title',
  17527. margin: [ 0, 0, 0, 12 ]
  17528. } );
  17529. }
  17530. if ( config.customize ) {
  17531. config.customize( doc, config, dt );
  17532. }
  17533. var pdf = _pdfMake().createPdf( doc );
  17534. if ( config.download === 'open' && ! _isDuffSafari() ) {
  17535. pdf.open();
  17536. }
  17537. else {
  17538. pdf.download( info.filename );
  17539. }
  17540. this.processing( false );
  17541. },
  17542. title: '*',
  17543. filename: '*',
  17544. extension: '.pdf',
  17545. exportOptions: {},
  17546. orientation: 'portrait',
  17547. pageSize: 'A4',
  17548. header: true,
  17549. footer: false,
  17550. messageTop: '*',
  17551. messageBottom: '*',
  17552. customize: null,
  17553. download: 'download'
  17554. };
  17555. return DataTable.Buttons;
  17556. }));
  17557. /*!
  17558. * Print button for Buttons and DataTables.
  17559. * 2016 SpryMedia Ltd - datatables.net/license
  17560. */
  17561. (function( factory ){
  17562. if ( typeof define === 'function' && define.amd ) {
  17563. // AMD
  17564. define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
  17565. return factory( $, window, document );
  17566. } );
  17567. }
  17568. else if ( typeof exports === 'object' ) {
  17569. // CommonJS
  17570. module.exports = function (root, $) {
  17571. if ( ! root ) {
  17572. root = window;
  17573. }
  17574. if ( ! $ || ! $.fn.dataTable ) {
  17575. $ = require('datatables.net')(root, $).$;
  17576. }
  17577. if ( ! $.fn.dataTable.Buttons ) {
  17578. require('datatables.net-buttons')(root, $);
  17579. }
  17580. return factory( $, root, root.document );
  17581. };
  17582. }
  17583. else {
  17584. // Browser
  17585. factory( jQuery, window, document );
  17586. }
  17587. }(function( $, window, document, undefined ) {
  17588. 'use strict';
  17589. var DataTable = $.fn.dataTable;
  17590. var _link = document.createElement( 'a' );
  17591. /**
  17592. * Clone link and style tags, taking into account the need to change the source
  17593. * path.
  17594. *
  17595. * @param {node} el Element to convert
  17596. */
  17597. var _styleToAbs = function( el ) {
  17598. var url;
  17599. var clone = $(el).clone()[0];
  17600. var linkHost;
  17601. if ( clone.nodeName.toLowerCase() === 'link' ) {
  17602. clone.href = _relToAbs( clone.href );
  17603. }
  17604. return clone.outerHTML;
  17605. };
  17606. /**
  17607. * Convert a URL from a relative to an absolute address so it will work
  17608. * correctly in the popup window which has no base URL.
  17609. *
  17610. * @param {string} href URL
  17611. */
  17612. var _relToAbs = function( href ) {
  17613. // Assign to a link on the original page so the browser will do all the
  17614. // hard work of figuring out where the file actually is
  17615. _link.href = href;
  17616. var linkHost = _link.host;
  17617. // IE doesn't have a trailing slash on the host
  17618. // Chrome has it on the pathname
  17619. if ( linkHost.indexOf('/') === -1 && _link.pathname.indexOf('/') !== 0) {
  17620. linkHost += '/';
  17621. }
  17622. return _link.protocol+"//"+linkHost+_link.pathname+_link.search;
  17623. };
  17624. DataTable.ext.buttons.print = {
  17625. className: 'buttons-print',
  17626. text: function ( dt ) {
  17627. return dt.i18n( 'buttons.print', 'Print' );
  17628. },
  17629. action: function ( e, dt, button, config ) {
  17630. var data = dt.buttons.exportData(
  17631. $.extend( {decodeEntities: false}, config.exportOptions ) // XSS protection
  17632. );
  17633. var exportInfo = dt.buttons.exportInfo( config );
  17634. var columnClasses = dt
  17635. .columns( config.exportOptions.columns )
  17636. .flatten()
  17637. .map( function (idx) {
  17638. return dt.settings()[0].aoColumns[dt.column(idx).index()].sClass;
  17639. } )
  17640. .toArray();
  17641. var addRow = function ( d, tag ) {
  17642. var str = '<tr>';
  17643. for ( var i=0, ien=d.length ; i<ien ; i++ ) {
  17644. // null and undefined aren't useful in the print output
  17645. var dataOut = d[i] === null || d[i] === undefined ?
  17646. '' :
  17647. d[i];
  17648. var classAttr = columnClasses[i] ?
  17649. 'class="'+columnClasses[i]+'"' :
  17650. '';
  17651. str += '<'+tag+' '+classAttr+'>'+dataOut+'</'+tag+'>';
  17652. }
  17653. return str + '</tr>';
  17654. };
  17655. // Construct a table for printing
  17656. var html = '<table class="'+dt.table().node().className+'">';
  17657. if ( config.header ) {
  17658. html += '<thead>'+ addRow( data.header, 'th' ) +'</thead>';
  17659. }
  17660. html += '<tbody>';
  17661. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  17662. html += addRow( data.body[i], 'td' );
  17663. }
  17664. html += '</tbody>';
  17665. if ( config.footer && data.footer ) {
  17666. html += '<tfoot>'+ addRow( data.footer, 'th' ) +'</tfoot>';
  17667. }
  17668. html += '</table>';
  17669. // Open a new window for the printable table
  17670. var win = window.open( '', '' );
  17671. win.document.close();
  17672. // Inject the title and also a copy of the style and link tags from this
  17673. // document so the table can retain its base styling. Note that we have
  17674. // to use string manipulation as IE won't allow elements to be created
  17675. // in the host document and then appended to the new window.
  17676. var head = '<title>'+exportInfo.title+'</title>';
  17677. $('style, link').each( function () {
  17678. head += _styleToAbs( this );
  17679. } );
  17680. try {
  17681. win.document.head.innerHTML = head; // Work around for Edge
  17682. }
  17683. catch (e) {
  17684. $(win.document.head).html( head ); // Old IE
  17685. }
  17686. // Inject the table and other surrounding information
  17687. win.document.body.innerHTML =
  17688. '<h1>'+exportInfo.title+'</h1>'+
  17689. '<div>'+(exportInfo.messageTop || '')+'</div>'+
  17690. html+
  17691. '<div>'+(exportInfo.messageBottom || '')+'</div>';
  17692. $(win.document.body).addClass('dt-print-view');
  17693. $('img', win.document.body).each( function ( i, img ) {
  17694. img.setAttribute( 'src', _relToAbs( img.getAttribute('src') ) );
  17695. } );
  17696. if ( config.customize ) {
  17697. config.customize( win, config, dt );
  17698. }
  17699. // Allow stylesheets time to load
  17700. var autoPrint = function () {
  17701. if ( config.autoPrint ) {
  17702. win.print(); // blocking - so close will not
  17703. win.close(); // execute until this is done
  17704. }
  17705. };
  17706. if ( navigator.userAgent.match(/Trident\/\d.\d/) ) { // IE needs to call this without a setTimeout
  17707. autoPrint();
  17708. }
  17709. else {
  17710. win.setTimeout( autoPrint, 1000 );
  17711. }
  17712. },
  17713. title: '*',
  17714. messageTop: '*',
  17715. messageBottom: '*',
  17716. exportOptions: {},
  17717. header: true,
  17718. footer: false,
  17719. autoPrint: true,
  17720. customize: null
  17721. };
  17722. return DataTable.Buttons;
  17723. }));
  17724. /*!
  17725. * Column visibility buttons for Buttons and DataTables.
  17726. * 2016 SpryMedia Ltd - datatables.net/license
  17727. */
  17728. (function( factory ){
  17729. if ( typeof define === 'function' && define.amd ) {
  17730. // AMD
  17731. define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
  17732. return factory( $, window, document );
  17733. } );
  17734. }
  17735. else if ( typeof exports === 'object' ) {
  17736. // CommonJS
  17737. module.exports = function (root, $) {
  17738. if ( ! root ) {
  17739. root = window;
  17740. }
  17741. if ( ! $ || ! $.fn.dataTable ) {
  17742. $ = require('datatables.net')(root, $).$;
  17743. }
  17744. if ( ! $.fn.dataTable.Buttons ) {
  17745. require('datatables.net-buttons')(root, $);
  17746. }
  17747. return factory( $, root, root.document );
  17748. };
  17749. }
  17750. else {
  17751. // Browser
  17752. factory( jQuery, window, document );
  17753. }
  17754. }(function( $, window, document, undefined ) {
  17755. 'use strict';
  17756. var DataTable = $.fn.dataTable;
  17757. $.extend( DataTable.ext.buttons, {
  17758. // A collection of column visibility buttons
  17759. colvis: function ( dt, conf ) {
  17760. return {
  17761. extend: 'collection',
  17762. text: function ( dt ) {
  17763. return dt.i18n( 'buttons.colvis', 'Column visibility' );
  17764. },
  17765. className: 'buttons-colvis',
  17766. buttons: [ {
  17767. extend: 'columnsToggle',
  17768. columns: conf.columns,
  17769. columnText: conf.columnText
  17770. } ]
  17771. };
  17772. },
  17773. // Selected columns with individual buttons - toggle column visibility
  17774. columnsToggle: function ( dt, conf ) {
  17775. var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {
  17776. return {
  17777. extend: 'columnToggle',
  17778. columns: idx,
  17779. columnText: conf.columnText
  17780. };
  17781. } ).toArray();
  17782. return columns;
  17783. },
  17784. // Single button to toggle column visibility
  17785. columnToggle: function ( dt, conf ) {
  17786. return {
  17787. extend: 'columnVisibility',
  17788. columns: conf.columns,
  17789. columnText: conf.columnText
  17790. };
  17791. },
  17792. // Selected columns with individual buttons - set column visibility
  17793. columnsVisibility: function ( dt, conf ) {
  17794. var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {
  17795. return {
  17796. extend: 'columnVisibility',
  17797. columns: idx,
  17798. visibility: conf.visibility,
  17799. columnText: conf.columnText
  17800. };
  17801. } ).toArray();
  17802. return columns;
  17803. },
  17804. // Single button to set column visibility
  17805. columnVisibility: {
  17806. columns: undefined, // column selector
  17807. text: function ( dt, button, conf ) {
  17808. return conf._columnText( dt, conf );
  17809. },
  17810. className: 'buttons-columnVisibility',
  17811. action: function ( e, dt, button, conf ) {
  17812. var col = dt.columns( conf.columns );
  17813. var curr = col.visible();
  17814. col.visible( conf.visibility !== undefined ?
  17815. conf.visibility :
  17816. ! (curr.length ? curr[0] : false )
  17817. );
  17818. },
  17819. init: function ( dt, button, conf ) {
  17820. var that = this;
  17821. button.attr( 'data-cv-idx', conf.columns );
  17822. dt
  17823. .on( 'column-visibility.dt'+conf.namespace, function (e, settings) {
  17824. if ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) {
  17825. that.active( dt.column( conf.columns ).visible() );
  17826. }
  17827. } )
  17828. .on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) {
  17829. if ( dt.columns( conf.columns ).count() !== 1 ) {
  17830. return;
  17831. }
  17832. // This button controls the same column index but the text for the column has
  17833. // changed
  17834. button.text( conf._columnText( dt, conf ) );
  17835. // Since its a different column, we need to check its visibility
  17836. that.active( dt.column( conf.columns ).visible() );
  17837. } );
  17838. this.active( dt.column( conf.columns ).visible() );
  17839. },
  17840. destroy: function ( dt, button, conf ) {
  17841. dt
  17842. .off( 'column-visibility.dt'+conf.namespace )
  17843. .off( 'column-reorder.dt'+conf.namespace );
  17844. },
  17845. _columnText: function ( dt, conf ) {
  17846. // Use DataTables' internal data structure until this is presented
  17847. // is a public API. The other option is to use
  17848. // `$( column(col).node() ).text()` but the node might not have been
  17849. // populated when Buttons is constructed.
  17850. var idx = dt.column( conf.columns ).index();
  17851. var title = dt.settings()[0].aoColumns[ idx ].sTitle
  17852. .replace(/\n/g," ") // remove new lines
  17853. .replace(/<br\s*\/?>/gi, " ") // replace line breaks with spaces
  17854. .replace(/<select(.*?)<\/select>/g, "") // remove select tags, including options text
  17855. .replace(/<!\-\-.*?\-\->/g, "") // strip HTML comments
  17856. .replace(/<.*?>/g, "") // strip HTML
  17857. .replace(/^\s+|\s+$/g,""); // trim
  17858. return conf.columnText ?
  17859. conf.columnText( dt, idx, title ) :
  17860. title;
  17861. }
  17862. },
  17863. colvisRestore: {
  17864. className: 'buttons-colvisRestore',
  17865. text: function ( dt ) {
  17866. return dt.i18n( 'buttons.colvisRestore', 'Restore visibility' );
  17867. },
  17868. init: function ( dt, button, conf ) {
  17869. conf._visOriginal = dt.columns().indexes().map( function ( idx ) {
  17870. return dt.column( idx ).visible();
  17871. } ).toArray();
  17872. },
  17873. action: function ( e, dt, button, conf ) {
  17874. dt.columns().every( function ( i ) {
  17875. // Take into account that ColReorder might have disrupted our
  17876. // indexes
  17877. var idx = dt.colReorder && dt.colReorder.transpose ?
  17878. dt.colReorder.transpose( i, 'toOriginal' ) :
  17879. i;
  17880. this.visible( conf._visOriginal[ idx ] );
  17881. } );
  17882. }
  17883. },
  17884. colvisGroup: {
  17885. className: 'buttons-colvisGroup',
  17886. action: function ( e, dt, button, conf ) {
  17887. dt.columns( conf.show ).visible( true, false );
  17888. dt.columns( conf.hide ).visible( false, false );
  17889. dt.columns.adjust();
  17890. },
  17891. show: [],
  17892. hide: []
  17893. }
  17894. } );
  17895. return DataTable.Buttons;
  17896. }));
  17897. /* Set the defaults for DataTables buttons */
  17898. $.extend(true, $.fn.dataTable.Buttons.defaults, {
  17899. dom: {
  17900. container: {
  17901. className: 'dt-buttons'
  17902. },
  17903. button: {
  17904. className: 'btn'
  17905. }
  17906. }
  17907. });
  17908. /* auto fill button class on popup */
  17909. $.fn.dataTable.AutoFill.classes.btn = 'btn btn-primary';
  17910. /*! ColReorder 1.5.2
  17911. * ©2010-2019 SpryMedia Ltd - datatables.net/license
  17912. */
  17913. /**
  17914. * @summary ColReorder
  17915. * @description Provide the ability to reorder columns in a DataTable
  17916. * @version 1.5.2
  17917. * @file dataTables.colReorder.js
  17918. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  17919. * @contact www.sprymedia.co.uk/contact
  17920. * @copyright Copyright 2010-2019 SpryMedia Ltd.
  17921. *
  17922. * This source file is free software, available under the following license:
  17923. * MIT license - http://datatables.net/license/mit
  17924. *
  17925. * This source file is distributed in the hope that it will be useful, but
  17926. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17927. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  17928. *
  17929. * For details please refer to: http://www.datatables.net
  17930. */
  17931. (function( factory ){
  17932. if ( typeof define === 'function' && define.amd ) {
  17933. // AMD
  17934. define( ['jquery', 'datatables.net'], function ( $ ) {
  17935. return factory( $, window, document );
  17936. } );
  17937. }
  17938. else if ( typeof exports === 'object' ) {
  17939. // CommonJS
  17940. module.exports = function (root, $) {
  17941. if ( ! root ) {
  17942. root = window;
  17943. }
  17944. if ( ! $ || ! $.fn.dataTable ) {
  17945. $ = require('datatables.net')(root, $).$;
  17946. }
  17947. return factory( $, root, root.document );
  17948. };
  17949. }
  17950. else {
  17951. // Browser
  17952. factory( jQuery, window, document );
  17953. }
  17954. }(function( $, window, document, undefined ) {
  17955. 'use strict';
  17956. var DataTable = $.fn.dataTable;
  17957. /**
  17958. * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
  17959. * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
  17960. * @method fnInvertKeyValues
  17961. * @param array aIn Array to switch around
  17962. * @returns array
  17963. */
  17964. function fnInvertKeyValues( aIn )
  17965. {
  17966. var aRet=[];
  17967. for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
  17968. {
  17969. aRet[ aIn[i] ] = i;
  17970. }
  17971. return aRet;
  17972. }
  17973. /**
  17974. * Modify an array by switching the position of two elements
  17975. * @method fnArraySwitch
  17976. * @param array aArray Array to consider, will be modified by reference (i.e. no return)
  17977. * @param int iFrom From point
  17978. * @param int iTo Insert point
  17979. * @returns void
  17980. */
  17981. function fnArraySwitch( aArray, iFrom, iTo )
  17982. {
  17983. var mStore = aArray.splice( iFrom, 1 )[0];
  17984. aArray.splice( iTo, 0, mStore );
  17985. }
  17986. /**
  17987. * Switch the positions of nodes in a parent node (note this is specifically designed for
  17988. * table rows). Note this function considers all element nodes under the parent!
  17989. * @method fnDomSwitch
  17990. * @param string sTag Tag to consider
  17991. * @param int iFrom Element to move
  17992. * @param int Point to element the element to (before this point), can be null for append
  17993. * @returns void
  17994. */
  17995. function fnDomSwitch( nParent, iFrom, iTo )
  17996. {
  17997. var anTags = [];
  17998. for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
  17999. {
  18000. if ( nParent.childNodes[i].nodeType == 1 )
  18001. {
  18002. anTags.push( nParent.childNodes[i] );
  18003. }
  18004. }
  18005. var nStore = anTags[ iFrom ];
  18006. if ( iTo !== null )
  18007. {
  18008. nParent.insertBefore( nStore, anTags[iTo] );
  18009. }
  18010. else
  18011. {
  18012. nParent.appendChild( nStore );
  18013. }
  18014. }
  18015. /**
  18016. * Plug-in for DataTables which will reorder the internal column structure by taking the column
  18017. * from one position (iFrom) and insert it into a given point (iTo).
  18018. * @method $.fn.dataTableExt.oApi.fnColReorder
  18019. * @param object oSettings DataTables settings object - automatically added by DataTables!
  18020. * @param int iFrom Take the column to be repositioned from this point
  18021. * @param int iTo and insert it into this point
  18022. * @param bool drop Indicate if the reorder is the final one (i.e. a drop)
  18023. * not a live reorder
  18024. * @param bool invalidateRows speeds up processing if false passed
  18025. * @returns void
  18026. */
  18027. $.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows )
  18028. {
  18029. var i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol;
  18030. var attrMap = function ( obj, prop, mapping ) {
  18031. if ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) {
  18032. return;
  18033. }
  18034. var a = obj[ prop ].split('.');
  18035. var num = a.shift();
  18036. if ( isNaN( num*1 ) ) {
  18037. return;
  18038. }
  18039. obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');
  18040. };
  18041. /* Sanity check in the input */
  18042. if ( iFrom == iTo )
  18043. {
  18044. /* Pointless reorder */
  18045. return;
  18046. }
  18047. if ( iFrom < 0 || iFrom >= iCols )
  18048. {
  18049. this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
  18050. return;
  18051. }
  18052. if ( iTo < 0 || iTo >= iCols )
  18053. {
  18054. this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
  18055. return;
  18056. }
  18057. /*
  18058. * Calculate the new column array index, so we have a mapping between the old and new
  18059. */
  18060. var aiMapping = [];
  18061. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  18062. {
  18063. aiMapping[i] = i;
  18064. }
  18065. fnArraySwitch( aiMapping, iFrom, iTo );
  18066. var aiInvertMapping = fnInvertKeyValues( aiMapping );
  18067. /*
  18068. * Convert all internal indexing to the new column order indexes
  18069. */
  18070. /* Sorting */
  18071. for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
  18072. {
  18073. oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
  18074. }
  18075. /* Fixed sorting */
  18076. if ( oSettings.aaSortingFixed !== null )
  18077. {
  18078. for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
  18079. {
  18080. oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
  18081. }
  18082. }
  18083. /* Data column sorting (the column which the sort for a given column should take place on) */
  18084. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  18085. {
  18086. oCol = oSettings.aoColumns[i];
  18087. for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
  18088. {
  18089. oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
  18090. }
  18091. // Update the column indexes
  18092. oCol.idx = aiInvertMapping[ oCol.idx ];
  18093. }
  18094. // Update 1.10 optimised sort class removal variable
  18095. $.each( oSettings.aLastSort, function (i, val) {
  18096. oSettings.aLastSort[i].src = aiInvertMapping[ val.src ];
  18097. } );
  18098. /* Update the Get and Set functions for each column */
  18099. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  18100. {
  18101. oCol = oSettings.aoColumns[i];
  18102. if ( typeof oCol.mData == 'number' ) {
  18103. oCol.mData = aiInvertMapping[ oCol.mData ];
  18104. }
  18105. else if ( $.isPlainObject( oCol.mData ) ) {
  18106. // HTML5 data sourced
  18107. attrMap( oCol.mData, '_', aiInvertMapping );
  18108. attrMap( oCol.mData, 'filter', aiInvertMapping );
  18109. attrMap( oCol.mData, 'sort', aiInvertMapping );
  18110. attrMap( oCol.mData, 'type', aiInvertMapping );
  18111. }
  18112. }
  18113. /*
  18114. * Move the DOM elements
  18115. */
  18116. if ( oSettings.aoColumns[iFrom].bVisible )
  18117. {
  18118. /* Calculate the current visible index and the point to insert the node before. The insert
  18119. * before needs to take into account that there might not be an element to insert before,
  18120. * in which case it will be null, and an appendChild should be used
  18121. */
  18122. var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
  18123. var iInsertBeforeIndex = null;
  18124. i = iTo < iFrom ? iTo : iTo + 1;
  18125. while ( iInsertBeforeIndex === null && i < iCols )
  18126. {
  18127. iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
  18128. i++;
  18129. }
  18130. /* Header */
  18131. nTrs = oSettings.nTHead.getElementsByTagName('tr');
  18132. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  18133. {
  18134. fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
  18135. }
  18136. /* Footer */
  18137. if ( oSettings.nTFoot !== null )
  18138. {
  18139. nTrs = oSettings.nTFoot.getElementsByTagName('tr');
  18140. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  18141. {
  18142. fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
  18143. }
  18144. }
  18145. /* Body */
  18146. for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
  18147. {
  18148. if ( oSettings.aoData[i].nTr !== null )
  18149. {
  18150. fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
  18151. }
  18152. }
  18153. }
  18154. /*
  18155. * Move the internal array elements
  18156. */
  18157. /* Columns */
  18158. fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
  18159. // regenerate the get / set functions
  18160. for ( i=0, iLen=iCols ; i<iLen ; i++ ) {
  18161. oSettings.oApi._fnColumnOptions( oSettings, i, {} );
  18162. }
  18163. /* Search columns */
  18164. fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
  18165. /* Array array - internal data anodes cache */
  18166. for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
  18167. {
  18168. var data = oSettings.aoData[i];
  18169. var cells = data.anCells;
  18170. if ( cells ) {
  18171. fnArraySwitch( cells, iFrom, iTo );
  18172. // Longer term, should this be moved into the DataTables' invalidate
  18173. // methods?
  18174. for ( j=0, jen=cells.length ; j<jen ; j++ ) {
  18175. if ( cells[j] && cells[j]._DT_CellIndex ) {
  18176. cells[j]._DT_CellIndex.column = j;
  18177. }
  18178. }
  18179. }
  18180. // For DOM sourced data, the invalidate will reread the cell into
  18181. // the data array, but for data sources as an array, they need to
  18182. // be flipped
  18183. if ( data.src !== 'dom' && $.isArray( data._aData ) ) {
  18184. fnArraySwitch( data._aData, iFrom, iTo );
  18185. }
  18186. }
  18187. /* Reposition the header elements in the header layout array */
  18188. for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
  18189. {
  18190. fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
  18191. }
  18192. if ( oSettings.aoFooter !== null )
  18193. {
  18194. for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
  18195. {
  18196. fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
  18197. }
  18198. }
  18199. if ( invalidateRows || invalidateRows === undefined )
  18200. {
  18201. $.fn.dataTable.Api( oSettings ).rows().invalidate();
  18202. }
  18203. /*
  18204. * Update DataTables' event handlers
  18205. */
  18206. /* Sort listener */
  18207. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  18208. {
  18209. $(oSettings.aoColumns[i].nTh).off('.DT');
  18210. this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
  18211. }
  18212. /* Fire an event so other plug-ins can update */
  18213. $(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, {
  18214. from: iFrom,
  18215. to: iTo,
  18216. mapping: aiInvertMapping,
  18217. drop: drop,
  18218. // Old style parameters for compatibility
  18219. iFrom: iFrom,
  18220. iTo: iTo,
  18221. aiInvertMapping: aiInvertMapping
  18222. } ] );
  18223. };
  18224. /**
  18225. * ColReorder provides column visibility control for DataTables
  18226. * @class ColReorder
  18227. * @constructor
  18228. * @param {object} dt DataTables settings object
  18229. * @param {object} opts ColReorder options
  18230. */
  18231. var ColReorder = function( dt, opts )
  18232. {
  18233. var settings = new $.fn.dataTable.Api( dt ).settings()[0];
  18234. // Ensure that we can't initialise on the same table twice
  18235. if ( settings._colReorder ) {
  18236. return settings._colReorder;
  18237. }
  18238. // Allow the options to be a boolean for defaults
  18239. if ( opts === true ) {
  18240. opts = {};
  18241. }
  18242. // Convert from camelCase to Hungarian, just as DataTables does
  18243. var camelToHungarian = $.fn.dataTable.camelToHungarian;
  18244. if ( camelToHungarian ) {
  18245. camelToHungarian( ColReorder.defaults, ColReorder.defaults, true );
  18246. camelToHungarian( ColReorder.defaults, opts || {} );
  18247. }
  18248. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18249. * Public class variables
  18250. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  18251. /**
  18252. * @namespace Settings object which contains customisable information for ColReorder instance
  18253. */
  18254. this.s = {
  18255. /**
  18256. * DataTables settings object
  18257. * @property dt
  18258. * @type Object
  18259. * @default null
  18260. */
  18261. "dt": null,
  18262. /**
  18263. * Enable flag
  18264. * @property dt
  18265. * @type Object
  18266. * @default null
  18267. */
  18268. "enable": null,
  18269. /**
  18270. * Initialisation object used for this instance
  18271. * @property init
  18272. * @type object
  18273. * @default {}
  18274. */
  18275. "init": $.extend( true, {}, ColReorder.defaults, opts ),
  18276. /**
  18277. * Number of columns to fix (not allow to be reordered)
  18278. * @property fixed
  18279. * @type int
  18280. * @default 0
  18281. */
  18282. "fixed": 0,
  18283. /**
  18284. * Number of columns to fix counting from right (not allow to be reordered)
  18285. * @property fixedRight
  18286. * @type int
  18287. * @default 0
  18288. */
  18289. "fixedRight": 0,
  18290. /**
  18291. * Callback function for once the reorder has been done
  18292. * @property reorderCallback
  18293. * @type function
  18294. * @default null
  18295. */
  18296. "reorderCallback": null,
  18297. /**
  18298. * @namespace Information used for the mouse drag
  18299. */
  18300. "mouse": {
  18301. "startX": -1,
  18302. "startY": -1,
  18303. "offsetX": -1,
  18304. "offsetY": -1,
  18305. "target": -1,
  18306. "targetIndex": -1,
  18307. "fromIndex": -1
  18308. },
  18309. /**
  18310. * Information which is used for positioning the insert cusor and knowing where to do the
  18311. * insert. Array of objects with the properties:
  18312. * x: x-axis position
  18313. * to: insert point
  18314. * @property aoTargets
  18315. * @type array
  18316. * @default []
  18317. */
  18318. "aoTargets": []
  18319. };
  18320. /**
  18321. * @namespace Common and useful DOM elements for the class instance
  18322. */
  18323. this.dom = {
  18324. /**
  18325. * Dragging element (the one the mouse is moving)
  18326. * @property drag
  18327. * @type element
  18328. * @default null
  18329. */
  18330. "drag": null,
  18331. /**
  18332. * The insert cursor
  18333. * @property pointer
  18334. * @type element
  18335. * @default null
  18336. */
  18337. "pointer": null
  18338. };
  18339. /* Constructor logic */
  18340. this.s.enable = this.s.init.bEnable;
  18341. this.s.dt = settings;
  18342. this.s.dt._colReorder = this;
  18343. this._fnConstruct();
  18344. return this;
  18345. };
  18346. $.extend( ColReorder.prototype, {
  18347. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18348. * Public methods
  18349. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  18350. /**
  18351. * Enable / disable end user interaction
  18352. */
  18353. fnEnable: function ( flag )
  18354. {
  18355. if ( flag === false ) {
  18356. return fnDisable();
  18357. }
  18358. this.s.enable = true;
  18359. },
  18360. /**
  18361. * Disable end user interaction
  18362. */
  18363. fnDisable: function ()
  18364. {
  18365. this.s.enable = false;
  18366. },
  18367. /**
  18368. * Reset the column ordering to the original ordering that was detected on
  18369. * start up.
  18370. * @return {this} Returns `this` for chaining.
  18371. *
  18372. * @example
  18373. * // DataTables initialisation with ColReorder
  18374. * var table = $('#example').dataTable( {
  18375. * "sDom": 'Rlfrtip'
  18376. * } );
  18377. *
  18378. * // Add click event to a button to reset the ordering
  18379. * $('#resetOrdering').click( function (e) {
  18380. * e.preventDefault();
  18381. * $.fn.dataTable.ColReorder( table ).fnReset();
  18382. * } );
  18383. */
  18384. "fnReset": function ()
  18385. {
  18386. this._fnOrderColumns( this.fnOrder() );
  18387. return this;
  18388. },
  18389. /**
  18390. * `Deprecated` - Get the current order of the columns, as an array.
  18391. * @return {array} Array of column identifiers
  18392. * @deprecated `fnOrder` should be used in preference to this method.
  18393. * `fnOrder` acts as a getter/setter.
  18394. */
  18395. "fnGetCurrentOrder": function ()
  18396. {
  18397. return this.fnOrder();
  18398. },
  18399. /**
  18400. * Get the current order of the columns, as an array. Note that the values
  18401. * given in the array are unique identifiers for each column. Currently
  18402. * these are the original ordering of the columns that was detected on
  18403. * start up, but this could potentially change in future.
  18404. * @return {array} Array of column identifiers
  18405. *
  18406. * @example
  18407. * // Get column ordering for the table
  18408. * var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();
  18409. *//**
  18410. * Set the order of the columns, from the positions identified in the
  18411. * ordering array given. Note that ColReorder takes a brute force approach
  18412. * to reordering, so it is possible multiple reordering events will occur
  18413. * before the final order is settled upon.
  18414. * @param {array} [set] Array of column identifiers in the new order. Note
  18415. * that every column must be included, uniquely, in this array.
  18416. * @return {this} Returns `this` for chaining.
  18417. *
  18418. * @example
  18419. * // Swap the first and second columns
  18420. * $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );
  18421. *
  18422. * @example
  18423. * // Move the first column to the end for the table `#example`
  18424. * var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();
  18425. * var first = curr.shift();
  18426. * curr.push( first );
  18427. * $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );
  18428. *
  18429. * @example
  18430. * // Reverse the table's order
  18431. * $.fn.dataTable.ColReorder( '#example' ).fnOrder(
  18432. * $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()
  18433. * );
  18434. */
  18435. "fnOrder": function ( set, original )
  18436. {
  18437. var a = [], i, ien, j, jen;
  18438. var columns = this.s.dt.aoColumns;
  18439. if ( set === undefined ){
  18440. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  18441. a.push( columns[i]._ColReorder_iOrigCol );
  18442. }
  18443. return a;
  18444. }
  18445. // The order given is based on the original indexes, rather than the
  18446. // existing ones, so we need to translate from the original to current
  18447. // before then doing the order
  18448. if ( original ) {
  18449. var order = this.fnOrder();
  18450. for ( i=0, ien=set.length ; i<ien ; i++ ) {
  18451. a.push( $.inArray( set[i], order ) );
  18452. }
  18453. set = a;
  18454. }
  18455. this._fnOrderColumns( fnInvertKeyValues( set ) );
  18456. return this;
  18457. },
  18458. /**
  18459. * Convert from the original column index, to the original
  18460. *
  18461. * @param {int|array} idx Index(es) to convert
  18462. * @param {string} dir Transpose direction - `fromOriginal` / `toCurrent`
  18463. * or `'toOriginal` / `fromCurrent`
  18464. * @return {int|array} Converted values
  18465. */
  18466. fnTranspose: function ( idx, dir )
  18467. {
  18468. if ( ! dir ) {
  18469. dir = 'toCurrent';
  18470. }
  18471. var order = this.fnOrder();
  18472. var columns = this.s.dt.aoColumns;
  18473. if ( dir === 'toCurrent' ) {
  18474. // Given an original index, want the current
  18475. return ! $.isArray( idx ) ?
  18476. $.inArray( idx, order ) :
  18477. $.map( idx, function ( index ) {
  18478. return $.inArray( index, order );
  18479. } );
  18480. }
  18481. else {
  18482. // Given a current index, want the original
  18483. return ! $.isArray( idx ) ?
  18484. columns[idx]._ColReorder_iOrigCol :
  18485. $.map( idx, function ( index ) {
  18486. return columns[index]._ColReorder_iOrigCol;
  18487. } );
  18488. }
  18489. },
  18490. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18491. * Private methods (they are of course public in JS, but recommended as private)
  18492. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  18493. /**
  18494. * Constructor logic
  18495. * @method _fnConstruct
  18496. * @returns void
  18497. * @private
  18498. */
  18499. "_fnConstruct": function ()
  18500. {
  18501. var that = this;
  18502. var iLen = this.s.dt.aoColumns.length;
  18503. var table = this.s.dt.nTable;
  18504. var i;
  18505. /* Columns discounted from reordering - counting left to right */
  18506. if ( this.s.init.iFixedColumns )
  18507. {
  18508. this.s.fixed = this.s.init.iFixedColumns;
  18509. }
  18510. if ( this.s.init.iFixedColumnsLeft )
  18511. {
  18512. this.s.fixed = this.s.init.iFixedColumnsLeft;
  18513. }
  18514. /* Columns discounted from reordering - counting right to left */
  18515. this.s.fixedRight = this.s.init.iFixedColumnsRight ?
  18516. this.s.init.iFixedColumnsRight :
  18517. 0;
  18518. /* Drop callback initialisation option */
  18519. if ( this.s.init.fnReorderCallback )
  18520. {
  18521. this.s.reorderCallback = this.s.init.fnReorderCallback;
  18522. }
  18523. /* Add event handlers for the drag and drop, and also mark the original column order */
  18524. for ( i = 0; i < iLen; i++ )
  18525. {
  18526. if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )
  18527. {
  18528. this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
  18529. }
  18530. /* Mark the original column order for later reference */
  18531. this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
  18532. }
  18533. /* State saving */
  18534. this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
  18535. that._fnStateSave.call( that, oData );
  18536. }, "ColReorder_State" );
  18537. /* An initial column order has been specified */
  18538. var aiOrder = null;
  18539. if ( this.s.init.aiOrder )
  18540. {
  18541. aiOrder = this.s.init.aiOrder.slice();
  18542. }
  18543. /* State loading, overrides the column order given */
  18544. if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
  18545. this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
  18546. {
  18547. aiOrder = this.s.dt.oLoadedState.ColReorder;
  18548. }
  18549. /* If we have an order to apply - do so */
  18550. if ( aiOrder )
  18551. {
  18552. /* We might be called during or after the DataTables initialisation. If before, then we need
  18553. * to wait until the draw is done, if after, then do what we need to do right away
  18554. */
  18555. if ( !that.s.dt._bInitComplete )
  18556. {
  18557. var bDone = false;
  18558. $(table).on( 'draw.dt.colReorder', function () {
  18559. if ( !that.s.dt._bInitComplete && !bDone )
  18560. {
  18561. bDone = true;
  18562. var resort = fnInvertKeyValues( aiOrder );
  18563. that._fnOrderColumns.call( that, resort );
  18564. }
  18565. } );
  18566. }
  18567. else
  18568. {
  18569. var resort = fnInvertKeyValues( aiOrder );
  18570. that._fnOrderColumns.call( that, resort );
  18571. }
  18572. }
  18573. else {
  18574. this._fnSetColumnIndexes();
  18575. }
  18576. // Destroy clean up
  18577. $(table).on( 'destroy.dt.colReorder', function () {
  18578. $(table).off( 'destroy.dt.colReorder draw.dt.colReorder' );
  18579. $.each( that.s.dt.aoColumns, function (i, column) {
  18580. $(column.nTh).off('.ColReorder');
  18581. $(column.nTh).removeAttr('data-column-index');
  18582. } );
  18583. that.s.dt._colReorder = null;
  18584. that.s = null;
  18585. } );
  18586. },
  18587. /**
  18588. * Set the column order from an array
  18589. * @method _fnOrderColumns
  18590. * @param array a An array of integers which dictate the column order that should be applied
  18591. * @returns void
  18592. * @private
  18593. */
  18594. "_fnOrderColumns": function ( a )
  18595. {
  18596. var changed = false;
  18597. if ( a.length != this.s.dt.aoColumns.length )
  18598. {
  18599. this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+
  18600. "match known number of columns. Skipping." );
  18601. return;
  18602. }
  18603. for ( var i=0, iLen=a.length ; i<iLen ; i++ )
  18604. {
  18605. var currIndex = $.inArray( i, a );
  18606. if ( i != currIndex )
  18607. {
  18608. /* Reorder our switching array */
  18609. fnArraySwitch( a, currIndex, i );
  18610. /* Do the column reorder in the table */
  18611. this.s.dt.oInstance.fnColReorder( currIndex, i, true, false );
  18612. changed = true;
  18613. }
  18614. }
  18615. this._fnSetColumnIndexes();
  18616. // Has anything actually changed? If not, then nothing else to do
  18617. if ( ! changed ) {
  18618. return;
  18619. }
  18620. $.fn.dataTable.Api( this.s.dt ).rows().invalidate();
  18621. /* When scrolling we need to recalculate the column sizes to allow for the shift */
  18622. if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
  18623. {
  18624. this.s.dt.oInstance.fnAdjustColumnSizing( false );
  18625. }
  18626. /* Save the state */
  18627. this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
  18628. if ( this.s.reorderCallback !== null )
  18629. {
  18630. this.s.reorderCallback.call( this );
  18631. }
  18632. },
  18633. /**
  18634. * Because we change the indexes of columns in the table, relative to their starting point
  18635. * we need to reorder the state columns to what they are at the starting point so we can
  18636. * then rearrange them again on state load!
  18637. * @method _fnStateSave
  18638. * @param object oState DataTables state
  18639. * @returns string JSON encoded cookie string for DataTables
  18640. * @private
  18641. */
  18642. "_fnStateSave": function ( oState )
  18643. {
  18644. var i, iLen, aCopy, iOrigColumn;
  18645. var oSettings = this.s.dt;
  18646. var columns = oSettings.aoColumns;
  18647. oState.ColReorder = [];
  18648. /* Sorting */
  18649. if ( oState.aaSorting ) {
  18650. // 1.10.0-
  18651. for ( i=0 ; i<oState.aaSorting.length ; i++ ) {
  18652. oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
  18653. }
  18654. var aSearchCopy = $.extend( true, [], oState.aoSearchCols );
  18655. for ( i=0, iLen=columns.length ; i<iLen ; i++ )
  18656. {
  18657. iOrigColumn = columns[i]._ColReorder_iOrigCol;
  18658. /* Column filter */
  18659. oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
  18660. /* Visibility */
  18661. oState.abVisCols[ iOrigColumn ] = columns[i].bVisible;
  18662. /* Column reordering */
  18663. oState.ColReorder.push( iOrigColumn );
  18664. }
  18665. }
  18666. else if ( oState.order ) {
  18667. // 1.10.1+
  18668. for ( i=0 ; i<oState.order.length ; i++ ) {
  18669. oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;
  18670. }
  18671. var stateColumnsCopy = $.extend( true, [], oState.columns );
  18672. for ( i=0, iLen=columns.length ; i<iLen ; i++ )
  18673. {
  18674. iOrigColumn = columns[i]._ColReorder_iOrigCol;
  18675. /* Columns */
  18676. oState.columns[ iOrigColumn ] = stateColumnsCopy[i];
  18677. /* Column reordering */
  18678. oState.ColReorder.push( iOrigColumn );
  18679. }
  18680. }
  18681. },
  18682. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18683. * Mouse drop and drag
  18684. */
  18685. /**
  18686. * Add a mouse down listener to a particluar TH element
  18687. * @method _fnMouseListener
  18688. * @param int i Column index
  18689. * @param element nTh TH element clicked on
  18690. * @returns void
  18691. * @private
  18692. */
  18693. "_fnMouseListener": function ( i, nTh )
  18694. {
  18695. var that = this;
  18696. $(nTh)
  18697. .on( 'mousedown.ColReorder', function (e) {
  18698. if ( that.s.enable && e.which === 1 ) {
  18699. that._fnMouseDown.call( that, e, nTh );
  18700. }
  18701. } )
  18702. .on( 'touchstart.ColReorder', function (e) {
  18703. if ( that.s.enable ) {
  18704. that._fnMouseDown.call( that, e, nTh );
  18705. }
  18706. } );
  18707. },
  18708. /**
  18709. * Mouse down on a TH element in the table header
  18710. * @method _fnMouseDown
  18711. * @param event e Mouse event
  18712. * @param element nTh TH element to be dragged
  18713. * @returns void
  18714. * @private
  18715. */
  18716. "_fnMouseDown": function ( e, nTh )
  18717. {
  18718. var that = this;
  18719. /* Store information about the mouse position */
  18720. var target = $(e.target).closest('th, td');
  18721. var offset = target.offset();
  18722. var idx = parseInt( $(nTh).attr('data-column-index'), 10 );
  18723. if ( idx === undefined ) {
  18724. return;
  18725. }
  18726. this.s.mouse.startX = this._fnCursorPosition( e, 'pageX' );
  18727. this.s.mouse.startY = this._fnCursorPosition( e, 'pageY' );
  18728. this.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left;
  18729. this.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top;
  18730. this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];
  18731. this.s.mouse.targetIndex = idx;
  18732. this.s.mouse.fromIndex = idx;
  18733. this._fnRegions();
  18734. /* Add event handlers to the document */
  18735. $(document)
  18736. .on( 'mousemove.ColReorder touchmove.ColReorder', function (e) {
  18737. that._fnMouseMove.call( that, e );
  18738. } )
  18739. .on( 'mouseup.ColReorder touchend.ColReorder', function (e) {
  18740. that._fnMouseUp.call( that, e );
  18741. } );
  18742. },
  18743. /**
  18744. * Deal with a mouse move event while dragging a node
  18745. * @method _fnMouseMove
  18746. * @param event e Mouse event
  18747. * @returns void
  18748. * @private
  18749. */
  18750. "_fnMouseMove": function ( e )
  18751. {
  18752. var that = this;
  18753. if ( this.dom.drag === null )
  18754. {
  18755. /* Only create the drag element if the mouse has moved a specific distance from the start
  18756. * point - this allows the user to make small mouse movements when sorting and not have a
  18757. * possibly confusing drag element showing up
  18758. */
  18759. if ( Math.pow(
  18760. Math.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) +
  18761. Math.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 )
  18762. {
  18763. return;
  18764. }
  18765. this._fnCreateDragNode();
  18766. }
  18767. /* Position the element - we respect where in the element the click occured */
  18768. this.dom.drag.css( {
  18769. left: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX,
  18770. top: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY
  18771. } );
  18772. /* Based on the current mouse position, calculate where the insert should go */
  18773. var target;
  18774. var lastToIndex = this.s.mouse.toIndex;
  18775. var cursorXPosiotion = this._fnCursorPosition(e, 'pageX');
  18776. var targetsPrev = function (i) {
  18777. while (i >= 0) {
  18778. i--;
  18779. if (i <= 0) {
  18780. return null;
  18781. }
  18782. if (that.s.aoTargets[i+1].x !== that.s.aoTargets[i].x) {
  18783. return that.s.aoTargets[i];
  18784. }
  18785. }
  18786. };
  18787. var firstNotHidden = function () {
  18788. for (var i=0 ; i<that.s.aoTargets.length-1 ; i++) {
  18789. if (that.s.aoTargets[i].x !== that.s.aoTargets[i+1].x) {
  18790. return that.s.aoTargets[i];
  18791. }
  18792. }
  18793. };
  18794. var lastNotHidden = function () {
  18795. for (var i=that.s.aoTargets.length-1 ; i>0 ; i--) {
  18796. if (that.s.aoTargets[i].x !== that.s.aoTargets[i-1].x) {
  18797. return that.s.aoTargets[i];
  18798. }
  18799. }
  18800. };
  18801. for (var i = 1; i < this.s.aoTargets.length; i++) {
  18802. var prevTarget = targetsPrev(i);
  18803. if (! prevTarget) {
  18804. prevTarget = firstNotHidden();
  18805. }
  18806. var prevTargetMiddle = prevTarget.x + (this.s.aoTargets[i].x - prevTarget.x) / 2;
  18807. if (this._fnIsLtr()) {
  18808. if (cursorXPosiotion < prevTargetMiddle ) {
  18809. target = prevTarget;
  18810. break;
  18811. }
  18812. }
  18813. else {
  18814. if (cursorXPosiotion > prevTargetMiddle) {
  18815. target = prevTarget;
  18816. break;
  18817. }
  18818. }
  18819. }
  18820. if (target) {
  18821. this.dom.pointer.css('left', target.x);
  18822. this.s.mouse.toIndex = target.to;
  18823. }
  18824. else {
  18825. // The insert element wasn't positioned in the array (less than
  18826. // operator), so we put it at the end
  18827. this.dom.pointer.css( 'left', lastNotHidden().x );
  18828. this.s.mouse.toIndex = lastNotHidden().to;
  18829. }
  18830. // Perform reordering if realtime updating is on and the column has moved
  18831. if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {
  18832. this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
  18833. this.s.mouse.fromIndex = this.s.mouse.toIndex;
  18834. // Not great for performance, but required to keep everything in alignment
  18835. if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
  18836. {
  18837. this.s.dt.oInstance.fnAdjustColumnSizing( false );
  18838. }
  18839. this._fnRegions();
  18840. }
  18841. },
  18842. /**
  18843. * Finish off the mouse drag and insert the column where needed
  18844. * @method _fnMouseUp
  18845. * @param event e Mouse event
  18846. * @returns void
  18847. * @private
  18848. */
  18849. "_fnMouseUp": function ( e )
  18850. {
  18851. var that = this;
  18852. $(document).off( '.ColReorder' );
  18853. if ( this.dom.drag !== null )
  18854. {
  18855. /* Remove the guide elements */
  18856. this.dom.drag.remove();
  18857. this.dom.pointer.remove();
  18858. this.dom.drag = null;
  18859. this.dom.pointer = null;
  18860. /* Actually do the reorder */
  18861. this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true );
  18862. this._fnSetColumnIndexes();
  18863. /* When scrolling we need to recalculate the column sizes to allow for the shift */
  18864. if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
  18865. {
  18866. this.s.dt.oInstance.fnAdjustColumnSizing( false );
  18867. }
  18868. /* Save the state */
  18869. this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
  18870. if ( this.s.reorderCallback !== null )
  18871. {
  18872. this.s.reorderCallback.call( this );
  18873. }
  18874. }
  18875. },
  18876. /**
  18877. * Calculate a cached array with the points of the column inserts, and the
  18878. * 'to' points
  18879. * @method _fnRegions
  18880. * @returns void
  18881. * @private
  18882. */
  18883. "_fnRegions": function ()
  18884. {
  18885. var aoColumns = this.s.dt.aoColumns;
  18886. var isLTR = this._fnIsLtr();
  18887. this.s.aoTargets.splice(0, this.s.aoTargets.length);
  18888. var lastBound = $(this.s.dt.nTable).offset().left;
  18889. var aoColumnBounds = [];
  18890. $.each(aoColumns, function (i, column) {
  18891. if (column.bVisible && column.nTh.style.display !== 'none') {
  18892. var nth = $(column.nTh);
  18893. var bound = nth.offset().left;
  18894. if (isLTR) {
  18895. bound += nth.outerWidth();
  18896. }
  18897. aoColumnBounds.push({
  18898. index: i,
  18899. bound: bound
  18900. });
  18901. lastBound = bound;
  18902. }
  18903. else {
  18904. aoColumnBounds.push({
  18905. index: i,
  18906. bound: lastBound
  18907. });
  18908. }
  18909. });
  18910. var firstColumn = aoColumnBounds[0];
  18911. var firstColumnWidth = $(aoColumns[firstColumn.index].nTh).outerWidth();
  18912. this.s.aoTargets.push({
  18913. to: 0,
  18914. x: firstColumn.bound - firstColumnWidth
  18915. });
  18916. for (var i = 0; i < aoColumnBounds.length; i++) {
  18917. var columnBound = aoColumnBounds[i];
  18918. var iToPoint = columnBound.index;
  18919. /* For the column / header in question, we want it's position to remain the same if the
  18920. * position is just to it's immediate left or right, so we only increment the counter for
  18921. * other columns
  18922. */
  18923. if (columnBound.index < this.s.mouse.fromIndex) {
  18924. iToPoint++;
  18925. }
  18926. this.s.aoTargets.push({
  18927. to: iToPoint,
  18928. x: columnBound.bound
  18929. });
  18930. }
  18931. /* Disallow columns for being reordered by drag and drop, counting right to left */
  18932. if ( this.s.fixedRight !== 0 )
  18933. {
  18934. this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );
  18935. }
  18936. /* Disallow columns for being reordered by drag and drop, counting left to right */
  18937. if ( this.s.fixed !== 0 )
  18938. {
  18939. this.s.aoTargets.splice( 0, this.s.fixed );
  18940. }
  18941. },
  18942. /**
  18943. * Copy the TH element that is being drags so the user has the idea that they are actually
  18944. * moving it around the page.
  18945. * @method _fnCreateDragNode
  18946. * @returns void
  18947. * @private
  18948. */
  18949. "_fnCreateDragNode": function ()
  18950. {
  18951. var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "";
  18952. var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;
  18953. var origTr = origCell.parentNode;
  18954. var origThead = origTr.parentNode;
  18955. var origTable = origThead.parentNode;
  18956. var cloneCell = $(origCell).clone();
  18957. // This is a slightly odd combination of jQuery and DOM, but it is the
  18958. // fastest and least resource intensive way I could think of cloning
  18959. // the table with just a single header cell in it.
  18960. this.dom.drag = $(origTable.cloneNode(false))
  18961. .addClass( 'DTCR_clonedTable' )
  18962. .append(
  18963. $(origThead.cloneNode(false)).append(
  18964. $(origTr.cloneNode(false)).append(
  18965. cloneCell[0]
  18966. )
  18967. )
  18968. )
  18969. .css( {
  18970. position: 'absolute',
  18971. top: 0,
  18972. left: 0,
  18973. width: $(origCell).outerWidth(),
  18974. height: $(origCell).outerHeight()
  18975. } )
  18976. .appendTo( 'body' );
  18977. this.dom.pointer = $('<div></div>')
  18978. .addClass( 'DTCR_pointer' )
  18979. .css( {
  18980. position: 'absolute',
  18981. top: scrolling ?
  18982. $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :
  18983. $(this.s.dt.nTable).offset().top,
  18984. height : scrolling ?
  18985. $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :
  18986. $(this.s.dt.nTable).height()
  18987. } )
  18988. .appendTo( 'body' );
  18989. },
  18990. /**
  18991. * Add a data attribute to the column headers, so we know the index of
  18992. * the row to be reordered. This allows fast detection of the index, and
  18993. * for this plug-in to work with FixedHeader which clones the nodes.
  18994. * @private
  18995. */
  18996. "_fnSetColumnIndexes": function ()
  18997. {
  18998. $.each( this.s.dt.aoColumns, function (i, column) {
  18999. $(column.nTh).attr('data-column-index', i);
  19000. } );
  19001. },
  19002. /**
  19003. * Get cursor position regardless of mouse or touch input
  19004. * @param {Event} e jQuery Event
  19005. * @param {string} prop Property to get
  19006. * @return {number} Value
  19007. */
  19008. _fnCursorPosition: function ( e, prop ) {
  19009. if ( e.type.indexOf('touch') !== -1 ) {
  19010. return e.originalEvent.touches[0][ prop ];
  19011. }
  19012. return e[ prop ];
  19013. },
  19014. _fnIsLtr: function () {
  19015. return $(this.s.dt.nTable).css('direction') !== "rtl";
  19016. }
  19017. } );
  19018. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19019. * Static parameters
  19020. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  19021. /**
  19022. * ColReorder default settings for initialisation
  19023. * @namespace
  19024. * @static
  19025. */
  19026. ColReorder.defaults = {
  19027. /**
  19028. * Predefined ordering for the columns that will be applied automatically
  19029. * on initialisation. If not specified then the order that the columns are
  19030. * found to be in the HTML is the order used.
  19031. * @type array
  19032. * @default null
  19033. * @static
  19034. */
  19035. aiOrder: null,
  19036. /**
  19037. * ColReorder enable on initialisation
  19038. * @type boolean
  19039. * @default true
  19040. * @static
  19041. */
  19042. bEnable: true,
  19043. /**
  19044. * Redraw the table's column ordering as the end user draws the column
  19045. * (`true`) or wait until the mouse is released (`false` - default). Note
  19046. * that this will perform a redraw on each reordering, which involves an
  19047. * Ajax request each time if you are using server-side processing in
  19048. * DataTables.
  19049. * @type boolean
  19050. * @default false
  19051. * @static
  19052. */
  19053. bRealtime: true,
  19054. /**
  19055. * Indicate how many columns should be fixed in position (counting from the
  19056. * left). This will typically be 1 if used, but can be as high as you like.
  19057. * @type int
  19058. * @default 0
  19059. * @static
  19060. */
  19061. iFixedColumnsLeft: 0,
  19062. /**
  19063. * As `iFixedColumnsRight` but counting from the right.
  19064. * @type int
  19065. * @default 0
  19066. * @static
  19067. */
  19068. iFixedColumnsRight: 0,
  19069. /**
  19070. * Callback function that is fired when columns are reordered. The `column-
  19071. * reorder` event is preferred over this callback
  19072. * @type function():void
  19073. * @default null
  19074. * @static
  19075. */
  19076. fnReorderCallback: null
  19077. };
  19078. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19079. * Constants
  19080. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  19081. /**
  19082. * ColReorder version
  19083. * @constant version
  19084. * @type String
  19085. * @default As code
  19086. */
  19087. ColReorder.version = "1.5.2";
  19088. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19089. * DataTables interfaces
  19090. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  19091. // Expose
  19092. $.fn.dataTable.ColReorder = ColReorder;
  19093. $.fn.DataTable.ColReorder = ColReorder;
  19094. // Register a new feature with DataTables
  19095. if ( typeof $.fn.dataTable == "function" &&
  19096. typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
  19097. $.fn.dataTableExt.fnVersionCheck('1.10.8') )
  19098. {
  19099. $.fn.dataTableExt.aoFeatures.push( {
  19100. "fnInit": function( settings ) {
  19101. var table = settings.oInstance;
  19102. if ( ! settings._colReorder ) {
  19103. var dtInit = settings.oInit;
  19104. var opts = dtInit.colReorder || dtInit.oColReorder || {};
  19105. new ColReorder( settings, opts );
  19106. }
  19107. else {
  19108. table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
  19109. }
  19110. return null; /* No node for DataTables to insert */
  19111. },
  19112. "cFeature": "R",
  19113. "sFeature": "ColReorder"
  19114. } );
  19115. }
  19116. else {
  19117. alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download");
  19118. }
  19119. // Attach a listener to the document which listens for DataTables initialisation
  19120. // events so we can automatically initialise
  19121. $(document).on( 'preInit.dt.colReorder', function (e, settings) {
  19122. if ( e.namespace !== 'dt' ) {
  19123. return;
  19124. }
  19125. var init = settings.oInit.colReorder;
  19126. var defaults = DataTable.defaults.colReorder;
  19127. if ( init || defaults ) {
  19128. var opts = $.extend( {}, init, defaults );
  19129. if ( init !== false ) {
  19130. new ColReorder( settings, opts );
  19131. }
  19132. }
  19133. } );
  19134. // API augmentation
  19135. $.fn.dataTable.Api.register( 'colReorder.reset()', function () {
  19136. return this.iterator( 'table', function ( ctx ) {
  19137. ctx._colReorder.fnReset();
  19138. } );
  19139. } );
  19140. $.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) {
  19141. if ( set ) {
  19142. return this.iterator( 'table', function ( ctx ) {
  19143. ctx._colReorder.fnOrder( set, original );
  19144. } );
  19145. }
  19146. return this.context.length ?
  19147. this.context[0]._colReorder.fnOrder() :
  19148. null;
  19149. } );
  19150. $.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) {
  19151. return this.context.length && this.context[0]._colReorder ?
  19152. this.context[0]._colReorder.fnTranspose( idx, dir ) :
  19153. idx;
  19154. } );
  19155. $.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) {
  19156. if (this.context.length) {
  19157. this.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows );
  19158. this.context[0]._colReorder._fnSetColumnIndexes();
  19159. }
  19160. return this;
  19161. } );
  19162. $.fn.dataTable.Api.register( 'colReorder.enable()', function( flag ) {
  19163. return this.iterator( 'table', function ( ctx ) {
  19164. if ( ctx._colReorder ) {
  19165. ctx._colReorder.fnEnable( flag );
  19166. }
  19167. } );
  19168. } );
  19169. $.fn.dataTable.Api.register( 'colReorder.disable()', function() {
  19170. return this.iterator( 'table', function ( ctx ) {
  19171. if ( ctx._colReorder ) {
  19172. ctx._colReorder.fnDisable();
  19173. }
  19174. } );
  19175. } );
  19176. return ColReorder;
  19177. }));
  19178. /*! Bootstrap 4 styling wrapper for ColReorder
  19179. * ©2018 SpryMedia Ltd - datatables.net/license
  19180. */
  19181. (function( factory ){
  19182. if ( typeof define === 'function' && define.amd ) {
  19183. // AMD
  19184. define( ['jquery', 'datatables.net-bs4', 'datatables.net-colreorder'], function ( $ ) {
  19185. return factory( $, window, document );
  19186. } );
  19187. }
  19188. else if ( typeof exports === 'object' ) {
  19189. // CommonJS
  19190. module.exports = function (root, $) {
  19191. if ( ! root ) {
  19192. root = window;
  19193. }
  19194. if ( ! $ || ! $.fn.dataTable ) {
  19195. $ = require('datatables.net-bs4')(root, $).$;
  19196. }
  19197. if ( ! $.fn.dataTable.ColReorder ) {
  19198. require('datatables.net-colreorder')(root, $);
  19199. }
  19200. return factory( $, root, root.document );
  19201. };
  19202. }
  19203. else {
  19204. // Browser
  19205. factory( jQuery, window, document );
  19206. }
  19207. }(function( $, window, document, undefined ) {
  19208. return $.fn.dataTable;
  19209. }));
  19210. /*! FixedColumns 3.8.0
  19211. * ©2010-2018 SpryMedia Ltd - datatables.net/license
  19212. */
  19213. /**
  19214. * @summary FixedColumns
  19215. * @description Freeze columns in place on a scrolling DataTable
  19216. * @version 3.8.0
  19217. * @file dataTables.fixedColumns.js
  19218. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  19219. * @contact www.sprymedia.co.uk/contact
  19220. * @copyright Copyright 2010-2018 SpryMedia Ltd.
  19221. *
  19222. * This source file is free software, available under the following license:
  19223. * MIT license - http://datatables.net/license/mit
  19224. *
  19225. * This source file is distributed in the hope that it will be useful, but
  19226. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  19227. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  19228. *
  19229. * For details please refer to: http://www.datatables.net
  19230. */
  19231. (function( factory ){
  19232. if ( typeof define === 'function' && define.amd ) {
  19233. // AMD
  19234. define( ['jquery', 'datatables.net'], function ( $ ) {
  19235. return factory( $, window, document );
  19236. } );
  19237. }
  19238. else if ( typeof exports === 'object' ) {
  19239. // CommonJS
  19240. module.exports = function (root, $) {
  19241. if ( ! root ) {
  19242. root = window;
  19243. }
  19244. if ( ! $ || ! $.fn.dataTable ) {
  19245. $ = require('datatables.net')(root, $).$;
  19246. }
  19247. return factory( $, root, root.document );
  19248. };
  19249. }
  19250. else {
  19251. // Browser
  19252. factory( jQuery, window, document );
  19253. }
  19254. }(function( $, window, document, undefined ) {
  19255. 'use strict';
  19256. var DataTable = $.fn.dataTable;
  19257. var _firefoxScroll;
  19258. /**
  19259. * When making use of DataTables' x-axis scrolling feature, you may wish to
  19260. * fix the left most column in place. This plug-in for DataTables provides
  19261. * exactly this option (note for non-scrolling tables, please use the
  19262. * FixedHeader plug-in, which can fix headers and footers). Key
  19263. * features include:
  19264. *
  19265. * * Freezes the left or right most columns to the side of the table
  19266. * * Option to freeze two or more columns
  19267. * * Full integration with DataTables' scrolling options
  19268. * * Speed - FixedColumns is fast in its operation
  19269. *
  19270. * @class
  19271. * @constructor
  19272. * @global
  19273. * @param {object} dt DataTables instance. With DataTables 1.10 this can also
  19274. * be a jQuery collection, a jQuery selector, DataTables API instance or
  19275. * settings object.
  19276. * @param {object} [init={}] Configuration object for FixedColumns. Options are
  19277. * defined by {@link FixedColumns.defaults}
  19278. *
  19279. * @requires jQuery 1.7+
  19280. * @requires DataTables 1.8.0+
  19281. *
  19282. * @example
  19283. * var table = $('#example').dataTable( {
  19284. * "scrollX": "100%"
  19285. * } );
  19286. * new $.fn.dataTable.fixedColumns( table );
  19287. */
  19288. var FixedColumns = function ( dt, init ) {
  19289. var that = this;
  19290. /* Sanity check - you just know it will happen */
  19291. if ( ! ( this instanceof FixedColumns ) ) {
  19292. alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." );
  19293. return;
  19294. }
  19295. if ( init === undefined || init === true ) {
  19296. init = {};
  19297. }
  19298. // Use the DataTables Hungarian notation mapping method, if it exists to
  19299. // provide forwards compatibility for camel case variables
  19300. var camelToHungarian = $.fn.dataTable.camelToHungarian;
  19301. if ( camelToHungarian ) {
  19302. camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );
  19303. camelToHungarian( FixedColumns.defaults, init );
  19304. }
  19305. // v1.10 allows the settings object to be got form a number of sources
  19306. var dtSettings = new $.fn.dataTable.Api( dt ).settings()[0];
  19307. /**
  19308. * Settings object which contains customisable information for FixedColumns instance
  19309. * @namespace
  19310. * @extends FixedColumns.defaults
  19311. * @private
  19312. */
  19313. this.s = {
  19314. /**
  19315. * DataTables settings objects
  19316. * @type object
  19317. * @default Obtained from DataTables instance
  19318. */
  19319. "dt": dtSettings,
  19320. /**
  19321. * Number of columns in the DataTable - stored for quick access
  19322. * @type int
  19323. * @default Obtained from DataTables instance
  19324. */
  19325. "iTableColumns": dtSettings.aoColumns.length,
  19326. /**
  19327. * Original outer widths of the columns as rendered by DataTables - used to calculate
  19328. * the FixedColumns grid bounding box
  19329. * @type array.<int>
  19330. * @default []
  19331. */
  19332. "aiOuterWidths": [],
  19333. /**
  19334. * Original inner widths of the columns as rendered by DataTables - used to apply widths
  19335. * to the columns
  19336. * @type array.<int>
  19337. * @default []
  19338. */
  19339. "aiInnerWidths": [],
  19340. /**
  19341. * Is the document layout right-to-left
  19342. * @type boolean
  19343. */
  19344. rtl: $(dtSettings.nTable).css('direction') === 'rtl'
  19345. };
  19346. /**
  19347. * DOM elements used by the class instance
  19348. * @namespace
  19349. * @private
  19350. *
  19351. */
  19352. this.dom = {
  19353. /**
  19354. * DataTables scrolling element
  19355. * @type node
  19356. * @default null
  19357. */
  19358. "scroller": null,
  19359. /**
  19360. * DataTables header table
  19361. * @type node
  19362. * @default null
  19363. */
  19364. "header": null,
  19365. /**
  19366. * DataTables body table
  19367. * @type node
  19368. * @default null
  19369. */
  19370. "body": null,
  19371. /**
  19372. * DataTables footer table
  19373. * @type node
  19374. * @default null
  19375. */
  19376. "footer": null,
  19377. /**
  19378. * Display grid elements
  19379. * @namespace
  19380. */
  19381. "grid": {
  19382. /**
  19383. * Grid wrapper. This is the container element for the 3x3 grid
  19384. * @type node
  19385. * @default null
  19386. */
  19387. "wrapper": null,
  19388. /**
  19389. * DataTables scrolling element. This element is the DataTables
  19390. * component in the display grid (making up the main table - i.e.
  19391. * not the fixed columns).
  19392. * @type node
  19393. * @default null
  19394. */
  19395. "dt": null,
  19396. /**
  19397. * Left fixed column grid components
  19398. * @namespace
  19399. */
  19400. "left": {
  19401. "wrapper": null,
  19402. "head": null,
  19403. "body": null,
  19404. "foot": null
  19405. },
  19406. /**
  19407. * Right fixed column grid components
  19408. * @namespace
  19409. */
  19410. "right": {
  19411. "wrapper": null,
  19412. "head": null,
  19413. "body": null,
  19414. "foot": null
  19415. }
  19416. },
  19417. /**
  19418. * Cloned table nodes
  19419. * @namespace
  19420. */
  19421. "clone": {
  19422. /**
  19423. * Left column cloned table nodes
  19424. * @namespace
  19425. */
  19426. "left": {
  19427. /**
  19428. * Cloned header table
  19429. * @type node
  19430. * @default null
  19431. */
  19432. "header": null,
  19433. /**
  19434. * Cloned body table
  19435. * @type node
  19436. * @default null
  19437. */
  19438. "body": null,
  19439. /**
  19440. * Cloned footer table
  19441. * @type node
  19442. * @default null
  19443. */
  19444. "footer": null
  19445. },
  19446. /**
  19447. * Right column cloned table nodes
  19448. * @namespace
  19449. */
  19450. "right": {
  19451. /**
  19452. * Cloned header table
  19453. * @type node
  19454. * @default null
  19455. */
  19456. "header": null,
  19457. /**
  19458. * Cloned body table
  19459. * @type node
  19460. * @default null
  19461. */
  19462. "body": null,
  19463. /**
  19464. * Cloned footer table
  19465. * @type node
  19466. * @default null
  19467. */
  19468. "footer": null
  19469. }
  19470. }
  19471. };
  19472. if ( dtSettings._oFixedColumns ) {
  19473. throw 'FixedColumns already initialised on this table';
  19474. }
  19475. /* Attach the instance to the DataTables instance so it can be accessed easily */
  19476. dtSettings._oFixedColumns = this;
  19477. /* Let's do it */
  19478. if ( ! dtSettings._bInitComplete )
  19479. {
  19480. dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {
  19481. that._fnConstruct( init );
  19482. }, 'FixedColumns' );
  19483. }
  19484. else
  19485. {
  19486. this._fnConstruct( init );
  19487. }
  19488. };
  19489. $.extend( FixedColumns.prototype , {
  19490. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19491. * Public methods
  19492. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  19493. /**
  19494. * Update the fixed columns - including headers and footers. Note that FixedColumns will
  19495. * automatically update the display whenever the host DataTable redraws.
  19496. * @returns {void}
  19497. * @example
  19498. * var table = $('#example').dataTable( {
  19499. * "scrollX": "100%"
  19500. * } );
  19501. * var fc = new $.fn.dataTable.fixedColumns( table );
  19502. *
  19503. * // at some later point when the table has been manipulated....
  19504. * fc.fnUpdate();
  19505. */
  19506. "fnUpdate": function ()
  19507. {
  19508. this._fnDraw( true );
  19509. },
  19510. /**
  19511. * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.
  19512. * This is useful if you update the width of the table container. Note that FixedColumns will
  19513. * perform this function automatically when the window.resize event is fired.
  19514. * @returns {void}
  19515. * @example
  19516. * var table = $('#example').dataTable( {
  19517. * "scrollX": "100%"
  19518. * } );
  19519. * var fc = new $.fn.dataTable.fixedColumns( table );
  19520. *
  19521. * // Resize the table container and then have FixedColumns adjust its layout....
  19522. * $('#content').width( 1200 );
  19523. * fc.fnRedrawLayout();
  19524. */
  19525. "fnRedrawLayout": function ()
  19526. {
  19527. this._fnColCalc();
  19528. this._fnGridLayout();
  19529. this.fnUpdate();
  19530. },
  19531. /**
  19532. * Mark a row such that it's height should be recalculated when using 'semiauto' row
  19533. * height matching. This function will have no effect when 'none' or 'auto' row height
  19534. * matching is used.
  19535. * @param {Node} nTr TR element that should have it's height recalculated
  19536. * @returns {void}
  19537. * @example
  19538. * var table = $('#example').dataTable( {
  19539. * "scrollX": "100%"
  19540. * } );
  19541. * var fc = new $.fn.dataTable.fixedColumns( table );
  19542. *
  19543. * // manipulate the table - mark the row as needing an update then update the table
  19544. * // this allows the redraw performed by DataTables fnUpdate to recalculate the row
  19545. * // height
  19546. * fc.fnRecalculateHeight();
  19547. * table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
  19548. */
  19549. "fnRecalculateHeight": function ( nTr )
  19550. {
  19551. delete nTr._DTTC_iHeight;
  19552. nTr.style.height = 'auto';
  19553. },
  19554. /**
  19555. * Set the height of a given row - provides cross browser compatibility
  19556. * @param {Node} nTarget TR element that should have it's height recalculated
  19557. * @param {int} iHeight Height in pixels to set
  19558. * @returns {void}
  19559. * @example
  19560. * var table = $('#example').dataTable( {
  19561. * "scrollX": "100%"
  19562. * } );
  19563. * var fc = new $.fn.dataTable.fixedColumns( table );
  19564. *
  19565. * // You may want to do this after manipulating a row in the fixed column
  19566. * fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
  19567. */
  19568. "fnSetRowHeight": function ( nTarget, iHeight )
  19569. {
  19570. nTarget.style.height = iHeight+"px";
  19571. },
  19572. /**
  19573. * Get data index information about a row or cell in the table body.
  19574. * This function is functionally identical to fnGetPosition in DataTables,
  19575. * taking the same parameter (TH, TD or TR node) and returning exactly the
  19576. * the same information (data index information). THe difference between
  19577. * the two is that this method takes into account the fixed columns in the
  19578. * table, so you can pass in nodes from the master table, or the cloned
  19579. * tables and get the index position for the data in the main table.
  19580. * @param {node} node TR, TH or TD element to get the information about
  19581. * @returns {int} If nNode is given as a TR, then a single index is
  19582. * returned, or if given as a cell, an array of [row index, column index
  19583. * (visible), column index (all)] is given.
  19584. */
  19585. "fnGetPosition": function ( node )
  19586. {
  19587. var idx;
  19588. var inst = this.s.dt.oInstance;
  19589. if ( ! $(node).parents('.DTFC_Cloned').length )
  19590. {
  19591. // Not in a cloned table
  19592. return inst.fnGetPosition( node );
  19593. }
  19594. else
  19595. {
  19596. // Its in the cloned table, so need to look up position
  19597. if ( node.nodeName.toLowerCase() === 'tr' ) {
  19598. idx = $(node).index();
  19599. return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
  19600. }
  19601. else
  19602. {
  19603. var colIdx = $(node).index();
  19604. idx = $(node.parentNode).index();
  19605. var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
  19606. return [
  19607. row,
  19608. colIdx,
  19609. inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )
  19610. ];
  19611. }
  19612. }
  19613. },
  19614. fnToFixedNode: function ( rowIdx, colIdx )
  19615. {
  19616. var found;
  19617. if ( colIdx < this.s.iLeftColumns ) {
  19618. found = $(this.dom.clone.left.body).find('[data-dt-row='+rowIdx+'][data-dt-column='+colIdx+']');
  19619. }
  19620. else if ( colIdx >= this.s.iRightColumns ) {
  19621. found = $(this.dom.clone.right.body).find('[data-dt-row='+rowIdx+'][data-dt-column='+colIdx+']');
  19622. }
  19623. if ( found && found.length ) {
  19624. return found[0];
  19625. }
  19626. // Fallback - non-fixed node
  19627. var table = new $.fn.dataTable.Api(this.s.dt);
  19628. return table.cell(rowIdx, colIdx).node();
  19629. },
  19630. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19631. * Private methods (they are of course public in JS, but recommended as private)
  19632. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  19633. /**
  19634. * Initialisation for FixedColumns
  19635. * @param {Object} oInit User settings for initialisation
  19636. * @returns {void}
  19637. * @private
  19638. */
  19639. "_fnConstruct": function ( oInit )
  19640. {
  19641. var i, iLen, iWidth,
  19642. that = this;
  19643. /* Sanity checking */
  19644. if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||
  19645. this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )
  19646. {
  19647. alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+
  19648. "Please upgrade your DataTables installation" );
  19649. return;
  19650. }
  19651. if ( this.s.dt.oScroll.sX === "" )
  19652. {
  19653. this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+
  19654. "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+
  19655. "column fixing when scrolling is not enabled" );
  19656. return;
  19657. }
  19658. /* Apply the settings from the user / defaults */
  19659. this.s = $.extend( true, this.s, FixedColumns.defaults, oInit );
  19660. /* Set up the DOM as we need it and cache nodes */
  19661. var classes = this.s.dt.oClasses;
  19662. this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];
  19663. this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];
  19664. /* Set up the DOM that we want for the fixed column layout grid */
  19665. this._fnColCalc();
  19666. this._fnGridSetup();
  19667. /* Event handlers */
  19668. var mouseController;
  19669. var mouseDown = false;
  19670. // When the mouse is down (drag scroll) the mouse controller cannot
  19671. // change, as the browser keeps the original element as the scrolling one
  19672. $(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function (e) {
  19673. if ( e.button === 0 ) {
  19674. mouseDown = true;
  19675. $(document).one( 'mouseup', function () {
  19676. mouseDown = false;
  19677. } );
  19678. }
  19679. } );
  19680. // When the body is scrolled - scroll the left and right columns
  19681. $(this.dom.scroller)
  19682. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  19683. if ( ! mouseDown ) {
  19684. mouseController = 'main';
  19685. }
  19686. } )
  19687. .on( 'scroll.DTFC', function (e) {
  19688. if ( ! mouseController && e.originalEvent ) {
  19689. mouseController = 'main';
  19690. }
  19691. if ( mouseController === 'main' ) {
  19692. if ( that.s.iLeftColumns > 0 ) {
  19693. that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;
  19694. }
  19695. if ( that.s.iRightColumns > 0 ) {
  19696. that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;
  19697. }
  19698. }
  19699. } );
  19700. var wheelType = 'onwheel' in document.createElement('div') ?
  19701. 'wheel.DTFC' :
  19702. 'mousewheel.DTFC';
  19703. if ( that.s.iLeftColumns > 0 ) {
  19704. // When scrolling the left column, scroll the body and right column
  19705. $(that.dom.grid.left.liner)
  19706. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  19707. if ( ! mouseDown ) {
  19708. mouseController = 'left';
  19709. }
  19710. } )
  19711. .on( 'scroll.DTFC', function ( e ) {
  19712. if ( ! mouseController && e.originalEvent ) {
  19713. mouseController = 'left';
  19714. }
  19715. if ( mouseController === 'left' ) {
  19716. that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;
  19717. if ( that.s.iRightColumns > 0 ) {
  19718. that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;
  19719. }
  19720. }
  19721. } )
  19722. .on( wheelType, function(e) {
  19723. // Pass horizontal scrolling through
  19724. var xDelta = e.type === 'wheel' ?
  19725. -e.originalEvent.deltaX :
  19726. e.originalEvent.wheelDeltaX;
  19727. that.dom.scroller.scrollLeft -= xDelta;
  19728. } );
  19729. }
  19730. if ( that.s.iRightColumns > 0 ) {
  19731. // When scrolling the right column, scroll the body and the left column
  19732. $(that.dom.grid.right.liner)
  19733. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  19734. if ( ! mouseDown ) {
  19735. mouseController = 'right';
  19736. }
  19737. } )
  19738. .on( 'scroll.DTFC', function ( e ) {
  19739. if ( ! mouseController && e.originalEvent ) {
  19740. mouseController = 'right';
  19741. }
  19742. if ( mouseController === 'right' ) {
  19743. that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;
  19744. if ( that.s.iLeftColumns > 0 ) {
  19745. that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;
  19746. }
  19747. }
  19748. } )
  19749. .on( wheelType, function(e) {
  19750. // Pass horizontal scrolling through
  19751. var xDelta = e.type === 'wheel' ?
  19752. -e.originalEvent.deltaX :
  19753. e.originalEvent.wheelDeltaX;
  19754. that.dom.scroller.scrollLeft -= xDelta;
  19755. } );
  19756. }
  19757. $(window).on( 'resize.DTFC', function () {
  19758. that._fnGridLayout.call( that );
  19759. } );
  19760. var bFirstDraw = true;
  19761. var jqTable = $(this.s.dt.nTable);
  19762. jqTable
  19763. .on( 'draw.dt.DTFC', function () {
  19764. that._fnColCalc();
  19765. that._fnDraw.call( that, bFirstDraw );
  19766. bFirstDraw = false;
  19767. } )
  19768. .on( 'column-sizing.dt.DTFC', function () {
  19769. that._fnColCalc();
  19770. that._fnGridLayout( that );
  19771. } )
  19772. .on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) {
  19773. if ( recalc === undefined || recalc ) {
  19774. that._fnColCalc();
  19775. that._fnGridLayout( that );
  19776. that._fnDraw( true );
  19777. }
  19778. } )
  19779. .on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) {
  19780. if ( e.namespace === 'dt' ) {
  19781. that._fnDraw( false );
  19782. }
  19783. } )
  19784. .on( 'destroy.dt.DTFC', function () {
  19785. jqTable.off( '.DTFC' );
  19786. $(that.dom.scroller).off( '.DTFC' );
  19787. $(window).off( '.DTFC' );
  19788. $(that.s.dt.nTableWrapper).off( '.DTFC' );
  19789. $(that.dom.grid.left.liner).off( '.DTFC '+wheelType );
  19790. $(that.dom.grid.left.wrapper).remove();
  19791. $(that.dom.grid.right.liner).off( '.DTFC '+wheelType );
  19792. $(that.dom.grid.right.wrapper).remove();
  19793. } );
  19794. /* Get things right to start with - note that due to adjusting the columns, there must be
  19795. * another redraw of the main table. It doesn't need to be a full redraw however.
  19796. */
  19797. this._fnGridLayout();
  19798. this.s.dt.oInstance.fnDraw(false);
  19799. },
  19800. /**
  19801. * Calculate the column widths for the grid layout
  19802. * @returns {void}
  19803. * @private
  19804. */
  19805. "_fnColCalc": function ()
  19806. {
  19807. var that = this;
  19808. var iLeftWidth = 0;
  19809. var iRightWidth = 0;
  19810. this.s.aiInnerWidths = [];
  19811. this.s.aiOuterWidths = [];
  19812. $.each( this.s.dt.aoColumns, function (i, col) {
  19813. var th = $(col.nTh);
  19814. var border;
  19815. if ( ! th.filter(':visible').length ) {
  19816. that.s.aiInnerWidths.push( 0 );
  19817. that.s.aiOuterWidths.push( 0 );
  19818. }
  19819. else
  19820. {
  19821. // Inner width is used to assign widths to cells
  19822. // Outer width is used to calculate the container
  19823. var iWidth = th.outerWidth();
  19824. // When working with the left most-cell, need to add on the
  19825. // table's border to the outerWidth, since we need to take
  19826. // account of it, but it isn't in any cell
  19827. if ( that.s.aiOuterWidths.length === 0 ) {
  19828. border = $(that.s.dt.nTable).css('border-left-width');
  19829. iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
  19830. 1 :
  19831. parseInt( border, 10 );
  19832. }
  19833. // Likewise with the final column on the right
  19834. if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {
  19835. border = $(that.s.dt.nTable).css('border-right-width');
  19836. iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
  19837. 1 :
  19838. parseInt( border, 10 );
  19839. }
  19840. that.s.aiOuterWidths.push( iWidth );
  19841. that.s.aiInnerWidths.push( th.width() );
  19842. if ( i < that.s.iLeftColumns )
  19843. {
  19844. iLeftWidth += iWidth;
  19845. }
  19846. if ( that.s.iTableColumns-that.s.iRightColumns <= i )
  19847. {
  19848. iRightWidth += iWidth;
  19849. }
  19850. }
  19851. } );
  19852. this.s.iLeftWidth = iLeftWidth;
  19853. this.s.iRightWidth = iRightWidth;
  19854. },
  19855. /**
  19856. * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid
  19857. * for the left column, the DataTable (for which we just reuse the scrolling element DataTable
  19858. * puts into the DOM) and the right column. In each of he two fixed column elements there is a
  19859. * grouping wrapper element and then a head, body and footer wrapper. In each of these we then
  19860. * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.
  19861. * @returns {void}
  19862. * @private
  19863. */
  19864. "_fnGridSetup": function ()
  19865. {
  19866. var that = this;
  19867. var oOverflow = this._fnDTOverflow();
  19868. var block;
  19869. this.dom.body = this.s.dt.nTable;
  19870. this.dom.header = this.s.dt.nTHead.parentNode;
  19871. this.dom.header.parentNode.parentNode.style.position = "relative";
  19872. var nSWrapper =
  19873. $('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;">'+
  19874. '<div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;" aria-hidden="true">'+
  19875. '<div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
  19876. '<div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; height:0; overflow:hidden;">'+
  19877. '<div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
  19878. '</div>'+
  19879. '<div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
  19880. '</div>'+
  19881. '<div class="DTFC_RightWrapper" style="position:absolute; top:0; right:0;" aria-hidden="true">'+
  19882. '<div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;">'+
  19883. '<div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
  19884. '</div>'+
  19885. '<div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; height:0; overflow:hidden;">'+
  19886. '<div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
  19887. '</div>'+
  19888. '<div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;">'+
  19889. '<div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
  19890. '</div>'+
  19891. '</div>'+
  19892. '</div>')[0];
  19893. var nLeft = nSWrapper.childNodes[0];
  19894. var nRight = nSWrapper.childNodes[1];
  19895. this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );
  19896. nSWrapper.appendChild( this.dom.grid.dt );
  19897. this.dom.grid.wrapper = nSWrapper;
  19898. if ( this.s.iLeftColumns > 0 )
  19899. {
  19900. this.dom.grid.left.wrapper = nLeft;
  19901. this.dom.grid.left.head = nLeft.childNodes[0];
  19902. this.dom.grid.left.body = nLeft.childNodes[1];
  19903. this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];
  19904. nSWrapper.appendChild( nLeft );
  19905. }
  19906. if ( this.s.iRightColumns > 0 )
  19907. {
  19908. this.dom.grid.right.wrapper = nRight;
  19909. this.dom.grid.right.head = nRight.childNodes[0];
  19910. this.dom.grid.right.body = nRight.childNodes[1];
  19911. this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];
  19912. nRight.style.right = oOverflow.bar+"px";
  19913. block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];
  19914. block.style.width = oOverflow.bar+"px";
  19915. block.style.right = -oOverflow.bar+"px";
  19916. this.dom.grid.right.headBlock = block;
  19917. block = $('div.DTFC_RightFootBlocker', nSWrapper)[0];
  19918. block.style.width = oOverflow.bar+"px";
  19919. block.style.right = -oOverflow.bar+"px";
  19920. this.dom.grid.right.footBlock = block;
  19921. nSWrapper.appendChild( nRight );
  19922. }
  19923. if ( this.s.dt.nTFoot )
  19924. {
  19925. this.dom.footer = this.s.dt.nTFoot.parentNode;
  19926. if ( this.s.iLeftColumns > 0 )
  19927. {
  19928. this.dom.grid.left.foot = nLeft.childNodes[2];
  19929. }
  19930. if ( this.s.iRightColumns > 0 )
  19931. {
  19932. this.dom.grid.right.foot = nRight.childNodes[2];
  19933. }
  19934. }
  19935. // RTL support - swap the position of the left and right columns (#48)
  19936. if ( this.s.rtl ) {
  19937. $('div.DTFC_RightHeadBlocker', nSWrapper).css( {
  19938. left: -oOverflow.bar+'px',
  19939. right: ''
  19940. } );
  19941. }
  19942. },
  19943. /**
  19944. * Style and position the grid used for the FixedColumns layout
  19945. * @returns {void}
  19946. * @private
  19947. */
  19948. "_fnGridLayout": function ()
  19949. {
  19950. var that = this;
  19951. var oGrid = this.dom.grid;
  19952. var iWidth = $(oGrid.wrapper).width();
  19953. var iBodyHeight = this.s.dt.nTable.parentNode.offsetHeight;
  19954. var iFullHeight = this.s.dt.nTable.parentNode.parentNode.offsetHeight;
  19955. var oOverflow = this._fnDTOverflow();
  19956. var iLeftWidth = this.s.iLeftWidth;
  19957. var iRightWidth = this.s.iRightWidth;
  19958. var rtl = $(this.dom.body).css('direction') === 'rtl';
  19959. var wrapper;
  19960. var scrollbarAdjust = function ( node, width ) {
  19961. if ( ! oOverflow.bar ) {
  19962. // If there is no scrollbar (Macs) we need to hide the auto scrollbar
  19963. node.style.width = (width+20)+"px";
  19964. node.style.paddingRight = "20px";
  19965. node.style.boxSizing = "border-box";
  19966. }
  19967. else if ( that._firefoxScrollError() ) {
  19968. // See the above function for why this is required
  19969. if ( $(node).height() > 34 ) {
  19970. node.style.width = (width+oOverflow.bar)+"px";
  19971. }
  19972. }
  19973. else {
  19974. // Otherwise just overflow by the scrollbar
  19975. node.style.width = (width+oOverflow.bar)+"px";
  19976. }
  19977. };
  19978. // When x scrolling - don't paint the fixed columns over the x scrollbar
  19979. if ( oOverflow.x )
  19980. {
  19981. iBodyHeight -= oOverflow.bar;
  19982. }
  19983. oGrid.wrapper.style.height = iFullHeight+"px";
  19984. if ( this.s.iLeftColumns > 0 )
  19985. {
  19986. wrapper = oGrid.left.wrapper;
  19987. wrapper.style.width = iLeftWidth+'px';
  19988. wrapper.style.height = '1px';
  19989. // Swap the position of the left and right columns for rtl (#48)
  19990. // This is always up against the edge, scrollbar on the far side
  19991. if ( rtl ) {
  19992. wrapper.style.left = '';
  19993. wrapper.style.right = 0;
  19994. }
  19995. else {
  19996. wrapper.style.left = 0;
  19997. wrapper.style.right = '';
  19998. }
  19999. oGrid.left.body.style.height = iBodyHeight+"px";
  20000. if ( oGrid.left.foot ) {
  20001. oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar
  20002. }
  20003. scrollbarAdjust( oGrid.left.liner, iLeftWidth );
  20004. oGrid.left.liner.style.height = iBodyHeight+"px";
  20005. oGrid.left.liner.style.maxHeight = iBodyHeight+"px";
  20006. }
  20007. if ( this.s.iRightColumns > 0 )
  20008. {
  20009. wrapper = oGrid.right.wrapper;
  20010. wrapper.style.width = iRightWidth+'px';
  20011. wrapper.style.height = '1px';
  20012. // Need to take account of the vertical scrollbar
  20013. if ( this.s.rtl ) {
  20014. wrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0;
  20015. wrapper.style.right = '';
  20016. }
  20017. else {
  20018. wrapper.style.left = '';
  20019. wrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0;
  20020. }
  20021. oGrid.right.body.style.height = iBodyHeight+"px";
  20022. if ( oGrid.right.foot ) {
  20023. oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px";
  20024. }
  20025. scrollbarAdjust( oGrid.right.liner, iRightWidth );
  20026. oGrid.right.liner.style.height = iBodyHeight+"px";
  20027. oGrid.right.liner.style.maxHeight = iBodyHeight+"px";
  20028. oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';
  20029. oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';
  20030. }
  20031. },
  20032. /**
  20033. * Get information about the DataTable's scrolling state - specifically if the table is scrolling
  20034. * on either the x or y axis, and also the scrollbar width.
  20035. * @returns {object} Information about the DataTables scrolling state with the properties:
  20036. * 'x', 'y' and 'bar'
  20037. * @private
  20038. */
  20039. "_fnDTOverflow": function ()
  20040. {
  20041. var nTable = this.s.dt.nTable;
  20042. var nTableScrollBody = nTable.parentNode;
  20043. var out = {
  20044. "x": false,
  20045. "y": false,
  20046. "bar": this.s.dt.oScroll.iBarWidth
  20047. };
  20048. if ( nTable.offsetWidth > nTableScrollBody.clientWidth )
  20049. {
  20050. out.x = true;
  20051. }
  20052. if ( nTable.offsetHeight > nTableScrollBody.clientHeight )
  20053. {
  20054. out.y = true;
  20055. }
  20056. return out;
  20057. },
  20058. /**
  20059. * Clone and position the fixed columns
  20060. * @returns {void}
  20061. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  20062. * @private
  20063. */
  20064. "_fnDraw": function ( bAll )
  20065. {
  20066. this._fnGridLayout();
  20067. this._fnCloneLeft( bAll );
  20068. this._fnCloneRight( bAll );
  20069. /* Draw callback function */
  20070. if ( this.s.fnDrawCallback !== null )
  20071. {
  20072. this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );
  20073. }
  20074. /* Event triggering */
  20075. $(this).trigger( 'draw.dtfc', {
  20076. "leftClone": this.dom.clone.left,
  20077. "rightClone": this.dom.clone.right
  20078. } );
  20079. },
  20080. /**
  20081. * Clone the right columns
  20082. * @returns {void}
  20083. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  20084. * @private
  20085. */
  20086. "_fnCloneRight": function ( bAll )
  20087. {
  20088. if ( this.s.iRightColumns <= 0 ) {
  20089. return;
  20090. }
  20091. var that = this,
  20092. i, jq,
  20093. aiColumns = [];
  20094. for ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {
  20095. if ( this.s.dt.aoColumns[i].bVisible ) {
  20096. aiColumns.push( i );
  20097. }
  20098. }
  20099. this._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );
  20100. },
  20101. /**
  20102. * Clone the left columns
  20103. * @returns {void}
  20104. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  20105. * @private
  20106. */
  20107. "_fnCloneLeft": function ( bAll )
  20108. {
  20109. if ( this.s.iLeftColumns <= 0 ) {
  20110. return;
  20111. }
  20112. var that = this,
  20113. i, jq,
  20114. aiColumns = [];
  20115. for ( i=0 ; i<this.s.iLeftColumns ; i++ ) {
  20116. if ( this.s.dt.aoColumns[i].bVisible ) {
  20117. aiColumns.push( i );
  20118. }
  20119. }
  20120. this._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );
  20121. },
  20122. /**
  20123. * Make a copy of the layout object for a header or footer element from DataTables. Note that
  20124. * this method will clone the nodes in the layout object.
  20125. * @returns {Array} Copy of the layout array
  20126. * @param {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)
  20127. * @param {Object} aiColumns Columns to copy
  20128. * @param {boolean} events Copy cell events or not
  20129. * @private
  20130. */
  20131. "_fnCopyLayout": function ( aoOriginal, aiColumns, events )
  20132. {
  20133. var aReturn = [];
  20134. var aClones = [];
  20135. var aCloned = [];
  20136. for ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )
  20137. {
  20138. var aRow = [];
  20139. aRow.nTr = $(aoOriginal[i].nTr).clone(events, false)[0];
  20140. for ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )
  20141. {
  20142. if ( $.inArray( j, aiColumns ) === -1 )
  20143. {
  20144. continue;
  20145. }
  20146. var iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );
  20147. if ( iCloned === -1 )
  20148. {
  20149. var nClone = $(aoOriginal[i][j].cell).clone(events, false)[0];
  20150. aClones.push( nClone );
  20151. aCloned.push( aoOriginal[i][j].cell );
  20152. aRow.push( {
  20153. "cell": nClone,
  20154. "unique": aoOriginal[i][j].unique
  20155. } );
  20156. }
  20157. else
  20158. {
  20159. aRow.push( {
  20160. "cell": aClones[ iCloned ],
  20161. "unique": aoOriginal[i][j].unique
  20162. } );
  20163. }
  20164. }
  20165. aReturn.push( aRow );
  20166. }
  20167. return aReturn;
  20168. },
  20169. /**
  20170. * Clone the DataTable nodes and place them in the DOM (sized correctly)
  20171. * @returns {void}
  20172. * @param {Object} oClone Object containing the header, footer and body cloned DOM elements
  20173. * @param {Object} oGrid Grid object containing the display grid elements for the cloned
  20174. * column (left or right)
  20175. * @param {Array} aiColumns Column indexes which should be operated on from the DataTable
  20176. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  20177. * @private
  20178. */
  20179. "_fnClone": function ( oClone, oGrid, aiColumns, bAll )
  20180. {
  20181. var that = this,
  20182. i, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,
  20183. jqCloneThead, aoFixedHeader,
  20184. dt = this.s.dt;
  20185. /*
  20186. * Header
  20187. */
  20188. if ( bAll )
  20189. {
  20190. $(oClone.header).remove();
  20191. oClone.header = $(this.dom.header).clone(true, false)[0];
  20192. oClone.header.className += " DTFC_Cloned";
  20193. oClone.header.style.width = "100%";
  20194. oGrid.head.appendChild( oClone.header );
  20195. /* Copy the DataTables layout cache for the header for our floating column */
  20196. aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, true );
  20197. jqCloneThead = $('>thead', oClone.header);
  20198. jqCloneThead.empty();
  20199. /* Add the created cloned TR elements to the table */
  20200. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  20201. {
  20202. jqCloneThead[0].appendChild( aoCloneLayout[i].nTr );
  20203. }
  20204. /* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan
  20205. * calculations for us
  20206. */
  20207. dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
  20208. }
  20209. else
  20210. {
  20211. /* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows
  20212. * etc, we make a copy of the header from the DataTable again, but don't insert the
  20213. * cloned cells, just copy the classes across. To get the matching layout for the
  20214. * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping
  20215. */
  20216. aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, false );
  20217. aoFixedHeader=[];
  20218. dt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );
  20219. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  20220. {
  20221. for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
  20222. {
  20223. aoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;
  20224. // If jQuery UI theming is used we need to copy those elements as well
  20225. $('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {
  20226. this.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;
  20227. } );
  20228. }
  20229. }
  20230. }
  20231. this._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );
  20232. /*
  20233. * Body
  20234. */
  20235. if ( this.s.sHeightMatch == 'auto' )
  20236. {
  20237. /* Remove any heights which have been applied already and let the browser figure it out */
  20238. $('>tbody>tr', that.dom.body).css('height', 'auto');
  20239. }
  20240. if ( oClone.body !== null )
  20241. {
  20242. $(oClone.body).remove();
  20243. oClone.body = null;
  20244. }
  20245. oClone.body = $(this.dom.body).clone(true)[0];
  20246. oClone.body.className += " DTFC_Cloned";
  20247. oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px";
  20248. oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */
  20249. if ( oClone.body.getAttribute('id') !== null )
  20250. {
  20251. oClone.body.removeAttribute('id');
  20252. }
  20253. $('>thead>tr', oClone.body).empty();
  20254. $('>tfoot', oClone.body).remove();
  20255. var nBody = $('tbody', oClone.body)[0];
  20256. $(nBody).empty();
  20257. if ( dt.aiDisplay.length > 0 )
  20258. {
  20259. /* Copy the DataTables' header elements to force the column width in exactly the
  20260. * same way that DataTables does it - have the header element, apply the width and
  20261. * colapse it down
  20262. */
  20263. var nInnerThead = $('>thead>tr', oClone.body)[0];
  20264. for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
  20265. {
  20266. iColumn = aiColumns[iIndex];
  20267. nClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];
  20268. nClone.innerHTML = "";
  20269. var oStyle = nClone.style;
  20270. oStyle.paddingTop = "0";
  20271. oStyle.paddingBottom = "0";
  20272. oStyle.borderTopWidth = "0";
  20273. oStyle.borderBottomWidth = "0";
  20274. oStyle.height = 0;
  20275. oStyle.width = that.s.aiInnerWidths[iColumn]+"px";
  20276. nInnerThead.appendChild( nClone );
  20277. }
  20278. /* Add in the tbody elements, cloning form the master table */
  20279. $('>tbody>tr', that.dom.body).each( function (z) {
  20280. var i = that.s.dt.oFeatures.bServerSide===false ?
  20281. that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;
  20282. var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');
  20283. var n = this.cloneNode(false);
  20284. n.removeAttribute('id');
  20285. n.setAttribute( 'data-dt-row', i );
  20286. for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
  20287. {
  20288. iColumn = aiColumns[iIndex];
  20289. if ( aTds.length > 0 )
  20290. {
  20291. nClone = $( aTds[iColumn] ).clone(true, true)[0];
  20292. nClone.removeAttribute( 'id' );
  20293. nClone.setAttribute( 'data-dt-row', i );
  20294. nClone.setAttribute( 'data-dt-column', iColumn );
  20295. n.appendChild( nClone );
  20296. }
  20297. }
  20298. nBody.appendChild( n );
  20299. } );
  20300. }
  20301. else
  20302. {
  20303. $('>tbody>tr', that.dom.body).each( function (z) {
  20304. nClone = this.cloneNode(true);
  20305. nClone.className += ' DTFC_NoData';
  20306. $('td', nClone).html('');
  20307. nBody.appendChild( nClone );
  20308. } );
  20309. }
  20310. oClone.body.style.width = "100%";
  20311. oClone.body.style.margin = "0";
  20312. oClone.body.style.padding = "0";
  20313. // Interop with Scroller - need to use a height forcing element in the
  20314. // scrolling area in the same way that Scroller does in the body scroll.
  20315. if ( dt.oScroller !== undefined )
  20316. {
  20317. var scrollerForcer = dt.oScroller.dom.force;
  20318. if ( ! oGrid.forcer ) {
  20319. oGrid.forcer = scrollerForcer.cloneNode( true );
  20320. oGrid.liner.appendChild( oGrid.forcer );
  20321. }
  20322. else {
  20323. oGrid.forcer.style.height = scrollerForcer.style.height;
  20324. }
  20325. }
  20326. oGrid.liner.appendChild( oClone.body );
  20327. this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );
  20328. /*
  20329. * Footer
  20330. */
  20331. if ( dt.nTFoot !== null )
  20332. {
  20333. if ( bAll )
  20334. {
  20335. if ( oClone.footer !== null )
  20336. {
  20337. oClone.footer.parentNode.removeChild( oClone.footer );
  20338. }
  20339. oClone.footer = $(this.dom.footer).clone(true, true)[0];
  20340. oClone.footer.className += " DTFC_Cloned";
  20341. oClone.footer.style.width = "100%";
  20342. oGrid.foot.appendChild( oClone.footer );
  20343. /* Copy the footer just like we do for the header */
  20344. aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true );
  20345. var jqCloneTfoot = $('>tfoot', oClone.footer);
  20346. jqCloneTfoot.empty();
  20347. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  20348. {
  20349. jqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );
  20350. }
  20351. dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
  20352. }
  20353. else
  20354. {
  20355. aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, false );
  20356. var aoCurrFooter=[];
  20357. dt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );
  20358. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  20359. {
  20360. for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
  20361. {
  20362. aoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;
  20363. }
  20364. }
  20365. }
  20366. this._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );
  20367. }
  20368. /* Equalise the column widths between the header footer and body - body get's priority */
  20369. var anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );
  20370. $(anUnique).each( function (i) {
  20371. iColumn = aiColumns[i];
  20372. this.style.width = that.s.aiInnerWidths[iColumn]+"px";
  20373. } );
  20374. if ( that.s.dt.nTFoot !== null )
  20375. {
  20376. anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );
  20377. $(anUnique).each( function (i) {
  20378. iColumn = aiColumns[i];
  20379. this.style.width = that.s.aiInnerWidths[iColumn]+"px";
  20380. } );
  20381. }
  20382. },
  20383. /**
  20384. * From a given table node (THEAD etc), get a list of TR direct child elements
  20385. * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)
  20386. * @returns {Array} List of TR elements found
  20387. * @private
  20388. */
  20389. "_fnGetTrNodes": function ( nIn )
  20390. {
  20391. var aOut = [];
  20392. for ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )
  20393. {
  20394. if ( nIn.childNodes[i].nodeName.toUpperCase() == "TR" )
  20395. {
  20396. aOut.push( nIn.childNodes[i] );
  20397. }
  20398. }
  20399. return aOut;
  20400. },
  20401. /**
  20402. * Equalise the heights of the rows in a given table node in a cross browser way
  20403. * @returns {void}
  20404. * @param {String} nodeName Node type - thead, tbody or tfoot
  20405. * @param {Node} original Original node to take the heights from
  20406. * @param {Node} clone Copy the heights to
  20407. * @private
  20408. */
  20409. "_fnEqualiseHeights": function ( nodeName, original, clone )
  20410. {
  20411. if ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )
  20412. {
  20413. return;
  20414. }
  20415. var that = this,
  20416. i, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,
  20417. rootOriginal = original.getElementsByTagName(nodeName)[0],
  20418. rootClone = clone.getElementsByTagName(nodeName)[0],
  20419. jqBoxHack = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),
  20420. iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(),
  20421. anOriginal = this._fnGetTrNodes( rootOriginal ),
  20422. anClone = this._fnGetTrNodes( rootClone ),
  20423. heights = [];
  20424. for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
  20425. {
  20426. iHeightOriginal = anOriginal[i].offsetHeight;
  20427. iHeightClone = anClone[i].offsetHeight;
  20428. iHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;
  20429. if ( this.s.sHeightMatch == 'semiauto' )
  20430. {
  20431. anOriginal[i]._DTTC_iHeight = iHeight;
  20432. }
  20433. heights.push( iHeight );
  20434. }
  20435. for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
  20436. {
  20437. anClone[i].style.height = heights[i]+"px";
  20438. anOriginal[i].style.height = heights[i]+"px";
  20439. }
  20440. },
  20441. /**
  20442. * Determine if the UA suffers from Firefox's overflow:scroll scrollbars
  20443. * not being shown bug.
  20444. *
  20445. * Firefox doesn't draw scrollbars, even if it is told to using
  20446. * overflow:scroll, if the div is less than 34px height. See bugs 292284 and
  20447. * 781885. Using UA detection here since this is particularly hard to detect
  20448. * using objects - its a straight up rendering error in Firefox.
  20449. *
  20450. * @return {boolean} True if Firefox error is present, false otherwise
  20451. */
  20452. _firefoxScrollError: function () {
  20453. if ( _firefoxScroll === undefined ) {
  20454. var test = $('<div/>')
  20455. .css( {
  20456. position: 'absolute',
  20457. top: 0,
  20458. left: 0,
  20459. height: 10,
  20460. width: 50,
  20461. overflow: 'scroll'
  20462. } )
  20463. .appendTo( 'body' );
  20464. // Make sure this doesn't apply on Macs with 0 width scrollbars
  20465. _firefoxScroll = (
  20466. test[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0
  20467. );
  20468. test.remove();
  20469. }
  20470. return _firefoxScroll;
  20471. }
  20472. } );
  20473. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20474. * Statics
  20475. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  20476. /**
  20477. * FixedColumns default settings for initialisation
  20478. * @name FixedColumns.defaults
  20479. * @namespace
  20480. * @static
  20481. */
  20482. FixedColumns.defaults = /** @lends FixedColumns.defaults */{
  20483. /**
  20484. * Number of left hand columns to fix in position
  20485. * @type int
  20486. * @default 1
  20487. * @static
  20488. * @example
  20489. * var = $('#example').dataTable( {
  20490. * "scrollX": "100%"
  20491. * } );
  20492. * new $.fn.dataTable.fixedColumns( table, {
  20493. * "leftColumns": 2
  20494. * } );
  20495. */
  20496. "iLeftColumns": 1,
  20497. /**
  20498. * Number of right hand columns to fix in position
  20499. * @type int
  20500. * @default 0
  20501. * @static
  20502. * @example
  20503. * var table = $('#example').dataTable( {
  20504. * "scrollX": "100%"
  20505. * } );
  20506. * new $.fn.dataTable.fixedColumns( table, {
  20507. * "rightColumns": 1
  20508. * } );
  20509. */
  20510. "iRightColumns": 0,
  20511. /**
  20512. * Draw callback function which is called when FixedColumns has redrawn the fixed assets
  20513. * @type function(object, object):void
  20514. * @default null
  20515. * @static
  20516. * @example
  20517. * var table = $('#example').dataTable( {
  20518. * "scrollX": "100%"
  20519. * } );
  20520. * new $.fn.dataTable.fixedColumns( table, {
  20521. * "drawCallback": function () {
  20522. * alert( "FixedColumns redraw" );
  20523. * }
  20524. * } );
  20525. */
  20526. "fnDrawCallback": null,
  20527. /**
  20528. * Height matching algorthim to use. This can be "none" which will result in no height
  20529. * matching being applied by FixedColumns (height matching could be forced by CSS in this
  20530. * case), "semiauto" whereby the height calculation will be performed once, and the result
  20531. * cached to be used again (fnRecalculateHeight can be used to force recalculation), or
  20532. * "auto" when height matching is performed on every draw (slowest but must accurate)
  20533. * @type string
  20534. * @default semiauto
  20535. * @static
  20536. * @example
  20537. * var table = $('#example').dataTable( {
  20538. * "scrollX": "100%"
  20539. * } );
  20540. * new $.fn.dataTable.fixedColumns( table, {
  20541. * "heightMatch": "auto"
  20542. * } );
  20543. */
  20544. "sHeightMatch": "semiauto"
  20545. };
  20546. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20547. * Constants
  20548. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  20549. /**
  20550. * FixedColumns version
  20551. * @name FixedColumns.version
  20552. * @type String
  20553. * @default See code
  20554. * @static
  20555. */
  20556. FixedColumns.version = "3.8.0";
  20557. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20558. * DataTables API integration
  20559. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  20560. DataTable.Api.register( 'fixedColumns()', function () {
  20561. return this;
  20562. } );
  20563. DataTable.Api.register( 'fixedColumns().update()', function () {
  20564. return this.iterator( 'table', function ( ctx ) {
  20565. if ( ctx._oFixedColumns ) {
  20566. ctx._oFixedColumns.fnUpdate();
  20567. }
  20568. } );
  20569. } );
  20570. DataTable.Api.register( 'fixedColumns().relayout()', function () {
  20571. return this.iterator( 'table', function ( ctx ) {
  20572. if ( ctx._oFixedColumns ) {
  20573. ctx._oFixedColumns.fnRedrawLayout();
  20574. }
  20575. } );
  20576. } );
  20577. DataTable.Api.register( 'rows().recalcHeight()', function () {
  20578. return this.iterator( 'row', function ( ctx, idx ) {
  20579. if ( ctx._oFixedColumns ) {
  20580. ctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() );
  20581. }
  20582. } );
  20583. } );
  20584. DataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) {
  20585. row = $(row);
  20586. return row.parents('.DTFC_Cloned').length ?
  20587. this.rows( { page: 'current' } ).indexes()[ row.index() ] :
  20588. this.row( row ).index();
  20589. } );
  20590. DataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) {
  20591. cell = $(cell);
  20592. if ( cell.parents('.DTFC_Cloned').length ) {
  20593. var rowClonedIdx = cell.parent().index();
  20594. var rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ];
  20595. var columnIdx;
  20596. if ( cell.parents('.DTFC_LeftWrapper').length ) {
  20597. columnIdx = cell.index();
  20598. }
  20599. else {
  20600. var columns = this.columns().flatten().length;
  20601. columnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index();
  20602. }
  20603. return {
  20604. row: rowIdx,
  20605. column: this.column.index( 'toData', columnIdx ),
  20606. columnVisible: columnIdx
  20607. };
  20608. }
  20609. else {
  20610. return this.cell( cell ).index();
  20611. }
  20612. } );
  20613. DataTable.Api.registerPlural( 'cells().fixedNodes()', 'cell().fixedNode()', function () {
  20614. return this.iterator( 'cell', function ( settings, row, column ) {
  20615. return settings._oFixedColumns
  20616. ? settings._oFixedColumns.fnToFixedNode( row, column )
  20617. : this.node();
  20618. }, 1 );
  20619. } );
  20620. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20621. * Initialisation
  20622. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  20623. // Attach a listener to the document which listens for DataTables initialisation
  20624. // events so we can automatically initialise
  20625. $(document).on( 'init.dt.fixedColumns', function (e, settings) {
  20626. if ( e.namespace !== 'dt' ) {
  20627. return;
  20628. }
  20629. var init = settings.oInit.fixedColumns;
  20630. var defaults = DataTable.defaults.fixedColumns;
  20631. if ( init || defaults ) {
  20632. var opts = $.extend( {}, init, defaults );
  20633. if ( init !== false ) {
  20634. new FixedColumns( settings, opts );
  20635. }
  20636. }
  20637. } );
  20638. // Make FixedColumns accessible from the DataTables instance
  20639. $.fn.dataTable.FixedColumns = FixedColumns;
  20640. $.fn.DataTable.FixedColumns = FixedColumns;
  20641. return FixedColumns;
  20642. }));
  20643. /*! Bootstrap 4 styling wrapper for FixedColumns
  20644. * ©2018 SpryMedia Ltd - datatables.net/license
  20645. */
  20646. (function( factory ){
  20647. if ( typeof define === 'function' && define.amd ) {
  20648. // AMD
  20649. define( ['jquery', 'datatables.net-bs4', 'datatables.net-fixedcolumns'], function ( $ ) {
  20650. return factory( $, window, document );
  20651. } );
  20652. }
  20653. else if ( typeof exports === 'object' ) {
  20654. // CommonJS
  20655. module.exports = function (root, $) {
  20656. if ( ! root ) {
  20657. root = window;
  20658. }
  20659. if ( ! $ || ! $.fn.dataTable ) {
  20660. $ = require('datatables.net-bs4')(root, $).$;
  20661. }
  20662. if ( ! $.fn.dataTable.FixedColumns ) {
  20663. require('datatables.net-fixedcolumns')(root, $);
  20664. }
  20665. return factory( $, root, root.document );
  20666. };
  20667. }
  20668. else {
  20669. // Browser
  20670. factory( jQuery, window, document );
  20671. }
  20672. }(function( $, window, document, undefined ) {
  20673. return $.fn.dataTable;
  20674. }));
  20675. /*! FixedHeader 3.1.6-dev
  20676. * ©2009-2018 SpryMedia Ltd - datatables.net/license
  20677. */
  20678. /**
  20679. * @summary FixedHeader
  20680. * @description Fix a table's header or footer, so it is always visible while
  20681. * scrolling
  20682. * @version 3.1.6-dev
  20683. * @file dataTables.fixedHeader.js
  20684. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  20685. * @contact www.sprymedia.co.uk/contact
  20686. * @copyright Copyright 2009-2018 SpryMedia Ltd.
  20687. *
  20688. * This source file is free software, available under the following license:
  20689. * MIT license - http://datatables.net/license/mit
  20690. *
  20691. * This source file is distributed in the hope that it will be useful, but
  20692. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  20693. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  20694. *
  20695. * For details please refer to: http://www.datatables.net
  20696. */
  20697. (function( factory ){
  20698. if ( typeof define === 'function' && define.amd ) {
  20699. // AMD
  20700. define( ['jquery', 'datatables.net'], function ( $ ) {
  20701. return factory( $, window, document );
  20702. } );
  20703. }
  20704. else if ( typeof exports === 'object' ) {
  20705. // CommonJS
  20706. module.exports = function (root, $) {
  20707. if ( ! root ) {
  20708. root = window;
  20709. }
  20710. if ( ! $ || ! $.fn.dataTable ) {
  20711. $ = require('datatables.net')(root, $).$;
  20712. }
  20713. return factory( $, root, root.document );
  20714. };
  20715. }
  20716. else {
  20717. // Browser
  20718. factory( jQuery, window, document );
  20719. }
  20720. }(function( $, window, document, undefined ) {
  20721. 'use strict';
  20722. var DataTable = $.fn.dataTable;
  20723. var _instCounter = 0;
  20724. var FixedHeader = function ( dt, config ) {
  20725. // Sanity check - you just know it will happen
  20726. if ( ! (this instanceof FixedHeader) ) {
  20727. throw "FixedHeader must be initialised with the 'new' keyword.";
  20728. }
  20729. // Allow a boolean true for defaults
  20730. if ( config === true ) {
  20731. config = {};
  20732. }
  20733. dt = new DataTable.Api( dt );
  20734. this.c = $.extend( true, {}, FixedHeader.defaults, config );
  20735. this.s = {
  20736. dt: dt,
  20737. position: {
  20738. theadTop: 0,
  20739. tbodyTop: 0,
  20740. tfootTop: 0,
  20741. tfootBottom: 0,
  20742. width: 0,
  20743. left: 0,
  20744. tfootHeight: 0,
  20745. theadHeight: 0,
  20746. windowHeight: $(window).height(),
  20747. visible: true
  20748. },
  20749. headerMode: null,
  20750. footerMode: null,
  20751. autoWidth: dt.settings()[0].oFeatures.bAutoWidth,
  20752. namespace: '.dtfc'+(_instCounter++),
  20753. scrollLeft: {
  20754. header: -1,
  20755. footer: -1
  20756. },
  20757. enable: true
  20758. };
  20759. this.dom = {
  20760. floatingHeader: null,
  20761. thead: $(dt.table().header()),
  20762. tbody: $(dt.table().body()),
  20763. tfoot: $(dt.table().footer()),
  20764. header: {
  20765. host: null,
  20766. floating: null,
  20767. placeholder: null
  20768. },
  20769. footer: {
  20770. host: null,
  20771. floating: null,
  20772. placeholder: null
  20773. }
  20774. };
  20775. this.dom.header.host = this.dom.thead.parent();
  20776. this.dom.footer.host = this.dom.tfoot.parent();
  20777. var dtSettings = dt.settings()[0];
  20778. if ( dtSettings._fixedHeader ) {
  20779. throw "FixedHeader already initialised on table "+dtSettings.nTable.id;
  20780. }
  20781. dtSettings._fixedHeader = this;
  20782. this._constructor();
  20783. };
  20784. /*
  20785. * Variable: FixedHeader
  20786. * Purpose: Prototype for FixedHeader
  20787. * Scope: global
  20788. */
  20789. $.extend( FixedHeader.prototype, {
  20790. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20791. * API methods
  20792. */
  20793. /**
  20794. * Kill off FH and any events
  20795. */
  20796. destroy: function () {
  20797. this.s.dt.off( '.dtfc' );
  20798. $(window).off( this.s.namespace );
  20799. if ( this.c.header ) {
  20800. this._modeChange( 'in-place', 'header', true );
  20801. }
  20802. if ( this.c.footer && this.dom.tfoot.length ) {
  20803. this._modeChange( 'in-place', 'footer', true );
  20804. }
  20805. },
  20806. /**
  20807. * Enable / disable the fixed elements
  20808. *
  20809. * @param {boolean} enable `true` to enable, `false` to disable
  20810. */
  20811. enable: function ( enable, update )
  20812. {
  20813. this.s.enable = enable;
  20814. if ( update || update === undefined ) {
  20815. this._positions();
  20816. this._scroll( true );
  20817. }
  20818. },
  20819. /**
  20820. * Get enabled status
  20821. */
  20822. enabled: function ()
  20823. {
  20824. return this.s.enable;
  20825. },
  20826. /**
  20827. * Set header offset
  20828. *
  20829. * @param {int} new value for headerOffset
  20830. */
  20831. headerOffset: function ( offset )
  20832. {
  20833. if ( offset !== undefined ) {
  20834. this.c.headerOffset = offset;
  20835. this.update();
  20836. }
  20837. return this.c.headerOffset;
  20838. },
  20839. /**
  20840. * Set footer offset
  20841. *
  20842. * @param {int} new value for footerOffset
  20843. */
  20844. footerOffset: function ( offset )
  20845. {
  20846. if ( offset !== undefined ) {
  20847. this.c.footerOffset = offset;
  20848. this.update();
  20849. }
  20850. return this.c.footerOffset;
  20851. },
  20852. /**
  20853. * Recalculate the position of the fixed elements and force them into place
  20854. */
  20855. update: function ()
  20856. {
  20857. var table = this.s.dt.table().node();
  20858. if ( $(table).is(':visible') ) {
  20859. this.enable( true, false );
  20860. }
  20861. else {
  20862. this.enable( false, false );
  20863. }
  20864. this._positions();
  20865. this._scroll( true );
  20866. },
  20867. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20868. * Constructor
  20869. */
  20870. /**
  20871. * FixedHeader constructor - adding the required event listeners and
  20872. * simple initialisation
  20873. *
  20874. * @private
  20875. */
  20876. _constructor: function ()
  20877. {
  20878. var that = this;
  20879. var dt = this.s.dt;
  20880. $(window)
  20881. .on( 'scroll'+this.s.namespace, function () {
  20882. that._scroll();
  20883. } )
  20884. .on( 'resize'+this.s.namespace, DataTable.util.throttle( function () {
  20885. that.s.position.windowHeight = $(window).height();
  20886. that.update();
  20887. }, 50 ) );
  20888. var autoHeader = $('.fh-fixedHeader');
  20889. if ( ! this.c.headerOffset && autoHeader.length ) {
  20890. this.c.headerOffset = autoHeader.outerHeight();
  20891. }
  20892. var autoFooter = $('.fh-fixedFooter');
  20893. if ( ! this.c.footerOffset && autoFooter.length ) {
  20894. this.c.footerOffset = autoFooter.outerHeight();
  20895. }
  20896. dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function () {
  20897. that.update();
  20898. } );
  20899. dt.on( 'destroy.dtfc', function () {
  20900. that.destroy();
  20901. } );
  20902. this._positions();
  20903. this._scroll();
  20904. },
  20905. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20906. * Private methods
  20907. */
  20908. /**
  20909. * Clone a fixed item to act as a place holder for the original element
  20910. * which is moved into a clone of the table element, and moved around the
  20911. * document to give the fixed effect.
  20912. *
  20913. * @param {string} item 'header' or 'footer'
  20914. * @param {boolean} force Force the clone to happen, or allow automatic
  20915. * decision (reuse existing if available)
  20916. * @private
  20917. */
  20918. _clone: function ( item, force )
  20919. {
  20920. var dt = this.s.dt;
  20921. var itemDom = this.dom[ item ];
  20922. var itemElement = item === 'header' ?
  20923. this.dom.thead :
  20924. this.dom.tfoot;
  20925. if ( ! force && itemDom.floating ) {
  20926. // existing floating element - reuse it
  20927. itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );
  20928. }
  20929. else {
  20930. if ( itemDom.floating ) {
  20931. itemDom.placeholder.remove();
  20932. this._unsize( item );
  20933. itemDom.floating.children().detach();
  20934. itemDom.floating.remove();
  20935. }
  20936. itemDom.floating = $( dt.table().node().cloneNode( false ) )
  20937. .css( 'table-layout', 'fixed' )
  20938. .attr( 'aria-hidden', 'true' )
  20939. .removeAttr( 'id' )
  20940. .append( itemElement )
  20941. .appendTo( 'body' );
  20942. // Insert a fake thead/tfoot into the DataTable to stop it jumping around
  20943. itemDom.placeholder = itemElement.clone( false );
  20944. itemDom.placeholder
  20945. .find( '*[id]' )
  20946. .removeAttr( 'id' );
  20947. itemDom.host.prepend( itemDom.placeholder );
  20948. // Clone widths
  20949. this._matchWidths( itemDom.placeholder, itemDom.floating );
  20950. }
  20951. },
  20952. /**
  20953. * Copy widths from the cells in one element to another. This is required
  20954. * for the footer as the footer in the main table takes its sizes from the
  20955. * header columns. That isn't present in the footer so to have it still
  20956. * align correctly, the sizes need to be copied over. It is also required
  20957. * for the header when auto width is not enabled
  20958. *
  20959. * @param {jQuery} from Copy widths from
  20960. * @param {jQuery} to Copy widths to
  20961. * @private
  20962. */
  20963. _matchWidths: function ( from, to ) {
  20964. var get = function ( name ) {
  20965. return $(name, from)
  20966. .map( function () {
  20967. return $(this).width();
  20968. } ).toArray();
  20969. };
  20970. var set = function ( name, toWidths ) {
  20971. $(name, to).each( function ( i ) {
  20972. $(this).css( {
  20973. width: toWidths[i],
  20974. minWidth: toWidths[i]
  20975. } );
  20976. } );
  20977. };
  20978. var thWidths = get( 'th' );
  20979. var tdWidths = get( 'td' );
  20980. set( 'th', thWidths );
  20981. set( 'td', tdWidths );
  20982. },
  20983. /**
  20984. * Remove assigned widths from the cells in an element. This is required
  20985. * when inserting the footer back into the main table so the size is defined
  20986. * by the header columns and also when auto width is disabled in the
  20987. * DataTable.
  20988. *
  20989. * @param {string} item The `header` or `footer`
  20990. * @private
  20991. */
  20992. _unsize: function ( item ) {
  20993. var el = this.dom[ item ].floating;
  20994. if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {
  20995. $('th, td', el).css( {
  20996. width: '',
  20997. minWidth: ''
  20998. } );
  20999. }
  21000. else if ( el && item === 'header' ) {
  21001. $('th, td', el).css( 'min-width', '' );
  21002. }
  21003. },
  21004. /**
  21005. * Reposition the floating elements to take account of horizontal page
  21006. * scroll
  21007. *
  21008. * @param {string} item The `header` or `footer`
  21009. * @param {int} scrollLeft Document scrollLeft
  21010. * @private
  21011. */
  21012. _horizontal: function ( item, scrollLeft )
  21013. {
  21014. var itemDom = this.dom[ item ];
  21015. var position = this.s.position;
  21016. var lastScrollLeft = this.s.scrollLeft;
  21017. if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {
  21018. itemDom.floating.css( 'left', position.left - scrollLeft );
  21019. lastScrollLeft[ item ] = scrollLeft;
  21020. }
  21021. },
  21022. /**
  21023. * Change from one display mode to another. Each fixed item can be in one
  21024. * of:
  21025. *
  21026. * * `in-place` - In the main DataTable
  21027. * * `in` - Floating over the DataTable
  21028. * * `below` - (Header only) Fixed to the bottom of the table body
  21029. * * `above` - (Footer only) Fixed to the top of the table body
  21030. *
  21031. * @param {string} mode Mode that the item should be shown in
  21032. * @param {string} item 'header' or 'footer'
  21033. * @param {boolean} forceChange Force a redraw of the mode, even if already
  21034. * in that mode.
  21035. * @private
  21036. */
  21037. _modeChange: function ( mode, item, forceChange )
  21038. {
  21039. var dt = this.s.dt;
  21040. var itemDom = this.dom[ item ];
  21041. var position = this.s.position;
  21042. // Record focus. Browser's will cause input elements to loose focus if
  21043. // they are inserted else where in the doc
  21044. var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];
  21045. var focus = $.contains( tablePart[0], document.activeElement ) ?
  21046. document.activeElement :
  21047. null;
  21048. if ( focus ) {
  21049. focus.blur();
  21050. }
  21051. if ( mode === 'in-place' ) {
  21052. // Insert the header back into the table's real header
  21053. if ( itemDom.placeholder ) {
  21054. itemDom.placeholder.remove();
  21055. itemDom.placeholder = null;
  21056. }
  21057. this._unsize( item );
  21058. if ( item === 'header' ) {
  21059. itemDom.host.prepend( tablePart );
  21060. }
  21061. else {
  21062. itemDom.host.append( tablePart );
  21063. }
  21064. if ( itemDom.floating ) {
  21065. itemDom.floating.remove();
  21066. itemDom.floating = null;
  21067. }
  21068. }
  21069. else if ( mode === 'in' ) {
  21070. // Remove the header from the read header and insert into a fixed
  21071. // positioned floating table clone
  21072. this._clone( item, forceChange );
  21073. itemDom.floating
  21074. .addClass( 'fixedHeader-floating' )
  21075. .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )
  21076. .css( 'left', position.left+'px' )
  21077. .css( 'width', position.width+'px' );
  21078. if ( item === 'footer' ) {
  21079. itemDom.floating.css( 'top', '' );
  21080. }
  21081. }
  21082. else if ( mode === 'below' ) { // only used for the header
  21083. // Fix the position of the floating header at base of the table body
  21084. this._clone( item, forceChange );
  21085. itemDom.floating
  21086. .addClass( 'fixedHeader-locked' )
  21087. .css( 'top', position.tfootTop - position.theadHeight )
  21088. .css( 'left', position.left+'px' )
  21089. .css( 'width', position.width+'px' );
  21090. }
  21091. else if ( mode === 'above' ) { // only used for the footer
  21092. // Fix the position of the floating footer at top of the table body
  21093. this._clone( item, forceChange );
  21094. itemDom.floating
  21095. .addClass( 'fixedHeader-locked' )
  21096. .css( 'top', position.tbodyTop )
  21097. .css( 'left', position.left+'px' )
  21098. .css( 'width', position.width+'px' );
  21099. }
  21100. // Restore focus if it was lost
  21101. if ( focus && focus !== document.activeElement ) {
  21102. setTimeout( function () {
  21103. focus.focus();
  21104. }, 10 );
  21105. }
  21106. this.s.scrollLeft.header = -1;
  21107. this.s.scrollLeft.footer = -1;
  21108. this.s[item+'Mode'] = mode;
  21109. },
  21110. /**
  21111. * Cache the positional information that is required for the mode
  21112. * calculations that FixedHeader performs.
  21113. *
  21114. * @private
  21115. */
  21116. _positions: function ()
  21117. {
  21118. var dt = this.s.dt;
  21119. var table = dt.table();
  21120. var position = this.s.position;
  21121. var dom = this.dom;
  21122. var tableNode = $(table.node());
  21123. // Need to use the header and footer that are in the main table,
  21124. // regardless of if they are clones, since they hold the positions we
  21125. // want to measure from
  21126. var thead = tableNode.children('thead');
  21127. var tfoot = tableNode.children('tfoot');
  21128. var tbody = dom.tbody;
  21129. position.visible = tableNode.is(':visible');
  21130. position.width = tableNode.outerWidth();
  21131. position.left = tableNode.offset().left;
  21132. position.theadTop = thead.offset().top;
  21133. position.tbodyTop = tbody.offset().top;
  21134. position.tbodyHeight = tbody.outerHeight();
  21135. position.theadHeight = position.tbodyTop - position.theadTop;
  21136. if ( tfoot.length ) {
  21137. position.tfootTop = tfoot.offset().top;
  21138. position.tfootBottom = position.tfootTop + tfoot.outerHeight();
  21139. position.tfootHeight = position.tfootBottom - position.tfootTop;
  21140. }
  21141. else {
  21142. position.tfootTop = position.tbodyTop + tbody.outerHeight();
  21143. position.tfootBottom = position.tfootTop;
  21144. position.tfootHeight = position.tfootTop;
  21145. }
  21146. },
  21147. /**
  21148. * Mode calculation - determine what mode the fixed items should be placed
  21149. * into.
  21150. *
  21151. * @param {boolean} forceChange Force a redraw of the mode, even if already
  21152. * in that mode.
  21153. * @private
  21154. */
  21155. _scroll: function ( forceChange )
  21156. {
  21157. var windowTop = $(document).scrollTop();
  21158. var windowLeft = $(document).scrollLeft();
  21159. var position = this.s.position;
  21160. var headerMode, footerMode;
  21161. if ( this.c.header ) {
  21162. if ( ! this.s.enable ) {
  21163. headerMode = 'in-place';
  21164. }
  21165. else if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {
  21166. headerMode = 'in-place';
  21167. }
  21168. else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {
  21169. headerMode = 'in';
  21170. }
  21171. else {
  21172. headerMode = 'below';
  21173. }
  21174. if ( forceChange || headerMode !== this.s.headerMode ) {
  21175. this._modeChange( headerMode, 'header', forceChange );
  21176. }
  21177. this._horizontal( 'header', windowLeft );
  21178. }
  21179. if ( this.c.footer && this.dom.tfoot.length ) {
  21180. if ( ! this.s.enable ) {
  21181. headerMode = 'in-place';
  21182. }
  21183. else if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {
  21184. footerMode = 'in-place';
  21185. }
  21186. else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {
  21187. footerMode = 'in';
  21188. }
  21189. else {
  21190. footerMode = 'above';
  21191. }
  21192. if ( forceChange || footerMode !== this.s.footerMode ) {
  21193. this._modeChange( footerMode, 'footer', forceChange );
  21194. }
  21195. this._horizontal( 'footer', windowLeft );
  21196. }
  21197. }
  21198. } );
  21199. /**
  21200. * Version
  21201. * @type {String}
  21202. * @static
  21203. */
  21204. FixedHeader.version = "3.1.6-dev";
  21205. /**
  21206. * Defaults
  21207. * @type {Object}
  21208. * @static
  21209. */
  21210. FixedHeader.defaults = {
  21211. header: true,
  21212. footer: false,
  21213. headerOffset: 0,
  21214. footerOffset: 0
  21215. };
  21216. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21217. * DataTables interfaces
  21218. */
  21219. // Attach for constructor access
  21220. $.fn.dataTable.FixedHeader = FixedHeader;
  21221. $.fn.DataTable.FixedHeader = FixedHeader;
  21222. // DataTables creation - check if the FixedHeader option has been defined on the
  21223. // table and if so, initialise
  21224. $(document).on( 'init.dt.dtfh', function (e, settings, json) {
  21225. if ( e.namespace !== 'dt' ) {
  21226. return;
  21227. }
  21228. var init = settings.oInit.fixedHeader;
  21229. var defaults = DataTable.defaults.fixedHeader;
  21230. if ( (init || defaults) && ! settings._fixedHeader ) {
  21231. var opts = $.extend( {}, defaults, init );
  21232. if ( init !== false ) {
  21233. new FixedHeader( settings, opts );
  21234. }
  21235. }
  21236. } );
  21237. // DataTables API methods
  21238. DataTable.Api.register( 'fixedHeader()', function () {} );
  21239. DataTable.Api.register( 'fixedHeader.adjust()', function () {
  21240. return this.iterator( 'table', function ( ctx ) {
  21241. var fh = ctx._fixedHeader;
  21242. if ( fh ) {
  21243. fh.update();
  21244. }
  21245. } );
  21246. } );
  21247. DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {
  21248. return this.iterator( 'table', function ( ctx ) {
  21249. var fh = ctx._fixedHeader;
  21250. flag = ( flag !== undefined ? flag : true );
  21251. if ( fh && flag !== fh.enabled() ) {
  21252. fh.enable( flag );
  21253. }
  21254. } );
  21255. } );
  21256. DataTable.Api.register( 'fixedHeader.enabled()', function () {
  21257. if ( this.context.length ) {
  21258. var fx = this.content[0]._fixedHeader;
  21259. if ( fh ) {
  21260. return fh.enabled();
  21261. }
  21262. }
  21263. return false;
  21264. } );
  21265. DataTable.Api.register( 'fixedHeader.disable()', function ( ) {
  21266. return this.iterator( 'table', function ( ctx ) {
  21267. var fh = ctx._fixedHeader;
  21268. if ( fh && fh.enabled() ) {
  21269. fh.enable( false );
  21270. }
  21271. } );
  21272. } );
  21273. $.each( ['header', 'footer'], function ( i, el ) {
  21274. DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {
  21275. var ctx = this.context;
  21276. if ( offset === undefined ) {
  21277. return ctx.length && ctx[0]._fixedHeader ?
  21278. ctx[0]._fixedHeader[el +'Offset']() :
  21279. undefined;
  21280. }
  21281. return this.iterator( 'table', function ( ctx ) {
  21282. var fh = ctx._fixedHeader;
  21283. if ( fh ) {
  21284. fh[ el +'Offset' ]( offset );
  21285. }
  21286. } );
  21287. } );
  21288. } );
  21289. return FixedHeader;
  21290. }));
  21291. /*! Bootstrap 4 styling wrapper for FixedHeader
  21292. * ©2018 SpryMedia Ltd - datatables.net/license
  21293. */
  21294. (function( factory ){
  21295. if ( typeof define === 'function' && define.amd ) {
  21296. // AMD
  21297. define( ['jquery', 'datatables.net-bs4', 'datatables.net-fixedheader'], function ( $ ) {
  21298. return factory( $, window, document );
  21299. } );
  21300. }
  21301. else if ( typeof exports === 'object' ) {
  21302. // CommonJS
  21303. module.exports = function (root, $) {
  21304. if ( ! root ) {
  21305. root = window;
  21306. }
  21307. if ( ! $ || ! $.fn.dataTable ) {
  21308. $ = require('datatables.net-bs4')(root, $).$;
  21309. }
  21310. if ( ! $.fn.dataTable.FixedHeader ) {
  21311. require('datatables.net-fixedheader')(root, $);
  21312. }
  21313. return factory( $, root, root.document );
  21314. };
  21315. }
  21316. else {
  21317. // Browser
  21318. factory( jQuery, window, document );
  21319. }
  21320. }(function( $, window, document, undefined ) {
  21321. return $.fn.dataTable;
  21322. }));
  21323. /*! KeyTable 2.5.1
  21324. * ©2009-2019 SpryMedia Ltd - datatables.net/license
  21325. */
  21326. /**
  21327. * @summary KeyTable
  21328. * @description Spreadsheet like keyboard navigation for DataTables
  21329. * @version 2.5.1
  21330. * @file dataTables.keyTable.js
  21331. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  21332. * @contact www.sprymedia.co.uk/contact
  21333. * @copyright Copyright 2009-2019 SpryMedia Ltd.
  21334. *
  21335. * This source file is free software, available under the following license:
  21336. * MIT license - http://datatables.net/license/mit
  21337. *
  21338. * This source file is distributed in the hope that it will be useful, but
  21339. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  21340. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  21341. *
  21342. * For details please refer to: http://www.datatables.net
  21343. */
  21344. (function( factory ){
  21345. if ( typeof define === 'function' && define.amd ) {
  21346. // AMD
  21347. define( ['jquery', 'datatables.net'], function ( $ ) {
  21348. return factory( $, window, document );
  21349. } );
  21350. }
  21351. else if ( typeof exports === 'object' ) {
  21352. // CommonJS
  21353. module.exports = function (root, $) {
  21354. if ( ! root ) {
  21355. root = window;
  21356. }
  21357. if ( ! $ || ! $.fn.dataTable ) {
  21358. $ = require('datatables.net')(root, $).$;
  21359. }
  21360. return factory( $, root, root.document );
  21361. };
  21362. }
  21363. else {
  21364. // Browser
  21365. factory( jQuery, window, document );
  21366. }
  21367. }(function( $, window, document, undefined ) {
  21368. 'use strict';
  21369. var DataTable = $.fn.dataTable;
  21370. var namespaceCounter = 0;
  21371. var KeyTable = function ( dt, opts ) {
  21372. // Sanity check that we are using DataTables 1.10 or newer
  21373. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
  21374. throw 'KeyTable requires DataTables 1.10.8 or newer';
  21375. }
  21376. // User and defaults configuration object
  21377. this.c = $.extend( true, {},
  21378. DataTable.defaults.keyTable,
  21379. KeyTable.defaults,
  21380. opts
  21381. );
  21382. // Internal settings
  21383. this.s = {
  21384. /** @type {DataTable.Api} DataTables' API instance */
  21385. dt: new DataTable.Api( dt ),
  21386. enable: true,
  21387. /** @type {bool} Flag for if a draw is triggered by focus */
  21388. focusDraw: false,
  21389. /** @type {bool} Flag to indicate when waiting for a draw to happen.
  21390. * Will ignore key presses at this point
  21391. */
  21392. waitingForDraw: false,
  21393. /** @type {object} Information about the last cell that was focused */
  21394. lastFocus: null,
  21395. /** @type {string} Unique namespace per instance */
  21396. namespace: '.keyTable-'+(namespaceCounter++)
  21397. };
  21398. // DOM items
  21399. this.dom = {
  21400. };
  21401. // Check if row reorder has already been initialised on this table
  21402. var settings = this.s.dt.settings()[0];
  21403. var exisiting = settings.keytable;
  21404. if ( exisiting ) {
  21405. return exisiting;
  21406. }
  21407. settings.keytable = this;
  21408. this._constructor();
  21409. };
  21410. $.extend( KeyTable.prototype, {
  21411. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21412. * API methods for DataTables API interface
  21413. */
  21414. /**
  21415. * Blur the table's cell focus
  21416. */
  21417. blur: function ()
  21418. {
  21419. this._blur();
  21420. },
  21421. /**
  21422. * Enable cell focus for the table
  21423. *
  21424. * @param {string} state Can be `true`, `false` or `-string navigation-only`
  21425. */
  21426. enable: function ( state )
  21427. {
  21428. this.s.enable = state;
  21429. },
  21430. /**
  21431. * Focus on a cell
  21432. * @param {integer} row Row index
  21433. * @param {integer} column Column index
  21434. */
  21435. focus: function ( row, column )
  21436. {
  21437. this._focus( this.s.dt.cell( row, column ) );
  21438. },
  21439. /**
  21440. * Is the cell focused
  21441. * @param {object} cell Cell index to check
  21442. * @returns {boolean} true if focused, false otherwise
  21443. */
  21444. focused: function ( cell )
  21445. {
  21446. var lastFocus = this.s.lastFocus;
  21447. if ( ! lastFocus ) {
  21448. return false;
  21449. }
  21450. var lastIdx = this.s.lastFocus.cell.index();
  21451. return cell.row === lastIdx.row && cell.column === lastIdx.column;
  21452. },
  21453. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21454. * Constructor
  21455. */
  21456. /**
  21457. * Initialise the KeyTable instance
  21458. *
  21459. * @private
  21460. */
  21461. _constructor: function ()
  21462. {
  21463. this._tabInput();
  21464. var that = this;
  21465. var dt = this.s.dt;
  21466. var table = $( dt.table().node() );
  21467. var namespace = this.s.namespace;
  21468. var editorBlock = false;
  21469. // Need to be able to calculate the cell positions relative to the table
  21470. if ( table.css('position') === 'static' ) {
  21471. table.css( 'position', 'relative' );
  21472. }
  21473. // Click to focus
  21474. $( dt.table().body() ).on( 'click'+namespace, 'th, td', function (e) {
  21475. if ( that.s.enable === false ) {
  21476. return;
  21477. }
  21478. var cell = dt.cell( this );
  21479. if ( ! cell.any() ) {
  21480. return;
  21481. }
  21482. that._focus( cell, null, false, e );
  21483. } );
  21484. // Key events
  21485. $( document ).on( 'keydown'+namespace, function (e) {
  21486. if ( ! editorBlock ) {
  21487. that._key( e );
  21488. }
  21489. } );
  21490. // Click blur
  21491. if ( this.c.blurable ) {
  21492. $( document ).on( 'mousedown'+namespace, function ( e ) {
  21493. // Click on the search input will blur focus
  21494. if ( $(e.target).parents( '.dataTables_filter' ).length ) {
  21495. that._blur();
  21496. }
  21497. // If the click was inside the DataTables container, don't blur
  21498. if ( $(e.target).parents().filter( dt.table().container() ).length ) {
  21499. return;
  21500. }
  21501. // Don't blur in Editor form
  21502. if ( $(e.target).parents('div.DTE').length ) {
  21503. return;
  21504. }
  21505. // Or an Editor date input
  21506. if ( $(e.target).parents('div.editor-datetime').length ) {
  21507. return;
  21508. }
  21509. //If the click was inside the fixed columns container, don't blur
  21510. if ( $(e.target).parents().filter('.DTFC_Cloned').length ) {
  21511. return;
  21512. }
  21513. that._blur();
  21514. } );
  21515. }
  21516. if ( this.c.editor ) {
  21517. var editor = this.c.editor;
  21518. // Need to disable KeyTable when the main editor is shown
  21519. editor.on( 'open.keyTableMain', function (e, mode, action) {
  21520. if ( mode !== 'inline' && that.s.enable ) {
  21521. that.enable( false );
  21522. editor.one( 'close'+namespace, function () {
  21523. that.enable( true );
  21524. } );
  21525. }
  21526. } );
  21527. if ( this.c.editOnFocus ) {
  21528. dt.on( 'key-focus'+namespace+' key-refocus'+namespace, function ( e, dt, cell, orig ) {
  21529. that._editor( null, orig, true );
  21530. } );
  21531. }
  21532. // Activate Editor when a key is pressed (will be ignored, if
  21533. // already active).
  21534. dt.on( 'key'+namespace, function ( e, dt, key, cell, orig ) {
  21535. that._editor( key, orig, false );
  21536. } );
  21537. // Active editing on double click - it will already have focus from
  21538. // the click event handler above
  21539. $( dt.table().body() ).on( 'dblclick'+namespace, 'th, td', function (e) {
  21540. if ( that.s.enable === false ) {
  21541. return;
  21542. }
  21543. var cell = dt.cell( this );
  21544. if ( ! cell.any() ) {
  21545. return;
  21546. }
  21547. that._editor( null, e, true );
  21548. } );
  21549. // While Editor is busy processing, we don't want to process any key events
  21550. editor
  21551. .on('preSubmit', function () {
  21552. editorBlock = true;
  21553. } )
  21554. .on('preSubmitCancelled', function () {
  21555. editorBlock = false;
  21556. } )
  21557. .on('submitComplete', function () {
  21558. editorBlock = false;
  21559. } );
  21560. }
  21561. // Stave saving
  21562. if ( dt.settings()[0].oFeatures.bStateSave ) {
  21563. dt.on( 'stateSaveParams'+namespace, function (e, s, d) {
  21564. d.keyTable = that.s.lastFocus ?
  21565. that.s.lastFocus.cell.index() :
  21566. null;
  21567. } );
  21568. }
  21569. // Redraw - retain focus on the current cell
  21570. dt.on( 'draw'+namespace, function (e) {
  21571. if ( that.s.focusDraw ) {
  21572. return;
  21573. }
  21574. var lastFocus = that.s.lastFocus;
  21575. if ( lastFocus && lastFocus.node && $(lastFocus.node).closest('body') === document.body ) {
  21576. var relative = that.s.lastFocus.relative;
  21577. var info = dt.page.info();
  21578. var row = relative.row + info.start;
  21579. if ( info.recordsDisplay === 0 ) {
  21580. return;
  21581. }
  21582. // Reverse if needed
  21583. if ( row >= info.recordsDisplay ) {
  21584. row = info.recordsDisplay - 1;
  21585. }
  21586. that._focus( row, relative.column, true, e );
  21587. }
  21588. } );
  21589. // Clipboard support
  21590. if ( this.c.clipboard ) {
  21591. this._clipboard();
  21592. }
  21593. dt.on( 'destroy'+namespace, function () {
  21594. that._blur( true );
  21595. // Event tidy up
  21596. dt.off( namespace );
  21597. $( dt.table().body() )
  21598. .off( 'click'+namespace, 'th, td' )
  21599. .off( 'dblclick'+namespace, 'th, td' );
  21600. $( document )
  21601. .off( 'mousedown'+namespace )
  21602. .off( 'keydown'+namespace )
  21603. .off( 'copy'+namespace )
  21604. .off( 'paste'+namespace );
  21605. } );
  21606. // Initial focus comes from state or options
  21607. var state = dt.state.loaded();
  21608. if ( state && state.keyTable ) {
  21609. // Wait until init is done
  21610. dt.one( 'init', function () {
  21611. var cell = dt.cell( state.keyTable );
  21612. // Ensure that the saved cell still exists
  21613. if ( cell.any() ) {
  21614. cell.focus();
  21615. }
  21616. } );
  21617. }
  21618. else if ( this.c.focus ) {
  21619. dt.cell( this.c.focus ).focus();
  21620. }
  21621. },
  21622. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21623. * Private methods
  21624. */
  21625. /**
  21626. * Blur the control
  21627. *
  21628. * @param {boolean} [noEvents=false] Don't trigger updates / events (for destroying)
  21629. * @private
  21630. */
  21631. _blur: function (noEvents)
  21632. {
  21633. if ( ! this.s.enable || ! this.s.lastFocus ) {
  21634. return;
  21635. }
  21636. var cell = this.s.lastFocus.cell;
  21637. $( cell.node() ).removeClass( this.c.className );
  21638. this.s.lastFocus = null;
  21639. if ( ! noEvents ) {
  21640. this._updateFixedColumns(cell.index().column);
  21641. this._emitEvent( 'key-blur', [ this.s.dt, cell ] );
  21642. }
  21643. },
  21644. /**
  21645. * Clipboard interaction handlers
  21646. *
  21647. * @private
  21648. */
  21649. _clipboard: function () {
  21650. var dt = this.s.dt;
  21651. var that = this;
  21652. var namespace = this.s.namespace;
  21653. // IE8 doesn't support getting selected text
  21654. if ( ! window.getSelection ) {
  21655. return;
  21656. }
  21657. $(document).on( 'copy'+namespace, function (ejq) {
  21658. var e = ejq.originalEvent;
  21659. var selection = window.getSelection().toString();
  21660. var focused = that.s.lastFocus;
  21661. // Only copy cell text to clipboard if there is no other selection
  21662. // and there is a focused cell
  21663. if ( ! selection && focused ) {
  21664. e.clipboardData.setData(
  21665. 'text/plain',
  21666. focused.cell.render( that.c.clipboardOrthogonal )
  21667. );
  21668. e.preventDefault();
  21669. }
  21670. } );
  21671. $(document).on( 'paste'+namespace, function (ejq) {
  21672. var e = ejq.originalEvent;
  21673. var focused = that.s.lastFocus;
  21674. var activeEl = document.activeElement;
  21675. var editor = that.c.editor;
  21676. var pastedText;
  21677. if ( focused && (! activeEl || activeEl.nodeName.toLowerCase() === 'body') ) {
  21678. e.preventDefault();
  21679. if ( window.clipboardData && window.clipboardData.getData ) {
  21680. // IE
  21681. pastedText = window.clipboardData.getData('Text');
  21682. }
  21683. else if ( e.clipboardData && e.clipboardData.getData ) {
  21684. // Everything else
  21685. pastedText = e.clipboardData.getData('text/plain');
  21686. }
  21687. if ( editor ) {
  21688. // Got Editor - need to activate inline editing,
  21689. // set the value and submit
  21690. editor
  21691. .inline( focused.cell.index() )
  21692. .set( editor.displayed()[0], pastedText )
  21693. .submit();
  21694. }
  21695. else {
  21696. // No editor, so just dump the data in
  21697. focused.cell.data( pastedText );
  21698. dt.draw(false);
  21699. }
  21700. }
  21701. } );
  21702. },
  21703. /**
  21704. * Get an array of the column indexes that KeyTable can operate on. This
  21705. * is a merge of the user supplied columns and the visible columns.
  21706. *
  21707. * @private
  21708. */
  21709. _columns: function ()
  21710. {
  21711. var dt = this.s.dt;
  21712. var user = dt.columns( this.c.columns ).indexes();
  21713. var out = [];
  21714. dt.columns( ':visible' ).every( function (i) {
  21715. if ( user.indexOf( i ) !== -1 ) {
  21716. out.push( i );
  21717. }
  21718. } );
  21719. return out;
  21720. },
  21721. /**
  21722. * Perform excel like navigation for Editor by triggering an edit on key
  21723. * press
  21724. *
  21725. * @param {integer} key Key code for the pressed key
  21726. * @param {object} orig Original event
  21727. * @private
  21728. */
  21729. _editor: function ( key, orig, hardEdit )
  21730. {
  21731. var that = this;
  21732. var dt = this.s.dt;
  21733. var editor = this.c.editor;
  21734. var editCell = this.s.lastFocus.cell;
  21735. var namespace = this.s.namespace;
  21736. // Do nothing if there is already an inline edit in this cell
  21737. if ( $('div.DTE', editCell.node()).length ) {
  21738. return;
  21739. }
  21740. // Don't activate Editor on control key presses
  21741. if ( key !== null && (
  21742. (key >= 0x00 && key <= 0x09) ||
  21743. key === 0x0b ||
  21744. key === 0x0c ||
  21745. (key >= 0x0e && key <= 0x1f) ||
  21746. (key >= 0x70 && key <= 0x7b) ||
  21747. (key >= 0x7f && key <= 0x9f)
  21748. ) ) {
  21749. return;
  21750. }
  21751. orig.stopPropagation();
  21752. // Return key should do nothing - for textareas it would empty the
  21753. // contents
  21754. if ( key === 13 ) {
  21755. orig.preventDefault();
  21756. }
  21757. var editInline = function () {
  21758. editor
  21759. .one( 'open'+namespace, function () {
  21760. // Remove cancel open
  21761. editor.off( 'cancelOpen'+namespace );
  21762. // Excel style - select all text
  21763. if ( ! hardEdit ) {
  21764. $('div.DTE_Field_InputControl input, div.DTE_Field_InputControl textarea').select();
  21765. }
  21766. // Reduce the keys the Keys listens for
  21767. dt.keys.enable( hardEdit ? 'tab-only' : 'navigation-only' );
  21768. // On blur of the navigation submit
  21769. dt.on( 'key-blur.editor', function (e, dt, cell) {
  21770. if ( editor.displayed() && cell.node() === editCell.node() ) {
  21771. editor.submit();
  21772. }
  21773. } );
  21774. // Highlight the cell a different colour on full edit
  21775. if ( hardEdit ) {
  21776. $( dt.table().container() ).addClass('dtk-focus-alt');
  21777. }
  21778. // If the dev cancels the submit, we need to return focus
  21779. editor.on( 'preSubmitCancelled'+namespace, function () {
  21780. setTimeout( function () {
  21781. that._focus( editCell, null, false );
  21782. }, 50 );
  21783. } );
  21784. editor.on( 'submitUnsuccessful'+namespace, function () {
  21785. that._focus( editCell, null, false );
  21786. } );
  21787. // Restore full key navigation on close
  21788. editor.one( 'close', function () {
  21789. dt.keys.enable( true );
  21790. dt.off( 'key-blur.editor' );
  21791. editor.off( namespace );
  21792. $( dt.table().container() ).removeClass('dtk-focus-alt');
  21793. } );
  21794. } )
  21795. .one( 'cancelOpen'+namespace, function () {
  21796. // `preOpen` can cancel the display of the form, so it
  21797. // might be that the open event handler isn't needed
  21798. editor.off( namespace );
  21799. } )
  21800. .inline( editCell.index() );
  21801. };
  21802. // Editor 1.7 listens for `return` on keyup, so if return is the trigger
  21803. // key, we need to wait for `keyup` otherwise Editor would just submit
  21804. // the content triggered by this keypress.
  21805. if ( key === 13 ) {
  21806. hardEdit = true;
  21807. $(document).one( 'keyup', function () { // immediately removed
  21808. editInline();
  21809. } );
  21810. }
  21811. else {
  21812. editInline();
  21813. }
  21814. },
  21815. /**
  21816. * Emit an event on the DataTable for listeners
  21817. *
  21818. * @param {string} name Event name
  21819. * @param {array} args Event arguments
  21820. * @private
  21821. */
  21822. _emitEvent: function ( name, args )
  21823. {
  21824. this.s.dt.iterator( 'table', function ( ctx, i ) {
  21825. $(ctx.nTable).triggerHandler( name, args );
  21826. } );
  21827. },
  21828. /**
  21829. * Focus on a particular cell, shifting the table's paging if required
  21830. *
  21831. * @param {DataTables.Api|integer} row Can be given as an API instance that
  21832. * contains the cell to focus or as an integer. As the latter it is the
  21833. * visible row index (from the whole data set) - NOT the data index
  21834. * @param {integer} [column] Not required if a cell is given as the first
  21835. * parameter. Otherwise this is the column data index for the cell to
  21836. * focus on
  21837. * @param {boolean} [shift=true] Should the viewport be moved to show cell
  21838. * @private
  21839. */
  21840. _focus: function ( row, column, shift, originalEvent )
  21841. {
  21842. var that = this;
  21843. var dt = this.s.dt;
  21844. var pageInfo = dt.page.info();
  21845. var lastFocus = this.s.lastFocus;
  21846. if ( ! originalEvent) {
  21847. originalEvent = null;
  21848. }
  21849. if ( ! this.s.enable ) {
  21850. return;
  21851. }
  21852. if ( typeof row !== 'number' ) {
  21853. // Its an API instance - check that there is actually a row
  21854. if ( ! row.any() ) {
  21855. return;
  21856. }
  21857. // Convert the cell to a row and column
  21858. var index = row.index();
  21859. column = index.column;
  21860. row = dt
  21861. .rows( { filter: 'applied', order: 'applied' } )
  21862. .indexes()
  21863. .indexOf( index.row );
  21864. // Don't focus rows that were filtered out.
  21865. if ( row < 0 ) {
  21866. return;
  21867. }
  21868. // For server-side processing normalise the row by adding the start
  21869. // point, since `rows().indexes()` includes only rows that are
  21870. // available at the client-side
  21871. if ( pageInfo.serverSide ) {
  21872. row += pageInfo.start;
  21873. }
  21874. }
  21875. // Is the row on the current page? If not, we need to redraw to show the
  21876. // page
  21877. if ( pageInfo.length !== -1 && (row < pageInfo.start || row >= pageInfo.start+pageInfo.length) ) {
  21878. this.s.focusDraw = true;
  21879. this.s.waitingForDraw = true;
  21880. dt
  21881. .one( 'draw', function () {
  21882. that.s.focusDraw = false;
  21883. that.s.waitingForDraw = false;
  21884. that._focus( row, column, undefined, originalEvent );
  21885. } )
  21886. .page( Math.floor( row / pageInfo.length ) )
  21887. .draw( false );
  21888. return;
  21889. }
  21890. // In the available columns?
  21891. if ( $.inArray( column, this._columns() ) === -1 ) {
  21892. return;
  21893. }
  21894. // De-normalise the server-side processing row, so we select the row
  21895. // in its displayed position
  21896. if ( pageInfo.serverSide ) {
  21897. row -= pageInfo.start;
  21898. }
  21899. // Get the cell from the current position - ignoring any cells which might
  21900. // not have been rendered (therefore can't use `:eq()` selector).
  21901. var cells = dt.cells( null, column, {search: 'applied', order: 'applied'} ).flatten();
  21902. var cell = dt.cell( cells[ row ] );
  21903. if ( lastFocus ) {
  21904. // Don't trigger a refocus on the same cell
  21905. if ( lastFocus.node === cell.node() ) {
  21906. this._emitEvent( 'key-refocus', [ this.s.dt, cell, originalEvent || null ] );
  21907. return;
  21908. }
  21909. // Otherwise blur the old focus
  21910. this._blur();
  21911. }
  21912. // Clear focus from other tables
  21913. this._removeOtherFocus();
  21914. var node = $( cell.node() );
  21915. node.addClass( this.c.className );
  21916. this._updateFixedColumns(column);
  21917. // Shift viewpoint and page to make cell visible
  21918. if ( shift === undefined || shift === true ) {
  21919. this._scroll( $(window), $(document.body), node, 'offset' );
  21920. var bodyParent = dt.table().body().parentNode;
  21921. if ( bodyParent !== dt.table().header().parentNode ) {
  21922. var parent = $(bodyParent.parentNode);
  21923. this._scroll( parent, parent, node, 'position' );
  21924. }
  21925. }
  21926. // Event and finish
  21927. this.s.lastFocus = {
  21928. cell: cell,
  21929. node: cell.node(),
  21930. relative: {
  21931. row: dt.rows( { page: 'current' } ).indexes().indexOf( cell.index().row ),
  21932. column: cell.index().column
  21933. }
  21934. };
  21935. this._emitEvent( 'key-focus', [ this.s.dt, cell, originalEvent || null ] );
  21936. dt.state.save();
  21937. },
  21938. /**
  21939. * Handle key press
  21940. *
  21941. * @param {object} e Event
  21942. * @private
  21943. */
  21944. _key: function ( e )
  21945. {
  21946. // If we are waiting for a draw to happen from another key event, then
  21947. // do nothing for this new key press.
  21948. if ( this.s.waitingForDraw ) {
  21949. e.preventDefault();
  21950. return;
  21951. }
  21952. var enable = this.s.enable;
  21953. var navEnable = enable === true || enable === 'navigation-only';
  21954. if ( ! enable ) {
  21955. return;
  21956. }
  21957. if ( (e.keyCode === 0 || e.ctrlKey || e.metaKey || e.altKey) && !(e.ctrlKey && e.altKey) ) {
  21958. return;
  21959. }
  21960. // If not focused, then there is no key action to take
  21961. var lastFocus = this.s.lastFocus;
  21962. if ( ! lastFocus ) {
  21963. return;
  21964. }
  21965. // And the last focus still exists!
  21966. if ( ! this.s.dt.cell(lastFocus.node).any() ) {
  21967. this.s.lastFocus = null;
  21968. return;
  21969. }
  21970. var that = this;
  21971. var dt = this.s.dt;
  21972. var scrolling = this.s.dt.settings()[0].oScroll.sY ? true : false;
  21973. // If we are not listening for this key, do nothing
  21974. if ( this.c.keys && $.inArray( e.keyCode, this.c.keys ) === -1 ) {
  21975. return;
  21976. }
  21977. switch( e.keyCode ) {
  21978. case 9: // tab
  21979. // `enable` can be tab-only
  21980. this._shift( e, e.shiftKey ? 'left' : 'right', true );
  21981. break;
  21982. case 27: // esc
  21983. if ( this.s.blurable && enable === true ) {
  21984. this._blur();
  21985. }
  21986. break;
  21987. case 33: // page up (previous page)
  21988. case 34: // page down (next page)
  21989. if ( navEnable && !scrolling ) {
  21990. e.preventDefault();
  21991. dt
  21992. .page( e.keyCode === 33 ? 'previous' : 'next' )
  21993. .draw( false );
  21994. }
  21995. break;
  21996. case 35: // end (end of current page)
  21997. case 36: // home (start of current page)
  21998. if ( navEnable ) {
  21999. e.preventDefault();
  22000. var indexes = dt.cells( {page: 'current'} ).indexes();
  22001. var colIndexes = this._columns();
  22002. this._focus( dt.cell(
  22003. indexes[ e.keyCode === 35 ? indexes.length-1 : colIndexes[0] ]
  22004. ), null, true, e );
  22005. }
  22006. break;
  22007. case 37: // left arrow
  22008. if ( navEnable ) {
  22009. this._shift( e, 'left' );
  22010. }
  22011. break;
  22012. case 38: // up arrow
  22013. if ( navEnable ) {
  22014. this._shift( e, 'up' );
  22015. }
  22016. break;
  22017. case 39: // right arrow
  22018. if ( navEnable ) {
  22019. this._shift( e, 'right' );
  22020. }
  22021. break;
  22022. case 40: // down arrow
  22023. if ( navEnable ) {
  22024. this._shift( e, 'down' );
  22025. }
  22026. break;
  22027. case 113: // F2 - Excel like hard edit
  22028. if ( this.c.editor ) {
  22029. this._editor(null, e, true);
  22030. break;
  22031. }
  22032. // else fallthrough
  22033. default:
  22034. // Everything else - pass through only when fully enabled
  22035. if ( enable === true ) {
  22036. this._emitEvent( 'key', [ dt, e.keyCode, this.s.lastFocus.cell, e ] );
  22037. }
  22038. break;
  22039. }
  22040. },
  22041. /**
  22042. * Remove focus from all tables other than this one
  22043. */
  22044. _removeOtherFocus: function ()
  22045. {
  22046. var thisTable = this.s.dt.table().node();
  22047. $.fn.dataTable.tables({api:true}).iterator('table', function (settings) {
  22048. if (this.table().node() !== thisTable) {
  22049. this.cell.blur();
  22050. }
  22051. });
  22052. },
  22053. /**
  22054. * Scroll a container to make a cell visible in it. This can be used for
  22055. * both DataTables scrolling and native window scrolling.
  22056. *
  22057. * @param {jQuery} container Scrolling container
  22058. * @param {jQuery} scroller Item being scrolled
  22059. * @param {jQuery} cell Cell in the scroller
  22060. * @param {string} posOff `position` or `offset` - which to use for the
  22061. * calculation. `offset` for the document, otherwise `position`
  22062. * @private
  22063. */
  22064. _scroll: function ( container, scroller, cell, posOff )
  22065. {
  22066. var offset = cell[posOff]();
  22067. var height = cell.outerHeight();
  22068. var width = cell.outerWidth();
  22069. var scrollTop = scroller.scrollTop();
  22070. var scrollLeft = scroller.scrollLeft();
  22071. var containerHeight = container.height();
  22072. var containerWidth = container.width();
  22073. // If Scroller is being used, the table can be `position: absolute` and that
  22074. // needs to be taken account of in the offset. If no Scroller, this will be 0
  22075. if ( posOff === 'position' ) {
  22076. offset.top += parseInt( cell.closest('table').css('top'), 10 );
  22077. }
  22078. // Top correction
  22079. if ( offset.top < scrollTop ) {
  22080. scroller.scrollTop( offset.top );
  22081. }
  22082. // Left correction
  22083. if ( offset.left < scrollLeft ) {
  22084. scroller.scrollLeft( offset.left );
  22085. }
  22086. // Bottom correction
  22087. if ( offset.top + height > scrollTop + containerHeight && height < containerHeight ) {
  22088. scroller.scrollTop( offset.top + height - containerHeight );
  22089. }
  22090. // Right correction
  22091. if ( offset.left + width > scrollLeft + containerWidth && width < containerWidth ) {
  22092. scroller.scrollLeft( offset.left + width - containerWidth );
  22093. }
  22094. },
  22095. /**
  22096. * Calculate a single offset movement in the table - up, down, left and
  22097. * right and then perform the focus if possible
  22098. *
  22099. * @param {object} e Event object
  22100. * @param {string} direction Movement direction
  22101. * @param {boolean} keyBlurable `true` if the key press can result in the
  22102. * table being blurred. This is so arrow keys won't blur the table, but
  22103. * tab will.
  22104. * @private
  22105. */
  22106. _shift: function ( e, direction, keyBlurable )
  22107. {
  22108. var that = this;
  22109. var dt = this.s.dt;
  22110. var pageInfo = dt.page.info();
  22111. var rows = pageInfo.recordsDisplay;
  22112. var currentCell = this.s.lastFocus.cell;
  22113. var columns = this._columns();
  22114. if ( ! currentCell ) {
  22115. return;
  22116. }
  22117. var currRow = dt
  22118. .rows( { filter: 'applied', order: 'applied' } )
  22119. .indexes()
  22120. .indexOf( currentCell.index().row );
  22121. // When server-side processing, `rows().indexes()` only gives the rows
  22122. // that are available at the client-side, so we need to normalise the
  22123. // row's current position by the display start point
  22124. if ( pageInfo.serverSide ) {
  22125. currRow += pageInfo.start;
  22126. }
  22127. var currCol = dt
  22128. .columns( columns )
  22129. .indexes()
  22130. .indexOf( currentCell.index().column );
  22131. var
  22132. row = currRow,
  22133. column = columns[ currCol ]; // row is the display, column is an index
  22134. if ( direction === 'right' ) {
  22135. if ( currCol >= columns.length - 1 ) {
  22136. row++;
  22137. column = columns[0];
  22138. }
  22139. else {
  22140. column = columns[ currCol+1 ];
  22141. }
  22142. }
  22143. else if ( direction === 'left' ) {
  22144. if ( currCol === 0 ) {
  22145. row--;
  22146. column = columns[ columns.length - 1 ];
  22147. }
  22148. else {
  22149. column = columns[ currCol-1 ];
  22150. }
  22151. }
  22152. else if ( direction === 'up' ) {
  22153. row--;
  22154. }
  22155. else if ( direction === 'down' ) {
  22156. row++;
  22157. }
  22158. if ( row >= 0 && row < rows && $.inArray( column, columns ) !== -1 ) {
  22159. if (e) {
  22160. e.preventDefault();
  22161. }
  22162. this._focus( row, column, true, e );
  22163. }
  22164. else if ( ! keyBlurable || ! this.c.blurable ) {
  22165. // No new focus, but if the table isn't blurable, then don't loose
  22166. // focus
  22167. if (e) {
  22168. e.preventDefault();
  22169. }
  22170. }
  22171. else {
  22172. this._blur();
  22173. }
  22174. },
  22175. /**
  22176. * Create a hidden input element that can receive focus on behalf of the
  22177. * table
  22178. *
  22179. * @private
  22180. */
  22181. _tabInput: function ()
  22182. {
  22183. var that = this;
  22184. var dt = this.s.dt;
  22185. var tabIndex = this.c.tabIndex !== null ?
  22186. this.c.tabIndex :
  22187. dt.settings()[0].iTabIndex;
  22188. if ( tabIndex == -1 ) {
  22189. return;
  22190. }
  22191. var div = $('<div><input type="text" tabindex="'+tabIndex+'"/></div>')
  22192. .css( {
  22193. position: 'absolute',
  22194. height: 1,
  22195. width: 0,
  22196. overflow: 'hidden'
  22197. } )
  22198. .insertBefore( dt.table().node() );
  22199. div.children().on( 'focus', function (e) {
  22200. var cell = dt.cell(':eq(0)', that._columns(), {page: 'current'});
  22201. if ( cell.any() ) {
  22202. that._focus( cell, null, true, e );
  22203. }
  22204. } );
  22205. },
  22206. /**
  22207. * Update fixed columns if they are enabled and if the cell we are
  22208. * focusing is inside a fixed column
  22209. * @param {integer} column Index of the column being changed
  22210. * @private
  22211. */
  22212. _updateFixedColumns: function( column )
  22213. {
  22214. var dt = this.s.dt;
  22215. var settings = dt.settings()[0];
  22216. if ( settings._oFixedColumns ) {
  22217. var leftCols = settings._oFixedColumns.s.iLeftColumns;
  22218. var rightCols = settings.aoColumns.length - settings._oFixedColumns.s.iRightColumns;
  22219. if (column < leftCols || column >= rightCols) {
  22220. dt.fixedColumns().update();
  22221. }
  22222. }
  22223. }
  22224. } );
  22225. /**
  22226. * KeyTable default settings for initialisation
  22227. *
  22228. * @namespace
  22229. * @name KeyTable.defaults
  22230. * @static
  22231. */
  22232. KeyTable.defaults = {
  22233. /**
  22234. * Can focus be removed from the table
  22235. * @type {Boolean}
  22236. */
  22237. blurable: true,
  22238. /**
  22239. * Class to give to the focused cell
  22240. * @type {String}
  22241. */
  22242. className: 'focus',
  22243. /**
  22244. * Enable or disable clipboard support
  22245. * @type {Boolean}
  22246. */
  22247. clipboard: true,
  22248. /**
  22249. * Orthogonal data that should be copied to clipboard
  22250. * @type {string}
  22251. */
  22252. clipboardOrthogonal: 'display',
  22253. /**
  22254. * Columns that can be focused. This is automatically merged with the
  22255. * visible columns as only visible columns can gain focus.
  22256. * @type {String}
  22257. */
  22258. columns: '', // all
  22259. /**
  22260. * Editor instance to automatically perform Excel like navigation
  22261. * @type {Editor}
  22262. */
  22263. editor: null,
  22264. /**
  22265. * Trigger editing immediately on focus
  22266. * @type {boolean}
  22267. */
  22268. editOnFocus: false,
  22269. /**
  22270. * Select a cell to automatically select on start up. `null` for no
  22271. * automatic selection
  22272. * @type {cell-selector}
  22273. */
  22274. focus: null,
  22275. /**
  22276. * Array of keys to listen for
  22277. * @type {null|array}
  22278. */
  22279. keys: null,
  22280. /**
  22281. * Tab index for where the table should sit in the document's tab flow
  22282. * @type {integer|null}
  22283. */
  22284. tabIndex: null
  22285. };
  22286. KeyTable.version = "2.5.1";
  22287. $.fn.dataTable.KeyTable = KeyTable;
  22288. $.fn.DataTable.KeyTable = KeyTable;
  22289. DataTable.Api.register( 'cell.blur()', function () {
  22290. return this.iterator( 'table', function (ctx) {
  22291. if ( ctx.keytable ) {
  22292. ctx.keytable.blur();
  22293. }
  22294. } );
  22295. } );
  22296. DataTable.Api.register( 'cell().focus()', function () {
  22297. return this.iterator( 'cell', function (ctx, row, column) {
  22298. if ( ctx.keytable ) {
  22299. ctx.keytable.focus( row, column );
  22300. }
  22301. } );
  22302. } );
  22303. DataTable.Api.register( 'keys.disable()', function () {
  22304. return this.iterator( 'table', function (ctx) {
  22305. if ( ctx.keytable ) {
  22306. ctx.keytable.enable( false );
  22307. }
  22308. } );
  22309. } );
  22310. DataTable.Api.register( 'keys.enable()', function ( opts ) {
  22311. return this.iterator( 'table', function (ctx) {
  22312. if ( ctx.keytable ) {
  22313. ctx.keytable.enable( opts === undefined ? true : opts );
  22314. }
  22315. } );
  22316. } );
  22317. DataTable.Api.register( 'keys.move()', function ( dir ) {
  22318. return this.iterator( 'table', function (ctx) {
  22319. if ( ctx.keytable ) {
  22320. ctx.keytable._shift( null, dir, false );
  22321. }
  22322. } );
  22323. } );
  22324. // Cell selector
  22325. DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
  22326. var focused = opts.focused;
  22327. var kt = settings.keytable;
  22328. var out = [];
  22329. if ( ! kt || focused === undefined ) {
  22330. return cells;
  22331. }
  22332. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  22333. if ( (focused === true && kt.focused( cells[i] ) ) ||
  22334. (focused === false && ! kt.focused( cells[i] ) )
  22335. ) {
  22336. out.push( cells[i] );
  22337. }
  22338. }
  22339. return out;
  22340. } );
  22341. // Attach a listener to the document which listens for DataTables initialisation
  22342. // events so we can automatically initialise
  22343. $(document).on( 'preInit.dt.dtk', function (e, settings, json) {
  22344. if ( e.namespace !== 'dt' ) {
  22345. return;
  22346. }
  22347. var init = settings.oInit.keys;
  22348. var defaults = DataTable.defaults.keys;
  22349. if ( init || defaults ) {
  22350. var opts = $.extend( {}, defaults, init );
  22351. if ( init !== false ) {
  22352. new KeyTable( settings, opts );
  22353. }
  22354. }
  22355. } );
  22356. return KeyTable;
  22357. }));
  22358. /*! Bootstrap 4 styling wrapper for KeyTable
  22359. * ©2018 SpryMedia Ltd - datatables.net/license
  22360. */
  22361. (function( factory ){
  22362. if ( typeof define === 'function' && define.amd ) {
  22363. // AMD
  22364. define( ['jquery', 'datatables.net-bs4', 'datatables.net-keytable'], function ( $ ) {
  22365. return factory( $, window, document );
  22366. } );
  22367. }
  22368. else if ( typeof exports === 'object' ) {
  22369. // CommonJS
  22370. module.exports = function (root, $) {
  22371. if ( ! root ) {
  22372. root = window;
  22373. }
  22374. if ( ! $ || ! $.fn.dataTable ) {
  22375. $ = require('datatables.net-bs4')(root, $).$;
  22376. }
  22377. if ( ! $.fn.dataTable.KeyTable ) {
  22378. require('datatables.net-keytable')(root, $);
  22379. }
  22380. return factory( $, root, root.document );
  22381. };
  22382. }
  22383. else {
  22384. // Browser
  22385. factory( jQuery, window, document );
  22386. }
  22387. }(function( $, window, document, undefined ) {
  22388. return $.fn.dataTable;
  22389. }));
  22390. /*! Responsive 2.2.3
  22391. * 2014-2018 SpryMedia Ltd - datatables.net/license
  22392. */
  22393. /**
  22394. * @summary Responsive
  22395. * @description Responsive tables plug-in for DataTables
  22396. * @version 2.2.3
  22397. * @file dataTables.responsive.js
  22398. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  22399. * @contact www.sprymedia.co.uk/contact
  22400. * @copyright Copyright 2014-2018 SpryMedia Ltd.
  22401. *
  22402. * This source file is free software, available under the following license:
  22403. * MIT license - http://datatables.net/license/mit
  22404. *
  22405. * This source file is distributed in the hope that it will be useful, but
  22406. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  22407. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  22408. *
  22409. * For details please refer to: http://www.datatables.net
  22410. */
  22411. (function( factory ){
  22412. if ( typeof define === 'function' && define.amd ) {
  22413. // AMD
  22414. define( ['jquery', 'datatables.net'], function ( $ ) {
  22415. return factory( $, window, document );
  22416. } );
  22417. }
  22418. else if ( typeof exports === 'object' ) {
  22419. // CommonJS
  22420. module.exports = function (root, $) {
  22421. if ( ! root ) {
  22422. root = window;
  22423. }
  22424. if ( ! $ || ! $.fn.dataTable ) {
  22425. $ = require('datatables.net')(root, $).$;
  22426. }
  22427. return factory( $, root, root.document );
  22428. };
  22429. }
  22430. else {
  22431. // Browser
  22432. factory( jQuery, window, document );
  22433. }
  22434. }(function( $, window, document, undefined ) {
  22435. 'use strict';
  22436. var DataTable = $.fn.dataTable;
  22437. /**
  22438. * Responsive is a plug-in for the DataTables library that makes use of
  22439. * DataTables' ability to change the visibility of columns, changing the
  22440. * visibility of columns so the displayed columns fit into the table container.
  22441. * The end result is that complex tables will be dynamically adjusted to fit
  22442. * into the viewport, be it on a desktop, tablet or mobile browser.
  22443. *
  22444. * Responsive for DataTables has two modes of operation, which can used
  22445. * individually or combined:
  22446. *
  22447. * * Class name based control - columns assigned class names that match the
  22448. * breakpoint logic can be shown / hidden as required for each breakpoint.
  22449. * * Automatic control - columns are automatically hidden when there is no
  22450. * room left to display them. Columns removed from the right.
  22451. *
  22452. * In additional to column visibility control, Responsive also has built into
  22453. * options to use DataTables' child row display to show / hide the information
  22454. * from the table that has been hidden. There are also two modes of operation
  22455. * for this child row display:
  22456. *
  22457. * * Inline - when the control element that the user can use to show / hide
  22458. * child rows is displayed inside the first column of the table.
  22459. * * Column - where a whole column is dedicated to be the show / hide control.
  22460. *
  22461. * Initialisation of Responsive is performed by:
  22462. *
  22463. * * Adding the class `responsive` or `dt-responsive` to the table. In this case
  22464. * Responsive will automatically be initialised with the default configuration
  22465. * options when the DataTable is created.
  22466. * * Using the `responsive` option in the DataTables configuration options. This
  22467. * can also be used to specify the configuration options, or simply set to
  22468. * `true` to use the defaults.
  22469. *
  22470. * @class
  22471. * @param {object} settings DataTables settings object for the host table
  22472. * @param {object} [opts] Configuration options
  22473. * @requires jQuery 1.7+
  22474. * @requires DataTables 1.10.3+
  22475. *
  22476. * @example
  22477. * $('#example').DataTable( {
  22478. * responsive: true
  22479. * } );
  22480. * } );
  22481. */
  22482. var Responsive = function ( settings, opts ) {
  22483. // Sanity check that we are using DataTables 1.10 or newer
  22484. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) {
  22485. throw 'DataTables Responsive requires DataTables 1.10.10 or newer';
  22486. }
  22487. this.s = {
  22488. dt: new DataTable.Api( settings ),
  22489. columns: [],
  22490. current: []
  22491. };
  22492. // Check if responsive has already been initialised on this table
  22493. if ( this.s.dt.settings()[0].responsive ) {
  22494. return;
  22495. }
  22496. // details is an object, but for simplicity the user can give it as a string
  22497. // or a boolean
  22498. if ( opts && typeof opts.details === 'string' ) {
  22499. opts.details = { type: opts.details };
  22500. }
  22501. else if ( opts && opts.details === false ) {
  22502. opts.details = { type: false };
  22503. }
  22504. else if ( opts && opts.details === true ) {
  22505. opts.details = { type: 'inline' };
  22506. }
  22507. this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
  22508. settings.responsive = this;
  22509. this._constructor();
  22510. };
  22511. $.extend( Responsive.prototype, {
  22512. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22513. * Constructor
  22514. */
  22515. /**
  22516. * Initialise the Responsive instance
  22517. *
  22518. * @private
  22519. */
  22520. _constructor: function ()
  22521. {
  22522. var that = this;
  22523. var dt = this.s.dt;
  22524. var dtPrivateSettings = dt.settings()[0];
  22525. var oldWindowWidth = $(window).width();
  22526. dt.settings()[0]._responsive = this;
  22527. // Use DataTables' throttle function to avoid processor thrashing on
  22528. // resize
  22529. $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
  22530. // iOS has a bug whereby resize can fire when only scrolling
  22531. // See: http://stackoverflow.com/questions/8898412
  22532. var width = $(window).width();
  22533. if ( width !== oldWindowWidth ) {
  22534. that._resize();
  22535. oldWindowWidth = width;
  22536. }
  22537. } ) );
  22538. // DataTables doesn't currently trigger an event when a row is added, so
  22539. // we need to hook into its private API to enforce the hidden rows when
  22540. // new data is added
  22541. dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
  22542. if ( $.inArray( false, that.s.current ) !== -1 ) {
  22543. $('>td, >th', tr).each( function ( i ) {
  22544. var idx = dt.column.index( 'toData', i );
  22545. if ( that.s.current[idx] === false ) {
  22546. $(this).css('display', 'none');
  22547. }
  22548. } );
  22549. }
  22550. } );
  22551. // Destroy event handler
  22552. dt.on( 'destroy.dtr', function () {
  22553. dt.off( '.dtr' );
  22554. $( dt.table().body() ).off( '.dtr' );
  22555. $(window).off( 'resize.dtr orientationchange.dtr' );
  22556. // Restore the columns that we've hidden
  22557. $.each( that.s.current, function ( i, val ) {
  22558. if ( val === false ) {
  22559. that._setColumnVis( i, true );
  22560. }
  22561. } );
  22562. } );
  22563. // Reorder the breakpoints array here in case they have been added out
  22564. // of order
  22565. this.c.breakpoints.sort( function (a, b) {
  22566. return a.width < b.width ? 1 :
  22567. a.width > b.width ? -1 : 0;
  22568. } );
  22569. this._classLogic();
  22570. this._resizeAuto();
  22571. // Details handler
  22572. var details = this.c.details;
  22573. if ( details.type !== false ) {
  22574. that._detailsInit();
  22575. // DataTables will trigger this event on every column it shows and
  22576. // hides individually
  22577. dt.on( 'column-visibility.dtr', function () {
  22578. // Use a small debounce to allow multiple columns to be set together
  22579. if ( that._timer ) {
  22580. clearTimeout( that._timer );
  22581. }
  22582. that._timer = setTimeout( function () {
  22583. that._timer = null;
  22584. that._classLogic();
  22585. that._resizeAuto();
  22586. that._resize();
  22587. that._redrawChildren();
  22588. }, 100 );
  22589. } );
  22590. // Redraw the details box on each draw which will happen if the data
  22591. // has changed. This is used until DataTables implements a native
  22592. // `updated` event for rows
  22593. dt.on( 'draw.dtr', function () {
  22594. that._redrawChildren();
  22595. } );
  22596. $(dt.table().node()).addClass( 'dtr-'+details.type );
  22597. }
  22598. dt.on( 'column-reorder.dtr', function (e, settings, details) {
  22599. that._classLogic();
  22600. that._resizeAuto();
  22601. that._resize();
  22602. } );
  22603. // Change in column sizes means we need to calc
  22604. dt.on( 'column-sizing.dtr', function () {
  22605. that._resizeAuto();
  22606. that._resize();
  22607. });
  22608. // On Ajax reload we want to reopen any child rows which are displayed
  22609. // by responsive
  22610. dt.on( 'preXhr.dtr', function () {
  22611. var rowIds = [];
  22612. dt.rows().every( function () {
  22613. if ( this.child.isShown() ) {
  22614. rowIds.push( this.id(true) );
  22615. }
  22616. } );
  22617. dt.one( 'draw.dtr', function () {
  22618. that._resizeAuto();
  22619. that._resize();
  22620. dt.rows( rowIds ).every( function () {
  22621. that._detailsDisplay( this, false );
  22622. } );
  22623. } );
  22624. });
  22625. dt.on( 'init.dtr', function (e, settings, details) {
  22626. that._resizeAuto();
  22627. that._resize();
  22628. // If columns were hidden, then DataTables needs to adjust the
  22629. // column sizing
  22630. if ( $.inArray( false, that.s.current ) ) {
  22631. dt.columns.adjust();
  22632. }
  22633. } );
  22634. // First pass - draw the table for the current viewport size
  22635. this._resize();
  22636. },
  22637. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22638. * Private methods
  22639. */
  22640. /**
  22641. * Calculate the visibility for the columns in a table for a given
  22642. * breakpoint. The result is pre-determined based on the class logic if
  22643. * class names are used to control all columns, but the width of the table
  22644. * is also used if there are columns which are to be automatically shown
  22645. * and hidden.
  22646. *
  22647. * @param {string} breakpoint Breakpoint name to use for the calculation
  22648. * @return {array} Array of boolean values initiating the visibility of each
  22649. * column.
  22650. * @private
  22651. */
  22652. _columnsVisiblity: function ( breakpoint )
  22653. {
  22654. var dt = this.s.dt;
  22655. var columns = this.s.columns;
  22656. var i, ien;
  22657. // Create an array that defines the column ordering based first on the
  22658. // column's priority, and secondly the column index. This allows the
  22659. // columns to be removed from the right if the priority matches
  22660. var order = columns
  22661. .map( function ( col, idx ) {
  22662. return {
  22663. columnIdx: idx,
  22664. priority: col.priority
  22665. };
  22666. } )
  22667. .sort( function ( a, b ) {
  22668. if ( a.priority !== b.priority ) {
  22669. return a.priority - b.priority;
  22670. }
  22671. return a.columnIdx - b.columnIdx;
  22672. } );
  22673. // Class logic - determine which columns are in this breakpoint based
  22674. // on the classes. If no class control (i.e. `auto`) then `-` is used
  22675. // to indicate this to the rest of the function
  22676. var display = $.map( columns, function ( col, i ) {
  22677. if ( dt.column(i).visible() === false ) {
  22678. return 'not-visible';
  22679. }
  22680. return col.auto && col.minWidth === null ?
  22681. false :
  22682. col.auto === true ?
  22683. '-' :
  22684. $.inArray( breakpoint, col.includeIn ) !== -1;
  22685. } );
  22686. // Auto column control - first pass: how much width is taken by the
  22687. // ones that must be included from the non-auto columns
  22688. var requiredWidth = 0;
  22689. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  22690. if ( display[i] === true ) {
  22691. requiredWidth += columns[i].minWidth;
  22692. }
  22693. }
  22694. // Second pass, use up any remaining width for other columns. For
  22695. // scrolling tables we need to subtract the width of the scrollbar. It
  22696. // may not be requires which makes this sub-optimal, but it would
  22697. // require another full redraw to make complete use of those extra few
  22698. // pixels
  22699. var scrolling = dt.settings()[0].oScroll;
  22700. var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
  22701. var widthAvailable = dt.table().container().offsetWidth - bar;
  22702. var usedWidth = widthAvailable - requiredWidth;
  22703. // Control column needs to always be included. This makes it sub-
  22704. // optimal in terms of using the available with, but to stop layout
  22705. // thrashing or overflow. Also we need to account for the control column
  22706. // width first so we know how much width is available for the other
  22707. // columns, since the control column might not be the first one shown
  22708. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  22709. if ( columns[i].control ) {
  22710. usedWidth -= columns[i].minWidth;
  22711. }
  22712. }
  22713. // Allow columns to be shown (counting by priority and then right to
  22714. // left) until we run out of room
  22715. var empty = false;
  22716. for ( i=0, ien=order.length ; i<ien ; i++ ) {
  22717. var colIdx = order[i].columnIdx;
  22718. if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
  22719. // Once we've found a column that won't fit we don't let any
  22720. // others display either, or columns might disappear in the
  22721. // middle of the table
  22722. if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
  22723. empty = true;
  22724. display[colIdx] = false;
  22725. }
  22726. else {
  22727. display[colIdx] = true;
  22728. }
  22729. usedWidth -= columns[colIdx].minWidth;
  22730. }
  22731. }
  22732. // Determine if the 'control' column should be shown (if there is one).
  22733. // This is the case when there is a hidden column (that is not the
  22734. // control column). The two loops look inefficient here, but they are
  22735. // trivial and will fly through. We need to know the outcome from the
  22736. // first , before the action in the second can be taken
  22737. var showControl = false;
  22738. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  22739. if ( ! columns[i].control && ! columns[i].never && display[i] === false ) {
  22740. showControl = true;
  22741. break;
  22742. }
  22743. }
  22744. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  22745. if ( columns[i].control ) {
  22746. display[i] = showControl;
  22747. }
  22748. // Replace not visible string with false from the control column detection above
  22749. if ( display[i] === 'not-visible' ) {
  22750. display[i] = false;
  22751. }
  22752. }
  22753. // Finally we need to make sure that there is at least one column that
  22754. // is visible
  22755. if ( $.inArray( true, display ) === -1 ) {
  22756. display[0] = true;
  22757. }
  22758. return display;
  22759. },
  22760. /**
  22761. * Create the internal `columns` array with information about the columns
  22762. * for the table. This includes determining which breakpoints the column
  22763. * will appear in, based upon class names in the column, which makes up the
  22764. * vast majority of this method.
  22765. *
  22766. * @private
  22767. */
  22768. _classLogic: function ()
  22769. {
  22770. var that = this;
  22771. var calc = {};
  22772. var breakpoints = this.c.breakpoints;
  22773. var dt = this.s.dt;
  22774. var columns = dt.columns().eq(0).map( function (i) {
  22775. var column = this.column(i);
  22776. var className = column.header().className;
  22777. var priority = dt.settings()[0].aoColumns[i].responsivePriority;
  22778. if ( priority === undefined ) {
  22779. var dataPriority = $(column.header()).data('priority');
  22780. priority = dataPriority !== undefined ?
  22781. dataPriority * 1 :
  22782. 10000;
  22783. }
  22784. return {
  22785. className: className,
  22786. includeIn: [],
  22787. auto: false,
  22788. control: false,
  22789. never: className.match(/\bnever\b/) ? true : false,
  22790. priority: priority
  22791. };
  22792. } );
  22793. // Simply add a breakpoint to `includeIn` array, ensuring that there are
  22794. // no duplicates
  22795. var add = function ( colIdx, name ) {
  22796. var includeIn = columns[ colIdx ].includeIn;
  22797. if ( $.inArray( name, includeIn ) === -1 ) {
  22798. includeIn.push( name );
  22799. }
  22800. };
  22801. var column = function ( colIdx, name, operator, matched ) {
  22802. var size, i, ien;
  22803. if ( ! operator ) {
  22804. columns[ colIdx ].includeIn.push( name );
  22805. }
  22806. else if ( operator === 'max-' ) {
  22807. // Add this breakpoint and all smaller
  22808. size = that._find( name ).width;
  22809. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  22810. if ( breakpoints[i].width <= size ) {
  22811. add( colIdx, breakpoints[i].name );
  22812. }
  22813. }
  22814. }
  22815. else if ( operator === 'min-' ) {
  22816. // Add this breakpoint and all larger
  22817. size = that._find( name ).width;
  22818. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  22819. if ( breakpoints[i].width >= size ) {
  22820. add( colIdx, breakpoints[i].name );
  22821. }
  22822. }
  22823. }
  22824. else if ( operator === 'not-' ) {
  22825. // Add all but this breakpoint
  22826. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  22827. if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
  22828. add( colIdx, breakpoints[i].name );
  22829. }
  22830. }
  22831. }
  22832. };
  22833. // Loop over each column and determine if it has a responsive control
  22834. // class
  22835. columns.each( function ( col, i ) {
  22836. var classNames = col.className.split(' ');
  22837. var hasClass = false;
  22838. // Split the class name up so multiple rules can be applied if needed
  22839. for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
  22840. var className = $.trim( classNames[k] );
  22841. if ( className === 'all' ) {
  22842. // Include in all
  22843. hasClass = true;
  22844. col.includeIn = $.map( breakpoints, function (a) {
  22845. return a.name;
  22846. } );
  22847. return;
  22848. }
  22849. else if ( className === 'none' || col.never ) {
  22850. // Include in none (default) and no auto
  22851. hasClass = true;
  22852. return;
  22853. }
  22854. else if ( className === 'control' ) {
  22855. // Special column that is only visible, when one of the other
  22856. // columns is hidden. This is used for the details control
  22857. hasClass = true;
  22858. col.control = true;
  22859. return;
  22860. }
  22861. $.each( breakpoints, function ( j, breakpoint ) {
  22862. // Does this column have a class that matches this breakpoint?
  22863. var brokenPoint = breakpoint.name.split('-');
  22864. var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
  22865. var match = className.match( re );
  22866. if ( match ) {
  22867. hasClass = true;
  22868. if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
  22869. // Class name matches breakpoint name fully
  22870. column( i, breakpoint.name, match[1], match[2]+match[3] );
  22871. }
  22872. else if ( match[2] === brokenPoint[0] && ! match[3] ) {
  22873. // Class name matched primary breakpoint name with no qualifier
  22874. column( i, breakpoint.name, match[1], match[2] );
  22875. }
  22876. }
  22877. } );
  22878. }
  22879. // If there was no control class, then automatic sizing is used
  22880. if ( ! hasClass ) {
  22881. col.auto = true;
  22882. }
  22883. } );
  22884. this.s.columns = columns;
  22885. },
  22886. /**
  22887. * Show the details for the child row
  22888. *
  22889. * @param {DataTables.Api} row API instance for the row
  22890. * @param {boolean} update Update flag
  22891. * @private
  22892. */
  22893. _detailsDisplay: function ( row, update )
  22894. {
  22895. var that = this;
  22896. var dt = this.s.dt;
  22897. var details = this.c.details;
  22898. if ( details && details.type !== false ) {
  22899. var res = details.display( row, update, function () {
  22900. return details.renderer(
  22901. dt, row[0], that._detailsObj(row[0])
  22902. );
  22903. } );
  22904. if ( res === true || res === false ) {
  22905. $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
  22906. }
  22907. }
  22908. },
  22909. /**
  22910. * Initialisation for the details handler
  22911. *
  22912. * @private
  22913. */
  22914. _detailsInit: function ()
  22915. {
  22916. var that = this;
  22917. var dt = this.s.dt;
  22918. var details = this.c.details;
  22919. // The inline type always uses the first child as the target
  22920. if ( details.type === 'inline' ) {
  22921. details.target = 'td:first-child, th:first-child';
  22922. }
  22923. // Keyboard accessibility
  22924. dt.on( 'draw.dtr', function () {
  22925. that._tabIndexes();
  22926. } );
  22927. that._tabIndexes(); // Initial draw has already happened
  22928. $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
  22929. if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
  22930. $(this).click();
  22931. }
  22932. } );
  22933. // type.target can be a string jQuery selector or a column index
  22934. var target = details.target;
  22935. var selector = typeof target === 'string' ? target : 'td, th';
  22936. // Click handler to show / hide the details rows when they are available
  22937. $( dt.table().body() )
  22938. .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
  22939. // If the table is not collapsed (i.e. there is no hidden columns)
  22940. // then take no action
  22941. if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
  22942. return;
  22943. }
  22944. // Check that the row is actually a DataTable's controlled node
  22945. if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
  22946. return;
  22947. }
  22948. // For column index, we determine if we should act or not in the
  22949. // handler - otherwise it is already okay
  22950. if ( typeof target === 'number' ) {
  22951. var targetIdx = target < 0 ?
  22952. dt.columns().eq(0).length + target :
  22953. target;
  22954. if ( dt.cell( this ).index().column !== targetIdx ) {
  22955. return;
  22956. }
  22957. }
  22958. // $().closest() includes itself in its check
  22959. var row = dt.row( $(this).closest('tr') );
  22960. // Check event type to do an action
  22961. if ( e.type === 'click' ) {
  22962. // The renderer is given as a function so the caller can execute it
  22963. // only when they need (i.e. if hiding there is no point is running
  22964. // the renderer)
  22965. that._detailsDisplay( row, false );
  22966. }
  22967. else if ( e.type === 'mousedown' ) {
  22968. // For mouse users, prevent the focus ring from showing
  22969. $(this).css('outline', 'none');
  22970. }
  22971. else if ( e.type === 'mouseup' ) {
  22972. // And then re-allow at the end of the click
  22973. $(this).blur().css('outline', '');
  22974. }
  22975. } );
  22976. },
  22977. /**
  22978. * Get the details to pass to a renderer for a row
  22979. * @param {int} rowIdx Row index
  22980. * @private
  22981. */
  22982. _detailsObj: function ( rowIdx )
  22983. {
  22984. var that = this;
  22985. var dt = this.s.dt;
  22986. return $.map( this.s.columns, function( col, i ) {
  22987. // Never and control columns should not be passed to the renderer
  22988. if ( col.never || col.control ) {
  22989. return;
  22990. }
  22991. return {
  22992. title: dt.settings()[0].aoColumns[ i ].sTitle,
  22993. data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
  22994. hidden: dt.column( i ).visible() && !that.s.current[ i ],
  22995. columnIndex: i,
  22996. rowIndex: rowIdx
  22997. };
  22998. } );
  22999. },
  23000. /**
  23001. * Find a breakpoint object from a name
  23002. *
  23003. * @param {string} name Breakpoint name to find
  23004. * @return {object} Breakpoint description object
  23005. * @private
  23006. */
  23007. _find: function ( name )
  23008. {
  23009. var breakpoints = this.c.breakpoints;
  23010. for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  23011. if ( breakpoints[i].name === name ) {
  23012. return breakpoints[i];
  23013. }
  23014. }
  23015. },
  23016. /**
  23017. * Re-create the contents of the child rows as the display has changed in
  23018. * some way.
  23019. *
  23020. * @private
  23021. */
  23022. _redrawChildren: function ()
  23023. {
  23024. var that = this;
  23025. var dt = this.s.dt;
  23026. dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
  23027. var row = dt.row( idx );
  23028. that._detailsDisplay( dt.row( idx ), true );
  23029. } );
  23030. },
  23031. /**
  23032. * Alter the table display for a resized viewport. This involves first
  23033. * determining what breakpoint the window currently is in, getting the
  23034. * column visibilities to apply and then setting them.
  23035. *
  23036. * @private
  23037. */
  23038. _resize: function ()
  23039. {
  23040. var that = this;
  23041. var dt = this.s.dt;
  23042. var width = $(window).width();
  23043. var breakpoints = this.c.breakpoints;
  23044. var breakpoint = breakpoints[0].name;
  23045. var columns = this.s.columns;
  23046. var i, ien;
  23047. var oldVis = this.s.current.slice();
  23048. // Determine what breakpoint we are currently at
  23049. for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
  23050. if ( width <= breakpoints[i].width ) {
  23051. breakpoint = breakpoints[i].name;
  23052. break;
  23053. }
  23054. }
  23055. // Show the columns for that break point
  23056. var columnsVis = this._columnsVisiblity( breakpoint );
  23057. this.s.current = columnsVis;
  23058. // Set the class before the column visibility is changed so event
  23059. // listeners know what the state is. Need to determine if there are
  23060. // any columns that are not visible but can be shown
  23061. var collapsedClass = false;
  23062. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  23063. if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) {
  23064. collapsedClass = true;
  23065. break;
  23066. }
  23067. }
  23068. $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
  23069. var changed = false;
  23070. var visible = 0;
  23071. dt.columns().eq(0).each( function ( colIdx, i ) {
  23072. if ( columnsVis[i] === true ) {
  23073. visible++;
  23074. }
  23075. if ( columnsVis[i] !== oldVis[i] ) {
  23076. changed = true;
  23077. that._setColumnVis( colIdx, columnsVis[i] );
  23078. }
  23079. } );
  23080. if ( changed ) {
  23081. this._redrawChildren();
  23082. // Inform listeners of the change
  23083. $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
  23084. // If no records, update the "No records" display element
  23085. if ( dt.page.info().recordsDisplay === 0 ) {
  23086. $('td', dt.table().body()).eq(0).attr('colspan', visible);
  23087. }
  23088. }
  23089. },
  23090. /**
  23091. * Determine the width of each column in the table so the auto column hiding
  23092. * has that information to work with. This method is never going to be 100%
  23093. * perfect since column widths can change slightly per page, but without
  23094. * seriously compromising performance this is quite effective.
  23095. *
  23096. * @private
  23097. */
  23098. _resizeAuto: function ()
  23099. {
  23100. var dt = this.s.dt;
  23101. var columns = this.s.columns;
  23102. // Are we allowed to do auto sizing?
  23103. if ( ! this.c.auto ) {
  23104. return;
  23105. }
  23106. // Are there any columns that actually need auto-sizing, or do they all
  23107. // have classes defined
  23108. if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
  23109. return;
  23110. }
  23111. // Need to restore all children. They will be reinstated by a re-render
  23112. if ( ! $.isEmptyObject( _childNodeStore ) ) {
  23113. $.each( _childNodeStore, function ( key ) {
  23114. var idx = key.split('-');
  23115. _childNodesRestore( dt, idx[0]*1, idx[1]*1 );
  23116. } );
  23117. }
  23118. // Clone the table with the current data in it
  23119. var tableWidth = dt.table().node().offsetWidth;
  23120. var columnWidths = dt.columns;
  23121. var clonedTable = dt.table().node().cloneNode( false );
  23122. var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
  23123. var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
  23124. // Header
  23125. var headerCells = dt.columns()
  23126. .header()
  23127. .filter( function (idx) {
  23128. return dt.column(idx).visible();
  23129. } )
  23130. .to$()
  23131. .clone( false )
  23132. .css( 'display', 'table-cell' )
  23133. .css( 'min-width', 0 );
  23134. // Body rows - we don't need to take account of DataTables' column
  23135. // visibility since we implement our own here (hence the `display` set)
  23136. $(clonedBody)
  23137. .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
  23138. .find( 'th, td' ).css( 'display', '' );
  23139. // Footer
  23140. var footer = dt.table().footer();
  23141. if ( footer ) {
  23142. var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
  23143. var footerCells = dt.columns()
  23144. .footer()
  23145. .filter( function (idx) {
  23146. return dt.column(idx).visible();
  23147. } )
  23148. .to$()
  23149. .clone( false )
  23150. .css( 'display', 'table-cell' );
  23151. $('<tr/>')
  23152. .append( footerCells )
  23153. .appendTo( clonedFooter );
  23154. }
  23155. $('<tr/>')
  23156. .append( headerCells )
  23157. .appendTo( clonedHeader );
  23158. // In the inline case extra padding is applied to the first column to
  23159. // give space for the show / hide icon. We need to use this in the
  23160. // calculation
  23161. if ( this.c.details.type === 'inline' ) {
  23162. $(clonedTable).addClass( 'dtr-inline collapsed' );
  23163. }
  23164. // It is unsafe to insert elements with the same name into the DOM
  23165. // multiple times. For example, cloning and inserting a checked radio
  23166. // clears the chcecked state of the original radio.
  23167. $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
  23168. // A position absolute table would take the table out of the flow of
  23169. // our container element, bypassing the height and width (Scroller)
  23170. $( clonedTable ).css( 'position', 'relative' )
  23171. var inserted = $('<div/>')
  23172. .css( {
  23173. width: 1,
  23174. height: 1,
  23175. overflow: 'hidden',
  23176. clear: 'both'
  23177. } )
  23178. .append( clonedTable );
  23179. inserted.insertBefore( dt.table().node() );
  23180. // The cloned header now contains the smallest that each column can be
  23181. headerCells.each( function (i) {
  23182. var idx = dt.column.index( 'fromVisible', i );
  23183. columns[ idx ].minWidth = this.offsetWidth || 0;
  23184. } );
  23185. inserted.remove();
  23186. },
  23187. /**
  23188. * Set a column's visibility.
  23189. *
  23190. * We don't use DataTables' column visibility controls in order to ensure
  23191. * that column visibility can Responsive can no-exist. Since only IE8+ is
  23192. * supported (and all evergreen browsers of course) the control of the
  23193. * display attribute works well.
  23194. *
  23195. * @param {integer} col Column index
  23196. * @param {boolean} showHide Show or hide (true or false)
  23197. * @private
  23198. */
  23199. _setColumnVis: function ( col, showHide )
  23200. {
  23201. var dt = this.s.dt;
  23202. var display = showHide ? '' : 'none'; // empty string will remove the attr
  23203. $( dt.column( col ).header() ).css( 'display', display );
  23204. $( dt.column( col ).footer() ).css( 'display', display );
  23205. dt.column( col ).nodes().to$().css( 'display', display );
  23206. // If the are child nodes stored, we might need to reinsert them
  23207. if ( ! $.isEmptyObject( _childNodeStore ) ) {
  23208. dt.cells( null, col ).indexes().each( function (idx) {
  23209. _childNodesRestore( dt, idx.row, idx.column );
  23210. } );
  23211. }
  23212. },
  23213. /**
  23214. * Update the cell tab indexes for keyboard accessibility. This is called on
  23215. * every table draw - that is potentially inefficient, but also the least
  23216. * complex option given that column visibility can change on the fly. Its a
  23217. * shame user-focus was removed from CSS 3 UI, as it would have solved this
  23218. * issue with a single CSS statement.
  23219. *
  23220. * @private
  23221. */
  23222. _tabIndexes: function ()
  23223. {
  23224. var dt = this.s.dt;
  23225. var cells = dt.cells( { page: 'current' } ).nodes().to$();
  23226. var ctx = dt.settings()[0];
  23227. var target = this.c.details.target;
  23228. cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
  23229. if ( typeof target === 'number' ) {
  23230. dt.cells( null, target, { page: 'current' } ).nodes().to$()
  23231. .attr( 'tabIndex', ctx.iTabIndex )
  23232. .data( 'dtr-keyboard', 1 );
  23233. }
  23234. else {
  23235. // This is a bit of a hack - we need to limit the selected nodes to just
  23236. // those of this table
  23237. if ( target === 'td:first-child, th:first-child' ) {
  23238. target = '>td:first-child, >th:first-child';
  23239. }
  23240. $( target, dt.rows( { page: 'current' } ).nodes() )
  23241. .attr( 'tabIndex', ctx.iTabIndex )
  23242. .data( 'dtr-keyboard', 1 );
  23243. }
  23244. }
  23245. } );
  23246. /**
  23247. * List of default breakpoints. Each item in the array is an object with two
  23248. * properties:
  23249. *
  23250. * * `name` - the breakpoint name.
  23251. * * `width` - the breakpoint width
  23252. *
  23253. * @name Responsive.breakpoints
  23254. * @static
  23255. */
  23256. Responsive.breakpoints = [
  23257. { name: 'desktop', width: Infinity },
  23258. { name: 'tablet-l', width: 1024 },
  23259. { name: 'tablet-p', width: 768 },
  23260. { name: 'mobile-l', width: 480 },
  23261. { name: 'mobile-p', width: 320 }
  23262. ];
  23263. /**
  23264. * Display methods - functions which define how the hidden data should be shown
  23265. * in the table.
  23266. *
  23267. * @namespace
  23268. * @name Responsive.defaults
  23269. * @static
  23270. */
  23271. Responsive.display = {
  23272. childRow: function ( row, update, render ) {
  23273. if ( update ) {
  23274. if ( $(row.node()).hasClass('parent') ) {
  23275. row.child( render(), 'child' ).show();
  23276. return true;
  23277. }
  23278. }
  23279. else {
  23280. if ( ! row.child.isShown() ) {
  23281. row.child( render(), 'child' ).show();
  23282. $( row.node() ).addClass( 'parent' );
  23283. return true;
  23284. }
  23285. else {
  23286. row.child( false );
  23287. $( row.node() ).removeClass( 'parent' );
  23288. return false;
  23289. }
  23290. }
  23291. },
  23292. childRowImmediate: function ( row, update, render ) {
  23293. if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
  23294. // User interaction and the row is show, or nothing to show
  23295. row.child( false );
  23296. $( row.node() ).removeClass( 'parent' );
  23297. return false;
  23298. }
  23299. else {
  23300. // Display
  23301. row.child( render(), 'child' ).show();
  23302. $( row.node() ).addClass( 'parent' );
  23303. return true;
  23304. }
  23305. },
  23306. // This is a wrapper so the modal options for Bootstrap and jQuery UI can
  23307. // have options passed into them. This specific one doesn't need to be a
  23308. // function but it is for consistency in the `modal` name
  23309. modal: function ( options ) {
  23310. return function ( row, update, render ) {
  23311. if ( ! update ) {
  23312. // Show a modal
  23313. var close = function () {
  23314. modal.remove(); // will tidy events for us
  23315. $(document).off( 'keypress.dtr' );
  23316. };
  23317. var modal = $('<div class="dtr-modal"/>')
  23318. .append( $('<div class="dtr-modal-display"/>')
  23319. .append( $('<div class="dtr-modal-content"/>')
  23320. .append( render() )
  23321. )
  23322. .append( $('<div class="dtr-modal-close">&times;</div>' )
  23323. .click( function () {
  23324. close();
  23325. } )
  23326. )
  23327. )
  23328. .append( $('<div class="dtr-modal-background"/>')
  23329. .click( function () {
  23330. close();
  23331. } )
  23332. )
  23333. .appendTo( 'body' );
  23334. $(document).on( 'keyup.dtr', function (e) {
  23335. if ( e.keyCode === 27 ) {
  23336. e.stopPropagation();
  23337. close();
  23338. }
  23339. } );
  23340. }
  23341. else {
  23342. $('div.dtr-modal-content')
  23343. .empty()
  23344. .append( render() );
  23345. }
  23346. if ( options && options.header ) {
  23347. $('div.dtr-modal-content').prepend(
  23348. '<h2>'+options.header( row )+'</h2>'
  23349. );
  23350. }
  23351. };
  23352. }
  23353. };
  23354. var _childNodeStore = {};
  23355. function _childNodes( dt, row, col ) {
  23356. var name = row+'-'+col;
  23357. if ( _childNodeStore[ name ] ) {
  23358. return _childNodeStore[ name ];
  23359. }
  23360. // https://jsperf.com/childnodes-array-slice-vs-loop
  23361. var nodes = [];
  23362. var children = dt.cell( row, col ).node().childNodes;
  23363. for ( var i=0, ien=children.length ; i<ien ; i++ ) {
  23364. nodes.push( children[i] );
  23365. }
  23366. _childNodeStore[ name ] = nodes;
  23367. return nodes;
  23368. }
  23369. function _childNodesRestore( dt, row, col ) {
  23370. var name = row+'-'+col;
  23371. if ( ! _childNodeStore[ name ] ) {
  23372. return;
  23373. }
  23374. var node = dt.cell( row, col ).node();
  23375. var store = _childNodeStore[ name ];
  23376. var parent = store[0].parentNode;
  23377. var parentChildren = parent.childNodes;
  23378. var a = [];
  23379. for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
  23380. a.push( parentChildren[i] );
  23381. }
  23382. for ( var j=0, jen=a.length ; j<jen ; j++ ) {
  23383. node.appendChild( a[j] );
  23384. }
  23385. _childNodeStore[ name ] = undefined;
  23386. }
  23387. /**
  23388. * Display methods - functions which define how the hidden data should be shown
  23389. * in the table.
  23390. *
  23391. * @namespace
  23392. * @name Responsive.defaults
  23393. * @static
  23394. */
  23395. Responsive.renderer = {
  23396. listHiddenNodes: function () {
  23397. return function ( api, rowIdx, columns ) {
  23398. var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>');
  23399. var found = false;
  23400. var data = $.each( columns, function ( i, col ) {
  23401. if ( col.hidden ) {
  23402. $(
  23403. '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
  23404. '<span class="dtr-title">'+
  23405. col.title+
  23406. '</span> '+
  23407. '</li>'
  23408. )
  23409. .append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
  23410. .appendTo( ul );
  23411. found = true;
  23412. }
  23413. } );
  23414. return found ?
  23415. ul :
  23416. false;
  23417. };
  23418. },
  23419. listHidden: function () {
  23420. return function ( api, rowIdx, columns ) {
  23421. var data = $.map( columns, function ( col ) {
  23422. return col.hidden ?
  23423. '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
  23424. '<span class="dtr-title">'+
  23425. col.title+
  23426. '</span> '+
  23427. '<span class="dtr-data">'+
  23428. col.data+
  23429. '</span>'+
  23430. '</li>' :
  23431. '';
  23432. } ).join('');
  23433. return data ?
  23434. $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
  23435. false;
  23436. }
  23437. },
  23438. tableAll: function ( options ) {
  23439. options = $.extend( {
  23440. tableClass: ''
  23441. }, options );
  23442. return function ( api, rowIdx, columns ) {
  23443. var data = $.map( columns, function ( col ) {
  23444. return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
  23445. '<td>'+col.title+':'+'</td> '+
  23446. '<td>'+col.data+'</td>'+
  23447. '</tr>';
  23448. } ).join('');
  23449. return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
  23450. }
  23451. }
  23452. };
  23453. /**
  23454. * Responsive default settings for initialisation
  23455. *
  23456. * @namespace
  23457. * @name Responsive.defaults
  23458. * @static
  23459. */
  23460. Responsive.defaults = {
  23461. /**
  23462. * List of breakpoints for the instance. Note that this means that each
  23463. * instance can have its own breakpoints. Additionally, the breakpoints
  23464. * cannot be changed once an instance has been creased.
  23465. *
  23466. * @type {Array}
  23467. * @default Takes the value of `Responsive.breakpoints`
  23468. */
  23469. breakpoints: Responsive.breakpoints,
  23470. /**
  23471. * Enable / disable auto hiding calculations. It can help to increase
  23472. * performance slightly if you disable this option, but all columns would
  23473. * need to have breakpoint classes assigned to them
  23474. *
  23475. * @type {Boolean}
  23476. * @default `true`
  23477. */
  23478. auto: true,
  23479. /**
  23480. * Details control. If given as a string value, the `type` property of the
  23481. * default object is set to that value, and the defaults used for the rest
  23482. * of the object - this is for ease of implementation.
  23483. *
  23484. * The object consists of the following properties:
  23485. *
  23486. * * `display` - A function that is used to show and hide the hidden details
  23487. * * `renderer` - function that is called for display of the child row data.
  23488. * The default function will show the data from the hidden columns
  23489. * * `target` - Used as the selector for what objects to attach the child
  23490. * open / close to
  23491. * * `type` - `false` to disable the details display, `inline` or `column`
  23492. * for the two control types
  23493. *
  23494. * @type {Object|string}
  23495. */
  23496. details: {
  23497. display: Responsive.display.childRow,
  23498. renderer: Responsive.renderer.listHidden(),
  23499. target: 0,
  23500. type: 'inline'
  23501. },
  23502. /**
  23503. * Orthogonal data request option. This is used to define the data type
  23504. * requested when Responsive gets the data to show in the child row.
  23505. *
  23506. * @type {String}
  23507. */
  23508. orthogonal: 'display'
  23509. };
  23510. /*
  23511. * API
  23512. */
  23513. var Api = $.fn.dataTable.Api;
  23514. // Doesn't do anything - work around for a bug in DT... Not documented
  23515. Api.register( 'responsive()', function () {
  23516. return this;
  23517. } );
  23518. Api.register( 'responsive.index()', function ( li ) {
  23519. li = $(li);
  23520. return {
  23521. column: li.data('dtr-index'),
  23522. row: li.parent().data('dtr-index')
  23523. };
  23524. } );
  23525. Api.register( 'responsive.rebuild()', function () {
  23526. return this.iterator( 'table', function ( ctx ) {
  23527. if ( ctx._responsive ) {
  23528. ctx._responsive._classLogic();
  23529. }
  23530. } );
  23531. } );
  23532. Api.register( 'responsive.recalc()', function () {
  23533. return this.iterator( 'table', function ( ctx ) {
  23534. if ( ctx._responsive ) {
  23535. ctx._responsive._resizeAuto();
  23536. ctx._responsive._resize();
  23537. }
  23538. } );
  23539. } );
  23540. Api.register( 'responsive.hasHidden()', function () {
  23541. var ctx = this.context[0];
  23542. return ctx._responsive ?
  23543. $.inArray( false, ctx._responsive.s.current ) !== -1 :
  23544. false;
  23545. } );
  23546. Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {
  23547. return this.iterator( 'column', function ( settings, column ) {
  23548. return settings._responsive ?
  23549. settings._responsive.s.current[ column ] :
  23550. false;
  23551. }, 1 );
  23552. } );
  23553. /**
  23554. * Version information
  23555. *
  23556. * @name Responsive.version
  23557. * @static
  23558. */
  23559. Responsive.version = '2.2.3';
  23560. $.fn.dataTable.Responsive = Responsive;
  23561. $.fn.DataTable.Responsive = Responsive;
  23562. // Attach a listener to the document which listens for DataTables initialisation
  23563. // events so we can automatically initialise
  23564. $(document).on( 'preInit.dt.dtr', function (e, settings, json) {
  23565. if ( e.namespace !== 'dt' ) {
  23566. return;
  23567. }
  23568. if ( $(settings.nTable).hasClass( 'responsive' ) ||
  23569. $(settings.nTable).hasClass( 'dt-responsive' ) ||
  23570. settings.oInit.responsive ||
  23571. DataTable.defaults.responsive
  23572. ) {
  23573. var init = settings.oInit.responsive;
  23574. if ( init !== false ) {
  23575. new Responsive( settings, $.isPlainObject( init ) ? init : {} );
  23576. }
  23577. }
  23578. } );
  23579. return Responsive;
  23580. }));
  23581. /*! Bootstrap 4 integration for DataTables' Responsive
  23582. * ©2016 SpryMedia Ltd - datatables.net/license
  23583. */
  23584. (function( factory ){
  23585. if ( typeof define === 'function' && define.amd ) {
  23586. // AMD
  23587. define( ['jquery', 'datatables.net-bs4', 'datatables.net-responsive'], function ( $ ) {
  23588. return factory( $, window, document );
  23589. } );
  23590. }
  23591. else if ( typeof exports === 'object' ) {
  23592. // CommonJS
  23593. module.exports = function (root, $) {
  23594. if ( ! root ) {
  23595. root = window;
  23596. }
  23597. if ( ! $ || ! $.fn.dataTable ) {
  23598. $ = require('datatables.net-bs4')(root, $).$;
  23599. }
  23600. if ( ! $.fn.dataTable.Responsive ) {
  23601. require('datatables.net-responsive')(root, $);
  23602. }
  23603. return factory( $, root, root.document );
  23604. };
  23605. }
  23606. else {
  23607. // Browser
  23608. factory( jQuery, window, document );
  23609. }
  23610. }(function( $, window, document, undefined ) {
  23611. 'use strict';
  23612. var DataTable = $.fn.dataTable;
  23613. var _display = DataTable.Responsive.display;
  23614. var _original = _display.modal;
  23615. var _modal = $(
  23616. '<div class="modal fade dtr-bs-modal" role="dialog">'+
  23617. '<div class="modal-dialog" role="document">'+
  23618. '<div class="modal-content">'+
  23619. '<div class="modal-header">'+
  23620. '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>'+
  23621. '</div>'+
  23622. '<div class="modal-body"/>'+
  23623. '</div>'+
  23624. '</div>'+
  23625. '</div>'
  23626. );
  23627. _display.modal = function ( options ) {
  23628. return function ( row, update, render ) {
  23629. if ( ! $.fn.modal ) {
  23630. _original( row, update, render );
  23631. }
  23632. else {
  23633. if ( ! update ) {
  23634. if ( options && options.header ) {
  23635. var header = _modal.find('div.modal-header');
  23636. var button = header.find('button').detach();
  23637. header
  23638. .empty()
  23639. .append( '<h4 class="modal-title">'+options.header( row )+'</h4>' )
  23640. .append( button );
  23641. }
  23642. _modal.find( 'div.modal-body' )
  23643. .empty()
  23644. .append( render() );
  23645. _modal
  23646. .appendTo( 'body' )
  23647. .modal();
  23648. }
  23649. }
  23650. };
  23651. };
  23652. return DataTable.Responsive;
  23653. }));
  23654. /*! RowGroup 1.1.1
  23655. * ©2017-2019 SpryMedia Ltd - datatables.net/license
  23656. */
  23657. /**
  23658. * @summary RowGroup
  23659. * @description RowGrouping for DataTables
  23660. * @version 1.1.1
  23661. * @file dataTables.rowGroup.js
  23662. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  23663. * @contact datatables.net
  23664. * @copyright Copyright 2017-2019 SpryMedia Ltd.
  23665. *
  23666. * This source file is free software, available under the following license:
  23667. * MIT license - http://datatables.net/license/mit
  23668. *
  23669. * This source file is distributed in the hope that it will be useful, but
  23670. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  23671. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  23672. *
  23673. * For details please refer to: http://www.datatables.net
  23674. */
  23675. (function( factory ){
  23676. if ( typeof define === 'function' && define.amd ) {
  23677. // AMD
  23678. define( ['jquery', 'datatables.net'], function ( $ ) {
  23679. return factory( $, window, document );
  23680. } );
  23681. }
  23682. else if ( typeof exports === 'object' ) {
  23683. // CommonJS
  23684. module.exports = function (root, $) {
  23685. if ( ! root ) {
  23686. root = window;
  23687. }
  23688. if ( ! $ || ! $.fn.dataTable ) {
  23689. $ = require('datatables.net')(root, $).$;
  23690. }
  23691. return factory( $, root, root.document );
  23692. };
  23693. }
  23694. else {
  23695. // Browser
  23696. factory( jQuery, window, document );
  23697. }
  23698. }(function( $, window, document, undefined ) {
  23699. 'use strict';
  23700. var DataTable = $.fn.dataTable;
  23701. var RowGroup = function ( dt, opts ) {
  23702. // Sanity check that we are using DataTables 1.10 or newer
  23703. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
  23704. throw 'RowGroup requires DataTables 1.10.8 or newer';
  23705. }
  23706. // User and defaults configuration object
  23707. this.c = $.extend( true, {},
  23708. DataTable.defaults.rowGroup,
  23709. RowGroup.defaults,
  23710. opts
  23711. );
  23712. // Internal settings
  23713. this.s = {
  23714. dt: new DataTable.Api( dt )
  23715. };
  23716. // DOM items
  23717. this.dom = {
  23718. };
  23719. // Check if row grouping has already been initialised on this table
  23720. var settings = this.s.dt.settings()[0];
  23721. var existing = settings.rowGroup;
  23722. if ( existing ) {
  23723. return existing;
  23724. }
  23725. settings.rowGroup = this;
  23726. this._constructor();
  23727. };
  23728. $.extend( RowGroup.prototype, {
  23729. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23730. * API methods for DataTables API interface
  23731. */
  23732. /**
  23733. * Get/set the grouping data source - need to call draw after this is
  23734. * executed as a setter
  23735. * @returns string~RowGroup
  23736. */
  23737. dataSrc: function ( val )
  23738. {
  23739. if ( val === undefined ) {
  23740. return this.c.dataSrc;
  23741. }
  23742. var dt = this.s.dt;
  23743. this.c.dataSrc = val;
  23744. $(dt.table().node()).triggerHandler( 'rowgroup-datasrc.dt', [ dt, val ] );
  23745. return this;
  23746. },
  23747. /**
  23748. * Disable - need to call draw after this is executed
  23749. * @returns RowGroup
  23750. */
  23751. disable: function ()
  23752. {
  23753. this.c.enable = false;
  23754. return this;
  23755. },
  23756. /**
  23757. * Enable - need to call draw after this is executed
  23758. * @returns RowGroup
  23759. */
  23760. enable: function ( flag )
  23761. {
  23762. if ( flag === false ) {
  23763. return this.disable();
  23764. }
  23765. this.c.enable = true;
  23766. return this;
  23767. },
  23768. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23769. * Constructor
  23770. */
  23771. _constructor: function ()
  23772. {
  23773. var that = this;
  23774. var dt = this.s.dt;
  23775. dt.on( 'draw.dtrg', function () {
  23776. if ( that.c.enable ) {
  23777. that._draw();
  23778. }
  23779. } );
  23780. dt.on( 'column-visibility.dt.dtrg responsive-resize.dt.dtrg', function () {
  23781. that._adjustColspan();
  23782. } );
  23783. dt.on( 'destroy', function () {
  23784. dt.off( '.dtrg' );
  23785. } );
  23786. dt.on('responsive-resize.dt', function () {
  23787. that._adjustColspan();
  23788. })
  23789. },
  23790. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23791. * Private methods
  23792. */
  23793. /**
  23794. * Adjust column span when column visibility changes
  23795. * @private
  23796. */
  23797. _adjustColspan: function ()
  23798. {
  23799. $( 'tr.'+this.c.className, this.s.dt.table().body() ).find('td')
  23800. .attr( 'colspan', this._colspan() );
  23801. },
  23802. /**
  23803. * Get the number of columns that a grouping row should span
  23804. * @private
  23805. */
  23806. _colspan: function ()
  23807. {
  23808. return this.s.dt.columns().visible().reduce( function (a, b) {
  23809. return a + b;
  23810. }, 0 );
  23811. },
  23812. /**
  23813. * Update function that is called whenever we need to draw the grouping rows.
  23814. * This is basically a bootstrap for the self iterative _group and _groupDisplay
  23815. * methods
  23816. * @private
  23817. */
  23818. _draw: function ()
  23819. {
  23820. var dt = this.s.dt;
  23821. var groupedRows = this._group( 0, dt.rows( { page: 'current' } ).indexes() );
  23822. this._groupDisplay( 0, groupedRows );
  23823. },
  23824. /**
  23825. * Get the grouping information from a data set (index) of rows
  23826. * @param {number} level Nesting level
  23827. * @param {DataTables.Api} rows API of the rows to consider for this group
  23828. * @returns {object[]} Nested grouping information - it is structured like this:
  23829. * {
  23830. * dataPoint: 'Edinburgh',
  23831. * rows: [ 1,2,3,4,5,6,7 ],
  23832. * children: [ {
  23833. * dataPoint: 'developer'
  23834. * rows: [ 1, 2, 3 ]
  23835. * },
  23836. * {
  23837. * dataPoint: 'support',
  23838. * rows: [ 4, 5, 6, 7 ]
  23839. * } ]
  23840. * }
  23841. * @private
  23842. */
  23843. _group: function ( level, rows ) {
  23844. var fns = $.isArray( this.c.dataSrc ) ? this.c.dataSrc : [ this.c.dataSrc ];
  23845. var fn = DataTable.ext.oApi._fnGetObjectDataFn( fns[ level ] );
  23846. var dt = this.s.dt;
  23847. var group, last;
  23848. var data = [];
  23849. var that = this;
  23850. for ( var i=0, ien=rows.length ; i<ien ; i++ ) {
  23851. var rowIndex = rows[i];
  23852. var rowData = dt.row( rowIndex ).data();
  23853. var group = fn( rowData );
  23854. if ( group === null || group === undefined ) {
  23855. group = that.c.emptyDataGroup;
  23856. }
  23857. if ( last === undefined || group !== last ) {
  23858. data.push( {
  23859. dataPoint: group,
  23860. rows: []
  23861. } );
  23862. last = group;
  23863. }
  23864. data[ data.length-1 ].rows.push( rowIndex );
  23865. }
  23866. if ( fns[ level+1 ] !== undefined ) {
  23867. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  23868. data[i].children = this._group( level+1, data[i].rows );
  23869. }
  23870. }
  23871. return data;
  23872. },
  23873. /**
  23874. * Row group display - insert the rows into the document
  23875. * @param {number} level Nesting level
  23876. * @param {object[]} groups Takes the nested array from `_group`
  23877. * @private
  23878. */
  23879. _groupDisplay: function ( level, groups )
  23880. {
  23881. var dt = this.s.dt;
  23882. var display;
  23883. for ( var i=0, ien=groups.length ; i<ien ; i++ ) {
  23884. var group = groups[i];
  23885. var groupName = group.dataPoint;
  23886. var row;
  23887. var rows = group.rows;
  23888. if ( this.c.startRender ) {
  23889. display = this.c.startRender.call( this, dt.rows(rows), groupName, level );
  23890. row = this._rowWrap( display, this.c.startClassName, level );
  23891. if ( row ) {
  23892. row.insertBefore( dt.row( rows[0] ).node() );
  23893. }
  23894. }
  23895. if ( this.c.endRender ) {
  23896. display = this.c.endRender.call( this, dt.rows(rows), groupName, level );
  23897. row = this._rowWrap( display, this.c.endClassName, level );
  23898. if ( row ) {
  23899. row.insertAfter( dt.row( rows[ rows.length-1 ] ).node() );
  23900. }
  23901. }
  23902. if ( group.children ) {
  23903. this._groupDisplay( level+1, group.children );
  23904. }
  23905. }
  23906. },
  23907. /**
  23908. * Take a rendered value from an end user and make it suitable for display
  23909. * as a row, by wrapping it in a row, or detecting that it is a row.
  23910. * @param {node|jQuery|string} display Display value
  23911. * @param {string} className Class to add to the row
  23912. * @param {array} group
  23913. * @param {number} group level
  23914. * @private
  23915. */
  23916. _rowWrap: function ( display, className, level )
  23917. {
  23918. var row;
  23919. if ( display === null || display === '' ) {
  23920. display = this.c.emptyDataGroup;
  23921. }
  23922. if ( display === undefined || display === null ) {
  23923. return null;
  23924. }
  23925. if ( typeof display === 'object' && display.nodeName && display.nodeName.toLowerCase() === 'tr') {
  23926. row = $(display);
  23927. }
  23928. else if (display instanceof $ && display.length && display[0].nodeName.toLowerCase() === 'tr') {
  23929. row = display;
  23930. }
  23931. else {
  23932. row = $('<tr/>')
  23933. .append(
  23934. $('<td/>')
  23935. .attr( 'colspan', this._colspan() )
  23936. .append( display )
  23937. );
  23938. }
  23939. return row
  23940. .addClass( this.c.className )
  23941. .addClass( className )
  23942. .addClass( 'dtrg-level-'+level );
  23943. }
  23944. } );
  23945. /**
  23946. * RowGroup default settings for initialisation
  23947. *
  23948. * @namespace
  23949. * @name RowGroup.defaults
  23950. * @static
  23951. */
  23952. RowGroup.defaults = {
  23953. /**
  23954. * Class to apply to grouping rows - applied to both the start and
  23955. * end grouping rows.
  23956. * @type string
  23957. */
  23958. className: 'dtrg-group',
  23959. /**
  23960. * Data property from which to read the grouping information
  23961. * @type string|integer|array
  23962. */
  23963. dataSrc: 0,
  23964. /**
  23965. * Text to show if no data is found for a group
  23966. * @type string
  23967. */
  23968. emptyDataGroup: 'No group',
  23969. /**
  23970. * Initial enablement state
  23971. * @boolean
  23972. */
  23973. enable: true,
  23974. /**
  23975. * Class name to give to the end grouping row
  23976. * @type string
  23977. */
  23978. endClassName: 'dtrg-end',
  23979. /**
  23980. * End grouping label function
  23981. * @function
  23982. */
  23983. endRender: null,
  23984. /**
  23985. * Class name to give to the start grouping row
  23986. * @type string
  23987. */
  23988. startClassName: 'dtrg-start',
  23989. /**
  23990. * Start grouping label function
  23991. * @function
  23992. */
  23993. startRender: function ( rows, group ) {
  23994. return group;
  23995. }
  23996. };
  23997. RowGroup.version = "1.1.1";
  23998. $.fn.dataTable.RowGroup = RowGroup;
  23999. $.fn.DataTable.RowGroup = RowGroup;
  24000. DataTable.Api.register( 'rowGroup()', function () {
  24001. return this;
  24002. } );
  24003. DataTable.Api.register( 'rowGroup().disable()', function () {
  24004. return this.iterator( 'table', function (ctx) {
  24005. if ( ctx.rowGroup ) {
  24006. ctx.rowGroup.enable( false );
  24007. }
  24008. } );
  24009. } );
  24010. DataTable.Api.register( 'rowGroup().enable()', function ( opts ) {
  24011. return this.iterator( 'table', function (ctx) {
  24012. if ( ctx.rowGroup ) {
  24013. ctx.rowGroup.enable( opts === undefined ? true : opts );
  24014. }
  24015. } );
  24016. } );
  24017. DataTable.Api.register( 'rowGroup().dataSrc()', function ( val ) {
  24018. if ( val === undefined ) {
  24019. return this.context[0].rowGroup.dataSrc();
  24020. }
  24021. return this.iterator( 'table', function (ctx) {
  24022. if ( ctx.rowGroup ) {
  24023. ctx.rowGroup.dataSrc( val );
  24024. }
  24025. } );
  24026. } );
  24027. // Attach a listener to the document which listens for DataTables initialisation
  24028. // events so we can automatically initialise
  24029. $(document).on( 'preInit.dt.dtrg', function (e, settings, json) {
  24030. if ( e.namespace !== 'dt' ) {
  24031. return;
  24032. }
  24033. var init = settings.oInit.rowGroup;
  24034. var defaults = DataTable.defaults.rowGroup;
  24035. if ( init || defaults ) {
  24036. var opts = $.extend( {}, defaults, init );
  24037. if ( init !== false ) {
  24038. new RowGroup( settings, opts );
  24039. }
  24040. }
  24041. } );
  24042. return RowGroup;
  24043. }));
  24044. /*! Bootstrap 4 styling wrapper for RowGroup
  24045. * ©2018 SpryMedia Ltd - datatables.net/license
  24046. */
  24047. (function( factory ){
  24048. if ( typeof define === 'function' && define.amd ) {
  24049. // AMD
  24050. define( ['jquery', 'datatables.net-bs4', 'datatables.net-rowgroup'], function ( $ ) {
  24051. return factory( $, window, document );
  24052. } );
  24053. }
  24054. else if ( typeof exports === 'object' ) {
  24055. // CommonJS
  24056. module.exports = function (root, $) {
  24057. if ( ! root ) {
  24058. root = window;
  24059. }
  24060. if ( ! $ || ! $.fn.dataTable ) {
  24061. $ = require('datatables.net-bs4')(root, $).$;
  24062. }
  24063. if ( ! $.fn.dataTable.RowGroup ) {
  24064. require('datatables.net-rowgroup')(root, $);
  24065. }
  24066. return factory( $, root, root.document );
  24067. };
  24068. }
  24069. else {
  24070. // Browser
  24071. factory( jQuery, window, document );
  24072. }
  24073. }(function( $, window, document, undefined ) {
  24074. return $.fn.dataTable;
  24075. }));
  24076. /*! RowReorder 1.2.6
  24077. * 2015-2019 SpryMedia Ltd - datatables.net/license
  24078. */
  24079. /**
  24080. * @summary RowReorder
  24081. * @description Row reordering extension for DataTables
  24082. * @version 1.2.6
  24083. * @file dataTables.rowReorder.js
  24084. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  24085. * @contact www.sprymedia.co.uk/contact
  24086. * @copyright Copyright 2015-2019 SpryMedia Ltd.
  24087. *
  24088. * This source file is free software, available under the following license:
  24089. * MIT license - http://datatables.net/license/mit
  24090. *
  24091. * This source file is distributed in the hope that it will be useful, but
  24092. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  24093. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  24094. *
  24095. * For details please refer to: http://www.datatables.net
  24096. */
  24097. (function( factory ){
  24098. if ( typeof define === 'function' && define.amd ) {
  24099. // AMD
  24100. define( ['jquery', 'datatables.net'], function ( $ ) {
  24101. return factory( $, window, document );
  24102. } );
  24103. }
  24104. else if ( typeof exports === 'object' ) {
  24105. // CommonJS
  24106. module.exports = function (root, $) {
  24107. if ( ! root ) {
  24108. root = window;
  24109. }
  24110. if ( ! $ || ! $.fn.dataTable ) {
  24111. $ = require('datatables.net')(root, $).$;
  24112. }
  24113. return factory( $, root, root.document );
  24114. };
  24115. }
  24116. else {
  24117. // Browser
  24118. factory( jQuery, window, document );
  24119. }
  24120. }(function( $, window, document, undefined ) {
  24121. 'use strict';
  24122. var DataTable = $.fn.dataTable;
  24123. /**
  24124. * RowReorder provides the ability in DataTables to click and drag rows to
  24125. * reorder them. When a row is dropped the data for the rows effected will be
  24126. * updated to reflect the change. Normally this data point should also be the
  24127. * column being sorted upon in the DataTable but this does not need to be the
  24128. * case. RowReorder implements a "data swap" method - so the rows being
  24129. * reordered take the value of the data point from the row that used to occupy
  24130. * the row's new position.
  24131. *
  24132. * Initialisation is done by either:
  24133. *
  24134. * * `rowReorder` parameter in the DataTable initialisation object
  24135. * * `new $.fn.dataTable.RowReorder( table, opts )` after DataTables
  24136. * initialisation.
  24137. *
  24138. * @class
  24139. * @param {object} settings DataTables settings object for the host table
  24140. * @param {object} [opts] Configuration options
  24141. * @requires jQuery 1.7+
  24142. * @requires DataTables 1.10.7+
  24143. */
  24144. var RowReorder = function ( dt, opts ) {
  24145. // Sanity check that we are using DataTables 1.10 or newer
  24146. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
  24147. throw 'DataTables RowReorder requires DataTables 1.10.8 or newer';
  24148. }
  24149. // User and defaults configuration object
  24150. this.c = $.extend( true, {},
  24151. DataTable.defaults.rowReorder,
  24152. RowReorder.defaults,
  24153. opts
  24154. );
  24155. // Internal settings
  24156. this.s = {
  24157. /** @type {integer} Scroll body top cache */
  24158. bodyTop: null,
  24159. /** @type {DataTable.Api} DataTables' API instance */
  24160. dt: new DataTable.Api( dt ),
  24161. /** @type {function} Data fetch function */
  24162. getDataFn: DataTable.ext.oApi._fnGetObjectDataFn( this.c.dataSrc ),
  24163. /** @type {array} Pixel positions for row insertion calculation */
  24164. middles: null,
  24165. /** @type {Object} Cached dimension information for use in the mouse move event handler */
  24166. scroll: {},
  24167. /** @type {integer} Interval object used for smooth scrolling */
  24168. scrollInterval: null,
  24169. /** @type {function} Data set function */
  24170. setDataFn: DataTable.ext.oApi._fnSetObjectDataFn( this.c.dataSrc ),
  24171. /** @type {Object} Mouse down information */
  24172. start: {
  24173. top: 0,
  24174. left: 0,
  24175. offsetTop: 0,
  24176. offsetLeft: 0,
  24177. nodes: []
  24178. },
  24179. /** @type {integer} Window height cached value */
  24180. windowHeight: 0,
  24181. /** @type {integer} Document outer height cached value */
  24182. documentOuterHeight: 0,
  24183. /** @type {integer} DOM clone outer height cached value */
  24184. domCloneOuterHeight: 0
  24185. };
  24186. // DOM items
  24187. this.dom = {
  24188. /** @type {jQuery} Cloned row being moved around */
  24189. clone: null,
  24190. /** @type {jQuery} DataTables scrolling container */
  24191. dtScroll: $('div.dataTables_scrollBody', this.s.dt.table().container())
  24192. };
  24193. // Check if row reorder has already been initialised on this table
  24194. var settings = this.s.dt.settings()[0];
  24195. var exisiting = settings.rowreorder;
  24196. if ( exisiting ) {
  24197. return exisiting;
  24198. }
  24199. settings.rowreorder = this;
  24200. this._constructor();
  24201. };
  24202. $.extend( RowReorder.prototype, {
  24203. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  24204. * Constructor
  24205. */
  24206. /**
  24207. * Initialise the RowReorder instance
  24208. *
  24209. * @private
  24210. */
  24211. _constructor: function ()
  24212. {
  24213. var that = this;
  24214. var dt = this.s.dt;
  24215. var table = $( dt.table().node() );
  24216. // Need to be able to calculate the row positions relative to the table
  24217. if ( table.css('position') === 'static' ) {
  24218. table.css( 'position', 'relative' );
  24219. }
  24220. // listen for mouse down on the target column - we have to implement
  24221. // this rather than using HTML5 drag and drop as drag and drop doesn't
  24222. // appear to work on table rows at this time. Also mobile browsers are
  24223. // not supported.
  24224. // Use `table().container()` rather than just the table node for IE8 -
  24225. // otherwise it only works once...
  24226. $(dt.table().container()).on( 'mousedown.rowReorder touchstart.rowReorder', this.c.selector, function (e) {
  24227. if ( ! that.c.enable ) {
  24228. return;
  24229. }
  24230. // Ignore excluded children of the selector
  24231. if ( $(e.target).is(that.c.excludedChildren) ) {
  24232. return true;
  24233. }
  24234. var tr = $(this).closest('tr');
  24235. var row = dt.row( tr );
  24236. // Double check that it is a DataTable row
  24237. if ( row.any() ) {
  24238. that._emitEvent( 'pre-row-reorder', {
  24239. node: row.node(),
  24240. index: row.index()
  24241. } );
  24242. that._mouseDown( e, tr );
  24243. return false;
  24244. }
  24245. } );
  24246. dt.on( 'destroy.rowReorder', function () {
  24247. $(dt.table().container()).off( '.rowReorder' );
  24248. dt.off( '.rowReorder' );
  24249. } );
  24250. },
  24251. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  24252. * Private methods
  24253. */
  24254. /**
  24255. * Cache the measurements that RowReorder needs in the mouse move handler
  24256. * to attempt to speed things up, rather than reading from the DOM.
  24257. *
  24258. * @private
  24259. */
  24260. _cachePositions: function ()
  24261. {
  24262. var dt = this.s.dt;
  24263. // Frustratingly, if we add `position:relative` to the tbody, the
  24264. // position is still relatively to the parent. So we need to adjust
  24265. // for that
  24266. var headerHeight = $( dt.table().node() ).find('thead').outerHeight();
  24267. // Need to pass the nodes through jQuery to get them in document order,
  24268. // not what DataTables thinks it is, since we have been altering the
  24269. // order
  24270. var nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  24271. var tops = $.map( nodes, function ( node, i ) {
  24272. return $(node).position().top - headerHeight;
  24273. } );
  24274. var middles = $.map( tops, function ( top, i ) {
  24275. return tops.length < i-1 ?
  24276. (top + tops[i+1]) / 2 :
  24277. (top + top + $( dt.row( ':last-child' ).node() ).outerHeight() ) / 2;
  24278. } );
  24279. this.s.middles = middles;
  24280. this.s.bodyTop = $( dt.table().body() ).offset().top;
  24281. this.s.windowHeight = $(window).height();
  24282. this.s.documentOuterHeight = $(document).outerHeight();
  24283. },
  24284. /**
  24285. * Clone a row so it can be floated around the screen
  24286. *
  24287. * @param {jQuery} target Node to be cloned
  24288. * @private
  24289. */
  24290. _clone: function ( target )
  24291. {
  24292. var dt = this.s.dt;
  24293. var clone = $( dt.table().node().cloneNode(false) )
  24294. .addClass( 'dt-rowReorder-float' )
  24295. .append('<tbody/>')
  24296. .append( target.clone( false ) );
  24297. // Match the table and column widths - read all sizes before setting
  24298. // to reduce reflows
  24299. var tableWidth = target.outerWidth();
  24300. var tableHeight = target.outerHeight();
  24301. var sizes = target.children().map( function () {
  24302. return $(this).width();
  24303. } );
  24304. clone
  24305. .width( tableWidth )
  24306. .height( tableHeight )
  24307. .find('tr').children().each( function (i) {
  24308. this.style.width = sizes[i]+'px';
  24309. } );
  24310. // Insert into the document to have it floating around
  24311. clone.appendTo( 'body' );
  24312. this.dom.clone = clone;
  24313. this.s.domCloneOuterHeight = clone.outerHeight();
  24314. },
  24315. /**
  24316. * Update the cloned item's position in the document
  24317. *
  24318. * @param {object} e Event giving the mouse's position
  24319. * @private
  24320. */
  24321. _clonePosition: function ( e )
  24322. {
  24323. var start = this.s.start;
  24324. var topDiff = this._eventToPage( e, 'Y' ) - start.top;
  24325. var leftDiff = this._eventToPage( e, 'X' ) - start.left;
  24326. var snap = this.c.snapX;
  24327. var left;
  24328. var top = topDiff + start.offsetTop;
  24329. if ( snap === true ) {
  24330. left = start.offsetLeft;
  24331. }
  24332. else if ( typeof snap === 'number' ) {
  24333. left = start.offsetLeft + snap;
  24334. }
  24335. else {
  24336. left = leftDiff + start.offsetLeft;
  24337. }
  24338. if(top < 0) {
  24339. top = 0
  24340. }
  24341. else if(top + this.s.domCloneOuterHeight > this.s.documentOuterHeight) {
  24342. top = this.s.documentOuterHeight - this.s.domCloneOuterHeight;
  24343. }
  24344. this.dom.clone.css( {
  24345. top: top,
  24346. left: left
  24347. } );
  24348. },
  24349. /**
  24350. * Emit an event on the DataTable for listeners
  24351. *
  24352. * @param {string} name Event name
  24353. * @param {array} args Event arguments
  24354. * @private
  24355. */
  24356. _emitEvent: function ( name, args )
  24357. {
  24358. this.s.dt.iterator( 'table', function ( ctx, i ) {
  24359. $(ctx.nTable).triggerHandler( name+'.dt', args );
  24360. } );
  24361. },
  24362. /**
  24363. * Get pageX/Y position from an event, regardless of if it is a mouse or
  24364. * touch event.
  24365. *
  24366. * @param {object} e Event
  24367. * @param {string} pos X or Y (must be a capital)
  24368. * @private
  24369. */
  24370. _eventToPage: function ( e, pos )
  24371. {
  24372. if ( e.type.indexOf( 'touch' ) !== -1 ) {
  24373. return e.originalEvent.touches[0][ 'page'+pos ];
  24374. }
  24375. return e[ 'page'+pos ];
  24376. },
  24377. /**
  24378. * Mouse down event handler. Read initial positions and add event handlers
  24379. * for the move.
  24380. *
  24381. * @param {object} e Mouse event
  24382. * @param {jQuery} target TR element that is to be moved
  24383. * @private
  24384. */
  24385. _mouseDown: function ( e, target )
  24386. {
  24387. var that = this;
  24388. var dt = this.s.dt;
  24389. var start = this.s.start;
  24390. var offset = target.offset();
  24391. start.top = this._eventToPage( e, 'Y' );
  24392. start.left = this._eventToPage( e, 'X' );
  24393. start.offsetTop = offset.top;
  24394. start.offsetLeft = offset.left;
  24395. start.nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  24396. this._cachePositions();
  24397. this._clone( target );
  24398. this._clonePosition( e );
  24399. this.dom.target = target;
  24400. target.addClass( 'dt-rowReorder-moving' );
  24401. $( document )
  24402. .on( 'mouseup.rowReorder touchend.rowReorder', function (e) {
  24403. that._mouseUp(e);
  24404. } )
  24405. .on( 'mousemove.rowReorder touchmove.rowReorder', function (e) {
  24406. that._mouseMove(e);
  24407. } );
  24408. // Check if window is x-scrolling - if not, disable it for the duration
  24409. // of the drag
  24410. if ( $(window).width() === $(document).width() ) {
  24411. $(document.body).addClass( 'dt-rowReorder-noOverflow' );
  24412. }
  24413. // Cache scrolling information so mouse move doesn't need to read.
  24414. // This assumes that the window and DT scroller will not change size
  24415. // during an row drag, which I think is a fair assumption
  24416. var scrollWrapper = this.dom.dtScroll;
  24417. this.s.scroll = {
  24418. windowHeight: $(window).height(),
  24419. windowWidth: $(window).width(),
  24420. dtTop: scrollWrapper.length ? scrollWrapper.offset().top : null,
  24421. dtLeft: scrollWrapper.length ? scrollWrapper.offset().left : null,
  24422. dtHeight: scrollWrapper.length ? scrollWrapper.outerHeight() : null,
  24423. dtWidth: scrollWrapper.length ? scrollWrapper.outerWidth() : null
  24424. };
  24425. },
  24426. /**
  24427. * Mouse move event handler - move the cloned row and shuffle the table's
  24428. * rows if required.
  24429. *
  24430. * @param {object} e Mouse event
  24431. * @private
  24432. */
  24433. _mouseMove: function ( e )
  24434. {
  24435. this._clonePosition( e );
  24436. // Transform the mouse position into a position in the table's body
  24437. var bodyY = this._eventToPage( e, 'Y' ) - this.s.bodyTop;
  24438. var middles = this.s.middles;
  24439. var insertPoint = null;
  24440. var dt = this.s.dt;
  24441. var body = dt.table().body();
  24442. // Determine where the row should be inserted based on the mouse
  24443. // position
  24444. for ( var i=0, ien=middles.length ; i<ien ; i++ ) {
  24445. if ( bodyY < middles[i] ) {
  24446. insertPoint = i;
  24447. break;
  24448. }
  24449. }
  24450. if ( insertPoint === null ) {
  24451. insertPoint = middles.length;
  24452. }
  24453. // Perform the DOM shuffle if it has changed from last time
  24454. if ( this.s.lastInsert === null || this.s.lastInsert !== insertPoint ) {
  24455. if ( insertPoint === 0 ) {
  24456. this.dom.target.prependTo( body );
  24457. }
  24458. else {
  24459. var nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  24460. if ( insertPoint > this.s.lastInsert ) {
  24461. this.dom.target.insertAfter( nodes[ insertPoint-1 ] );
  24462. }
  24463. else {
  24464. this.dom.target.insertBefore( nodes[ insertPoint ] );
  24465. }
  24466. }
  24467. this._cachePositions();
  24468. this.s.lastInsert = insertPoint;
  24469. }
  24470. this._shiftScroll( e );
  24471. },
  24472. /**
  24473. * Mouse up event handler - release the event handlers and perform the
  24474. * table updates
  24475. *
  24476. * @param {object} e Mouse event
  24477. * @private
  24478. */
  24479. _mouseUp: function ( e )
  24480. {
  24481. var that = this;
  24482. var dt = this.s.dt;
  24483. var i, ien;
  24484. var dataSrc = this.c.dataSrc;
  24485. this.dom.clone.remove();
  24486. this.dom.clone = null;
  24487. this.dom.target.removeClass( 'dt-rowReorder-moving' );
  24488. //this.dom.target = null;
  24489. $(document).off( '.rowReorder' );
  24490. $(document.body).removeClass( 'dt-rowReorder-noOverflow' );
  24491. clearInterval( this.s.scrollInterval );
  24492. this.s.scrollInterval = null;
  24493. // Calculate the difference
  24494. var startNodes = this.s.start.nodes;
  24495. var endNodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  24496. var idDiff = {};
  24497. var fullDiff = [];
  24498. var diffNodes = [];
  24499. var getDataFn = this.s.getDataFn;
  24500. var setDataFn = this.s.setDataFn;
  24501. for ( i=0, ien=startNodes.length ; i<ien ; i++ ) {
  24502. if ( startNodes[i] !== endNodes[i] ) {
  24503. var id = dt.row( endNodes[i] ).id();
  24504. var endRowData = dt.row( endNodes[i] ).data();
  24505. var startRowData = dt.row( startNodes[i] ).data();
  24506. if ( id ) {
  24507. idDiff[ id ] = getDataFn( startRowData );
  24508. }
  24509. fullDiff.push( {
  24510. node: endNodes[i],
  24511. oldData: getDataFn( endRowData ),
  24512. newData: getDataFn( startRowData ),
  24513. newPosition: i,
  24514. oldPosition: $.inArray( endNodes[i], startNodes )
  24515. } );
  24516. diffNodes.push( endNodes[i] );
  24517. }
  24518. }
  24519. // Create event args
  24520. var eventArgs = [ fullDiff, {
  24521. dataSrc: dataSrc,
  24522. nodes: diffNodes,
  24523. values: idDiff,
  24524. triggerRow: dt.row( this.dom.target ),
  24525. originalEvent: e
  24526. } ];
  24527. // Emit event
  24528. this._emitEvent( 'row-reorder', eventArgs );
  24529. var update = function () {
  24530. if ( that.c.update ) {
  24531. for ( i=0, ien=fullDiff.length ; i<ien ; i++ ) {
  24532. var row = dt.row( fullDiff[i].node );
  24533. var rowData = row.data();
  24534. setDataFn( rowData, fullDiff[i].newData );
  24535. // Invalidate the cell that has the same data source as the dataSrc
  24536. dt.columns().every( function () {
  24537. if ( this.dataSrc() === dataSrc ) {
  24538. dt.cell( fullDiff[i].node, this.index() ).invalidate( 'data' );
  24539. }
  24540. } );
  24541. }
  24542. // Trigger row reordered event
  24543. that._emitEvent( 'row-reordered', eventArgs );
  24544. dt.draw( false );
  24545. }
  24546. };
  24547. // Editor interface
  24548. if ( this.c.editor ) {
  24549. // Disable user interaction while Editor is submitting
  24550. this.c.enable = false;
  24551. this.c.editor
  24552. .edit(
  24553. diffNodes,
  24554. false,
  24555. $.extend( {submit: 'changed'}, this.c.formOptions )
  24556. )
  24557. .multiSet( dataSrc, idDiff )
  24558. .one( 'preSubmitCancelled.rowReorder', function () {
  24559. that.c.enable = true;
  24560. that.c.editor.off( '.rowReorder' );
  24561. dt.draw( false );
  24562. } )
  24563. .one( 'submitUnsuccessful.rowReorder', function () {
  24564. dt.draw( false );
  24565. } )
  24566. .one( 'submitSuccess.rowReorder', function () {
  24567. update();
  24568. } )
  24569. .one( 'submitComplete', function () {
  24570. that.c.enable = true;
  24571. that.c.editor.off( '.rowReorder' );
  24572. } )
  24573. .submit();
  24574. }
  24575. else {
  24576. update();
  24577. }
  24578. },
  24579. /**
  24580. * Move the window and DataTables scrolling during a drag to scroll new
  24581. * content into view.
  24582. *
  24583. * This matches the `_shiftScroll` method used in AutoFill, but only
  24584. * horizontal scrolling is considered here.
  24585. *
  24586. * @param {object} e Mouse move event object
  24587. * @private
  24588. */
  24589. _shiftScroll: function ( e )
  24590. {
  24591. var that = this;
  24592. var dt = this.s.dt;
  24593. var scroll = this.s.scroll;
  24594. var runInterval = false;
  24595. var scrollSpeed = 5;
  24596. var buffer = 65;
  24597. var
  24598. windowY = e.pageY - document.body.scrollTop,
  24599. windowVert,
  24600. dtVert;
  24601. // Window calculations - based on the mouse position in the window,
  24602. // regardless of scrolling
  24603. if ( windowY < buffer ) {
  24604. windowVert = scrollSpeed * -1;
  24605. }
  24606. else if ( windowY > scroll.windowHeight - buffer ) {
  24607. windowVert = scrollSpeed;
  24608. }
  24609. // DataTables scrolling calculations - based on the table's position in
  24610. // the document and the mouse position on the page
  24611. if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {
  24612. dtVert = scrollSpeed * -1;
  24613. }
  24614. else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
  24615. dtVert = scrollSpeed;
  24616. }
  24617. // This is where it gets interesting. We want to continue scrolling
  24618. // without requiring a mouse move, so we need an interval to be
  24619. // triggered. The interval should continue until it is no longer needed,
  24620. // but it must also use the latest scroll commands (for example consider
  24621. // that the mouse might move from scrolling up to scrolling left, all
  24622. // with the same interval running. We use the `scroll` object to "pass"
  24623. // this information to the interval. Can't use local variables as they
  24624. // wouldn't be the ones that are used by an already existing interval!
  24625. if ( windowVert || dtVert ) {
  24626. scroll.windowVert = windowVert;
  24627. scroll.dtVert = dtVert;
  24628. runInterval = true;
  24629. }
  24630. else if ( this.s.scrollInterval ) {
  24631. // Don't need to scroll - remove any existing timer
  24632. clearInterval( this.s.scrollInterval );
  24633. this.s.scrollInterval = null;
  24634. }
  24635. // If we need to run the interval to scroll and there is no existing
  24636. // interval (if there is an existing one, it will continue to run)
  24637. if ( ! this.s.scrollInterval && runInterval ) {
  24638. this.s.scrollInterval = setInterval( function () {
  24639. // Don't need to worry about setting scroll <0 or beyond the
  24640. // scroll bound as the browser will just reject that.
  24641. if ( scroll.windowVert ) {
  24642. document.body.scrollTop += scroll.windowVert;
  24643. }
  24644. // DataTables scrolling
  24645. if ( scroll.dtVert ) {
  24646. var scroller = that.dom.dtScroll[0];
  24647. if ( scroll.dtVert ) {
  24648. scroller.scrollTop += scroll.dtVert;
  24649. }
  24650. }
  24651. }, 20 );
  24652. }
  24653. }
  24654. } );
  24655. /**
  24656. * RowReorder default settings for initialisation
  24657. *
  24658. * @namespace
  24659. * @name RowReorder.defaults
  24660. * @static
  24661. */
  24662. RowReorder.defaults = {
  24663. /**
  24664. * Data point in the host row's data source object for where to get and set
  24665. * the data to reorder. This will normally also be the sorting column.
  24666. *
  24667. * @type {Number}
  24668. */
  24669. dataSrc: 0,
  24670. /**
  24671. * Editor instance that will be used to perform the update
  24672. *
  24673. * @type {DataTable.Editor}
  24674. */
  24675. editor: null,
  24676. /**
  24677. * Enable / disable RowReorder's user interaction
  24678. * @type {Boolean}
  24679. */
  24680. enable: true,
  24681. /**
  24682. * Form options to pass to Editor when submitting a change in the row order.
  24683. * See the Editor `from-options` object for details of the options
  24684. * available.
  24685. * @type {Object}
  24686. */
  24687. formOptions: {},
  24688. /**
  24689. * Drag handle selector. This defines the element that when dragged will
  24690. * reorder a row.
  24691. *
  24692. * @type {String}
  24693. */
  24694. selector: 'td:first-child',
  24695. /**
  24696. * Optionally lock the dragged row's x-position. This can be `true` to
  24697. * fix the position match the host table's, `false` to allow free movement
  24698. * of the row, or a number to define an offset from the host table.
  24699. *
  24700. * @type {Boolean|number}
  24701. */
  24702. snapX: false,
  24703. /**
  24704. * Update the table's data on drop
  24705. *
  24706. * @type {Boolean}
  24707. */
  24708. update: true,
  24709. /**
  24710. * Selector for children of the drag handle selector that mouseDown events
  24711. * will be passed through to and drag will not activate
  24712. *
  24713. * @type {String}
  24714. */
  24715. excludedChildren: 'a'
  24716. };
  24717. /*
  24718. * API
  24719. */
  24720. var Api = $.fn.dataTable.Api;
  24721. // Doesn't do anything - work around for a bug in DT... Not documented
  24722. Api.register( 'rowReorder()', function () {
  24723. return this;
  24724. } );
  24725. Api.register( 'rowReorder.enable()', function ( toggle ) {
  24726. if ( toggle === undefined ) {
  24727. toggle = true;
  24728. }
  24729. return this.iterator( 'table', function ( ctx ) {
  24730. if ( ctx.rowreorder ) {
  24731. ctx.rowreorder.c.enable = toggle;
  24732. }
  24733. } );
  24734. } );
  24735. Api.register( 'rowReorder.disable()', function () {
  24736. return this.iterator( 'table', function ( ctx ) {
  24737. if ( ctx.rowreorder ) {
  24738. ctx.rowreorder.c.enable = false;
  24739. }
  24740. } );
  24741. } );
  24742. /**
  24743. * Version information
  24744. *
  24745. * @name RowReorder.version
  24746. * @static
  24747. */
  24748. RowReorder.version = '1.2.6';
  24749. $.fn.dataTable.RowReorder = RowReorder;
  24750. $.fn.DataTable.RowReorder = RowReorder;
  24751. // Attach a listener to the document which listens for DataTables initialisation
  24752. // events so we can automatically initialise
  24753. $(document).on( 'init.dt.dtr', function (e, settings, json) {
  24754. if ( e.namespace !== 'dt' ) {
  24755. return;
  24756. }
  24757. var init = settings.oInit.rowReorder;
  24758. var defaults = DataTable.defaults.rowReorder;
  24759. if ( init || defaults ) {
  24760. var opts = $.extend( {}, init, defaults );
  24761. if ( init !== false ) {
  24762. new RowReorder( settings, opts );
  24763. }
  24764. }
  24765. } );
  24766. return RowReorder;
  24767. }));
  24768. /*! Bootstrap 4 styling wrapper for RowReorder
  24769. * ©2018 SpryMedia Ltd - datatables.net/license
  24770. */
  24771. (function( factory ){
  24772. if ( typeof define === 'function' && define.amd ) {
  24773. // AMD
  24774. define( ['jquery', 'datatables.net-bs4', 'datatables.net-rowreorder'], function ( $ ) {
  24775. return factory( $, window, document );
  24776. } );
  24777. }
  24778. else if ( typeof exports === 'object' ) {
  24779. // CommonJS
  24780. module.exports = function (root, $) {
  24781. if ( ! root ) {
  24782. root = window;
  24783. }
  24784. if ( ! $ || ! $.fn.dataTable ) {
  24785. $ = require('datatables.net-bs4')(root, $).$;
  24786. }
  24787. if ( ! $.fn.dataTable.RowReorder ) {
  24788. require('datatables.net-rowreorder')(root, $);
  24789. }
  24790. return factory( $, root, root.document );
  24791. };
  24792. }
  24793. else {
  24794. // Browser
  24795. factory( jQuery, window, document );
  24796. }
  24797. }(function( $, window, document, undefined ) {
  24798. return $.fn.dataTable;
  24799. }));
  24800. /*! Scroller 2.0.1
  24801. * ©2011-2019 SpryMedia Ltd - datatables.net/license
  24802. */
  24803. /**
  24804. * @summary Scroller
  24805. * @description Virtual rendering for DataTables
  24806. * @version 2.0.1
  24807. * @file dataTables.scroller.js
  24808. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  24809. * @contact www.sprymedia.co.uk/contact
  24810. * @copyright Copyright 2011-2019 SpryMedia Ltd.
  24811. *
  24812. * This source file is free software, available under the following license:
  24813. * MIT license - http://datatables.net/license/mit
  24814. *
  24815. * This source file is distributed in the hope that it will be useful, but
  24816. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  24817. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  24818. *
  24819. * For details please refer to: http://www.datatables.net
  24820. */
  24821. (function( factory ){
  24822. if ( typeof define === 'function' && define.amd ) {
  24823. // AMD
  24824. define( ['jquery', 'datatables.net'], function ( $ ) {
  24825. return factory( $, window, document );
  24826. } );
  24827. }
  24828. else if ( typeof exports === 'object' ) {
  24829. // CommonJS
  24830. module.exports = function (root, $) {
  24831. if ( ! root ) {
  24832. root = window;
  24833. }
  24834. if ( ! $ || ! $.fn.dataTable ) {
  24835. $ = require('datatables.net')(root, $).$;
  24836. }
  24837. return factory( $, root, root.document );
  24838. };
  24839. }
  24840. else {
  24841. // Browser
  24842. factory( jQuery, window, document );
  24843. }
  24844. }(function( $, window, document, undefined ) {
  24845. 'use strict';
  24846. var DataTable = $.fn.dataTable;
  24847. /**
  24848. * Scroller is a virtual rendering plug-in for DataTables which allows large
  24849. * datasets to be drawn on screen every quickly. What the virtual rendering means
  24850. * is that only the visible portion of the table (and a bit to either side to make
  24851. * the scrolling smooth) is drawn, while the scrolling container gives the
  24852. * visual impression that the whole table is visible. This is done by making use
  24853. * of the pagination abilities of DataTables and moving the table around in the
  24854. * scrolling container DataTables adds to the page. The scrolling container is
  24855. * forced to the height it would be for the full table display using an extra
  24856. * element.
  24857. *
  24858. * Note that rows in the table MUST all be the same height. Information in a cell
  24859. * which expands on to multiple lines will cause some odd behaviour in the scrolling.
  24860. *
  24861. * Scroller is initialised by simply including the letter 'S' in the sDom for the
  24862. * table you want to have this feature enabled on. Note that the 'S' must come
  24863. * AFTER the 't' parameter in `dom`.
  24864. *
  24865. * Key features include:
  24866. * <ul class="limit_length">
  24867. * <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>
  24868. * <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>
  24869. * <li>Display millions of rows</li>
  24870. * <li>Integration with state saving in DataTables (scrolling position is saved)</li>
  24871. * <li>Easy to use</li>
  24872. * </ul>
  24873. *
  24874. * @class
  24875. * @constructor
  24876. * @global
  24877. * @param {object} dt DataTables settings object or API instance
  24878. * @param {object} [opts={}] Configuration object for FixedColumns. Options
  24879. * are defined by {@link Scroller.defaults}
  24880. *
  24881. * @requires jQuery 1.7+
  24882. * @requires DataTables 1.10.0+
  24883. *
  24884. * @example
  24885. * $(document).ready(function() {
  24886. * $('#example').DataTable( {
  24887. * "scrollY": "200px",
  24888. * "ajax": "media/dataset/large.txt",
  24889. * "scroller": true,
  24890. * "deferRender": true
  24891. * } );
  24892. * } );
  24893. */
  24894. var Scroller = function ( dt, opts ) {
  24895. /* Sanity check - you just know it will happen */
  24896. if ( ! (this instanceof Scroller) ) {
  24897. alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." );
  24898. return;
  24899. }
  24900. if ( opts === undefined ) {
  24901. opts = {};
  24902. }
  24903. var dtApi = $.fn.dataTable.Api( dt );
  24904. /**
  24905. * Settings object which contains customisable information for the Scroller instance
  24906. * @namespace
  24907. * @private
  24908. * @extends Scroller.defaults
  24909. */
  24910. this.s = {
  24911. /**
  24912. * DataTables settings object
  24913. * @type object
  24914. * @default Passed in as first parameter to constructor
  24915. */
  24916. dt: dtApi.settings()[0],
  24917. /**
  24918. * DataTables API instance
  24919. * @type DataTable.Api
  24920. */
  24921. dtApi: dtApi,
  24922. /**
  24923. * Pixel location of the top of the drawn table in the viewport
  24924. * @type int
  24925. * @default 0
  24926. */
  24927. tableTop: 0,
  24928. /**
  24929. * Pixel location of the bottom of the drawn table in the viewport
  24930. * @type int
  24931. * @default 0
  24932. */
  24933. tableBottom: 0,
  24934. /**
  24935. * Pixel location of the boundary for when the next data set should be loaded and drawn
  24936. * when scrolling up the way.
  24937. * @type int
  24938. * @default 0
  24939. * @private
  24940. */
  24941. redrawTop: 0,
  24942. /**
  24943. * Pixel location of the boundary for when the next data set should be loaded and drawn
  24944. * when scrolling down the way. Note that this is actually calculated as the offset from
  24945. * the top.
  24946. * @type int
  24947. * @default 0
  24948. * @private
  24949. */
  24950. redrawBottom: 0,
  24951. /**
  24952. * Auto row height or not indicator
  24953. * @type bool
  24954. * @default 0
  24955. */
  24956. autoHeight: true,
  24957. /**
  24958. * Number of rows calculated as visible in the visible viewport
  24959. * @type int
  24960. * @default 0
  24961. */
  24962. viewportRows: 0,
  24963. /**
  24964. * setTimeout reference for state saving, used when state saving is enabled in the DataTable
  24965. * and when the user scrolls the viewport in order to stop the cookie set taking too much
  24966. * CPU!
  24967. * @type int
  24968. * @default 0
  24969. */
  24970. stateTO: null,
  24971. /**
  24972. * setTimeout reference for the redraw, used when server-side processing is enabled in the
  24973. * DataTables in order to prevent DoSing the server
  24974. * @type int
  24975. * @default null
  24976. */
  24977. drawTO: null,
  24978. heights: {
  24979. jump: null,
  24980. page: null,
  24981. virtual: null,
  24982. scroll: null,
  24983. /**
  24984. * Height of rows in the table
  24985. * @type int
  24986. * @default 0
  24987. */
  24988. row: null,
  24989. /**
  24990. * Pixel height of the viewport
  24991. * @type int
  24992. * @default 0
  24993. */
  24994. viewport: null,
  24995. labelFactor: 1
  24996. },
  24997. topRowFloat: 0,
  24998. scrollDrawDiff: null,
  24999. loaderVisible: false,
  25000. forceReposition: false,
  25001. baseRowTop: 0,
  25002. baseScrollTop: 0,
  25003. mousedown: false,
  25004. lastScrollTop: 0
  25005. };
  25006. // @todo The defaults should extend a `c` property and the internal settings
  25007. // only held in the `s` property. At the moment they are mixed
  25008. this.s = $.extend( this.s, Scroller.oDefaults, opts );
  25009. // Workaround for row height being read from height object (see above comment)
  25010. this.s.heights.row = this.s.rowHeight;
  25011. /**
  25012. * DOM elements used by the class instance
  25013. * @private
  25014. * @namespace
  25015. *
  25016. */
  25017. this.dom = {
  25018. "force": document.createElement('div'),
  25019. "label": $('<div class="dts_label">0</div>'),
  25020. "scroller": null,
  25021. "table": null,
  25022. "loader": null
  25023. };
  25024. // Attach the instance to the DataTables instance so it can be accessed in
  25025. // future. Don't initialise Scroller twice on the same table
  25026. if ( this.s.dt.oScroller ) {
  25027. return;
  25028. }
  25029. this.s.dt.oScroller = this;
  25030. /* Let's do it */
  25031. this.construct();
  25032. };
  25033. $.extend( Scroller.prototype, {
  25034. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  25035. * Public methods - to be exposed via the DataTables API
  25036. */
  25037. /**
  25038. * Calculate and store information about how many rows are to be displayed
  25039. * in the scrolling viewport, based on current dimensions in the browser's
  25040. * rendering. This can be particularly useful if the table is initially
  25041. * drawn in a hidden element - for example in a tab.
  25042. * @param {bool} [redraw=true] Redraw the table automatically after the recalculation, with
  25043. * the new dimensions forming the basis for the draw.
  25044. * @returns {void}
  25045. */
  25046. measure: function ( redraw )
  25047. {
  25048. if ( this.s.autoHeight )
  25049. {
  25050. this._calcRowHeight();
  25051. }
  25052. var heights = this.s.heights;
  25053. if ( heights.row ) {
  25054. heights.viewport = $.contains(document, this.dom.scroller) ?
  25055. this.dom.scroller.clientHeight :
  25056. this._parseHeight($(this.dom.scroller).css('height'));
  25057. // If collapsed (no height) use the max-height parameter
  25058. if ( ! heights.viewport ) {
  25059. heights.viewport = this._parseHeight($(this.dom.scroller).css('max-height'));
  25060. }
  25061. this.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;
  25062. this.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;
  25063. }
  25064. var label = this.dom.label.outerHeight();
  25065. heights.labelFactor = (heights.viewport-label) / heights.scroll;
  25066. if ( redraw === undefined || redraw )
  25067. {
  25068. this.s.dt.oInstance.fnDraw( false );
  25069. }
  25070. },
  25071. /**
  25072. * Get information about current displayed record range. This corresponds to
  25073. * the information usually displayed in the "Info" block of the table.
  25074. *
  25075. * @returns {object} info as an object:
  25076. * {
  25077. * start: {int}, // the 0-indexed record at the top of the viewport
  25078. * end: {int}, // the 0-indexed record at the bottom of the viewport
  25079. * }
  25080. */
  25081. pageInfo: function()
  25082. {
  25083. var
  25084. dt = this.s.dt,
  25085. iScrollTop = this.dom.scroller.scrollTop,
  25086. iTotal = dt.fnRecordsDisplay(),
  25087. iPossibleEnd = Math.ceil(this.pixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani));
  25088. return {
  25089. start: Math.floor(this.pixelsToRow(iScrollTop, false, this.s.ani)),
  25090. end: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1
  25091. };
  25092. },
  25093. /**
  25094. * Calculate the row number that will be found at the given pixel position
  25095. * (y-scroll).
  25096. *
  25097. * Please note that when the height of the full table exceeds 1 million
  25098. * pixels, Scroller switches into a non-linear mode for the scrollbar to fit
  25099. * all of the records into a finite area, but this function returns a linear
  25100. * value (relative to the last non-linear positioning).
  25101. * @param {int} pixels Offset from top to calculate the row number of
  25102. * @param {int} [intParse=true] If an integer value should be returned
  25103. * @param {int} [virtual=false] Perform the calculations in the virtual domain
  25104. * @returns {int} Row index
  25105. */
  25106. pixelsToRow: function ( pixels, intParse, virtual )
  25107. {
  25108. var diff = pixels - this.s.baseScrollTop;
  25109. var row = virtual ?
  25110. (this._domain( 'physicalToVirtual', this.s.baseScrollTop ) + diff) / this.s.heights.row :
  25111. ( diff / this.s.heights.row ) + this.s.baseRowTop;
  25112. return intParse || intParse === undefined ?
  25113. parseInt( row, 10 ) :
  25114. row;
  25115. },
  25116. /**
  25117. * Calculate the pixel position from the top of the scrolling container for
  25118. * a given row
  25119. * @param {int} iRow Row number to calculate the position of
  25120. * @returns {int} Pixels
  25121. */
  25122. rowToPixels: function ( rowIdx, intParse, virtual )
  25123. {
  25124. var pixels;
  25125. var diff = rowIdx - this.s.baseRowTop;
  25126. if ( virtual ) {
  25127. pixels = this._domain( 'virtualToPhysical', this.s.baseScrollTop );
  25128. pixels += diff * this.s.heights.row;
  25129. }
  25130. else {
  25131. pixels = this.s.baseScrollTop;
  25132. pixels += diff * this.s.heights.row;
  25133. }
  25134. return intParse || intParse === undefined ?
  25135. parseInt( pixels, 10 ) :
  25136. pixels;
  25137. },
  25138. /**
  25139. * Calculate the row number that will be found at the given pixel position (y-scroll)
  25140. * @param {int} row Row index to scroll to
  25141. * @param {bool} [animate=true] Animate the transition or not
  25142. * @returns {void}
  25143. */
  25144. scrollToRow: function ( row, animate )
  25145. {
  25146. var that = this;
  25147. var ani = false;
  25148. var px = this.rowToPixels( row );
  25149. // We need to know if the table will redraw or not before doing the
  25150. // scroll. If it will not redraw, then we need to use the currently
  25151. // displayed table, and scroll with the physical pixels. Otherwise, we
  25152. // need to calculate the table's new position from the virtual
  25153. // transform.
  25154. var preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;
  25155. var drawRow = row - preRows;
  25156. if ( drawRow < 0 ) {
  25157. drawRow = 0;
  25158. }
  25159. if ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {
  25160. ani = true;
  25161. px = this._domain( 'virtualToPhysical', row * this.s.heights.row );
  25162. // If we need records outside the current draw region, but the new
  25163. // scrolling position is inside that (due to the non-linear nature
  25164. // for larger numbers of records), we need to force position update.
  25165. if ( this.s.redrawTop < px && px < this.s.redrawBottom ) {
  25166. this.s.forceReposition = true;
  25167. animate = false;
  25168. }
  25169. }
  25170. if ( animate === undefined || animate )
  25171. {
  25172. this.s.ani = ani;
  25173. $(this.dom.scroller).animate( {
  25174. "scrollTop": px
  25175. }, function () {
  25176. // This needs to happen after the animation has completed and
  25177. // the final scroll event fired
  25178. setTimeout( function () {
  25179. that.s.ani = false;
  25180. }, 250 );
  25181. } );
  25182. }
  25183. else
  25184. {
  25185. $(this.dom.scroller).scrollTop( px );
  25186. }
  25187. },
  25188. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  25189. * Constructor
  25190. */
  25191. /**
  25192. * Initialisation for Scroller
  25193. * @returns {void}
  25194. * @private
  25195. */
  25196. construct: function ()
  25197. {
  25198. var that = this;
  25199. var dt = this.s.dtApi;
  25200. /* Sanity check */
  25201. if ( !this.s.dt.oFeatures.bPaginate ) {
  25202. this.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );
  25203. return;
  25204. }
  25205. /* Insert a div element that we can use to force the DT scrolling container to
  25206. * the height that would be required if the whole table was being displayed
  25207. */
  25208. this.dom.force.style.position = "relative";
  25209. this.dom.force.style.top = "0px";
  25210. this.dom.force.style.left = "0px";
  25211. this.dom.force.style.width = "1px";
  25212. this.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];
  25213. this.dom.scroller.appendChild( this.dom.force );
  25214. this.dom.scroller.style.position = "relative";
  25215. this.dom.table = $('>table', this.dom.scroller)[0];
  25216. this.dom.table.style.position = "absolute";
  25217. this.dom.table.style.top = "0px";
  25218. this.dom.table.style.left = "0px";
  25219. // Add class to 'announce' that we are a Scroller table
  25220. $(dt.table().container()).addClass('dts DTS');
  25221. // Add a 'loading' indicator
  25222. if ( this.s.loadingIndicator )
  25223. {
  25224. this.dom.loader = $('<div class="dataTables_processing dts_loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')
  25225. .css('display', 'none');
  25226. $(this.dom.scroller.parentNode)
  25227. .css('position', 'relative')
  25228. .append( this.dom.loader );
  25229. }
  25230. this.dom.label.appendTo(this.dom.scroller);
  25231. /* Initial size calculations */
  25232. if ( this.s.heights.row && this.s.heights.row != 'auto' )
  25233. {
  25234. this.s.autoHeight = false;
  25235. }
  25236. this.measure( false );
  25237. // Scrolling callback to see if a page change is needed - use a throttled
  25238. // function for the save save callback so we aren't hitting it on every
  25239. // scroll
  25240. this.s.ingnoreScroll = true;
  25241. this.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () {
  25242. that.s.dtApi.state.save();
  25243. }, 500 );
  25244. $(this.dom.scroller).on( 'scroll.dt-scroller', function (e) {
  25245. that._scroll.call( that );
  25246. } );
  25247. // In iOS we catch the touchstart event in case the user tries to scroll
  25248. // while the display is already scrolling
  25249. $(this.dom.scroller).on('touchstart.dt-scroller', function () {
  25250. that._scroll.call( that );
  25251. } );
  25252. $(this.dom.scroller)
  25253. .on('mousedown.dt-scroller', function () {
  25254. that.s.mousedown = true;
  25255. })
  25256. .on('mouseup.dt-scroller', function () {
  25257. that.s.mouseup = false;
  25258. that.dom.label.css('display', 'none');
  25259. });
  25260. // On resize, update the information element, since the number of rows shown might change
  25261. $(window).on( 'resize.dt-scroller', function () {
  25262. that.measure( false );
  25263. that._info();
  25264. } );
  25265. // Add a state saving parameter to the DT state saving so we can restore the exact
  25266. // position of the scrolling. Slightly surprisingly the scroll position isn't actually
  25267. // stored, but rather tha base units which are needed to calculate it. This allows for
  25268. // virtual scrolling as well.
  25269. var initialStateSave = true;
  25270. var loadedState = dt.state.loaded();
  25271. dt.on( 'stateSaveParams.scroller', function ( e, settings, data ) {
  25272. // Need to used the saved position on init
  25273. data.scroller = {
  25274. topRow: initialStateSave && loadedState && loadedState.scroller ?
  25275. loadedState.scroller.topRow :
  25276. that.s.topRowFloat,
  25277. baseScrollTop: that.s.baseScrollTop,
  25278. baseRowTop: that.s.baseRowTop
  25279. };
  25280. initialStateSave = false;
  25281. } );
  25282. if ( loadedState && loadedState.scroller ) {
  25283. this.s.topRowFloat = loadedState.scroller.topRow;
  25284. this.s.baseScrollTop = loadedState.scroller.baseScrollTop;
  25285. this.s.baseRowTop = loadedState.scroller.baseRowTop;
  25286. }
  25287. dt.on( 'init.scroller', function () {
  25288. that.measure( false );
  25289. // Setting to `jump` will instruct _draw to calculate the scroll top
  25290. // position
  25291. that.s.scrollType = 'jump';
  25292. that._draw();
  25293. // Update the scroller when the DataTable is redrawn
  25294. dt.on( 'draw.scroller', function () {
  25295. that._draw();
  25296. });
  25297. } );
  25298. // Set height before the draw happens, allowing everything else to update
  25299. // on draw complete without worry for roder.
  25300. dt.on( 'preDraw.dt.scroller', function () {
  25301. that._scrollForce();
  25302. } );
  25303. // Destructor
  25304. dt.on( 'destroy.scroller', function () {
  25305. $(window).off( 'resize.dt-scroller' );
  25306. $(that.dom.scroller).off('.dt-scroller');
  25307. $(that.s.dt.nTable).off( '.scroller' );
  25308. $(that.s.dt.nTableWrapper).removeClass('DTS');
  25309. $('div.DTS_Loading', that.dom.scroller.parentNode).remove();
  25310. that.dom.table.style.position = "";
  25311. that.dom.table.style.top = "";
  25312. that.dom.table.style.left = "";
  25313. } );
  25314. },
  25315. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  25316. * Private methods
  25317. */
  25318. /**
  25319. * Automatic calculation of table row height. This is just a little tricky here as using
  25320. * initialisation DataTables has tale the table out of the document, so we need to create
  25321. * a new table and insert it into the document, calculate the row height and then whip the
  25322. * table out.
  25323. * @returns {void}
  25324. * @private
  25325. */
  25326. _calcRowHeight: function ()
  25327. {
  25328. var dt = this.s.dt;
  25329. var origTable = dt.nTable;
  25330. var nTable = origTable.cloneNode( false );
  25331. var tbody = $('<tbody/>').appendTo( nTable );
  25332. var container = $(
  25333. '<div class="'+dt.oClasses.sWrapper+' DTS">'+
  25334. '<div class="'+dt.oClasses.sScrollWrapper+'">'+
  25335. '<div class="'+dt.oClasses.sScrollBody+'"></div>'+
  25336. '</div>'+
  25337. '</div>'
  25338. );
  25339. // Want 3 rows in the sizing table so :first-child and :last-child
  25340. // CSS styles don't come into play - take the size of the middle row
  25341. $('tbody tr:lt(4)', origTable).clone().appendTo( tbody );
  25342. var rowsCount = $('tr', tbody).length;
  25343. if ( rowsCount === 1 ) {
  25344. tbody.prepend('<tr><td>&#160;</td></tr>');
  25345. tbody.append('<tr><td>&#160;</td></tr>');
  25346. }
  25347. else {
  25348. for (; rowsCount < 3; rowsCount++) {
  25349. tbody.append('<tr><td>&#160;</td></tr>');
  25350. }
  25351. }
  25352. $('div.'+dt.oClasses.sScrollBody, container).append( nTable );
  25353. // If initialised using `dom`, use the holding element as the insert point
  25354. var insertEl = this.s.dt.nHolding || origTable.parentNode;
  25355. if ( ! $(insertEl).is(':visible') ) {
  25356. insertEl = 'body';
  25357. }
  25358. container.appendTo( insertEl );
  25359. this.s.heights.row = $('tr', tbody).eq(1).outerHeight();
  25360. container.remove();
  25361. },
  25362. /**
  25363. * Draw callback function which is fired when the DataTable is redrawn. The main function of
  25364. * this method is to position the drawn table correctly the scrolling container for the rows
  25365. * that is displays as a result of the scrolling position.
  25366. * @returns {void}
  25367. * @private
  25368. */
  25369. _draw: function ()
  25370. {
  25371. var
  25372. that = this,
  25373. heights = this.s.heights,
  25374. iScrollTop = this.dom.scroller.scrollTop,
  25375. iTableHeight = $(this.s.dt.nTable).height(),
  25376. displayStart = this.s.dt._iDisplayStart,
  25377. displayLen = this.s.dt._iDisplayLength,
  25378. displayEnd = this.s.dt.fnRecordsDisplay();
  25379. // Disable the scroll event listener while we are updating the DOM
  25380. this.s.skip = true;
  25381. // If paging is reset
  25382. if ( (this.s.dt.bSorted || this.s.dt.bFiltered) && displayStart === 0 && !this.s.dt._drawHold ) {
  25383. this.s.topRowFloat = 0;
  25384. }
  25385. iScrollTop = this.s.scrollType === 'jump' ?
  25386. this._domain( 'virtualToPhysical', this.s.topRowFloat * heights.row ) :
  25387. iScrollTop;
  25388. // Store positional information so positional calculations can be based
  25389. // upon the current table draw position
  25390. this.s.baseScrollTop = iScrollTop;
  25391. this.s.baseRowTop = this.s.topRowFloat;
  25392. // Position the table in the virtual scroller
  25393. var tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);
  25394. if ( displayStart === 0 ) {
  25395. tableTop = 0;
  25396. }
  25397. else if ( displayStart + displayLen >= displayEnd ) {
  25398. tableTop = heights.scroll - iTableHeight;
  25399. }
  25400. this.dom.table.style.top = tableTop+'px';
  25401. /* Cache some information for the scroller */
  25402. this.s.tableTop = tableTop;
  25403. this.s.tableBottom = iTableHeight + this.s.tableTop;
  25404. // Calculate the boundaries for where a redraw will be triggered by the
  25405. // scroll event listener
  25406. var boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;
  25407. this.s.redrawTop = iScrollTop - boundaryPx;
  25408. this.s.redrawBottom = iScrollTop + boundaryPx > heights.scroll - heights.viewport - heights.row ?
  25409. heights.scroll - heights.viewport - heights.row :
  25410. iScrollTop + boundaryPx;
  25411. this.s.skip = false;
  25412. // Restore the scrolling position that was saved by DataTable's state
  25413. // saving Note that this is done on the second draw when data is Ajax
  25414. // sourced, and the first draw when DOM soured
  25415. if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&
  25416. typeof this.s.dt.oLoadedState.iScroller != 'undefined' )
  25417. {
  25418. // A quirk of DataTables is that the draw callback will occur on an
  25419. // empty set if Ajax sourced, but not if server-side processing.
  25420. var ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ?
  25421. true :
  25422. false;
  25423. if ( ( ajaxSourced && this.s.dt.iDraw == 2) ||
  25424. (!ajaxSourced && this.s.dt.iDraw == 1) )
  25425. {
  25426. setTimeout( function () {
  25427. $(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );
  25428. that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);
  25429. // In order to prevent layout thrashing we need another
  25430. // small delay
  25431. setTimeout( function () {
  25432. that.s.ingnoreScroll = false;
  25433. }, 0 );
  25434. }, 0 );
  25435. }
  25436. }
  25437. else {
  25438. that.s.ingnoreScroll = false;
  25439. }
  25440. // Because of the order of the DT callbacks, the info update will
  25441. // take precedence over the one we want here. So a 'thread' break is
  25442. // needed. Only add the thread break if bInfo is set
  25443. if ( this.s.dt.oFeatures.bInfo ) {
  25444. setTimeout( function () {
  25445. that._info.call( that );
  25446. }, 0 );
  25447. }
  25448. // Hide the loading indicator
  25449. if ( this.dom.loader && this.s.loaderVisible ) {
  25450. this.dom.loader.css( 'display', 'none' );
  25451. this.s.loaderVisible = false;
  25452. }
  25453. },
  25454. /**
  25455. * Convert from one domain to another. The physical domain is the actual
  25456. * pixel count on the screen, while the virtual is if we had browsers which
  25457. * had scrolling containers of infinite height (i.e. the absolute value)
  25458. *
  25459. * @param {string} dir Domain transform direction, `virtualToPhysical` or
  25460. * `physicalToVirtual`
  25461. * @returns {number} Calculated transform
  25462. * @private
  25463. */
  25464. _domain: function ( dir, val )
  25465. {
  25466. var heights = this.s.heights;
  25467. var diff;
  25468. var magic = 10000; // the point at which the non-linear calculations start to happen
  25469. // If the virtual and physical height match, then we use a linear
  25470. // transform between the two, allowing the scrollbar to be linear
  25471. if ( heights.virtual === heights.scroll ) {
  25472. return val;
  25473. }
  25474. // In the first 10k pixels and the last 10k pixels, we want the scrolling
  25475. // to be linear. After that it can be non-linear. It would be unusual for
  25476. // anyone to mouse wheel through that much.
  25477. if ( val < magic ) {
  25478. return val;
  25479. }
  25480. else if ( dir === 'virtualToPhysical' && val >= heights.virtual - magic ) {
  25481. diff = heights.virtual - val;
  25482. return heights.scroll - diff;
  25483. }
  25484. else if ( dir === 'physicalToVirtual' && val >= heights.scroll - magic ) {
  25485. diff = heights.scroll - val;
  25486. return heights.virtual - diff;
  25487. }
  25488. // Otherwise, we want a non-linear scrollbar to take account of the
  25489. // redrawing regions at the start and end of the table, otherwise these
  25490. // can stutter badly - on large tables 30px (for example) scroll might
  25491. // be hundreds of rows, so the table would be redrawing every few px at
  25492. // the start and end. Use a simple linear eq. to stop this, effectively
  25493. // causing a kink in the scrolling ratio. It does mean the scrollbar is
  25494. // non-linear, but with such massive data sets, the scrollbar is going
  25495. // to be a best guess anyway
  25496. var m = (heights.virtual - magic - magic) / (heights.scroll - magic - magic);
  25497. var c = magic - (m*magic);
  25498. return dir === 'virtualToPhysical' ?
  25499. (val-c) / m :
  25500. (m*val) + c;
  25501. },
  25502. /**
  25503. * Update any information elements that are controlled by the DataTable based on the scrolling
  25504. * viewport and what rows are visible in it. This function basically acts in the same way as
  25505. * _fnUpdateInfo in DataTables, and effectively replaces that function.
  25506. * @returns {void}
  25507. * @private
  25508. */
  25509. _info: function ()
  25510. {
  25511. if ( !this.s.dt.oFeatures.bInfo )
  25512. {
  25513. return;
  25514. }
  25515. var
  25516. dt = this.s.dt,
  25517. language = dt.oLanguage,
  25518. iScrollTop = this.dom.scroller.scrollTop,
  25519. iStart = Math.floor( this.pixelsToRow(iScrollTop, false, this.s.ani)+1 ),
  25520. iMax = dt.fnRecordsTotal(),
  25521. iTotal = dt.fnRecordsDisplay(),
  25522. iPossibleEnd = Math.ceil( this.pixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),
  25523. iEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,
  25524. sStart = dt.fnFormatNumber( iStart ),
  25525. sEnd = dt.fnFormatNumber( iEnd ),
  25526. sMax = dt.fnFormatNumber( iMax ),
  25527. sTotal = dt.fnFormatNumber( iTotal ),
  25528. sOut;
  25529. if ( dt.fnRecordsDisplay() === 0 &&
  25530. dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
  25531. {
  25532. /* Empty record set */
  25533. sOut = language.sInfoEmpty+ language.sInfoPostFix;
  25534. }
  25535. else if ( dt.fnRecordsDisplay() === 0 )
  25536. {
  25537. /* Empty record set after filtering */
  25538. sOut = language.sInfoEmpty +' '+
  25539. language.sInfoFiltered.replace('_MAX_', sMax)+
  25540. language.sInfoPostFix;
  25541. }
  25542. else if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
  25543. {
  25544. /* Normal record set */
  25545. sOut = language.sInfo.
  25546. replace('_START_', sStart).
  25547. replace('_END_', sEnd).
  25548. replace('_MAX_', sMax).
  25549. replace('_TOTAL_', sTotal)+
  25550. language.sInfoPostFix;
  25551. }
  25552. else
  25553. {
  25554. /* Record set after filtering */
  25555. sOut = language.sInfo.
  25556. replace('_START_', sStart).
  25557. replace('_END_', sEnd).
  25558. replace('_MAX_', sMax).
  25559. replace('_TOTAL_', sTotal) +' '+
  25560. language.sInfoFiltered.replace(
  25561. '_MAX_',
  25562. dt.fnFormatNumber(dt.fnRecordsTotal())
  25563. )+
  25564. language.sInfoPostFix;
  25565. }
  25566. var callback = language.fnInfoCallback;
  25567. if ( callback ) {
  25568. sOut = callback.call( dt.oInstance,
  25569. dt, iStart, iEnd, iMax, iTotal, sOut
  25570. );
  25571. }
  25572. var n = dt.aanFeatures.i;
  25573. if ( typeof n != 'undefined' )
  25574. {
  25575. for ( var i=0, iLen=n.length ; i<iLen ; i++ )
  25576. {
  25577. $(n[i]).html( sOut );
  25578. }
  25579. }
  25580. // DT doesn't actually (yet) trigger this event, but it will in future
  25581. $(dt.nTable).triggerHandler( 'info.dt' );
  25582. },
  25583. /**
  25584. * Parse CSS height property string as number
  25585. *
  25586. * An attempt is made to parse the string as a number. Currently supported units are 'px',
  25587. * 'vh', and 'rem'. 'em' is partially supported; it works as long as the parent element's
  25588. * font size matches the body element. Zero is returned for unrecognized strings.
  25589. * @param {string} cssHeight CSS height property string
  25590. * @returns {number} height
  25591. * @private
  25592. */
  25593. _parseHeight: function(cssHeight) {
  25594. var height;
  25595. var matches = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(px|em|rem|vh)$/.exec(cssHeight);
  25596. if (matches === null) {
  25597. return 0;
  25598. }
  25599. var value = parseFloat(matches[1]);
  25600. var unit = matches[2];
  25601. if ( unit === 'px' ) {
  25602. height = value;
  25603. }
  25604. else if ( unit === 'vh' ) {
  25605. height = ( value / 100 ) * $(window).height();
  25606. }
  25607. else if ( unit === 'rem' ) {
  25608. height = value * parseFloat($(':root').css('font-size'));
  25609. }
  25610. else if ( unit === 'em' ) {
  25611. height = value * parseFloat($('body').css('font-size'));
  25612. }
  25613. return height ?
  25614. height :
  25615. 0;
  25616. },
  25617. /**
  25618. * Scrolling function - fired whenever the scrolling position is changed.
  25619. * This method needs to use the stored values to see if the table should be
  25620. * redrawn as we are moving towards the end of the information that is
  25621. * currently drawn or not. If needed, then it will redraw the table based on
  25622. * the new position.
  25623. * @returns {void}
  25624. * @private
  25625. */
  25626. _scroll: function ()
  25627. {
  25628. var
  25629. that = this,
  25630. heights = this.s.heights,
  25631. iScrollTop = this.dom.scroller.scrollTop,
  25632. iTopRow;
  25633. if ( this.s.skip ) {
  25634. return;
  25635. }
  25636. if ( this.s.ingnoreScroll ) {
  25637. return;
  25638. }
  25639. if ( iScrollTop === this.s.lastScrollTop ) {
  25640. return;
  25641. }
  25642. /* If the table has been sorted or filtered, then we use the redraw that
  25643. * DataTables as done, rather than performing our own
  25644. */
  25645. if ( this.s.dt.bFiltered || this.s.dt.bSorted ) {
  25646. this.s.lastScrollTop = 0;
  25647. return;
  25648. }
  25649. /* Update the table's information display for what is now in the viewport */
  25650. this._info();
  25651. /* We don't want to state save on every scroll event - that's heavy
  25652. * handed, so use a timeout to update the state saving only when the
  25653. * scrolling has finished
  25654. */
  25655. clearTimeout( this.s.stateTO );
  25656. this.s.stateTO = setTimeout( function () {
  25657. that.s.dtApi.state.save();
  25658. }, 250 );
  25659. this.s.scrollType = Math.abs(iScrollTop - this.s.lastScrollTop) > heights.viewport ?
  25660. 'jump' :
  25661. 'cont';
  25662. this.s.topRowFloat = this.s.scrollType === 'cont' ?
  25663. this.pixelsToRow( iScrollTop, false, false ) :
  25664. this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
  25665. if ( this.s.topRowFloat < 0 ) {
  25666. this.s.topRowFloat = 0;
  25667. }
  25668. /* Check if the scroll point is outside the trigger boundary which would required
  25669. * a DataTables redraw
  25670. */
  25671. if ( this.s.forceReposition || iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {
  25672. var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );
  25673. iTopRow = parseInt(this.s.topRowFloat, 10) - preRows;
  25674. this.s.forceReposition = false;
  25675. if ( iTopRow <= 0 ) {
  25676. /* At the start of the table */
  25677. iTopRow = 0;
  25678. }
  25679. else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {
  25680. /* At the end of the table */
  25681. iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;
  25682. if ( iTopRow < 0 ) {
  25683. iTopRow = 0;
  25684. }
  25685. }
  25686. else if ( iTopRow % 2 !== 0 ) {
  25687. // For the row-striping classes (odd/even) we want only to start
  25688. // on evens otherwise the stripes will change between draws and
  25689. // look rubbish
  25690. iTopRow++;
  25691. }
  25692. if ( iTopRow != this.s.dt._iDisplayStart ) {
  25693. /* Cache the new table position for quick lookups */
  25694. this.s.tableTop = $(this.s.dt.nTable).offset().top;
  25695. this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;
  25696. var draw = function () {
  25697. if ( that.s.scrollDrawReq === null ) {
  25698. that.s.scrollDrawReq = iScrollTop;
  25699. }
  25700. that.s.dt._iDisplayStart = iTopRow;
  25701. that.s.dt.oApi._fnDraw( that.s.dt );
  25702. };
  25703. /* Do the DataTables redraw based on the calculated start point - note that when
  25704. * using server-side processing we introduce a small delay to not DoS the server...
  25705. */
  25706. if ( this.s.dt.oFeatures.bServerSide ) {
  25707. clearTimeout( this.s.drawTO );
  25708. this.s.drawTO = setTimeout( draw, this.s.serverWait );
  25709. }
  25710. else {
  25711. draw();
  25712. }
  25713. if ( this.dom.loader && ! this.s.loaderVisible ) {
  25714. this.dom.loader.css( 'display', 'block' );
  25715. this.s.loaderVisible = true;
  25716. }
  25717. }
  25718. }
  25719. else {
  25720. this.s.topRowFloat = this.pixelsToRow( iScrollTop, false, true );
  25721. }
  25722. this.s.lastScrollTop = iScrollTop;
  25723. this.s.stateSaveThrottle();
  25724. if ( this.s.scrollType === 'jump' && this.s.mousedown ) {
  25725. this.dom.label
  25726. .html( this.s.dt.fnFormatNumber( parseInt( this.s.topRowFloat, 10 )+1 ) )
  25727. .css( 'top', iScrollTop + (iScrollTop * heights.labelFactor ) )
  25728. .css( 'display', 'block' );
  25729. }
  25730. },
  25731. /**
  25732. * Force the scrolling container to have height beyond that of just the
  25733. * table that has been drawn so the user can scroll the whole data set.
  25734. *
  25735. * Note that if the calculated required scrolling height exceeds a maximum
  25736. * value (1 million pixels - hard-coded) the forcing element will be set
  25737. * only to that maximum value and virtual / physical domain transforms will
  25738. * be used to allow Scroller to display tables of any number of records.
  25739. * @returns {void}
  25740. * @private
  25741. */
  25742. _scrollForce: function ()
  25743. {
  25744. var heights = this.s.heights;
  25745. var max = 1000000;
  25746. heights.virtual = heights.row * this.s.dt.fnRecordsDisplay();
  25747. heights.scroll = heights.virtual;
  25748. if ( heights.scroll > max ) {
  25749. heights.scroll = max;
  25750. }
  25751. // Minimum height so there is always a row visible (the 'no rows found'
  25752. // if reduced to zero filtering)
  25753. this.dom.force.style.height = heights.scroll > this.s.heights.row ?
  25754. heights.scroll+'px' :
  25755. this.s.heights.row+'px';
  25756. }
  25757. } );
  25758. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  25759. * Statics
  25760. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  25761. /**
  25762. * Scroller default settings for initialisation
  25763. * @namespace
  25764. * @name Scroller.defaults
  25765. * @static
  25766. */
  25767. Scroller.defaults = {
  25768. /**
  25769. * Scroller uses the boundary scaling factor to decide when to redraw the table - which it
  25770. * typically does before you reach the end of the currently loaded data set (in order to
  25771. * allow the data to look continuous to a user scrolling through the data). If given as 0
  25772. * then the table will be redrawn whenever the viewport is scrolled, while 1 would not
  25773. * redraw the table until the currently loaded data has all been shown. You will want
  25774. * something in the middle - the default factor of 0.5 is usually suitable.
  25775. * @type float
  25776. * @default 0.5
  25777. * @static
  25778. */
  25779. boundaryScale: 0.5,
  25780. /**
  25781. * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch
  25782. * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch
  25783. * rows that will be shown in "near scrolling" (i.e. just beyond the current display area).
  25784. * The value is based upon the number of rows that can be displayed in the viewport (i.e.
  25785. * a value of 1), and will apply the display range to records before before and after the
  25786. * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth
  25787. * of rows before the current viewport, the current viewport's rows and 1 viewport's worth
  25788. * of rows after the current viewport. Adjusting this value can be useful for ensuring
  25789. * smooth scrolling based on your data set.
  25790. * @type int
  25791. * @default 7
  25792. * @static
  25793. */
  25794. displayBuffer: 9,
  25795. /**
  25796. * Show (or not) the loading element in the background of the table. Note that you should
  25797. * include the dataTables.scroller.css file for this to be displayed correctly.
  25798. * @type boolean
  25799. * @default false
  25800. * @static
  25801. */
  25802. loadingIndicator: false,
  25803. /**
  25804. * Scroller will attempt to automatically calculate the height of rows for it's internal
  25805. * calculations. However the height that is used can be overridden using this parameter.
  25806. * @type int|string
  25807. * @default auto
  25808. * @static
  25809. */
  25810. rowHeight: "auto",
  25811. /**
  25812. * When using server-side processing, Scroller will wait a small amount of time to allow
  25813. * the scrolling to finish before requesting more data from the server. This prevents
  25814. * you from DoSing your own server! The wait time can be configured by this parameter.
  25815. * @type int
  25816. * @default 200
  25817. * @static
  25818. */
  25819. serverWait: 200
  25820. };
  25821. Scroller.oDefaults = Scroller.defaults;
  25822. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  25823. * Constants
  25824. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  25825. /**
  25826. * Scroller version
  25827. * @type String
  25828. * @default See code
  25829. * @name Scroller.version
  25830. * @static
  25831. */
  25832. Scroller.version = "2.0.1";
  25833. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  25834. * Initialisation
  25835. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  25836. // Attach a listener to the document which listens for DataTables initialisation
  25837. // events so we can automatically initialise
  25838. $(document).on( 'preInit.dt.dtscroller', function (e, settings) {
  25839. if ( e.namespace !== 'dt' ) {
  25840. return;
  25841. }
  25842. var init = settings.oInit.scroller;
  25843. var defaults = DataTable.defaults.scroller;
  25844. if ( init || defaults ) {
  25845. var opts = $.extend( {}, init, defaults );
  25846. if ( init !== false ) {
  25847. new Scroller( settings, opts );
  25848. }
  25849. }
  25850. } );
  25851. // Attach Scroller to DataTables so it can be accessed as an 'extra'
  25852. $.fn.dataTable.Scroller = Scroller;
  25853. $.fn.DataTable.Scroller = Scroller;
  25854. // DataTables 1.10 API method aliases
  25855. var Api = $.fn.dataTable.Api;
  25856. Api.register( 'scroller()', function () {
  25857. return this;
  25858. } );
  25859. // Undocumented and deprecated - is it actually useful at all?
  25860. Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {
  25861. var ctx = this.context;
  25862. if ( ctx.length && ctx[0].oScroller ) {
  25863. return ctx[0].oScroller.rowToPixels( rowIdx, intParse, virtual );
  25864. }
  25865. // undefined
  25866. } );
  25867. // Undocumented and deprecated - is it actually useful at all?
  25868. Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {
  25869. var ctx = this.context;
  25870. if ( ctx.length && ctx[0].oScroller ) {
  25871. return ctx[0].oScroller.pixelsToRow( pixels, intParse, virtual );
  25872. }
  25873. // undefined
  25874. } );
  25875. // `scroller().scrollToRow()` is undocumented and deprecated. Use `scroller.toPosition()
  25876. Api.register( ['scroller().scrollToRow()', 'scroller.toPosition()'], function ( idx, ani ) {
  25877. this.iterator( 'table', function ( ctx ) {
  25878. if ( ctx.oScroller ) {
  25879. ctx.oScroller.scrollToRow( idx, ani );
  25880. }
  25881. } );
  25882. return this;
  25883. } );
  25884. Api.register( 'row().scrollTo()', function ( ani ) {
  25885. var that = this;
  25886. this.iterator( 'row', function ( ctx, rowIdx ) {
  25887. if ( ctx.oScroller ) {
  25888. var displayIdx = that
  25889. .rows( { order: 'applied', search: 'applied' } )
  25890. .indexes()
  25891. .indexOf( rowIdx );
  25892. ctx.oScroller.scrollToRow( displayIdx, ani );
  25893. }
  25894. } );
  25895. return this;
  25896. } );
  25897. Api.register( 'scroller.measure()', function ( redraw ) {
  25898. this.iterator( 'table', function ( ctx ) {
  25899. if ( ctx.oScroller ) {
  25900. ctx.oScroller.measure( redraw );
  25901. }
  25902. } );
  25903. return this;
  25904. } );
  25905. Api.register( 'scroller.page()', function() {
  25906. var ctx = this.context;
  25907. if ( ctx.length && ctx[0].oScroller ) {
  25908. return ctx[0].oScroller.pageInfo();
  25909. }
  25910. // undefined
  25911. } );
  25912. return Scroller;
  25913. }));
  25914. /*! Bootstrap 4 styling wrapper for Scroller
  25915. * ©2018 SpryMedia Ltd - datatables.net/license
  25916. */
  25917. (function( factory ){
  25918. if ( typeof define === 'function' && define.amd ) {
  25919. // AMD
  25920. define( ['jquery', 'datatables.net-bs4', 'datatables.net-scroller'], function ( $ ) {
  25921. return factory( $, window, document );
  25922. } );
  25923. }
  25924. else if ( typeof exports === 'object' ) {
  25925. // CommonJS
  25926. module.exports = function (root, $) {
  25927. if ( ! root ) {
  25928. root = window;
  25929. }
  25930. if ( ! $ || ! $.fn.dataTable ) {
  25931. $ = require('datatables.net-bs4')(root, $).$;
  25932. }
  25933. if ( ! $.fn.dataTable.Scroller ) {
  25934. require('datatables.net-scroller')(root, $);
  25935. }
  25936. return factory( $, root, root.document );
  25937. };
  25938. }
  25939. else {
  25940. // Browser
  25941. factory( jQuery, window, document );
  25942. }
  25943. }(function( $, window, document, undefined ) {
  25944. return $.fn.dataTable;
  25945. }));
  25946. /*! Select for DataTables 1.3.1
  25947. * 2015-2019 SpryMedia Ltd - datatables.net/license/mit
  25948. */
  25949. /**
  25950. * @summary Select for DataTables
  25951. * @description A collection of API methods, events and buttons for DataTables
  25952. * that provides selection options of the items in a DataTable
  25953. * @version 1.3.1
  25954. * @file dataTables.select.js
  25955. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  25956. * @contact datatables.net/forums
  25957. * @copyright Copyright 2015-2019 SpryMedia Ltd.
  25958. *
  25959. * This source file is free software, available under the following license:
  25960. * MIT license - http://datatables.net/license/mit
  25961. *
  25962. * This source file is distributed in the hope that it will be useful, but
  25963. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  25964. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  25965. *
  25966. * For details please refer to: http://www.datatables.net/extensions/select
  25967. */
  25968. (function( factory ){
  25969. if ( typeof define === 'function' && define.amd ) {
  25970. // AMD
  25971. define( ['jquery', 'datatables.net'], function ( $ ) {
  25972. return factory( $, window, document );
  25973. } );
  25974. }
  25975. else if ( typeof exports === 'object' ) {
  25976. // CommonJS
  25977. module.exports = function (root, $) {
  25978. if ( ! root ) {
  25979. root = window;
  25980. }
  25981. if ( ! $ || ! $.fn.dataTable ) {
  25982. $ = require('datatables.net')(root, $).$;
  25983. }
  25984. return factory( $, root, root.document );
  25985. };
  25986. }
  25987. else {
  25988. // Browser
  25989. factory( jQuery, window, document );
  25990. }
  25991. }(function( $, window, document, undefined ) {
  25992. 'use strict';
  25993. var DataTable = $.fn.dataTable;
  25994. // Version information for debugger
  25995. DataTable.select = {};
  25996. DataTable.select.version = '1.3.1';
  25997. DataTable.select.init = function ( dt ) {
  25998. var ctx = dt.settings()[0];
  25999. var init = ctx.oInit.select;
  26000. var defaults = DataTable.defaults.select;
  26001. var opts = init === undefined ?
  26002. defaults :
  26003. init;
  26004. // Set defaults
  26005. var items = 'row';
  26006. var style = 'api';
  26007. var blurable = false;
  26008. var toggleable = true;
  26009. var info = true;
  26010. var selector = 'td, th';
  26011. var className = 'selected';
  26012. var setStyle = false;
  26013. ctx._select = {};
  26014. // Initialisation customisations
  26015. if ( opts === true ) {
  26016. style = 'os';
  26017. setStyle = true;
  26018. }
  26019. else if ( typeof opts === 'string' ) {
  26020. style = opts;
  26021. setStyle = true;
  26022. }
  26023. else if ( $.isPlainObject( opts ) ) {
  26024. if ( opts.blurable !== undefined ) {
  26025. blurable = opts.blurable;
  26026. }
  26027. if ( opts.toggleable !== undefined ) {
  26028. toggleable = opts.toggleable;
  26029. }
  26030. if ( opts.info !== undefined ) {
  26031. info = opts.info;
  26032. }
  26033. if ( opts.items !== undefined ) {
  26034. items = opts.items;
  26035. }
  26036. if ( opts.style !== undefined ) {
  26037. style = opts.style;
  26038. setStyle = true;
  26039. }
  26040. else {
  26041. style = 'os';
  26042. setStyle = true;
  26043. }
  26044. if ( opts.selector !== undefined ) {
  26045. selector = opts.selector;
  26046. }
  26047. if ( opts.className !== undefined ) {
  26048. className = opts.className;
  26049. }
  26050. }
  26051. dt.select.selector( selector );
  26052. dt.select.items( items );
  26053. dt.select.style( style );
  26054. dt.select.blurable( blurable );
  26055. dt.select.toggleable( toggleable );
  26056. dt.select.info( info );
  26057. ctx._select.className = className;
  26058. // Sort table based on selected rows. Requires Select Datatables extension
  26059. $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
  26060. return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
  26061. if ( settings._select.items === 'row' ) {
  26062. return $( td ).parent().hasClass( settings._select.className );
  26063. } else if ( settings._select.items === 'cell' ) {
  26064. return $( td ).hasClass( settings._select.className );
  26065. }
  26066. return false;
  26067. });
  26068. };
  26069. // If the init options haven't enabled select, but there is a selectable
  26070. // class name, then enable
  26071. if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
  26072. dt.select.style( 'os' );
  26073. }
  26074. };
  26075. /*
  26076. Select is a collection of API methods, event handlers, event emitters and
  26077. buttons (for the `Buttons` extension) for DataTables. It provides the following
  26078. features, with an overview of how they are implemented:
  26079. ## Selection of rows, columns and cells. Whether an item is selected or not is
  26080. stored in:
  26081. * rows: a `_select_selected` property which contains a boolean value of the
  26082. DataTables' `aoData` object for each row
  26083. * columns: a `_select_selected` property which contains a boolean value of the
  26084. DataTables' `aoColumns` object for each column
  26085. * cells: a `_selected_cells` property which contains an array of boolean values
  26086. of the `aoData` object for each row. The array is the same length as the
  26087. columns array, with each element of it representing a cell.
  26088. This method of using boolean flags allows Select to operate when nodes have not
  26089. been created for rows / cells (DataTables' defer rendering feature).
  26090. ## API methods
  26091. A range of API methods are available for triggering selection and de-selection
  26092. of rows. Methods are also available to configure the selection events that can
  26093. be triggered by an end user (such as which items are to be selected). To a large
  26094. extent, these of API methods *is* Select. It is basically a collection of helper
  26095. functions that can be used to select items in a DataTable.
  26096. Configuration of select is held in the object `_select` which is attached to the
  26097. DataTables settings object on initialisation. Select being available on a table
  26098. is not optional when Select is loaded, but its default is for selection only to
  26099. be available via the API - so the end user wouldn't be able to select rows
  26100. without additional configuration.
  26101. The `_select` object contains the following properties:
  26102. ```
  26103. {
  26104. items:string - Can be `rows`, `columns` or `cells`. Defines what item
  26105. will be selected if the user is allowed to activate row
  26106. selection using the mouse.
  26107. style:string - Can be `none`, `single`, `multi` or `os`. Defines the
  26108. interaction style when selecting items
  26109. blurable:boolean - If row selection can be cleared by clicking outside of
  26110. the table
  26111. toggleable:boolean - If row selection can be cancelled by repeated clicking
  26112. on the row
  26113. info:boolean - If the selection summary should be shown in the table
  26114. information elements
  26115. }
  26116. ```
  26117. In addition to the API methods, Select also extends the DataTables selector
  26118. options for rows, columns and cells adding a `selected` option to the selector
  26119. options object, allowing the developer to select only selected items or
  26120. unselected items.
  26121. ## Mouse selection of items
  26122. Clicking on items can be used to select items. This is done by a simple event
  26123. handler that will select the items using the API methods.
  26124. */
  26125. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  26126. * Local functions
  26127. */
  26128. /**
  26129. * Add one or more cells to the selection when shift clicking in OS selection
  26130. * style cell selection.
  26131. *
  26132. * Cell range is more complicated than row and column as we want to select
  26133. * in the visible grid rather than by index in sequence. For example, if you
  26134. * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
  26135. * should also be selected (and not 1-3, 1-4. etc)
  26136. *
  26137. * @param {DataTable.Api} dt DataTable
  26138. * @param {object} idx Cell index to select to
  26139. * @param {object} last Cell index to select from
  26140. * @private
  26141. */
  26142. function cellRange( dt, idx, last )
  26143. {
  26144. var indexes;
  26145. var columnIndexes;
  26146. var rowIndexes;
  26147. var selectColumns = function ( start, end ) {
  26148. if ( start > end ) {
  26149. var tmp = end;
  26150. end = start;
  26151. start = tmp;
  26152. }
  26153. var record = false;
  26154. return dt.columns( ':visible' ).indexes().filter( function (i) {
  26155. if ( i === start ) {
  26156. record = true;
  26157. }
  26158. if ( i === end ) { // not else if, as start might === end
  26159. record = false;
  26160. return true;
  26161. }
  26162. return record;
  26163. } );
  26164. };
  26165. var selectRows = function ( start, end ) {
  26166. var indexes = dt.rows( { search: 'applied' } ).indexes();
  26167. // Which comes first - might need to swap
  26168. if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
  26169. var tmp = end;
  26170. end = start;
  26171. start = tmp;
  26172. }
  26173. var record = false;
  26174. return indexes.filter( function (i) {
  26175. if ( i === start ) {
  26176. record = true;
  26177. }
  26178. if ( i === end ) {
  26179. record = false;
  26180. return true;
  26181. }
  26182. return record;
  26183. } );
  26184. };
  26185. if ( ! dt.cells( { selected: true } ).any() && ! last ) {
  26186. // select from the top left cell to this one
  26187. columnIndexes = selectColumns( 0, idx.column );
  26188. rowIndexes = selectRows( 0 , idx.row );
  26189. }
  26190. else {
  26191. // Get column indexes between old and new
  26192. columnIndexes = selectColumns( last.column, idx.column );
  26193. rowIndexes = selectRows( last.row , idx.row );
  26194. }
  26195. indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
  26196. if ( ! dt.cells( idx, { selected: true } ).any() ) {
  26197. // Select range
  26198. dt.cells( indexes ).select();
  26199. }
  26200. else {
  26201. // Deselect range
  26202. dt.cells( indexes ).deselect();
  26203. }
  26204. }
  26205. /**
  26206. * Disable mouse selection by removing the selectors
  26207. *
  26208. * @param {DataTable.Api} dt DataTable to remove events from
  26209. * @private
  26210. */
  26211. function disableMouseSelection( dt )
  26212. {
  26213. var ctx = dt.settings()[0];
  26214. var selector = ctx._select.selector;
  26215. $( dt.table().container() )
  26216. .off( 'mousedown.dtSelect', selector )
  26217. .off( 'mouseup.dtSelect', selector )
  26218. .off( 'click.dtSelect', selector );
  26219. $('body').off( 'click.dtSelect' + _safeId(dt.table().node()) );
  26220. }
  26221. /**
  26222. * Attach mouse listeners to the table to allow mouse selection of items
  26223. *
  26224. * @param {DataTable.Api} dt DataTable to remove events from
  26225. * @private
  26226. */
  26227. function enableMouseSelection ( dt )
  26228. {
  26229. var container = $( dt.table().container() );
  26230. var ctx = dt.settings()[0];
  26231. var selector = ctx._select.selector;
  26232. var matchSelection;
  26233. container
  26234. .on( 'mousedown.dtSelect', selector, function(e) {
  26235. // Disallow text selection for shift clicking on the table so multi
  26236. // element selection doesn't look terrible!
  26237. if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
  26238. container
  26239. .css( '-moz-user-select', 'none' )
  26240. .one('selectstart.dtSelect', selector, function () {
  26241. return false;
  26242. } );
  26243. }
  26244. if ( window.getSelection ) {
  26245. matchSelection = window.getSelection();
  26246. }
  26247. } )
  26248. .on( 'mouseup.dtSelect', selector, function() {
  26249. // Allow text selection to occur again, Mozilla style (tested in FF
  26250. // 35.0.1 - still required)
  26251. container.css( '-moz-user-select', '' );
  26252. } )
  26253. .on( 'click.dtSelect', selector, function ( e ) {
  26254. var items = dt.select.items();
  26255. var idx;
  26256. // If text was selected (click and drag), then we shouldn't change
  26257. // the row's selected state
  26258. if ( matchSelection ) {
  26259. var selection = window.getSelection();
  26260. // If the element that contains the selection is not in the table, we can ignore it
  26261. // This can happen if the developer selects text from the click event
  26262. if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
  26263. if ( selection !== matchSelection ) {
  26264. return;
  26265. }
  26266. }
  26267. }
  26268. var ctx = dt.settings()[0];
  26269. var wrapperClass = $.trim(dt.settings()[0].oClasses.sWrapper).replace(/ +/g, '.');
  26270. // Ignore clicks inside a sub-table
  26271. if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {
  26272. return;
  26273. }
  26274. var cell = dt.cell( $(e.target).closest('td, th') );
  26275. // Check the cell actually belongs to the host DataTable (so child
  26276. // rows, etc, are ignored)
  26277. if ( ! cell.any() ) {
  26278. return;
  26279. }
  26280. var event = $.Event('user-select.dt');
  26281. eventTrigger( dt, event, [ items, cell, e ] );
  26282. if ( event.isDefaultPrevented() ) {
  26283. return;
  26284. }
  26285. var cellIndex = cell.index();
  26286. if ( items === 'row' ) {
  26287. idx = cellIndex.row;
  26288. typeSelect( e, dt, ctx, 'row', idx );
  26289. }
  26290. else if ( items === 'column' ) {
  26291. idx = cell.index().column;
  26292. typeSelect( e, dt, ctx, 'column', idx );
  26293. }
  26294. else if ( items === 'cell' ) {
  26295. idx = cell.index();
  26296. typeSelect( e, dt, ctx, 'cell', idx );
  26297. }
  26298. ctx._select_lastCell = cellIndex;
  26299. } );
  26300. // Blurable
  26301. $('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) {
  26302. if ( ctx._select.blurable ) {
  26303. // If the click was inside the DataTables container, don't blur
  26304. if ( $(e.target).parents().filter( dt.table().container() ).length ) {
  26305. return;
  26306. }
  26307. // Ignore elements which have been removed from the DOM (i.e. paging
  26308. // buttons)
  26309. if ( $(e.target).parents('html').length === 0 ) {
  26310. return;
  26311. }
  26312. // Don't blur in Editor form
  26313. if ( $(e.target).parents('div.DTE').length ) {
  26314. return;
  26315. }
  26316. clear( ctx, true );
  26317. }
  26318. } );
  26319. }
  26320. /**
  26321. * Trigger an event on a DataTable
  26322. *
  26323. * @param {DataTable.Api} api DataTable to trigger events on
  26324. * @param {boolean} selected true if selected, false if deselected
  26325. * @param {string} type Item type acting on
  26326. * @param {boolean} any Require that there are values before
  26327. * triggering
  26328. * @private
  26329. */
  26330. function eventTrigger ( api, type, args, any )
  26331. {
  26332. if ( any && ! api.flatten().length ) {
  26333. return;
  26334. }
  26335. if ( typeof type === 'string' ) {
  26336. type = type +'.dt';
  26337. }
  26338. args.unshift( api );
  26339. $(api.table().node()).trigger( type, args );
  26340. }
  26341. /**
  26342. * Update the information element of the DataTable showing information about the
  26343. * items selected. This is done by adding tags to the existing text
  26344. *
  26345. * @param {DataTable.Api} api DataTable to update
  26346. * @private
  26347. */
  26348. function info ( api )
  26349. {
  26350. var ctx = api.settings()[0];
  26351. if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
  26352. return;
  26353. }
  26354. if ( api.select.style() === 'api' ) {
  26355. return;
  26356. }
  26357. var rows = api.rows( { selected: true } ).flatten().length;
  26358. var columns = api.columns( { selected: true } ).flatten().length;
  26359. var cells = api.cells( { selected: true } ).flatten().length;
  26360. var add = function ( el, name, num ) {
  26361. el.append( $('<span class="select-item"/>').append( api.i18n(
  26362. 'select.'+name+'s',
  26363. { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
  26364. num
  26365. ) ) );
  26366. };
  26367. // Internal knowledge of DataTables to loop over all information elements
  26368. $.each( ctx.aanFeatures.i, function ( i, el ) {
  26369. el = $(el);
  26370. var output = $('<span class="select-info"/>');
  26371. add( output, 'row', rows );
  26372. add( output, 'column', columns );
  26373. add( output, 'cell', cells );
  26374. var exisiting = el.children('span.select-info');
  26375. if ( exisiting.length ) {
  26376. exisiting.remove();
  26377. }
  26378. if ( output.text() !== '' ) {
  26379. el.append( output );
  26380. }
  26381. } );
  26382. }
  26383. /**
  26384. * Initialisation of a new table. Attach event handlers and callbacks to allow
  26385. * Select to operate correctly.
  26386. *
  26387. * This will occur _after_ the initial DataTables initialisation, although
  26388. * before Ajax data is rendered, if there is ajax data
  26389. *
  26390. * @param {DataTable.settings} ctx Settings object to operate on
  26391. * @private
  26392. */
  26393. function init ( ctx ) {
  26394. var api = new DataTable.Api( ctx );
  26395. // Row callback so that classes can be added to rows and cells if the item
  26396. // was selected before the element was created. This will happen with the
  26397. // `deferRender` option enabled.
  26398. //
  26399. // This method of attaching to `aoRowCreatedCallback` is a hack until
  26400. // DataTables has proper events for row manipulation If you are reviewing
  26401. // this code to create your own plug-ins, please do not do this!
  26402. ctx.aoRowCreatedCallback.push( {
  26403. fn: function ( row, data, index ) {
  26404. var i, ien;
  26405. var d = ctx.aoData[ index ];
  26406. // Row
  26407. if ( d._select_selected ) {
  26408. $( row ).addClass( ctx._select.className );
  26409. }
  26410. // Cells and columns - if separated out, we would need to do two
  26411. // loops, so it makes sense to combine them into a single one
  26412. for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
  26413. if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
  26414. $(d.anCells[i]).addClass( ctx._select.className );
  26415. }
  26416. }
  26417. },
  26418. sName: 'select-deferRender'
  26419. } );
  26420. // On Ajax reload we want to reselect all rows which are currently selected,
  26421. // if there is an rowId (i.e. a unique value to identify each row with)
  26422. api.on( 'preXhr.dt.dtSelect', function () {
  26423. // note that column selection doesn't need to be cached and then
  26424. // reselected, as they are already selected
  26425. var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
  26426. return d !== undefined;
  26427. } );
  26428. var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
  26429. var id = api.row( cellIdx.row ).id( true );
  26430. return id ?
  26431. { row: id, column: cellIdx.column } :
  26432. undefined;
  26433. } ).filter( function ( d ) {
  26434. return d !== undefined;
  26435. } );
  26436. // On the next draw, reselect the currently selected items
  26437. api.one( 'draw.dt.dtSelect', function () {
  26438. api.rows( rows ).select();
  26439. // `cells` is not a cell index selector, so it needs a loop
  26440. if ( cells.any() ) {
  26441. cells.each( function ( id ) {
  26442. api.cells( id.row, id.column ).select();
  26443. } );
  26444. }
  26445. } );
  26446. } );
  26447. // Update the table information element with selected item summary
  26448. api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
  26449. info( api );
  26450. } );
  26451. // Clean up and release
  26452. api.on( 'destroy.dtSelect', function () {
  26453. disableMouseSelection( api );
  26454. api.off( '.dtSelect' );
  26455. } );
  26456. }
  26457. /**
  26458. * Add one or more items (rows or columns) to the selection when shift clicking
  26459. * in OS selection style
  26460. *
  26461. * @param {DataTable.Api} dt DataTable
  26462. * @param {string} type Row or column range selector
  26463. * @param {object} idx Item index to select to
  26464. * @param {object} last Item index to select from
  26465. * @private
  26466. */
  26467. function rowColumnRange( dt, type, idx, last )
  26468. {
  26469. // Add a range of rows from the last selected row to this one
  26470. var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
  26471. var idx1 = $.inArray( last, indexes );
  26472. var idx2 = $.inArray( idx, indexes );
  26473. if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
  26474. // select from top to here - slightly odd, but both Windows and Mac OS
  26475. // do this
  26476. indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
  26477. }
  26478. else {
  26479. // reverse so we can shift click 'up' as well as down
  26480. if ( idx1 > idx2 ) {
  26481. var tmp = idx2;
  26482. idx2 = idx1;
  26483. idx1 = tmp;
  26484. }
  26485. indexes.splice( idx2+1, indexes.length );
  26486. indexes.splice( 0, idx1 );
  26487. }
  26488. if ( ! dt[type]( idx, { selected: true } ).any() ) {
  26489. // Select range
  26490. dt[type+'s']( indexes ).select();
  26491. }
  26492. else {
  26493. // Deselect range - need to keep the clicked on row selected
  26494. indexes.splice( $.inArray( idx, indexes ), 1 );
  26495. dt[type+'s']( indexes ).deselect();
  26496. }
  26497. }
  26498. /**
  26499. * Clear all selected items
  26500. *
  26501. * @param {DataTable.settings} ctx Settings object of the host DataTable
  26502. * @param {boolean} [force=false] Force the de-selection to happen, regardless
  26503. * of selection style
  26504. * @private
  26505. */
  26506. function clear( ctx, force )
  26507. {
  26508. if ( force || ctx._select.style === 'single' ) {
  26509. var api = new DataTable.Api( ctx );
  26510. api.rows( { selected: true } ).deselect();
  26511. api.columns( { selected: true } ).deselect();
  26512. api.cells( { selected: true } ).deselect();
  26513. }
  26514. }
  26515. /**
  26516. * Select items based on the current configuration for style and items.
  26517. *
  26518. * @param {object} e Mouse event object
  26519. * @param {DataTables.Api} dt DataTable
  26520. * @param {DataTable.settings} ctx Settings object of the host DataTable
  26521. * @param {string} type Items to select
  26522. * @param {int|object} idx Index of the item to select
  26523. * @private
  26524. */
  26525. function typeSelect ( e, dt, ctx, type, idx )
  26526. {
  26527. var style = dt.select.style();
  26528. var toggleable = dt.select.toggleable();
  26529. var isSelected = dt[type]( idx, { selected: true } ).any();
  26530. if ( isSelected && ! toggleable ) {
  26531. return;
  26532. }
  26533. if ( style === 'os' ) {
  26534. if ( e.ctrlKey || e.metaKey ) {
  26535. // Add or remove from the selection
  26536. dt[type]( idx ).select( ! isSelected );
  26537. }
  26538. else if ( e.shiftKey ) {
  26539. if ( type === 'cell' ) {
  26540. cellRange( dt, idx, ctx._select_lastCell || null );
  26541. }
  26542. else {
  26543. rowColumnRange( dt, type, idx, ctx._select_lastCell ?
  26544. ctx._select_lastCell[type] :
  26545. null
  26546. );
  26547. }
  26548. }
  26549. else {
  26550. // No cmd or shift click - deselect if selected, or select
  26551. // this row only
  26552. var selected = dt[type+'s']( { selected: true } );
  26553. if ( isSelected && selected.flatten().length === 1 ) {
  26554. dt[type]( idx ).deselect();
  26555. }
  26556. else {
  26557. selected.deselect();
  26558. dt[type]( idx ).select();
  26559. }
  26560. }
  26561. } else if ( style == 'multi+shift' ) {
  26562. if ( e.shiftKey ) {
  26563. if ( type === 'cell' ) {
  26564. cellRange( dt, idx, ctx._select_lastCell || null );
  26565. }
  26566. else {
  26567. rowColumnRange( dt, type, idx, ctx._select_lastCell ?
  26568. ctx._select_lastCell[type] :
  26569. null
  26570. );
  26571. }
  26572. }
  26573. else {
  26574. dt[ type ]( idx ).select( ! isSelected );
  26575. }
  26576. }
  26577. else {
  26578. dt[ type ]( idx ).select( ! isSelected );
  26579. }
  26580. }
  26581. function _safeId( node ) {
  26582. return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
  26583. }
  26584. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  26585. * DataTables selectors
  26586. */
  26587. // row and column are basically identical just assigned to different properties
  26588. // and checking a different array, so we can dynamically create the functions to
  26589. // reduce the code size
  26590. $.each( [
  26591. { type: 'row', prop: 'aoData' },
  26592. { type: 'column', prop: 'aoColumns' }
  26593. ], function ( i, o ) {
  26594. DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
  26595. var selected = opts.selected;
  26596. var data;
  26597. var out = [];
  26598. if ( selected !== true && selected !== false ) {
  26599. return indexes;
  26600. }
  26601. for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
  26602. data = settings[ o.prop ][ indexes[i] ];
  26603. if ( (selected === true && data._select_selected === true) ||
  26604. (selected === false && ! data._select_selected )
  26605. ) {
  26606. out.push( indexes[i] );
  26607. }
  26608. }
  26609. return out;
  26610. } );
  26611. } );
  26612. DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
  26613. var selected = opts.selected;
  26614. var rowData;
  26615. var out = [];
  26616. if ( selected === undefined ) {
  26617. return cells;
  26618. }
  26619. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  26620. rowData = settings.aoData[ cells[i].row ];
  26621. if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
  26622. (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
  26623. ) {
  26624. out.push( cells[i] );
  26625. }
  26626. }
  26627. return out;
  26628. } );
  26629. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  26630. * DataTables API
  26631. *
  26632. * For complete documentation, please refer to the docs/api directory or the
  26633. * DataTables site
  26634. */
  26635. // Local variables to improve compression
  26636. var apiRegister = DataTable.Api.register;
  26637. var apiRegisterPlural = DataTable.Api.registerPlural;
  26638. apiRegister( 'select()', function () {
  26639. return this.iterator( 'table', function ( ctx ) {
  26640. DataTable.select.init( new DataTable.Api( ctx ) );
  26641. } );
  26642. } );
  26643. apiRegister( 'select.blurable()', function ( flag ) {
  26644. if ( flag === undefined ) {
  26645. return this.context[0]._select.blurable;
  26646. }
  26647. return this.iterator( 'table', function ( ctx ) {
  26648. ctx._select.blurable = flag;
  26649. } );
  26650. } );
  26651. apiRegister( 'select.toggleable()', function ( flag ) {
  26652. if ( flag === undefined ) {
  26653. return this.context[0]._select.toggleable;
  26654. }
  26655. return this.iterator( 'table', function ( ctx ) {
  26656. ctx._select.toggleable = flag;
  26657. } );
  26658. } );
  26659. apiRegister( 'select.info()', function ( flag ) {
  26660. if ( info === undefined ) {
  26661. return this.context[0]._select.info;
  26662. }
  26663. return this.iterator( 'table', function ( ctx ) {
  26664. ctx._select.info = flag;
  26665. } );
  26666. } );
  26667. apiRegister( 'select.items()', function ( items ) {
  26668. if ( items === undefined ) {
  26669. return this.context[0]._select.items;
  26670. }
  26671. return this.iterator( 'table', function ( ctx ) {
  26672. ctx._select.items = items;
  26673. eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
  26674. } );
  26675. } );
  26676. // Takes effect from the _next_ selection. None disables future selection, but
  26677. // does not clear the current selection. Use the `deselect` methods for that
  26678. apiRegister( 'select.style()', function ( style ) {
  26679. if ( style === undefined ) {
  26680. return this.context[0]._select.style;
  26681. }
  26682. return this.iterator( 'table', function ( ctx ) {
  26683. ctx._select.style = style;
  26684. if ( ! ctx._select_init ) {
  26685. init( ctx );
  26686. }
  26687. // Add / remove mouse event handlers. They aren't required when only
  26688. // API selection is available
  26689. var dt = new DataTable.Api( ctx );
  26690. disableMouseSelection( dt );
  26691. if ( style !== 'api' ) {
  26692. enableMouseSelection( dt );
  26693. }
  26694. eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
  26695. } );
  26696. } );
  26697. apiRegister( 'select.selector()', function ( selector ) {
  26698. if ( selector === undefined ) {
  26699. return this.context[0]._select.selector;
  26700. }
  26701. return this.iterator( 'table', function ( ctx ) {
  26702. disableMouseSelection( new DataTable.Api( ctx ) );
  26703. ctx._select.selector = selector;
  26704. if ( ctx._select.style !== 'api' ) {
  26705. enableMouseSelection( new DataTable.Api( ctx ) );
  26706. }
  26707. } );
  26708. } );
  26709. apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
  26710. var api = this;
  26711. if ( select === false ) {
  26712. return this.deselect();
  26713. }
  26714. this.iterator( 'row', function ( ctx, idx ) {
  26715. clear( ctx );
  26716. ctx.aoData[ idx ]._select_selected = true;
  26717. $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
  26718. } );
  26719. this.iterator( 'table', function ( ctx, i ) {
  26720. eventTrigger( api, 'select', [ 'row', api[i] ], true );
  26721. } );
  26722. return this;
  26723. } );
  26724. apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
  26725. var api = this;
  26726. if ( select === false ) {
  26727. return this.deselect();
  26728. }
  26729. this.iterator( 'column', function ( ctx, idx ) {
  26730. clear( ctx );
  26731. ctx.aoColumns[ idx ]._select_selected = true;
  26732. var column = new DataTable.Api( ctx ).column( idx );
  26733. $( column.header() ).addClass( ctx._select.className );
  26734. $( column.footer() ).addClass( ctx._select.className );
  26735. column.nodes().to$().addClass( ctx._select.className );
  26736. } );
  26737. this.iterator( 'table', function ( ctx, i ) {
  26738. eventTrigger( api, 'select', [ 'column', api[i] ], true );
  26739. } );
  26740. return this;
  26741. } );
  26742. apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
  26743. var api = this;
  26744. if ( select === false ) {
  26745. return this.deselect();
  26746. }
  26747. this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
  26748. clear( ctx );
  26749. var data = ctx.aoData[ rowIdx ];
  26750. if ( data._selected_cells === undefined ) {
  26751. data._selected_cells = [];
  26752. }
  26753. data._selected_cells[ colIdx ] = true;
  26754. if ( data.anCells ) {
  26755. $( data.anCells[ colIdx ] ).addClass( ctx._select.className );
  26756. }
  26757. } );
  26758. this.iterator( 'table', function ( ctx, i ) {
  26759. eventTrigger( api, 'select', [ 'cell', api[i] ], true );
  26760. } );
  26761. return this;
  26762. } );
  26763. apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
  26764. var api = this;
  26765. this.iterator( 'row', function ( ctx, idx ) {
  26766. ctx.aoData[ idx ]._select_selected = false;
  26767. $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
  26768. } );
  26769. this.iterator( 'table', function ( ctx, i ) {
  26770. eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
  26771. } );
  26772. return this;
  26773. } );
  26774. apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
  26775. var api = this;
  26776. this.iterator( 'column', function ( ctx, idx ) {
  26777. ctx.aoColumns[ idx ]._select_selected = false;
  26778. var api = new DataTable.Api( ctx );
  26779. var column = api.column( idx );
  26780. $( column.header() ).removeClass( ctx._select.className );
  26781. $( column.footer() ).removeClass( ctx._select.className );
  26782. // Need to loop over each cell, rather than just using
  26783. // `column().nodes()` as cells which are individually selected should
  26784. // not have the `selected` class removed from them
  26785. api.cells( null, idx ).indexes().each( function (cellIdx) {
  26786. var data = ctx.aoData[ cellIdx.row ];
  26787. var cellSelected = data._selected_cells;
  26788. if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
  26789. $( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className );
  26790. }
  26791. } );
  26792. } );
  26793. this.iterator( 'table', function ( ctx, i ) {
  26794. eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
  26795. } );
  26796. return this;
  26797. } );
  26798. apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
  26799. var api = this;
  26800. this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
  26801. var data = ctx.aoData[ rowIdx ];
  26802. data._selected_cells[ colIdx ] = false;
  26803. // Remove class only if the cells exist, and the cell is not column
  26804. // selected, in which case the class should remain (since it is selected
  26805. // in the column)
  26806. if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
  26807. $( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
  26808. }
  26809. } );
  26810. this.iterator( 'table', function ( ctx, i ) {
  26811. eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
  26812. } );
  26813. return this;
  26814. } );
  26815. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  26816. * Buttons
  26817. */
  26818. function i18n( label, def ) {
  26819. return function (dt) {
  26820. return dt.i18n( 'buttons.'+label, def );
  26821. };
  26822. }
  26823. // Common events with suitable namespaces
  26824. function namespacedEvents ( config ) {
  26825. var unique = config._eventNamespace;
  26826. return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
  26827. }
  26828. function enabled ( dt, config ) {
  26829. if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
  26830. return true;
  26831. }
  26832. if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
  26833. return true;
  26834. }
  26835. if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
  26836. return true;
  26837. }
  26838. return false;
  26839. }
  26840. var _buttonNamespace = 0;
  26841. $.extend( DataTable.ext.buttons, {
  26842. selected: {
  26843. text: i18n( 'selected', 'Selected' ),
  26844. className: 'buttons-selected',
  26845. limitTo: [ 'rows', 'columns', 'cells' ],
  26846. init: function ( dt, node, config ) {
  26847. var that = this;
  26848. config._eventNamespace = '.select'+(_buttonNamespace++);
  26849. // .DT namespace listeners are removed by DataTables automatically
  26850. // on table destroy
  26851. dt.on( namespacedEvents(config), function () {
  26852. that.enable( enabled(dt, config) );
  26853. } );
  26854. this.disable();
  26855. },
  26856. destroy: function ( dt, node, config ) {
  26857. dt.off( config._eventNamespace );
  26858. }
  26859. },
  26860. selectedSingle: {
  26861. text: i18n( 'selectedSingle', 'Selected single' ),
  26862. className: 'buttons-selected-single',
  26863. init: function ( dt, node, config ) {
  26864. var that = this;
  26865. config._eventNamespace = '.select'+(_buttonNamespace++);
  26866. dt.on( namespacedEvents(config), function () {
  26867. var count = dt.rows( { selected: true } ).flatten().length +
  26868. dt.columns( { selected: true } ).flatten().length +
  26869. dt.cells( { selected: true } ).flatten().length;
  26870. that.enable( count === 1 );
  26871. } );
  26872. this.disable();
  26873. },
  26874. destroy: function ( dt, node, config ) {
  26875. dt.off( config._eventNamespace );
  26876. }
  26877. },
  26878. selectAll: {
  26879. text: i18n( 'selectAll', 'Select all' ),
  26880. className: 'buttons-select-all',
  26881. action: function () {
  26882. var items = this.select.items();
  26883. this[ items+'s' ]().select();
  26884. }
  26885. },
  26886. selectNone: {
  26887. text: i18n( 'selectNone', 'Deselect all' ),
  26888. className: 'buttons-select-none',
  26889. action: function () {
  26890. clear( this.settings()[0], true );
  26891. },
  26892. init: function ( dt, node, config ) {
  26893. var that = this;
  26894. config._eventNamespace = '.select'+(_buttonNamespace++);
  26895. dt.on( namespacedEvents(config), function () {
  26896. var count = dt.rows( { selected: true } ).flatten().length +
  26897. dt.columns( { selected: true } ).flatten().length +
  26898. dt.cells( { selected: true } ).flatten().length;
  26899. that.enable( count > 0 );
  26900. } );
  26901. this.disable();
  26902. },
  26903. destroy: function ( dt, node, config ) {
  26904. dt.off( config._eventNamespace );
  26905. }
  26906. }
  26907. } );
  26908. $.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
  26909. var lc = item.toLowerCase();
  26910. DataTable.ext.buttons[ 'select'+item+'s' ] = {
  26911. text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
  26912. className: 'buttons-select-'+lc+'s',
  26913. action: function () {
  26914. this.select.items( lc );
  26915. },
  26916. init: function ( dt ) {
  26917. var that = this;
  26918. dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
  26919. that.active( items === lc );
  26920. } );
  26921. }
  26922. };
  26923. } );
  26924. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  26925. * Initialisation
  26926. */
  26927. // DataTables creation - check if select has been defined in the options. Note
  26928. // this required that the table be in the document! If it isn't then something
  26929. // needs to trigger this method unfortunately. The next major release of
  26930. // DataTables will rework the events and address this.
  26931. $(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
  26932. if ( e.namespace !== 'dt' ) {
  26933. return;
  26934. }
  26935. DataTable.select.init( new DataTable.Api( ctx ) );
  26936. } );
  26937. return DataTable.select;
  26938. }));
  26939. /*! Bootstrap 4 styling wrapper for Select
  26940. * ©2018 SpryMedia Ltd - datatables.net/license
  26941. */
  26942. (function( factory ){
  26943. if ( typeof define === 'function' && define.amd ) {
  26944. // AMD
  26945. define( ['jquery', 'datatables.net-bs4', 'datatables.net-select'], function ( $ ) {
  26946. return factory( $, window, document );
  26947. } );
  26948. }
  26949. else if ( typeof exports === 'object' ) {
  26950. // CommonJS
  26951. module.exports = function (root, $) {
  26952. if ( ! root ) {
  26953. root = window;
  26954. }
  26955. if ( ! $ || ! $.fn.dataTable ) {
  26956. $ = require('datatables.net-bs4')(root, $).$;
  26957. }
  26958. if ( ! $.fn.dataTable.select ) {
  26959. require('datatables.net-select')(root, $);
  26960. }
  26961. return factory( $, root, root.document );
  26962. };
  26963. }
  26964. else {
  26965. // Browser
  26966. factory( jQuery, window, document );
  26967. }
  26968. }(function( $, window, document, undefined ) {
  26969. return $.fn.dataTable;
  26970. }));
  26971. /**
  26972. * @summary altEditor
  26973. * @description Lightweight editor for DataTables
  26974. * @version 3.0
  26975. * @copyright Copyright 2016 Kingkode & Gotbootstrap.com
  26976. */
  26977. (function (factory) {
  26978. if (typeof define === 'function' && define.amd) {
  26979. // AMD
  26980. define(['jquery', 'datatables.net'], function ($) {
  26981. return factory($, window, document);
  26982. });
  26983. }
  26984. else if (typeof exports === 'object') {
  26985. // CommonJS
  26986. module.exports = function (root, $) {
  26987. if (!root) {
  26988. root = window;
  26989. }
  26990. if (!$ || !$.fn.dataTable) {
  26991. $ = require('datatables.net')(root, $).$;
  26992. }
  26993. return factory($, root, root.document);
  26994. };
  26995. }
  26996. else {
  26997. // Browser
  26998. factory(jQuery, window, document);
  26999. }
  27000. })
  27001. (function ($, window, document, undefined) {
  27002. 'use strict';
  27003. var DataTable = $.fn.dataTable;
  27004. var _instance = 0;
  27005. /**
  27006. * altEditor provides modal editing of records for Datatables
  27007. *
  27008. * @class altEditor
  27009. * @constructor
  27010. * @param {object}
  27011. * oTD DataTables settings object
  27012. * @param {object}
  27013. * oConfig Configuration object for altEditor
  27014. */
  27015. var altEditor = function (dt, opts) {
  27016. if (!DataTable.versionCheck || !DataTable.versionCheck('1.10.8')) {
  27017. throw ("Warning: altEditor requires DataTables 1.10.8 or greater");
  27018. }
  27019. // User and defaults configuration object
  27020. this.c = $.extend(true, {}, DataTable.defaults.altEditor,
  27021. altEditor.defaults, opts);
  27022. /**
  27023. * @namespace Settings object which contains customisable information
  27024. * for altEditor instance
  27025. */
  27026. this.s = {
  27027. /** @type {DataTable.Api} DataTables' API instance */
  27028. dt: new DataTable.Api(dt),
  27029. /** @type {String} Unique namespace for events attached to the document */
  27030. namespace: '.altEditor' + (_instance++)
  27031. };
  27032. /**
  27033. * @namespace Common and useful DOM elements for the class instance
  27034. */
  27035. this.dom = {
  27036. /** @type {jQuery} altEditor handle */
  27037. modal: $('<div class="dt-altEditor-handle"/>'),
  27038. };
  27039. /* Constructor logic */
  27040. this._constructor();
  27041. }
  27042. $.extend(
  27043. altEditor.prototype,
  27044. {
  27045. /***************************************************************
  27046. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  27047. * Constructor * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  27048. */
  27049. /**
  27050. * Initialise the RowReorder instance
  27051. *
  27052. * @private
  27053. */
  27054. _constructor: function () {
  27055. var that = this;
  27056. var dt = this.s.dt;
  27057. if (dt.settings()[0].oInit.onAddRow)
  27058. that.onAddRow = dt.settings()[0].oInit.onAddRow;
  27059. if (dt.settings()[0].oInit.onDeleteRow)
  27060. that.onDeleteRow = dt.settings()[0].oInit.onDeleteRow;
  27061. if (dt.settings()[0].oInit.onEditRow)
  27062. that.onEditRow = dt.settings()[0].oInit.onEditRow;
  27063. this._setup();
  27064. dt.on('destroy.altEditor', function () {
  27065. dt.off('.altEditor');
  27066. $(dt.table().body()).off(that.s.namespace);
  27067. $(document.body).off(that.s.namespace);
  27068. });
  27069. },
  27070. /***************************************************************
  27071. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  27072. * Private methods * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  27073. */
  27074. /**
  27075. * Setup dom and bind button actions
  27076. *
  27077. * @private
  27078. */
  27079. _setup: function () {
  27080. var that = this;
  27081. var dt = this.s.dt;
  27082. var modal_id = 'altEditor-modal-' + ("" + Math.random()).replace(".", "");
  27083. this.modal_selector = '#' + modal_id;
  27084. var modal = '<div class="modal fade" id="' + modal_id + '" tabindex="-1" role="dialog">' +
  27085. '<div class="modal-dialog">' +
  27086. '<div class="modal-content">' +
  27087. '<div class="modal-header">' +
  27088. '<h5 class="modal-title"></h5>' +
  27089. '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true"><i class="fal fa-times"></i></span></button>' +
  27090. '</div>' +
  27091. '<div class="modal-body">' +
  27092. '<p></p>' +
  27093. '</div>' +
  27094. '<div class="modal-footer">' +
  27095. '<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>' + //FIXME need i18n
  27096. '<input type="submit" form="altEditor-form" class="btn btn-primary"></input>' +
  27097. '</div>' +
  27098. '</div>' +
  27099. '</div>' +
  27100. '</div>';
  27101. // add modal
  27102. $('body').append(modal);
  27103. // add Edit Button
  27104. if (dt.button('edit:name')) {
  27105. dt.button('edit:name').action(function (e, dt, node, config) {
  27106. that._openEditModal();
  27107. });
  27108. $(this.modal_selector).on('click', '#editRowBtn', function (e) {
  27109. if (that._inputValidation()) {
  27110. e.preventDefault();
  27111. e.stopPropagation();
  27112. that._editRowData();
  27113. }
  27114. });
  27115. }
  27116. // add Delete Button
  27117. if (dt.button('delete:name')) {
  27118. dt.button('delete:name').action(function (e, dt, node, config) {
  27119. that._openDeleteModal();
  27120. });
  27121. $(this.modal_selector).on('click', '#deleteRowBtn', function (e) {
  27122. e.preventDefault();
  27123. e.stopPropagation();
  27124. that._deleteRow();
  27125. $(this).prop('disabled', true);
  27126. });
  27127. }
  27128. // add Add Button
  27129. if (dt.button('add:name')) {
  27130. dt.button('add:name').action(function (e, dt, node, config) {
  27131. that._openAddModal();
  27132. });
  27133. $(this.modal_selector).on('click', '#addRowBtn', function (e) {
  27134. if (that._inputValidation()) {
  27135. e.preventDefault();
  27136. e.stopPropagation();
  27137. that._addRowData();
  27138. }
  27139. });
  27140. }
  27141. // add Refresh button
  27142. if (this.s.dt.button('refresh:name')) {
  27143. this.s.dt.button('refresh:name').action(function (e, dt, node, config) {
  27144. if (dt.ajax && dt.ajax.url()) {
  27145. dt.ajax.reload();
  27146. }
  27147. });
  27148. }
  27149. },
  27150. /**
  27151. * Emit an event on the DataTable for listeners
  27152. *
  27153. * @param {string}
  27154. * name Event name
  27155. * @param {array}
  27156. * args Event arguments
  27157. * @private
  27158. */
  27159. _emitEvent: function (name, args) {
  27160. this.s.dt.iterator('table', function (ctx, i) {
  27161. $(ctx.nTable).triggerHandler(name + '.dt', args);
  27162. });
  27163. },
  27164. /**
  27165. * Open Edit Modal for selected row
  27166. *
  27167. * @private
  27168. */
  27169. _openEditModal: function () {
  27170. var that = this;
  27171. var dt = this.s.dt;
  27172. var columnDefs = [];
  27173. // Adding column attributes to object.
  27174. // Please set the ID as readonly.
  27175. for (var i in dt.context[0].aoColumns) {
  27176. var obj = dt.context[0].aoColumns[i];
  27177. columnDefs[i] = {
  27178. title: obj.sTitle,
  27179. name: obj.data ? obj.data : obj.mData,
  27180. type: (obj.type ? obj.type : 'text'),
  27181. options: (obj.options ? obj.options : []),
  27182. msg: (obj.errorMsg ? obj.errorMsg : ''),
  27183. hoverMsg: (obj.hoverMsg ? obj.hoverMsg : ''),
  27184. pattern: (obj.pattern ? obj.pattern : '.*'),
  27185. special: (obj.special ? obj.special : ''),
  27186. unique: (obj.unique ? obj.unique : false),
  27187. uniqueMsg: (obj.uniqueMsg ? obj.uniqueMsg : ''),
  27188. placeholderMsg: (obj.placeholderMsg ? obj.placeholderMsg : ''),
  27189. maxLength: (obj.maxLength ? obj.maxLength : false),
  27190. multiple: (obj.multiple ? obj.multiple : false),
  27191. select2: (obj.select2 ? obj.select2 : false),
  27192. datepicker: (obj.datepicker ? obj.datepicker : false)
  27193. };
  27194. }
  27195. var adata = dt.rows({
  27196. selected: true
  27197. });
  27198. // Building edit-form
  27199. var data = "";
  27200. data += "<form name='altEditor-form' role='form' novalidate>";
  27201. for (var j in columnDefs) {
  27202. // handle hidden fields
  27203. if (columnDefs[j].type.indexOf("hidden") >= 0) {
  27204. data += "<input type='hidden' id='" + columnDefs[j].name + "' value='" + adata.data()[0][columnDefs[j].name] + "'></input>";
  27205. }
  27206. else {
  27207. // handle fields that are visible to the user
  27208. data += "<div class='form-group row'>"
  27209. data += "<label for='" + columnDefs[j].name + "' class='col-lg-3 col-form-label form-label text-left text-lg-right'>" + columnDefs[j].title + ":</label>"
  27210. data += "<div class='col-lg-9'>";
  27211. // Adding text-inputs and errorlabels
  27212. if (columnDefs[j].type.indexOf("text") >= 0 ||
  27213. columnDefs[j].type.indexOf("date") >= 0 ||
  27214. columnDefs[j].type.indexOf("email") >= 0 ||
  27215. columnDefs[j].type.indexOf("password") >= 0 ||
  27216. columnDefs[j].type.indexOf("number") >= 0 ||
  27217. columnDefs[j].type.indexOf("time") >= 0) {
  27218. data += "<input type='"
  27219. + that._quoteattr(columnDefs[j].type)
  27220. + "' id='"
  27221. + that._quoteattr(columnDefs[j].name)
  27222. + "' pattern='"
  27223. + that._quoteattr(columnDefs[j].pattern)
  27224. + "' title='"
  27225. + that._quoteattr(columnDefs[j].hoverMsg)
  27226. + "' name='"
  27227. + that._quoteattr(columnDefs[j].title)
  27228. + "' placeholder='"
  27229. + that._quoteattr(columnDefs[j].placeholderMsg)
  27230. + "' data-special='"
  27231. + that._quoteattr(columnDefs[j].special)
  27232. + "' data-errorMsg='"
  27233. + that._quoteattr(columnDefs[j].msg)
  27234. + "' data-uniqueMsg='"
  27235. + that._quoteattr(columnDefs[j].uniqueMsg)
  27236. + "' data-unique='"
  27237. + columnDefs[j].unique
  27238. + "'"
  27239. + (columnDefs[j].maxLength == false ? "" : " maxlength='" + columnDefs[j].maxLength + "'")
  27240. + " style='overflow:hidden' class='form-control' value='"
  27241. + that._quoteattr(adata.data()[0][columnDefs[j].name]) + "'>";
  27242. data += "<label id='" + columnDefs[j].name + "label"
  27243. + "' class='errorLabel help-block text-danger' style='display: none'></label>";
  27244. }
  27245. // Adding readonly-fields
  27246. if (columnDefs[j].type.indexOf("readonly") >= 0) {
  27247. data += "<input type='text' readonly id='"
  27248. + columnDefs[j].name
  27249. + "' name='"
  27250. + columnDefs[j].title
  27251. + "' placeholder='"
  27252. + columnDefs[j].placeholderMsg
  27253. + "' style='overflow:hidden' class='form-control' value='"
  27254. + adata.data()[0][columnDefs[j].name] + "'>";
  27255. }
  27256. // Adding select-fields
  27257. if (columnDefs[j].type.indexOf("select") >= 0) {
  27258. var options = "";
  27259. for (var i = 0; i < columnDefs[j].options.length; i++) {
  27260. // Assigning the selected value of the <selected> option
  27261. if (adata.data()[0][columnDefs[j].name]
  27262. .indexOf(columnDefs[j].options[i])>= 0) {
  27263. options += "<option value='"
  27264. + columnDefs[j].options[i] + "'selected>"
  27265. + columnDefs[j].options[i] + "</option>";
  27266. } else {
  27267. options += "<option value='"
  27268. + columnDefs[j].options[i] + "'>"
  27269. + columnDefs[j].options[i] + "</option>";
  27270. }
  27271. }
  27272. data += "<select class='custom-select form-control" + (columnDefs[j].select2 ? ' select2' : '') + "' id='" + columnDefs[j].name + "' name='" + columnDefs[j].title + "' " + (columnDefs[j].multiple ? 'multiple' : '') + ">" + options
  27273. + "</select>";
  27274. }
  27275. data += "</div><div style='clear:both;'></div></div>";
  27276. }
  27277. }
  27278. // close form
  27279. data += "</form>";
  27280. var selector = this.modal_selector;
  27281. $(selector).on('show.bs.modal', function () {
  27282. var btns = '<button type="button" data-content="remove" class="btn btn-default" data-dismiss="modal">Cancel</button>' +
  27283. '<button type="button" data-content="remove" class="btn btn-primary" id="editRowBtn">Save</button>';
  27284. $(selector).find('.modal-title').html('Edit Record');
  27285. $(selector).find('.modal-body').html(data);
  27286. $(selector).find('.modal-footer').html(btns);
  27287. });
  27288. $(selector).modal('show');
  27289. $(selector + ' input[0]').focus();
  27290. // enable select 2 items
  27291. for (var j in columnDefs) {
  27292. if (columnDefs[j].select2) {
  27293. // require select2
  27294. $(selector).find("select#" + columnDefs[j].name).select2(columnDefs[j].select2);
  27295. }
  27296. }
  27297. // enable datepicker
  27298. for (var j in columnDefs) {
  27299. if (columnDefs[j].datepicker) {
  27300. // Require jquery-ui
  27301. $(selector).find("#" + columnDefs[j].name).datepicker(columnDefs[j].datepicker);
  27302. }
  27303. }
  27304. },
  27305. /**
  27306. * Callback for "Edit" button
  27307. */
  27308. _editRowData: function () {
  27309. var that = this;
  27310. var dt = this.s.dt;
  27311. // Complete new row data
  27312. var rowDataArray = {};
  27313. var adata = dt.rows({
  27314. selected: true
  27315. });
  27316. // Getting the inputs from the edit-modal
  27317. $('form[name="altEditor-form"] *').filter(':input').each(function (i) {
  27318. rowDataArray[$(this).attr('id')] = $(this).val();
  27319. });
  27320. console.log(rowDataArray); //DEBUG
  27321. that.onEditRow(that,
  27322. rowDataArray,
  27323. function(data,b,c,d,e){ that._editRowCallback(data,b,c,d,e); },
  27324. function(data){ that._errorCallback(data);
  27325. });
  27326. },
  27327. /**
  27328. * Open Delete Modal for selected row
  27329. *
  27330. * @private
  27331. */
  27332. _openDeleteModal: function () {
  27333. var that = this;
  27334. var dt = this.s.dt;
  27335. var columnDefs = [];
  27336. // Adding attribute IDs and values to object
  27337. for (var i in dt.context[0].aoColumns) {
  27338. columnDefs.push({
  27339. title: dt.context[0].aoColumns[i].sTitle,
  27340. type: (dt.context[0].aoColumns[i].type ? dt.context[0].aoColumns[i].type : 'text'),
  27341. name: dt.context[0].aoColumns[i].data ? dt.context[0].aoColumns[i].data : dt.context[0].aoColumns[i].mData
  27342. });
  27343. }
  27344. var adata = dt.rows({
  27345. selected: true
  27346. });
  27347. // Building delete-modal
  27348. var data = "";
  27349. data += "<form name='altEditor-form' role='form'><div class='row'>";
  27350. for (var j in columnDefs) {
  27351. if (columnDefs[j].type.indexOf("hidden") >= 0) {
  27352. data += "<input type='hidden' id='" + columnDefs[j].title + "' value='" + adata.data()[0][columnDefs[j].name] + "' readonly></input>";
  27353. }
  27354. else {
  27355. data += "<div class='col-12 mb-2'><label class='form-label' for='"
  27356. + that._quoteattr(columnDefs[j].name)
  27357. + "'>"
  27358. + columnDefs[j].title
  27359. + ":&nbsp</label> <input type='hidden' id='"
  27360. + that._quoteattr(columnDefs[j].title)
  27361. + "' name='"
  27362. + that._quoteattr(columnDefs[j].title)
  27363. + "' placeholder='"
  27364. + that._quoteattr(columnDefs[j].placeholderMsg)
  27365. + "' style='overflow:hidden' class='form-control' value='"
  27366. + that._quoteattr(adata.data()[0][columnDefs[j].name]) + "' >"
  27367. + adata.data()[0][columnDefs[j].name]
  27368. + "</input></div>";
  27369. }
  27370. }
  27371. // close the form
  27372. data += "</div></form>";
  27373. var selector = this.modal_selector;
  27374. $(selector).on('show.bs.modal', function () {
  27375. var btns = '<button type="button" data-content="remove" class="btn btn-default" data-dismiss="modal">Cancel</button>' +
  27376. '<button type="button" data-content="remove" class="btn btn-danger" id="deleteRowBtn"><i class="fal fa-times"></i> Delete</button>';
  27377. $(selector).find('.modal-title').html('Delete Record');
  27378. $(selector).find('.modal-body').html(data);
  27379. $(selector).find('.modal-footer').html(btns);
  27380. });
  27381. $(selector).modal('show');
  27382. $(selector + ' input[0]').focus();
  27383. },
  27384. /**
  27385. * Callback for "Delete" button
  27386. */
  27387. _deleteRow: function () {
  27388. var that = this;
  27389. var dt = this.s.dt;
  27390. var jsonDataArray = {};
  27391. var adata = dt.rows({
  27392. selected: true
  27393. });
  27394. // Getting the IDs and Values of the tablerow
  27395. for (var i = 0; i < dt.context[0].aoColumns.length; i++) {
  27396. // .data is the attribute name, if any; .idx is the column index, so it should always exists
  27397. var name = dt.context[0].aoColumns[i].data ? dt.context[0].aoColumns[i].data :
  27398. dt.context[0].aoColumns[i].mData ? dt.context[0].aoColumns[i].mData :
  27399. dt.context[0].aoColumns[i].idx;
  27400. jsonDataArray[name] = adata.data()[0][name];
  27401. }
  27402. that.onDeleteRow(that,
  27403. jsonDataArray,
  27404. function(data){ that._deleteRowCallback(data); },
  27405. function(data){ that._errorCallback(data);
  27406. });
  27407. },
  27408. /**
  27409. * Open Add Modal for selected row
  27410. *
  27411. * @private
  27412. */
  27413. _openAddModal: function () {
  27414. var that = this;
  27415. var dt = this.s.dt;
  27416. var columnDefs = [];
  27417. // Adding column attributes to object.
  27418. for (var i in dt.context[0].aoColumns) {
  27419. var obj = dt.context[0].aoColumns[i];
  27420. columnDefs[i] = {
  27421. title: obj.sTitle,
  27422. name: (obj.data ? obj.data : obj.mData),
  27423. type: (obj.type ? obj.type : 'text'),
  27424. defaultValue: (obj.defaultValue ? obj.defaultValue : ''),
  27425. options: (obj.options ? obj.options : []),
  27426. msg: (obj.errorMsg ? obj.errorMsg : ''),
  27427. hoverMsg: (obj.hoverMsg ? obj.hoverMsg : ''),
  27428. pattern: (obj.pattern ? obj.pattern : '.*'),
  27429. special: (obj.special ? obj.special : ''),
  27430. placeholderMsg: (obj.placeholderMsg ? obj.placeholderMsg : ''),
  27431. unique: (obj.unique ? obj.unique : false),
  27432. uniqueMsg: (obj.uniqueMsg ? obj.uniqueMsg : ''),
  27433. maxLength: (obj.maxLength ? obj.maxLength : false),
  27434. multiple: (obj.multiple ? obj.multiple : false),
  27435. select2: (obj.select2 ? obj.select2 : false)
  27436. }
  27437. }
  27438. // Building add-form
  27439. var data = "";
  27440. data += "<form name='altEditor-form' role='form' class='needs-validation' novalidate=''>";
  27441. for (var j in columnDefs) {
  27442. if (columnDefs[j].type.indexOf("hidden") >= 0) {
  27443. // just do nothing for hidden fields!
  27444. }
  27445. else {
  27446. data += "<div class='form-group row'>"
  27447. + "<label class='form-label col-sm-3 col-form-label text-left text-sm-right' for='"
  27448. + columnDefs[j].name
  27449. + "'>"
  27450. + columnDefs[j].title
  27451. + ":</label><div class='col-lg-9'>";
  27452. // Adding text-inputs and errorlabels
  27453. if (columnDefs[j].type.indexOf("text") >= 0 ||
  27454. columnDefs[j].type.indexOf("date") >= 0 ||
  27455. columnDefs[j].type.indexOf("email") >= 0 ||
  27456. columnDefs[j].type.indexOf("password") >= 0 ||
  27457. columnDefs[j].type.indexOf("number") >= 0 ||
  27458. columnDefs[j].type.indexOf("time") >= 0) {
  27459. data += "<input type='"
  27460. + that._quoteattr(columnDefs[j].type)
  27461. + "' id='"
  27462. + that._quoteattr(columnDefs[j].name)
  27463. + "' pattern='"
  27464. + that._quoteattr(columnDefs[j].pattern)
  27465. + "' title='"
  27466. + that._quoteattr(columnDefs[j].hoverMsg)
  27467. + "' name='"
  27468. + that._quoteattr(columnDefs[j].title)
  27469. + "' placeholder='"
  27470. + that._quoteattr(columnDefs[j].placeholderMsg)
  27471. + "' value='"
  27472. + that._quoteattr(columnDefs[j].defaultValue)
  27473. + "' data-special='"
  27474. + columnDefs[j].special
  27475. + "' data-errorMsg='"
  27476. + that._quoteattr(columnDefs[j].msg)
  27477. + "' data-uniqueMsg='"
  27478. + that._quoteattr(columnDefs[j].uniqueMsg)
  27479. + "' data-unique='"
  27480. + columnDefs[j].unique
  27481. + "'"
  27482. + (columnDefs[j].maxLength == false ? "" : " maxlength='" + columnDefs[j].maxLength + "'")
  27483. + " style='overflow:hidden' class='form-control' value=''>";
  27484. data += "<label id='" + that._quoteattr(columnDefs[j].name) + "label"
  27485. + "' class='errorLabel help-block text-danger' style='display:none'></label>";
  27486. }
  27487. // Adding readonly-fields
  27488. if (columnDefs[j].type.indexOf("readonly") >= 0) {
  27489. data += "<input type='text' readonly id='"
  27490. + that._quoteattr(columnDefs[j].name)
  27491. + "' name='"
  27492. + that._quoteattr(columnDefs[j].title)
  27493. + "' placeholder='"
  27494. + that._quoteattr(columnDefs[j].placeholderMsg)
  27495. + "' style='overflow:hidden' class='form-control' value=''>";
  27496. }
  27497. // Adding select-fields
  27498. if (columnDefs[j].type.indexOf("select") >= 0) {
  27499. var options = "";
  27500. for (var i = 0; i < columnDefs[j].options.length; i++) {
  27501. options += "<option value='" + that._quoteattr(columnDefs[j].options[i])
  27502. + "'>" + columnDefs[j].options[i] + "</option>";
  27503. }
  27504. data += "<select class='custom-select form-control" + (columnDefs[j].select2 ? ' select2' : '') + "' id='" + that._quoteattr(columnDefs[j].name) + "' name='" + that._quoteattr(columnDefs[j].title) + "' " + (columnDefs[j].multiple ? 'multiple' : '') + ">" + options
  27505. + "</select>";
  27506. }
  27507. data += "</div><div style='clear:both;'></div></div>";
  27508. }
  27509. }
  27510. data += "</form>";
  27511. var selector = this.modal_selector;
  27512. $(selector).on('show.bs.modal', function () {
  27513. var btns = '<button type="button" data-content="remove" class="btn btn-default" data-dismiss="modal">Cancel</button>' +
  27514. '<button type="button" data-content="remove" class="btn btn-primary" id="addRowBtn">Add</button>';
  27515. $(selector).find('.modal-title').html(
  27516. 'Add Record');
  27517. $(selector).find('.modal-body')
  27518. .html(data);
  27519. $(selector)
  27520. .find('.modal-footer')
  27521. .html(btns);
  27522. });
  27523. $(selector).modal('show');
  27524. $(selector + ' input[0]').focus();
  27525. // enable select 2 items
  27526. for (var j in columnDefs) {
  27527. if (columnDefs[j].select2) {
  27528. $(selector).find("select#" + columnDefs[j].name).select2(columnDefs[j].select2);
  27529. }
  27530. }
  27531. },
  27532. /**
  27533. * Callback for "Add" button
  27534. */
  27535. _addRowData: function () {
  27536. var that = this;
  27537. var dt = this.s.dt;
  27538. var rowDataArray = {};
  27539. // Getting the inputs from the modal
  27540. $('form[name="altEditor-form"] *').filter(':input').each(function (i) {
  27541. rowDataArray[$(this).attr('id')] = $(this).val();
  27542. });
  27543. //console.log(rowDataArray); //DEBUG
  27544. that.onAddRow(that,
  27545. rowDataArray,
  27546. function(data){ that._addRowCallback(data); },
  27547. function(data){ that._errorCallback(data);
  27548. });
  27549. },
  27550. /**
  27551. * Called after a row has been deleted on server
  27552. */
  27553. _deleteRowCallback: function (response, status, more) {
  27554. var selector = this.modal_selector;
  27555. $(selector + ' .modal-body .alert').remove();
  27556. var message = '<div class="alert alert-success" role="alert">' +
  27557. '<strong>Success!</strong>' +
  27558. '</div>';
  27559. $(selector + ' .modal-body').append(message);
  27560. this.s.dt.row({
  27561. selected : true
  27562. }).remove();
  27563. this.s.dt.draw();
  27564. // Disabling submit button
  27565. $("div"+selector).find("button#addRowBtn").prop('disabled', true);
  27566. $("div"+selector).find("button#editRowBtn").prop('disabled', true);
  27567. $("div"+selector).find("button#deleteRowBtn").prop('disabled', true);
  27568. //hide modal
  27569. //$(this.modal_selector).modal('hide');
  27570. $(selector).modal('hide');
  27571. },
  27572. /**
  27573. * Called after a row has been inserted on server
  27574. */
  27575. _addRowCallback: function (response, status, more) {
  27576. //TODO should honor dt.ajax().dataSrc
  27577. var data = (typeof response === "string") ? JSON.parse(response) : response;
  27578. var selector = this.modal_selector;
  27579. $(selector + ' .modal-body .alert').remove();
  27580. var message = '<div class="alert alert-success" role="alert">' +
  27581. '<strong>Success!</strong>' +
  27582. '</div>';
  27583. $(selector + ' .modal-body').append(message);
  27584. this.s.dt.row.add(data).draw(false);
  27585. // Disabling submit button
  27586. $("div" + selector).find("button#addRowBtn").prop('disabled', true);
  27587. $("div" + selector).find("button#editRowBtn").prop('disabled', true);
  27588. $("div" + selector).find("button#deleteRowBtn").prop('disabled', true);
  27589. //hide modal
  27590. //$(this.modal_selector).modal('hide');
  27591. $(selector).modal('hide');
  27592. },
  27593. /**
  27594. * Called after a row has been updated on server
  27595. */
  27596. _editRowCallback: function (response, status, more) {
  27597. //TODO should honor dt.ajax().dataSrc
  27598. var data = (typeof response === "string") ? JSON.parse(response) : response;
  27599. var selector = this.modal_selector;
  27600. $(selector + ' .modal-body .alert').remove();
  27601. var message = '<div class="alert alert-success" role="alert">' +
  27602. '<strong>Success!</strong>' +
  27603. '</div>';
  27604. $(selector + ' .modal-body').prepend(message);
  27605. this.s.dt.row({
  27606. selected : true
  27607. }).data(data);
  27608. this.s.dt.draw();
  27609. // Disabling submit button
  27610. $("div" + selector).find("button#addRowBtn").prop('disabled', true);
  27611. $("div" + selector).find("button#editRowBtn").prop('disabled', true);
  27612. $("div" + selector).find("button#deleteRowBtn").prop('disabled', true);
  27613. //hide modal
  27614. //$(this.modal_selector).modal('hide');
  27615. $(selector).modal('hide');
  27616. },
  27617. /**
  27618. * Called after AJAX server returned an error
  27619. */
  27620. _errorCallback: function (response, status, more) {
  27621. var error = response;
  27622. var selector = this.modal_selector;
  27623. $(selector + ' .modal-body .alert').remove();
  27624. var errstr = "There was an unknown error!";
  27625. if (error.responseJSON && error.responseJSON.errors) {
  27626. errstr = "";
  27627. for (var key in error.responseJSON.errors) {
  27628. errstr += error.responseJSON.errors[key][0];
  27629. }
  27630. }
  27631. var message = '<div class="alert alert-danger" role="alert">' +
  27632. '<strong>Error!</strong> ' + (error.status == null ? "" : 'Response code: ' + error.status) + " " + errstr +
  27633. '</div>';
  27634. $(selector + ' .modal-body').append(message);
  27635. },
  27636. /**
  27637. * Default callback for insertion: mock webservice, always success.
  27638. */
  27639. onAddRow: function(dt, rowdata, success, error) {
  27640. console.log("Missing AJAX configuration for INSERT");
  27641. success(rowdata);
  27642. },
  27643. /**
  27644. * Default callback for editing: mock webservice, always success.
  27645. */
  27646. onEditRow: function(dt, rowdata, success, error) {
  27647. console.log("Missing AJAX configuration for UPDATE");
  27648. success(rowdata);
  27649. },
  27650. /**
  27651. * Default callback for deletion: mock webservice, always success.
  27652. */
  27653. onDeleteRow: function(dt, rowdata, success, error) {
  27654. console.log("Missing AJAX configuration for DELETE");
  27655. success(rowdata);
  27656. },
  27657. /**
  27658. * Validates input
  27659. * @returns {boolean}
  27660. * @private
  27661. */
  27662. _inputValidation: function () {
  27663. var that = this;
  27664. var dt = this.s.dt;
  27665. var isValid = false;
  27666. var errorcount = 0;
  27667. // Looping through all text fields
  27668. $('form[name="altEditor-form"] *').filter(':text').each(
  27669. function (i) {
  27670. var errorLabel = "#" + $(this).attr("id") + "label";
  27671. // reset error display
  27672. $(errorLabel).hide();
  27673. $(errorLabel).empty();
  27674. if (!$(this).val().match($(this).attr("pattern"))) {
  27675. $(errorLabel).html($(this).attr("data-errorMsg"));
  27676. $(errorLabel).show();
  27677. errorcount++;
  27678. }
  27679. // now check if its should be unique
  27680. else if ($(this).attr("data-unique") == "true") {
  27681. // go through each item in this column
  27682. var colData = dt.column("th:contains('" + $(this).attr("name") + "')").data();
  27683. var selectedCellData = null;
  27684. if (dt.row({selected: true}).index() != null)
  27685. selectedCellData = dt.cell(dt.row({selected: true}).index(), dt.column("th:contains('" + $(this).attr("name") + "')").index()).data();
  27686. for (var j in colData) {
  27687. // if the element is in the column and its not the selected one then its not unique
  27688. if ($(this).val() == colData[j] && colData[j] != selectedCellData) {
  27689. $(errorLabel).html($(this).attr("data-uniqueMsg"));
  27690. $(errorLabel).show();
  27691. errorcount++;
  27692. }
  27693. }
  27694. }
  27695. });
  27696. if (errorcount == 0) {
  27697. isValid = true;
  27698. }
  27699. return isValid;
  27700. },
  27701. /**
  27702. * Sanitizes input for use in HTML
  27703. * @param s
  27704. * @param preserveCR
  27705. * @returns {string}
  27706. * @private
  27707. */
  27708. _quoteattr: function (s, preserveCR) {
  27709. if (s == null)
  27710. return "";
  27711. preserveCR = preserveCR ? '&#13;' : '\n';
  27712. return ('' + s) /* Forces the conversion to string. */
  27713. .replace(/&/g, '&amp;') /* This MUST be the 1st replacement. */
  27714. .replace(/'/g, '&apos;') /* The 4 other predefined entities, required. */
  27715. .replace(/"/g, '&quot;')
  27716. .replace(/</g, '&lt;')
  27717. .replace(/>/g, '&gt;')
  27718. .replace(/\r\n/g, preserveCR) /* Must be before the next replacement. */
  27719. .replace(/[\r\n]/g, preserveCR);
  27720. },
  27721. });
  27722. /**
  27723. * altEditor version
  27724. *
  27725. * @static
  27726. * @type String
  27727. */
  27728. altEditor.version = '2.0';
  27729. /**
  27730. * altEditor defaults
  27731. *
  27732. * @namespace
  27733. */
  27734. altEditor.defaults = {
  27735. /**
  27736. * @type {Boolean} Ask user what they want to do, even for a single
  27737. * option
  27738. */
  27739. alwaysAsk: false,
  27740. /** @type {string|null} What will trigger a focus */
  27741. focus: null, // focus, click, hover
  27742. /** @type {column-selector} Columns to provide auto fill for */
  27743. columns: '', // all
  27744. /** @type {boolean|null} Update the cells after a drag */
  27745. update: null, // false is editor given, true otherwise
  27746. /** @type {DataTable.Editor} Editor instance for automatic submission */
  27747. editor: null
  27748. };
  27749. /**
  27750. * Classes used by altEditor that are configurable
  27751. *
  27752. * @namespace
  27753. */
  27754. altEditor.classes = {
  27755. /** @type {String} Class used by the selection button */
  27756. btn: 'btn'
  27757. };
  27758. // Attach a listener to the document which listens for DataTables
  27759. // initialisation
  27760. // events so we can automatically initialise
  27761. $(document).on('preInit.dt.altEditor', function (e, settings, json) {
  27762. if (e.namespace !== 'dt') {
  27763. return;
  27764. }
  27765. var init = settings.oInit.altEditor;
  27766. var defaults = DataTable.defaults.altEditor;
  27767. if (init || defaults) {
  27768. var opts = $.extend({}, init, defaults);
  27769. if (init !== false) {
  27770. new altEditor(settings, opts);
  27771. }
  27772. }
  27773. });
  27774. // Alias for access
  27775. DataTable.altEditor = altEditor;
  27776. return altEditor;
  27777. });