datatables.js 759 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464274652746627467274682746927470274712747227473274742747527476274772747827479274802748127482274832748427485274862748727488274892749027491274922749327494274952749627497274982749927500275012750227503275042750527506275072750827509275102751127512275132751427515275162751727518275192752027521275222752327524275252752627527275282752927530275312753227533275342753527536275372753827539275402754127542275432754427545275462754727548275492755027551275522755327554275552755627557275582755927560275612756227563275642756527566275672756827569275702757127572275732757427575275762757727578275792758027581275822758327584275852758627587275882758927590275912759227593275942759527596275972759827599276002760127602276032760427605276062760727608276092761027611276122761327614276152761627617276182761927620276212762227623276242762527626276272762827629276302763127632276332763427635276362763727638276392764027641276422764327644276452764627647276482764927650276512765227653276542765527656276572765827659276602766127662276632766427665276662766727668276692767027671276722767327674276752767627677276782767927680276812768227683276842768527686276872768827689276902769127692276932769427695276962769727698276992770027701277022770327704277052770627707277082770927710277112771227713277142771527716277172771827719277202772127722277232772427725277262772727728277292773027731277322773327734277352773627737277382773927740277412774227743277442774527746277472774827749277502775127752277532775427755277562775727758277592776027761277622776327764277652776627767277682776927770277712777227773277742777527776277772777827779277802778127782277832778427785277862778727788
  1. /*
  2. * This combined file was created by the DataTables downloader builder:
  3. * https://datatables.net/download
  4. *
  5. * To rebuild or modify this file with the latest versions of the included
  6. * software please visit:
  7. * https://datatables.net/download/#dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5
  8. *
  9. * Included libraries:
  10. * DataTables 1.10.16, AutoFill 2.2.2, Buttons 1.5.1, ColReorder 1.4.1, FixedColumns 3.2.4, FixedHeader 3.1.3, KeyTable 2.3.2, Responsive 2.2.1, RowReorder 1.2.3, Scroller 1.4.4, Select 1.2.5
  11. */
  12. /*! DataTables 1.10.16
  13. * ©2008-2017 SpryMedia Ltd - datatables.net/license
  14. */
  15. /**
  16. * @summary DataTables
  17. * @description Paginate, search and order HTML tables
  18. * @version 1.10.16
  19. * @file jquery.dataTables.js
  20. * @author SpryMedia Ltd
  21. * @contact www.datatables.net
  22. * @copyright Copyright 2008-2017 SpryMedia Ltd.
  23. *
  24. * This source file is free software, available under the following license:
  25. * MIT license - http://datatables.net/license
  26. *
  27. * This source file is distributed in the hope that it will be useful, but
  28. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  29. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  30. *
  31. * For details please refer to: http://www.datatables.net
  32. */
  33. /*jslint evil: true, undef: true, browser: true */
  34. /*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*/
  35. (function( factory ) {
  36. "use strict";
  37. if ( typeof define === 'function' && define.amd ) {
  38. // AMD
  39. define( ['jquery'], function ( $ ) {
  40. return factory( $, window, document );
  41. } );
  42. }
  43. else if ( typeof exports === 'object' ) {
  44. // CommonJS
  45. module.exports = function (root, $) {
  46. if ( ! root ) {
  47. // CommonJS environments without a window global must pass a
  48. // root. This will give an error otherwise
  49. root = window;
  50. }
  51. if ( ! $ ) {
  52. $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
  53. require('jquery') :
  54. require('jquery')( root );
  55. }
  56. return factory( $, root, root.document );
  57. };
  58. }
  59. else {
  60. // Browser
  61. factory( jQuery, window, document );
  62. }
  63. }
  64. (function( $, window, document, undefined ) {
  65. "use strict";
  66. /**
  67. * DataTables is a plug-in for the jQuery Javascript library. It is a highly
  68. * flexible tool, based upon the foundations of progressive enhancement,
  69. * which will add advanced interaction controls to any HTML table. For a
  70. * full list of features please refer to
  71. * [DataTables.net](href="http://datatables.net).
  72. *
  73. * Note that the `DataTable` object is not a global variable but is aliased
  74. * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
  75. * be accessed.
  76. *
  77. * @class
  78. * @param {object} [init={}] Configuration object for DataTables. Options
  79. * are defined by {@link DataTable.defaults}
  80. * @requires jQuery 1.7+
  81. *
  82. * @example
  83. * // Basic initialisation
  84. * $(document).ready( function {
  85. * $('#example').dataTable();
  86. * } );
  87. *
  88. * @example
  89. * // Initialisation with configuration options - in this case, disable
  90. * // pagination and sorting.
  91. * $(document).ready( function {
  92. * $('#example').dataTable( {
  93. * "paginate": false,
  94. * "sort": false
  95. * } );
  96. * } );
  97. */
  98. var DataTable = function ( options )
  99. {
  100. /**
  101. * Perform a jQuery selector action on the table's TR elements (from the tbody) and
  102. * return the resulting jQuery object.
  103. * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
  104. * @param {object} [oOpts] Optional parameters for modifying the rows to be included
  105. * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
  106. * criterion ("applied") or all TR elements (i.e. no filter).
  107. * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
  108. * Can be either 'current', whereby the current sorting of the table is used, or
  109. * 'original' whereby the original order the data was read into the table is used.
  110. * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
  111. * ("current") or not ("all"). If 'current' is given, then order is assumed to be
  112. * 'current' and filter is 'applied', regardless of what they might be given as.
  113. * @returns {object} jQuery object, filtered by the given selector.
  114. * @dtopt API
  115. * @deprecated Since v1.10
  116. *
  117. * @example
  118. * $(document).ready(function() {
  119. * var oTable = $('#example').dataTable();
  120. *
  121. * // Highlight every second row
  122. * oTable.$('tr:odd').css('backgroundColor', 'blue');
  123. * } );
  124. *
  125. * @example
  126. * $(document).ready(function() {
  127. * var oTable = $('#example').dataTable();
  128. *
  129. * // Filter to rows with 'Webkit' in them, add a background colour and then
  130. * // remove the filter, thus highlighting the 'Webkit' rows only.
  131. * oTable.fnFilter('Webkit');
  132. * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
  133. * oTable.fnFilter('');
  134. * } );
  135. */
  136. this.$ = function ( sSelector, oOpts )
  137. {
  138. return this.api(true).$( sSelector, oOpts );
  139. };
  140. /**
  141. * Almost identical to $ in operation, but in this case returns the data for the matched
  142. * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
  143. * rather than any descendants, so the data can be obtained for the row/cell. If matching
  144. * rows are found, the data returned is the original data array/object that was used to
  145. * create the row (or a generated array if from a DOM source).
  146. *
  147. * This method is often useful in-combination with $ where both functions are given the
  148. * same parameters and the array indexes will match identically.
  149. * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
  150. * @param {object} [oOpts] Optional parameters for modifying the rows to be included
  151. * @param {string} [oOpts.filter=none] Select elements that meet the current filter
  152. * criterion ("applied") or all elements (i.e. no filter).
  153. * @param {string} [oOpts.order=current] Order of the data in the processed array.
  154. * Can be either 'current', whereby the current sorting of the table is used, or
  155. * 'original' whereby the original order the data was read into the table is used.
  156. * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
  157. * ("current") or not ("all"). If 'current' is given, then order is assumed to be
  158. * 'current' and filter is 'applied', regardless of what they might be given as.
  159. * @returns {array} Data for the matched elements. If any elements, as a result of the
  160. * selector, were not TR, TD or TH elements in the DataTable, they will have a null
  161. * entry in the array.
  162. * @dtopt API
  163. * @deprecated Since v1.10
  164. *
  165. * @example
  166. * $(document).ready(function() {
  167. * var oTable = $('#example').dataTable();
  168. *
  169. * // Get the data from the first row in the table
  170. * var data = oTable._('tr:first');
  171. *
  172. * // Do something useful with the data
  173. * alert( "First cell is: "+data[0] );
  174. * } );
  175. *
  176. * @example
  177. * $(document).ready(function() {
  178. * var oTable = $('#example').dataTable();
  179. *
  180. * // Filter to 'Webkit' and get all data for
  181. * oTable.fnFilter('Webkit');
  182. * var data = oTable._('tr', {"search": "applied"});
  183. *
  184. * // Do something with the data
  185. * alert( data.length+" rows matched the search" );
  186. * } );
  187. */
  188. this._ = function ( sSelector, oOpts )
  189. {
  190. return this.api(true).rows( sSelector, oOpts ).data();
  191. };
  192. /**
  193. * Create a DataTables Api instance, with the currently selected tables for
  194. * the Api's context.
  195. * @param {boolean} [traditional=false] Set the API instance's context to be
  196. * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
  197. * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
  198. * or if all tables captured in the jQuery object should be used.
  199. * @return {DataTables.Api}
  200. */
  201. this.api = function ( traditional )
  202. {
  203. return traditional ?
  204. new _Api(
  205. _fnSettingsFromNode( this[ _ext.iApiIndex ] )
  206. ) :
  207. new _Api( this );
  208. };
  209. /**
  210. * Add a single new row or multiple rows of data to the table. Please note
  211. * that this is suitable for client-side processing only - if you are using
  212. * server-side processing (i.e. "bServerSide": true), then to add data, you
  213. * must add it to the data source, i.e. the server-side, through an Ajax call.
  214. * @param {array|object} data The data to be added to the table. This can be:
  215. * <ul>
  216. * <li>1D array of data - add a single row with the data provided</li>
  217. * <li>2D array of arrays - add multiple rows in a single call</li>
  218. * <li>object - data object when using <i>mData</i></li>
  219. * <li>array of objects - multiple data objects when using <i>mData</i></li>
  220. * </ul>
  221. * @param {bool} [redraw=true] redraw the table or not
  222. * @returns {array} An array of integers, representing the list of indexes in
  223. * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
  224. * the table.
  225. * @dtopt API
  226. * @deprecated Since v1.10
  227. *
  228. * @example
  229. * // Global var for counter
  230. * var giCount = 2;
  231. *
  232. * $(document).ready(function() {
  233. * $('#example').dataTable();
  234. * } );
  235. *
  236. * function fnClickAddRow() {
  237. * $('#example').dataTable().fnAddData( [
  238. * giCount+".1",
  239. * giCount+".2",
  240. * giCount+".3",
  241. * giCount+".4" ]
  242. * );
  243. *
  244. * giCount++;
  245. * }
  246. */
  247. this.fnAddData = function( data, redraw )
  248. {
  249. var api = this.api( true );
  250. /* Check if we want to add multiple rows or not */
  251. var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
  252. api.rows.add( data ) :
  253. api.row.add( data );
  254. if ( redraw === undefined || redraw ) {
  255. api.draw();
  256. }
  257. return rows.flatten().toArray();
  258. };
  259. /**
  260. * This function will make DataTables recalculate the column sizes, based on the data
  261. * contained in the table and the sizes applied to the columns (in the DOM, CSS or
  262. * through the sWidth parameter). This can be useful when the width of the table's
  263. * parent element changes (for example a window resize).
  264. * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
  265. * @dtopt API
  266. * @deprecated Since v1.10
  267. *
  268. * @example
  269. * $(document).ready(function() {
  270. * var oTable = $('#example').dataTable( {
  271. * "sScrollY": "200px",
  272. * "bPaginate": false
  273. * } );
  274. *
  275. * $(window).on('resize', function () {
  276. * oTable.fnAdjustColumnSizing();
  277. * } );
  278. * } );
  279. */
  280. this.fnAdjustColumnSizing = function ( bRedraw )
  281. {
  282. var api = this.api( true ).columns.adjust();
  283. var settings = api.settings()[0];
  284. var scroll = settings.oScroll;
  285. if ( bRedraw === undefined || bRedraw ) {
  286. api.draw( false );
  287. }
  288. else if ( scroll.sX !== "" || scroll.sY !== "" ) {
  289. /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
  290. _fnScrollDraw( settings );
  291. }
  292. };
  293. /**
  294. * Quickly and simply clear a table
  295. * @param {bool} [bRedraw=true] redraw the table or not
  296. * @dtopt API
  297. * @deprecated Since v1.10
  298. *
  299. * @example
  300. * $(document).ready(function() {
  301. * var oTable = $('#example').dataTable();
  302. *
  303. * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
  304. * oTable.fnClearTable();
  305. * } );
  306. */
  307. this.fnClearTable = function( bRedraw )
  308. {
  309. var api = this.api( true ).clear();
  310. if ( bRedraw === undefined || bRedraw ) {
  311. api.draw();
  312. }
  313. };
  314. /**
  315. * The exact opposite of 'opening' a row, this function will close any rows which
  316. * are currently 'open'.
  317. * @param {node} nTr the table row to 'close'
  318. * @returns {int} 0 on success, or 1 if failed (can't find the row)
  319. * @dtopt API
  320. * @deprecated Since v1.10
  321. *
  322. * @example
  323. * $(document).ready(function() {
  324. * var oTable;
  325. *
  326. * // 'open' an information row when a row is clicked on
  327. * $('#example tbody tr').click( function () {
  328. * if ( oTable.fnIsOpen(this) ) {
  329. * oTable.fnClose( this );
  330. * } else {
  331. * oTable.fnOpen( this, "Temporary row opened", "info_row" );
  332. * }
  333. * } );
  334. *
  335. * oTable = $('#example').dataTable();
  336. * } );
  337. */
  338. this.fnClose = function( nTr )
  339. {
  340. this.api( true ).row( nTr ).child.hide();
  341. };
  342. /**
  343. * Remove a row for the table
  344. * @param {mixed} target The index of the row from aoData to be deleted, or
  345. * the TR element you want to delete
  346. * @param {function|null} [callBack] Callback function
  347. * @param {bool} [redraw=true] Redraw the table or not
  348. * @returns {array} The row that was deleted
  349. * @dtopt API
  350. * @deprecated Since v1.10
  351. *
  352. * @example
  353. * $(document).ready(function() {
  354. * var oTable = $('#example').dataTable();
  355. *
  356. * // Immediately remove the first row
  357. * oTable.fnDeleteRow( 0 );
  358. * } );
  359. */
  360. this.fnDeleteRow = function( target, callback, redraw )
  361. {
  362. var api = this.api( true );
  363. var rows = api.rows( target );
  364. var settings = rows.settings()[0];
  365. var data = settings.aoData[ rows[0][0] ];
  366. rows.remove();
  367. if ( callback ) {
  368. callback.call( this, settings, data );
  369. }
  370. if ( redraw === undefined || redraw ) {
  371. api.draw();
  372. }
  373. return data;
  374. };
  375. /**
  376. * Restore the table to it's original state in the DOM by removing all of DataTables
  377. * enhancements, alterations to the DOM structure of the table and event listeners.
  378. * @param {boolean} [remove=false] Completely remove the table from the DOM
  379. * @dtopt API
  380. * @deprecated Since v1.10
  381. *
  382. * @example
  383. * $(document).ready(function() {
  384. * // This example is fairly pointless in reality, but shows how fnDestroy can be used
  385. * var oTable = $('#example').dataTable();
  386. * oTable.fnDestroy();
  387. * } );
  388. */
  389. this.fnDestroy = function ( remove )
  390. {
  391. this.api( true ).destroy( remove );
  392. };
  393. /**
  394. * Redraw the table
  395. * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
  396. * @dtopt API
  397. * @deprecated Since v1.10
  398. *
  399. * @example
  400. * $(document).ready(function() {
  401. * var oTable = $('#example').dataTable();
  402. *
  403. * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
  404. * oTable.fnDraw();
  405. * } );
  406. */
  407. this.fnDraw = function( complete )
  408. {
  409. // Note that this isn't an exact match to the old call to _fnDraw - it takes
  410. // into account the new data, but can hold position.
  411. this.api( true ).draw( complete );
  412. };
  413. /**
  414. * Filter the input based on data
  415. * @param {string} sInput String to filter the table on
  416. * @param {int|null} [iColumn] Column to limit filtering to
  417. * @param {bool} [bRegex=false] Treat as regular expression or not
  418. * @param {bool} [bSmart=true] Perform smart filtering or not
  419. * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
  420. * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
  421. * @dtopt API
  422. * @deprecated Since v1.10
  423. *
  424. * @example
  425. * $(document).ready(function() {
  426. * var oTable = $('#example').dataTable();
  427. *
  428. * // Sometime later - filter...
  429. * oTable.fnFilter( 'test string' );
  430. * } );
  431. */
  432. this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
  433. {
  434. var api = this.api( true );
  435. if ( iColumn === null || iColumn === undefined ) {
  436. api.search( sInput, bRegex, bSmart, bCaseInsensitive );
  437. }
  438. else {
  439. api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
  440. }
  441. api.draw();
  442. };
  443. /**
  444. * Get the data for the whole table, an individual row or an individual cell based on the
  445. * provided parameters.
  446. * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
  447. * a TR node then the data source for the whole row will be returned. If given as a
  448. * TD/TH cell node then iCol will be automatically calculated and the data for the
  449. * cell returned. If given as an integer, then this is treated as the aoData internal
  450. * data index for the row (see fnGetPosition) and the data for that row used.
  451. * @param {int} [col] Optional column index that you want the data of.
  452. * @returns {array|object|string} If mRow is undefined, then the data for all rows is
  453. * returned. If mRow is defined, just data for that row, and is iCol is
  454. * defined, only data for the designated cell is returned.
  455. * @dtopt API
  456. * @deprecated Since v1.10
  457. *
  458. * @example
  459. * // Row data
  460. * $(document).ready(function() {
  461. * oTable = $('#example').dataTable();
  462. *
  463. * oTable.$('tr').click( function () {
  464. * var data = oTable.fnGetData( this );
  465. * // ... do something with the array / object of data for the row
  466. * } );
  467. * } );
  468. *
  469. * @example
  470. * // Individual cell data
  471. * $(document).ready(function() {
  472. * oTable = $('#example').dataTable();
  473. *
  474. * oTable.$('td').click( function () {
  475. * var sData = oTable.fnGetData( this );
  476. * alert( 'The cell clicked on had the value of '+sData );
  477. * } );
  478. * } );
  479. */
  480. this.fnGetData = function( src, col )
  481. {
  482. var api = this.api( true );
  483. if ( src !== undefined ) {
  484. var type = src.nodeName ? src.nodeName.toLowerCase() : '';
  485. return col !== undefined || type == 'td' || type == 'th' ?
  486. api.cell( src, col ).data() :
  487. api.row( src ).data() || null;
  488. }
  489. return api.data().toArray();
  490. };
  491. /**
  492. * Get an array of the TR nodes that are used in the table's body. Note that you will
  493. * typically want to use the '$' API method in preference to this as it is more
  494. * flexible.
  495. * @param {int} [iRow] Optional row index for the TR element you want
  496. * @returns {array|node} If iRow is undefined, returns an array of all TR elements
  497. * in the table's body, or iRow is defined, just the TR element requested.
  498. * @dtopt API
  499. * @deprecated Since v1.10
  500. *
  501. * @example
  502. * $(document).ready(function() {
  503. * var oTable = $('#example').dataTable();
  504. *
  505. * // Get the nodes from the table
  506. * var nNodes = oTable.fnGetNodes( );
  507. * } );
  508. */
  509. this.fnGetNodes = function( iRow )
  510. {
  511. var api = this.api( true );
  512. return iRow !== undefined ?
  513. api.row( iRow ).node() :
  514. api.rows().nodes().flatten().toArray();
  515. };
  516. /**
  517. * Get the array indexes of a particular cell from it's DOM element
  518. * and column index including hidden columns
  519. * @param {node} node this can either be a TR, TD or TH in the table's body
  520. * @returns {int} If nNode is given as a TR, then a single index is returned, or
  521. * if given as a cell, an array of [row index, column index (visible),
  522. * column index (all)] is given.
  523. * @dtopt API
  524. * @deprecated Since v1.10
  525. *
  526. * @example
  527. * $(document).ready(function() {
  528. * $('#example tbody td').click( function () {
  529. * // Get the position of the current data from the node
  530. * var aPos = oTable.fnGetPosition( this );
  531. *
  532. * // Get the data array for this row
  533. * var aData = oTable.fnGetData( aPos[0] );
  534. *
  535. * // Update the data array and return the value
  536. * aData[ aPos[1] ] = 'clicked';
  537. * this.innerHTML = 'clicked';
  538. * } );
  539. *
  540. * // Init DataTables
  541. * oTable = $('#example').dataTable();
  542. * } );
  543. */
  544. this.fnGetPosition = function( node )
  545. {
  546. var api = this.api( true );
  547. var nodeName = node.nodeName.toUpperCase();
  548. if ( nodeName == 'TR' ) {
  549. return api.row( node ).index();
  550. }
  551. else if ( nodeName == 'TD' || nodeName == 'TH' ) {
  552. var cell = api.cell( node ).index();
  553. return [
  554. cell.row,
  555. cell.columnVisible,
  556. cell.column
  557. ];
  558. }
  559. return null;
  560. };
  561. /**
  562. * Check to see if a row is 'open' or not.
  563. * @param {node} nTr the table row to check
  564. * @returns {boolean} true if the row is currently open, false otherwise
  565. * @dtopt API
  566. * @deprecated Since v1.10
  567. *
  568. * @example
  569. * $(document).ready(function() {
  570. * var oTable;
  571. *
  572. * // 'open' an information row when a row is clicked on
  573. * $('#example tbody tr').click( function () {
  574. * if ( oTable.fnIsOpen(this) ) {
  575. * oTable.fnClose( this );
  576. * } else {
  577. * oTable.fnOpen( this, "Temporary row opened", "info_row" );
  578. * }
  579. * } );
  580. *
  581. * oTable = $('#example').dataTable();
  582. * } );
  583. */
  584. this.fnIsOpen = function( nTr )
  585. {
  586. return this.api( true ).row( nTr ).child.isShown();
  587. };
  588. /**
  589. * This function will place a new row directly after a row which is currently
  590. * on display on the page, with the HTML contents that is passed into the
  591. * function. This can be used, for example, to ask for confirmation that a
  592. * particular record should be deleted.
  593. * @param {node} nTr The table row to 'open'
  594. * @param {string|node|jQuery} mHtml The HTML to put into the row
  595. * @param {string} sClass Class to give the new TD cell
  596. * @returns {node} The row opened. Note that if the table row passed in as the
  597. * first parameter, is not found in the table, this method will silently
  598. * return.
  599. * @dtopt API
  600. * @deprecated Since v1.10
  601. *
  602. * @example
  603. * $(document).ready(function() {
  604. * var oTable;
  605. *
  606. * // 'open' an information row when a row is clicked on
  607. * $('#example tbody tr').click( function () {
  608. * if ( oTable.fnIsOpen(this) ) {
  609. * oTable.fnClose( this );
  610. * } else {
  611. * oTable.fnOpen( this, "Temporary row opened", "info_row" );
  612. * }
  613. * } );
  614. *
  615. * oTable = $('#example').dataTable();
  616. * } );
  617. */
  618. this.fnOpen = function( nTr, mHtml, sClass )
  619. {
  620. return this.api( true )
  621. .row( nTr )
  622. .child( mHtml, sClass )
  623. .show()
  624. .child()[0];
  625. };
  626. /**
  627. * Change the pagination - provides the internal logic for pagination in a simple API
  628. * function. With this function you can have a DataTables table go to the next,
  629. * previous, first or last pages.
  630. * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
  631. * or page number to jump to (integer), note that page 0 is the first page.
  632. * @param {bool} [bRedraw=true] Redraw the table or not
  633. * @dtopt API
  634. * @deprecated Since v1.10
  635. *
  636. * @example
  637. * $(document).ready(function() {
  638. * var oTable = $('#example').dataTable();
  639. * oTable.fnPageChange( 'next' );
  640. * } );
  641. */
  642. this.fnPageChange = function ( mAction, bRedraw )
  643. {
  644. var api = this.api( true ).page( mAction );
  645. if ( bRedraw === undefined || bRedraw ) {
  646. api.draw(false);
  647. }
  648. };
  649. /**
  650. * Show a particular column
  651. * @param {int} iCol The column whose display should be changed
  652. * @param {bool} bShow Show (true) or hide (false) the column
  653. * @param {bool} [bRedraw=true] Redraw the table or not
  654. * @dtopt API
  655. * @deprecated Since v1.10
  656. *
  657. * @example
  658. * $(document).ready(function() {
  659. * var oTable = $('#example').dataTable();
  660. *
  661. * // Hide the second column after initialisation
  662. * oTable.fnSetColumnVis( 1, false );
  663. * } );
  664. */
  665. this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
  666. {
  667. var api = this.api( true ).column( iCol ).visible( bShow );
  668. if ( bRedraw === undefined || bRedraw ) {
  669. api.columns.adjust().draw();
  670. }
  671. };
  672. /**
  673. * Get the settings for a particular table for external manipulation
  674. * @returns {object} DataTables settings object. See
  675. * {@link DataTable.models.oSettings}
  676. * @dtopt API
  677. * @deprecated Since v1.10
  678. *
  679. * @example
  680. * $(document).ready(function() {
  681. * var oTable = $('#example').dataTable();
  682. * var oSettings = oTable.fnSettings();
  683. *
  684. * // Show an example parameter from the settings
  685. * alert( oSettings._iDisplayStart );
  686. * } );
  687. */
  688. this.fnSettings = function()
  689. {
  690. return _fnSettingsFromNode( this[_ext.iApiIndex] );
  691. };
  692. /**
  693. * Sort the table by a particular column
  694. * @param {int} iCol the data index to sort on. Note that this will not match the
  695. * 'display index' if you have hidden data entries
  696. * @dtopt API
  697. * @deprecated Since v1.10
  698. *
  699. * @example
  700. * $(document).ready(function() {
  701. * var oTable = $('#example').dataTable();
  702. *
  703. * // Sort immediately with columns 0 and 1
  704. * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
  705. * } );
  706. */
  707. this.fnSort = function( aaSort )
  708. {
  709. this.api( true ).order( aaSort ).draw();
  710. };
  711. /**
  712. * Attach a sort listener to an element for a given column
  713. * @param {node} nNode the element to attach the sort listener to
  714. * @param {int} iColumn the column that a click on this node will sort on
  715. * @param {function} [fnCallback] callback function when sort is run
  716. * @dtopt API
  717. * @deprecated Since v1.10
  718. *
  719. * @example
  720. * $(document).ready(function() {
  721. * var oTable = $('#example').dataTable();
  722. *
  723. * // Sort on column 1, when 'sorter' is clicked on
  724. * oTable.fnSortListener( document.getElementById('sorter'), 1 );
  725. * } );
  726. */
  727. this.fnSortListener = function( nNode, iColumn, fnCallback )
  728. {
  729. this.api( true ).order.listener( nNode, iColumn, fnCallback );
  730. };
  731. /**
  732. * Update a table cell or row - this method will accept either a single value to
  733. * update the cell with, an array of values with one element for each column or
  734. * an object in the same format as the original data source. The function is
  735. * self-referencing in order to make the multi column updates easier.
  736. * @param {object|array|string} mData Data to update the cell/row with
  737. * @param {node|int} mRow TR element you want to update or the aoData index
  738. * @param {int} [iColumn] The column to update, give as null or undefined to
  739. * update a whole row.
  740. * @param {bool} [bRedraw=true] Redraw the table or not
  741. * @param {bool} [bAction=true] Perform pre-draw actions or not
  742. * @returns {int} 0 on success, 1 on error
  743. * @dtopt API
  744. * @deprecated Since v1.10
  745. *
  746. * @example
  747. * $(document).ready(function() {
  748. * var oTable = $('#example').dataTable();
  749. * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
  750. * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
  751. * } );
  752. */
  753. this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
  754. {
  755. var api = this.api( true );
  756. if ( iColumn === undefined || iColumn === null ) {
  757. api.row( mRow ).data( mData );
  758. }
  759. else {
  760. api.cell( mRow, iColumn ).data( mData );
  761. }
  762. if ( bAction === undefined || bAction ) {
  763. api.columns.adjust();
  764. }
  765. if ( bRedraw === undefined || bRedraw ) {
  766. api.draw();
  767. }
  768. return 0;
  769. };
  770. /**
  771. * Provide a common method for plug-ins to check the version of DataTables being used, in order
  772. * to ensure compatibility.
  773. * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
  774. * formats "X" and "X.Y" are also acceptable.
  775. * @returns {boolean} true if this version of DataTables is greater or equal to the required
  776. * version, or false if this version of DataTales is not suitable
  777. * @method
  778. * @dtopt API
  779. * @deprecated Since v1.10
  780. *
  781. * @example
  782. * $(document).ready(function() {
  783. * var oTable = $('#example').dataTable();
  784. * alert( oTable.fnVersionCheck( '1.9.0' ) );
  785. * } );
  786. */
  787. this.fnVersionCheck = _ext.fnVersionCheck;
  788. var _that = this;
  789. var emptyInit = options === undefined;
  790. var len = this.length;
  791. if ( emptyInit ) {
  792. options = {};
  793. }
  794. this.oApi = this.internal = _ext.internal;
  795. // Extend with old style plug-in API methods
  796. for ( var fn in DataTable.ext.internal ) {
  797. if ( fn ) {
  798. this[fn] = _fnExternApiFunc(fn);
  799. }
  800. }
  801. this.each(function() {
  802. // For each initialisation we want to give it a clean initialisation
  803. // object that can be bashed around
  804. var o = {};
  805. var oInit = len > 1 ? // optimisation for single table case
  806. _fnExtend( o, options, true ) :
  807. options;
  808. /*global oInit,_that,emptyInit*/
  809. var i=0, iLen, j, jLen, k, kLen;
  810. var sId = this.getAttribute( 'id' );
  811. var bInitHandedOff = false;
  812. var defaults = DataTable.defaults;
  813. var $this = $(this);
  814. /* Sanity check */
  815. if ( this.nodeName.toLowerCase() != 'table' )
  816. {
  817. _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
  818. return;
  819. }
  820. /* Backwards compatibility for the defaults */
  821. _fnCompatOpts( defaults );
  822. _fnCompatCols( defaults.column );
  823. /* Convert the camel-case defaults to Hungarian */
  824. _fnCamelToHungarian( defaults, defaults, true );
  825. _fnCamelToHungarian( defaults.column, defaults.column, true );
  826. /* Setting up the initialisation object */
  827. _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
  828. /* Check to see if we are re-initialising a table */
  829. var allSettings = DataTable.settings;
  830. for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
  831. {
  832. var s = allSettings[i];
  833. /* Base check on table node */
  834. if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
  835. {
  836. var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
  837. var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
  838. if ( emptyInit || bRetrieve )
  839. {
  840. return s.oInstance;
  841. }
  842. else if ( bDestroy )
  843. {
  844. s.oInstance.fnDestroy();
  845. break;
  846. }
  847. else
  848. {
  849. _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
  850. return;
  851. }
  852. }
  853. /* If the element we are initialising has the same ID as a table which was previously
  854. * initialised, but the table nodes don't match (from before) then we destroy the old
  855. * instance by simply deleting it. This is under the assumption that the table has been
  856. * destroyed by other methods. Anyone using non-id selectors will need to do this manually
  857. */
  858. if ( s.sTableId == this.id )
  859. {
  860. allSettings.splice( i, 1 );
  861. break;
  862. }
  863. }
  864. /* Ensure the table has an ID - required for accessibility */
  865. if ( sId === null || sId === "" )
  866. {
  867. sId = "DataTables_Table_"+(DataTable.ext._unique++);
  868. this.id = sId;
  869. }
  870. /* Create the settings object for this table and set some of the default parameters */
  871. var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
  872. "sDestroyWidth": $this[0].style.width,
  873. "sInstance": sId,
  874. "sTableId": sId
  875. } );
  876. oSettings.nTable = this;
  877. oSettings.oApi = _that.internal;
  878. oSettings.oInit = oInit;
  879. allSettings.push( oSettings );
  880. // Need to add the instance after the instance after the settings object has been added
  881. // to the settings array, so we can self reference the table instance if more than one
  882. oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
  883. // Backwards compatibility, before we apply all the defaults
  884. _fnCompatOpts( oInit );
  885. if ( oInit.oLanguage )
  886. {
  887. _fnLanguageCompat( oInit.oLanguage );
  888. }
  889. // If the length menu is given, but the init display length is not, use the length menu
  890. if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
  891. {
  892. oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
  893. oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
  894. }
  895. // Apply the defaults and init options to make a single init object will all
  896. // options defined from defaults and instance options.
  897. oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
  898. // Map the initialisation options onto the settings object
  899. _fnMap( oSettings.oFeatures, oInit, [
  900. "bPaginate",
  901. "bLengthChange",
  902. "bFilter",
  903. "bSort",
  904. "bSortMulti",
  905. "bInfo",
  906. "bProcessing",
  907. "bAutoWidth",
  908. "bSortClasses",
  909. "bServerSide",
  910. "bDeferRender"
  911. ] );
  912. _fnMap( oSettings, oInit, [
  913. "asStripeClasses",
  914. "ajax",
  915. "fnServerData",
  916. "fnFormatNumber",
  917. "sServerMethod",
  918. "aaSorting",
  919. "aaSortingFixed",
  920. "aLengthMenu",
  921. "sPaginationType",
  922. "sAjaxSource",
  923. "sAjaxDataProp",
  924. "iStateDuration",
  925. "sDom",
  926. "bSortCellsTop",
  927. "iTabIndex",
  928. "fnStateLoadCallback",
  929. "fnStateSaveCallback",
  930. "renderer",
  931. "searchDelay",
  932. "rowId",
  933. [ "iCookieDuration", "iStateDuration" ], // backwards compat
  934. [ "oSearch", "oPreviousSearch" ],
  935. [ "aoSearchCols", "aoPreSearchCols" ],
  936. [ "iDisplayLength", "_iDisplayLength" ]
  937. ] );
  938. _fnMap( oSettings.oScroll, oInit, [
  939. [ "sScrollX", "sX" ],
  940. [ "sScrollXInner", "sXInner" ],
  941. [ "sScrollY", "sY" ],
  942. [ "bScrollCollapse", "bCollapse" ]
  943. ] );
  944. _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
  945. /* Callback functions which are array driven */
  946. _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
  947. _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
  948. _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
  949. _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
  950. _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
  951. _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
  952. _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
  953. _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
  954. _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
  955. _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
  956. _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
  957. oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
  958. /* Browser support detection */
  959. _fnBrowserDetect( oSettings );
  960. var oClasses = oSettings.oClasses;
  961. $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
  962. $this.addClass( oClasses.sTable );
  963. if ( oSettings.iInitDisplayStart === undefined )
  964. {
  965. /* Display start point, taking into account the save saving */
  966. oSettings.iInitDisplayStart = oInit.iDisplayStart;
  967. oSettings._iDisplayStart = oInit.iDisplayStart;
  968. }
  969. if ( oInit.iDeferLoading !== null )
  970. {
  971. oSettings.bDeferLoading = true;
  972. var tmp = $.isArray( oInit.iDeferLoading );
  973. oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
  974. oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
  975. }
  976. /* Language definitions */
  977. var oLanguage = oSettings.oLanguage;
  978. $.extend( true, oLanguage, oInit.oLanguage );
  979. if ( oLanguage.sUrl )
  980. {
  981. /* Get the language definitions from a file - because this Ajax call makes the language
  982. * get async to the remainder of this function we use bInitHandedOff to indicate that
  983. * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
  984. */
  985. $.ajax( {
  986. dataType: 'json',
  987. url: oLanguage.sUrl,
  988. success: function ( json ) {
  989. _fnLanguageCompat( json );
  990. _fnCamelToHungarian( defaults.oLanguage, json );
  991. $.extend( true, oLanguage, json );
  992. _fnInitialise( oSettings );
  993. },
  994. error: function () {
  995. // Error occurred loading language file, continue on as best we can
  996. _fnInitialise( oSettings );
  997. }
  998. } );
  999. bInitHandedOff = true;
  1000. }
  1001. /*
  1002. * Stripes
  1003. */
  1004. if ( oInit.asStripeClasses === null )
  1005. {
  1006. oSettings.asStripeClasses =[
  1007. oClasses.sStripeOdd,
  1008. oClasses.sStripeEven
  1009. ];
  1010. }
  1011. /* Remove row stripe classes if they are already on the table row */
  1012. var stripeClasses = oSettings.asStripeClasses;
  1013. var rowOne = $this.children('tbody').find('tr').eq(0);
  1014. if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
  1015. return rowOne.hasClass(el);
  1016. } ) ) !== -1 ) {
  1017. $('tbody tr', this).removeClass( stripeClasses.join(' ') );
  1018. oSettings.asDestroyStripes = stripeClasses.slice();
  1019. }
  1020. /*
  1021. * Columns
  1022. * See if we should load columns automatically or use defined ones
  1023. */
  1024. var anThs = [];
  1025. var aoColumnsInit;
  1026. var nThead = this.getElementsByTagName('thead');
  1027. if ( nThead.length !== 0 )
  1028. {
  1029. _fnDetectHeader( oSettings.aoHeader, nThead[0] );
  1030. anThs = _fnGetUniqueThs( oSettings );
  1031. }
  1032. /* If not given a column array, generate one with nulls */
  1033. if ( oInit.aoColumns === null )
  1034. {
  1035. aoColumnsInit = [];
  1036. for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
  1037. {
  1038. aoColumnsInit.push( null );
  1039. }
  1040. }
  1041. else
  1042. {
  1043. aoColumnsInit = oInit.aoColumns;
  1044. }
  1045. /* Add the columns */
  1046. for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
  1047. {
  1048. _fnAddColumn( oSettings, anThs ? anThs[i] : null );
  1049. }
  1050. /* Apply the column definitions */
  1051. _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
  1052. _fnColumnOptions( oSettings, iCol, oDef );
  1053. } );
  1054. /* HTML5 attribute detection - build an mData object automatically if the
  1055. * attributes are found
  1056. */
  1057. if ( rowOne.length ) {
  1058. var a = function ( cell, name ) {
  1059. return cell.getAttribute( 'data-'+name ) !== null ? name : null;
  1060. };
  1061. $( rowOne[0] ).children('th, td').each( function (i, cell) {
  1062. var col = oSettings.aoColumns[i];
  1063. if ( col.mData === i ) {
  1064. var sort = a( cell, 'sort' ) || a( cell, 'order' );
  1065. var filter = a( cell, 'filter' ) || a( cell, 'search' );
  1066. if ( sort !== null || filter !== null ) {
  1067. col.mData = {
  1068. _: i+'.display',
  1069. sort: sort !== null ? i+'.@data-'+sort : undefined,
  1070. type: sort !== null ? i+'.@data-'+sort : undefined,
  1071. filter: filter !== null ? i+'.@data-'+filter : undefined
  1072. };
  1073. _fnColumnOptions( oSettings, i );
  1074. }
  1075. }
  1076. } );
  1077. }
  1078. var features = oSettings.oFeatures;
  1079. var loadedInit = function () {
  1080. /*
  1081. * Sorting
  1082. * @todo For modularisation (1.11) this needs to do into a sort start up handler
  1083. */
  1084. // If aaSorting is not defined, then we use the first indicator in asSorting
  1085. // in case that has been altered, so the default sort reflects that option
  1086. if ( oInit.aaSorting === undefined ) {
  1087. var sorting = oSettings.aaSorting;
  1088. for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
  1089. sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
  1090. }
  1091. }
  1092. /* Do a first pass on the sorting classes (allows any size changes to be taken into
  1093. * account, and also will apply sorting disabled classes if disabled
  1094. */
  1095. _fnSortingClasses( oSettings );
  1096. if ( features.bSort ) {
  1097. _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
  1098. if ( oSettings.bSorted ) {
  1099. var aSort = _fnSortFlatten( oSettings );
  1100. var sortedColumns = {};
  1101. $.each( aSort, function (i, val) {
  1102. sortedColumns[ val.src ] = val.dir;
  1103. } );
  1104. _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
  1105. _fnSortAria( oSettings );
  1106. }
  1107. } );
  1108. }
  1109. _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
  1110. if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
  1111. _fnSortingClasses( oSettings );
  1112. }
  1113. }, 'sc' );
  1114. /*
  1115. * Final init
  1116. * Cache the header, body and footer as required, creating them if needed
  1117. */
  1118. // Work around for Webkit bug 83867 - store the caption-side before removing from doc
  1119. var captions = $this.children('caption').each( function () {
  1120. this._captionSide = $(this).css('caption-side');
  1121. } );
  1122. var thead = $this.children('thead');
  1123. if ( thead.length === 0 ) {
  1124. thead = $('<thead/>').appendTo($this);
  1125. }
  1126. oSettings.nTHead = thead[0];
  1127. var tbody = $this.children('tbody');
  1128. if ( tbody.length === 0 ) {
  1129. tbody = $('<tbody/>').appendTo($this);
  1130. }
  1131. oSettings.nTBody = tbody[0];
  1132. var tfoot = $this.children('tfoot');
  1133. if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
  1134. // If we are a scrolling table, and no footer has been given, then we need to create
  1135. // a tfoot element for the caption element to be appended to
  1136. tfoot = $('<tfoot/>').appendTo($this);
  1137. }
  1138. if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
  1139. $this.addClass( oClasses.sNoFooter );
  1140. }
  1141. else if ( tfoot.length > 0 ) {
  1142. oSettings.nTFoot = tfoot[0];
  1143. _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
  1144. }
  1145. /* Check if there is data passing into the constructor */
  1146. if ( oInit.aaData ) {
  1147. for ( i=0 ; i<oInit.aaData.length ; i++ ) {
  1148. _fnAddData( oSettings, oInit.aaData[ i ] );
  1149. }
  1150. }
  1151. else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
  1152. /* Grab the data from the page - only do this when deferred loading or no Ajax
  1153. * source since there is no point in reading the DOM data if we are then going
  1154. * to replace it with Ajax data
  1155. */
  1156. _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
  1157. }
  1158. /* Copy the data index array */
  1159. oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
  1160. /* Initialisation complete - table can be drawn */
  1161. oSettings.bInitialised = true;
  1162. /* Check if we need to initialise the table (it might not have been handed off to the
  1163. * language processor)
  1164. */
  1165. if ( bInitHandedOff === false ) {
  1166. _fnInitialise( oSettings );
  1167. }
  1168. };
  1169. /* Must be done after everything which can be overridden by the state saving! */
  1170. if ( oInit.bStateSave )
  1171. {
  1172. features.bStateSave = true;
  1173. _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
  1174. _fnLoadState( oSettings, oInit, loadedInit );
  1175. }
  1176. else {
  1177. loadedInit();
  1178. }
  1179. } );
  1180. _that = null;
  1181. return this;
  1182. };
  1183. /*
  1184. * It is useful to have variables which are scoped locally so only the
  1185. * DataTables functions can access them and they don't leak into global space.
  1186. * At the same time these functions are often useful over multiple files in the
  1187. * core and API, so we list, or at least document, all variables which are used
  1188. * by DataTables as private variables here. This also ensures that there is no
  1189. * clashing of variable names and that they can easily referenced for reuse.
  1190. */
  1191. // Defined else where
  1192. // _selector_run
  1193. // _selector_opts
  1194. // _selector_first
  1195. // _selector_row_indexes
  1196. var _ext; // DataTable.ext
  1197. var _Api; // DataTable.Api
  1198. var _api_register; // DataTable.Api.register
  1199. var _api_registerPlural; // DataTable.Api.registerPlural
  1200. var _re_dic = {};
  1201. var _re_new_lines = /[\r\n]/g;
  1202. var _re_html = /<.*?>/g;
  1203. // This is not strict ISO8601 - Date.parse() is quite lax, although
  1204. // implementations differ between browsers.
  1205. var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
  1206. // Escape regular expression special characters
  1207. var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
  1208. // http://en.wikipedia.org/wiki/Foreign_exchange_market
  1209. // - \u20BD - Russian ruble.
  1210. // - \u20a9 - South Korean Won
  1211. // - \u20BA - Turkish Lira
  1212. // - \u20B9 - Indian Rupee
  1213. // - R - Brazil (R$) and South Africa
  1214. // - fr - Swiss Franc
  1215. // - kr - Swedish krona, Norwegian krone and Danish krone
  1216. // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
  1217. // standards as thousands separators.
  1218. var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
  1219. var _empty = function ( d ) {
  1220. return !d || d === true || d === '-' ? true : false;
  1221. };
  1222. var _intVal = function ( s ) {
  1223. var integer = parseInt( s, 10 );
  1224. return !isNaN(integer) && isFinite(s) ? integer : null;
  1225. };
  1226. // Convert from a formatted number with characters other than `.` as the
  1227. // decimal place, to a Javascript number
  1228. var _numToDecimal = function ( num, decimalPoint ) {
  1229. // Cache created regular expressions for speed as this function is called often
  1230. if ( ! _re_dic[ decimalPoint ] ) {
  1231. _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
  1232. }
  1233. return typeof num === 'string' && decimalPoint !== '.' ?
  1234. num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
  1235. num;
  1236. };
  1237. var _isNumber = function ( d, decimalPoint, formatted ) {
  1238. var strType = typeof d === 'string';
  1239. // If empty return immediately so there must be a number if it is a
  1240. // formatted string (this stops the string "k", or "kr", etc being detected
  1241. // as a formatted number for currency
  1242. if ( _empty( d ) ) {
  1243. return true;
  1244. }
  1245. if ( decimalPoint && strType ) {
  1246. d = _numToDecimal( d, decimalPoint );
  1247. }
  1248. if ( formatted && strType ) {
  1249. d = d.replace( _re_formatted_numeric, '' );
  1250. }
  1251. return !isNaN( parseFloat(d) ) && isFinite( d );
  1252. };
  1253. // A string without HTML in it can be considered to be HTML still
  1254. var _isHtml = function ( d ) {
  1255. return _empty( d ) || typeof d === 'string';
  1256. };
  1257. var _htmlNumeric = function ( d, decimalPoint, formatted ) {
  1258. if ( _empty( d ) ) {
  1259. return true;
  1260. }
  1261. var html = _isHtml( d );
  1262. return ! html ?
  1263. null :
  1264. _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
  1265. true :
  1266. null;
  1267. };
  1268. var _pluck = function ( a, prop, prop2 ) {
  1269. var out = [];
  1270. var i=0, ien=a.length;
  1271. // Could have the test in the loop for slightly smaller code, but speed
  1272. // is essential here
  1273. if ( prop2 !== undefined ) {
  1274. for ( ; i<ien ; i++ ) {
  1275. if ( a[i] && a[i][ prop ] ) {
  1276. out.push( a[i][ prop ][ prop2 ] );
  1277. }
  1278. }
  1279. }
  1280. else {
  1281. for ( ; i<ien ; i++ ) {
  1282. if ( a[i] ) {
  1283. out.push( a[i][ prop ] );
  1284. }
  1285. }
  1286. }
  1287. return out;
  1288. };
  1289. // Basically the same as _pluck, but rather than looping over `a` we use `order`
  1290. // as the indexes to pick from `a`
  1291. var _pluck_order = function ( a, order, prop, prop2 )
  1292. {
  1293. var out = [];
  1294. var i=0, ien=order.length;
  1295. // Could have the test in the loop for slightly smaller code, but speed
  1296. // is essential here
  1297. if ( prop2 !== undefined ) {
  1298. for ( ; i<ien ; i++ ) {
  1299. if ( a[ order[i] ][ prop ] ) {
  1300. out.push( a[ order[i] ][ prop ][ prop2 ] );
  1301. }
  1302. }
  1303. }
  1304. else {
  1305. for ( ; i<ien ; i++ ) {
  1306. out.push( a[ order[i] ][ prop ] );
  1307. }
  1308. }
  1309. return out;
  1310. };
  1311. var _range = function ( len, start )
  1312. {
  1313. var out = [];
  1314. var end;
  1315. if ( start === undefined ) {
  1316. start = 0;
  1317. end = len;
  1318. }
  1319. else {
  1320. end = start;
  1321. start = len;
  1322. }
  1323. for ( var i=start ; i<end ; i++ ) {
  1324. out.push( i );
  1325. }
  1326. return out;
  1327. };
  1328. var _removeEmpty = function ( a )
  1329. {
  1330. var out = [];
  1331. for ( var i=0, ien=a.length ; i<ien ; i++ ) {
  1332. if ( a[i] ) { // careful - will remove all falsy values!
  1333. out.push( a[i] );
  1334. }
  1335. }
  1336. return out;
  1337. };
  1338. var _stripHtml = function ( d ) {
  1339. return d.replace( _re_html, '' );
  1340. };
  1341. /**
  1342. * Determine if all values in the array are unique. This means we can short
  1343. * cut the _unique method at the cost of a single loop. A sorted array is used
  1344. * to easily check the values.
  1345. *
  1346. * @param {array} src Source array
  1347. * @return {boolean} true if all unique, false otherwise
  1348. * @ignore
  1349. */
  1350. var _areAllUnique = function ( src ) {
  1351. if ( src.length < 2 ) {
  1352. return true;
  1353. }
  1354. var sorted = src.slice().sort();
  1355. var last = sorted[0];
  1356. for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
  1357. if ( sorted[i] === last ) {
  1358. return false;
  1359. }
  1360. last = sorted[i];
  1361. }
  1362. return true;
  1363. };
  1364. /**
  1365. * Find the unique elements in a source array.
  1366. *
  1367. * @param {array} src Source array
  1368. * @return {array} Array of unique items
  1369. * @ignore
  1370. */
  1371. var _unique = function ( src )
  1372. {
  1373. if ( _areAllUnique( src ) ) {
  1374. return src.slice();
  1375. }
  1376. // A faster unique method is to use object keys to identify used values,
  1377. // but this doesn't work with arrays or objects, which we must also
  1378. // consider. See jsperf.com/compare-array-unique-versions/4 for more
  1379. // information.
  1380. var
  1381. out = [],
  1382. val,
  1383. i, ien=src.length,
  1384. j, k=0;
  1385. again: for ( i=0 ; i<ien ; i++ ) {
  1386. val = src[i];
  1387. for ( j=0 ; j<k ; j++ ) {
  1388. if ( out[j] === val ) {
  1389. continue again;
  1390. }
  1391. }
  1392. out.push( val );
  1393. k++;
  1394. }
  1395. return out;
  1396. };
  1397. /**
  1398. * DataTables utility methods
  1399. *
  1400. * This namespace provides helper methods that DataTables uses internally to
  1401. * create a DataTable, but which are not exclusively used only for DataTables.
  1402. * These methods can be used by extension authors to save the duplication of
  1403. * code.
  1404. *
  1405. * @namespace
  1406. */
  1407. DataTable.util = {
  1408. /**
  1409. * Throttle the calls to a function. Arguments and context are maintained
  1410. * for the throttled function.
  1411. *
  1412. * @param {function} fn Function to be called
  1413. * @param {integer} freq Call frequency in mS
  1414. * @return {function} Wrapped function
  1415. */
  1416. throttle: function ( fn, freq ) {
  1417. var
  1418. frequency = freq !== undefined ? freq : 200,
  1419. last,
  1420. timer;
  1421. return function () {
  1422. var
  1423. that = this,
  1424. now = +new Date(),
  1425. args = arguments;
  1426. if ( last && now < last + frequency ) {
  1427. clearTimeout( timer );
  1428. timer = setTimeout( function () {
  1429. last = undefined;
  1430. fn.apply( that, args );
  1431. }, frequency );
  1432. }
  1433. else {
  1434. last = now;
  1435. fn.apply( that, args );
  1436. }
  1437. };
  1438. },
  1439. /**
  1440. * Escape a string such that it can be used in a regular expression
  1441. *
  1442. * @param {string} val string to escape
  1443. * @returns {string} escaped string
  1444. */
  1445. escapeRegex: function ( val ) {
  1446. return val.replace( _re_escape_regex, '\\$1' );
  1447. }
  1448. };
  1449. /**
  1450. * Create a mapping object that allows camel case parameters to be looked up
  1451. * for their Hungarian counterparts. The mapping is stored in a private
  1452. * parameter called `_hungarianMap` which can be accessed on the source object.
  1453. * @param {object} o
  1454. * @memberof DataTable#oApi
  1455. */
  1456. function _fnHungarianMap ( o )
  1457. {
  1458. var
  1459. hungarian = 'a aa ai ao as b fn i m o s ',
  1460. match,
  1461. newKey,
  1462. map = {};
  1463. $.each( o, function (key, val) {
  1464. match = key.match(/^([^A-Z]+?)([A-Z])/);
  1465. if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
  1466. {
  1467. newKey = key.replace( match[0], match[2].toLowerCase() );
  1468. map[ newKey ] = key;
  1469. if ( match[1] === 'o' )
  1470. {
  1471. _fnHungarianMap( o[key] );
  1472. }
  1473. }
  1474. } );
  1475. o._hungarianMap = map;
  1476. }
  1477. /**
  1478. * Convert from camel case parameters to Hungarian, based on a Hungarian map
  1479. * created by _fnHungarianMap.
  1480. * @param {object} src The model object which holds all parameters that can be
  1481. * mapped.
  1482. * @param {object} user The object to convert from camel case to Hungarian.
  1483. * @param {boolean} force When set to `true`, properties which already have a
  1484. * Hungarian value in the `user` object will be overwritten. Otherwise they
  1485. * won't be.
  1486. * @memberof DataTable#oApi
  1487. */
  1488. function _fnCamelToHungarian ( src, user, force )
  1489. {
  1490. if ( ! src._hungarianMap ) {
  1491. _fnHungarianMap( src );
  1492. }
  1493. var hungarianKey;
  1494. $.each( user, function (key, val) {
  1495. hungarianKey = src._hungarianMap[ key ];
  1496. if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
  1497. {
  1498. // For objects, we need to buzz down into the object to copy parameters
  1499. if ( hungarianKey.charAt(0) === 'o' )
  1500. {
  1501. // Copy the camelCase options over to the hungarian
  1502. if ( ! user[ hungarianKey ] ) {
  1503. user[ hungarianKey ] = {};
  1504. }
  1505. $.extend( true, user[hungarianKey], user[key] );
  1506. _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
  1507. }
  1508. else {
  1509. user[hungarianKey] = user[ key ];
  1510. }
  1511. }
  1512. } );
  1513. }
  1514. /**
  1515. * Language compatibility - when certain options are given, and others aren't, we
  1516. * need to duplicate the values over, in order to provide backwards compatibility
  1517. * with older language files.
  1518. * @param {object} oSettings dataTables settings object
  1519. * @memberof DataTable#oApi
  1520. */
  1521. function _fnLanguageCompat( lang )
  1522. {
  1523. var defaults = DataTable.defaults.oLanguage;
  1524. var zeroRecords = lang.sZeroRecords;
  1525. /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
  1526. * sZeroRecords - assuming that is given.
  1527. */
  1528. if ( ! lang.sEmptyTable && zeroRecords &&
  1529. defaults.sEmptyTable === "No data available in table" )
  1530. {
  1531. _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
  1532. }
  1533. /* Likewise with loading records */
  1534. if ( ! lang.sLoadingRecords && zeroRecords &&
  1535. defaults.sLoadingRecords === "Loading..." )
  1536. {
  1537. _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
  1538. }
  1539. // Old parameter name of the thousands separator mapped onto the new
  1540. if ( lang.sInfoThousands ) {
  1541. lang.sThousands = lang.sInfoThousands;
  1542. }
  1543. var decimal = lang.sDecimal;
  1544. if ( decimal ) {
  1545. _addNumericSort( decimal );
  1546. }
  1547. }
  1548. /**
  1549. * Map one parameter onto another
  1550. * @param {object} o Object to map
  1551. * @param {*} knew The new parameter name
  1552. * @param {*} old The old parameter name
  1553. */
  1554. var _fnCompatMap = function ( o, knew, old ) {
  1555. if ( o[ knew ] !== undefined ) {
  1556. o[ old ] = o[ knew ];
  1557. }
  1558. };
  1559. /**
  1560. * Provide backwards compatibility for the main DT options. Note that the new
  1561. * options are mapped onto the old parameters, so this is an external interface
  1562. * change only.
  1563. * @param {object} init Object to map
  1564. */
  1565. function _fnCompatOpts ( init )
  1566. {
  1567. _fnCompatMap( init, 'ordering', 'bSort' );
  1568. _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
  1569. _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
  1570. _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
  1571. _fnCompatMap( init, 'order', 'aaSorting' );
  1572. _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
  1573. _fnCompatMap( init, 'paging', 'bPaginate' );
  1574. _fnCompatMap( init, 'pagingType', 'sPaginationType' );
  1575. _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
  1576. _fnCompatMap( init, 'searching', 'bFilter' );
  1577. // Boolean initialisation of x-scrolling
  1578. if ( typeof init.sScrollX === 'boolean' ) {
  1579. init.sScrollX = init.sScrollX ? '100%' : '';
  1580. }
  1581. if ( typeof init.scrollX === 'boolean' ) {
  1582. init.scrollX = init.scrollX ? '100%' : '';
  1583. }
  1584. // Column search objects are in an array, so it needs to be converted
  1585. // element by element
  1586. var searchCols = init.aoSearchCols;
  1587. if ( searchCols ) {
  1588. for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
  1589. if ( searchCols[i] ) {
  1590. _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
  1591. }
  1592. }
  1593. }
  1594. }
  1595. /**
  1596. * Provide backwards compatibility for column options. Note that the new options
  1597. * are mapped onto the old parameters, so this is an external interface change
  1598. * only.
  1599. * @param {object} init Object to map
  1600. */
  1601. function _fnCompatCols ( init )
  1602. {
  1603. _fnCompatMap( init, 'orderable', 'bSortable' );
  1604. _fnCompatMap( init, 'orderData', 'aDataSort' );
  1605. _fnCompatMap( init, 'orderSequence', 'asSorting' );
  1606. _fnCompatMap( init, 'orderDataType', 'sortDataType' );
  1607. // orderData can be given as an integer
  1608. var dataSort = init.aDataSort;
  1609. if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
  1610. init.aDataSort = [ dataSort ];
  1611. }
  1612. }
  1613. /**
  1614. * Browser feature detection for capabilities, quirks
  1615. * @param {object} settings dataTables settings object
  1616. * @memberof DataTable#oApi
  1617. */
  1618. function _fnBrowserDetect( settings )
  1619. {
  1620. // We don't need to do this every time DataTables is constructed, the values
  1621. // calculated are specific to the browser and OS configuration which we
  1622. // don't expect to change between initialisations
  1623. if ( ! DataTable.__browser ) {
  1624. var browser = {};
  1625. DataTable.__browser = browser;
  1626. // Scrolling feature / quirks detection
  1627. var n = $('<div/>')
  1628. .css( {
  1629. position: 'fixed',
  1630. top: 0,
  1631. left: $(window).scrollLeft()*-1, // allow for scrolling
  1632. height: 1,
  1633. width: 1,
  1634. overflow: 'hidden'
  1635. } )
  1636. .append(
  1637. $('<div/>')
  1638. .css( {
  1639. position: 'absolute',
  1640. top: 1,
  1641. left: 1,
  1642. width: 100,
  1643. overflow: 'scroll'
  1644. } )
  1645. .append(
  1646. $('<div/>')
  1647. .css( {
  1648. width: '100%',
  1649. height: 10
  1650. } )
  1651. )
  1652. )
  1653. .appendTo( 'body' );
  1654. var outer = n.children();
  1655. var inner = outer.children();
  1656. // Numbers below, in order, are:
  1657. // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
  1658. //
  1659. // IE6 XP: 100 100 100 83
  1660. // IE7 Vista: 100 100 100 83
  1661. // IE 8+ Windows: 83 83 100 83
  1662. // Evergreen Windows: 83 83 100 83
  1663. // Evergreen Mac with scrollbars: 85 85 100 85
  1664. // Evergreen Mac without scrollbars: 100 100 100 100
  1665. // Get scrollbar width
  1666. browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
  1667. // IE6/7 will oversize a width 100% element inside a scrolling element, to
  1668. // include the width of the scrollbar, while other browsers ensure the inner
  1669. // element is contained without forcing scrolling
  1670. browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
  1671. // In rtl text layout, some browsers (most, but not all) will place the
  1672. // scrollbar on the left, rather than the right.
  1673. browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
  1674. // IE8- don't provide height and width for getBoundingClientRect
  1675. browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
  1676. n.remove();
  1677. }
  1678. $.extend( settings.oBrowser, DataTable.__browser );
  1679. settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
  1680. }
  1681. /**
  1682. * Array.prototype reduce[Right] method, used for browsers which don't support
  1683. * JS 1.6. Done this way to reduce code size, since we iterate either way
  1684. * @param {object} settings dataTables settings object
  1685. * @memberof DataTable#oApi
  1686. */
  1687. function _fnReduce ( that, fn, init, start, end, inc )
  1688. {
  1689. var
  1690. i = start,
  1691. value,
  1692. isSet = false;
  1693. if ( init !== undefined ) {
  1694. value = init;
  1695. isSet = true;
  1696. }
  1697. while ( i !== end ) {
  1698. if ( ! that.hasOwnProperty(i) ) {
  1699. continue;
  1700. }
  1701. value = isSet ?
  1702. fn( value, that[i], i, that ) :
  1703. that[i];
  1704. isSet = true;
  1705. i += inc;
  1706. }
  1707. return value;
  1708. }
  1709. /**
  1710. * Add a column to the list used for the table with default values
  1711. * @param {object} oSettings dataTables settings object
  1712. * @param {node} nTh The th element for this column
  1713. * @memberof DataTable#oApi
  1714. */
  1715. function _fnAddColumn( oSettings, nTh )
  1716. {
  1717. // Add column to aoColumns array
  1718. var oDefaults = DataTable.defaults.column;
  1719. var iCol = oSettings.aoColumns.length;
  1720. var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
  1721. "nTh": nTh ? nTh : document.createElement('th'),
  1722. "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
  1723. "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
  1724. "mData": oDefaults.mData ? oDefaults.mData : iCol,
  1725. idx: iCol
  1726. } );
  1727. oSettings.aoColumns.push( oCol );
  1728. // Add search object for column specific search. Note that the `searchCols[ iCol ]`
  1729. // passed into extend can be undefined. This allows the user to give a default
  1730. // with only some of the parameters defined, and also not give a default
  1731. var searchCols = oSettings.aoPreSearchCols;
  1732. searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
  1733. // Use the default column options function to initialise classes etc
  1734. _fnColumnOptions( oSettings, iCol, $(nTh).data() );
  1735. }
  1736. /**
  1737. * Apply options for a column
  1738. * @param {object} oSettings dataTables settings object
  1739. * @param {int} iCol column index to consider
  1740. * @param {object} oOptions object with sType, bVisible and bSearchable etc
  1741. * @memberof DataTable#oApi
  1742. */
  1743. function _fnColumnOptions( oSettings, iCol, oOptions )
  1744. {
  1745. var oCol = oSettings.aoColumns[ iCol ];
  1746. var oClasses = oSettings.oClasses;
  1747. var th = $(oCol.nTh);
  1748. // Try to get width information from the DOM. We can't get it from CSS
  1749. // as we'd need to parse the CSS stylesheet. `width` option can override
  1750. if ( ! oCol.sWidthOrig ) {
  1751. // Width attribute
  1752. oCol.sWidthOrig = th.attr('width') || null;
  1753. // Style attribute
  1754. var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
  1755. if ( t ) {
  1756. oCol.sWidthOrig = t[1];
  1757. }
  1758. }
  1759. /* User specified column options */
  1760. if ( oOptions !== undefined && oOptions !== null )
  1761. {
  1762. // Backwards compatibility
  1763. _fnCompatCols( oOptions );
  1764. // Map camel case parameters to their Hungarian counterparts
  1765. _fnCamelToHungarian( DataTable.defaults.column, oOptions );
  1766. /* Backwards compatibility for mDataProp */
  1767. if ( oOptions.mDataProp !== undefined && !oOptions.mData )
  1768. {
  1769. oOptions.mData = oOptions.mDataProp;
  1770. }
  1771. if ( oOptions.sType )
  1772. {
  1773. oCol._sManualType = oOptions.sType;
  1774. }
  1775. // `class` is a reserved word in Javascript, so we need to provide
  1776. // the ability to use a valid name for the camel case input
  1777. if ( oOptions.className && ! oOptions.sClass )
  1778. {
  1779. oOptions.sClass = oOptions.className;
  1780. }
  1781. if ( oOptions.sClass ) {
  1782. th.addClass( oOptions.sClass );
  1783. }
  1784. $.extend( oCol, oOptions );
  1785. _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
  1786. /* iDataSort to be applied (backwards compatibility), but aDataSort will take
  1787. * priority if defined
  1788. */
  1789. if ( oOptions.iDataSort !== undefined )
  1790. {
  1791. oCol.aDataSort = [ oOptions.iDataSort ];
  1792. }
  1793. _fnMap( oCol, oOptions, "aDataSort" );
  1794. }
  1795. /* Cache the data get and set functions for speed */
  1796. var mDataSrc = oCol.mData;
  1797. var mData = _fnGetObjectDataFn( mDataSrc );
  1798. var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
  1799. var attrTest = function( src ) {
  1800. return typeof src === 'string' && src.indexOf('@') !== -1;
  1801. };
  1802. oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
  1803. attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
  1804. );
  1805. oCol._setter = null;
  1806. oCol.fnGetData = function (rowData, type, meta) {
  1807. var innerData = mData( rowData, type, undefined, meta );
  1808. return mRender && type ?
  1809. mRender( innerData, type, rowData, meta ) :
  1810. innerData;
  1811. };
  1812. oCol.fnSetData = function ( rowData, val, meta ) {
  1813. return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
  1814. };
  1815. // Indicate if DataTables should read DOM data as an object or array
  1816. // Used in _fnGetRowElements
  1817. if ( typeof mDataSrc !== 'number' ) {
  1818. oSettings._rowReadObject = true;
  1819. }
  1820. /* Feature sorting overrides column specific when off */
  1821. if ( !oSettings.oFeatures.bSort )
  1822. {
  1823. oCol.bSortable = false;
  1824. th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
  1825. }
  1826. /* Check that the class assignment is correct for sorting */
  1827. var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
  1828. var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
  1829. if ( !oCol.bSortable || (!bAsc && !bDesc) )
  1830. {
  1831. oCol.sSortingClass = oClasses.sSortableNone;
  1832. oCol.sSortingClassJUI = "";
  1833. }
  1834. else if ( bAsc && !bDesc )
  1835. {
  1836. oCol.sSortingClass = oClasses.sSortableAsc;
  1837. oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
  1838. }
  1839. else if ( !bAsc && bDesc )
  1840. {
  1841. oCol.sSortingClass = oClasses.sSortableDesc;
  1842. oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
  1843. }
  1844. else
  1845. {
  1846. oCol.sSortingClass = oClasses.sSortable;
  1847. oCol.sSortingClassJUI = oClasses.sSortJUI;
  1848. }
  1849. }
  1850. /**
  1851. * Adjust the table column widths for new data. Note: you would probably want to
  1852. * do a redraw after calling this function!
  1853. * @param {object} settings dataTables settings object
  1854. * @memberof DataTable#oApi
  1855. */
  1856. function _fnAdjustColumnSizing ( settings )
  1857. {
  1858. /* Not interested in doing column width calculation if auto-width is disabled */
  1859. if ( settings.oFeatures.bAutoWidth !== false )
  1860. {
  1861. var columns = settings.aoColumns;
  1862. _fnCalculateColumnWidths( settings );
  1863. for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
  1864. {
  1865. columns[i].nTh.style.width = columns[i].sWidth;
  1866. }
  1867. }
  1868. var scroll = settings.oScroll;
  1869. if ( scroll.sY !== '' || scroll.sX !== '')
  1870. {
  1871. _fnScrollDraw( settings );
  1872. }
  1873. _fnCallbackFire( settings, null, 'column-sizing', [settings] );
  1874. }
  1875. /**
  1876. * Covert the index of a visible column to the index in the data array (take account
  1877. * of hidden columns)
  1878. * @param {object} oSettings dataTables settings object
  1879. * @param {int} iMatch Visible column index to lookup
  1880. * @returns {int} i the data index
  1881. * @memberof DataTable#oApi
  1882. */
  1883. function _fnVisibleToColumnIndex( oSettings, iMatch )
  1884. {
  1885. var aiVis = _fnGetColumns( oSettings, 'bVisible' );
  1886. return typeof aiVis[iMatch] === 'number' ?
  1887. aiVis[iMatch] :
  1888. null;
  1889. }
  1890. /**
  1891. * Covert the index of an index in the data array and convert it to the visible
  1892. * column index (take account of hidden columns)
  1893. * @param {int} iMatch Column index to lookup
  1894. * @param {object} oSettings dataTables settings object
  1895. * @returns {int} i the data index
  1896. * @memberof DataTable#oApi
  1897. */
  1898. function _fnColumnIndexToVisible( oSettings, iMatch )
  1899. {
  1900. var aiVis = _fnGetColumns( oSettings, 'bVisible' );
  1901. var iPos = $.inArray( iMatch, aiVis );
  1902. return iPos !== -1 ? iPos : null;
  1903. }
  1904. /**
  1905. * Get the number of visible columns
  1906. * @param {object} oSettings dataTables settings object
  1907. * @returns {int} i the number of visible columns
  1908. * @memberof DataTable#oApi
  1909. */
  1910. function _fnVisbleColumns( oSettings )
  1911. {
  1912. var vis = 0;
  1913. // No reduce in IE8, use a loop for now
  1914. $.each( oSettings.aoColumns, function ( i, col ) {
  1915. if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
  1916. vis++;
  1917. }
  1918. } );
  1919. return vis;
  1920. }
  1921. /**
  1922. * Get an array of column indexes that match a given property
  1923. * @param {object} oSettings dataTables settings object
  1924. * @param {string} sParam Parameter in aoColumns to look for - typically
  1925. * bVisible or bSearchable
  1926. * @returns {array} Array of indexes with matched properties
  1927. * @memberof DataTable#oApi
  1928. */
  1929. function _fnGetColumns( oSettings, sParam )
  1930. {
  1931. var a = [];
  1932. $.map( oSettings.aoColumns, function(val, i) {
  1933. if ( val[sParam] ) {
  1934. a.push( i );
  1935. }
  1936. } );
  1937. return a;
  1938. }
  1939. /**
  1940. * Calculate the 'type' of a column
  1941. * @param {object} settings dataTables settings object
  1942. * @memberof DataTable#oApi
  1943. */
  1944. function _fnColumnTypes ( settings )
  1945. {
  1946. var columns = settings.aoColumns;
  1947. var data = settings.aoData;
  1948. var types = DataTable.ext.type.detect;
  1949. var i, ien, j, jen, k, ken;
  1950. var col, cell, detectedType, cache;
  1951. // For each column, spin over the
  1952. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  1953. col = columns[i];
  1954. cache = [];
  1955. if ( ! col.sType && col._sManualType ) {
  1956. col.sType = col._sManualType;
  1957. }
  1958. else if ( ! col.sType ) {
  1959. for ( j=0, jen=types.length ; j<jen ; j++ ) {
  1960. for ( k=0, ken=data.length ; k<ken ; k++ ) {
  1961. // Use a cache array so we only need to get the type data
  1962. // from the formatter once (when using multiple detectors)
  1963. if ( cache[k] === undefined ) {
  1964. cache[k] = _fnGetCellData( settings, k, i, 'type' );
  1965. }
  1966. detectedType = types[j]( cache[k], settings );
  1967. // If null, then this type can't apply to this column, so
  1968. // rather than testing all cells, break out. There is an
  1969. // exception for the last type which is `html`. We need to
  1970. // scan all rows since it is possible to mix string and HTML
  1971. // types
  1972. if ( ! detectedType && j !== types.length-1 ) {
  1973. break;
  1974. }
  1975. // Only a single match is needed for html type since it is
  1976. // bottom of the pile and very similar to string
  1977. if ( detectedType === 'html' ) {
  1978. break;
  1979. }
  1980. }
  1981. // Type is valid for all data points in the column - use this
  1982. // type
  1983. if ( detectedType ) {
  1984. col.sType = detectedType;
  1985. break;
  1986. }
  1987. }
  1988. // Fall back - if no type was detected, always use string
  1989. if ( ! col.sType ) {
  1990. col.sType = 'string';
  1991. }
  1992. }
  1993. }
  1994. }
  1995. /**
  1996. * Take the column definitions and static columns arrays and calculate how
  1997. * they relate to column indexes. The callback function will then apply the
  1998. * definition found for a column to a suitable configuration object.
  1999. * @param {object} oSettings dataTables settings object
  2000. * @param {array} aoColDefs The aoColumnDefs array that is to be applied
  2001. * @param {array} aoCols The aoColumns array that defines columns individually
  2002. * @param {function} fn Callback function - takes two parameters, the calculated
  2003. * column index and the definition for that column.
  2004. * @memberof DataTable#oApi
  2005. */
  2006. function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
  2007. {
  2008. var i, iLen, j, jLen, k, kLen, def;
  2009. var columns = oSettings.aoColumns;
  2010. // Column definitions with aTargets
  2011. if ( aoColDefs )
  2012. {
  2013. /* Loop over the definitions array - loop in reverse so first instance has priority */
  2014. for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
  2015. {
  2016. def = aoColDefs[i];
  2017. /* Each definition can target multiple columns, as it is an array */
  2018. var aTargets = def.targets !== undefined ?
  2019. def.targets :
  2020. def.aTargets;
  2021. if ( ! $.isArray( aTargets ) )
  2022. {
  2023. aTargets = [ aTargets ];
  2024. }
  2025. for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
  2026. {
  2027. if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
  2028. {
  2029. /* Add columns that we don't yet know about */
  2030. while( columns.length <= aTargets[j] )
  2031. {
  2032. _fnAddColumn( oSettings );
  2033. }
  2034. /* Integer, basic index */
  2035. fn( aTargets[j], def );
  2036. }
  2037. else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
  2038. {
  2039. /* Negative integer, right to left column counting */
  2040. fn( columns.length+aTargets[j], def );
  2041. }
  2042. else if ( typeof aTargets[j] === 'string' )
  2043. {
  2044. /* Class name matching on TH element */
  2045. for ( k=0, kLen=columns.length ; k<kLen ; k++ )
  2046. {
  2047. if ( aTargets[j] == "_all" ||
  2048. $(columns[k].nTh).hasClass( aTargets[j] ) )
  2049. {
  2050. fn( k, def );
  2051. }
  2052. }
  2053. }
  2054. }
  2055. }
  2056. }
  2057. // Statically defined columns array
  2058. if ( aoCols )
  2059. {
  2060. for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
  2061. {
  2062. fn( i, aoCols[i] );
  2063. }
  2064. }
  2065. }
  2066. /**
  2067. * Add a data array to the table, creating DOM node etc. This is the parallel to
  2068. * _fnGatherData, but for adding rows from a Javascript source, rather than a
  2069. * DOM source.
  2070. * @param {object} oSettings dataTables settings object
  2071. * @param {array} aData data array to be added
  2072. * @param {node} [nTr] TR element to add to the table - optional. If not given,
  2073. * DataTables will create a row automatically
  2074. * @param {array} [anTds] Array of TD|TH elements for the row - must be given
  2075. * if nTr is.
  2076. * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
  2077. * @memberof DataTable#oApi
  2078. */
  2079. function _fnAddData ( oSettings, aDataIn, nTr, anTds )
  2080. {
  2081. /* Create the object for storing information about this new row */
  2082. var iRow = oSettings.aoData.length;
  2083. var oData = $.extend( true, {}, DataTable.models.oRow, {
  2084. src: nTr ? 'dom' : 'data',
  2085. idx: iRow
  2086. } );
  2087. oData._aData = aDataIn;
  2088. oSettings.aoData.push( oData );
  2089. /* Create the cells */
  2090. var nTd, sThisType;
  2091. var columns = oSettings.aoColumns;
  2092. // Invalidate the column types as the new data needs to be revalidated
  2093. for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
  2094. {
  2095. columns[i].sType = null;
  2096. }
  2097. /* Add to the display array */
  2098. oSettings.aiDisplayMaster.push( iRow );
  2099. var id = oSettings.rowIdFn( aDataIn );
  2100. if ( id !== undefined ) {
  2101. oSettings.aIds[ id ] = oData;
  2102. }
  2103. /* Create the DOM information, or register it if already present */
  2104. if ( nTr || ! oSettings.oFeatures.bDeferRender )
  2105. {
  2106. _fnCreateTr( oSettings, iRow, nTr, anTds );
  2107. }
  2108. return iRow;
  2109. }
  2110. /**
  2111. * Add one or more TR elements to the table. Generally we'd expect to
  2112. * use this for reading data from a DOM sourced table, but it could be
  2113. * used for an TR element. Note that if a TR is given, it is used (i.e.
  2114. * it is not cloned).
  2115. * @param {object} settings dataTables settings object
  2116. * @param {array|node|jQuery} trs The TR element(s) to add to the table
  2117. * @returns {array} Array of indexes for the added rows
  2118. * @memberof DataTable#oApi
  2119. */
  2120. function _fnAddTr( settings, trs )
  2121. {
  2122. var row;
  2123. // Allow an individual node to be passed in
  2124. if ( ! (trs instanceof $) ) {
  2125. trs = $(trs);
  2126. }
  2127. return trs.map( function (i, el) {
  2128. row = _fnGetRowElements( settings, el );
  2129. return _fnAddData( settings, row.data, el, row.cells );
  2130. } );
  2131. }
  2132. /**
  2133. * Take a TR element and convert it to an index in aoData
  2134. * @param {object} oSettings dataTables settings object
  2135. * @param {node} n the TR element to find
  2136. * @returns {int} index if the node is found, null if not
  2137. * @memberof DataTable#oApi
  2138. */
  2139. function _fnNodeToDataIndex( oSettings, n )
  2140. {
  2141. return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
  2142. }
  2143. /**
  2144. * Take a TD element and convert it into a column data index (not the visible index)
  2145. * @param {object} oSettings dataTables settings object
  2146. * @param {int} iRow The row number the TD/TH can be found in
  2147. * @param {node} n The TD/TH element to find
  2148. * @returns {int} index if the node is found, -1 if not
  2149. * @memberof DataTable#oApi
  2150. */
  2151. function _fnNodeToColumnIndex( oSettings, iRow, n )
  2152. {
  2153. return $.inArray( n, oSettings.aoData[ iRow ].anCells );
  2154. }
  2155. /**
  2156. * Get the data for a given cell from the internal cache, taking into account data mapping
  2157. * @param {object} settings dataTables settings object
  2158. * @param {int} rowIdx aoData row id
  2159. * @param {int} colIdx Column index
  2160. * @param {string} type data get type ('display', 'type' 'filter' 'sort')
  2161. * @returns {*} Cell data
  2162. * @memberof DataTable#oApi
  2163. */
  2164. function _fnGetCellData( settings, rowIdx, colIdx, type )
  2165. {
  2166. var draw = settings.iDraw;
  2167. var col = settings.aoColumns[colIdx];
  2168. var rowData = settings.aoData[rowIdx]._aData;
  2169. var defaultContent = col.sDefaultContent;
  2170. var cellData = col.fnGetData( rowData, type, {
  2171. settings: settings,
  2172. row: rowIdx,
  2173. col: colIdx
  2174. } );
  2175. if ( cellData === undefined ) {
  2176. if ( settings.iDrawError != draw && defaultContent === null ) {
  2177. _fnLog( settings, 0, "Requested unknown parameter "+
  2178. (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
  2179. " for row "+rowIdx+", column "+colIdx, 4 );
  2180. settings.iDrawError = draw;
  2181. }
  2182. return defaultContent;
  2183. }
  2184. // When the data source is null and a specific data type is requested (i.e.
  2185. // not the original data), we can use default column data
  2186. if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
  2187. cellData = defaultContent;
  2188. }
  2189. else if ( typeof cellData === 'function' ) {
  2190. // If the data source is a function, then we run it and use the return,
  2191. // executing in the scope of the data object (for instances)
  2192. return cellData.call( rowData );
  2193. }
  2194. if ( cellData === null && type == 'display' ) {
  2195. return '';
  2196. }
  2197. return cellData;
  2198. }
  2199. /**
  2200. * Set the value for a specific cell, into the internal data cache
  2201. * @param {object} settings dataTables settings object
  2202. * @param {int} rowIdx aoData row id
  2203. * @param {int} colIdx Column index
  2204. * @param {*} val Value to set
  2205. * @memberof DataTable#oApi
  2206. */
  2207. function _fnSetCellData( settings, rowIdx, colIdx, val )
  2208. {
  2209. var col = settings.aoColumns[colIdx];
  2210. var rowData = settings.aoData[rowIdx]._aData;
  2211. col.fnSetData( rowData, val, {
  2212. settings: settings,
  2213. row: rowIdx,
  2214. col: colIdx
  2215. } );
  2216. }
  2217. // Private variable that is used to match action syntax in the data property object
  2218. var __reArray = /\[.*?\]$/;
  2219. var __reFn = /\(\)$/;
  2220. /**
  2221. * Split string on periods, taking into account escaped periods
  2222. * @param {string} str String to split
  2223. * @return {array} Split string
  2224. */
  2225. function _fnSplitObjNotation( str )
  2226. {
  2227. return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
  2228. return s.replace(/\\\./g, '.');
  2229. } );
  2230. }
  2231. /**
  2232. * Return a function that can be used to get data from a source object, taking
  2233. * into account the ability to use nested objects as a source
  2234. * @param {string|int|function} mSource The data source for the object
  2235. * @returns {function} Data get function
  2236. * @memberof DataTable#oApi
  2237. */
  2238. function _fnGetObjectDataFn( mSource )
  2239. {
  2240. if ( $.isPlainObject( mSource ) )
  2241. {
  2242. /* Build an object of get functions, and wrap them in a single call */
  2243. var o = {};
  2244. $.each( mSource, function (key, val) {
  2245. if ( val ) {
  2246. o[key] = _fnGetObjectDataFn( val );
  2247. }
  2248. } );
  2249. return function (data, type, row, meta) {
  2250. var t = o[type] || o._;
  2251. return t !== undefined ?
  2252. t(data, type, row, meta) :
  2253. data;
  2254. };
  2255. }
  2256. else if ( mSource === null )
  2257. {
  2258. /* Give an empty string for rendering / sorting etc */
  2259. return function (data) { // type, row and meta also passed, but not used
  2260. return data;
  2261. };
  2262. }
  2263. else if ( typeof mSource === 'function' )
  2264. {
  2265. return function (data, type, row, meta) {
  2266. return mSource( data, type, row, meta );
  2267. };
  2268. }
  2269. else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
  2270. mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
  2271. {
  2272. /* If there is a . in the source string then the data source is in a
  2273. * nested object so we loop over the data for each level to get the next
  2274. * level down. On each loop we test for undefined, and if found immediately
  2275. * return. This allows entire objects to be missing and sDefaultContent to
  2276. * be used if defined, rather than throwing an error
  2277. */
  2278. var fetchData = function (data, type, src) {
  2279. var arrayNotation, funcNotation, out, innerSrc;
  2280. if ( src !== "" )
  2281. {
  2282. var a = _fnSplitObjNotation( src );
  2283. for ( var i=0, iLen=a.length ; i<iLen ; i++ )
  2284. {
  2285. // Check if we are dealing with special notation
  2286. arrayNotation = a[i].match(__reArray);
  2287. funcNotation = a[i].match(__reFn);
  2288. if ( arrayNotation )
  2289. {
  2290. // Array notation
  2291. a[i] = a[i].replace(__reArray, '');
  2292. // Condition allows simply [] to be passed in
  2293. if ( a[i] !== "" ) {
  2294. data = data[ a[i] ];
  2295. }
  2296. out = [];
  2297. // Get the remainder of the nested object to get
  2298. a.splice( 0, i+1 );
  2299. innerSrc = a.join('.');
  2300. // Traverse each entry in the array getting the properties requested
  2301. if ( $.isArray( data ) ) {
  2302. for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
  2303. out.push( fetchData( data[j], type, innerSrc ) );
  2304. }
  2305. }
  2306. // If a string is given in between the array notation indicators, that
  2307. // is used to join the strings together, otherwise an array is returned
  2308. var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
  2309. data = (join==="") ? out : out.join(join);
  2310. // The inner call to fetchData has already traversed through the remainder
  2311. // of the source requested, so we exit from the loop
  2312. break;
  2313. }
  2314. else if ( funcNotation )
  2315. {
  2316. // Function call
  2317. a[i] = a[i].replace(__reFn, '');
  2318. data = data[ a[i] ]();
  2319. continue;
  2320. }
  2321. if ( data === null || data[ a[i] ] === undefined )
  2322. {
  2323. return undefined;
  2324. }
  2325. data = data[ a[i] ];
  2326. }
  2327. }
  2328. return data;
  2329. };
  2330. return function (data, type) { // row and meta also passed, but not used
  2331. return fetchData( data, type, mSource );
  2332. };
  2333. }
  2334. else
  2335. {
  2336. /* Array or flat object mapping */
  2337. return function (data, type) { // row and meta also passed, but not used
  2338. return data[mSource];
  2339. };
  2340. }
  2341. }
  2342. /**
  2343. * Return a function that can be used to set data from a source object, taking
  2344. * into account the ability to use nested objects as a source
  2345. * @param {string|int|function} mSource The data source for the object
  2346. * @returns {function} Data set function
  2347. * @memberof DataTable#oApi
  2348. */
  2349. function _fnSetObjectDataFn( mSource )
  2350. {
  2351. if ( $.isPlainObject( mSource ) )
  2352. {
  2353. /* Unlike get, only the underscore (global) option is used for for
  2354. * setting data since we don't know the type here. This is why an object
  2355. * option is not documented for `mData` (which is read/write), but it is
  2356. * for `mRender` which is read only.
  2357. */
  2358. return _fnSetObjectDataFn( mSource._ );
  2359. }
  2360. else if ( mSource === null )
  2361. {
  2362. /* Nothing to do when the data source is null */
  2363. return function () {};
  2364. }
  2365. else if ( typeof mSource === 'function' )
  2366. {
  2367. return function (data, val, meta) {
  2368. mSource( data, 'set', val, meta );
  2369. };
  2370. }
  2371. else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
  2372. mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
  2373. {
  2374. /* Like the get, we need to get data from a nested object */
  2375. var setData = function (data, val, src) {
  2376. var a = _fnSplitObjNotation( src ), b;
  2377. var aLast = a[a.length-1];
  2378. var arrayNotation, funcNotation, o, innerSrc;
  2379. for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
  2380. {
  2381. // Check if we are dealing with an array notation request
  2382. arrayNotation = a[i].match(__reArray);
  2383. funcNotation = a[i].match(__reFn);
  2384. if ( arrayNotation )
  2385. {
  2386. a[i] = a[i].replace(__reArray, '');
  2387. data[ a[i] ] = [];
  2388. // Get the remainder of the nested object to set so we can recurse
  2389. b = a.slice();
  2390. b.splice( 0, i+1 );
  2391. innerSrc = b.join('.');
  2392. // Traverse each entry in the array setting the properties requested
  2393. if ( $.isArray( val ) )
  2394. {
  2395. for ( var j=0, jLen=val.length ; j<jLen ; j++ )
  2396. {
  2397. o = {};
  2398. setData( o, val[j], innerSrc );
  2399. data[ a[i] ].push( o );
  2400. }
  2401. }
  2402. else
  2403. {
  2404. // We've been asked to save data to an array, but it
  2405. // isn't array data to be saved. Best that can be done
  2406. // is to just save the value.
  2407. data[ a[i] ] = val;
  2408. }
  2409. // The inner call to setData has already traversed through the remainder
  2410. // of the source and has set the data, thus we can exit here
  2411. return;
  2412. }
  2413. else if ( funcNotation )
  2414. {
  2415. // Function call
  2416. a[i] = a[i].replace(__reFn, '');
  2417. data = data[ a[i] ]( val );
  2418. }
  2419. // If the nested object doesn't currently exist - since we are
  2420. // trying to set the value - create it
  2421. if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
  2422. {
  2423. data[ a[i] ] = {};
  2424. }
  2425. data = data[ a[i] ];
  2426. }
  2427. // Last item in the input - i.e, the actual set
  2428. if ( aLast.match(__reFn ) )
  2429. {
  2430. // Function call
  2431. data = data[ aLast.replace(__reFn, '') ]( val );
  2432. }
  2433. else
  2434. {
  2435. // If array notation is used, we just want to strip it and use the property name
  2436. // and assign the value. If it isn't used, then we get the result we want anyway
  2437. data[ aLast.replace(__reArray, '') ] = val;
  2438. }
  2439. };
  2440. return function (data, val) { // meta is also passed in, but not used
  2441. return setData( data, val, mSource );
  2442. };
  2443. }
  2444. else
  2445. {
  2446. /* Array or flat object mapping */
  2447. return function (data, val) { // meta is also passed in, but not used
  2448. data[mSource] = val;
  2449. };
  2450. }
  2451. }
  2452. /**
  2453. * Return an array with the full table data
  2454. * @param {object} oSettings dataTables settings object
  2455. * @returns array {array} aData Master data array
  2456. * @memberof DataTable#oApi
  2457. */
  2458. function _fnGetDataMaster ( settings )
  2459. {
  2460. return _pluck( settings.aoData, '_aData' );
  2461. }
  2462. /**
  2463. * Nuke the table
  2464. * @param {object} oSettings dataTables settings object
  2465. * @memberof DataTable#oApi
  2466. */
  2467. function _fnClearTable( settings )
  2468. {
  2469. settings.aoData.length = 0;
  2470. settings.aiDisplayMaster.length = 0;
  2471. settings.aiDisplay.length = 0;
  2472. settings.aIds = {};
  2473. }
  2474. /**
  2475. * Take an array of integers (index array) and remove a target integer (value - not
  2476. * the key!)
  2477. * @param {array} a Index array to target
  2478. * @param {int} iTarget value to find
  2479. * @memberof DataTable#oApi
  2480. */
  2481. function _fnDeleteIndex( a, iTarget, splice )
  2482. {
  2483. var iTargetIndex = -1;
  2484. for ( var i=0, iLen=a.length ; i<iLen ; i++ )
  2485. {
  2486. if ( a[i] == iTarget )
  2487. {
  2488. iTargetIndex = i;
  2489. }
  2490. else if ( a[i] > iTarget )
  2491. {
  2492. a[i]--;
  2493. }
  2494. }
  2495. if ( iTargetIndex != -1 && splice === undefined )
  2496. {
  2497. a.splice( iTargetIndex, 1 );
  2498. }
  2499. }
  2500. /**
  2501. * Mark cached data as invalid such that a re-read of the data will occur when
  2502. * the cached data is next requested. Also update from the data source object.
  2503. *
  2504. * @param {object} settings DataTables settings object
  2505. * @param {int} rowIdx Row index to invalidate
  2506. * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
  2507. * or 'data'
  2508. * @param {int} [colIdx] Column index to invalidate. If undefined the whole
  2509. * row will be invalidated
  2510. * @memberof DataTable#oApi
  2511. *
  2512. * @todo For the modularisation of v1.11 this will need to become a callback, so
  2513. * the sort and filter methods can subscribe to it. That will required
  2514. * initialisation options for sorting, which is why it is not already baked in
  2515. */
  2516. function _fnInvalidate( settings, rowIdx, src, colIdx )
  2517. {
  2518. var row = settings.aoData[ rowIdx ];
  2519. var i, ien;
  2520. var cellWrite = function ( cell, col ) {
  2521. // This is very frustrating, but in IE if you just write directly
  2522. // to innerHTML, and elements that are overwritten are GC'ed,
  2523. // even if there is a reference to them elsewhere
  2524. while ( cell.childNodes.length ) {
  2525. cell.removeChild( cell.firstChild );
  2526. }
  2527. cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
  2528. };
  2529. // Are we reading last data from DOM or the data object?
  2530. if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
  2531. // Read the data from the DOM
  2532. row._aData = _fnGetRowElements(
  2533. settings, row, colIdx, colIdx === undefined ? undefined : row._aData
  2534. )
  2535. .data;
  2536. }
  2537. else {
  2538. // Reading from data object, update the DOM
  2539. var cells = row.anCells;
  2540. if ( cells ) {
  2541. if ( colIdx !== undefined ) {
  2542. cellWrite( cells[colIdx], colIdx );
  2543. }
  2544. else {
  2545. for ( i=0, ien=cells.length ; i<ien ; i++ ) {
  2546. cellWrite( cells[i], i );
  2547. }
  2548. }
  2549. }
  2550. }
  2551. // For both row and cell invalidation, the cached data for sorting and
  2552. // filtering is nulled out
  2553. row._aSortData = null;
  2554. row._aFilterData = null;
  2555. // Invalidate the type for a specific column (if given) or all columns since
  2556. // the data might have changed
  2557. var cols = settings.aoColumns;
  2558. if ( colIdx !== undefined ) {
  2559. cols[ colIdx ].sType = null;
  2560. }
  2561. else {
  2562. for ( i=0, ien=cols.length ; i<ien ; i++ ) {
  2563. cols[i].sType = null;
  2564. }
  2565. // Update DataTables special `DT_*` attributes for the row
  2566. _fnRowAttributes( settings, row );
  2567. }
  2568. }
  2569. /**
  2570. * Build a data source object from an HTML row, reading the contents of the
  2571. * cells that are in the row.
  2572. *
  2573. * @param {object} settings DataTables settings object
  2574. * @param {node|object} TR element from which to read data or existing row
  2575. * object from which to re-read the data from the cells
  2576. * @param {int} [colIdx] Optional column index
  2577. * @param {array|object} [d] Data source object. If `colIdx` is given then this
  2578. * parameter should also be given and will be used to write the data into.
  2579. * Only the column in question will be written
  2580. * @returns {object} Object with two parameters: `data` the data read, in
  2581. * document order, and `cells` and array of nodes (they can be useful to the
  2582. * caller, so rather than needing a second traversal to get them, just return
  2583. * them from here).
  2584. * @memberof DataTable#oApi
  2585. */
  2586. function _fnGetRowElements( settings, row, colIdx, d )
  2587. {
  2588. var
  2589. tds = [],
  2590. td = row.firstChild,
  2591. name, col, o, i=0, contents,
  2592. columns = settings.aoColumns,
  2593. objectRead = settings._rowReadObject;
  2594. // Allow the data object to be passed in, or construct
  2595. d = d !== undefined ?
  2596. d :
  2597. objectRead ?
  2598. {} :
  2599. [];
  2600. var attr = function ( str, td ) {
  2601. if ( typeof str === 'string' ) {
  2602. var idx = str.indexOf('@');
  2603. if ( idx !== -1 ) {
  2604. var attr = str.substring( idx+1 );
  2605. var setter = _fnSetObjectDataFn( str );
  2606. setter( d, td.getAttribute( attr ) );
  2607. }
  2608. }
  2609. };
  2610. // Read data from a cell and store into the data object
  2611. var cellProcess = function ( cell ) {
  2612. if ( colIdx === undefined || colIdx === i ) {
  2613. col = columns[i];
  2614. contents = $.trim(cell.innerHTML);
  2615. if ( col && col._bAttrSrc ) {
  2616. var setter = _fnSetObjectDataFn( col.mData._ );
  2617. setter( d, contents );
  2618. attr( col.mData.sort, cell );
  2619. attr( col.mData.type, cell );
  2620. attr( col.mData.filter, cell );
  2621. }
  2622. else {
  2623. // Depending on the `data` option for the columns the data can
  2624. // be read to either an object or an array.
  2625. if ( objectRead ) {
  2626. if ( ! col._setter ) {
  2627. // Cache the setter function
  2628. col._setter = _fnSetObjectDataFn( col.mData );
  2629. }
  2630. col._setter( d, contents );
  2631. }
  2632. else {
  2633. d[i] = contents;
  2634. }
  2635. }
  2636. }
  2637. i++;
  2638. };
  2639. if ( td ) {
  2640. // `tr` element was passed in
  2641. while ( td ) {
  2642. name = td.nodeName.toUpperCase();
  2643. if ( name == "TD" || name == "TH" ) {
  2644. cellProcess( td );
  2645. tds.push( td );
  2646. }
  2647. td = td.nextSibling;
  2648. }
  2649. }
  2650. else {
  2651. // Existing row object passed in
  2652. tds = row.anCells;
  2653. for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
  2654. cellProcess( tds[j] );
  2655. }
  2656. }
  2657. // Read the ID from the DOM if present
  2658. var rowNode = row.firstChild ? row : row.nTr;
  2659. if ( rowNode ) {
  2660. var id = rowNode.getAttribute( 'id' );
  2661. if ( id ) {
  2662. _fnSetObjectDataFn( settings.rowId )( d, id );
  2663. }
  2664. }
  2665. return {
  2666. data: d,
  2667. cells: tds
  2668. };
  2669. }
  2670. /**
  2671. * Create a new TR element (and it's TD children) for a row
  2672. * @param {object} oSettings dataTables settings object
  2673. * @param {int} iRow Row to consider
  2674. * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
  2675. * DataTables will create a row automatically
  2676. * @param {array} [anTds] Array of TD|TH elements for the row - must be given
  2677. * if nTr is.
  2678. * @memberof DataTable#oApi
  2679. */
  2680. function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
  2681. {
  2682. var
  2683. row = oSettings.aoData[iRow],
  2684. rowData = row._aData,
  2685. cells = [],
  2686. nTr, nTd, oCol,
  2687. i, iLen;
  2688. if ( row.nTr === null )
  2689. {
  2690. nTr = nTrIn || document.createElement('tr');
  2691. row.nTr = nTr;
  2692. row.anCells = cells;
  2693. /* Use a private property on the node to allow reserve mapping from the node
  2694. * to the aoData array for fast look up
  2695. */
  2696. nTr._DT_RowIndex = iRow;
  2697. /* Special parameters can be given by the data source to be used on the row */
  2698. _fnRowAttributes( oSettings, row );
  2699. /* Process each column */
  2700. for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
  2701. {
  2702. oCol = oSettings.aoColumns[i];
  2703. nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
  2704. nTd._DT_CellIndex = {
  2705. row: iRow,
  2706. column: i
  2707. };
  2708. cells.push( nTd );
  2709. // Need to create the HTML if new, or if a rendering function is defined
  2710. if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
  2711. (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
  2712. ) {
  2713. nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
  2714. }
  2715. /* Add user defined class */
  2716. if ( oCol.sClass )
  2717. {
  2718. nTd.className += ' '+oCol.sClass;
  2719. }
  2720. // Visibility - add or remove as required
  2721. if ( oCol.bVisible && ! nTrIn )
  2722. {
  2723. nTr.appendChild( nTd );
  2724. }
  2725. else if ( ! oCol.bVisible && nTrIn )
  2726. {
  2727. nTd.parentNode.removeChild( nTd );
  2728. }
  2729. if ( oCol.fnCreatedCell )
  2730. {
  2731. oCol.fnCreatedCell.call( oSettings.oInstance,
  2732. nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
  2733. );
  2734. }
  2735. }
  2736. _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
  2737. }
  2738. // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
  2739. // and deployed
  2740. row.nTr.setAttribute( 'role', 'row' );
  2741. }
  2742. /**
  2743. * Add attributes to a row based on the special `DT_*` parameters in a data
  2744. * source object.
  2745. * @param {object} settings DataTables settings object
  2746. * @param {object} DataTables row object for the row to be modified
  2747. * @memberof DataTable#oApi
  2748. */
  2749. function _fnRowAttributes( settings, row )
  2750. {
  2751. var tr = row.nTr;
  2752. var data = row._aData;
  2753. if ( tr ) {
  2754. var id = settings.rowIdFn( data );
  2755. if ( id ) {
  2756. tr.id = id;
  2757. }
  2758. if ( data.DT_RowClass ) {
  2759. // Remove any classes added by DT_RowClass before
  2760. var a = data.DT_RowClass.split(' ');
  2761. row.__rowc = row.__rowc ?
  2762. _unique( row.__rowc.concat( a ) ) :
  2763. a;
  2764. $(tr)
  2765. .removeClass( row.__rowc.join(' ') )
  2766. .addClass( data.DT_RowClass );
  2767. }
  2768. if ( data.DT_RowAttr ) {
  2769. $(tr).attr( data.DT_RowAttr );
  2770. }
  2771. if ( data.DT_RowData ) {
  2772. $(tr).data( data.DT_RowData );
  2773. }
  2774. }
  2775. }
  2776. /**
  2777. * Create the HTML header for the table
  2778. * @param {object} oSettings dataTables settings object
  2779. * @memberof DataTable#oApi
  2780. */
  2781. function _fnBuildHead( oSettings )
  2782. {
  2783. var i, ien, cell, row, column;
  2784. var thead = oSettings.nTHead;
  2785. var tfoot = oSettings.nTFoot;
  2786. var createHeader = $('th, td', thead).length === 0;
  2787. var classes = oSettings.oClasses;
  2788. var columns = oSettings.aoColumns;
  2789. if ( createHeader ) {
  2790. row = $('<tr/>').appendTo( thead );
  2791. }
  2792. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  2793. column = columns[i];
  2794. cell = $( column.nTh ).addClass( column.sClass );
  2795. if ( createHeader ) {
  2796. cell.appendTo( row );
  2797. }
  2798. // 1.11 move into sorting
  2799. if ( oSettings.oFeatures.bSort ) {
  2800. cell.addClass( column.sSortingClass );
  2801. if ( column.bSortable !== false ) {
  2802. cell
  2803. .attr( 'tabindex', oSettings.iTabIndex )
  2804. .attr( 'aria-controls', oSettings.sTableId );
  2805. _fnSortAttachListener( oSettings, column.nTh, i );
  2806. }
  2807. }
  2808. if ( column.sTitle != cell[0].innerHTML ) {
  2809. cell.html( column.sTitle );
  2810. }
  2811. _fnRenderer( oSettings, 'header' )(
  2812. oSettings, cell, column, classes
  2813. );
  2814. }
  2815. if ( createHeader ) {
  2816. _fnDetectHeader( oSettings.aoHeader, thead );
  2817. }
  2818. /* ARIA role for the rows */
  2819. $(thead).find('>tr').attr('role', 'row');
  2820. /* Deal with the footer - add classes if required */
  2821. $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
  2822. $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
  2823. // Cache the footer cells. Note that we only take the cells from the first
  2824. // row in the footer. If there is more than one row the user wants to
  2825. // interact with, they need to use the table().foot() method. Note also this
  2826. // allows cells to be used for multiple columns using colspan
  2827. if ( tfoot !== null ) {
  2828. var cells = oSettings.aoFooter[0];
  2829. for ( i=0, ien=cells.length ; i<ien ; i++ ) {
  2830. column = columns[i];
  2831. column.nTf = cells[i].cell;
  2832. if ( column.sClass ) {
  2833. $(column.nTf).addClass( column.sClass );
  2834. }
  2835. }
  2836. }
  2837. }
  2838. /**
  2839. * Draw the header (or footer) element based on the column visibility states. The
  2840. * methodology here is to use the layout array from _fnDetectHeader, modified for
  2841. * the instantaneous column visibility, to construct the new layout. The grid is
  2842. * traversed over cell at a time in a rows x columns grid fashion, although each
  2843. * cell insert can cover multiple elements in the grid - which is tracks using the
  2844. * aApplied array. Cell inserts in the grid will only occur where there isn't
  2845. * already a cell in that position.
  2846. * @param {object} oSettings dataTables settings object
  2847. * @param array {objects} aoSource Layout array from _fnDetectHeader
  2848. * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
  2849. * @memberof DataTable#oApi
  2850. */
  2851. function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
  2852. {
  2853. var i, iLen, j, jLen, k, kLen, n, nLocalTr;
  2854. var aoLocal = [];
  2855. var aApplied = [];
  2856. var iColumns = oSettings.aoColumns.length;
  2857. var iRowspan, iColspan;
  2858. if ( ! aoSource )
  2859. {
  2860. return;
  2861. }
  2862. if ( bIncludeHidden === undefined )
  2863. {
  2864. bIncludeHidden = false;
  2865. }
  2866. /* Make a copy of the master layout array, but without the visible columns in it */
  2867. for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
  2868. {
  2869. aoLocal[i] = aoSource[i].slice();
  2870. aoLocal[i].nTr = aoSource[i].nTr;
  2871. /* Remove any columns which are currently hidden */
  2872. for ( j=iColumns-1 ; j>=0 ; j-- )
  2873. {
  2874. if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
  2875. {
  2876. aoLocal[i].splice( j, 1 );
  2877. }
  2878. }
  2879. /* Prep the applied array - it needs an element for each row */
  2880. aApplied.push( [] );
  2881. }
  2882. for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
  2883. {
  2884. nLocalTr = aoLocal[i].nTr;
  2885. /* All cells are going to be replaced, so empty out the row */
  2886. if ( nLocalTr )
  2887. {
  2888. while( (n = nLocalTr.firstChild) )
  2889. {
  2890. nLocalTr.removeChild( n );
  2891. }
  2892. }
  2893. for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
  2894. {
  2895. iRowspan = 1;
  2896. iColspan = 1;
  2897. /* Check to see if there is already a cell (row/colspan) covering our target
  2898. * insert point. If there is, then there is nothing to do.
  2899. */
  2900. if ( aApplied[i][j] === undefined )
  2901. {
  2902. nLocalTr.appendChild( aoLocal[i][j].cell );
  2903. aApplied[i][j] = 1;
  2904. /* Expand the cell to cover as many rows as needed */
  2905. while ( aoLocal[i+iRowspan] !== undefined &&
  2906. aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
  2907. {
  2908. aApplied[i+iRowspan][j] = 1;
  2909. iRowspan++;
  2910. }
  2911. /* Expand the cell to cover as many columns as needed */
  2912. while ( aoLocal[i][j+iColspan] !== undefined &&
  2913. aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
  2914. {
  2915. /* Must update the applied array over the rows for the columns */
  2916. for ( k=0 ; k<iRowspan ; k++ )
  2917. {
  2918. aApplied[i+k][j+iColspan] = 1;
  2919. }
  2920. iColspan++;
  2921. }
  2922. /* Do the actual expansion in the DOM */
  2923. $(aoLocal[i][j].cell)
  2924. .attr('rowspan', iRowspan)
  2925. .attr('colspan', iColspan);
  2926. }
  2927. }
  2928. }
  2929. }
  2930. /**
  2931. * Insert the required TR nodes into the table for display
  2932. * @param {object} oSettings dataTables settings object
  2933. * @memberof DataTable#oApi
  2934. */
  2935. function _fnDraw( oSettings )
  2936. {
  2937. /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
  2938. var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
  2939. if ( $.inArray( false, aPreDraw ) !== -1 )
  2940. {
  2941. _fnProcessingDisplay( oSettings, false );
  2942. return;
  2943. }
  2944. var i, iLen, n;
  2945. var anRows = [];
  2946. var iRowCount = 0;
  2947. var asStripeClasses = oSettings.asStripeClasses;
  2948. var iStripes = asStripeClasses.length;
  2949. var iOpenRows = oSettings.aoOpenRows.length;
  2950. var oLang = oSettings.oLanguage;
  2951. var iInitDisplayStart = oSettings.iInitDisplayStart;
  2952. var bServerSide = _fnDataSource( oSettings ) == 'ssp';
  2953. var aiDisplay = oSettings.aiDisplay;
  2954. oSettings.bDrawing = true;
  2955. /* Check and see if we have an initial draw position from state saving */
  2956. if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
  2957. {
  2958. oSettings._iDisplayStart = bServerSide ?
  2959. iInitDisplayStart :
  2960. iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
  2961. 0 :
  2962. iInitDisplayStart;
  2963. oSettings.iInitDisplayStart = -1;
  2964. }
  2965. var iDisplayStart = oSettings._iDisplayStart;
  2966. var iDisplayEnd = oSettings.fnDisplayEnd();
  2967. /* Server-side processing draw intercept */
  2968. if ( oSettings.bDeferLoading )
  2969. {
  2970. oSettings.bDeferLoading = false;
  2971. oSettings.iDraw++;
  2972. _fnProcessingDisplay( oSettings, false );
  2973. }
  2974. else if ( !bServerSide )
  2975. {
  2976. oSettings.iDraw++;
  2977. }
  2978. else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
  2979. {
  2980. return;
  2981. }
  2982. if ( aiDisplay.length !== 0 )
  2983. {
  2984. var iStart = bServerSide ? 0 : iDisplayStart;
  2985. var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
  2986. for ( var j=iStart ; j<iEnd ; j++ )
  2987. {
  2988. var iDataIndex = aiDisplay[j];
  2989. var aoData = oSettings.aoData[ iDataIndex ];
  2990. if ( aoData.nTr === null )
  2991. {
  2992. _fnCreateTr( oSettings, iDataIndex );
  2993. }
  2994. var nRow = aoData.nTr;
  2995. /* Remove the old striping classes and then add the new one */
  2996. if ( iStripes !== 0 )
  2997. {
  2998. var sStripe = asStripeClasses[ iRowCount % iStripes ];
  2999. if ( aoData._sRowStripe != sStripe )
  3000. {
  3001. $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
  3002. aoData._sRowStripe = sStripe;
  3003. }
  3004. }
  3005. // Row callback functions - might want to manipulate the row
  3006. // iRowCount and j are not currently documented. Are they at all
  3007. // useful?
  3008. _fnCallbackFire( oSettings, 'aoRowCallback', null,
  3009. [nRow, aoData._aData, iRowCount, j] );
  3010. anRows.push( nRow );
  3011. iRowCount++;
  3012. }
  3013. }
  3014. else
  3015. {
  3016. /* Table is empty - create a row with an empty message in it */
  3017. var sZero = oLang.sZeroRecords;
  3018. if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
  3019. {
  3020. sZero = oLang.sLoadingRecords;
  3021. }
  3022. else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
  3023. {
  3024. sZero = oLang.sEmptyTable;
  3025. }
  3026. anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
  3027. .append( $('<td />', {
  3028. 'valign': 'top',
  3029. 'colSpan': _fnVisbleColumns( oSettings ),
  3030. 'class': oSettings.oClasses.sRowEmpty
  3031. } ).html( sZero ) )[0];
  3032. }
  3033. /* Header and footer callbacks */
  3034. _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
  3035. _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
  3036. _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
  3037. _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
  3038. var body = $(oSettings.nTBody);
  3039. body.children().detach();
  3040. body.append( $(anRows) );
  3041. /* Call all required callback functions for the end of a draw */
  3042. _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
  3043. /* Draw is complete, sorting and filtering must be as well */
  3044. oSettings.bSorted = false;
  3045. oSettings.bFiltered = false;
  3046. oSettings.bDrawing = false;
  3047. }
  3048. /**
  3049. * Redraw the table - taking account of the various features which are enabled
  3050. * @param {object} oSettings dataTables settings object
  3051. * @param {boolean} [holdPosition] Keep the current paging position. By default
  3052. * the paging is reset to the first page
  3053. * @memberof DataTable#oApi
  3054. */
  3055. function _fnReDraw( settings, holdPosition )
  3056. {
  3057. var
  3058. features = settings.oFeatures,
  3059. sort = features.bSort,
  3060. filter = features.bFilter;
  3061. if ( sort ) {
  3062. _fnSort( settings );
  3063. }
  3064. if ( filter ) {
  3065. _fnFilterComplete( settings, settings.oPreviousSearch );
  3066. }
  3067. else {
  3068. // No filtering, so we want to just use the display master
  3069. settings.aiDisplay = settings.aiDisplayMaster.slice();
  3070. }
  3071. if ( holdPosition !== true ) {
  3072. settings._iDisplayStart = 0;
  3073. }
  3074. // Let any modules know about the draw hold position state (used by
  3075. // scrolling internally)
  3076. settings._drawHold = holdPosition;
  3077. _fnDraw( settings );
  3078. settings._drawHold = false;
  3079. }
  3080. /**
  3081. * Add the options to the page HTML for the table
  3082. * @param {object} oSettings dataTables settings object
  3083. * @memberof DataTable#oApi
  3084. */
  3085. function _fnAddOptionsHtml ( oSettings )
  3086. {
  3087. var classes = oSettings.oClasses;
  3088. var table = $(oSettings.nTable);
  3089. var holding = $('<div/>').insertBefore( table ); // Holding element for speed
  3090. var features = oSettings.oFeatures;
  3091. // All DataTables are wrapped in a div
  3092. var insert = $('<div/>', {
  3093. id: oSettings.sTableId+'_wrapper',
  3094. 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
  3095. } );
  3096. oSettings.nHolding = holding[0];
  3097. oSettings.nTableWrapper = insert[0];
  3098. oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
  3099. /* Loop over the user set positioning and place the elements as needed */
  3100. var aDom = oSettings.sDom.split('');
  3101. var featureNode, cOption, nNewNode, cNext, sAttr, j;
  3102. for ( var i=0 ; i<aDom.length ; i++ )
  3103. {
  3104. featureNode = null;
  3105. cOption = aDom[i];
  3106. if ( cOption == '<' )
  3107. {
  3108. /* New container div */
  3109. nNewNode = $('<div/>')[0];
  3110. /* Check to see if we should append an id and/or a class name to the container */
  3111. cNext = aDom[i+1];
  3112. if ( cNext == "'" || cNext == '"' )
  3113. {
  3114. sAttr = "";
  3115. j = 2;
  3116. while ( aDom[i+j] != cNext )
  3117. {
  3118. sAttr += aDom[i+j];
  3119. j++;
  3120. }
  3121. /* Replace jQuery UI constants @todo depreciated */
  3122. if ( sAttr == "H" )
  3123. {
  3124. sAttr = classes.sJUIHeader;
  3125. }
  3126. else if ( sAttr == "F" )
  3127. {
  3128. sAttr = classes.sJUIFooter;
  3129. }
  3130. /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
  3131. * breaks the string into parts and applies them as needed
  3132. */
  3133. if ( sAttr.indexOf('.') != -1 )
  3134. {
  3135. var aSplit = sAttr.split('.');
  3136. nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
  3137. nNewNode.className = aSplit[1];
  3138. }
  3139. else if ( sAttr.charAt(0) == "#" )
  3140. {
  3141. nNewNode.id = sAttr.substr(1, sAttr.length-1);
  3142. }
  3143. else
  3144. {
  3145. nNewNode.className = sAttr;
  3146. }
  3147. i += j; /* Move along the position array */
  3148. }
  3149. insert.append( nNewNode );
  3150. insert = $(nNewNode);
  3151. }
  3152. else if ( cOption == '>' )
  3153. {
  3154. /* End container div */
  3155. insert = insert.parent();
  3156. }
  3157. // @todo Move options into their own plugins?
  3158. else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
  3159. {
  3160. /* Length */
  3161. featureNode = _fnFeatureHtmlLength( oSettings );
  3162. }
  3163. else if ( cOption == 'f' && features.bFilter )
  3164. {
  3165. /* Filter */
  3166. featureNode = _fnFeatureHtmlFilter( oSettings );
  3167. }
  3168. else if ( cOption == 'r' && features.bProcessing )
  3169. {
  3170. /* pRocessing */
  3171. featureNode = _fnFeatureHtmlProcessing( oSettings );
  3172. }
  3173. else if ( cOption == 't' )
  3174. {
  3175. /* Table */
  3176. featureNode = _fnFeatureHtmlTable( oSettings );
  3177. }
  3178. else if ( cOption == 'i' && features.bInfo )
  3179. {
  3180. /* Info */
  3181. featureNode = _fnFeatureHtmlInfo( oSettings );
  3182. }
  3183. else if ( cOption == 'p' && features.bPaginate )
  3184. {
  3185. /* Pagination */
  3186. featureNode = _fnFeatureHtmlPaginate( oSettings );
  3187. }
  3188. else if ( DataTable.ext.feature.length !== 0 )
  3189. {
  3190. /* Plug-in features */
  3191. var aoFeatures = DataTable.ext.feature;
  3192. for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
  3193. {
  3194. if ( cOption == aoFeatures[k].cFeature )
  3195. {
  3196. featureNode = aoFeatures[k].fnInit( oSettings );
  3197. break;
  3198. }
  3199. }
  3200. }
  3201. /* Add to the 2D features array */
  3202. if ( featureNode )
  3203. {
  3204. var aanFeatures = oSettings.aanFeatures;
  3205. if ( ! aanFeatures[cOption] )
  3206. {
  3207. aanFeatures[cOption] = [];
  3208. }
  3209. aanFeatures[cOption].push( featureNode );
  3210. insert.append( featureNode );
  3211. }
  3212. }
  3213. /* Built our DOM structure - replace the holding div with what we want */
  3214. holding.replaceWith( insert );
  3215. oSettings.nHolding = null;
  3216. }
  3217. /**
  3218. * Use the DOM source to create up an array of header cells. The idea here is to
  3219. * create a layout grid (array) of rows x columns, which contains a reference
  3220. * to the cell that that point in the grid (regardless of col/rowspan), such that
  3221. * any column / row could be removed and the new grid constructed
  3222. * @param array {object} aLayout Array to store the calculated layout in
  3223. * @param {node} nThead The header/footer element for the table
  3224. * @memberof DataTable#oApi
  3225. */
  3226. function _fnDetectHeader ( aLayout, nThead )
  3227. {
  3228. var nTrs = $(nThead).children('tr');
  3229. var nTr, nCell;
  3230. var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
  3231. var bUnique;
  3232. var fnShiftCol = function ( a, i, j ) {
  3233. var k = a[i];
  3234. while ( k[j] ) {
  3235. j++;
  3236. }
  3237. return j;
  3238. };
  3239. aLayout.splice( 0, aLayout.length );
  3240. /* We know how many rows there are in the layout - so prep it */
  3241. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  3242. {
  3243. aLayout.push( [] );
  3244. }
  3245. /* Calculate a layout array */
  3246. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  3247. {
  3248. nTr = nTrs[i];
  3249. iColumn = 0;
  3250. /* For every cell in the row... */
  3251. nCell = nTr.firstChild;
  3252. while ( nCell ) {
  3253. if ( nCell.nodeName.toUpperCase() == "TD" ||
  3254. nCell.nodeName.toUpperCase() == "TH" )
  3255. {
  3256. /* Get the col and rowspan attributes from the DOM and sanitise them */
  3257. iColspan = nCell.getAttribute('colspan') * 1;
  3258. iRowspan = nCell.getAttribute('rowspan') * 1;
  3259. iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
  3260. iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
  3261. /* There might be colspan cells already in this row, so shift our target
  3262. * accordingly
  3263. */
  3264. iColShifted = fnShiftCol( aLayout, i, iColumn );
  3265. /* Cache calculation for unique columns */
  3266. bUnique = iColspan === 1 ? true : false;
  3267. /* If there is col / rowspan, copy the information into the layout grid */
  3268. for ( l=0 ; l<iColspan ; l++ )
  3269. {
  3270. for ( k=0 ; k<iRowspan ; k++ )
  3271. {
  3272. aLayout[i+k][iColShifted+l] = {
  3273. "cell": nCell,
  3274. "unique": bUnique
  3275. };
  3276. aLayout[i+k].nTr = nTr;
  3277. }
  3278. }
  3279. }
  3280. nCell = nCell.nextSibling;
  3281. }
  3282. }
  3283. }
  3284. /**
  3285. * Get an array of unique th elements, one for each column
  3286. * @param {object} oSettings dataTables settings object
  3287. * @param {node} nHeader automatically detect the layout from this node - optional
  3288. * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
  3289. * @returns array {node} aReturn list of unique th's
  3290. * @memberof DataTable#oApi
  3291. */
  3292. function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
  3293. {
  3294. var aReturn = [];
  3295. if ( !aLayout )
  3296. {
  3297. aLayout = oSettings.aoHeader;
  3298. if ( nHeader )
  3299. {
  3300. aLayout = [];
  3301. _fnDetectHeader( aLayout, nHeader );
  3302. }
  3303. }
  3304. for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
  3305. {
  3306. for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
  3307. {
  3308. if ( aLayout[i][j].unique &&
  3309. (!aReturn[j] || !oSettings.bSortCellsTop) )
  3310. {
  3311. aReturn[j] = aLayout[i][j].cell;
  3312. }
  3313. }
  3314. }
  3315. return aReturn;
  3316. }
  3317. /**
  3318. * Create an Ajax call based on the table's settings, taking into account that
  3319. * parameters can have multiple forms, and backwards compatibility.
  3320. *
  3321. * @param {object} oSettings dataTables settings object
  3322. * @param {array} data Data to send to the server, required by
  3323. * DataTables - may be augmented by developer callbacks
  3324. * @param {function} fn Callback function to run when data is obtained
  3325. */
  3326. function _fnBuildAjax( oSettings, data, fn )
  3327. {
  3328. // Compatibility with 1.9-, allow fnServerData and event to manipulate
  3329. _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
  3330. // Convert to object based for 1.10+ if using the old array scheme which can
  3331. // come from server-side processing or serverParams
  3332. if ( data && $.isArray(data) ) {
  3333. var tmp = {};
  3334. var rbracket = /(.*?)\[\]$/;
  3335. $.each( data, function (key, val) {
  3336. var match = val.name.match(rbracket);
  3337. if ( match ) {
  3338. // Support for arrays
  3339. var name = match[0];
  3340. if ( ! tmp[ name ] ) {
  3341. tmp[ name ] = [];
  3342. }
  3343. tmp[ name ].push( val.value );
  3344. }
  3345. else {
  3346. tmp[val.name] = val.value;
  3347. }
  3348. } );
  3349. data = tmp;
  3350. }
  3351. var ajaxData;
  3352. var ajax = oSettings.ajax;
  3353. var instance = oSettings.oInstance;
  3354. var callback = function ( json ) {
  3355. _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
  3356. fn( json );
  3357. };
  3358. if ( $.isPlainObject( ajax ) && ajax.data )
  3359. {
  3360. ajaxData = ajax.data;
  3361. var newData = $.isFunction( ajaxData ) ?
  3362. ajaxData( data, oSettings ) : // fn can manipulate data or return
  3363. ajaxData; // an object object or array to merge
  3364. // If the function returned something, use that alone
  3365. data = $.isFunction( ajaxData ) && newData ?
  3366. newData :
  3367. $.extend( true, data, newData );
  3368. // Remove the data property as we've resolved it already and don't want
  3369. // jQuery to do it again (it is restored at the end of the function)
  3370. delete ajax.data;
  3371. }
  3372. var baseAjax = {
  3373. "data": data,
  3374. "success": function (json) {
  3375. var error = json.error || json.sError;
  3376. if ( error ) {
  3377. _fnLog( oSettings, 0, error );
  3378. }
  3379. oSettings.json = json;
  3380. callback( json );
  3381. },
  3382. "dataType": "json",
  3383. "cache": false,
  3384. "type": oSettings.sServerMethod,
  3385. "error": function (xhr, error, thrown) {
  3386. var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
  3387. if ( $.inArray( true, ret ) === -1 ) {
  3388. if ( error == "parsererror" ) {
  3389. _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
  3390. }
  3391. else if ( xhr.readyState === 4 ) {
  3392. _fnLog( oSettings, 0, 'Ajax error', 7 );
  3393. }
  3394. }
  3395. _fnProcessingDisplay( oSettings, false );
  3396. }
  3397. };
  3398. // Store the data submitted for the API
  3399. oSettings.oAjaxData = data;
  3400. // Allow plug-ins and external processes to modify the data
  3401. _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
  3402. if ( oSettings.fnServerData )
  3403. {
  3404. // DataTables 1.9- compatibility
  3405. oSettings.fnServerData.call( instance,
  3406. oSettings.sAjaxSource,
  3407. $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
  3408. return { name: key, value: val };
  3409. } ),
  3410. callback,
  3411. oSettings
  3412. );
  3413. }
  3414. else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
  3415. {
  3416. // DataTables 1.9- compatibility
  3417. oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
  3418. url: ajax || oSettings.sAjaxSource
  3419. } ) );
  3420. }
  3421. else if ( $.isFunction( ajax ) )
  3422. {
  3423. // Is a function - let the caller define what needs to be done
  3424. oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
  3425. }
  3426. else
  3427. {
  3428. // Object to extend the base settings
  3429. oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
  3430. // Restore for next time around
  3431. ajax.data = ajaxData;
  3432. }
  3433. }
  3434. /**
  3435. * Update the table using an Ajax call
  3436. * @param {object} settings dataTables settings object
  3437. * @returns {boolean} Block the table drawing or not
  3438. * @memberof DataTable#oApi
  3439. */
  3440. function _fnAjaxUpdate( settings )
  3441. {
  3442. if ( settings.bAjaxDataGet ) {
  3443. settings.iDraw++;
  3444. _fnProcessingDisplay( settings, true );
  3445. _fnBuildAjax(
  3446. settings,
  3447. _fnAjaxParameters( settings ),
  3448. function(json) {
  3449. _fnAjaxUpdateDraw( settings, json );
  3450. }
  3451. );
  3452. return false;
  3453. }
  3454. return true;
  3455. }
  3456. /**
  3457. * Build up the parameters in an object needed for a server-side processing
  3458. * request. Note that this is basically done twice, is different ways - a modern
  3459. * method which is used by default in DataTables 1.10 which uses objects and
  3460. * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
  3461. * the sAjaxSource option is used in the initialisation, or the legacyAjax
  3462. * option is set.
  3463. * @param {object} oSettings dataTables settings object
  3464. * @returns {bool} block the table drawing or not
  3465. * @memberof DataTable#oApi
  3466. */
  3467. function _fnAjaxParameters( settings )
  3468. {
  3469. var
  3470. columns = settings.aoColumns,
  3471. columnCount = columns.length,
  3472. features = settings.oFeatures,
  3473. preSearch = settings.oPreviousSearch,
  3474. preColSearch = settings.aoPreSearchCols,
  3475. i, data = [], dataProp, column, columnSearch,
  3476. sort = _fnSortFlatten( settings ),
  3477. displayStart = settings._iDisplayStart,
  3478. displayLength = features.bPaginate !== false ?
  3479. settings._iDisplayLength :
  3480. -1;
  3481. var param = function ( name, value ) {
  3482. data.push( { 'name': name, 'value': value } );
  3483. };
  3484. // DataTables 1.9- compatible method
  3485. param( 'sEcho', settings.iDraw );
  3486. param( 'iColumns', columnCount );
  3487. param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
  3488. param( 'iDisplayStart', displayStart );
  3489. param( 'iDisplayLength', displayLength );
  3490. // DataTables 1.10+ method
  3491. var d = {
  3492. draw: settings.iDraw,
  3493. columns: [],
  3494. order: [],
  3495. start: displayStart,
  3496. length: displayLength,
  3497. search: {
  3498. value: preSearch.sSearch,
  3499. regex: preSearch.bRegex
  3500. }
  3501. };
  3502. for ( i=0 ; i<columnCount ; i++ ) {
  3503. column = columns[i];
  3504. columnSearch = preColSearch[i];
  3505. dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
  3506. d.columns.push( {
  3507. data: dataProp,
  3508. name: column.sName,
  3509. searchable: column.bSearchable,
  3510. orderable: column.bSortable,
  3511. search: {
  3512. value: columnSearch.sSearch,
  3513. regex: columnSearch.bRegex
  3514. }
  3515. } );
  3516. param( "mDataProp_"+i, dataProp );
  3517. if ( features.bFilter ) {
  3518. param( 'sSearch_'+i, columnSearch.sSearch );
  3519. param( 'bRegex_'+i, columnSearch.bRegex );
  3520. param( 'bSearchable_'+i, column.bSearchable );
  3521. }
  3522. if ( features.bSort ) {
  3523. param( 'bSortable_'+i, column.bSortable );
  3524. }
  3525. }
  3526. if ( features.bFilter ) {
  3527. param( 'sSearch', preSearch.sSearch );
  3528. param( 'bRegex', preSearch.bRegex );
  3529. }
  3530. if ( features.bSort ) {
  3531. $.each( sort, function ( i, val ) {
  3532. d.order.push( { column: val.col, dir: val.dir } );
  3533. param( 'iSortCol_'+i, val.col );
  3534. param( 'sSortDir_'+i, val.dir );
  3535. } );
  3536. param( 'iSortingCols', sort.length );
  3537. }
  3538. // If the legacy.ajax parameter is null, then we automatically decide which
  3539. // form to use, based on sAjaxSource
  3540. var legacy = DataTable.ext.legacy.ajax;
  3541. if ( legacy === null ) {
  3542. return settings.sAjaxSource ? data : d;
  3543. }
  3544. // Otherwise, if legacy has been specified then we use that to decide on the
  3545. // form
  3546. return legacy ? data : d;
  3547. }
  3548. /**
  3549. * Data the data from the server (nuking the old) and redraw the table
  3550. * @param {object} oSettings dataTables settings object
  3551. * @param {object} json json data return from the server.
  3552. * @param {string} json.sEcho Tracking flag for DataTables to match requests
  3553. * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
  3554. * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
  3555. * @param {array} json.aaData The data to display on this page
  3556. * @param {string} [json.sColumns] Column ordering (sName, comma separated)
  3557. * @memberof DataTable#oApi
  3558. */
  3559. function _fnAjaxUpdateDraw ( settings, json )
  3560. {
  3561. // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
  3562. // Support both
  3563. var compat = function ( old, modern ) {
  3564. return json[old] !== undefined ? json[old] : json[modern];
  3565. };
  3566. var data = _fnAjaxDataSrc( settings, json );
  3567. var draw = compat( 'sEcho', 'draw' );
  3568. var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
  3569. var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
  3570. if ( draw ) {
  3571. // Protect against out of sequence returns
  3572. if ( draw*1 < settings.iDraw ) {
  3573. return;
  3574. }
  3575. settings.iDraw = draw * 1;
  3576. }
  3577. _fnClearTable( settings );
  3578. settings._iRecordsTotal = parseInt(recordsTotal, 10);
  3579. settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
  3580. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  3581. _fnAddData( settings, data[i] );
  3582. }
  3583. settings.aiDisplay = settings.aiDisplayMaster.slice();
  3584. settings.bAjaxDataGet = false;
  3585. _fnDraw( settings );
  3586. if ( ! settings._bInitComplete ) {
  3587. _fnInitComplete( settings, json );
  3588. }
  3589. settings.bAjaxDataGet = true;
  3590. _fnProcessingDisplay( settings, false );
  3591. }
  3592. /**
  3593. * Get the data from the JSON data source to use for drawing a table. Using
  3594. * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
  3595. * source object, or from a processing function.
  3596. * @param {object} oSettings dataTables settings object
  3597. * @param {object} json Data source object / array from the server
  3598. * @return {array} Array of data to use
  3599. */
  3600. function _fnAjaxDataSrc ( oSettings, json )
  3601. {
  3602. var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
  3603. oSettings.ajax.dataSrc :
  3604. oSettings.sAjaxDataProp; // Compatibility with 1.9-.
  3605. // Compatibility with 1.9-. In order to read from aaData, check if the
  3606. // default has been changed, if not, check for aaData
  3607. if ( dataSrc === 'data' ) {
  3608. return json.aaData || json[dataSrc];
  3609. }
  3610. return dataSrc !== "" ?
  3611. _fnGetObjectDataFn( dataSrc )( json ) :
  3612. json;
  3613. }
  3614. /**
  3615. * Generate the node required for filtering text
  3616. * @returns {node} Filter control element
  3617. * @param {object} oSettings dataTables settings object
  3618. * @memberof DataTable#oApi
  3619. */
  3620. function _fnFeatureHtmlFilter ( settings )
  3621. {
  3622. var classes = settings.oClasses;
  3623. var tableId = settings.sTableId;
  3624. var language = settings.oLanguage;
  3625. var previousSearch = settings.oPreviousSearch;
  3626. var features = settings.aanFeatures;
  3627. var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
  3628. var str = language.sSearch;
  3629. str = str.match(/_INPUT_/) ?
  3630. str.replace('_INPUT_', input) :
  3631. str+input;
  3632. var filter = $('<div/>', {
  3633. 'id': ! features.f ? tableId+'_filter' : null,
  3634. 'class': classes.sFilter
  3635. } )
  3636. .append( $('<label/>' ).append( str ) );
  3637. var searchFn = function() {
  3638. /* Update all other filter input elements for the new display */
  3639. var n = features.f;
  3640. var val = !this.value ? "" : this.value; // mental IE8 fix :-(
  3641. /* Now do the filter */
  3642. if ( val != previousSearch.sSearch ) {
  3643. _fnFilterComplete( settings, {
  3644. "sSearch": val,
  3645. "bRegex": previousSearch.bRegex,
  3646. "bSmart": previousSearch.bSmart ,
  3647. "bCaseInsensitive": previousSearch.bCaseInsensitive
  3648. } );
  3649. // Need to redraw, without resorting
  3650. settings._iDisplayStart = 0;
  3651. _fnDraw( settings );
  3652. }
  3653. };
  3654. var searchDelay = settings.searchDelay !== null ?
  3655. settings.searchDelay :
  3656. _fnDataSource( settings ) === 'ssp' ?
  3657. 400 :
  3658. 0;
  3659. var jqFilter = $('input', filter)
  3660. .val( previousSearch.sSearch )
  3661. .attr( 'placeholder', language.sSearchPlaceholder )
  3662. .on(
  3663. 'keyup.DT search.DT input.DT paste.DT cut.DT',
  3664. searchDelay ?
  3665. _fnThrottle( searchFn, searchDelay ) :
  3666. searchFn
  3667. )
  3668. .on( 'keypress.DT', function(e) {
  3669. /* Prevent form submission */
  3670. if ( e.keyCode == 13 ) {
  3671. return false;
  3672. }
  3673. } )
  3674. .attr('aria-controls', tableId);
  3675. // Update the input elements whenever the table is filtered
  3676. $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
  3677. if ( settings === s ) {
  3678. // IE9 throws an 'unknown error' if document.activeElement is used
  3679. // inside an iframe or frame...
  3680. try {
  3681. if ( jqFilter[0] !== document.activeElement ) {
  3682. jqFilter.val( previousSearch.sSearch );
  3683. }
  3684. }
  3685. catch ( e ) {}
  3686. }
  3687. } );
  3688. return filter[0];
  3689. }
  3690. /**
  3691. * Filter the table using both the global filter and column based filtering
  3692. * @param {object} oSettings dataTables settings object
  3693. * @param {object} oSearch search information
  3694. * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
  3695. * @memberof DataTable#oApi
  3696. */
  3697. function _fnFilterComplete ( oSettings, oInput, iForce )
  3698. {
  3699. var oPrevSearch = oSettings.oPreviousSearch;
  3700. var aoPrevSearch = oSettings.aoPreSearchCols;
  3701. var fnSaveFilter = function ( oFilter ) {
  3702. /* Save the filtering values */
  3703. oPrevSearch.sSearch = oFilter.sSearch;
  3704. oPrevSearch.bRegex = oFilter.bRegex;
  3705. oPrevSearch.bSmart = oFilter.bSmart;
  3706. oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
  3707. };
  3708. var fnRegex = function ( o ) {
  3709. // Backwards compatibility with the bEscapeRegex option
  3710. return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
  3711. };
  3712. // Resolve any column types that are unknown due to addition or invalidation
  3713. // @todo As per sort - can this be moved into an event handler?
  3714. _fnColumnTypes( oSettings );
  3715. /* In server-side processing all filtering is done by the server, so no point hanging around here */
  3716. if ( _fnDataSource( oSettings ) != 'ssp' )
  3717. {
  3718. /* Global filter */
  3719. _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
  3720. fnSaveFilter( oInput );
  3721. /* Now do the individual column filter */
  3722. for ( var i=0 ; i<aoPrevSearch.length ; i++ )
  3723. {
  3724. _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
  3725. aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
  3726. }
  3727. /* Custom filtering */
  3728. _fnFilterCustom( oSettings );
  3729. }
  3730. else
  3731. {
  3732. fnSaveFilter( oInput );
  3733. }
  3734. /* Tell the draw function we have been filtering */
  3735. oSettings.bFiltered = true;
  3736. _fnCallbackFire( oSettings, null, 'search', [oSettings] );
  3737. }
  3738. /**
  3739. * Apply custom filtering functions
  3740. * @param {object} oSettings dataTables settings object
  3741. * @memberof DataTable#oApi
  3742. */
  3743. function _fnFilterCustom( settings )
  3744. {
  3745. var filters = DataTable.ext.search;
  3746. var displayRows = settings.aiDisplay;
  3747. var row, rowIdx;
  3748. for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
  3749. var rows = [];
  3750. // Loop over each row and see if it should be included
  3751. for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
  3752. rowIdx = displayRows[ j ];
  3753. row = settings.aoData[ rowIdx ];
  3754. if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
  3755. rows.push( rowIdx );
  3756. }
  3757. }
  3758. // So the array reference doesn't break set the results into the
  3759. // existing array
  3760. displayRows.length = 0;
  3761. $.merge( displayRows, rows );
  3762. }
  3763. }
  3764. /**
  3765. * Filter the table on a per-column basis
  3766. * @param {object} oSettings dataTables settings object
  3767. * @param {string} sInput string to filter on
  3768. * @param {int} iColumn column to filter
  3769. * @param {bool} bRegex treat search string as a regular expression or not
  3770. * @param {bool} bSmart use smart filtering or not
  3771. * @param {bool} bCaseInsensitive Do case insenstive matching or not
  3772. * @memberof DataTable#oApi
  3773. */
  3774. function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
  3775. {
  3776. if ( searchStr === '' ) {
  3777. return;
  3778. }
  3779. var data;
  3780. var out = [];
  3781. var display = settings.aiDisplay;
  3782. var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
  3783. for ( var i=0 ; i<display.length ; i++ ) {
  3784. data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
  3785. if ( rpSearch.test( data ) ) {
  3786. out.push( display[i] );
  3787. }
  3788. }
  3789. settings.aiDisplay = out;
  3790. }
  3791. /**
  3792. * Filter the data table based on user input and draw the table
  3793. * @param {object} settings dataTables settings object
  3794. * @param {string} input string to filter on
  3795. * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
  3796. * @param {bool} regex treat as a regular expression or not
  3797. * @param {bool} smart perform smart filtering or not
  3798. * @param {bool} caseInsensitive Do case insenstive matching or not
  3799. * @memberof DataTable#oApi
  3800. */
  3801. function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
  3802. {
  3803. var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
  3804. var prevSearch = settings.oPreviousSearch.sSearch;
  3805. var displayMaster = settings.aiDisplayMaster;
  3806. var display, invalidated, i;
  3807. var filtered = [];
  3808. // Need to take account of custom filtering functions - always filter
  3809. if ( DataTable.ext.search.length !== 0 ) {
  3810. force = true;
  3811. }
  3812. // Check if any of the rows were invalidated
  3813. invalidated = _fnFilterData( settings );
  3814. // If the input is blank - we just want the full data set
  3815. if ( input.length <= 0 ) {
  3816. settings.aiDisplay = displayMaster.slice();
  3817. }
  3818. else {
  3819. // New search - start from the master array
  3820. if ( invalidated ||
  3821. force ||
  3822. prevSearch.length > input.length ||
  3823. input.indexOf(prevSearch) !== 0 ||
  3824. settings.bSorted // On resort, the display master needs to be
  3825. // re-filtered since indexes will have changed
  3826. ) {
  3827. settings.aiDisplay = displayMaster.slice();
  3828. }
  3829. // Search the display array
  3830. display = settings.aiDisplay;
  3831. for ( i=0 ; i<display.length ; i++ ) {
  3832. if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
  3833. filtered.push( display[i] );
  3834. }
  3835. }
  3836. settings.aiDisplay = filtered;
  3837. }
  3838. }
  3839. /**
  3840. * Build a regular expression object suitable for searching a table
  3841. * @param {string} sSearch string to search for
  3842. * @param {bool} bRegex treat as a regular expression or not
  3843. * @param {bool} bSmart perform smart filtering or not
  3844. * @param {bool} bCaseInsensitive Do case insensitive matching or not
  3845. * @returns {RegExp} constructed object
  3846. * @memberof DataTable#oApi
  3847. */
  3848. function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
  3849. {
  3850. search = regex ?
  3851. search :
  3852. _fnEscapeRegex( search );
  3853. if ( smart ) {
  3854. /* For smart filtering we want to allow the search to work regardless of
  3855. * word order. We also want double quoted text to be preserved, so word
  3856. * order is important - a la google. So this is what we want to
  3857. * generate:
  3858. *
  3859. * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
  3860. */
  3861. var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
  3862. if ( word.charAt(0) === '"' ) {
  3863. var m = word.match( /^"(.*)"$/ );
  3864. word = m ? m[1] : word;
  3865. }
  3866. return word.replace('"', '');
  3867. } );
  3868. search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
  3869. }
  3870. return new RegExp( search, caseInsensitive ? 'i' : '' );
  3871. }
  3872. /**
  3873. * Escape a string such that it can be used in a regular expression
  3874. * @param {string} sVal string to escape
  3875. * @returns {string} escaped string
  3876. * @memberof DataTable#oApi
  3877. */
  3878. var _fnEscapeRegex = DataTable.util.escapeRegex;
  3879. var __filter_div = $('<div>')[0];
  3880. var __filter_div_textContent = __filter_div.textContent !== undefined;
  3881. // Update the filtering data for each row if needed (by invalidation or first run)
  3882. function _fnFilterData ( settings )
  3883. {
  3884. var columns = settings.aoColumns;
  3885. var column;
  3886. var i, j, ien, jen, filterData, cellData, row;
  3887. var fomatters = DataTable.ext.type.search;
  3888. var wasInvalidated = false;
  3889. for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  3890. row = settings.aoData[i];
  3891. if ( ! row._aFilterData ) {
  3892. filterData = [];
  3893. for ( j=0, jen=columns.length ; j<jen ; j++ ) {
  3894. column = columns[j];
  3895. if ( column.bSearchable ) {
  3896. cellData = _fnGetCellData( settings, i, j, 'filter' );
  3897. if ( fomatters[ column.sType ] ) {
  3898. cellData = fomatters[ column.sType ]( cellData );
  3899. }
  3900. // Search in DataTables 1.10 is string based. In 1.11 this
  3901. // should be altered to also allow strict type checking.
  3902. if ( cellData === null ) {
  3903. cellData = '';
  3904. }
  3905. if ( typeof cellData !== 'string' && cellData.toString ) {
  3906. cellData = cellData.toString();
  3907. }
  3908. }
  3909. else {
  3910. cellData = '';
  3911. }
  3912. // If it looks like there is an HTML entity in the string,
  3913. // attempt to decode it so sorting works as expected. Note that
  3914. // we could use a single line of jQuery to do this, but the DOM
  3915. // method used here is much faster http://jsperf.com/html-decode
  3916. if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
  3917. __filter_div.innerHTML = cellData;
  3918. cellData = __filter_div_textContent ?
  3919. __filter_div.textContent :
  3920. __filter_div.innerText;
  3921. }
  3922. if ( cellData.replace ) {
  3923. cellData = cellData.replace(/[\r\n]/g, '');
  3924. }
  3925. filterData.push( cellData );
  3926. }
  3927. row._aFilterData = filterData;
  3928. row._sFilterRow = filterData.join(' ');
  3929. wasInvalidated = true;
  3930. }
  3931. }
  3932. return wasInvalidated;
  3933. }
  3934. /**
  3935. * Convert from the internal Hungarian notation to camelCase for external
  3936. * interaction
  3937. * @param {object} obj Object to convert
  3938. * @returns {object} Inverted object
  3939. * @memberof DataTable#oApi
  3940. */
  3941. function _fnSearchToCamel ( obj )
  3942. {
  3943. return {
  3944. search: obj.sSearch,
  3945. smart: obj.bSmart,
  3946. regex: obj.bRegex,
  3947. caseInsensitive: obj.bCaseInsensitive
  3948. };
  3949. }
  3950. /**
  3951. * Convert from camelCase notation to the internal Hungarian. We could use the
  3952. * Hungarian convert function here, but this is cleaner
  3953. * @param {object} obj Object to convert
  3954. * @returns {object} Inverted object
  3955. * @memberof DataTable#oApi
  3956. */
  3957. function _fnSearchToHung ( obj )
  3958. {
  3959. return {
  3960. sSearch: obj.search,
  3961. bSmart: obj.smart,
  3962. bRegex: obj.regex,
  3963. bCaseInsensitive: obj.caseInsensitive
  3964. };
  3965. }
  3966. /**
  3967. * Generate the node required for the info display
  3968. * @param {object} oSettings dataTables settings object
  3969. * @returns {node} Information element
  3970. * @memberof DataTable#oApi
  3971. */
  3972. function _fnFeatureHtmlInfo ( settings )
  3973. {
  3974. var
  3975. tid = settings.sTableId,
  3976. nodes = settings.aanFeatures.i,
  3977. n = $('<div/>', {
  3978. 'class': settings.oClasses.sInfo,
  3979. 'id': ! nodes ? tid+'_info' : null
  3980. } );
  3981. if ( ! nodes ) {
  3982. // Update display on each draw
  3983. settings.aoDrawCallback.push( {
  3984. "fn": _fnUpdateInfo,
  3985. "sName": "information"
  3986. } );
  3987. n
  3988. .attr( 'role', 'status' )
  3989. .attr( 'aria-live', 'polite' );
  3990. // Table is described by our info div
  3991. $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
  3992. }
  3993. return n[0];
  3994. }
  3995. /**
  3996. * Update the information elements in the display
  3997. * @param {object} settings dataTables settings object
  3998. * @memberof DataTable#oApi
  3999. */
  4000. function _fnUpdateInfo ( settings )
  4001. {
  4002. /* Show information about the table */
  4003. var nodes = settings.aanFeatures.i;
  4004. if ( nodes.length === 0 ) {
  4005. return;
  4006. }
  4007. var
  4008. lang = settings.oLanguage,
  4009. start = settings._iDisplayStart+1,
  4010. end = settings.fnDisplayEnd(),
  4011. max = settings.fnRecordsTotal(),
  4012. total = settings.fnRecordsDisplay(),
  4013. out = total ?
  4014. lang.sInfo :
  4015. lang.sInfoEmpty;
  4016. if ( total !== max ) {
  4017. /* Record set after filtering */
  4018. out += ' ' + lang.sInfoFiltered;
  4019. }
  4020. // Convert the macros
  4021. out += lang.sInfoPostFix;
  4022. out = _fnInfoMacros( settings, out );
  4023. var callback = lang.fnInfoCallback;
  4024. if ( callback !== null ) {
  4025. out = callback.call( settings.oInstance,
  4026. settings, start, end, max, total, out
  4027. );
  4028. }
  4029. $(nodes).html( out );
  4030. }
  4031. function _fnInfoMacros ( settings, str )
  4032. {
  4033. // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
  4034. // internally
  4035. var
  4036. formatter = settings.fnFormatNumber,
  4037. start = settings._iDisplayStart+1,
  4038. len = settings._iDisplayLength,
  4039. vis = settings.fnRecordsDisplay(),
  4040. all = len === -1;
  4041. return str.
  4042. replace(/_START_/g, formatter.call( settings, start ) ).
  4043. replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
  4044. replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
  4045. replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
  4046. replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
  4047. replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
  4048. }
  4049. /**
  4050. * Draw the table for the first time, adding all required features
  4051. * @param {object} settings dataTables settings object
  4052. * @memberof DataTable#oApi
  4053. */
  4054. function _fnInitialise ( settings )
  4055. {
  4056. var i, iLen, iAjaxStart=settings.iInitDisplayStart;
  4057. var columns = settings.aoColumns, column;
  4058. var features = settings.oFeatures;
  4059. var deferLoading = settings.bDeferLoading; // value modified by the draw
  4060. /* Ensure that the table data is fully initialised */
  4061. if ( ! settings.bInitialised ) {
  4062. setTimeout( function(){ _fnInitialise( settings ); }, 200 );
  4063. return;
  4064. }
  4065. /* Show the display HTML options */
  4066. _fnAddOptionsHtml( settings );
  4067. /* Build and draw the header / footer for the table */
  4068. _fnBuildHead( settings );
  4069. _fnDrawHead( settings, settings.aoHeader );
  4070. _fnDrawHead( settings, settings.aoFooter );
  4071. /* Okay to show that something is going on now */
  4072. _fnProcessingDisplay( settings, true );
  4073. /* Calculate sizes for columns */
  4074. if ( features.bAutoWidth ) {
  4075. _fnCalculateColumnWidths( settings );
  4076. }
  4077. for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
  4078. column = columns[i];
  4079. if ( column.sWidth ) {
  4080. column.nTh.style.width = _fnStringToCss( column.sWidth );
  4081. }
  4082. }
  4083. _fnCallbackFire( settings, null, 'preInit', [settings] );
  4084. // If there is default sorting required - let's do it. The sort function
  4085. // will do the drawing for us. Otherwise we draw the table regardless of the
  4086. // Ajax source - this allows the table to look initialised for Ajax sourcing
  4087. // data (show 'loading' message possibly)
  4088. _fnReDraw( settings );
  4089. // Server-side processing init complete is done by _fnAjaxUpdateDraw
  4090. var dataSrc = _fnDataSource( settings );
  4091. if ( dataSrc != 'ssp' || deferLoading ) {
  4092. // if there is an ajax source load the data
  4093. if ( dataSrc == 'ajax' ) {
  4094. _fnBuildAjax( settings, [], function(json) {
  4095. var aData = _fnAjaxDataSrc( settings, json );
  4096. // Got the data - add it to the table
  4097. for ( i=0 ; i<aData.length ; i++ ) {
  4098. _fnAddData( settings, aData[i] );
  4099. }
  4100. // Reset the init display for cookie saving. We've already done
  4101. // a filter, and therefore cleared it before. So we need to make
  4102. // it appear 'fresh'
  4103. settings.iInitDisplayStart = iAjaxStart;
  4104. _fnReDraw( settings );
  4105. _fnProcessingDisplay( settings, false );
  4106. _fnInitComplete( settings, json );
  4107. }, settings );
  4108. }
  4109. else {
  4110. _fnProcessingDisplay( settings, false );
  4111. _fnInitComplete( settings );
  4112. }
  4113. }
  4114. }
  4115. /**
  4116. * Draw the table for the first time, adding all required features
  4117. * @param {object} oSettings dataTables settings object
  4118. * @param {object} [json] JSON from the server that completed the table, if using Ajax source
  4119. * with client-side processing (optional)
  4120. * @memberof DataTable#oApi
  4121. */
  4122. function _fnInitComplete ( settings, json )
  4123. {
  4124. settings._bInitComplete = true;
  4125. // When data was added after the initialisation (data or Ajax) we need to
  4126. // calculate the column sizing
  4127. if ( json || settings.oInit.aaData ) {
  4128. _fnAdjustColumnSizing( settings );
  4129. }
  4130. _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
  4131. _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
  4132. }
  4133. function _fnLengthChange ( settings, val )
  4134. {
  4135. var len = parseInt( val, 10 );
  4136. settings._iDisplayLength = len;
  4137. _fnLengthOverflow( settings );
  4138. // Fire length change event
  4139. _fnCallbackFire( settings, null, 'length', [settings, len] );
  4140. }
  4141. /**
  4142. * Generate the node required for user display length changing
  4143. * @param {object} settings dataTables settings object
  4144. * @returns {node} Display length feature node
  4145. * @memberof DataTable#oApi
  4146. */
  4147. function _fnFeatureHtmlLength ( settings )
  4148. {
  4149. var
  4150. classes = settings.oClasses,
  4151. tableId = settings.sTableId,
  4152. menu = settings.aLengthMenu,
  4153. d2 = $.isArray( menu[0] ),
  4154. lengths = d2 ? menu[0] : menu,
  4155. language = d2 ? menu[1] : menu;
  4156. var select = $('<select/>', {
  4157. 'name': tableId+'_length',
  4158. 'aria-controls': tableId,
  4159. 'class': classes.sLengthSelect
  4160. } );
  4161. for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
  4162. select[0][ i ] = new Option(
  4163. typeof language[i] === 'number' ?
  4164. settings.fnFormatNumber( language[i] ) :
  4165. language[i],
  4166. lengths[i]
  4167. );
  4168. }
  4169. var div = $('<div><label/></div>').addClass( classes.sLength );
  4170. if ( ! settings.aanFeatures.l ) {
  4171. div[0].id = tableId+'_length';
  4172. }
  4173. div.children().append(
  4174. settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
  4175. );
  4176. // Can't use `select` variable as user might provide their own and the
  4177. // reference is broken by the use of outerHTML
  4178. $('select', div)
  4179. .val( settings._iDisplayLength )
  4180. .on( 'change.DT', function(e) {
  4181. _fnLengthChange( settings, $(this).val() );
  4182. _fnDraw( settings );
  4183. } );
  4184. // Update node value whenever anything changes the table's length
  4185. $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
  4186. if ( settings === s ) {
  4187. $('select', div).val( len );
  4188. }
  4189. } );
  4190. return div[0];
  4191. }
  4192. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4193. * Note that most of the paging logic is done in
  4194. * DataTable.ext.pager
  4195. */
  4196. /**
  4197. * Generate the node required for default pagination
  4198. * @param {object} oSettings dataTables settings object
  4199. * @returns {node} Pagination feature node
  4200. * @memberof DataTable#oApi
  4201. */
  4202. function _fnFeatureHtmlPaginate ( settings )
  4203. {
  4204. var
  4205. type = settings.sPaginationType,
  4206. plugin = DataTable.ext.pager[ type ],
  4207. modern = typeof plugin === 'function',
  4208. redraw = function( settings ) {
  4209. _fnDraw( settings );
  4210. },
  4211. node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
  4212. features = settings.aanFeatures;
  4213. if ( ! modern ) {
  4214. plugin.fnInit( settings, node, redraw );
  4215. }
  4216. /* Add a draw callback for the pagination on first instance, to update the paging display */
  4217. if ( ! features.p )
  4218. {
  4219. node.id = settings.sTableId+'_paginate';
  4220. settings.aoDrawCallback.push( {
  4221. "fn": function( settings ) {
  4222. if ( modern ) {
  4223. var
  4224. start = settings._iDisplayStart,
  4225. len = settings._iDisplayLength,
  4226. visRecords = settings.fnRecordsDisplay(),
  4227. all = len === -1,
  4228. page = all ? 0 : Math.ceil( start / len ),
  4229. pages = all ? 1 : Math.ceil( visRecords / len ),
  4230. buttons = plugin(page, pages),
  4231. i, ien;
  4232. for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
  4233. _fnRenderer( settings, 'pageButton' )(
  4234. settings, features.p[i], i, buttons, page, pages
  4235. );
  4236. }
  4237. }
  4238. else {
  4239. plugin.fnUpdate( settings, redraw );
  4240. }
  4241. },
  4242. "sName": "pagination"
  4243. } );
  4244. }
  4245. return node;
  4246. }
  4247. /**
  4248. * Alter the display settings to change the page
  4249. * @param {object} settings DataTables settings object
  4250. * @param {string|int} action Paging action to take: "first", "previous",
  4251. * "next" or "last" or page number to jump to (integer)
  4252. * @param [bool] redraw Automatically draw the update or not
  4253. * @returns {bool} true page has changed, false - no change
  4254. * @memberof DataTable#oApi
  4255. */
  4256. function _fnPageChange ( settings, action, redraw )
  4257. {
  4258. var
  4259. start = settings._iDisplayStart,
  4260. len = settings._iDisplayLength,
  4261. records = settings.fnRecordsDisplay();
  4262. if ( records === 0 || len === -1 )
  4263. {
  4264. start = 0;
  4265. }
  4266. else if ( typeof action === "number" )
  4267. {
  4268. start = action * len;
  4269. if ( start > records )
  4270. {
  4271. start = 0;
  4272. }
  4273. }
  4274. else if ( action == "first" )
  4275. {
  4276. start = 0;
  4277. }
  4278. else if ( action == "previous" )
  4279. {
  4280. start = len >= 0 ?
  4281. start - len :
  4282. 0;
  4283. if ( start < 0 )
  4284. {
  4285. start = 0;
  4286. }
  4287. }
  4288. else if ( action == "next" )
  4289. {
  4290. if ( start + len < records )
  4291. {
  4292. start += len;
  4293. }
  4294. }
  4295. else if ( action == "last" )
  4296. {
  4297. start = Math.floor( (records-1) / len) * len;
  4298. }
  4299. else
  4300. {
  4301. _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
  4302. }
  4303. var changed = settings._iDisplayStart !== start;
  4304. settings._iDisplayStart = start;
  4305. if ( changed ) {
  4306. _fnCallbackFire( settings, null, 'page', [settings] );
  4307. if ( redraw ) {
  4308. _fnDraw( settings );
  4309. }
  4310. }
  4311. return changed;
  4312. }
  4313. /**
  4314. * Generate the node required for the processing node
  4315. * @param {object} settings dataTables settings object
  4316. * @returns {node} Processing element
  4317. * @memberof DataTable#oApi
  4318. */
  4319. function _fnFeatureHtmlProcessing ( settings )
  4320. {
  4321. return $('<div/>', {
  4322. 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
  4323. 'class': settings.oClasses.sProcessing
  4324. } )
  4325. .html( settings.oLanguage.sProcessing )
  4326. .insertBefore( settings.nTable )[0];
  4327. }
  4328. /**
  4329. * Display or hide the processing indicator
  4330. * @param {object} settings dataTables settings object
  4331. * @param {bool} show Show the processing indicator (true) or not (false)
  4332. * @memberof DataTable#oApi
  4333. */
  4334. function _fnProcessingDisplay ( settings, show )
  4335. {
  4336. if ( settings.oFeatures.bProcessing ) {
  4337. $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
  4338. }
  4339. _fnCallbackFire( settings, null, 'processing', [settings, show] );
  4340. }
  4341. /**
  4342. * Add any control elements for the table - specifically scrolling
  4343. * @param {object} settings dataTables settings object
  4344. * @returns {node} Node to add to the DOM
  4345. * @memberof DataTable#oApi
  4346. */
  4347. function _fnFeatureHtmlTable ( settings )
  4348. {
  4349. var table = $(settings.nTable);
  4350. // Add the ARIA grid role to the table
  4351. table.attr( 'role', 'grid' );
  4352. // Scrolling from here on in
  4353. var scroll = settings.oScroll;
  4354. if ( scroll.sX === '' && scroll.sY === '' ) {
  4355. return settings.nTable;
  4356. }
  4357. var scrollX = scroll.sX;
  4358. var scrollY = scroll.sY;
  4359. var classes = settings.oClasses;
  4360. var caption = table.children('caption');
  4361. var captionSide = caption.length ? caption[0]._captionSide : null;
  4362. var headerClone = $( table[0].cloneNode(false) );
  4363. var footerClone = $( table[0].cloneNode(false) );
  4364. var footer = table.children('tfoot');
  4365. var _div = '<div/>';
  4366. var size = function ( s ) {
  4367. return !s ? null : _fnStringToCss( s );
  4368. };
  4369. if ( ! footer.length ) {
  4370. footer = null;
  4371. }
  4372. /*
  4373. * The HTML structure that we want to generate in this function is:
  4374. * div - scroller
  4375. * div - scroll head
  4376. * div - scroll head inner
  4377. * table - scroll head table
  4378. * thead - thead
  4379. * div - scroll body
  4380. * table - table (master table)
  4381. * thead - thead clone for sizing
  4382. * tbody - tbody
  4383. * div - scroll foot
  4384. * div - scroll foot inner
  4385. * table - scroll foot table
  4386. * tfoot - tfoot
  4387. */
  4388. var scroller = $( _div, { 'class': classes.sScrollWrapper } )
  4389. .append(
  4390. $(_div, { 'class': classes.sScrollHead } )
  4391. .css( {
  4392. overflow: 'hidden',
  4393. position: 'relative',
  4394. border: 0,
  4395. width: scrollX ? size(scrollX) : '100%'
  4396. } )
  4397. .append(
  4398. $(_div, { 'class': classes.sScrollHeadInner } )
  4399. .css( {
  4400. 'box-sizing': 'content-box',
  4401. width: scroll.sXInner || '100%'
  4402. } )
  4403. .append(
  4404. headerClone
  4405. .removeAttr('id')
  4406. .css( 'margin-left', 0 )
  4407. .append( captionSide === 'top' ? caption : null )
  4408. .append(
  4409. table.children('thead')
  4410. )
  4411. )
  4412. )
  4413. )
  4414. .append(
  4415. $(_div, { 'class': classes.sScrollBody } )
  4416. .css( {
  4417. position: 'relative',
  4418. overflow: 'auto',
  4419. width: size( scrollX )
  4420. } )
  4421. .append( table )
  4422. );
  4423. if ( footer ) {
  4424. scroller.append(
  4425. $(_div, { 'class': classes.sScrollFoot } )
  4426. .css( {
  4427. overflow: 'hidden',
  4428. border: 0,
  4429. width: scrollX ? size(scrollX) : '100%'
  4430. } )
  4431. .append(
  4432. $(_div, { 'class': classes.sScrollFootInner } )
  4433. .append(
  4434. footerClone
  4435. .removeAttr('id')
  4436. .css( 'margin-left', 0 )
  4437. .append( captionSide === 'bottom' ? caption : null )
  4438. .append(
  4439. table.children('tfoot')
  4440. )
  4441. )
  4442. )
  4443. );
  4444. }
  4445. var children = scroller.children();
  4446. var scrollHead = children[0];
  4447. var scrollBody = children[1];
  4448. var scrollFoot = footer ? children[2] : null;
  4449. // When the body is scrolled, then we also want to scroll the headers
  4450. if ( scrollX ) {
  4451. $(scrollBody).on( 'scroll.DT', function (e) {
  4452. var scrollLeft = this.scrollLeft;
  4453. scrollHead.scrollLeft = scrollLeft;
  4454. if ( footer ) {
  4455. scrollFoot.scrollLeft = scrollLeft;
  4456. }
  4457. } );
  4458. }
  4459. $(scrollBody).css(
  4460. scrollY && scroll.bCollapse ? 'max-height' : 'height',
  4461. scrollY
  4462. );
  4463. settings.nScrollHead = scrollHead;
  4464. settings.nScrollBody = scrollBody;
  4465. settings.nScrollFoot = scrollFoot;
  4466. // On redraw - align columns
  4467. settings.aoDrawCallback.push( {
  4468. "fn": _fnScrollDraw,
  4469. "sName": "scrolling"
  4470. } );
  4471. return scroller[0];
  4472. }
  4473. /**
  4474. * Update the header, footer and body tables for resizing - i.e. column
  4475. * alignment.
  4476. *
  4477. * Welcome to the most horrible function DataTables. The process that this
  4478. * function follows is basically:
  4479. * 1. Re-create the table inside the scrolling div
  4480. * 2. Take live measurements from the DOM
  4481. * 3. Apply the measurements to align the columns
  4482. * 4. Clean up
  4483. *
  4484. * @param {object} settings dataTables settings object
  4485. * @memberof DataTable#oApi
  4486. */
  4487. function _fnScrollDraw ( settings )
  4488. {
  4489. // Given that this is such a monster function, a lot of variables are use
  4490. // to try and keep the minimised size as small as possible
  4491. var
  4492. scroll = settings.oScroll,
  4493. scrollX = scroll.sX,
  4494. scrollXInner = scroll.sXInner,
  4495. scrollY = scroll.sY,
  4496. barWidth = scroll.iBarWidth,
  4497. divHeader = $(settings.nScrollHead),
  4498. divHeaderStyle = divHeader[0].style,
  4499. divHeaderInner = divHeader.children('div'),
  4500. divHeaderInnerStyle = divHeaderInner[0].style,
  4501. divHeaderTable = divHeaderInner.children('table'),
  4502. divBodyEl = settings.nScrollBody,
  4503. divBody = $(divBodyEl),
  4504. divBodyStyle = divBodyEl.style,
  4505. divFooter = $(settings.nScrollFoot),
  4506. divFooterInner = divFooter.children('div'),
  4507. divFooterTable = divFooterInner.children('table'),
  4508. header = $(settings.nTHead),
  4509. table = $(settings.nTable),
  4510. tableEl = table[0],
  4511. tableStyle = tableEl.style,
  4512. footer = settings.nTFoot ? $(settings.nTFoot) : null,
  4513. browser = settings.oBrowser,
  4514. ie67 = browser.bScrollOversize,
  4515. dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
  4516. headerTrgEls, footerTrgEls,
  4517. headerSrcEls, footerSrcEls,
  4518. headerCopy, footerCopy,
  4519. headerWidths=[], footerWidths=[],
  4520. headerContent=[], footerContent=[],
  4521. idx, correction, sanityWidth,
  4522. zeroOut = function(nSizer) {
  4523. var style = nSizer.style;
  4524. style.paddingTop = "0";
  4525. style.paddingBottom = "0";
  4526. style.borderTopWidth = "0";
  4527. style.borderBottomWidth = "0";
  4528. style.height = 0;
  4529. };
  4530. // If the scrollbar visibility has changed from the last draw, we need to
  4531. // adjust the column sizes as the table width will have changed to account
  4532. // for the scrollbar
  4533. var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
  4534. if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
  4535. settings.scrollBarVis = scrollBarVis;
  4536. _fnAdjustColumnSizing( settings );
  4537. return; // adjust column sizing will call this function again
  4538. }
  4539. else {
  4540. settings.scrollBarVis = scrollBarVis;
  4541. }
  4542. /*
  4543. * 1. Re-create the table inside the scrolling div
  4544. */
  4545. // Remove the old minimised thead and tfoot elements in the inner table
  4546. table.children('thead, tfoot').remove();
  4547. if ( footer ) {
  4548. footerCopy = footer.clone().prependTo( table );
  4549. footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
  4550. footerSrcEls = footerCopy.find('tr');
  4551. }
  4552. // Clone the current header and footer elements and then place it into the inner table
  4553. headerCopy = header.clone().prependTo( table );
  4554. headerTrgEls = header.find('tr'); // original header is in its own table
  4555. headerSrcEls = headerCopy.find('tr');
  4556. headerCopy.find('th, td').removeAttr('tabindex');
  4557. /*
  4558. * 2. Take live measurements from the DOM - do not alter the DOM itself!
  4559. */
  4560. // Remove old sizing and apply the calculated column widths
  4561. // Get the unique column headers in the newly created (cloned) header. We want to apply the
  4562. // calculated sizes to this header
  4563. if ( ! scrollX )
  4564. {
  4565. divBodyStyle.width = '100%';
  4566. divHeader[0].style.width = '100%';
  4567. }
  4568. $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
  4569. idx = _fnVisibleToColumnIndex( settings, i );
  4570. el.style.width = settings.aoColumns[idx].sWidth;
  4571. } );
  4572. if ( footer ) {
  4573. _fnApplyToChildren( function(n) {
  4574. n.style.width = "";
  4575. }, footerSrcEls );
  4576. }
  4577. // Size the table as a whole
  4578. sanityWidth = table.outerWidth();
  4579. if ( scrollX === "" ) {
  4580. // No x scrolling
  4581. tableStyle.width = "100%";
  4582. // IE7 will make the width of the table when 100% include the scrollbar
  4583. // - which is shouldn't. When there is a scrollbar we need to take this
  4584. // into account.
  4585. if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
  4586. divBody.css('overflow-y') == "scroll")
  4587. ) {
  4588. tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
  4589. }
  4590. // Recalculate the sanity width
  4591. sanityWidth = table.outerWidth();
  4592. }
  4593. else if ( scrollXInner !== "" ) {
  4594. // legacy x scroll inner has been given - use it
  4595. tableStyle.width = _fnStringToCss(scrollXInner);
  4596. // Recalculate the sanity width
  4597. sanityWidth = table.outerWidth();
  4598. }
  4599. // Hidden header should have zero height, so remove padding and borders. Then
  4600. // set the width based on the real headers
  4601. // Apply all styles in one pass
  4602. _fnApplyToChildren( zeroOut, headerSrcEls );
  4603. // Read all widths in next pass
  4604. _fnApplyToChildren( function(nSizer) {
  4605. headerContent.push( nSizer.innerHTML );
  4606. headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
  4607. }, headerSrcEls );
  4608. // Apply all widths in final pass
  4609. _fnApplyToChildren( function(nToSize, i) {
  4610. // Only apply widths to the DataTables detected header cells - this
  4611. // prevents complex headers from having contradictory sizes applied
  4612. if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
  4613. nToSize.style.width = headerWidths[i];
  4614. }
  4615. }, headerTrgEls );
  4616. $(headerSrcEls).height(0);
  4617. /* Same again with the footer if we have one */
  4618. if ( footer )
  4619. {
  4620. _fnApplyToChildren( zeroOut, footerSrcEls );
  4621. _fnApplyToChildren( function(nSizer) {
  4622. footerContent.push( nSizer.innerHTML );
  4623. footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
  4624. }, footerSrcEls );
  4625. _fnApplyToChildren( function(nToSize, i) {
  4626. nToSize.style.width = footerWidths[i];
  4627. }, footerTrgEls );
  4628. $(footerSrcEls).height(0);
  4629. }
  4630. /*
  4631. * 3. Apply the measurements
  4632. */
  4633. // "Hide" the header and footer that we used for the sizing. We need to keep
  4634. // the content of the cell so that the width applied to the header and body
  4635. // both match, but we want to hide it completely. We want to also fix their
  4636. // width to what they currently are
  4637. _fnApplyToChildren( function(nSizer, i) {
  4638. nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
  4639. nSizer.style.width = headerWidths[i];
  4640. }, headerSrcEls );
  4641. if ( footer )
  4642. {
  4643. _fnApplyToChildren( function(nSizer, i) {
  4644. nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
  4645. nSizer.style.width = footerWidths[i];
  4646. }, footerSrcEls );
  4647. }
  4648. // Sanity check that the table is of a sensible width. If not then we are going to get
  4649. // misalignment - try to prevent this by not allowing the table to shrink below its min width
  4650. if ( table.outerWidth() < sanityWidth )
  4651. {
  4652. // The min width depends upon if we have a vertical scrollbar visible or not */
  4653. correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
  4654. divBody.css('overflow-y') == "scroll")) ?
  4655. sanityWidth+barWidth :
  4656. sanityWidth;
  4657. // IE6/7 are a law unto themselves...
  4658. if ( ie67 && (divBodyEl.scrollHeight >
  4659. divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
  4660. ) {
  4661. tableStyle.width = _fnStringToCss( correction-barWidth );
  4662. }
  4663. // And give the user a warning that we've stopped the table getting too small
  4664. if ( scrollX === "" || scrollXInner !== "" ) {
  4665. _fnLog( settings, 1, 'Possible column misalignment', 6 );
  4666. }
  4667. }
  4668. else
  4669. {
  4670. correction = '100%';
  4671. }
  4672. // Apply to the container elements
  4673. divBodyStyle.width = _fnStringToCss( correction );
  4674. divHeaderStyle.width = _fnStringToCss( correction );
  4675. if ( footer ) {
  4676. settings.nScrollFoot.style.width = _fnStringToCss( correction );
  4677. }
  4678. /*
  4679. * 4. Clean up
  4680. */
  4681. if ( ! scrollY ) {
  4682. /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
  4683. * the scrollbar height from the visible display, rather than adding it on. We need to
  4684. * set the height in order to sort this. Don't want to do it in any other browsers.
  4685. */
  4686. if ( ie67 ) {
  4687. divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
  4688. }
  4689. }
  4690. /* Finally set the width's of the header and footer tables */
  4691. var iOuterWidth = table.outerWidth();
  4692. divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
  4693. divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
  4694. // Figure out if there are scrollbar present - if so then we need a the header and footer to
  4695. // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
  4696. var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
  4697. var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
  4698. divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
  4699. if ( footer ) {
  4700. divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
  4701. divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
  4702. divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
  4703. }
  4704. // Correct DOM ordering for colgroup - comes before the thead
  4705. table.children('colgroup').insertBefore( table.children('thead') );
  4706. /* Adjust the position of the header in case we loose the y-scrollbar */
  4707. divBody.scroll();
  4708. // If sorting or filtering has occurred, jump the scrolling back to the top
  4709. // only if we aren't holding the position
  4710. if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
  4711. divBodyEl.scrollTop = 0;
  4712. }
  4713. }
  4714. /**
  4715. * Apply a given function to the display child nodes of an element array (typically
  4716. * TD children of TR rows
  4717. * @param {function} fn Method to apply to the objects
  4718. * @param array {nodes} an1 List of elements to look through for display children
  4719. * @param array {nodes} an2 Another list (identical structure to the first) - optional
  4720. * @memberof DataTable#oApi
  4721. */
  4722. function _fnApplyToChildren( fn, an1, an2 )
  4723. {
  4724. var index=0, i=0, iLen=an1.length;
  4725. var nNode1, nNode2;
  4726. while ( i < iLen ) {
  4727. nNode1 = an1[i].firstChild;
  4728. nNode2 = an2 ? an2[i].firstChild : null;
  4729. while ( nNode1 ) {
  4730. if ( nNode1.nodeType === 1 ) {
  4731. if ( an2 ) {
  4732. fn( nNode1, nNode2, index );
  4733. }
  4734. else {
  4735. fn( nNode1, index );
  4736. }
  4737. index++;
  4738. }
  4739. nNode1 = nNode1.nextSibling;
  4740. nNode2 = an2 ? nNode2.nextSibling : null;
  4741. }
  4742. i++;
  4743. }
  4744. }
  4745. var __re_html_remove = /<.*?>/g;
  4746. /**
  4747. * Calculate the width of columns for the table
  4748. * @param {object} oSettings dataTables settings object
  4749. * @memberof DataTable#oApi
  4750. */
  4751. function _fnCalculateColumnWidths ( oSettings )
  4752. {
  4753. var
  4754. table = oSettings.nTable,
  4755. columns = oSettings.aoColumns,
  4756. scroll = oSettings.oScroll,
  4757. scrollY = scroll.sY,
  4758. scrollX = scroll.sX,
  4759. scrollXInner = scroll.sXInner,
  4760. columnCount = columns.length,
  4761. visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
  4762. headerCells = $('th', oSettings.nTHead),
  4763. tableWidthAttr = table.getAttribute('width'), // from DOM element
  4764. tableContainer = table.parentNode,
  4765. userInputs = false,
  4766. i, column, columnIdx, width, outerWidth,
  4767. browser = oSettings.oBrowser,
  4768. ie67 = browser.bScrollOversize;
  4769. var styleWidth = table.style.width;
  4770. if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
  4771. tableWidthAttr = styleWidth;
  4772. }
  4773. /* Convert any user input sizes into pixel sizes */
  4774. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4775. column = columns[ visibleColumns[i] ];
  4776. if ( column.sWidth !== null ) {
  4777. column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
  4778. userInputs = true;
  4779. }
  4780. }
  4781. /* If the number of columns in the DOM equals the number that we have to
  4782. * process in DataTables, then we can use the offsets that are created by
  4783. * the web- browser. No custom sizes can be set in order for this to happen,
  4784. * nor scrolling used
  4785. */
  4786. if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
  4787. columnCount == _fnVisbleColumns( oSettings ) &&
  4788. columnCount == headerCells.length
  4789. ) {
  4790. for ( i=0 ; i<columnCount ; i++ ) {
  4791. var colIdx = _fnVisibleToColumnIndex( oSettings, i );
  4792. if ( colIdx !== null ) {
  4793. columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
  4794. }
  4795. }
  4796. }
  4797. else
  4798. {
  4799. // Otherwise construct a single row, worst case, table with the widest
  4800. // node in the data, assign any user defined widths, then insert it into
  4801. // the DOM and allow the browser to do all the hard work of calculating
  4802. // table widths
  4803. var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
  4804. .css( 'visibility', 'hidden' )
  4805. .removeAttr( 'id' );
  4806. // Clean up the table body
  4807. tmpTable.find('tbody tr').remove();
  4808. var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
  4809. // Clone the table header and footer - we can't use the header / footer
  4810. // from the cloned table, since if scrolling is active, the table's
  4811. // real header and footer are contained in different table tags
  4812. tmpTable.find('thead, tfoot').remove();
  4813. tmpTable
  4814. .append( $(oSettings.nTHead).clone() )
  4815. .append( $(oSettings.nTFoot).clone() );
  4816. // Remove any assigned widths from the footer (from scrolling)
  4817. tmpTable.find('tfoot th, tfoot td').css('width', '');
  4818. // Apply custom sizing to the cloned header
  4819. headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
  4820. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4821. column = columns[ visibleColumns[i] ];
  4822. headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
  4823. _fnStringToCss( column.sWidthOrig ) :
  4824. '';
  4825. // For scrollX we need to force the column width otherwise the
  4826. // browser will collapse it. If this width is smaller than the
  4827. // width the column requires, then it will have no effect
  4828. if ( column.sWidthOrig && scrollX ) {
  4829. $( headerCells[i] ).append( $('<div/>').css( {
  4830. width: column.sWidthOrig,
  4831. margin: 0,
  4832. padding: 0,
  4833. border: 0,
  4834. height: 1
  4835. } ) );
  4836. }
  4837. }
  4838. // Find the widest cell for each column and put it into the table
  4839. if ( oSettings.aoData.length ) {
  4840. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4841. columnIdx = visibleColumns[i];
  4842. column = columns[ columnIdx ];
  4843. $( _fnGetWidestNode( oSettings, columnIdx ) )
  4844. .clone( false )
  4845. .append( column.sContentPadding )
  4846. .appendTo( tr );
  4847. }
  4848. }
  4849. // Tidy the temporary table - remove name attributes so there aren't
  4850. // duplicated in the dom (radio elements for example)
  4851. $('[name]', tmpTable).removeAttr('name');
  4852. // Table has been built, attach to the document so we can work with it.
  4853. // A holding element is used, positioned at the top of the container
  4854. // with minimal height, so it has no effect on if the container scrolls
  4855. // or not. Otherwise it might trigger scrolling when it actually isn't
  4856. // needed
  4857. var holder = $('<div/>').css( scrollX || scrollY ?
  4858. {
  4859. position: 'absolute',
  4860. top: 0,
  4861. left: 0,
  4862. height: 1,
  4863. right: 0,
  4864. overflow: 'hidden'
  4865. } :
  4866. {}
  4867. )
  4868. .append( tmpTable )
  4869. .appendTo( tableContainer );
  4870. // When scrolling (X or Y) we want to set the width of the table as
  4871. // appropriate. However, when not scrolling leave the table width as it
  4872. // is. This results in slightly different, but I think correct behaviour
  4873. if ( scrollX && scrollXInner ) {
  4874. tmpTable.width( scrollXInner );
  4875. }
  4876. else if ( scrollX ) {
  4877. tmpTable.css( 'width', 'auto' );
  4878. tmpTable.removeAttr('width');
  4879. // If there is no width attribute or style, then allow the table to
  4880. // collapse
  4881. if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
  4882. tmpTable.width( tableContainer.clientWidth );
  4883. }
  4884. }
  4885. else if ( scrollY ) {
  4886. tmpTable.width( tableContainer.clientWidth );
  4887. }
  4888. else if ( tableWidthAttr ) {
  4889. tmpTable.width( tableWidthAttr );
  4890. }
  4891. // Get the width of each column in the constructed table - we need to
  4892. // know the inner width (so it can be assigned to the other table's
  4893. // cells) and the outer width so we can calculate the full width of the
  4894. // table. This is safe since DataTables requires a unique cell for each
  4895. // column, but if ever a header can span multiple columns, this will
  4896. // need to be modified.
  4897. var total = 0;
  4898. for ( i=0 ; i<visibleColumns.length ; i++ ) {
  4899. var cell = $(headerCells[i]);
  4900. var border = cell.outerWidth() - cell.width();
  4901. // Use getBounding... where possible (not IE8-) because it can give
  4902. // sub-pixel accuracy, which we then want to round up!
  4903. var bounding = browser.bBounding ?
  4904. Math.ceil( headerCells[i].getBoundingClientRect().width ) :
  4905. cell.outerWidth();
  4906. // Total is tracked to remove any sub-pixel errors as the outerWidth
  4907. // of the table might not equal the total given here (IE!).
  4908. total += bounding;
  4909. // Width for each column to use
  4910. columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
  4911. }
  4912. table.style.width = _fnStringToCss( total );
  4913. // Finished with the table - ditch it
  4914. holder.remove();
  4915. }
  4916. // If there is a width attr, we want to attach an event listener which
  4917. // allows the table sizing to automatically adjust when the window is
  4918. // resized. Use the width attr rather than CSS, since we can't know if the
  4919. // CSS is a relative value or absolute - DOM read is always px.
  4920. if ( tableWidthAttr ) {
  4921. table.style.width = _fnStringToCss( tableWidthAttr );
  4922. }
  4923. if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
  4924. var bindResize = function () {
  4925. $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
  4926. _fnAdjustColumnSizing( oSettings );
  4927. } ) );
  4928. };
  4929. // IE6/7 will crash if we bind a resize event handler on page load.
  4930. // To be removed in 1.11 which drops IE6/7 support
  4931. if ( ie67 ) {
  4932. setTimeout( bindResize, 1000 );
  4933. }
  4934. else {
  4935. bindResize();
  4936. }
  4937. oSettings._reszEvt = true;
  4938. }
  4939. }
  4940. /**
  4941. * Throttle the calls to a function. Arguments and context are maintained for
  4942. * the throttled function
  4943. * @param {function} fn Function to be called
  4944. * @param {int} [freq=200] call frequency in mS
  4945. * @returns {function} wrapped function
  4946. * @memberof DataTable#oApi
  4947. */
  4948. var _fnThrottle = DataTable.util.throttle;
  4949. /**
  4950. * Convert a CSS unit width to pixels (e.g. 2em)
  4951. * @param {string} width width to be converted
  4952. * @param {node} parent parent to get the with for (required for relative widths) - optional
  4953. * @returns {int} width in pixels
  4954. * @memberof DataTable#oApi
  4955. */
  4956. function _fnConvertToWidth ( width, parent )
  4957. {
  4958. if ( ! width ) {
  4959. return 0;
  4960. }
  4961. var n = $('<div/>')
  4962. .css( 'width', _fnStringToCss( width ) )
  4963. .appendTo( parent || document.body );
  4964. var val = n[0].offsetWidth;
  4965. n.remove();
  4966. return val;
  4967. }
  4968. /**
  4969. * Get the widest node
  4970. * @param {object} settings dataTables settings object
  4971. * @param {int} colIdx column of interest
  4972. * @returns {node} widest table node
  4973. * @memberof DataTable#oApi
  4974. */
  4975. function _fnGetWidestNode( settings, colIdx )
  4976. {
  4977. var idx = _fnGetMaxLenString( settings, colIdx );
  4978. if ( idx < 0 ) {
  4979. return null;
  4980. }
  4981. var data = settings.aoData[ idx ];
  4982. return ! data.nTr ? // Might not have been created when deferred rendering
  4983. $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
  4984. data.anCells[ colIdx ];
  4985. }
  4986. /**
  4987. * Get the maximum strlen for each data column
  4988. * @param {object} settings dataTables settings object
  4989. * @param {int} colIdx column of interest
  4990. * @returns {string} max string length for each column
  4991. * @memberof DataTable#oApi
  4992. */
  4993. function _fnGetMaxLenString( settings, colIdx )
  4994. {
  4995. var s, max=-1, maxIdx = -1;
  4996. for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  4997. s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
  4998. s = s.replace( __re_html_remove, '' );
  4999. s = s.replace( /&nbsp;/g, ' ' );
  5000. if ( s.length > max ) {
  5001. max = s.length;
  5002. maxIdx = i;
  5003. }
  5004. }
  5005. return maxIdx;
  5006. }
  5007. /**
  5008. * Append a CSS unit (only if required) to a string
  5009. * @param {string} value to css-ify
  5010. * @returns {string} value with css unit
  5011. * @memberof DataTable#oApi
  5012. */
  5013. function _fnStringToCss( s )
  5014. {
  5015. if ( s === null ) {
  5016. return '0px';
  5017. }
  5018. if ( typeof s == 'number' ) {
  5019. return s < 0 ?
  5020. '0px' :
  5021. s+'px';
  5022. }
  5023. // Check it has a unit character already
  5024. return s.match(/\d$/) ?
  5025. s+'px' :
  5026. s;
  5027. }
  5028. function _fnSortFlatten ( settings )
  5029. {
  5030. var
  5031. i, iLen, k, kLen,
  5032. aSort = [],
  5033. aiOrig = [],
  5034. aoColumns = settings.aoColumns,
  5035. aDataSort, iCol, sType, srcCol,
  5036. fixed = settings.aaSortingFixed,
  5037. fixedObj = $.isPlainObject( fixed ),
  5038. nestedSort = [],
  5039. add = function ( a ) {
  5040. if ( a.length && ! $.isArray( a[0] ) ) {
  5041. // 1D array
  5042. nestedSort.push( a );
  5043. }
  5044. else {
  5045. // 2D array
  5046. $.merge( nestedSort, a );
  5047. }
  5048. };
  5049. // Build the sort array, with pre-fix and post-fix options if they have been
  5050. // specified
  5051. if ( $.isArray( fixed ) ) {
  5052. add( fixed );
  5053. }
  5054. if ( fixedObj && fixed.pre ) {
  5055. add( fixed.pre );
  5056. }
  5057. add( settings.aaSorting );
  5058. if (fixedObj && fixed.post ) {
  5059. add( fixed.post );
  5060. }
  5061. for ( i=0 ; i<nestedSort.length ; i++ )
  5062. {
  5063. srcCol = nestedSort[i][0];
  5064. aDataSort = aoColumns[ srcCol ].aDataSort;
  5065. for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
  5066. {
  5067. iCol = aDataSort[k];
  5068. sType = aoColumns[ iCol ].sType || 'string';
  5069. if ( nestedSort[i]._idx === undefined ) {
  5070. nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
  5071. }
  5072. aSort.push( {
  5073. src: srcCol,
  5074. col: iCol,
  5075. dir: nestedSort[i][1],
  5076. index: nestedSort[i]._idx,
  5077. type: sType,
  5078. formatter: DataTable.ext.type.order[ sType+"-pre" ]
  5079. } );
  5080. }
  5081. }
  5082. return aSort;
  5083. }
  5084. /**
  5085. * Change the order of the table
  5086. * @param {object} oSettings dataTables settings object
  5087. * @memberof DataTable#oApi
  5088. * @todo This really needs split up!
  5089. */
  5090. function _fnSort ( oSettings )
  5091. {
  5092. var
  5093. i, ien, iLen, j, jLen, k, kLen,
  5094. sDataType, nTh,
  5095. aiOrig = [],
  5096. oExtSort = DataTable.ext.type.order,
  5097. aoData = oSettings.aoData,
  5098. aoColumns = oSettings.aoColumns,
  5099. aDataSort, data, iCol, sType, oSort,
  5100. formatters = 0,
  5101. sortCol,
  5102. displayMaster = oSettings.aiDisplayMaster,
  5103. aSort;
  5104. // Resolve any column types that are unknown due to addition or invalidation
  5105. // @todo Can this be moved into a 'data-ready' handler which is called when
  5106. // data is going to be used in the table?
  5107. _fnColumnTypes( oSettings );
  5108. aSort = _fnSortFlatten( oSettings );
  5109. for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
  5110. sortCol = aSort[i];
  5111. // Track if we can use the fast sort algorithm
  5112. if ( sortCol.formatter ) {
  5113. formatters++;
  5114. }
  5115. // Load the data needed for the sort, for each cell
  5116. _fnSortData( oSettings, sortCol.col );
  5117. }
  5118. /* No sorting required if server-side or no sorting array */
  5119. if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
  5120. {
  5121. // Create a value - key array of the current row positions such that we can use their
  5122. // current position during the sort, if values match, in order to perform stable sorting
  5123. for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
  5124. aiOrig[ displayMaster[i] ] = i;
  5125. }
  5126. /* Do the sort - here we want multi-column sorting based on a given data source (column)
  5127. * and sorting function (from oSort) in a certain direction. It's reasonably complex to
  5128. * follow on it's own, but this is what we want (example two column sorting):
  5129. * fnLocalSorting = function(a,b){
  5130. * var iTest;
  5131. * iTest = oSort['string-asc']('data11', 'data12');
  5132. * if (iTest !== 0)
  5133. * return iTest;
  5134. * iTest = oSort['numeric-desc']('data21', 'data22');
  5135. * if (iTest !== 0)
  5136. * return iTest;
  5137. * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
  5138. * }
  5139. * Basically we have a test for each sorting column, if the data in that column is equal,
  5140. * test the next column. If all columns match, then we use a numeric sort on the row
  5141. * positions in the original data array to provide a stable sort.
  5142. *
  5143. * Note - I know it seems excessive to have two sorting methods, but the first is around
  5144. * 15% faster, so the second is only maintained for backwards compatibility with sorting
  5145. * methods which do not have a pre-sort formatting function.
  5146. */
  5147. if ( formatters === aSort.length ) {
  5148. // All sort types have formatting functions
  5149. displayMaster.sort( function ( a, b ) {
  5150. var
  5151. x, y, k, test, sort,
  5152. len=aSort.length,
  5153. dataA = aoData[a]._aSortData,
  5154. dataB = aoData[b]._aSortData;
  5155. for ( k=0 ; k<len ; k++ ) {
  5156. sort = aSort[k];
  5157. x = dataA[ sort.col ];
  5158. y = dataB[ sort.col ];
  5159. test = x<y ? -1 : x>y ? 1 : 0;
  5160. if ( test !== 0 ) {
  5161. return sort.dir === 'asc' ? test : -test;
  5162. }
  5163. }
  5164. x = aiOrig[a];
  5165. y = aiOrig[b];
  5166. return x<y ? -1 : x>y ? 1 : 0;
  5167. } );
  5168. }
  5169. else {
  5170. // Depreciated - remove in 1.11 (providing a plug-in option)
  5171. // Not all sort types have formatting methods, so we have to call their sorting
  5172. // methods.
  5173. displayMaster.sort( function ( a, b ) {
  5174. var
  5175. x, y, k, l, test, sort, fn,
  5176. len=aSort.length,
  5177. dataA = aoData[a]._aSortData,
  5178. dataB = aoData[b]._aSortData;
  5179. for ( k=0 ; k<len ; k++ ) {
  5180. sort = aSort[k];
  5181. x = dataA[ sort.col ];
  5182. y = dataB[ sort.col ];
  5183. fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
  5184. test = fn( x, y );
  5185. if ( test !== 0 ) {
  5186. return test;
  5187. }
  5188. }
  5189. x = aiOrig[a];
  5190. y = aiOrig[b];
  5191. return x<y ? -1 : x>y ? 1 : 0;
  5192. } );
  5193. }
  5194. }
  5195. /* Tell the draw function that we have sorted the data */
  5196. oSettings.bSorted = true;
  5197. }
  5198. function _fnSortAria ( settings )
  5199. {
  5200. var label;
  5201. var nextSort;
  5202. var columns = settings.aoColumns;
  5203. var aSort = _fnSortFlatten( settings );
  5204. var oAria = settings.oLanguage.oAria;
  5205. // ARIA attributes - need to loop all columns, to update all (removing old
  5206. // attributes as needed)
  5207. for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
  5208. {
  5209. var col = columns[i];
  5210. var asSorting = col.asSorting;
  5211. var sTitle = col.sTitle.replace( /<.*?>/g, "" );
  5212. var th = col.nTh;
  5213. // IE7 is throwing an error when setting these properties with jQuery's
  5214. // attr() and removeAttr() methods...
  5215. th.removeAttribute('aria-sort');
  5216. /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
  5217. if ( col.bSortable ) {
  5218. if ( aSort.length > 0 && aSort[0].col == i ) {
  5219. th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
  5220. nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
  5221. }
  5222. else {
  5223. nextSort = asSorting[0];
  5224. }
  5225. label = sTitle + ( nextSort === "asc" ?
  5226. oAria.sSortAscending :
  5227. oAria.sSortDescending
  5228. );
  5229. }
  5230. else {
  5231. label = sTitle;
  5232. }
  5233. th.setAttribute('aria-label', label);
  5234. }
  5235. }
  5236. /**
  5237. * Function to run on user sort request
  5238. * @param {object} settings dataTables settings object
  5239. * @param {node} attachTo node to attach the handler to
  5240. * @param {int} colIdx column sorting index
  5241. * @param {boolean} [append=false] Append the requested sort to the existing
  5242. * sort if true (i.e. multi-column sort)
  5243. * @param {function} [callback] callback function
  5244. * @memberof DataTable#oApi
  5245. */
  5246. function _fnSortListener ( settings, colIdx, append, callback )
  5247. {
  5248. var col = settings.aoColumns[ colIdx ];
  5249. var sorting = settings.aaSorting;
  5250. var asSorting = col.asSorting;
  5251. var nextSortIdx;
  5252. var next = function ( a, overflow ) {
  5253. var idx = a._idx;
  5254. if ( idx === undefined ) {
  5255. idx = $.inArray( a[1], asSorting );
  5256. }
  5257. return idx+1 < asSorting.length ?
  5258. idx+1 :
  5259. overflow ?
  5260. null :
  5261. 0;
  5262. };
  5263. // Convert to 2D array if needed
  5264. if ( typeof sorting[0] === 'number' ) {
  5265. sorting = settings.aaSorting = [ sorting ];
  5266. }
  5267. // If appending the sort then we are multi-column sorting
  5268. if ( append && settings.oFeatures.bSortMulti ) {
  5269. // Are we already doing some kind of sort on this column?
  5270. var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
  5271. if ( sortIdx !== -1 ) {
  5272. // Yes, modify the sort
  5273. nextSortIdx = next( sorting[sortIdx], true );
  5274. if ( nextSortIdx === null && sorting.length === 1 ) {
  5275. nextSortIdx = 0; // can't remove sorting completely
  5276. }
  5277. if ( nextSortIdx === null ) {
  5278. sorting.splice( sortIdx, 1 );
  5279. }
  5280. else {
  5281. sorting[sortIdx][1] = asSorting[ nextSortIdx ];
  5282. sorting[sortIdx]._idx = nextSortIdx;
  5283. }
  5284. }
  5285. else {
  5286. // No sort on this column yet
  5287. sorting.push( [ colIdx, asSorting[0], 0 ] );
  5288. sorting[sorting.length-1]._idx = 0;
  5289. }
  5290. }
  5291. else if ( sorting.length && sorting[0][0] == colIdx ) {
  5292. // Single column - already sorting on this column, modify the sort
  5293. nextSortIdx = next( sorting[0] );
  5294. sorting.length = 1;
  5295. sorting[0][1] = asSorting[ nextSortIdx ];
  5296. sorting[0]._idx = nextSortIdx;
  5297. }
  5298. else {
  5299. // Single column - sort only on this column
  5300. sorting.length = 0;
  5301. sorting.push( [ colIdx, asSorting[0] ] );
  5302. sorting[0]._idx = 0;
  5303. }
  5304. // Run the sort by calling a full redraw
  5305. _fnReDraw( settings );
  5306. // callback used for async user interaction
  5307. if ( typeof callback == 'function' ) {
  5308. callback( settings );
  5309. }
  5310. }
  5311. /**
  5312. * Attach a sort handler (click) to a node
  5313. * @param {object} settings dataTables settings object
  5314. * @param {node} attachTo node to attach the handler to
  5315. * @param {int} colIdx column sorting index
  5316. * @param {function} [callback] callback function
  5317. * @memberof DataTable#oApi
  5318. */
  5319. function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
  5320. {
  5321. var col = settings.aoColumns[ colIdx ];
  5322. _fnBindAction( attachTo, {}, function (e) {
  5323. /* If the column is not sortable - don't to anything */
  5324. if ( col.bSortable === false ) {
  5325. return;
  5326. }
  5327. // If processing is enabled use a timeout to allow the processing
  5328. // display to be shown - otherwise to it synchronously
  5329. if ( settings.oFeatures.bProcessing ) {
  5330. _fnProcessingDisplay( settings, true );
  5331. setTimeout( function() {
  5332. _fnSortListener( settings, colIdx, e.shiftKey, callback );
  5333. // In server-side processing, the draw callback will remove the
  5334. // processing display
  5335. if ( _fnDataSource( settings ) !== 'ssp' ) {
  5336. _fnProcessingDisplay( settings, false );
  5337. }
  5338. }, 0 );
  5339. }
  5340. else {
  5341. _fnSortListener( settings, colIdx, e.shiftKey, callback );
  5342. }
  5343. } );
  5344. }
  5345. /**
  5346. * Set the sorting classes on table's body, Note: it is safe to call this function
  5347. * when bSort and bSortClasses are false
  5348. * @param {object} oSettings dataTables settings object
  5349. * @memberof DataTable#oApi
  5350. */
  5351. function _fnSortingClasses( settings )
  5352. {
  5353. var oldSort = settings.aLastSort;
  5354. var sortClass = settings.oClasses.sSortColumn;
  5355. var sort = _fnSortFlatten( settings );
  5356. var features = settings.oFeatures;
  5357. var i, ien, colIdx;
  5358. if ( features.bSort && features.bSortClasses ) {
  5359. // Remove old sorting classes
  5360. for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
  5361. colIdx = oldSort[i].src;
  5362. // Remove column sorting
  5363. $( _pluck( settings.aoData, 'anCells', colIdx ) )
  5364. .removeClass( sortClass + (i<2 ? i+1 : 3) );
  5365. }
  5366. // Add new column sorting
  5367. for ( i=0, ien=sort.length ; i<ien ; i++ ) {
  5368. colIdx = sort[i].src;
  5369. $( _pluck( settings.aoData, 'anCells', colIdx ) )
  5370. .addClass( sortClass + (i<2 ? i+1 : 3) );
  5371. }
  5372. }
  5373. settings.aLastSort = sort;
  5374. }
  5375. // Get the data to sort a column, be it from cache, fresh (populating the
  5376. // cache), or from a sort formatter
  5377. function _fnSortData( settings, idx )
  5378. {
  5379. // Custom sorting function - provided by the sort data type
  5380. var column = settings.aoColumns[ idx ];
  5381. var customSort = DataTable.ext.order[ column.sSortDataType ];
  5382. var customData;
  5383. if ( customSort ) {
  5384. customData = customSort.call( settings.oInstance, settings, idx,
  5385. _fnColumnIndexToVisible( settings, idx )
  5386. );
  5387. }
  5388. // Use / populate cache
  5389. var row, cellData;
  5390. var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
  5391. for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  5392. row = settings.aoData[i];
  5393. if ( ! row._aSortData ) {
  5394. row._aSortData = [];
  5395. }
  5396. if ( ! row._aSortData[idx] || customSort ) {
  5397. cellData = customSort ?
  5398. customData[i] : // If there was a custom sort function, use data from there
  5399. _fnGetCellData( settings, i, idx, 'sort' );
  5400. row._aSortData[ idx ] = formatter ?
  5401. formatter( cellData ) :
  5402. cellData;
  5403. }
  5404. }
  5405. }
  5406. /**
  5407. * Save the state of a table
  5408. * @param {object} oSettings dataTables settings object
  5409. * @memberof DataTable#oApi
  5410. */
  5411. function _fnSaveState ( settings )
  5412. {
  5413. if ( !settings.oFeatures.bStateSave || settings.bDestroying )
  5414. {
  5415. return;
  5416. }
  5417. /* Store the interesting variables */
  5418. var state = {
  5419. time: +new Date(),
  5420. start: settings._iDisplayStart,
  5421. length: settings._iDisplayLength,
  5422. order: $.extend( true, [], settings.aaSorting ),
  5423. search: _fnSearchToCamel( settings.oPreviousSearch ),
  5424. columns: $.map( settings.aoColumns, function ( col, i ) {
  5425. return {
  5426. visible: col.bVisible,
  5427. search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
  5428. };
  5429. } )
  5430. };
  5431. _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
  5432. settings.oSavedState = state;
  5433. settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
  5434. }
  5435. /**
  5436. * Attempt to load a saved table state
  5437. * @param {object} oSettings dataTables settings object
  5438. * @param {object} oInit DataTables init object so we can override settings
  5439. * @param {function} callback Callback to execute when the state has been loaded
  5440. * @memberof DataTable#oApi
  5441. */
  5442. function _fnLoadState ( settings, oInit, callback )
  5443. {
  5444. var i, ien;
  5445. var columns = settings.aoColumns;
  5446. var loaded = function ( s ) {
  5447. if ( ! s || ! s.time ) {
  5448. callback();
  5449. return;
  5450. }
  5451. // Allow custom and plug-in manipulation functions to alter the saved data set and
  5452. // cancelling of loading by returning false
  5453. var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
  5454. if ( $.inArray( false, abStateLoad ) !== -1 ) {
  5455. callback();
  5456. return;
  5457. }
  5458. // Reject old data
  5459. var duration = settings.iStateDuration;
  5460. if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
  5461. callback();
  5462. return;
  5463. }
  5464. // Number of columns have changed - all bets are off, no restore of settings
  5465. if ( s.columns && columns.length !== s.columns.length ) {
  5466. callback();
  5467. return;
  5468. }
  5469. // Store the saved state so it might be accessed at any time
  5470. settings.oLoadedState = $.extend( true, {}, s );
  5471. // Restore key features - todo - for 1.11 this needs to be done by
  5472. // subscribed events
  5473. if ( s.start !== undefined ) {
  5474. settings._iDisplayStart = s.start;
  5475. settings.iInitDisplayStart = s.start;
  5476. }
  5477. if ( s.length !== undefined ) {
  5478. settings._iDisplayLength = s.length;
  5479. }
  5480. // Order
  5481. if ( s.order !== undefined ) {
  5482. settings.aaSorting = [];
  5483. $.each( s.order, function ( i, col ) {
  5484. settings.aaSorting.push( col[0] >= columns.length ?
  5485. [ 0, col[1] ] :
  5486. col
  5487. );
  5488. } );
  5489. }
  5490. // Search
  5491. if ( s.search !== undefined ) {
  5492. $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
  5493. }
  5494. // Columns
  5495. //
  5496. if ( s.columns ) {
  5497. for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
  5498. var col = s.columns[i];
  5499. // Visibility
  5500. if ( col.visible !== undefined ) {
  5501. columns[i].bVisible = col.visible;
  5502. }
  5503. // Search
  5504. if ( col.search !== undefined ) {
  5505. $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
  5506. }
  5507. }
  5508. }
  5509. _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
  5510. callback();
  5511. }
  5512. if ( ! settings.oFeatures.bStateSave ) {
  5513. callback();
  5514. return;
  5515. }
  5516. var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
  5517. if ( state !== undefined ) {
  5518. loaded( state );
  5519. }
  5520. // otherwise, wait for the loaded callback to be executed
  5521. }
  5522. /**
  5523. * Return the settings object for a particular table
  5524. * @param {node} table table we are using as a dataTable
  5525. * @returns {object} Settings object - or null if not found
  5526. * @memberof DataTable#oApi
  5527. */
  5528. function _fnSettingsFromNode ( table )
  5529. {
  5530. var settings = DataTable.settings;
  5531. var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
  5532. return idx !== -1 ?
  5533. settings[ idx ] :
  5534. null;
  5535. }
  5536. /**
  5537. * Log an error message
  5538. * @param {object} settings dataTables settings object
  5539. * @param {int} level log error messages, or display them to the user
  5540. * @param {string} msg error message
  5541. * @param {int} tn Technical note id to get more information about the error.
  5542. * @memberof DataTable#oApi
  5543. */
  5544. function _fnLog( settings, level, msg, tn )
  5545. {
  5546. msg = 'DataTables warning: '+
  5547. (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
  5548. if ( tn ) {
  5549. msg += '. For more information about this error, please see '+
  5550. 'http://datatables.net/tn/'+tn;
  5551. }
  5552. if ( ! level ) {
  5553. // Backwards compatibility pre 1.10
  5554. var ext = DataTable.ext;
  5555. var type = ext.sErrMode || ext.errMode;
  5556. if ( settings ) {
  5557. _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
  5558. }
  5559. if ( type == 'alert' ) {
  5560. alert( msg );
  5561. }
  5562. else if ( type == 'throw' ) {
  5563. throw new Error(msg);
  5564. }
  5565. else if ( typeof type == 'function' ) {
  5566. type( settings, tn, msg );
  5567. }
  5568. }
  5569. else if ( window.console && console.log ) {
  5570. console.log( msg );
  5571. }
  5572. }
  5573. /**
  5574. * See if a property is defined on one object, if so assign it to the other object
  5575. * @param {object} ret target object
  5576. * @param {object} src source object
  5577. * @param {string} name property
  5578. * @param {string} [mappedName] name to map too - optional, name used if not given
  5579. * @memberof DataTable#oApi
  5580. */
  5581. function _fnMap( ret, src, name, mappedName )
  5582. {
  5583. if ( $.isArray( name ) ) {
  5584. $.each( name, function (i, val) {
  5585. if ( $.isArray( val ) ) {
  5586. _fnMap( ret, src, val[0], val[1] );
  5587. }
  5588. else {
  5589. _fnMap( ret, src, val );
  5590. }
  5591. } );
  5592. return;
  5593. }
  5594. if ( mappedName === undefined ) {
  5595. mappedName = name;
  5596. }
  5597. if ( src[name] !== undefined ) {
  5598. ret[mappedName] = src[name];
  5599. }
  5600. }
  5601. /**
  5602. * Extend objects - very similar to jQuery.extend, but deep copy objects, and
  5603. * shallow copy arrays. The reason we need to do this, is that we don't want to
  5604. * deep copy array init values (such as aaSorting) since the dev wouldn't be
  5605. * able to override them, but we do want to deep copy arrays.
  5606. * @param {object} out Object to extend
  5607. * @param {object} extender Object from which the properties will be applied to
  5608. * out
  5609. * @param {boolean} breakRefs If true, then arrays will be sliced to take an
  5610. * independent copy with the exception of the `data` or `aaData` parameters
  5611. * if they are present. This is so you can pass in a collection to
  5612. * DataTables and have that used as your data source without breaking the
  5613. * references
  5614. * @returns {object} out Reference, just for convenience - out === the return.
  5615. * @memberof DataTable#oApi
  5616. * @todo This doesn't take account of arrays inside the deep copied objects.
  5617. */
  5618. function _fnExtend( out, extender, breakRefs )
  5619. {
  5620. var val;
  5621. for ( var prop in extender ) {
  5622. if ( extender.hasOwnProperty(prop) ) {
  5623. val = extender[prop];
  5624. if ( $.isPlainObject( val ) ) {
  5625. if ( ! $.isPlainObject( out[prop] ) ) {
  5626. out[prop] = {};
  5627. }
  5628. $.extend( true, out[prop], val );
  5629. }
  5630. else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
  5631. out[prop] = val.slice();
  5632. }
  5633. else {
  5634. out[prop] = val;
  5635. }
  5636. }
  5637. }
  5638. return out;
  5639. }
  5640. /**
  5641. * Bind an event handers to allow a click or return key to activate the callback.
  5642. * This is good for accessibility since a return on the keyboard will have the
  5643. * same effect as a click, if the element has focus.
  5644. * @param {element} n Element to bind the action to
  5645. * @param {object} oData Data object to pass to the triggered function
  5646. * @param {function} fn Callback function for when the event is triggered
  5647. * @memberof DataTable#oApi
  5648. */
  5649. function _fnBindAction( n, oData, fn )
  5650. {
  5651. $(n)
  5652. .on( 'click.DT', oData, function (e) {
  5653. n.blur(); // Remove focus outline for mouse users
  5654. fn(e);
  5655. } )
  5656. .on( 'keypress.DT', oData, function (e){
  5657. if ( e.which === 13 ) {
  5658. e.preventDefault();
  5659. fn(e);
  5660. }
  5661. } )
  5662. .on( 'selectstart.DT', function () {
  5663. /* Take the brutal approach to cancelling text selection */
  5664. return false;
  5665. } );
  5666. }
  5667. /**
  5668. * Register a callback function. Easily allows a callback function to be added to
  5669. * an array store of callback functions that can then all be called together.
  5670. * @param {object} oSettings dataTables settings object
  5671. * @param {string} sStore Name of the array storage for the callbacks in oSettings
  5672. * @param {function} fn Function to be called back
  5673. * @param {string} sName Identifying name for the callback (i.e. a label)
  5674. * @memberof DataTable#oApi
  5675. */
  5676. function _fnCallbackReg( oSettings, sStore, fn, sName )
  5677. {
  5678. if ( fn )
  5679. {
  5680. oSettings[sStore].push( {
  5681. "fn": fn,
  5682. "sName": sName
  5683. } );
  5684. }
  5685. }
  5686. /**
  5687. * Fire callback functions and trigger events. Note that the loop over the
  5688. * callback array store is done backwards! Further note that you do not want to
  5689. * fire off triggers in time sensitive applications (for example cell creation)
  5690. * as its slow.
  5691. * @param {object} settings dataTables settings object
  5692. * @param {string} callbackArr Name of the array storage for the callbacks in
  5693. * oSettings
  5694. * @param {string} eventName Name of the jQuery custom event to trigger. If
  5695. * null no trigger is fired
  5696. * @param {array} args Array of arguments to pass to the callback function /
  5697. * trigger
  5698. * @memberof DataTable#oApi
  5699. */
  5700. function _fnCallbackFire( settings, callbackArr, eventName, args )
  5701. {
  5702. var ret = [];
  5703. if ( callbackArr ) {
  5704. ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
  5705. return val.fn.apply( settings.oInstance, args );
  5706. } );
  5707. }
  5708. if ( eventName !== null ) {
  5709. var e = $.Event( eventName+'.dt' );
  5710. $(settings.nTable).trigger( e, args );
  5711. ret.push( e.result );
  5712. }
  5713. return ret;
  5714. }
  5715. function _fnLengthOverflow ( settings )
  5716. {
  5717. var
  5718. start = settings._iDisplayStart,
  5719. end = settings.fnDisplayEnd(),
  5720. len = settings._iDisplayLength;
  5721. /* If we have space to show extra rows (backing up from the end point - then do so */
  5722. if ( start >= end )
  5723. {
  5724. start = end - len;
  5725. }
  5726. // Keep the start record on the current page
  5727. start -= (start % len);
  5728. if ( len === -1 || start < 0 )
  5729. {
  5730. start = 0;
  5731. }
  5732. settings._iDisplayStart = start;
  5733. }
  5734. function _fnRenderer( settings, type )
  5735. {
  5736. var renderer = settings.renderer;
  5737. var host = DataTable.ext.renderer[type];
  5738. if ( $.isPlainObject( renderer ) && renderer[type] ) {
  5739. // Specific renderer for this type. If available use it, otherwise use
  5740. // the default.
  5741. return host[renderer[type]] || host._;
  5742. }
  5743. else if ( typeof renderer === 'string' ) {
  5744. // Common renderer - if there is one available for this type use it,
  5745. // otherwise use the default
  5746. return host[renderer] || host._;
  5747. }
  5748. // Use the default
  5749. return host._;
  5750. }
  5751. /**
  5752. * Detect the data source being used for the table. Used to simplify the code
  5753. * a little (ajax) and to make it compress a little smaller.
  5754. *
  5755. * @param {object} settings dataTables settings object
  5756. * @returns {string} Data source
  5757. * @memberof DataTable#oApi
  5758. */
  5759. function _fnDataSource ( settings )
  5760. {
  5761. if ( settings.oFeatures.bServerSide ) {
  5762. return 'ssp';
  5763. }
  5764. else if ( settings.ajax || settings.sAjaxSource ) {
  5765. return 'ajax';
  5766. }
  5767. return 'dom';
  5768. }
  5769. /**
  5770. * Computed structure of the DataTables API, defined by the options passed to
  5771. * `DataTable.Api.register()` when building the API.
  5772. *
  5773. * The structure is built in order to speed creation and extension of the Api
  5774. * objects since the extensions are effectively pre-parsed.
  5775. *
  5776. * The array is an array of objects with the following structure, where this
  5777. * base array represents the Api prototype base:
  5778. *
  5779. * [
  5780. * {
  5781. * name: 'data' -- string - Property name
  5782. * val: function () {}, -- function - Api method (or undefined if just an object
  5783. * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
  5784. * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
  5785. * },
  5786. * {
  5787. * name: 'row'
  5788. * val: {},
  5789. * methodExt: [ ... ],
  5790. * propExt: [
  5791. * {
  5792. * name: 'data'
  5793. * val: function () {},
  5794. * methodExt: [ ... ],
  5795. * propExt: [ ... ]
  5796. * },
  5797. * ...
  5798. * ]
  5799. * }
  5800. * ]
  5801. *
  5802. * @type {Array}
  5803. * @ignore
  5804. */
  5805. var __apiStruct = [];
  5806. /**
  5807. * `Array.prototype` reference.
  5808. *
  5809. * @type object
  5810. * @ignore
  5811. */
  5812. var __arrayProto = Array.prototype;
  5813. /**
  5814. * Abstraction for `context` parameter of the `Api` constructor to allow it to
  5815. * take several different forms for ease of use.
  5816. *
  5817. * Each of the input parameter types will be converted to a DataTables settings
  5818. * object where possible.
  5819. *
  5820. * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
  5821. * of:
  5822. *
  5823. * * `string` - jQuery selector. Any DataTables' matching the given selector
  5824. * with be found and used.
  5825. * * `node` - `TABLE` node which has already been formed into a DataTable.
  5826. * * `jQuery` - A jQuery object of `TABLE` nodes.
  5827. * * `object` - DataTables settings object
  5828. * * `DataTables.Api` - API instance
  5829. * @return {array|null} Matching DataTables settings objects. `null` or
  5830. * `undefined` is returned if no matching DataTable is found.
  5831. * @ignore
  5832. */
  5833. var _toSettings = function ( mixed )
  5834. {
  5835. var idx, jq;
  5836. var settings = DataTable.settings;
  5837. var tables = $.map( settings, function (el, i) {
  5838. return el.nTable;
  5839. } );
  5840. if ( ! mixed ) {
  5841. return [];
  5842. }
  5843. else if ( mixed.nTable && mixed.oApi ) {
  5844. // DataTables settings object
  5845. return [ mixed ];
  5846. }
  5847. else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
  5848. // Table node
  5849. idx = $.inArray( mixed, tables );
  5850. return idx !== -1 ? [ settings[idx] ] : null;
  5851. }
  5852. else if ( mixed && typeof mixed.settings === 'function' ) {
  5853. return mixed.settings().toArray();
  5854. }
  5855. else if ( typeof mixed === 'string' ) {
  5856. // jQuery selector
  5857. jq = $(mixed);
  5858. }
  5859. else if ( mixed instanceof $ ) {
  5860. // jQuery object (also DataTables instance)
  5861. jq = mixed;
  5862. }
  5863. if ( jq ) {
  5864. return jq.map( function(i) {
  5865. idx = $.inArray( this, tables );
  5866. return idx !== -1 ? settings[idx] : null;
  5867. } ).toArray();
  5868. }
  5869. };
  5870. /**
  5871. * DataTables API class - used to control and interface with one or more
  5872. * DataTables enhanced tables.
  5873. *
  5874. * The API class is heavily based on jQuery, presenting a chainable interface
  5875. * that you can use to interact with tables. Each instance of the API class has
  5876. * a "context" - i.e. the tables that it will operate on. This could be a single
  5877. * table, all tables on a page or a sub-set thereof.
  5878. *
  5879. * Additionally the API is designed to allow you to easily work with the data in
  5880. * the tables, retrieving and manipulating it as required. This is done by
  5881. * presenting the API class as an array like interface. The contents of the
  5882. * array depend upon the actions requested by each method (for example
  5883. * `rows().nodes()` will return an array of nodes, while `rows().data()` will
  5884. * return an array of objects or arrays depending upon your table's
  5885. * configuration). The API object has a number of array like methods (`push`,
  5886. * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
  5887. * `unique` etc) to assist your working with the data held in a table.
  5888. *
  5889. * Most methods (those which return an Api instance) are chainable, which means
  5890. * the return from a method call also has all of the methods available that the
  5891. * top level object had. For example, these two calls are equivalent:
  5892. *
  5893. * // Not chained
  5894. * api.row.add( {...} );
  5895. * api.draw();
  5896. *
  5897. * // Chained
  5898. * api.row.add( {...} ).draw();
  5899. *
  5900. * @class DataTable.Api
  5901. * @param {array|object|string|jQuery} context DataTable identifier. This is
  5902. * used to define which DataTables enhanced tables this API will operate on.
  5903. * Can be one of:
  5904. *
  5905. * * `string` - jQuery selector. Any DataTables' matching the given selector
  5906. * with be found and used.
  5907. * * `node` - `TABLE` node which has already been formed into a DataTable.
  5908. * * `jQuery` - A jQuery object of `TABLE` nodes.
  5909. * * `object` - DataTables settings object
  5910. * @param {array} [data] Data to initialise the Api instance with.
  5911. *
  5912. * @example
  5913. * // Direct initialisation during DataTables construction
  5914. * var api = $('#example').DataTable();
  5915. *
  5916. * @example
  5917. * // Initialisation using a DataTables jQuery object
  5918. * var api = $('#example').dataTable().api();
  5919. *
  5920. * @example
  5921. * // Initialisation as a constructor
  5922. * var api = new $.fn.DataTable.Api( 'table.dataTable' );
  5923. */
  5924. _Api = function ( context, data )
  5925. {
  5926. if ( ! (this instanceof _Api) ) {
  5927. return new _Api( context, data );
  5928. }
  5929. var settings = [];
  5930. var ctxSettings = function ( o ) {
  5931. var a = _toSettings( o );
  5932. if ( a ) {
  5933. settings = settings.concat( a );
  5934. }
  5935. };
  5936. if ( $.isArray( context ) ) {
  5937. for ( var i=0, ien=context.length ; i<ien ; i++ ) {
  5938. ctxSettings( context[i] );
  5939. }
  5940. }
  5941. else {
  5942. ctxSettings( context );
  5943. }
  5944. // Remove duplicates
  5945. this.context = _unique( settings );
  5946. // Initial data
  5947. if ( data ) {
  5948. $.merge( this, data );
  5949. }
  5950. // selector
  5951. this.selector = {
  5952. rows: null,
  5953. cols: null,
  5954. opts: null
  5955. };
  5956. _Api.extend( this, this, __apiStruct );
  5957. };
  5958. DataTable.Api = _Api;
  5959. // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
  5960. // isPlainObject.
  5961. $.extend( _Api.prototype, {
  5962. any: function ()
  5963. {
  5964. return this.count() !== 0;
  5965. },
  5966. concat: __arrayProto.concat,
  5967. context: [], // array of table settings objects
  5968. count: function ()
  5969. {
  5970. return this.flatten().length;
  5971. },
  5972. each: function ( fn )
  5973. {
  5974. for ( var i=0, ien=this.length ; i<ien; i++ ) {
  5975. fn.call( this, this[i], i, this );
  5976. }
  5977. return this;
  5978. },
  5979. eq: function ( idx )
  5980. {
  5981. var ctx = this.context;
  5982. return ctx.length > idx ?
  5983. new _Api( ctx[idx], this[idx] ) :
  5984. null;
  5985. },
  5986. filter: function ( fn )
  5987. {
  5988. var a = [];
  5989. if ( __arrayProto.filter ) {
  5990. a = __arrayProto.filter.call( this, fn, this );
  5991. }
  5992. else {
  5993. // Compatibility for browsers without EMCA-252-5 (JS 1.6)
  5994. for ( var i=0, ien=this.length ; i<ien ; i++ ) {
  5995. if ( fn.call( this, this[i], i, this ) ) {
  5996. a.push( this[i] );
  5997. }
  5998. }
  5999. }
  6000. return new _Api( this.context, a );
  6001. },
  6002. flatten: function ()
  6003. {
  6004. var a = [];
  6005. return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
  6006. },
  6007. join: __arrayProto.join,
  6008. indexOf: __arrayProto.indexOf || function (obj, start)
  6009. {
  6010. for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
  6011. if ( this[i] === obj ) {
  6012. return i;
  6013. }
  6014. }
  6015. return -1;
  6016. },
  6017. iterator: function ( flatten, type, fn, alwaysNew ) {
  6018. var
  6019. a = [], ret,
  6020. i, ien, j, jen,
  6021. context = this.context,
  6022. rows, items, item,
  6023. selector = this.selector;
  6024. // Argument shifting
  6025. if ( typeof flatten === 'string' ) {
  6026. alwaysNew = fn;
  6027. fn = type;
  6028. type = flatten;
  6029. flatten = false;
  6030. }
  6031. for ( i=0, ien=context.length ; i<ien ; i++ ) {
  6032. var apiInst = new _Api( context[i] );
  6033. if ( type === 'table' ) {
  6034. ret = fn.call( apiInst, context[i], i );
  6035. if ( ret !== undefined ) {
  6036. a.push( ret );
  6037. }
  6038. }
  6039. else if ( type === 'columns' || type === 'rows' ) {
  6040. // this has same length as context - one entry for each table
  6041. ret = fn.call( apiInst, context[i], this[i], i );
  6042. if ( ret !== undefined ) {
  6043. a.push( ret );
  6044. }
  6045. }
  6046. else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
  6047. // columns and rows share the same structure.
  6048. // 'this' is an array of column indexes for each context
  6049. items = this[i];
  6050. if ( type === 'column-rows' ) {
  6051. rows = _selector_row_indexes( context[i], selector.opts );
  6052. }
  6053. for ( j=0, jen=items.length ; j<jen ; j++ ) {
  6054. item = items[j];
  6055. if ( type === 'cell' ) {
  6056. ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
  6057. }
  6058. else {
  6059. ret = fn.call( apiInst, context[i], item, i, j, rows );
  6060. }
  6061. if ( ret !== undefined ) {
  6062. a.push( ret );
  6063. }
  6064. }
  6065. }
  6066. }
  6067. if ( a.length || alwaysNew ) {
  6068. var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
  6069. var apiSelector = api.selector;
  6070. apiSelector.rows = selector.rows;
  6071. apiSelector.cols = selector.cols;
  6072. apiSelector.opts = selector.opts;
  6073. return api;
  6074. }
  6075. return this;
  6076. },
  6077. lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
  6078. {
  6079. // Bit cheeky...
  6080. return this.indexOf.apply( this.toArray.reverse(), arguments );
  6081. },
  6082. length: 0,
  6083. map: function ( fn )
  6084. {
  6085. var a = [];
  6086. if ( __arrayProto.map ) {
  6087. a = __arrayProto.map.call( this, fn, this );
  6088. }
  6089. else {
  6090. // Compatibility for browsers without EMCA-252-5 (JS 1.6)
  6091. for ( var i=0, ien=this.length ; i<ien ; i++ ) {
  6092. a.push( fn.call( this, this[i], i ) );
  6093. }
  6094. }
  6095. return new _Api( this.context, a );
  6096. },
  6097. pluck: function ( prop )
  6098. {
  6099. return this.map( function ( el ) {
  6100. return el[ prop ];
  6101. } );
  6102. },
  6103. pop: __arrayProto.pop,
  6104. push: __arrayProto.push,
  6105. // Does not return an API instance
  6106. reduce: __arrayProto.reduce || function ( fn, init )
  6107. {
  6108. return _fnReduce( this, fn, init, 0, this.length, 1 );
  6109. },
  6110. reduceRight: __arrayProto.reduceRight || function ( fn, init )
  6111. {
  6112. return _fnReduce( this, fn, init, this.length-1, -1, -1 );
  6113. },
  6114. reverse: __arrayProto.reverse,
  6115. // Object with rows, columns and opts
  6116. selector: null,
  6117. shift: __arrayProto.shift,
  6118. slice: function () {
  6119. return new _Api( this.context, this );
  6120. },
  6121. sort: __arrayProto.sort, // ? name - order?
  6122. splice: __arrayProto.splice,
  6123. toArray: function ()
  6124. {
  6125. return __arrayProto.slice.call( this );
  6126. },
  6127. to$: function ()
  6128. {
  6129. return $( this );
  6130. },
  6131. toJQuery: function ()
  6132. {
  6133. return $( this );
  6134. },
  6135. unique: function ()
  6136. {
  6137. return new _Api( this.context, _unique(this) );
  6138. },
  6139. unshift: __arrayProto.unshift
  6140. } );
  6141. _Api.extend = function ( scope, obj, ext )
  6142. {
  6143. // Only extend API instances and static properties of the API
  6144. if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
  6145. return;
  6146. }
  6147. var
  6148. i, ien,
  6149. j, jen,
  6150. struct, inner,
  6151. methodScoping = function ( scope, fn, struc ) {
  6152. return function () {
  6153. var ret = fn.apply( scope, arguments );
  6154. // Method extension
  6155. _Api.extend( ret, ret, struc.methodExt );
  6156. return ret;
  6157. };
  6158. };
  6159. for ( i=0, ien=ext.length ; i<ien ; i++ ) {
  6160. struct = ext[i];
  6161. // Value
  6162. obj[ struct.name ] = typeof struct.val === 'function' ?
  6163. methodScoping( scope, struct.val, struct ) :
  6164. $.isPlainObject( struct.val ) ?
  6165. {} :
  6166. struct.val;
  6167. obj[ struct.name ].__dt_wrapper = true;
  6168. // Property extension
  6169. _Api.extend( scope, obj[ struct.name ], struct.propExt );
  6170. }
  6171. };
  6172. // @todo - Is there need for an augment function?
  6173. // _Api.augment = function ( inst, name )
  6174. // {
  6175. // // Find src object in the structure from the name
  6176. // var parts = name.split('.');
  6177. // _Api.extend( inst, obj );
  6178. // };
  6179. // [
  6180. // {
  6181. // name: 'data' -- string - Property name
  6182. // val: function () {}, -- function - Api method (or undefined if just an object
  6183. // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
  6184. // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
  6185. // },
  6186. // {
  6187. // name: 'row'
  6188. // val: {},
  6189. // methodExt: [ ... ],
  6190. // propExt: [
  6191. // {
  6192. // name: 'data'
  6193. // val: function () {},
  6194. // methodExt: [ ... ],
  6195. // propExt: [ ... ]
  6196. // },
  6197. // ...
  6198. // ]
  6199. // }
  6200. // ]
  6201. _Api.register = _api_register = function ( name, val )
  6202. {
  6203. if ( $.isArray( name ) ) {
  6204. for ( var j=0, jen=name.length ; j<jen ; j++ ) {
  6205. _Api.register( name[j], val );
  6206. }
  6207. return;
  6208. }
  6209. var
  6210. i, ien,
  6211. heir = name.split('.'),
  6212. struct = __apiStruct,
  6213. key, method;
  6214. var find = function ( src, name ) {
  6215. for ( var i=0, ien=src.length ; i<ien ; i++ ) {
  6216. if ( src[i].name === name ) {
  6217. return src[i];
  6218. }
  6219. }
  6220. return null;
  6221. };
  6222. for ( i=0, ien=heir.length ; i<ien ; i++ ) {
  6223. method = heir[i].indexOf('()') !== -1;
  6224. key = method ?
  6225. heir[i].replace('()', '') :
  6226. heir[i];
  6227. var src = find( struct, key );
  6228. if ( ! src ) {
  6229. src = {
  6230. name: key,
  6231. val: {},
  6232. methodExt: [],
  6233. propExt: []
  6234. };
  6235. struct.push( src );
  6236. }
  6237. if ( i === ien-1 ) {
  6238. src.val = val;
  6239. }
  6240. else {
  6241. struct = method ?
  6242. src.methodExt :
  6243. src.propExt;
  6244. }
  6245. }
  6246. };
  6247. _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
  6248. _Api.register( pluralName, val );
  6249. _Api.register( singularName, function () {
  6250. var ret = val.apply( this, arguments );
  6251. if ( ret === this ) {
  6252. // Returned item is the API instance that was passed in, return it
  6253. return this;
  6254. }
  6255. else if ( ret instanceof _Api ) {
  6256. // New API instance returned, want the value from the first item
  6257. // in the returned array for the singular result.
  6258. return ret.length ?
  6259. $.isArray( ret[0] ) ?
  6260. new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
  6261. ret[0] :
  6262. undefined;
  6263. }
  6264. // Non-API return - just fire it back
  6265. return ret;
  6266. } );
  6267. };
  6268. /**
  6269. * Selector for HTML tables. Apply the given selector to the give array of
  6270. * DataTables settings objects.
  6271. *
  6272. * @param {string|integer} [selector] jQuery selector string or integer
  6273. * @param {array} Array of DataTables settings objects to be filtered
  6274. * @return {array}
  6275. * @ignore
  6276. */
  6277. var __table_selector = function ( selector, a )
  6278. {
  6279. // Integer is used to pick out a table by index
  6280. if ( typeof selector === 'number' ) {
  6281. return [ a[ selector ] ];
  6282. }
  6283. // Perform a jQuery selector on the table nodes
  6284. var nodes = $.map( a, function (el, i) {
  6285. return el.nTable;
  6286. } );
  6287. return $(nodes)
  6288. .filter( selector )
  6289. .map( function (i) {
  6290. // Need to translate back from the table node to the settings
  6291. var idx = $.inArray( this, nodes );
  6292. return a[ idx ];
  6293. } )
  6294. .toArray();
  6295. };
  6296. /**
  6297. * Context selector for the API's context (i.e. the tables the API instance
  6298. * refers to.
  6299. *
  6300. * @name DataTable.Api#tables
  6301. * @param {string|integer} [selector] Selector to pick which tables the iterator
  6302. * should operate on. If not given, all tables in the current context are
  6303. * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
  6304. * select multiple tables or as an integer to select a single table.
  6305. * @returns {DataTable.Api} Returns a new API instance if a selector is given.
  6306. */
  6307. _api_register( 'tables()', function ( selector ) {
  6308. // A new instance is created if there was a selector specified
  6309. return selector ?
  6310. new _Api( __table_selector( selector, this.context ) ) :
  6311. this;
  6312. } );
  6313. _api_register( 'table()', function ( selector ) {
  6314. var tables = this.tables( selector );
  6315. var ctx = tables.context;
  6316. // Truncate to the first matched table
  6317. return ctx.length ?
  6318. new _Api( ctx[0] ) :
  6319. tables;
  6320. } );
  6321. _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
  6322. return this.iterator( 'table', function ( ctx ) {
  6323. return ctx.nTable;
  6324. }, 1 );
  6325. } );
  6326. _api_registerPlural( 'tables().body()', 'table().body()' , function () {
  6327. return this.iterator( 'table', function ( ctx ) {
  6328. return ctx.nTBody;
  6329. }, 1 );
  6330. } );
  6331. _api_registerPlural( 'tables().header()', 'table().header()' , function () {
  6332. return this.iterator( 'table', function ( ctx ) {
  6333. return ctx.nTHead;
  6334. }, 1 );
  6335. } );
  6336. _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
  6337. return this.iterator( 'table', function ( ctx ) {
  6338. return ctx.nTFoot;
  6339. }, 1 );
  6340. } );
  6341. _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
  6342. return this.iterator( 'table', function ( ctx ) {
  6343. return ctx.nTableWrapper;
  6344. }, 1 );
  6345. } );
  6346. /**
  6347. * Redraw the tables in the current context.
  6348. */
  6349. _api_register( 'draw()', function ( paging ) {
  6350. return this.iterator( 'table', function ( settings ) {
  6351. if ( paging === 'page' ) {
  6352. _fnDraw( settings );
  6353. }
  6354. else {
  6355. if ( typeof paging === 'string' ) {
  6356. paging = paging === 'full-hold' ?
  6357. false :
  6358. true;
  6359. }
  6360. _fnReDraw( settings, paging===false );
  6361. }
  6362. } );
  6363. } );
  6364. /**
  6365. * Get the current page index.
  6366. *
  6367. * @return {integer} Current page index (zero based)
  6368. *//**
  6369. * Set the current page.
  6370. *
  6371. * Note that if you attempt to show a page which does not exist, DataTables will
  6372. * not throw an error, but rather reset the paging.
  6373. *
  6374. * @param {integer|string} action The paging action to take. This can be one of:
  6375. * * `integer` - The page index to jump to
  6376. * * `string` - An action to take:
  6377. * * `first` - Jump to first page.
  6378. * * `next` - Jump to the next page
  6379. * * `previous` - Jump to previous page
  6380. * * `last` - Jump to the last page.
  6381. * @returns {DataTables.Api} this
  6382. */
  6383. _api_register( 'page()', function ( action ) {
  6384. if ( action === undefined ) {
  6385. return this.page.info().page; // not an expensive call
  6386. }
  6387. // else, have an action to take on all tables
  6388. return this.iterator( 'table', function ( settings ) {
  6389. _fnPageChange( settings, action );
  6390. } );
  6391. } );
  6392. /**
  6393. * Paging information for the first table in the current context.
  6394. *
  6395. * If you require paging information for another table, use the `table()` method
  6396. * with a suitable selector.
  6397. *
  6398. * @return {object} Object with the following properties set:
  6399. * * `page` - Current page index (zero based - i.e. the first page is `0`)
  6400. * * `pages` - Total number of pages
  6401. * * `start` - Display index for the first record shown on the current page
  6402. * * `end` - Display index for the last record shown on the current page
  6403. * * `length` - Display length (number of records). Note that generally `start
  6404. * + length = end`, but this is not always true, for example if there are
  6405. * only 2 records to show on the final page, with a length of 10.
  6406. * * `recordsTotal` - Full data set length
  6407. * * `recordsDisplay` - Data set length once the current filtering criterion
  6408. * are applied.
  6409. */
  6410. _api_register( 'page.info()', function ( action ) {
  6411. if ( this.context.length === 0 ) {
  6412. return undefined;
  6413. }
  6414. var
  6415. settings = this.context[0],
  6416. start = settings._iDisplayStart,
  6417. len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
  6418. visRecords = settings.fnRecordsDisplay(),
  6419. all = len === -1;
  6420. return {
  6421. "page": all ? 0 : Math.floor( start / len ),
  6422. "pages": all ? 1 : Math.ceil( visRecords / len ),
  6423. "start": start,
  6424. "end": settings.fnDisplayEnd(),
  6425. "length": len,
  6426. "recordsTotal": settings.fnRecordsTotal(),
  6427. "recordsDisplay": visRecords,
  6428. "serverSide": _fnDataSource( settings ) === 'ssp'
  6429. };
  6430. } );
  6431. /**
  6432. * Get the current page length.
  6433. *
  6434. * @return {integer} Current page length. Note `-1` indicates that all records
  6435. * are to be shown.
  6436. *//**
  6437. * Set the current page length.
  6438. *
  6439. * @param {integer} Page length to set. Use `-1` to show all records.
  6440. * @returns {DataTables.Api} this
  6441. */
  6442. _api_register( 'page.len()', function ( len ) {
  6443. // Note that we can't call this function 'length()' because `length`
  6444. // is a Javascript property of functions which defines how many arguments
  6445. // the function expects.
  6446. if ( len === undefined ) {
  6447. return this.context.length !== 0 ?
  6448. this.context[0]._iDisplayLength :
  6449. undefined;
  6450. }
  6451. // else, set the page length
  6452. return this.iterator( 'table', function ( settings ) {
  6453. _fnLengthChange( settings, len );
  6454. } );
  6455. } );
  6456. var __reload = function ( settings, holdPosition, callback ) {
  6457. // Use the draw event to trigger a callback
  6458. if ( callback ) {
  6459. var api = new _Api( settings );
  6460. api.one( 'draw', function () {
  6461. callback( api.ajax.json() );
  6462. } );
  6463. }
  6464. if ( _fnDataSource( settings ) == 'ssp' ) {
  6465. _fnReDraw( settings, holdPosition );
  6466. }
  6467. else {
  6468. _fnProcessingDisplay( settings, true );
  6469. // Cancel an existing request
  6470. var xhr = settings.jqXHR;
  6471. if ( xhr && xhr.readyState !== 4 ) {
  6472. xhr.abort();
  6473. }
  6474. // Trigger xhr
  6475. _fnBuildAjax( settings, [], function( json ) {
  6476. _fnClearTable( settings );
  6477. var data = _fnAjaxDataSrc( settings, json );
  6478. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  6479. _fnAddData( settings, data[i] );
  6480. }
  6481. _fnReDraw( settings, holdPosition );
  6482. _fnProcessingDisplay( settings, false );
  6483. } );
  6484. }
  6485. };
  6486. /**
  6487. * Get the JSON response from the last Ajax request that DataTables made to the
  6488. * server. Note that this returns the JSON from the first table in the current
  6489. * context.
  6490. *
  6491. * @return {object} JSON received from the server.
  6492. */
  6493. _api_register( 'ajax.json()', function () {
  6494. var ctx = this.context;
  6495. if ( ctx.length > 0 ) {
  6496. return ctx[0].json;
  6497. }
  6498. // else return undefined;
  6499. } );
  6500. /**
  6501. * Get the data submitted in the last Ajax request
  6502. */
  6503. _api_register( 'ajax.params()', function () {
  6504. var ctx = this.context;
  6505. if ( ctx.length > 0 ) {
  6506. return ctx[0].oAjaxData;
  6507. }
  6508. // else return undefined;
  6509. } );
  6510. /**
  6511. * Reload tables from the Ajax data source. Note that this function will
  6512. * automatically re-draw the table when the remote data has been loaded.
  6513. *
  6514. * @param {boolean} [reset=true] Reset (default) or hold the current paging
  6515. * position. A full re-sort and re-filter is performed when this method is
  6516. * called, which is why the pagination reset is the default action.
  6517. * @returns {DataTables.Api} this
  6518. */
  6519. _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
  6520. return this.iterator( 'table', function (settings) {
  6521. __reload( settings, resetPaging===false, callback );
  6522. } );
  6523. } );
  6524. /**
  6525. * Get the current Ajax URL. Note that this returns the URL from the first
  6526. * table in the current context.
  6527. *
  6528. * @return {string} Current Ajax source URL
  6529. *//**
  6530. * Set the Ajax URL. Note that this will set the URL for all tables in the
  6531. * current context.
  6532. *
  6533. * @param {string} url URL to set.
  6534. * @returns {DataTables.Api} this
  6535. */
  6536. _api_register( 'ajax.url()', function ( url ) {
  6537. var ctx = this.context;
  6538. if ( url === undefined ) {
  6539. // get
  6540. if ( ctx.length === 0 ) {
  6541. return undefined;
  6542. }
  6543. ctx = ctx[0];
  6544. return ctx.ajax ?
  6545. $.isPlainObject( ctx.ajax ) ?
  6546. ctx.ajax.url :
  6547. ctx.ajax :
  6548. ctx.sAjaxSource;
  6549. }
  6550. // set
  6551. return this.iterator( 'table', function ( settings ) {
  6552. if ( $.isPlainObject( settings.ajax ) ) {
  6553. settings.ajax.url = url;
  6554. }
  6555. else {
  6556. settings.ajax = url;
  6557. }
  6558. // No need to consider sAjaxSource here since DataTables gives priority
  6559. // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
  6560. // value of `sAjaxSource` redundant.
  6561. } );
  6562. } );
  6563. /**
  6564. * Load data from the newly set Ajax URL. Note that this method is only
  6565. * available when `ajax.url()` is used to set a URL. Additionally, this method
  6566. * has the same effect as calling `ajax.reload()` but is provided for
  6567. * convenience when setting a new URL. Like `ajax.reload()` it will
  6568. * automatically redraw the table once the remote data has been loaded.
  6569. *
  6570. * @returns {DataTables.Api} this
  6571. */
  6572. _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
  6573. // Same as a reload, but makes sense to present it for easy access after a
  6574. // url change
  6575. return this.iterator( 'table', function ( ctx ) {
  6576. __reload( ctx, resetPaging===false, callback );
  6577. } );
  6578. } );
  6579. var _selector_run = function ( type, selector, selectFn, settings, opts )
  6580. {
  6581. var
  6582. out = [], res,
  6583. a, i, ien, j, jen,
  6584. selectorType = typeof selector;
  6585. // Can't just check for isArray here, as an API or jQuery instance might be
  6586. // given with their array like look
  6587. if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
  6588. selector = [ selector ];
  6589. }
  6590. for ( i=0, ien=selector.length ; i<ien ; i++ ) {
  6591. // Only split on simple strings - complex expressions will be jQuery selectors
  6592. a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
  6593. selector[i].split(',') :
  6594. [ selector[i] ];
  6595. for ( j=0, jen=a.length ; j<jen ; j++ ) {
  6596. res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
  6597. if ( res && res.length ) {
  6598. out = out.concat( res );
  6599. }
  6600. }
  6601. }
  6602. // selector extensions
  6603. var ext = _ext.selector[ type ];
  6604. if ( ext.length ) {
  6605. for ( i=0, ien=ext.length ; i<ien ; i++ ) {
  6606. out = ext[i]( settings, opts, out );
  6607. }
  6608. }
  6609. return _unique( out );
  6610. };
  6611. var _selector_opts = function ( opts )
  6612. {
  6613. if ( ! opts ) {
  6614. opts = {};
  6615. }
  6616. // Backwards compatibility for 1.9- which used the terminology filter rather
  6617. // than search
  6618. if ( opts.filter && opts.search === undefined ) {
  6619. opts.search = opts.filter;
  6620. }
  6621. return $.extend( {
  6622. search: 'none',
  6623. order: 'current',
  6624. page: 'all'
  6625. }, opts );
  6626. };
  6627. var _selector_first = function ( inst )
  6628. {
  6629. // Reduce the API instance to the first item found
  6630. for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
  6631. if ( inst[i].length > 0 ) {
  6632. // Assign the first element to the first item in the instance
  6633. // and truncate the instance and context
  6634. inst[0] = inst[i];
  6635. inst[0].length = 1;
  6636. inst.length = 1;
  6637. inst.context = [ inst.context[i] ];
  6638. return inst;
  6639. }
  6640. }
  6641. // Not found - return an empty instance
  6642. inst.length = 0;
  6643. return inst;
  6644. };
  6645. var _selector_row_indexes = function ( settings, opts )
  6646. {
  6647. var
  6648. i, ien, tmp, a=[],
  6649. displayFiltered = settings.aiDisplay,
  6650. displayMaster = settings.aiDisplayMaster;
  6651. var
  6652. search = opts.search, // none, applied, removed
  6653. order = opts.order, // applied, current, index (original - compatibility with 1.9)
  6654. page = opts.page; // all, current
  6655. if ( _fnDataSource( settings ) == 'ssp' ) {
  6656. // In server-side processing mode, most options are irrelevant since
  6657. // rows not shown don't exist and the index order is the applied order
  6658. // Removed is a special case - for consistency just return an empty
  6659. // array
  6660. return search === 'removed' ?
  6661. [] :
  6662. _range( 0, displayMaster.length );
  6663. }
  6664. else if ( page == 'current' ) {
  6665. // Current page implies that order=current and fitler=applied, since it is
  6666. // fairly senseless otherwise, regardless of what order and search actually
  6667. // are
  6668. for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
  6669. a.push( displayFiltered[i] );
  6670. }
  6671. }
  6672. else if ( order == 'current' || order == 'applied' ) {
  6673. a = search == 'none' ?
  6674. displayMaster.slice() : // no search
  6675. search == 'applied' ?
  6676. displayFiltered.slice() : // applied search
  6677. $.map( displayMaster, function (el, i) { // removed search
  6678. return $.inArray( el, displayFiltered ) === -1 ? el : null;
  6679. } );
  6680. }
  6681. else if ( order == 'index' || order == 'original' ) {
  6682. for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  6683. if ( search == 'none' ) {
  6684. a.push( i );
  6685. }
  6686. else { // applied | removed
  6687. tmp = $.inArray( i, displayFiltered );
  6688. if ((tmp === -1 && search == 'removed') ||
  6689. (tmp >= 0 && search == 'applied') )
  6690. {
  6691. a.push( i );
  6692. }
  6693. }
  6694. }
  6695. }
  6696. return a;
  6697. };
  6698. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6699. * Rows
  6700. *
  6701. * {} - no selector - use all available rows
  6702. * {integer} - row aoData index
  6703. * {node} - TR node
  6704. * {string} - jQuery selector to apply to the TR elements
  6705. * {array} - jQuery array of nodes, or simply an array of TR nodes
  6706. *
  6707. */
  6708. var __row_selector = function ( settings, selector, opts )
  6709. {
  6710. var rows;
  6711. var run = function ( sel ) {
  6712. var selInt = _intVal( sel );
  6713. var i, ien;
  6714. // Short cut - selector is a number and no options provided (default is
  6715. // all records, so no need to check if the index is in there, since it
  6716. // must be - dev error if the index doesn't exist).
  6717. if ( selInt !== null && ! opts ) {
  6718. return [ selInt ];
  6719. }
  6720. if ( ! rows ) {
  6721. rows = _selector_row_indexes( settings, opts );
  6722. }
  6723. if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
  6724. // Selector - integer
  6725. return [ selInt ];
  6726. }
  6727. else if ( sel === null || sel === undefined || sel === '' ) {
  6728. // Selector - none
  6729. return rows;
  6730. }
  6731. // Selector - function
  6732. if ( typeof sel === 'function' ) {
  6733. return $.map( rows, function (idx) {
  6734. var row = settings.aoData[ idx ];
  6735. return sel( idx, row._aData, row.nTr ) ? idx : null;
  6736. } );
  6737. }
  6738. // Get nodes in the order from the `rows` array with null values removed
  6739. var nodes = _removeEmpty(
  6740. _pluck_order( settings.aoData, rows, 'nTr' )
  6741. );
  6742. // Selector - node
  6743. if ( sel.nodeName ) {
  6744. if ( sel._DT_RowIndex !== undefined ) {
  6745. return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
  6746. }
  6747. else if ( sel._DT_CellIndex ) {
  6748. return [ sel._DT_CellIndex.row ];
  6749. }
  6750. else {
  6751. var host = $(sel).closest('*[data-dt-row]');
  6752. return host.length ?
  6753. [ host.data('dt-row') ] :
  6754. [];
  6755. }
  6756. }
  6757. // ID selector. Want to always be able to select rows by id, regardless
  6758. // of if the tr element has been created or not, so can't rely upon
  6759. // jQuery here - hence a custom implementation. This does not match
  6760. // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
  6761. // but to select it using a CSS selector engine (like Sizzle or
  6762. // querySelect) it would need to need to be escaped for some characters.
  6763. // DataTables simplifies this for row selectors since you can select
  6764. // only a row. A # indicates an id any anything that follows is the id -
  6765. // unescaped.
  6766. if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
  6767. // get row index from id
  6768. var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
  6769. if ( rowObj !== undefined ) {
  6770. return [ rowObj.idx ];
  6771. }
  6772. // need to fall through to jQuery in case there is DOM id that
  6773. // matches
  6774. }
  6775. // Selector - jQuery selector string, array of nodes or jQuery object/
  6776. // As jQuery's .filter() allows jQuery objects to be passed in filter,
  6777. // it also allows arrays, so this will cope with all three options
  6778. return $(nodes)
  6779. .filter( sel )
  6780. .map( function () {
  6781. return this._DT_RowIndex;
  6782. } )
  6783. .toArray();
  6784. };
  6785. return _selector_run( 'row', selector, run, settings, opts );
  6786. };
  6787. _api_register( 'rows()', function ( selector, opts ) {
  6788. // argument shifting
  6789. if ( selector === undefined ) {
  6790. selector = '';
  6791. }
  6792. else if ( $.isPlainObject( selector ) ) {
  6793. opts = selector;
  6794. selector = '';
  6795. }
  6796. opts = _selector_opts( opts );
  6797. var inst = this.iterator( 'table', function ( settings ) {
  6798. return __row_selector( settings, selector, opts );
  6799. }, 1 );
  6800. // Want argument shifting here and in __row_selector?
  6801. inst.selector.rows = selector;
  6802. inst.selector.opts = opts;
  6803. return inst;
  6804. } );
  6805. _api_register( 'rows().nodes()', function () {
  6806. return this.iterator( 'row', function ( settings, row ) {
  6807. return settings.aoData[ row ].nTr || undefined;
  6808. }, 1 );
  6809. } );
  6810. _api_register( 'rows().data()', function () {
  6811. return this.iterator( true, 'rows', function ( settings, rows ) {
  6812. return _pluck_order( settings.aoData, rows, '_aData' );
  6813. }, 1 );
  6814. } );
  6815. _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
  6816. return this.iterator( 'row', function ( settings, row ) {
  6817. var r = settings.aoData[ row ];
  6818. return type === 'search' ? r._aFilterData : r._aSortData;
  6819. }, 1 );
  6820. } );
  6821. _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
  6822. return this.iterator( 'row', function ( settings, row ) {
  6823. _fnInvalidate( settings, row, src );
  6824. } );
  6825. } );
  6826. _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
  6827. return this.iterator( 'row', function ( settings, row ) {
  6828. return row;
  6829. }, 1 );
  6830. } );
  6831. _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
  6832. var a = [];
  6833. var context = this.context;
  6834. // `iterator` will drop undefined values, but in this case we want them
  6835. for ( var i=0, ien=context.length ; i<ien ; i++ ) {
  6836. for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
  6837. var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
  6838. a.push( (hash === true ? '#' : '' )+ id );
  6839. }
  6840. }
  6841. return new _Api( context, a );
  6842. } );
  6843. _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
  6844. var that = this;
  6845. this.iterator( 'row', function ( settings, row, thatIdx ) {
  6846. var data = settings.aoData;
  6847. var rowData = data[ row ];
  6848. var i, ien, j, jen;
  6849. var loopRow, loopCells;
  6850. data.splice( row, 1 );
  6851. // Update the cached indexes
  6852. for ( i=0, ien=data.length ; i<ien ; i++ ) {
  6853. loopRow = data[i];
  6854. loopCells = loopRow.anCells;
  6855. // Rows
  6856. if ( loopRow.nTr !== null ) {
  6857. loopRow.nTr._DT_RowIndex = i;
  6858. }
  6859. // Cells
  6860. if ( loopCells !== null ) {
  6861. for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
  6862. loopCells[j]._DT_CellIndex.row = i;
  6863. }
  6864. }
  6865. }
  6866. // Delete from the display arrays
  6867. _fnDeleteIndex( settings.aiDisplayMaster, row );
  6868. _fnDeleteIndex( settings.aiDisplay, row );
  6869. _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
  6870. // For server-side processing tables - subtract the deleted row from the count
  6871. if ( settings._iRecordsDisplay > 0 ) {
  6872. settings._iRecordsDisplay--;
  6873. }
  6874. // Check for an 'overflow' they case for displaying the table
  6875. _fnLengthOverflow( settings );
  6876. // Remove the row's ID reference if there is one
  6877. var id = settings.rowIdFn( rowData._aData );
  6878. if ( id !== undefined ) {
  6879. delete settings.aIds[ id ];
  6880. }
  6881. } );
  6882. this.iterator( 'table', function ( settings ) {
  6883. for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
  6884. settings.aoData[i].idx = i;
  6885. }
  6886. } );
  6887. return this;
  6888. } );
  6889. _api_register( 'rows.add()', function ( rows ) {
  6890. var newRows = this.iterator( 'table', function ( settings ) {
  6891. var row, i, ien;
  6892. var out = [];
  6893. for ( i=0, ien=rows.length ; i<ien ; i++ ) {
  6894. row = rows[i];
  6895. if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
  6896. out.push( _fnAddTr( settings, row )[0] );
  6897. }
  6898. else {
  6899. out.push( _fnAddData( settings, row ) );
  6900. }
  6901. }
  6902. return out;
  6903. }, 1 );
  6904. // Return an Api.rows() extended instance, so rows().nodes() etc can be used
  6905. var modRows = this.rows( -1 );
  6906. modRows.pop();
  6907. $.merge( modRows, newRows );
  6908. return modRows;
  6909. } );
  6910. /**
  6911. *
  6912. */
  6913. _api_register( 'row()', function ( selector, opts ) {
  6914. return _selector_first( this.rows( selector, opts ) );
  6915. } );
  6916. _api_register( 'row().data()', function ( data ) {
  6917. var ctx = this.context;
  6918. if ( data === undefined ) {
  6919. // Get
  6920. return ctx.length && this.length ?
  6921. ctx[0].aoData[ this[0] ]._aData :
  6922. undefined;
  6923. }
  6924. // Set
  6925. ctx[0].aoData[ this[0] ]._aData = data;
  6926. // Automatically invalidate
  6927. _fnInvalidate( ctx[0], this[0], 'data' );
  6928. return this;
  6929. } );
  6930. _api_register( 'row().node()', function () {
  6931. var ctx = this.context;
  6932. return ctx.length && this.length ?
  6933. ctx[0].aoData[ this[0] ].nTr || null :
  6934. null;
  6935. } );
  6936. _api_register( 'row.add()', function ( row ) {
  6937. // Allow a jQuery object to be passed in - only a single row is added from
  6938. // it though - the first element in the set
  6939. if ( row instanceof $ && row.length ) {
  6940. row = row[0];
  6941. }
  6942. var rows = this.iterator( 'table', function ( settings ) {
  6943. if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
  6944. return _fnAddTr( settings, row )[0];
  6945. }
  6946. return _fnAddData( settings, row );
  6947. } );
  6948. // Return an Api.rows() extended instance, with the newly added row selected
  6949. return this.row( rows[0] );
  6950. } );
  6951. var __details_add = function ( ctx, row, data, klass )
  6952. {
  6953. // Convert to array of TR elements
  6954. var rows = [];
  6955. var addRow = function ( r, k ) {
  6956. // Recursion to allow for arrays of jQuery objects
  6957. if ( $.isArray( r ) || r instanceof $ ) {
  6958. for ( var i=0, ien=r.length ; i<ien ; i++ ) {
  6959. addRow( r[i], k );
  6960. }
  6961. return;
  6962. }
  6963. // If we get a TR element, then just add it directly - up to the dev
  6964. // to add the correct number of columns etc
  6965. if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
  6966. rows.push( r );
  6967. }
  6968. else {
  6969. // Otherwise create a row with a wrapper
  6970. var created = $('<tr><td/></tr>').addClass( k );
  6971. $('td', created)
  6972. .addClass( k )
  6973. .html( r )
  6974. [0].colSpan = _fnVisbleColumns( ctx );
  6975. rows.push( created[0] );
  6976. }
  6977. };
  6978. addRow( data, klass );
  6979. if ( row._details ) {
  6980. row._details.detach();
  6981. }
  6982. row._details = $(rows);
  6983. // If the children were already shown, that state should be retained
  6984. if ( row._detailsShow ) {
  6985. row._details.insertAfter( row.nTr );
  6986. }
  6987. };
  6988. var __details_remove = function ( api, idx )
  6989. {
  6990. var ctx = api.context;
  6991. if ( ctx.length ) {
  6992. var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
  6993. if ( row && row._details ) {
  6994. row._details.remove();
  6995. row._detailsShow = undefined;
  6996. row._details = undefined;
  6997. }
  6998. }
  6999. };
  7000. var __details_display = function ( api, show ) {
  7001. var ctx = api.context;
  7002. if ( ctx.length && api.length ) {
  7003. var row = ctx[0].aoData[ api[0] ];
  7004. if ( row._details ) {
  7005. row._detailsShow = show;
  7006. if ( show ) {
  7007. row._details.insertAfter( row.nTr );
  7008. }
  7009. else {
  7010. row._details.detach();
  7011. }
  7012. __details_events( ctx[0] );
  7013. }
  7014. }
  7015. };
  7016. var __details_events = function ( settings )
  7017. {
  7018. var api = new _Api( settings );
  7019. var namespace = '.dt.DT_details';
  7020. var drawEvent = 'draw'+namespace;
  7021. var colvisEvent = 'column-visibility'+namespace;
  7022. var destroyEvent = 'destroy'+namespace;
  7023. var data = settings.aoData;
  7024. api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
  7025. if ( _pluck( data, '_details' ).length > 0 ) {
  7026. // On each draw, insert the required elements into the document
  7027. api.on( drawEvent, function ( e, ctx ) {
  7028. if ( settings !== ctx ) {
  7029. return;
  7030. }
  7031. api.rows( {page:'current'} ).eq(0).each( function (idx) {
  7032. // Internal data grab
  7033. var row = data[ idx ];
  7034. if ( row._detailsShow ) {
  7035. row._details.insertAfter( row.nTr );
  7036. }
  7037. } );
  7038. } );
  7039. // Column visibility change - update the colspan
  7040. api.on( colvisEvent, function ( e, ctx, idx, vis ) {
  7041. if ( settings !== ctx ) {
  7042. return;
  7043. }
  7044. // Update the colspan for the details rows (note, only if it already has
  7045. // a colspan)
  7046. var row, visible = _fnVisbleColumns( ctx );
  7047. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  7048. row = data[i];
  7049. if ( row._details ) {
  7050. row._details.children('td[colspan]').attr('colspan', visible );
  7051. }
  7052. }
  7053. } );
  7054. // Table destroyed - nuke any child rows
  7055. api.on( destroyEvent, function ( e, ctx ) {
  7056. if ( settings !== ctx ) {
  7057. return;
  7058. }
  7059. for ( var i=0, ien=data.length ; i<ien ; i++ ) {
  7060. if ( data[i]._details ) {
  7061. __details_remove( api, i );
  7062. }
  7063. }
  7064. } );
  7065. }
  7066. };
  7067. // Strings for the method names to help minification
  7068. var _emp = '';
  7069. var _child_obj = _emp+'row().child';
  7070. var _child_mth = _child_obj+'()';
  7071. // data can be:
  7072. // tr
  7073. // string
  7074. // jQuery or array of any of the above
  7075. _api_register( _child_mth, function ( data, klass ) {
  7076. var ctx = this.context;
  7077. if ( data === undefined ) {
  7078. // get
  7079. return ctx.length && this.length ?
  7080. ctx[0].aoData[ this[0] ]._details :
  7081. undefined;
  7082. }
  7083. else if ( data === true ) {
  7084. // show
  7085. this.child.show();
  7086. }
  7087. else if ( data === false ) {
  7088. // remove
  7089. __details_remove( this );
  7090. }
  7091. else if ( ctx.length && this.length ) {
  7092. // set
  7093. __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
  7094. }
  7095. return this;
  7096. } );
  7097. _api_register( [
  7098. _child_obj+'.show()',
  7099. _child_mth+'.show()' // only when `child()` was called with parameters (without
  7100. ], function ( show ) { // it returns an object and this method is not executed)
  7101. __details_display( this, true );
  7102. return this;
  7103. } );
  7104. _api_register( [
  7105. _child_obj+'.hide()',
  7106. _child_mth+'.hide()' // only when `child()` was called with parameters (without
  7107. ], function () { // it returns an object and this method is not executed)
  7108. __details_display( this, false );
  7109. return this;
  7110. } );
  7111. _api_register( [
  7112. _child_obj+'.remove()',
  7113. _child_mth+'.remove()' // only when `child()` was called with parameters (without
  7114. ], function () { // it returns an object and this method is not executed)
  7115. __details_remove( this );
  7116. return this;
  7117. } );
  7118. _api_register( _child_obj+'.isShown()', function () {
  7119. var ctx = this.context;
  7120. if ( ctx.length && this.length ) {
  7121. // _detailsShown as false or undefined will fall through to return false
  7122. return ctx[0].aoData[ this[0] ]._detailsShow || false;
  7123. }
  7124. return false;
  7125. } );
  7126. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7127. * Columns
  7128. *
  7129. * {integer} - column index (>=0 count from left, <0 count from right)
  7130. * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
  7131. * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
  7132. * "{string}:name" - column name
  7133. * "{string}" - jQuery selector on column header nodes
  7134. *
  7135. */
  7136. // can be an array of these items, comma separated list, or an array of comma
  7137. // separated lists
  7138. var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
  7139. // r1 and r2 are redundant - but it means that the parameters match for the
  7140. // iterator callback in columns().data()
  7141. var __columnData = function ( settings, column, r1, r2, rows ) {
  7142. var a = [];
  7143. for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
  7144. a.push( _fnGetCellData( settings, rows[row], column ) );
  7145. }
  7146. return a;
  7147. };
  7148. var __column_selector = function ( settings, selector, opts )
  7149. {
  7150. var
  7151. columns = settings.aoColumns,
  7152. names = _pluck( columns, 'sName' ),
  7153. nodes = _pluck( columns, 'nTh' );
  7154. var run = function ( s ) {
  7155. var selInt = _intVal( s );
  7156. // Selector - all
  7157. if ( s === '' ) {
  7158. return _range( columns.length );
  7159. }
  7160. // Selector - index
  7161. if ( selInt !== null ) {
  7162. return [ selInt >= 0 ?
  7163. selInt : // Count from left
  7164. columns.length + selInt // Count from right (+ because its a negative value)
  7165. ];
  7166. }
  7167. // Selector = function
  7168. if ( typeof s === 'function' ) {
  7169. var rows = _selector_row_indexes( settings, opts );
  7170. return $.map( columns, function (col, idx) {
  7171. return s(
  7172. idx,
  7173. __columnData( settings, idx, 0, 0, rows ),
  7174. nodes[ idx ]
  7175. ) ? idx : null;
  7176. } );
  7177. }
  7178. // jQuery or string selector
  7179. var match = typeof s === 'string' ?
  7180. s.match( __re_column_selector ) :
  7181. '';
  7182. if ( match ) {
  7183. switch( match[2] ) {
  7184. case 'visIdx':
  7185. case 'visible':
  7186. var idx = parseInt( match[1], 10 );
  7187. // Visible index given, convert to column index
  7188. if ( idx < 0 ) {
  7189. // Counting from the right
  7190. var visColumns = $.map( columns, function (col,i) {
  7191. return col.bVisible ? i : null;
  7192. } );
  7193. return [ visColumns[ visColumns.length + idx ] ];
  7194. }
  7195. // Counting from the left
  7196. return [ _fnVisibleToColumnIndex( settings, idx ) ];
  7197. case 'name':
  7198. // match by name. `names` is column index complete and in order
  7199. return $.map( names, function (name, i) {
  7200. return name === match[1] ? i : null;
  7201. } );
  7202. default:
  7203. return [];
  7204. }
  7205. }
  7206. // Cell in the table body
  7207. if ( s.nodeName && s._DT_CellIndex ) {
  7208. return [ s._DT_CellIndex.column ];
  7209. }
  7210. // jQuery selector on the TH elements for the columns
  7211. var jqResult = $( nodes )
  7212. .filter( s )
  7213. .map( function () {
  7214. return $.inArray( this, nodes ); // `nodes` is column index complete and in order
  7215. } )
  7216. .toArray();
  7217. if ( jqResult.length || ! s.nodeName ) {
  7218. return jqResult;
  7219. }
  7220. // Otherwise a node which might have a `dt-column` data attribute, or be
  7221. // a child or such an element
  7222. var host = $(s).closest('*[data-dt-column]');
  7223. return host.length ?
  7224. [ host.data('dt-column') ] :
  7225. [];
  7226. };
  7227. return _selector_run( 'column', selector, run, settings, opts );
  7228. };
  7229. var __setColumnVis = function ( settings, column, vis ) {
  7230. var
  7231. cols = settings.aoColumns,
  7232. col = cols[ column ],
  7233. data = settings.aoData,
  7234. row, cells, i, ien, tr;
  7235. // Get
  7236. if ( vis === undefined ) {
  7237. return col.bVisible;
  7238. }
  7239. // Set
  7240. // No change
  7241. if ( col.bVisible === vis ) {
  7242. return;
  7243. }
  7244. if ( vis ) {
  7245. // Insert column
  7246. // Need to decide if we should use appendChild or insertBefore
  7247. var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
  7248. for ( i=0, ien=data.length ; i<ien ; i++ ) {
  7249. tr = data[i].nTr;
  7250. cells = data[i].anCells;
  7251. if ( tr ) {
  7252. // insertBefore can act like appendChild if 2nd arg is null
  7253. tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
  7254. }
  7255. }
  7256. }
  7257. else {
  7258. // Remove column
  7259. $( _pluck( settings.aoData, 'anCells', column ) ).detach();
  7260. }
  7261. // Common actions
  7262. col.bVisible = vis;
  7263. _fnDrawHead( settings, settings.aoHeader );
  7264. _fnDrawHead( settings, settings.aoFooter );
  7265. _fnSaveState( settings );
  7266. };
  7267. _api_register( 'columns()', function ( selector, opts ) {
  7268. // argument shifting
  7269. if ( selector === undefined ) {
  7270. selector = '';
  7271. }
  7272. else if ( $.isPlainObject( selector ) ) {
  7273. opts = selector;
  7274. selector = '';
  7275. }
  7276. opts = _selector_opts( opts );
  7277. var inst = this.iterator( 'table', function ( settings ) {
  7278. return __column_selector( settings, selector, opts );
  7279. }, 1 );
  7280. // Want argument shifting here and in _row_selector?
  7281. inst.selector.cols = selector;
  7282. inst.selector.opts = opts;
  7283. return inst;
  7284. } );
  7285. _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
  7286. return this.iterator( 'column', function ( settings, column ) {
  7287. return settings.aoColumns[column].nTh;
  7288. }, 1 );
  7289. } );
  7290. _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
  7291. return this.iterator( 'column', function ( settings, column ) {
  7292. return settings.aoColumns[column].nTf;
  7293. }, 1 );
  7294. } );
  7295. _api_registerPlural( 'columns().data()', 'column().data()', function () {
  7296. return this.iterator( 'column-rows', __columnData, 1 );
  7297. } );
  7298. _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
  7299. return this.iterator( 'column', function ( settings, column ) {
  7300. return settings.aoColumns[column].mData;
  7301. }, 1 );
  7302. } );
  7303. _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
  7304. return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
  7305. return _pluck_order( settings.aoData, rows,
  7306. type === 'search' ? '_aFilterData' : '_aSortData', column
  7307. );
  7308. }, 1 );
  7309. } );
  7310. _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
  7311. return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
  7312. return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
  7313. }, 1 );
  7314. } );
  7315. _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
  7316. var ret = this.iterator( 'column', function ( settings, column ) {
  7317. if ( vis === undefined ) {
  7318. return settings.aoColumns[ column ].bVisible;
  7319. } // else
  7320. __setColumnVis( settings, column, vis );
  7321. } );
  7322. // Group the column visibility changes
  7323. if ( vis !== undefined ) {
  7324. // Second loop once the first is done for events
  7325. this.iterator( 'column', function ( settings, column ) {
  7326. _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
  7327. } );
  7328. if ( calc === undefined || calc ) {
  7329. this.columns.adjust();
  7330. }
  7331. }
  7332. return ret;
  7333. } );
  7334. _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
  7335. return this.iterator( 'column', function ( settings, column ) {
  7336. return type === 'visible' ?
  7337. _fnColumnIndexToVisible( settings, column ) :
  7338. column;
  7339. }, 1 );
  7340. } );
  7341. _api_register( 'columns.adjust()', function () {
  7342. return this.iterator( 'table', function ( settings ) {
  7343. _fnAdjustColumnSizing( settings );
  7344. }, 1 );
  7345. } );
  7346. _api_register( 'column.index()', function ( type, idx ) {
  7347. if ( this.context.length !== 0 ) {
  7348. var ctx = this.context[0];
  7349. if ( type === 'fromVisible' || type === 'toData' ) {
  7350. return _fnVisibleToColumnIndex( ctx, idx );
  7351. }
  7352. else if ( type === 'fromData' || type === 'toVisible' ) {
  7353. return _fnColumnIndexToVisible( ctx, idx );
  7354. }
  7355. }
  7356. } );
  7357. _api_register( 'column()', function ( selector, opts ) {
  7358. return _selector_first( this.columns( selector, opts ) );
  7359. } );
  7360. var __cell_selector = function ( settings, selector, opts )
  7361. {
  7362. var data = settings.aoData;
  7363. var rows = _selector_row_indexes( settings, opts );
  7364. var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
  7365. var allCells = $( [].concat.apply([], cells) );
  7366. var row;
  7367. var columns = settings.aoColumns.length;
  7368. var a, i, ien, j, o, host;
  7369. var run = function ( s ) {
  7370. var fnSelector = typeof s === 'function';
  7371. if ( s === null || s === undefined || fnSelector ) {
  7372. // All cells and function selectors
  7373. a = [];
  7374. for ( i=0, ien=rows.length ; i<ien ; i++ ) {
  7375. row = rows[i];
  7376. for ( j=0 ; j<columns ; j++ ) {
  7377. o = {
  7378. row: row,
  7379. column: j
  7380. };
  7381. if ( fnSelector ) {
  7382. // Selector - function
  7383. host = data[ row ];
  7384. if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
  7385. a.push( o );
  7386. }
  7387. }
  7388. else {
  7389. // Selector - all
  7390. a.push( o );
  7391. }
  7392. }
  7393. }
  7394. return a;
  7395. }
  7396. // Selector - index
  7397. if ( $.isPlainObject( s ) ) {
  7398. return [s];
  7399. }
  7400. // Selector - jQuery filtered cells
  7401. var jqResult = allCells
  7402. .filter( s )
  7403. .map( function (i, el) {
  7404. return { // use a new object, in case someone changes the values
  7405. row: el._DT_CellIndex.row,
  7406. column: el._DT_CellIndex.column
  7407. };
  7408. } )
  7409. .toArray();
  7410. if ( jqResult.length || ! s.nodeName ) {
  7411. return jqResult;
  7412. }
  7413. // Otherwise the selector is a node, and there is one last option - the
  7414. // element might be a child of an element which has dt-row and dt-column
  7415. // data attributes
  7416. host = $(s).closest('*[data-dt-row]');
  7417. return host.length ?
  7418. [ {
  7419. row: host.data('dt-row'),
  7420. column: host.data('dt-column')
  7421. } ] :
  7422. [];
  7423. };
  7424. return _selector_run( 'cell', selector, run, settings, opts );
  7425. };
  7426. _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
  7427. // Argument shifting
  7428. if ( $.isPlainObject( rowSelector ) ) {
  7429. // Indexes
  7430. if ( rowSelector.row === undefined ) {
  7431. // Selector options in first parameter
  7432. opts = rowSelector;
  7433. rowSelector = null;
  7434. }
  7435. else {
  7436. // Cell index objects in first parameter
  7437. opts = columnSelector;
  7438. columnSelector = null;
  7439. }
  7440. }
  7441. if ( $.isPlainObject( columnSelector ) ) {
  7442. opts = columnSelector;
  7443. columnSelector = null;
  7444. }
  7445. // Cell selector
  7446. if ( columnSelector === null || columnSelector === undefined ) {
  7447. return this.iterator( 'table', function ( settings ) {
  7448. return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
  7449. } );
  7450. }
  7451. // Row + column selector
  7452. var columns = this.columns( columnSelector, opts );
  7453. var rows = this.rows( rowSelector, opts );
  7454. var a, i, ien, j, jen;
  7455. var cells = this.iterator( 'table', function ( settings, idx ) {
  7456. a = [];
  7457. for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
  7458. for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
  7459. a.push( {
  7460. row: rows[idx][i],
  7461. column: columns[idx][j]
  7462. } );
  7463. }
  7464. }
  7465. return a;
  7466. }, 1 );
  7467. $.extend( cells.selector, {
  7468. cols: columnSelector,
  7469. rows: rowSelector,
  7470. opts: opts
  7471. } );
  7472. return cells;
  7473. } );
  7474. _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
  7475. return this.iterator( 'cell', function ( settings, row, column ) {
  7476. var data = settings.aoData[ row ];
  7477. return data && data.anCells ?
  7478. data.anCells[ column ] :
  7479. undefined;
  7480. }, 1 );
  7481. } );
  7482. _api_register( 'cells().data()', function () {
  7483. return this.iterator( 'cell', function ( settings, row, column ) {
  7484. return _fnGetCellData( settings, row, column );
  7485. }, 1 );
  7486. } );
  7487. _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
  7488. type = type === 'search' ? '_aFilterData' : '_aSortData';
  7489. return this.iterator( 'cell', function ( settings, row, column ) {
  7490. return settings.aoData[ row ][ type ][ column ];
  7491. }, 1 );
  7492. } );
  7493. _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
  7494. return this.iterator( 'cell', function ( settings, row, column ) {
  7495. return _fnGetCellData( settings, row, column, type );
  7496. }, 1 );
  7497. } );
  7498. _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
  7499. return this.iterator( 'cell', function ( settings, row, column ) {
  7500. return {
  7501. row: row,
  7502. column: column,
  7503. columnVisible: _fnColumnIndexToVisible( settings, column )
  7504. };
  7505. }, 1 );
  7506. } );
  7507. _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
  7508. return this.iterator( 'cell', function ( settings, row, column ) {
  7509. _fnInvalidate( settings, row, src, column );
  7510. } );
  7511. } );
  7512. _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
  7513. return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
  7514. } );
  7515. _api_register( 'cell().data()', function ( data ) {
  7516. var ctx = this.context;
  7517. var cell = this[0];
  7518. if ( data === undefined ) {
  7519. // Get
  7520. return ctx.length && cell.length ?
  7521. _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
  7522. undefined;
  7523. }
  7524. // Set
  7525. _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
  7526. _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
  7527. return this;
  7528. } );
  7529. /**
  7530. * Get current ordering (sorting) that has been applied to the table.
  7531. *
  7532. * @returns {array} 2D array containing the sorting information for the first
  7533. * table in the current context. Each element in the parent array represents
  7534. * a column being sorted upon (i.e. multi-sorting with two columns would have
  7535. * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
  7536. * the column index that the sorting condition applies to, the second is the
  7537. * direction of the sort (`desc` or `asc`) and, optionally, the third is the
  7538. * index of the sorting order from the `column.sorting` initialisation array.
  7539. *//**
  7540. * Set the ordering for the table.
  7541. *
  7542. * @param {integer} order Column index to sort upon.
  7543. * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
  7544. * @returns {DataTables.Api} this
  7545. *//**
  7546. * Set the ordering for the table.
  7547. *
  7548. * @param {array} order 1D array of sorting information to be applied.
  7549. * @param {array} [...] Optional additional sorting conditions
  7550. * @returns {DataTables.Api} this
  7551. *//**
  7552. * Set the ordering for the table.
  7553. *
  7554. * @param {array} order 2D array of sorting information to be applied.
  7555. * @returns {DataTables.Api} this
  7556. */
  7557. _api_register( 'order()', function ( order, dir ) {
  7558. var ctx = this.context;
  7559. if ( order === undefined ) {
  7560. // get
  7561. return ctx.length !== 0 ?
  7562. ctx[0].aaSorting :
  7563. undefined;
  7564. }
  7565. // set
  7566. if ( typeof order === 'number' ) {
  7567. // Simple column / direction passed in
  7568. order = [ [ order, dir ] ];
  7569. }
  7570. else if ( order.length && ! $.isArray( order[0] ) ) {
  7571. // Arguments passed in (list of 1D arrays)
  7572. order = Array.prototype.slice.call( arguments );
  7573. }
  7574. // otherwise a 2D array was passed in
  7575. return this.iterator( 'table', function ( settings ) {
  7576. settings.aaSorting = order.slice();
  7577. } );
  7578. } );
  7579. /**
  7580. * Attach a sort listener to an element for a given column
  7581. *
  7582. * @param {node|jQuery|string} node Identifier for the element(s) to attach the
  7583. * listener to. This can take the form of a single DOM node, a jQuery
  7584. * collection of nodes or a jQuery selector which will identify the node(s).
  7585. * @param {integer} column the column that a click on this node will sort on
  7586. * @param {function} [callback] callback function when sort is run
  7587. * @returns {DataTables.Api} this
  7588. */
  7589. _api_register( 'order.listener()', function ( node, column, callback ) {
  7590. return this.iterator( 'table', function ( settings ) {
  7591. _fnSortAttachListener( settings, node, column, callback );
  7592. } );
  7593. } );
  7594. _api_register( 'order.fixed()', function ( set ) {
  7595. if ( ! set ) {
  7596. var ctx = this.context;
  7597. var fixed = ctx.length ?
  7598. ctx[0].aaSortingFixed :
  7599. undefined;
  7600. return $.isArray( fixed ) ?
  7601. { pre: fixed } :
  7602. fixed;
  7603. }
  7604. return this.iterator( 'table', function ( settings ) {
  7605. settings.aaSortingFixed = $.extend( true, {}, set );
  7606. } );
  7607. } );
  7608. // Order by the selected column(s)
  7609. _api_register( [
  7610. 'columns().order()',
  7611. 'column().order()'
  7612. ], function ( dir ) {
  7613. var that = this;
  7614. return this.iterator( 'table', function ( settings, i ) {
  7615. var sort = [];
  7616. $.each( that[i], function (j, col) {
  7617. sort.push( [ col, dir ] );
  7618. } );
  7619. settings.aaSorting = sort;
  7620. } );
  7621. } );
  7622. _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
  7623. var ctx = this.context;
  7624. if ( input === undefined ) {
  7625. // get
  7626. return ctx.length !== 0 ?
  7627. ctx[0].oPreviousSearch.sSearch :
  7628. undefined;
  7629. }
  7630. // set
  7631. return this.iterator( 'table', function ( settings ) {
  7632. if ( ! settings.oFeatures.bFilter ) {
  7633. return;
  7634. }
  7635. _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
  7636. "sSearch": input+"",
  7637. "bRegex": regex === null ? false : regex,
  7638. "bSmart": smart === null ? true : smart,
  7639. "bCaseInsensitive": caseInsen === null ? true : caseInsen
  7640. } ), 1 );
  7641. } );
  7642. } );
  7643. _api_registerPlural(
  7644. 'columns().search()',
  7645. 'column().search()',
  7646. function ( input, regex, smart, caseInsen ) {
  7647. return this.iterator( 'column', function ( settings, column ) {
  7648. var preSearch = settings.aoPreSearchCols;
  7649. if ( input === undefined ) {
  7650. // get
  7651. return preSearch[ column ].sSearch;
  7652. }
  7653. // set
  7654. if ( ! settings.oFeatures.bFilter ) {
  7655. return;
  7656. }
  7657. $.extend( preSearch[ column ], {
  7658. "sSearch": input+"",
  7659. "bRegex": regex === null ? false : regex,
  7660. "bSmart": smart === null ? true : smart,
  7661. "bCaseInsensitive": caseInsen === null ? true : caseInsen
  7662. } );
  7663. _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
  7664. } );
  7665. }
  7666. );
  7667. /*
  7668. * State API methods
  7669. */
  7670. _api_register( 'state()', function () {
  7671. return this.context.length ?
  7672. this.context[0].oSavedState :
  7673. null;
  7674. } );
  7675. _api_register( 'state.clear()', function () {
  7676. return this.iterator( 'table', function ( settings ) {
  7677. // Save an empty object
  7678. settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
  7679. } );
  7680. } );
  7681. _api_register( 'state.loaded()', function () {
  7682. return this.context.length ?
  7683. this.context[0].oLoadedState :
  7684. null;
  7685. } );
  7686. _api_register( 'state.save()', function () {
  7687. return this.iterator( 'table', function ( settings ) {
  7688. _fnSaveState( settings );
  7689. } );
  7690. } );
  7691. /**
  7692. * Provide a common method for plug-ins to check the version of DataTables being
  7693. * used, in order to ensure compatibility.
  7694. *
  7695. * @param {string} version Version string to check for, in the format "X.Y.Z".
  7696. * Note that the formats "X" and "X.Y" are also acceptable.
  7697. * @returns {boolean} true if this version of DataTables is greater or equal to
  7698. * the required version, or false if this version of DataTales is not
  7699. * suitable
  7700. * @static
  7701. * @dtopt API-Static
  7702. *
  7703. * @example
  7704. * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
  7705. */
  7706. DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
  7707. {
  7708. var aThis = DataTable.version.split('.');
  7709. var aThat = version.split('.');
  7710. var iThis, iThat;
  7711. for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
  7712. iThis = parseInt( aThis[i], 10 ) || 0;
  7713. iThat = parseInt( aThat[i], 10 ) || 0;
  7714. // Parts are the same, keep comparing
  7715. if (iThis === iThat) {
  7716. continue;
  7717. }
  7718. // Parts are different, return immediately
  7719. return iThis > iThat;
  7720. }
  7721. return true;
  7722. };
  7723. /**
  7724. * Check if a `<table>` node is a DataTable table already or not.
  7725. *
  7726. * @param {node|jquery|string} table Table node, jQuery object or jQuery
  7727. * selector for the table to test. Note that if more than more than one
  7728. * table is passed on, only the first will be checked
  7729. * @returns {boolean} true the table given is a DataTable, or false otherwise
  7730. * @static
  7731. * @dtopt API-Static
  7732. *
  7733. * @example
  7734. * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
  7735. * $('#example').dataTable();
  7736. * }
  7737. */
  7738. DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
  7739. {
  7740. var t = $(table).get(0);
  7741. var is = false;
  7742. if ( table instanceof DataTable.Api ) {
  7743. return true;
  7744. }
  7745. $.each( DataTable.settings, function (i, o) {
  7746. var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
  7747. var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
  7748. if ( o.nTable === t || head === t || foot === t ) {
  7749. is = true;
  7750. }
  7751. } );
  7752. return is;
  7753. };
  7754. /**
  7755. * Get all DataTable tables that have been initialised - optionally you can
  7756. * select to get only currently visible tables.
  7757. *
  7758. * @param {boolean} [visible=false] Flag to indicate if you want all (default)
  7759. * or visible tables only.
  7760. * @returns {array} Array of `table` nodes (not DataTable instances) which are
  7761. * DataTables
  7762. * @static
  7763. * @dtopt API-Static
  7764. *
  7765. * @example
  7766. * $.each( $.fn.dataTable.tables(true), function () {
  7767. * $(table).DataTable().columns.adjust();
  7768. * } );
  7769. */
  7770. DataTable.tables = DataTable.fnTables = function ( visible )
  7771. {
  7772. var api = false;
  7773. if ( $.isPlainObject( visible ) ) {
  7774. api = visible.api;
  7775. visible = visible.visible;
  7776. }
  7777. var a = $.map( DataTable.settings, function (o) {
  7778. if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
  7779. return o.nTable;
  7780. }
  7781. } );
  7782. return api ?
  7783. new _Api( a ) :
  7784. a;
  7785. };
  7786. /**
  7787. * Convert from camel case parameters to Hungarian notation. This is made public
  7788. * for the extensions to provide the same ability as DataTables core to accept
  7789. * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
  7790. * parameters.
  7791. *
  7792. * @param {object} src The model object which holds all parameters that can be
  7793. * mapped.
  7794. * @param {object} user The object to convert from camel case to Hungarian.
  7795. * @param {boolean} force When set to `true`, properties which already have a
  7796. * Hungarian value in the `user` object will be overwritten. Otherwise they
  7797. * won't be.
  7798. */
  7799. DataTable.camelToHungarian = _fnCamelToHungarian;
  7800. /**
  7801. *
  7802. */
  7803. _api_register( '$()', function ( selector, opts ) {
  7804. var
  7805. rows = this.rows( opts ).nodes(), // Get all rows
  7806. jqRows = $(rows);
  7807. return $( [].concat(
  7808. jqRows.filter( selector ).toArray(),
  7809. jqRows.find( selector ).toArray()
  7810. ) );
  7811. } );
  7812. // jQuery functions to operate on the tables
  7813. $.each( [ 'on', 'one', 'off' ], function (i, key) {
  7814. _api_register( key+'()', function ( /* event, handler */ ) {
  7815. var args = Array.prototype.slice.call(arguments);
  7816. // Add the `dt` namespace automatically if it isn't already present
  7817. args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
  7818. return ! e.match(/\.dt\b/) ?
  7819. e+'.dt' :
  7820. e;
  7821. } ).join( ' ' );
  7822. var inst = $( this.tables().nodes() );
  7823. inst[key].apply( inst, args );
  7824. return this;
  7825. } );
  7826. } );
  7827. _api_register( 'clear()', function () {
  7828. return this.iterator( 'table', function ( settings ) {
  7829. _fnClearTable( settings );
  7830. } );
  7831. } );
  7832. _api_register( 'settings()', function () {
  7833. return new _Api( this.context, this.context );
  7834. } );
  7835. _api_register( 'init()', function () {
  7836. var ctx = this.context;
  7837. return ctx.length ? ctx[0].oInit : null;
  7838. } );
  7839. _api_register( 'data()', function () {
  7840. return this.iterator( 'table', function ( settings ) {
  7841. return _pluck( settings.aoData, '_aData' );
  7842. } ).flatten();
  7843. } );
  7844. _api_register( 'destroy()', function ( remove ) {
  7845. remove = remove || false;
  7846. return this.iterator( 'table', function ( settings ) {
  7847. var orig = settings.nTableWrapper.parentNode;
  7848. var classes = settings.oClasses;
  7849. var table = settings.nTable;
  7850. var tbody = settings.nTBody;
  7851. var thead = settings.nTHead;
  7852. var tfoot = settings.nTFoot;
  7853. var jqTable = $(table);
  7854. var jqTbody = $(tbody);
  7855. var jqWrapper = $(settings.nTableWrapper);
  7856. var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
  7857. var i, ien;
  7858. // Flag to note that the table is currently being destroyed - no action
  7859. // should be taken
  7860. settings.bDestroying = true;
  7861. // Fire off the destroy callbacks for plug-ins etc
  7862. _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
  7863. // If not being removed from the document, make all columns visible
  7864. if ( ! remove ) {
  7865. new _Api( settings ).columns().visible( true );
  7866. }
  7867. // Blitz all `DT` namespaced events (these are internal events, the
  7868. // lowercase, `dt` events are user subscribed and they are responsible
  7869. // for removing them
  7870. jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
  7871. $(window).off('.DT-'+settings.sInstance);
  7872. // When scrolling we had to break the table up - restore it
  7873. if ( table != thead.parentNode ) {
  7874. jqTable.children('thead').detach();
  7875. jqTable.append( thead );
  7876. }
  7877. if ( tfoot && table != tfoot.parentNode ) {
  7878. jqTable.children('tfoot').detach();
  7879. jqTable.append( tfoot );
  7880. }
  7881. settings.aaSorting = [];
  7882. settings.aaSortingFixed = [];
  7883. _fnSortingClasses( settings );
  7884. $( rows ).removeClass( settings.asStripeClasses.join(' ') );
  7885. $('th, td', thead).removeClass( classes.sSortable+' '+
  7886. classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
  7887. );
  7888. // Add the TR elements back into the table in their original order
  7889. jqTbody.children().detach();
  7890. jqTbody.append( rows );
  7891. // Remove the DataTables generated nodes, events and classes
  7892. var removedMethod = remove ? 'remove' : 'detach';
  7893. jqTable[ removedMethod ]();
  7894. jqWrapper[ removedMethod ]();
  7895. // If we need to reattach the table to the document
  7896. if ( ! remove && orig ) {
  7897. // insertBefore acts like appendChild if !arg[1]
  7898. orig.insertBefore( table, settings.nTableReinsertBefore );
  7899. // Restore the width of the original table - was read from the style property,
  7900. // so we can restore directly to that
  7901. jqTable
  7902. .css( 'width', settings.sDestroyWidth )
  7903. .removeClass( classes.sTable );
  7904. // If the were originally stripe classes - then we add them back here.
  7905. // Note this is not fool proof (for example if not all rows had stripe
  7906. // classes - but it's a good effort without getting carried away
  7907. ien = settings.asDestroyStripes.length;
  7908. if ( ien ) {
  7909. jqTbody.children().each( function (i) {
  7910. $(this).addClass( settings.asDestroyStripes[i % ien] );
  7911. } );
  7912. }
  7913. }
  7914. /* Remove the settings object from the settings array */
  7915. var idx = $.inArray( settings, DataTable.settings );
  7916. if ( idx !== -1 ) {
  7917. DataTable.settings.splice( idx, 1 );
  7918. }
  7919. } );
  7920. } );
  7921. // Add the `every()` method for rows, columns and cells in a compact form
  7922. $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
  7923. _api_register( type+'s().every()', function ( fn ) {
  7924. var opts = this.selector.opts;
  7925. var api = this;
  7926. return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
  7927. // Rows and columns:
  7928. // arg1 - index
  7929. // arg2 - table counter
  7930. // arg3 - loop counter
  7931. // arg4 - undefined
  7932. // Cells:
  7933. // arg1 - row index
  7934. // arg2 - column index
  7935. // arg3 - table counter
  7936. // arg4 - loop counter
  7937. fn.call(
  7938. api[ type ](
  7939. arg1,
  7940. type==='cell' ? arg2 : opts,
  7941. type==='cell' ? opts : undefined
  7942. ),
  7943. arg1, arg2, arg3, arg4
  7944. );
  7945. } );
  7946. } );
  7947. } );
  7948. // i18n method for extensions to be able to use the language object from the
  7949. // DataTable
  7950. _api_register( 'i18n()', function ( token, def, plural ) {
  7951. var ctx = this.context[0];
  7952. var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
  7953. if ( resolved === undefined ) {
  7954. resolved = def;
  7955. }
  7956. if ( plural !== undefined && $.isPlainObject( resolved ) ) {
  7957. resolved = resolved[ plural ] !== undefined ?
  7958. resolved[ plural ] :
  7959. resolved._;
  7960. }
  7961. return resolved.replace( '%d', plural ); // nb: plural might be undefined,
  7962. } );
  7963. /**
  7964. * Version string for plug-ins to check compatibility. Allowed format is
  7965. * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
  7966. * only for non-release builds. See http://semver.org/ for more information.
  7967. * @member
  7968. * @type string
  7969. * @default Version number
  7970. */
  7971. DataTable.version = "1.10.16";
  7972. /**
  7973. * Private data store, containing all of the settings objects that are
  7974. * created for the tables on a given page.
  7975. *
  7976. * Note that the `DataTable.settings` object is aliased to
  7977. * `jQuery.fn.dataTableExt` through which it may be accessed and
  7978. * manipulated, or `jQuery.fn.dataTable.settings`.
  7979. * @member
  7980. * @type array
  7981. * @default []
  7982. * @private
  7983. */
  7984. DataTable.settings = [];
  7985. /**
  7986. * Object models container, for the various models that DataTables has
  7987. * available to it. These models define the objects that are used to hold
  7988. * the active state and configuration of the table.
  7989. * @namespace
  7990. */
  7991. DataTable.models = {};
  7992. /**
  7993. * Template object for the way in which DataTables holds information about
  7994. * search information for the global filter and individual column filters.
  7995. * @namespace
  7996. */
  7997. DataTable.models.oSearch = {
  7998. /**
  7999. * Flag to indicate if the filtering should be case insensitive or not
  8000. * @type boolean
  8001. * @default true
  8002. */
  8003. "bCaseInsensitive": true,
  8004. /**
  8005. * Applied search term
  8006. * @type string
  8007. * @default <i>Empty string</i>
  8008. */
  8009. "sSearch": "",
  8010. /**
  8011. * Flag to indicate if the search term should be interpreted as a
  8012. * regular expression (true) or not (false) and therefore and special
  8013. * regex characters escaped.
  8014. * @type boolean
  8015. * @default false
  8016. */
  8017. "bRegex": false,
  8018. /**
  8019. * Flag to indicate if DataTables is to use its smart filtering or not.
  8020. * @type boolean
  8021. * @default true
  8022. */
  8023. "bSmart": true
  8024. };
  8025. /**
  8026. * Template object for the way in which DataTables holds information about
  8027. * each individual row. This is the object format used for the settings
  8028. * aoData array.
  8029. * @namespace
  8030. */
  8031. DataTable.models.oRow = {
  8032. /**
  8033. * TR element for the row
  8034. * @type node
  8035. * @default null
  8036. */
  8037. "nTr": null,
  8038. /**
  8039. * Array of TD elements for each row. This is null until the row has been
  8040. * created.
  8041. * @type array nodes
  8042. * @default []
  8043. */
  8044. "anCells": null,
  8045. /**
  8046. * Data object from the original data source for the row. This is either
  8047. * an array if using the traditional form of DataTables, or an object if
  8048. * using mData options. The exact type will depend on the passed in
  8049. * data from the data source, or will be an array if using DOM a data
  8050. * source.
  8051. * @type array|object
  8052. * @default []
  8053. */
  8054. "_aData": [],
  8055. /**
  8056. * Sorting data cache - this array is ostensibly the same length as the
  8057. * number of columns (although each index is generated only as it is
  8058. * needed), and holds the data that is used for sorting each column in the
  8059. * row. We do this cache generation at the start of the sort in order that
  8060. * the formatting of the sort data need be done only once for each cell
  8061. * per sort. This array should not be read from or written to by anything
  8062. * other than the master sorting methods.
  8063. * @type array
  8064. * @default null
  8065. * @private
  8066. */
  8067. "_aSortData": null,
  8068. /**
  8069. * Per cell filtering data cache. As per the sort data cache, used to
  8070. * increase the performance of the filtering in DataTables
  8071. * @type array
  8072. * @default null
  8073. * @private
  8074. */
  8075. "_aFilterData": null,
  8076. /**
  8077. * Filtering data cache. This is the same as the cell filtering cache, but
  8078. * in this case a string rather than an array. This is easily computed with
  8079. * a join on `_aFilterData`, but is provided as a cache so the join isn't
  8080. * needed on every search (memory traded for performance)
  8081. * @type array
  8082. * @default null
  8083. * @private
  8084. */
  8085. "_sFilterRow": null,
  8086. /**
  8087. * Cache of the class name that DataTables has applied to the row, so we
  8088. * can quickly look at this variable rather than needing to do a DOM check
  8089. * on className for the nTr property.
  8090. * @type string
  8091. * @default <i>Empty string</i>
  8092. * @private
  8093. */
  8094. "_sRowStripe": "",
  8095. /**
  8096. * Denote if the original data source was from the DOM, or the data source
  8097. * object. This is used for invalidating data, so DataTables can
  8098. * automatically read data from the original source, unless uninstructed
  8099. * otherwise.
  8100. * @type string
  8101. * @default null
  8102. * @private
  8103. */
  8104. "src": null,
  8105. /**
  8106. * Index in the aoData array. This saves an indexOf lookup when we have the
  8107. * object, but want to know the index
  8108. * @type integer
  8109. * @default -1
  8110. * @private
  8111. */
  8112. "idx": -1
  8113. };
  8114. /**
  8115. * Template object for the column information object in DataTables. This object
  8116. * is held in the settings aoColumns array and contains all the information that
  8117. * DataTables needs about each individual column.
  8118. *
  8119. * Note that this object is related to {@link DataTable.defaults.column}
  8120. * but this one is the internal data store for DataTables's cache of columns.
  8121. * It should NOT be manipulated outside of DataTables. Any configuration should
  8122. * be done through the initialisation options.
  8123. * @namespace
  8124. */
  8125. DataTable.models.oColumn = {
  8126. /**
  8127. * Column index. This could be worked out on-the-fly with $.inArray, but it
  8128. * is faster to just hold it as a variable
  8129. * @type integer
  8130. * @default null
  8131. */
  8132. "idx": null,
  8133. /**
  8134. * A list of the columns that sorting should occur on when this column
  8135. * is sorted. That this property is an array allows multi-column sorting
  8136. * to be defined for a column (for example first name / last name columns
  8137. * would benefit from this). The values are integers pointing to the
  8138. * columns to be sorted on (typically it will be a single integer pointing
  8139. * at itself, but that doesn't need to be the case).
  8140. * @type array
  8141. */
  8142. "aDataSort": null,
  8143. /**
  8144. * Define the sorting directions that are applied to the column, in sequence
  8145. * as the column is repeatedly sorted upon - i.e. the first value is used
  8146. * as the sorting direction when the column if first sorted (clicked on).
  8147. * Sort it again (click again) and it will move on to the next index.
  8148. * Repeat until loop.
  8149. * @type array
  8150. */
  8151. "asSorting": null,
  8152. /**
  8153. * Flag to indicate if the column is searchable, and thus should be included
  8154. * in the filtering or not.
  8155. * @type boolean
  8156. */
  8157. "bSearchable": null,
  8158. /**
  8159. * Flag to indicate if the column is sortable or not.
  8160. * @type boolean
  8161. */
  8162. "bSortable": null,
  8163. /**
  8164. * Flag to indicate if the column is currently visible in the table or not
  8165. * @type boolean
  8166. */
  8167. "bVisible": null,
  8168. /**
  8169. * Store for manual type assignment using the `column.type` option. This
  8170. * is held in store so we can manipulate the column's `sType` property.
  8171. * @type string
  8172. * @default null
  8173. * @private
  8174. */
  8175. "_sManualType": null,
  8176. /**
  8177. * Flag to indicate if HTML5 data attributes should be used as the data
  8178. * source for filtering or sorting. True is either are.
  8179. * @type boolean
  8180. * @default false
  8181. * @private
  8182. */
  8183. "_bAttrSrc": false,
  8184. /**
  8185. * Developer definable function that is called whenever a cell is created (Ajax source,
  8186. * etc) or processed for input (DOM source). This can be used as a compliment to mRender
  8187. * allowing you to modify the DOM element (add background colour for example) when the
  8188. * element is available.
  8189. * @type function
  8190. * @param {element} nTd The TD node that has been created
  8191. * @param {*} sData The Data for the cell
  8192. * @param {array|object} oData The data for the whole row
  8193. * @param {int} iRow The row index for the aoData data store
  8194. * @default null
  8195. */
  8196. "fnCreatedCell": null,
  8197. /**
  8198. * Function to get data from a cell in a column. You should <b>never</b>
  8199. * access data directly through _aData internally in DataTables - always use
  8200. * the method attached to this property. It allows mData to function as
  8201. * required. This function is automatically assigned by the column
  8202. * initialisation method
  8203. * @type function
  8204. * @param {array|object} oData The data array/object for the array
  8205. * (i.e. aoData[]._aData)
  8206. * @param {string} sSpecific The specific data type you want to get -
  8207. * 'display', 'type' 'filter' 'sort'
  8208. * @returns {*} The data for the cell from the given row's data
  8209. * @default null
  8210. */
  8211. "fnGetData": null,
  8212. /**
  8213. * Function to set data for a cell in the column. You should <b>never</b>
  8214. * set the data directly to _aData internally in DataTables - always use
  8215. * this method. It allows mData to function as required. This function
  8216. * is automatically assigned by the column initialisation method
  8217. * @type function
  8218. * @param {array|object} oData The data array/object for the array
  8219. * (i.e. aoData[]._aData)
  8220. * @param {*} sValue Value to set
  8221. * @default null
  8222. */
  8223. "fnSetData": null,
  8224. /**
  8225. * Property to read the value for the cells in the column from the data
  8226. * source array / object. If null, then the default content is used, if a
  8227. * function is given then the return from the function is used.
  8228. * @type function|int|string|null
  8229. * @default null
  8230. */
  8231. "mData": null,
  8232. /**
  8233. * Partner property to mData which is used (only when defined) to get
  8234. * the data - i.e. it is basically the same as mData, but without the
  8235. * 'set' option, and also the data fed to it is the result from mData.
  8236. * This is the rendering method to match the data method of mData.
  8237. * @type function|int|string|null
  8238. * @default null
  8239. */
  8240. "mRender": null,
  8241. /**
  8242. * Unique header TH/TD element for this column - this is what the sorting
  8243. * listener is attached to (if sorting is enabled.)
  8244. * @type node
  8245. * @default null
  8246. */
  8247. "nTh": null,
  8248. /**
  8249. * Unique footer TH/TD element for this column (if there is one). Not used
  8250. * in DataTables as such, but can be used for plug-ins to reference the
  8251. * footer for each column.
  8252. * @type node
  8253. * @default null
  8254. */
  8255. "nTf": null,
  8256. /**
  8257. * The class to apply to all TD elements in the table's TBODY for the column
  8258. * @type string
  8259. * @default null
  8260. */
  8261. "sClass": null,
  8262. /**
  8263. * When DataTables calculates the column widths to assign to each column,
  8264. * it finds the longest string in each column and then constructs a
  8265. * temporary table and reads the widths from that. The problem with this
  8266. * is that "mmm" is much wider then "iiii", but the latter is a longer
  8267. * string - thus the calculation can go wrong (doing it properly and putting
  8268. * it into an DOM object and measuring that is horribly(!) slow). Thus as
  8269. * a "work around" we provide this option. It will append its value to the
  8270. * text that is found to be the longest string for the column - i.e. padding.
  8271. * @type string
  8272. */
  8273. "sContentPadding": null,
  8274. /**
  8275. * Allows a default value to be given for a column's data, and will be used
  8276. * whenever a null data source is encountered (this can be because mData
  8277. * is set to null, or because the data source itself is null).
  8278. * @type string
  8279. * @default null
  8280. */
  8281. "sDefaultContent": null,
  8282. /**
  8283. * Name for the column, allowing reference to the column by name as well as
  8284. * by index (needs a lookup to work by name).
  8285. * @type string
  8286. */
  8287. "sName": null,
  8288. /**
  8289. * Custom sorting data type - defines which of the available plug-ins in
  8290. * afnSortData the custom sorting will use - if any is defined.
  8291. * @type string
  8292. * @default std
  8293. */
  8294. "sSortDataType": 'std',
  8295. /**
  8296. * Class to be applied to the header element when sorting on this column
  8297. * @type string
  8298. * @default null
  8299. */
  8300. "sSortingClass": null,
  8301. /**
  8302. * Class to be applied to the header element when sorting on this column -
  8303. * when jQuery UI theming is used.
  8304. * @type string
  8305. * @default null
  8306. */
  8307. "sSortingClassJUI": null,
  8308. /**
  8309. * Title of the column - what is seen in the TH element (nTh).
  8310. * @type string
  8311. */
  8312. "sTitle": null,
  8313. /**
  8314. * Column sorting and filtering type
  8315. * @type string
  8316. * @default null
  8317. */
  8318. "sType": null,
  8319. /**
  8320. * Width of the column
  8321. * @type string
  8322. * @default null
  8323. */
  8324. "sWidth": null,
  8325. /**
  8326. * Width of the column when it was first "encountered"
  8327. * @type string
  8328. * @default null
  8329. */
  8330. "sWidthOrig": null
  8331. };
  8332. /*
  8333. * Developer note: The properties of the object below are given in Hungarian
  8334. * notation, that was used as the interface for DataTables prior to v1.10, however
  8335. * from v1.10 onwards the primary interface is camel case. In order to avoid
  8336. * breaking backwards compatibility utterly with this change, the Hungarian
  8337. * version is still, internally the primary interface, but is is not documented
  8338. * - hence the @name tags in each doc comment. This allows a Javascript function
  8339. * to create a map from Hungarian notation to camel case (going the other direction
  8340. * would require each property to be listed, which would at around 3K to the size
  8341. * of DataTables, while this method is about a 0.5K hit.
  8342. *
  8343. * Ultimately this does pave the way for Hungarian notation to be dropped
  8344. * completely, but that is a massive amount of work and will break current
  8345. * installs (therefore is on-hold until v2).
  8346. */
  8347. /**
  8348. * Initialisation options that can be given to DataTables at initialisation
  8349. * time.
  8350. * @namespace
  8351. */
  8352. DataTable.defaults = {
  8353. /**
  8354. * An array of data to use for the table, passed in at initialisation which
  8355. * will be used in preference to any data which is already in the DOM. This is
  8356. * particularly useful for constructing tables purely in Javascript, for
  8357. * example with a custom Ajax call.
  8358. * @type array
  8359. * @default null
  8360. *
  8361. * @dtopt Option
  8362. * @name DataTable.defaults.data
  8363. *
  8364. * @example
  8365. * // Using a 2D array data source
  8366. * $(document).ready( function () {
  8367. * $('#example').dataTable( {
  8368. * "data": [
  8369. * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
  8370. * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
  8371. * ],
  8372. * "columns": [
  8373. * { "title": "Engine" },
  8374. * { "title": "Browser" },
  8375. * { "title": "Platform" },
  8376. * { "title": "Version" },
  8377. * { "title": "Grade" }
  8378. * ]
  8379. * } );
  8380. * } );
  8381. *
  8382. * @example
  8383. * // Using an array of objects as a data source (`data`)
  8384. * $(document).ready( function () {
  8385. * $('#example').dataTable( {
  8386. * "data": [
  8387. * {
  8388. * "engine": "Trident",
  8389. * "browser": "Internet Explorer 4.0",
  8390. * "platform": "Win 95+",
  8391. * "version": 4,
  8392. * "grade": "X"
  8393. * },
  8394. * {
  8395. * "engine": "Trident",
  8396. * "browser": "Internet Explorer 5.0",
  8397. * "platform": "Win 95+",
  8398. * "version": 5,
  8399. * "grade": "C"
  8400. * }
  8401. * ],
  8402. * "columns": [
  8403. * { "title": "Engine", "data": "engine" },
  8404. * { "title": "Browser", "data": "browser" },
  8405. * { "title": "Platform", "data": "platform" },
  8406. * { "title": "Version", "data": "version" },
  8407. * { "title": "Grade", "data": "grade" }
  8408. * ]
  8409. * } );
  8410. * } );
  8411. */
  8412. "aaData": null,
  8413. /**
  8414. * If ordering is enabled, then DataTables will perform a first pass sort on
  8415. * initialisation. You can define which column(s) the sort is performed
  8416. * upon, and the sorting direction, with this variable. The `sorting` array
  8417. * should contain an array for each column to be sorted initially containing
  8418. * the column's index and a direction string ('asc' or 'desc').
  8419. * @type array
  8420. * @default [[0,'asc']]
  8421. *
  8422. * @dtopt Option
  8423. * @name DataTable.defaults.order
  8424. *
  8425. * @example
  8426. * // Sort by 3rd column first, and then 4th column
  8427. * $(document).ready( function() {
  8428. * $('#example').dataTable( {
  8429. * "order": [[2,'asc'], [3,'desc']]
  8430. * } );
  8431. * } );
  8432. *
  8433. * // No initial sorting
  8434. * $(document).ready( function() {
  8435. * $('#example').dataTable( {
  8436. * "order": []
  8437. * } );
  8438. * } );
  8439. */
  8440. "aaSorting": [[0,'asc']],
  8441. /**
  8442. * This parameter is basically identical to the `sorting` parameter, but
  8443. * cannot be overridden by user interaction with the table. What this means
  8444. * is that you could have a column (visible or hidden) which the sorting
  8445. * will always be forced on first - any sorting after that (from the user)
  8446. * will then be performed as required. This can be useful for grouping rows
  8447. * together.
  8448. * @type array
  8449. * @default null
  8450. *
  8451. * @dtopt Option
  8452. * @name DataTable.defaults.orderFixed
  8453. *
  8454. * @example
  8455. * $(document).ready( function() {
  8456. * $('#example').dataTable( {
  8457. * "orderFixed": [[0,'asc']]
  8458. * } );
  8459. * } )
  8460. */
  8461. "aaSortingFixed": [],
  8462. /**
  8463. * DataTables can be instructed to load data to display in the table from a
  8464. * Ajax source. This option defines how that Ajax call is made and where to.
  8465. *
  8466. * The `ajax` property has three different modes of operation, depending on
  8467. * how it is defined. These are:
  8468. *
  8469. * * `string` - Set the URL from where the data should be loaded from.
  8470. * * `object` - Define properties for `jQuery.ajax`.
  8471. * * `function` - Custom data get function
  8472. *
  8473. * `string`
  8474. * --------
  8475. *
  8476. * As a string, the `ajax` property simply defines the URL from which
  8477. * DataTables will load data.
  8478. *
  8479. * `object`
  8480. * --------
  8481. *
  8482. * As an object, the parameters in the object are passed to
  8483. * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
  8484. * of the Ajax request. DataTables has a number of default parameters which
  8485. * you can override using this option. Please refer to the jQuery
  8486. * documentation for a full description of the options available, although
  8487. * the following parameters provide additional options in DataTables or
  8488. * require special consideration:
  8489. *
  8490. * * `data` - As with jQuery, `data` can be provided as an object, but it
  8491. * can also be used as a function to manipulate the data DataTables sends
  8492. * to the server. The function takes a single parameter, an object of
  8493. * parameters with the values that DataTables has readied for sending. An
  8494. * object may be returned which will be merged into the DataTables
  8495. * defaults, or you can add the items to the object that was passed in and
  8496. * not return anything from the function. This supersedes `fnServerParams`
  8497. * from DataTables 1.9-.
  8498. *
  8499. * * `dataSrc` - By default DataTables will look for the property `data` (or
  8500. * `aaData` for compatibility with DataTables 1.9-) when obtaining data
  8501. * from an Ajax source or for server-side processing - this parameter
  8502. * allows that property to be changed. You can use Javascript dotted
  8503. * object notation to get a data source for multiple levels of nesting, or
  8504. * it my be used as a function. As a function it takes a single parameter,
  8505. * the JSON returned from the server, which can be manipulated as
  8506. * required, with the returned value being that used by DataTables as the
  8507. * data source for the table. This supersedes `sAjaxDataProp` from
  8508. * DataTables 1.9-.
  8509. *
  8510. * * `success` - Should not be overridden it is used internally in
  8511. * DataTables. To manipulate / transform the data returned by the server
  8512. * use `ajax.dataSrc`, or use `ajax` as a function (see below).
  8513. *
  8514. * `function`
  8515. * ----------
  8516. *
  8517. * As a function, making the Ajax call is left up to yourself allowing
  8518. * complete control of the Ajax request. Indeed, if desired, a method other
  8519. * than Ajax could be used to obtain the required data, such as Web storage
  8520. * or an AIR database.
  8521. *
  8522. * The function is given four parameters and no return is required. The
  8523. * parameters are:
  8524. *
  8525. * 1. _object_ - Data to send to the server
  8526. * 2. _function_ - Callback function that must be executed when the required
  8527. * data has been obtained. That data should be passed into the callback
  8528. * as the only parameter
  8529. * 3. _object_ - DataTables settings object for the table
  8530. *
  8531. * Note that this supersedes `fnServerData` from DataTables 1.9-.
  8532. *
  8533. * @type string|object|function
  8534. * @default null
  8535. *
  8536. * @dtopt Option
  8537. * @name DataTable.defaults.ajax
  8538. * @since 1.10.0
  8539. *
  8540. * @example
  8541. * // Get JSON data from a file via Ajax.
  8542. * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
  8543. * $('#example').dataTable( {
  8544. * "ajax": "data.json"
  8545. * } );
  8546. *
  8547. * @example
  8548. * // Get JSON data from a file via Ajax, using `dataSrc` to change
  8549. * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
  8550. * $('#example').dataTable( {
  8551. * "ajax": {
  8552. * "url": "data.json",
  8553. * "dataSrc": "tableData"
  8554. * }
  8555. * } );
  8556. *
  8557. * @example
  8558. * // Get JSON data from a file via Ajax, using `dataSrc` to read data
  8559. * // from a plain array rather than an array in an object
  8560. * $('#example').dataTable( {
  8561. * "ajax": {
  8562. * "url": "data.json",
  8563. * "dataSrc": ""
  8564. * }
  8565. * } );
  8566. *
  8567. * @example
  8568. * // Manipulate the data returned from the server - add a link to data
  8569. * // (note this can, should, be done using `render` for the column - this
  8570. * // is just a simple example of how the data can be manipulated).
  8571. * $('#example').dataTable( {
  8572. * "ajax": {
  8573. * "url": "data.json",
  8574. * "dataSrc": function ( json ) {
  8575. * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
  8576. * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
  8577. * }
  8578. * return json;
  8579. * }
  8580. * }
  8581. * } );
  8582. *
  8583. * @example
  8584. * // Add data to the request
  8585. * $('#example').dataTable( {
  8586. * "ajax": {
  8587. * "url": "data.json",
  8588. * "data": function ( d ) {
  8589. * return {
  8590. * "extra_search": $('#extra').val()
  8591. * };
  8592. * }
  8593. * }
  8594. * } );
  8595. *
  8596. * @example
  8597. * // Send request as POST
  8598. * $('#example').dataTable( {
  8599. * "ajax": {
  8600. * "url": "data.json",
  8601. * "type": "POST"
  8602. * }
  8603. * } );
  8604. *
  8605. * @example
  8606. * // Get the data from localStorage (could interface with a form for
  8607. * // adding, editing and removing rows).
  8608. * $('#example').dataTable( {
  8609. * "ajax": function (data, callback, settings) {
  8610. * callback(
  8611. * JSON.parse( localStorage.getItem('dataTablesData') )
  8612. * );
  8613. * }
  8614. * } );
  8615. */
  8616. "ajax": null,
  8617. /**
  8618. * This parameter allows you to readily specify the entries in the length drop
  8619. * down menu that DataTables shows when pagination is enabled. It can be
  8620. * either a 1D array of options which will be used for both the displayed
  8621. * option and the value, or a 2D array which will use the array in the first
  8622. * position as the value, and the array in the second position as the
  8623. * displayed options (useful for language strings such as 'All').
  8624. *
  8625. * Note that the `pageLength` property will be automatically set to the
  8626. * first value given in this array, unless `pageLength` is also provided.
  8627. * @type array
  8628. * @default [ 10, 25, 50, 100 ]
  8629. *
  8630. * @dtopt Option
  8631. * @name DataTable.defaults.lengthMenu
  8632. *
  8633. * @example
  8634. * $(document).ready( function() {
  8635. * $('#example').dataTable( {
  8636. * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
  8637. * } );
  8638. * } );
  8639. */
  8640. "aLengthMenu": [ 10, 25, 50, 100 ],
  8641. /**
  8642. * The `columns` option in the initialisation parameter allows you to define
  8643. * details about the way individual columns behave. For a full list of
  8644. * column options that can be set, please see
  8645. * {@link DataTable.defaults.column}. Note that if you use `columns` to
  8646. * define your columns, you must have an entry in the array for every single
  8647. * column that you have in your table (these can be null if you don't which
  8648. * to specify any options).
  8649. * @member
  8650. *
  8651. * @name DataTable.defaults.column
  8652. */
  8653. "aoColumns": null,
  8654. /**
  8655. * Very similar to `columns`, `columnDefs` allows you to target a specific
  8656. * column, multiple columns, or all columns, using the `targets` property of
  8657. * each object in the array. This allows great flexibility when creating
  8658. * tables, as the `columnDefs` arrays can be of any length, targeting the
  8659. * columns you specifically want. `columnDefs` may use any of the column
  8660. * options available: {@link DataTable.defaults.column}, but it _must_
  8661. * have `targets` defined in each object in the array. Values in the `targets`
  8662. * array may be:
  8663. * <ul>
  8664. * <li>a string - class name will be matched on the TH for the column</li>
  8665. * <li>0 or a positive integer - column index counting from the left</li>
  8666. * <li>a negative integer - column index counting from the right</li>
  8667. * <li>the string "_all" - all columns (i.e. assign a default)</li>
  8668. * </ul>
  8669. * @member
  8670. *
  8671. * @name DataTable.defaults.columnDefs
  8672. */
  8673. "aoColumnDefs": null,
  8674. /**
  8675. * Basically the same as `search`, this parameter defines the individual column
  8676. * filtering state at initialisation time. The array must be of the same size
  8677. * as the number of columns, and each element be an object with the parameters
  8678. * `search` and `escapeRegex` (the latter is optional). 'null' is also
  8679. * accepted and the default will be used.
  8680. * @type array
  8681. * @default []
  8682. *
  8683. * @dtopt Option
  8684. * @name DataTable.defaults.searchCols
  8685. *
  8686. * @example
  8687. * $(document).ready( function() {
  8688. * $('#example').dataTable( {
  8689. * "searchCols": [
  8690. * null,
  8691. * { "search": "My filter" },
  8692. * null,
  8693. * { "search": "^[0-9]", "escapeRegex": false }
  8694. * ]
  8695. * } );
  8696. * } )
  8697. */
  8698. "aoSearchCols": [],
  8699. /**
  8700. * An array of CSS classes that should be applied to displayed rows. This
  8701. * array may be of any length, and DataTables will apply each class
  8702. * sequentially, looping when required.
  8703. * @type array
  8704. * @default null <i>Will take the values determined by the `oClasses.stripe*`
  8705. * options</i>
  8706. *
  8707. * @dtopt Option
  8708. * @name DataTable.defaults.stripeClasses
  8709. *
  8710. * @example
  8711. * $(document).ready( function() {
  8712. * $('#example').dataTable( {
  8713. * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
  8714. * } );
  8715. * } )
  8716. */
  8717. "asStripeClasses": null,
  8718. /**
  8719. * Enable or disable automatic column width calculation. This can be disabled
  8720. * as an optimisation (it takes some time to calculate the widths) if the
  8721. * tables widths are passed in using `columns`.
  8722. * @type boolean
  8723. * @default true
  8724. *
  8725. * @dtopt Features
  8726. * @name DataTable.defaults.autoWidth
  8727. *
  8728. * @example
  8729. * $(document).ready( function () {
  8730. * $('#example').dataTable( {
  8731. * "autoWidth": false
  8732. * } );
  8733. * } );
  8734. */
  8735. "bAutoWidth": true,
  8736. /**
  8737. * Deferred rendering can provide DataTables with a huge speed boost when you
  8738. * are using an Ajax or JS data source for the table. This option, when set to
  8739. * true, will cause DataTables to defer the creation of the table elements for
  8740. * each row until they are needed for a draw - saving a significant amount of
  8741. * time.
  8742. * @type boolean
  8743. * @default false
  8744. *
  8745. * @dtopt Features
  8746. * @name DataTable.defaults.deferRender
  8747. *
  8748. * @example
  8749. * $(document).ready( function() {
  8750. * $('#example').dataTable( {
  8751. * "ajax": "sources/arrays.txt",
  8752. * "deferRender": true
  8753. * } );
  8754. * } );
  8755. */
  8756. "bDeferRender": false,
  8757. /**
  8758. * Replace a DataTable which matches the given selector and replace it with
  8759. * one which has the properties of the new initialisation object passed. If no
  8760. * table matches the selector, then the new DataTable will be constructed as
  8761. * per normal.
  8762. * @type boolean
  8763. * @default false
  8764. *
  8765. * @dtopt Options
  8766. * @name DataTable.defaults.destroy
  8767. *
  8768. * @example
  8769. * $(document).ready( function() {
  8770. * $('#example').dataTable( {
  8771. * "srollY": "200px",
  8772. * "paginate": false
  8773. * } );
  8774. *
  8775. * // Some time later....
  8776. * $('#example').dataTable( {
  8777. * "filter": false,
  8778. * "destroy": true
  8779. * } );
  8780. * } );
  8781. */
  8782. "bDestroy": false,
  8783. /**
  8784. * Enable or disable filtering of data. Filtering in DataTables is "smart" in
  8785. * that it allows the end user to input multiple words (space separated) and
  8786. * will match a row containing those words, even if not in the order that was
  8787. * specified (this allow matching across multiple columns). Note that if you
  8788. * wish to use filtering in DataTables this must remain 'true' - to remove the
  8789. * default filtering input box and retain filtering abilities, please use
  8790. * {@link DataTable.defaults.dom}.
  8791. * @type boolean
  8792. * @default true
  8793. *
  8794. * @dtopt Features
  8795. * @name DataTable.defaults.searching
  8796. *
  8797. * @example
  8798. * $(document).ready( function () {
  8799. * $('#example').dataTable( {
  8800. * "searching": false
  8801. * } );
  8802. * } );
  8803. */
  8804. "bFilter": true,
  8805. /**
  8806. * Enable or disable the table information display. This shows information
  8807. * about the data that is currently visible on the page, including information
  8808. * about filtered data if that action is being performed.
  8809. * @type boolean
  8810. * @default true
  8811. *
  8812. * @dtopt Features
  8813. * @name DataTable.defaults.info
  8814. *
  8815. * @example
  8816. * $(document).ready( function () {
  8817. * $('#example').dataTable( {
  8818. * "info": false
  8819. * } );
  8820. * } );
  8821. */
  8822. "bInfo": true,
  8823. /**
  8824. * Allows the end user to select the size of a formatted page from a select
  8825. * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
  8826. * @type boolean
  8827. * @default true
  8828. *
  8829. * @dtopt Features
  8830. * @name DataTable.defaults.lengthChange
  8831. *
  8832. * @example
  8833. * $(document).ready( function () {
  8834. * $('#example').dataTable( {
  8835. * "lengthChange": false
  8836. * } );
  8837. * } );
  8838. */
  8839. "bLengthChange": true,
  8840. /**
  8841. * Enable or disable pagination.
  8842. * @type boolean
  8843. * @default true
  8844. *
  8845. * @dtopt Features
  8846. * @name DataTable.defaults.paging
  8847. *
  8848. * @example
  8849. * $(document).ready( function () {
  8850. * $('#example').dataTable( {
  8851. * "paging": false
  8852. * } );
  8853. * } );
  8854. */
  8855. "bPaginate": true,
  8856. /**
  8857. * Enable or disable the display of a 'processing' indicator when the table is
  8858. * being processed (e.g. a sort). This is particularly useful for tables with
  8859. * large amounts of data where it can take a noticeable amount of time to sort
  8860. * the entries.
  8861. * @type boolean
  8862. * @default false
  8863. *
  8864. * @dtopt Features
  8865. * @name DataTable.defaults.processing
  8866. *
  8867. * @example
  8868. * $(document).ready( function () {
  8869. * $('#example').dataTable( {
  8870. * "processing": true
  8871. * } );
  8872. * } );
  8873. */
  8874. "bProcessing": false,
  8875. /**
  8876. * Retrieve the DataTables object for the given selector. Note that if the
  8877. * table has already been initialised, this parameter will cause DataTables
  8878. * to simply return the object that has already been set up - it will not take
  8879. * account of any changes you might have made to the initialisation object
  8880. * passed to DataTables (setting this parameter to true is an acknowledgement
  8881. * that you understand this). `destroy` can be used to reinitialise a table if
  8882. * you need.
  8883. * @type boolean
  8884. * @default false
  8885. *
  8886. * @dtopt Options
  8887. * @name DataTable.defaults.retrieve
  8888. *
  8889. * @example
  8890. * $(document).ready( function() {
  8891. * initTable();
  8892. * tableActions();
  8893. * } );
  8894. *
  8895. * function initTable ()
  8896. * {
  8897. * return $('#example').dataTable( {
  8898. * "scrollY": "200px",
  8899. * "paginate": false,
  8900. * "retrieve": true
  8901. * } );
  8902. * }
  8903. *
  8904. * function tableActions ()
  8905. * {
  8906. * var table = initTable();
  8907. * // perform API operations with oTable
  8908. * }
  8909. */
  8910. "bRetrieve": false,
  8911. /**
  8912. * When vertical (y) scrolling is enabled, DataTables will force the height of
  8913. * the table's viewport to the given height at all times (useful for layout).
  8914. * However, this can look odd when filtering data down to a small data set,
  8915. * and the footer is left "floating" further down. This parameter (when
  8916. * enabled) will cause DataTables to collapse the table's viewport down when
  8917. * the result set will fit within the given Y height.
  8918. * @type boolean
  8919. * @default false
  8920. *
  8921. * @dtopt Options
  8922. * @name DataTable.defaults.scrollCollapse
  8923. *
  8924. * @example
  8925. * $(document).ready( function() {
  8926. * $('#example').dataTable( {
  8927. * "scrollY": "200",
  8928. * "scrollCollapse": true
  8929. * } );
  8930. * } );
  8931. */
  8932. "bScrollCollapse": false,
  8933. /**
  8934. * Configure DataTables to use server-side processing. Note that the
  8935. * `ajax` parameter must also be given in order to give DataTables a
  8936. * source to obtain the required data for each draw.
  8937. * @type boolean
  8938. * @default false
  8939. *
  8940. * @dtopt Features
  8941. * @dtopt Server-side
  8942. * @name DataTable.defaults.serverSide
  8943. *
  8944. * @example
  8945. * $(document).ready( function () {
  8946. * $('#example').dataTable( {
  8947. * "serverSide": true,
  8948. * "ajax": "xhr.php"
  8949. * } );
  8950. * } );
  8951. */
  8952. "bServerSide": false,
  8953. /**
  8954. * Enable or disable sorting of columns. Sorting of individual columns can be
  8955. * disabled by the `sortable` option for each column.
  8956. * @type boolean
  8957. * @default true
  8958. *
  8959. * @dtopt Features
  8960. * @name DataTable.defaults.ordering
  8961. *
  8962. * @example
  8963. * $(document).ready( function () {
  8964. * $('#example').dataTable( {
  8965. * "ordering": false
  8966. * } );
  8967. * } );
  8968. */
  8969. "bSort": true,
  8970. /**
  8971. * Enable or display DataTables' ability to sort multiple columns at the
  8972. * same time (activated by shift-click by the user).
  8973. * @type boolean
  8974. * @default true
  8975. *
  8976. * @dtopt Options
  8977. * @name DataTable.defaults.orderMulti
  8978. *
  8979. * @example
  8980. * // Disable multiple column sorting ability
  8981. * $(document).ready( function () {
  8982. * $('#example').dataTable( {
  8983. * "orderMulti": false
  8984. * } );
  8985. * } );
  8986. */
  8987. "bSortMulti": true,
  8988. /**
  8989. * Allows control over whether DataTables should use the top (true) unique
  8990. * cell that is found for a single column, or the bottom (false - default).
  8991. * This is useful when using complex headers.
  8992. * @type boolean
  8993. * @default false
  8994. *
  8995. * @dtopt Options
  8996. * @name DataTable.defaults.orderCellsTop
  8997. *
  8998. * @example
  8999. * $(document).ready( function() {
  9000. * $('#example').dataTable( {
  9001. * "orderCellsTop": true
  9002. * } );
  9003. * } );
  9004. */
  9005. "bSortCellsTop": false,
  9006. /**
  9007. * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
  9008. * `sorting\_3` to the columns which are currently being sorted on. This is
  9009. * presented as a feature switch as it can increase processing time (while
  9010. * classes are removed and added) so for large data sets you might want to
  9011. * turn this off.
  9012. * @type boolean
  9013. * @default true
  9014. *
  9015. * @dtopt Features
  9016. * @name DataTable.defaults.orderClasses
  9017. *
  9018. * @example
  9019. * $(document).ready( function () {
  9020. * $('#example').dataTable( {
  9021. * "orderClasses": false
  9022. * } );
  9023. * } );
  9024. */
  9025. "bSortClasses": true,
  9026. /**
  9027. * Enable or disable state saving. When enabled HTML5 `localStorage` will be
  9028. * used to save table display information such as pagination information,
  9029. * display length, filtering and sorting. As such when the end user reloads
  9030. * the page the display display will match what thy had previously set up.
  9031. *
  9032. * Due to the use of `localStorage` the default state saving is not supported
  9033. * in IE6 or 7. If state saving is required in those browsers, use
  9034. * `stateSaveCallback` to provide a storage solution such as cookies.
  9035. * @type boolean
  9036. * @default false
  9037. *
  9038. * @dtopt Features
  9039. * @name DataTable.defaults.stateSave
  9040. *
  9041. * @example
  9042. * $(document).ready( function () {
  9043. * $('#example').dataTable( {
  9044. * "stateSave": true
  9045. * } );
  9046. * } );
  9047. */
  9048. "bStateSave": false,
  9049. /**
  9050. * This function is called when a TR element is created (and all TD child
  9051. * elements have been inserted), or registered if using a DOM source, allowing
  9052. * manipulation of the TR element (adding classes etc).
  9053. * @type function
  9054. * @param {node} row "TR" element for the current row
  9055. * @param {array} data Raw data array for this row
  9056. * @param {int} dataIndex The index of this row in the internal aoData array
  9057. *
  9058. * @dtopt Callbacks
  9059. * @name DataTable.defaults.createdRow
  9060. *
  9061. * @example
  9062. * $(document).ready( function() {
  9063. * $('#example').dataTable( {
  9064. * "createdRow": function( row, data, dataIndex ) {
  9065. * // Bold the grade for all 'A' grade browsers
  9066. * if ( data[4] == "A" )
  9067. * {
  9068. * $('td:eq(4)', row).html( '<b>A</b>' );
  9069. * }
  9070. * }
  9071. * } );
  9072. * } );
  9073. */
  9074. "fnCreatedRow": null,
  9075. /**
  9076. * This function is called on every 'draw' event, and allows you to
  9077. * dynamically modify any aspect you want about the created DOM.
  9078. * @type function
  9079. * @param {object} settings DataTables settings object
  9080. *
  9081. * @dtopt Callbacks
  9082. * @name DataTable.defaults.drawCallback
  9083. *
  9084. * @example
  9085. * $(document).ready( function() {
  9086. * $('#example').dataTable( {
  9087. * "drawCallback": function( settings ) {
  9088. * alert( 'DataTables has redrawn the table' );
  9089. * }
  9090. * } );
  9091. * } );
  9092. */
  9093. "fnDrawCallback": null,
  9094. /**
  9095. * Identical to fnHeaderCallback() but for the table footer this function
  9096. * allows you to modify the table footer on every 'draw' event.
  9097. * @type function
  9098. * @param {node} foot "TR" element for the footer
  9099. * @param {array} data Full table data (as derived from the original HTML)
  9100. * @param {int} start Index for the current display starting point in the
  9101. * display array
  9102. * @param {int} end Index for the current display ending point in the
  9103. * display array
  9104. * @param {array int} display Index array to translate the visual position
  9105. * to the full data array
  9106. *
  9107. * @dtopt Callbacks
  9108. * @name DataTable.defaults.footerCallback
  9109. *
  9110. * @example
  9111. * $(document).ready( function() {
  9112. * $('#example').dataTable( {
  9113. * "footerCallback": function( tfoot, data, start, end, display ) {
  9114. * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
  9115. * }
  9116. * } );
  9117. * } )
  9118. */
  9119. "fnFooterCallback": null,
  9120. /**
  9121. * When rendering large numbers in the information element for the table
  9122. * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
  9123. * to have a comma separator for the 'thousands' units (e.g. 1 million is
  9124. * rendered as "1,000,000") to help readability for the end user. This
  9125. * function will override the default method DataTables uses.
  9126. * @type function
  9127. * @member
  9128. * @param {int} toFormat number to be formatted
  9129. * @returns {string} formatted string for DataTables to show the number
  9130. *
  9131. * @dtopt Callbacks
  9132. * @name DataTable.defaults.formatNumber
  9133. *
  9134. * @example
  9135. * // Format a number using a single quote for the separator (note that
  9136. * // this can also be done with the language.thousands option)
  9137. * $(document).ready( function() {
  9138. * $('#example').dataTable( {
  9139. * "formatNumber": function ( toFormat ) {
  9140. * return toFormat.toString().replace(
  9141. * /\B(?=(\d{3})+(?!\d))/g, "'"
  9142. * );
  9143. * };
  9144. * } );
  9145. * } );
  9146. */
  9147. "fnFormatNumber": function ( toFormat ) {
  9148. return toFormat.toString().replace(
  9149. /\B(?=(\d{3})+(?!\d))/g,
  9150. this.oLanguage.sThousands
  9151. );
  9152. },
  9153. /**
  9154. * This function is called on every 'draw' event, and allows you to
  9155. * dynamically modify the header row. This can be used to calculate and
  9156. * display useful information about the table.
  9157. * @type function
  9158. * @param {node} head "TR" element for the header
  9159. * @param {array} data Full table data (as derived from the original HTML)
  9160. * @param {int} start Index for the current display starting point in the
  9161. * display array
  9162. * @param {int} end Index for the current display ending point in the
  9163. * display array
  9164. * @param {array int} display Index array to translate the visual position
  9165. * to the full data array
  9166. *
  9167. * @dtopt Callbacks
  9168. * @name DataTable.defaults.headerCallback
  9169. *
  9170. * @example
  9171. * $(document).ready( function() {
  9172. * $('#example').dataTable( {
  9173. * "fheaderCallback": function( head, data, start, end, display ) {
  9174. * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
  9175. * }
  9176. * } );
  9177. * } )
  9178. */
  9179. "fnHeaderCallback": null,
  9180. /**
  9181. * The information element can be used to convey information about the current
  9182. * state of the table. Although the internationalisation options presented by
  9183. * DataTables are quite capable of dealing with most customisations, there may
  9184. * be times where you wish to customise the string further. This callback
  9185. * allows you to do exactly that.
  9186. * @type function
  9187. * @param {object} oSettings DataTables settings object
  9188. * @param {int} start Starting position in data for the draw
  9189. * @param {int} end End position in data for the draw
  9190. * @param {int} max Total number of rows in the table (regardless of
  9191. * filtering)
  9192. * @param {int} total Total number of rows in the data set, after filtering
  9193. * @param {string} pre The string that DataTables has formatted using it's
  9194. * own rules
  9195. * @returns {string} The string to be displayed in the information element.
  9196. *
  9197. * @dtopt Callbacks
  9198. * @name DataTable.defaults.infoCallback
  9199. *
  9200. * @example
  9201. * $('#example').dataTable( {
  9202. * "infoCallback": function( settings, start, end, max, total, pre ) {
  9203. * return start +" to "+ end;
  9204. * }
  9205. * } );
  9206. */
  9207. "fnInfoCallback": null,
  9208. /**
  9209. * Called when the table has been initialised. Normally DataTables will
  9210. * initialise sequentially and there will be no need for this function,
  9211. * however, this does not hold true when using external language information
  9212. * since that is obtained using an async XHR call.
  9213. * @type function
  9214. * @param {object} settings DataTables settings object
  9215. * @param {object} json The JSON object request from the server - only
  9216. * present if client-side Ajax sourced data is used
  9217. *
  9218. * @dtopt Callbacks
  9219. * @name DataTable.defaults.initComplete
  9220. *
  9221. * @example
  9222. * $(document).ready( function() {
  9223. * $('#example').dataTable( {
  9224. * "initComplete": function(settings, json) {
  9225. * alert( 'DataTables has finished its initialisation.' );
  9226. * }
  9227. * } );
  9228. * } )
  9229. */
  9230. "fnInitComplete": null,
  9231. /**
  9232. * Called at the very start of each table draw and can be used to cancel the
  9233. * draw by returning false, any other return (including undefined) results in
  9234. * the full draw occurring).
  9235. * @type function
  9236. * @param {object} settings DataTables settings object
  9237. * @returns {boolean} False will cancel the draw, anything else (including no
  9238. * return) will allow it to complete.
  9239. *
  9240. * @dtopt Callbacks
  9241. * @name DataTable.defaults.preDrawCallback
  9242. *
  9243. * @example
  9244. * $(document).ready( function() {
  9245. * $('#example').dataTable( {
  9246. * "preDrawCallback": function( settings ) {
  9247. * if ( $('#test').val() == 1 ) {
  9248. * return false;
  9249. * }
  9250. * }
  9251. * } );
  9252. * } );
  9253. */
  9254. "fnPreDrawCallback": null,
  9255. /**
  9256. * This function allows you to 'post process' each row after it have been
  9257. * generated for each table draw, but before it is rendered on screen. This
  9258. * function might be used for setting the row class name etc.
  9259. * @type function
  9260. * @param {node} row "TR" element for the current row
  9261. * @param {array} data Raw data array for this row
  9262. * @param {int} displayIndex The display index for the current table draw
  9263. * @param {int} displayIndexFull The index of the data in the full list of
  9264. * rows (after filtering)
  9265. *
  9266. * @dtopt Callbacks
  9267. * @name DataTable.defaults.rowCallback
  9268. *
  9269. * @example
  9270. * $(document).ready( function() {
  9271. * $('#example').dataTable( {
  9272. * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
  9273. * // Bold the grade for all 'A' grade browsers
  9274. * if ( data[4] == "A" ) {
  9275. * $('td:eq(4)', row).html( '<b>A</b>' );
  9276. * }
  9277. * }
  9278. * } );
  9279. * } );
  9280. */
  9281. "fnRowCallback": null,
  9282. /**
  9283. * __Deprecated__ The functionality provided by this parameter has now been
  9284. * superseded by that provided through `ajax`, which should be used instead.
  9285. *
  9286. * This parameter allows you to override the default function which obtains
  9287. * the data from the server so something more suitable for your application.
  9288. * For example you could use POST data, or pull information from a Gears or
  9289. * AIR database.
  9290. * @type function
  9291. * @member
  9292. * @param {string} source HTTP source to obtain the data from (`ajax`)
  9293. * @param {array} data A key/value pair object containing the data to send
  9294. * to the server
  9295. * @param {function} callback to be called on completion of the data get
  9296. * process that will draw the data on the page.
  9297. * @param {object} settings DataTables settings object
  9298. *
  9299. * @dtopt Callbacks
  9300. * @dtopt Server-side
  9301. * @name DataTable.defaults.serverData
  9302. *
  9303. * @deprecated 1.10. Please use `ajax` for this functionality now.
  9304. */
  9305. "fnServerData": null,
  9306. /**
  9307. * __Deprecated__ The functionality provided by this parameter has now been
  9308. * superseded by that provided through `ajax`, which should be used instead.
  9309. *
  9310. * It is often useful to send extra data to the server when making an Ajax
  9311. * request - for example custom filtering information, and this callback
  9312. * function makes it trivial to send extra information to the server. The
  9313. * passed in parameter is the data set that has been constructed by
  9314. * DataTables, and you can add to this or modify it as you require.
  9315. * @type function
  9316. * @param {array} data Data array (array of objects which are name/value
  9317. * pairs) that has been constructed by DataTables and will be sent to the
  9318. * server. In the case of Ajax sourced data with server-side processing
  9319. * this will be an empty array, for server-side processing there will be a
  9320. * significant number of parameters!
  9321. * @returns {undefined} Ensure that you modify the data array passed in,
  9322. * as this is passed by reference.
  9323. *
  9324. * @dtopt Callbacks
  9325. * @dtopt Server-side
  9326. * @name DataTable.defaults.serverParams
  9327. *
  9328. * @deprecated 1.10. Please use `ajax` for this functionality now.
  9329. */
  9330. "fnServerParams": null,
  9331. /**
  9332. * Load the table state. With this function you can define from where, and how, the
  9333. * state of a table is loaded. By default DataTables will load from `localStorage`
  9334. * but you might wish to use a server-side database or cookies.
  9335. * @type function
  9336. * @member
  9337. * @param {object} settings DataTables settings object
  9338. * @param {object} callback Callback that can be executed when done. It
  9339. * should be passed the loaded state object.
  9340. * @return {object} The DataTables state object to be loaded
  9341. *
  9342. * @dtopt Callbacks
  9343. * @name DataTable.defaults.stateLoadCallback
  9344. *
  9345. * @example
  9346. * $(document).ready( function() {
  9347. * $('#example').dataTable( {
  9348. * "stateSave": true,
  9349. * "stateLoadCallback": function (settings, callback) {
  9350. * $.ajax( {
  9351. * "url": "/state_load",
  9352. * "dataType": "json",
  9353. * "success": function (json) {
  9354. * callback( json );
  9355. * }
  9356. * } );
  9357. * }
  9358. * } );
  9359. * } );
  9360. */
  9361. "fnStateLoadCallback": function ( settings ) {
  9362. try {
  9363. return JSON.parse(
  9364. (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
  9365. 'DataTables_'+settings.sInstance+'_'+location.pathname
  9366. )
  9367. );
  9368. } catch (e) {}
  9369. },
  9370. /**
  9371. * Callback which allows modification of the saved state prior to loading that state.
  9372. * This callback is called when the table is loading state from the stored data, but
  9373. * prior to the settings object being modified by the saved state. Note that for
  9374. * plug-in authors, you should use the `stateLoadParams` event to load parameters for
  9375. * a plug-in.
  9376. * @type function
  9377. * @param {object} settings DataTables settings object
  9378. * @param {object} data The state object that is to be loaded
  9379. *
  9380. * @dtopt Callbacks
  9381. * @name DataTable.defaults.stateLoadParams
  9382. *
  9383. * @example
  9384. * // Remove a saved filter, so filtering is never loaded
  9385. * $(document).ready( function() {
  9386. * $('#example').dataTable( {
  9387. * "stateSave": true,
  9388. * "stateLoadParams": function (settings, data) {
  9389. * data.oSearch.sSearch = "";
  9390. * }
  9391. * } );
  9392. * } );
  9393. *
  9394. * @example
  9395. * // Disallow state loading by returning false
  9396. * $(document).ready( function() {
  9397. * $('#example').dataTable( {
  9398. * "stateSave": true,
  9399. * "stateLoadParams": function (settings, data) {
  9400. * return false;
  9401. * }
  9402. * } );
  9403. * } );
  9404. */
  9405. "fnStateLoadParams": null,
  9406. /**
  9407. * Callback that is called when the state has been loaded from the state saving method
  9408. * and the DataTables settings object has been modified as a result of the loaded state.
  9409. * @type function
  9410. * @param {object} settings DataTables settings object
  9411. * @param {object} data The state object that was loaded
  9412. *
  9413. * @dtopt Callbacks
  9414. * @name DataTable.defaults.stateLoaded
  9415. *
  9416. * @example
  9417. * // Show an alert with the filtering value that was saved
  9418. * $(document).ready( function() {
  9419. * $('#example').dataTable( {
  9420. * "stateSave": true,
  9421. * "stateLoaded": function (settings, data) {
  9422. * alert( 'Saved filter was: '+data.oSearch.sSearch );
  9423. * }
  9424. * } );
  9425. * } );
  9426. */
  9427. "fnStateLoaded": null,
  9428. /**
  9429. * Save the table state. This function allows you to define where and how the state
  9430. * information for the table is stored By default DataTables will use `localStorage`
  9431. * but you might wish to use a server-side database or cookies.
  9432. * @type function
  9433. * @member
  9434. * @param {object} settings DataTables settings object
  9435. * @param {object} data The state object to be saved
  9436. *
  9437. * @dtopt Callbacks
  9438. * @name DataTable.defaults.stateSaveCallback
  9439. *
  9440. * @example
  9441. * $(document).ready( function() {
  9442. * $('#example').dataTable( {
  9443. * "stateSave": true,
  9444. * "stateSaveCallback": function (settings, data) {
  9445. * // Send an Ajax request to the server with the state object
  9446. * $.ajax( {
  9447. * "url": "/state_save",
  9448. * "data": data,
  9449. * "dataType": "json",
  9450. * "method": "POST"
  9451. * "success": function () {}
  9452. * } );
  9453. * }
  9454. * } );
  9455. * } );
  9456. */
  9457. "fnStateSaveCallback": function ( settings, data ) {
  9458. try {
  9459. (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
  9460. 'DataTables_'+settings.sInstance+'_'+location.pathname,
  9461. JSON.stringify( data )
  9462. );
  9463. } catch (e) {}
  9464. },
  9465. /**
  9466. * Callback which allows modification of the state to be saved. Called when the table
  9467. * has changed state a new state save is required. This method allows modification of
  9468. * the state saving object prior to actually doing the save, including addition or
  9469. * other state properties or modification. Note that for plug-in authors, you should
  9470. * use the `stateSaveParams` event to save parameters for a plug-in.
  9471. * @type function
  9472. * @param {object} settings DataTables settings object
  9473. * @param {object} data The state object to be saved
  9474. *
  9475. * @dtopt Callbacks
  9476. * @name DataTable.defaults.stateSaveParams
  9477. *
  9478. * @example
  9479. * // Remove a saved filter, so filtering is never saved
  9480. * $(document).ready( function() {
  9481. * $('#example').dataTable( {
  9482. * "stateSave": true,
  9483. * "stateSaveParams": function (settings, data) {
  9484. * data.oSearch.sSearch = "";
  9485. * }
  9486. * } );
  9487. * } );
  9488. */
  9489. "fnStateSaveParams": null,
  9490. /**
  9491. * Duration for which the saved state information is considered valid. After this period
  9492. * has elapsed the state will be returned to the default.
  9493. * Value is given in seconds.
  9494. * @type int
  9495. * @default 7200 <i>(2 hours)</i>
  9496. *
  9497. * @dtopt Options
  9498. * @name DataTable.defaults.stateDuration
  9499. *
  9500. * @example
  9501. * $(document).ready( function() {
  9502. * $('#example').dataTable( {
  9503. * "stateDuration": 60*60*24; // 1 day
  9504. * } );
  9505. * } )
  9506. */
  9507. "iStateDuration": 7200,
  9508. /**
  9509. * When enabled DataTables will not make a request to the server for the first
  9510. * page draw - rather it will use the data already on the page (no sorting etc
  9511. * will be applied to it), thus saving on an XHR at load time. `deferLoading`
  9512. * is used to indicate that deferred loading is required, but it is also used
  9513. * to tell DataTables how many records there are in the full table (allowing
  9514. * the information element and pagination to be displayed correctly). In the case
  9515. * where a filtering is applied to the table on initial load, this can be
  9516. * indicated by giving the parameter as an array, where the first element is
  9517. * the number of records available after filtering and the second element is the
  9518. * number of records without filtering (allowing the table information element
  9519. * to be shown correctly).
  9520. * @type int | array
  9521. * @default null
  9522. *
  9523. * @dtopt Options
  9524. * @name DataTable.defaults.deferLoading
  9525. *
  9526. * @example
  9527. * // 57 records available in the table, no filtering applied
  9528. * $(document).ready( function() {
  9529. * $('#example').dataTable( {
  9530. * "serverSide": true,
  9531. * "ajax": "scripts/server_processing.php",
  9532. * "deferLoading": 57
  9533. * } );
  9534. * } );
  9535. *
  9536. * @example
  9537. * // 57 records after filtering, 100 without filtering (an initial filter applied)
  9538. * $(document).ready( function() {
  9539. * $('#example').dataTable( {
  9540. * "serverSide": true,
  9541. * "ajax": "scripts/server_processing.php",
  9542. * "deferLoading": [ 57, 100 ],
  9543. * "search": {
  9544. * "search": "my_filter"
  9545. * }
  9546. * } );
  9547. * } );
  9548. */
  9549. "iDeferLoading": null,
  9550. /**
  9551. * Number of rows to display on a single page when using pagination. If
  9552. * feature enabled (`lengthChange`) then the end user will be able to override
  9553. * this to a custom setting using a pop-up menu.
  9554. * @type int
  9555. * @default 10
  9556. *
  9557. * @dtopt Options
  9558. * @name DataTable.defaults.pageLength
  9559. *
  9560. * @example
  9561. * $(document).ready( function() {
  9562. * $('#example').dataTable( {
  9563. * "pageLength": 50
  9564. * } );
  9565. * } )
  9566. */
  9567. "iDisplayLength": 10,
  9568. /**
  9569. * Define the starting point for data display when using DataTables with
  9570. * pagination. Note that this parameter is the number of records, rather than
  9571. * the page number, so if you have 10 records per page and want to start on
  9572. * the third page, it should be "20".
  9573. * @type int
  9574. * @default 0
  9575. *
  9576. * @dtopt Options
  9577. * @name DataTable.defaults.displayStart
  9578. *
  9579. * @example
  9580. * $(document).ready( function() {
  9581. * $('#example').dataTable( {
  9582. * "displayStart": 20
  9583. * } );
  9584. * } )
  9585. */
  9586. "iDisplayStart": 0,
  9587. /**
  9588. * By default DataTables allows keyboard navigation of the table (sorting, paging,
  9589. * and filtering) by adding a `tabindex` attribute to the required elements. This
  9590. * allows you to tab through the controls and press the enter key to activate them.
  9591. * The tabindex is default 0, meaning that the tab follows the flow of the document.
  9592. * You can overrule this using this parameter if you wish. Use a value of -1 to
  9593. * disable built-in keyboard navigation.
  9594. * @type int
  9595. * @default 0
  9596. *
  9597. * @dtopt Options
  9598. * @name DataTable.defaults.tabIndex
  9599. *
  9600. * @example
  9601. * $(document).ready( function() {
  9602. * $('#example').dataTable( {
  9603. * "tabIndex": 1
  9604. * } );
  9605. * } );
  9606. */
  9607. "iTabIndex": 0,
  9608. /**
  9609. * Classes that DataTables assigns to the various components and features
  9610. * that it adds to the HTML table. This allows classes to be configured
  9611. * during initialisation in addition to through the static
  9612. * {@link DataTable.ext.oStdClasses} object).
  9613. * @namespace
  9614. * @name DataTable.defaults.classes
  9615. */
  9616. "oClasses": {},
  9617. /**
  9618. * All strings that DataTables uses in the user interface that it creates
  9619. * are defined in this object, allowing you to modified them individually or
  9620. * completely replace them all as required.
  9621. * @namespace
  9622. * @name DataTable.defaults.language
  9623. */
  9624. "oLanguage": {
  9625. /**
  9626. * Strings that are used for WAI-ARIA labels and controls only (these are not
  9627. * actually visible on the page, but will be read by screenreaders, and thus
  9628. * must be internationalised as well).
  9629. * @namespace
  9630. * @name DataTable.defaults.language.aria
  9631. */
  9632. "oAria": {
  9633. /**
  9634. * ARIA label that is added to the table headers when the column may be
  9635. * sorted ascending by activing the column (click or return when focused).
  9636. * Note that the column header is prefixed to this string.
  9637. * @type string
  9638. * @default : activate to sort column ascending
  9639. *
  9640. * @dtopt Language
  9641. * @name DataTable.defaults.language.aria.sortAscending
  9642. *
  9643. * @example
  9644. * $(document).ready( function() {
  9645. * $('#example').dataTable( {
  9646. * "language": {
  9647. * "aria": {
  9648. * "sortAscending": " - click/return to sort ascending"
  9649. * }
  9650. * }
  9651. * } );
  9652. * } );
  9653. */
  9654. "sSortAscending": ": activate to sort column ascending",
  9655. /**
  9656. * ARIA label that is added to the table headers when the column may be
  9657. * sorted descending by activing the column (click or return when focused).
  9658. * Note that the column header is prefixed to this string.
  9659. * @type string
  9660. * @default : activate to sort column ascending
  9661. *
  9662. * @dtopt Language
  9663. * @name DataTable.defaults.language.aria.sortDescending
  9664. *
  9665. * @example
  9666. * $(document).ready( function() {
  9667. * $('#example').dataTable( {
  9668. * "language": {
  9669. * "aria": {
  9670. * "sortDescending": " - click/return to sort descending"
  9671. * }
  9672. * }
  9673. * } );
  9674. * } );
  9675. */
  9676. "sSortDescending": ": activate to sort column descending"
  9677. },
  9678. /**
  9679. * Pagination string used by DataTables for the built-in pagination
  9680. * control types.
  9681. * @namespace
  9682. * @name DataTable.defaults.language.paginate
  9683. */
  9684. "oPaginate": {
  9685. /**
  9686. * Text to use when using the 'full_numbers' type of pagination for the
  9687. * button to take the user to the first page.
  9688. * @type string
  9689. * @default First
  9690. *
  9691. * @dtopt Language
  9692. * @name DataTable.defaults.language.paginate.first
  9693. *
  9694. * @example
  9695. * $(document).ready( function() {
  9696. * $('#example').dataTable( {
  9697. * "language": {
  9698. * "paginate": {
  9699. * "first": "First page"
  9700. * }
  9701. * }
  9702. * } );
  9703. * } );
  9704. */
  9705. "sFirst": "First",
  9706. /**
  9707. * Text to use when using the 'full_numbers' type of pagination for the
  9708. * button to take the user to the last page.
  9709. * @type string
  9710. * @default Last
  9711. *
  9712. * @dtopt Language
  9713. * @name DataTable.defaults.language.paginate.last
  9714. *
  9715. * @example
  9716. * $(document).ready( function() {
  9717. * $('#example').dataTable( {
  9718. * "language": {
  9719. * "paginate": {
  9720. * "last": "Last page"
  9721. * }
  9722. * }
  9723. * } );
  9724. * } );
  9725. */
  9726. "sLast": "Last",
  9727. /**
  9728. * Text to use for the 'next' pagination button (to take the user to the
  9729. * next page).
  9730. * @type string
  9731. * @default Next
  9732. *
  9733. * @dtopt Language
  9734. * @name DataTable.defaults.language.paginate.next
  9735. *
  9736. * @example
  9737. * $(document).ready( function() {
  9738. * $('#example').dataTable( {
  9739. * "language": {
  9740. * "paginate": {
  9741. * "next": "Next page"
  9742. * }
  9743. * }
  9744. * } );
  9745. * } );
  9746. */
  9747. "sNext": "Next",
  9748. /**
  9749. * Text to use for the 'previous' pagination button (to take the user to
  9750. * the previous page).
  9751. * @type string
  9752. * @default Previous
  9753. *
  9754. * @dtopt Language
  9755. * @name DataTable.defaults.language.paginate.previous
  9756. *
  9757. * @example
  9758. * $(document).ready( function() {
  9759. * $('#example').dataTable( {
  9760. * "language": {
  9761. * "paginate": {
  9762. * "previous": "Previous page"
  9763. * }
  9764. * }
  9765. * } );
  9766. * } );
  9767. */
  9768. "sPrevious": "Previous"
  9769. },
  9770. /**
  9771. * This string is shown in preference to `zeroRecords` when the table is
  9772. * empty of data (regardless of filtering). Note that this is an optional
  9773. * parameter - if it is not given, the value of `zeroRecords` will be used
  9774. * instead (either the default or given value).
  9775. * @type string
  9776. * @default No data available in table
  9777. *
  9778. * @dtopt Language
  9779. * @name DataTable.defaults.language.emptyTable
  9780. *
  9781. * @example
  9782. * $(document).ready( function() {
  9783. * $('#example').dataTable( {
  9784. * "language": {
  9785. * "emptyTable": "No data available in table"
  9786. * }
  9787. * } );
  9788. * } );
  9789. */
  9790. "sEmptyTable": "No data available in table",
  9791. /**
  9792. * This string gives information to the end user about the information
  9793. * that is current on display on the page. The following tokens can be
  9794. * used in the string and will be dynamically replaced as the table
  9795. * display updates. This tokens can be placed anywhere in the string, or
  9796. * removed as needed by the language requires:
  9797. *
  9798. * * `\_START\_` - Display index of the first record on the current page
  9799. * * `\_END\_` - Display index of the last record on the current page
  9800. * * `\_TOTAL\_` - Number of records in the table after filtering
  9801. * * `\_MAX\_` - Number of records in the table without filtering
  9802. * * `\_PAGE\_` - Current page number
  9803. * * `\_PAGES\_` - Total number of pages of data in the table
  9804. *
  9805. * @type string
  9806. * @default Showing _START_ to _END_ of _TOTAL_ entries
  9807. *
  9808. * @dtopt Language
  9809. * @name DataTable.defaults.language.info
  9810. *
  9811. * @example
  9812. * $(document).ready( function() {
  9813. * $('#example').dataTable( {
  9814. * "language": {
  9815. * "info": "Showing page _PAGE_ of _PAGES_"
  9816. * }
  9817. * } );
  9818. * } );
  9819. */
  9820. "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
  9821. /**
  9822. * Display information string for when the table is empty. Typically the
  9823. * format of this string should match `info`.
  9824. * @type string
  9825. * @default Showing 0 to 0 of 0 entries
  9826. *
  9827. * @dtopt Language
  9828. * @name DataTable.defaults.language.infoEmpty
  9829. *
  9830. * @example
  9831. * $(document).ready( function() {
  9832. * $('#example').dataTable( {
  9833. * "language": {
  9834. * "infoEmpty": "No entries to show"
  9835. * }
  9836. * } );
  9837. * } );
  9838. */
  9839. "sInfoEmpty": "Showing 0 to 0 of 0 entries",
  9840. /**
  9841. * When a user filters the information in a table, this string is appended
  9842. * to the information (`info`) to give an idea of how strong the filtering
  9843. * is. The variable _MAX_ is dynamically updated.
  9844. * @type string
  9845. * @default (filtered from _MAX_ total entries)
  9846. *
  9847. * @dtopt Language
  9848. * @name DataTable.defaults.language.infoFiltered
  9849. *
  9850. * @example
  9851. * $(document).ready( function() {
  9852. * $('#example').dataTable( {
  9853. * "language": {
  9854. * "infoFiltered": " - filtering from _MAX_ records"
  9855. * }
  9856. * } );
  9857. * } );
  9858. */
  9859. "sInfoFiltered": "(filtered from _MAX_ total entries)",
  9860. /**
  9861. * If can be useful to append extra information to the info string at times,
  9862. * and this variable does exactly that. This information will be appended to
  9863. * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
  9864. * being used) at all times.
  9865. * @type string
  9866. * @default <i>Empty string</i>
  9867. *
  9868. * @dtopt Language
  9869. * @name DataTable.defaults.language.infoPostFix
  9870. *
  9871. * @example
  9872. * $(document).ready( function() {
  9873. * $('#example').dataTable( {
  9874. * "language": {
  9875. * "infoPostFix": "All records shown are derived from real information."
  9876. * }
  9877. * } );
  9878. * } );
  9879. */
  9880. "sInfoPostFix": "",
  9881. /**
  9882. * This decimal place operator is a little different from the other
  9883. * language options since DataTables doesn't output floating point
  9884. * numbers, so it won't ever use this for display of a number. Rather,
  9885. * what this parameter does is modify the sort methods of the table so
  9886. * that numbers which are in a format which has a character other than
  9887. * a period (`.`) as a decimal place will be sorted numerically.
  9888. *
  9889. * Note that numbers with different decimal places cannot be shown in
  9890. * the same table and still be sortable, the table must be consistent.
  9891. * However, multiple different tables on the page can use different
  9892. * decimal place characters.
  9893. * @type string
  9894. * @default
  9895. *
  9896. * @dtopt Language
  9897. * @name DataTable.defaults.language.decimal
  9898. *
  9899. * @example
  9900. * $(document).ready( function() {
  9901. * $('#example').dataTable( {
  9902. * "language": {
  9903. * "decimal": ","
  9904. * "thousands": "."
  9905. * }
  9906. * } );
  9907. * } );
  9908. */
  9909. "sDecimal": "",
  9910. /**
  9911. * DataTables has a build in number formatter (`formatNumber`) which is
  9912. * used to format large numbers that are used in the table information.
  9913. * By default a comma is used, but this can be trivially changed to any
  9914. * character you wish with this parameter.
  9915. * @type string
  9916. * @default ,
  9917. *
  9918. * @dtopt Language
  9919. * @name DataTable.defaults.language.thousands
  9920. *
  9921. * @example
  9922. * $(document).ready( function() {
  9923. * $('#example').dataTable( {
  9924. * "language": {
  9925. * "thousands": "'"
  9926. * }
  9927. * } );
  9928. * } );
  9929. */
  9930. "sThousands": ",",
  9931. /**
  9932. * Detail the action that will be taken when the drop down menu for the
  9933. * pagination length option is changed. The '_MENU_' variable is replaced
  9934. * with a default select list of 10, 25, 50 and 100, and can be replaced
  9935. * with a custom select box if required.
  9936. * @type string
  9937. * @default Show _MENU_ entries
  9938. *
  9939. * @dtopt Language
  9940. * @name DataTable.defaults.language.lengthMenu
  9941. *
  9942. * @example
  9943. * // Language change only
  9944. * $(document).ready( function() {
  9945. * $('#example').dataTable( {
  9946. * "language": {
  9947. * "lengthMenu": "Display _MENU_ records"
  9948. * }
  9949. * } );
  9950. * } );
  9951. *
  9952. * @example
  9953. * // Language and options change
  9954. * $(document).ready( function() {
  9955. * $('#example').dataTable( {
  9956. * "language": {
  9957. * "lengthMenu": 'Display <select>'+
  9958. * '<option value="10">10</option>'+
  9959. * '<option value="20">20</option>'+
  9960. * '<option value="30">30</option>'+
  9961. * '<option value="40">40</option>'+
  9962. * '<option value="50">50</option>'+
  9963. * '<option value="-1">All</option>'+
  9964. * '</select> records'
  9965. * }
  9966. * } );
  9967. * } );
  9968. */
  9969. "sLengthMenu": "Show _MENU_ entries",
  9970. /**
  9971. * When using Ajax sourced data and during the first draw when DataTables is
  9972. * gathering the data, this message is shown in an empty row in the table to
  9973. * indicate to the end user the the data is being loaded. Note that this
  9974. * parameter is not used when loading data by server-side processing, just
  9975. * Ajax sourced data with client-side processing.
  9976. * @type string
  9977. * @default Loading...
  9978. *
  9979. * @dtopt Language
  9980. * @name DataTable.defaults.language.loadingRecords
  9981. *
  9982. * @example
  9983. * $(document).ready( function() {
  9984. * $('#example').dataTable( {
  9985. * "language": {
  9986. * "loadingRecords": "Please wait - loading..."
  9987. * }
  9988. * } );
  9989. * } );
  9990. */
  9991. "sLoadingRecords": "Loading...",
  9992. /**
  9993. * Text which is displayed when the table is processing a user action
  9994. * (usually a sort command or similar).
  9995. * @type string
  9996. * @default Processing...
  9997. *
  9998. * @dtopt Language
  9999. * @name DataTable.defaults.language.processing
  10000. *
  10001. * @example
  10002. * $(document).ready( function() {
  10003. * $('#example').dataTable( {
  10004. * "language": {
  10005. * "processing": "DataTables is currently busy"
  10006. * }
  10007. * } );
  10008. * } );
  10009. */
  10010. "sProcessing": "Processing...",
  10011. /**
  10012. * Details the actions that will be taken when the user types into the
  10013. * filtering input text box. The variable "_INPUT_", if used in the string,
  10014. * is replaced with the HTML text box for the filtering input allowing
  10015. * control over where it appears in the string. If "_INPUT_" is not given
  10016. * then the input box is appended to the string automatically.
  10017. * @type string
  10018. * @default Search:
  10019. *
  10020. * @dtopt Language
  10021. * @name DataTable.defaults.language.search
  10022. *
  10023. * @example
  10024. * // Input text box will be appended at the end automatically
  10025. * $(document).ready( function() {
  10026. * $('#example').dataTable( {
  10027. * "language": {
  10028. * "search": "Filter records:"
  10029. * }
  10030. * } );
  10031. * } );
  10032. *
  10033. * @example
  10034. * // Specify where the filter should appear
  10035. * $(document).ready( function() {
  10036. * $('#example').dataTable( {
  10037. * "language": {
  10038. * "search": "Apply filter _INPUT_ to table"
  10039. * }
  10040. * } );
  10041. * } );
  10042. */
  10043. "sSearch": "Search:",
  10044. /**
  10045. * Assign a `placeholder` attribute to the search `input` element
  10046. * @type string
  10047. * @default
  10048. *
  10049. * @dtopt Language
  10050. * @name DataTable.defaults.language.searchPlaceholder
  10051. */
  10052. "sSearchPlaceholder": "",
  10053. /**
  10054. * All of the language information can be stored in a file on the
  10055. * server-side, which DataTables will look up if this parameter is passed.
  10056. * It must store the URL of the language file, which is in a JSON format,
  10057. * and the object has the same properties as the oLanguage object in the
  10058. * initialiser object (i.e. the above parameters). Please refer to one of
  10059. * the example language files to see how this works in action.
  10060. * @type string
  10061. * @default <i>Empty string - i.e. disabled</i>
  10062. *
  10063. * @dtopt Language
  10064. * @name DataTable.defaults.language.url
  10065. *
  10066. * @example
  10067. * $(document).ready( function() {
  10068. * $('#example').dataTable( {
  10069. * "language": {
  10070. * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
  10071. * }
  10072. * } );
  10073. * } );
  10074. */
  10075. "sUrl": "",
  10076. /**
  10077. * Text shown inside the table records when the is no information to be
  10078. * displayed after filtering. `emptyTable` is shown when there is simply no
  10079. * information in the table at all (regardless of filtering).
  10080. * @type string
  10081. * @default No matching records found
  10082. *
  10083. * @dtopt Language
  10084. * @name DataTable.defaults.language.zeroRecords
  10085. *
  10086. * @example
  10087. * $(document).ready( function() {
  10088. * $('#example').dataTable( {
  10089. * "language": {
  10090. * "zeroRecords": "No records to display"
  10091. * }
  10092. * } );
  10093. * } );
  10094. */
  10095. "sZeroRecords": "No matching records found"
  10096. },
  10097. /**
  10098. * This parameter allows you to have define the global filtering state at
  10099. * initialisation time. As an object the `search` parameter must be
  10100. * defined, but all other parameters are optional. When `regex` is true,
  10101. * the search string will be treated as a regular expression, when false
  10102. * (default) it will be treated as a straight string. When `smart`
  10103. * DataTables will use it's smart filtering methods (to word match at
  10104. * any point in the data), when false this will not be done.
  10105. * @namespace
  10106. * @extends DataTable.models.oSearch
  10107. *
  10108. * @dtopt Options
  10109. * @name DataTable.defaults.search
  10110. *
  10111. * @example
  10112. * $(document).ready( function() {
  10113. * $('#example').dataTable( {
  10114. * "search": {"search": "Initial search"}
  10115. * } );
  10116. * } )
  10117. */
  10118. "oSearch": $.extend( {}, DataTable.models.oSearch ),
  10119. /**
  10120. * __Deprecated__ The functionality provided by this parameter has now been
  10121. * superseded by that provided through `ajax`, which should be used instead.
  10122. *
  10123. * By default DataTables will look for the property `data` (or `aaData` for
  10124. * compatibility with DataTables 1.9-) when obtaining data from an Ajax
  10125. * source or for server-side processing - this parameter allows that
  10126. * property to be changed. You can use Javascript dotted object notation to
  10127. * get a data source for multiple levels of nesting.
  10128. * @type string
  10129. * @default data
  10130. *
  10131. * @dtopt Options
  10132. * @dtopt Server-side
  10133. * @name DataTable.defaults.ajaxDataProp
  10134. *
  10135. * @deprecated 1.10. Please use `ajax` for this functionality now.
  10136. */
  10137. "sAjaxDataProp": "data",
  10138. /**
  10139. * __Deprecated__ The functionality provided by this parameter has now been
  10140. * superseded by that provided through `ajax`, which should be used instead.
  10141. *
  10142. * You can instruct DataTables to load data from an external
  10143. * source using this parameter (use aData if you want to pass data in you
  10144. * already have). Simply provide a url a JSON object can be obtained from.
  10145. * @type string
  10146. * @default null
  10147. *
  10148. * @dtopt Options
  10149. * @dtopt Server-side
  10150. * @name DataTable.defaults.ajaxSource
  10151. *
  10152. * @deprecated 1.10. Please use `ajax` for this functionality now.
  10153. */
  10154. "sAjaxSource": null,
  10155. /**
  10156. * This initialisation variable allows you to specify exactly where in the
  10157. * DOM you want DataTables to inject the various controls it adds to the page
  10158. * (for example you might want the pagination controls at the top of the
  10159. * table). DIV elements (with or without a custom class) can also be added to
  10160. * aid styling. The follow syntax is used:
  10161. * <ul>
  10162. * <li>The following options are allowed:
  10163. * <ul>
  10164. * <li>'l' - Length changing</li>
  10165. * <li>'f' - Filtering input</li>
  10166. * <li>'t' - The table!</li>
  10167. * <li>'i' - Information</li>
  10168. * <li>'p' - Pagination</li>
  10169. * <li>'r' - pRocessing</li>
  10170. * </ul>
  10171. * </li>
  10172. * <li>The following constants are allowed:
  10173. * <ul>
  10174. * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
  10175. * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
  10176. * </ul>
  10177. * </li>
  10178. * <li>The following syntax is expected:
  10179. * <ul>
  10180. * <li>'&lt;' and '&gt;' - div elements</li>
  10181. * <li>'&lt;"class" and '&gt;' - div with a class</li>
  10182. * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
  10183. * </ul>
  10184. * </li>
  10185. * <li>Examples:
  10186. * <ul>
  10187. * <li>'&lt;"wrapper"flipt&gt;'</li>
  10188. * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
  10189. * </ul>
  10190. * </li>
  10191. * </ul>
  10192. * @type string
  10193. * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
  10194. * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
  10195. *
  10196. * @dtopt Options
  10197. * @name DataTable.defaults.dom
  10198. *
  10199. * @example
  10200. * $(document).ready( function() {
  10201. * $('#example').dataTable( {
  10202. * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
  10203. * } );
  10204. * } );
  10205. */
  10206. "sDom": "lfrtip",
  10207. /**
  10208. * Search delay option. This will throttle full table searches that use the
  10209. * DataTables provided search input element (it does not effect calls to
  10210. * `dt-api search()`, providing a delay before the search is made.
  10211. * @type integer
  10212. * @default 0
  10213. *
  10214. * @dtopt Options
  10215. * @name DataTable.defaults.searchDelay
  10216. *
  10217. * @example
  10218. * $(document).ready( function() {
  10219. * $('#example').dataTable( {
  10220. * "searchDelay": 200
  10221. * } );
  10222. * } )
  10223. */
  10224. "searchDelay": null,
  10225. /**
  10226. * DataTables features six different built-in options for the buttons to
  10227. * display for pagination control:
  10228. *
  10229. * * `numbers` - Page number buttons only
  10230. * * `simple` - 'Previous' and 'Next' buttons only
  10231. * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
  10232. * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
  10233. * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
  10234. * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
  10235. *
  10236. * Further methods can be added using {@link DataTable.ext.oPagination}.
  10237. * @type string
  10238. * @default simple_numbers
  10239. *
  10240. * @dtopt Options
  10241. * @name DataTable.defaults.pagingType
  10242. *
  10243. * @example
  10244. * $(document).ready( function() {
  10245. * $('#example').dataTable( {
  10246. * "pagingType": "full_numbers"
  10247. * } );
  10248. * } )
  10249. */
  10250. "sPaginationType": "simple_numbers",
  10251. /**
  10252. * Enable horizontal scrolling. When a table is too wide to fit into a
  10253. * certain layout, or you have a large number of columns in the table, you
  10254. * can enable x-scrolling to show the table in a viewport, which can be
  10255. * scrolled. This property can be `true` which will allow the table to
  10256. * scroll horizontally when needed, or any CSS unit, or a number (in which
  10257. * case it will be treated as a pixel measurement). Setting as simply `true`
  10258. * is recommended.
  10259. * @type boolean|string
  10260. * @default <i>blank string - i.e. disabled</i>
  10261. *
  10262. * @dtopt Features
  10263. * @name DataTable.defaults.scrollX
  10264. *
  10265. * @example
  10266. * $(document).ready( function() {
  10267. * $('#example').dataTable( {
  10268. * "scrollX": true,
  10269. * "scrollCollapse": true
  10270. * } );
  10271. * } );
  10272. */
  10273. "sScrollX": "",
  10274. /**
  10275. * This property can be used to force a DataTable to use more width than it
  10276. * might otherwise do when x-scrolling is enabled. For example if you have a
  10277. * table which requires to be well spaced, this parameter is useful for
  10278. * "over-sizing" the table, and thus forcing scrolling. This property can by
  10279. * any CSS unit, or a number (in which case it will be treated as a pixel
  10280. * measurement).
  10281. * @type string
  10282. * @default <i>blank string - i.e. disabled</i>
  10283. *
  10284. * @dtopt Options
  10285. * @name DataTable.defaults.scrollXInner
  10286. *
  10287. * @example
  10288. * $(document).ready( function() {
  10289. * $('#example').dataTable( {
  10290. * "scrollX": "100%",
  10291. * "scrollXInner": "110%"
  10292. * } );
  10293. * } );
  10294. */
  10295. "sScrollXInner": "",
  10296. /**
  10297. * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
  10298. * to the given height, and enable scrolling for any data which overflows the
  10299. * current viewport. This can be used as an alternative to paging to display
  10300. * a lot of data in a small area (although paging and scrolling can both be
  10301. * enabled at the same time). This property can be any CSS unit, or a number
  10302. * (in which case it will be treated as a pixel measurement).
  10303. * @type string
  10304. * @default <i>blank string - i.e. disabled</i>
  10305. *
  10306. * @dtopt Features
  10307. * @name DataTable.defaults.scrollY
  10308. *
  10309. * @example
  10310. * $(document).ready( function() {
  10311. * $('#example').dataTable( {
  10312. * "scrollY": "200px",
  10313. * "paginate": false
  10314. * } );
  10315. * } );
  10316. */
  10317. "sScrollY": "",
  10318. /**
  10319. * __Deprecated__ The functionality provided by this parameter has now been
  10320. * superseded by that provided through `ajax`, which should be used instead.
  10321. *
  10322. * Set the HTTP method that is used to make the Ajax call for server-side
  10323. * processing or Ajax sourced data.
  10324. * @type string
  10325. * @default GET
  10326. *
  10327. * @dtopt Options
  10328. * @dtopt Server-side
  10329. * @name DataTable.defaults.serverMethod
  10330. *
  10331. * @deprecated 1.10. Please use `ajax` for this functionality now.
  10332. */
  10333. "sServerMethod": "GET",
  10334. /**
  10335. * DataTables makes use of renderers when displaying HTML elements for
  10336. * a table. These renderers can be added or modified by plug-ins to
  10337. * generate suitable mark-up for a site. For example the Bootstrap
  10338. * integration plug-in for DataTables uses a paging button renderer to
  10339. * display pagination buttons in the mark-up required by Bootstrap.
  10340. *
  10341. * For further information about the renderers available see
  10342. * DataTable.ext.renderer
  10343. * @type string|object
  10344. * @default null
  10345. *
  10346. * @name DataTable.defaults.renderer
  10347. *
  10348. */
  10349. "renderer": null,
  10350. /**
  10351. * Set the data property name that DataTables should use to get a row's id
  10352. * to set as the `id` property in the node.
  10353. * @type string
  10354. * @default DT_RowId
  10355. *
  10356. * @name DataTable.defaults.rowId
  10357. */
  10358. "rowId": "DT_RowId"
  10359. };
  10360. _fnHungarianMap( DataTable.defaults );
  10361. /*
  10362. * Developer note - See note in model.defaults.js about the use of Hungarian
  10363. * notation and camel case.
  10364. */
  10365. /**
  10366. * Column options that can be given to DataTables at initialisation time.
  10367. * @namespace
  10368. */
  10369. DataTable.defaults.column = {
  10370. /**
  10371. * Define which column(s) an order will occur on for this column. This
  10372. * allows a column's ordering to take multiple columns into account when
  10373. * doing a sort or use the data from a different column. For example first
  10374. * name / last name columns make sense to do a multi-column sort over the
  10375. * two columns.
  10376. * @type array|int
  10377. * @default null <i>Takes the value of the column index automatically</i>
  10378. *
  10379. * @name DataTable.defaults.column.orderData
  10380. * @dtopt Columns
  10381. *
  10382. * @example
  10383. * // Using `columnDefs`
  10384. * $(document).ready( function() {
  10385. * $('#example').dataTable( {
  10386. * "columnDefs": [
  10387. * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
  10388. * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
  10389. * { "orderData": 2, "targets": [ 2 ] }
  10390. * ]
  10391. * } );
  10392. * } );
  10393. *
  10394. * @example
  10395. * // Using `columns`
  10396. * $(document).ready( function() {
  10397. * $('#example').dataTable( {
  10398. * "columns": [
  10399. * { "orderData": [ 0, 1 ] },
  10400. * { "orderData": [ 1, 0 ] },
  10401. * { "orderData": 2 },
  10402. * null,
  10403. * null
  10404. * ]
  10405. * } );
  10406. * } );
  10407. */
  10408. "aDataSort": null,
  10409. "iDataSort": -1,
  10410. /**
  10411. * You can control the default ordering direction, and even alter the
  10412. * behaviour of the sort handler (i.e. only allow ascending ordering etc)
  10413. * using this parameter.
  10414. * @type array
  10415. * @default [ 'asc', 'desc' ]
  10416. *
  10417. * @name DataTable.defaults.column.orderSequence
  10418. * @dtopt Columns
  10419. *
  10420. * @example
  10421. * // Using `columnDefs`
  10422. * $(document).ready( function() {
  10423. * $('#example').dataTable( {
  10424. * "columnDefs": [
  10425. * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
  10426. * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
  10427. * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
  10428. * ]
  10429. * } );
  10430. * } );
  10431. *
  10432. * @example
  10433. * // Using `columns`
  10434. * $(document).ready( function() {
  10435. * $('#example').dataTable( {
  10436. * "columns": [
  10437. * null,
  10438. * { "orderSequence": [ "asc" ] },
  10439. * { "orderSequence": [ "desc", "asc", "asc" ] },
  10440. * { "orderSequence": [ "desc" ] },
  10441. * null
  10442. * ]
  10443. * } );
  10444. * } );
  10445. */
  10446. "asSorting": [ 'asc', 'desc' ],
  10447. /**
  10448. * Enable or disable filtering on the data in this column.
  10449. * @type boolean
  10450. * @default true
  10451. *
  10452. * @name DataTable.defaults.column.searchable
  10453. * @dtopt Columns
  10454. *
  10455. * @example
  10456. * // Using `columnDefs`
  10457. * $(document).ready( function() {
  10458. * $('#example').dataTable( {
  10459. * "columnDefs": [
  10460. * { "searchable": false, "targets": [ 0 ] }
  10461. * ] } );
  10462. * } );
  10463. *
  10464. * @example
  10465. * // Using `columns`
  10466. * $(document).ready( function() {
  10467. * $('#example').dataTable( {
  10468. * "columns": [
  10469. * { "searchable": false },
  10470. * null,
  10471. * null,
  10472. * null,
  10473. * null
  10474. * ] } );
  10475. * } );
  10476. */
  10477. "bSearchable": true,
  10478. /**
  10479. * Enable or disable ordering on this column.
  10480. * @type boolean
  10481. * @default true
  10482. *
  10483. * @name DataTable.defaults.column.orderable
  10484. * @dtopt Columns
  10485. *
  10486. * @example
  10487. * // Using `columnDefs`
  10488. * $(document).ready( function() {
  10489. * $('#example').dataTable( {
  10490. * "columnDefs": [
  10491. * { "orderable": false, "targets": [ 0 ] }
  10492. * ] } );
  10493. * } );
  10494. *
  10495. * @example
  10496. * // Using `columns`
  10497. * $(document).ready( function() {
  10498. * $('#example').dataTable( {
  10499. * "columns": [
  10500. * { "orderable": false },
  10501. * null,
  10502. * null,
  10503. * null,
  10504. * null
  10505. * ] } );
  10506. * } );
  10507. */
  10508. "bSortable": true,
  10509. /**
  10510. * Enable or disable the display of this column.
  10511. * @type boolean
  10512. * @default true
  10513. *
  10514. * @name DataTable.defaults.column.visible
  10515. * @dtopt Columns
  10516. *
  10517. * @example
  10518. * // Using `columnDefs`
  10519. * $(document).ready( function() {
  10520. * $('#example').dataTable( {
  10521. * "columnDefs": [
  10522. * { "visible": false, "targets": [ 0 ] }
  10523. * ] } );
  10524. * } );
  10525. *
  10526. * @example
  10527. * // Using `columns`
  10528. * $(document).ready( function() {
  10529. * $('#example').dataTable( {
  10530. * "columns": [
  10531. * { "visible": false },
  10532. * null,
  10533. * null,
  10534. * null,
  10535. * null
  10536. * ] } );
  10537. * } );
  10538. */
  10539. "bVisible": true,
  10540. /**
  10541. * Developer definable function that is called whenever a cell is created (Ajax source,
  10542. * etc) or processed for input (DOM source). This can be used as a compliment to mRender
  10543. * allowing you to modify the DOM element (add background colour for example) when the
  10544. * element is available.
  10545. * @type function
  10546. * @param {element} td The TD node that has been created
  10547. * @param {*} cellData The Data for the cell
  10548. * @param {array|object} rowData The data for the whole row
  10549. * @param {int} row The row index for the aoData data store
  10550. * @param {int} col The column index for aoColumns
  10551. *
  10552. * @name DataTable.defaults.column.createdCell
  10553. * @dtopt Columns
  10554. *
  10555. * @example
  10556. * $(document).ready( function() {
  10557. * $('#example').dataTable( {
  10558. * "columnDefs": [ {
  10559. * "targets": [3],
  10560. * "createdCell": function (td, cellData, rowData, row, col) {
  10561. * if ( cellData == "1.7" ) {
  10562. * $(td).css('color', 'blue')
  10563. * }
  10564. * }
  10565. * } ]
  10566. * });
  10567. * } );
  10568. */
  10569. "fnCreatedCell": null,
  10570. /**
  10571. * This parameter has been replaced by `data` in DataTables to ensure naming
  10572. * consistency. `dataProp` can still be used, as there is backwards
  10573. * compatibility in DataTables for this option, but it is strongly
  10574. * recommended that you use `data` in preference to `dataProp`.
  10575. * @name DataTable.defaults.column.dataProp
  10576. */
  10577. /**
  10578. * This property can be used to read data from any data source property,
  10579. * including deeply nested objects / properties. `data` can be given in a
  10580. * number of different ways which effect its behaviour:
  10581. *
  10582. * * `integer` - treated as an array index for the data source. This is the
  10583. * default that DataTables uses (incrementally increased for each column).
  10584. * * `string` - read an object property from the data source. There are
  10585. * three 'special' options that can be used in the string to alter how
  10586. * DataTables reads the data from the source object:
  10587. * * `.` - Dotted Javascript notation. Just as you use a `.` in
  10588. * Javascript to read from nested objects, so to can the options
  10589. * specified in `data`. For example: `browser.version` or
  10590. * `browser.name`. If your object parameter name contains a period, use
  10591. * `\\` to escape it - i.e. `first\\.name`.
  10592. * * `[]` - Array notation. DataTables can automatically combine data
  10593. * from and array source, joining the data with the characters provided
  10594. * between the two brackets. For example: `name[, ]` would provide a
  10595. * comma-space separated list from the source array. If no characters
  10596. * are provided between the brackets, the original array source is
  10597. * returned.
  10598. * * `()` - Function notation. Adding `()` to the end of a parameter will
  10599. * execute a function of the name given. For example: `browser()` for a
  10600. * simple function on the data source, `browser.version()` for a
  10601. * function in a nested property or even `browser().version` to get an
  10602. * object property if the function called returns an object. Note that
  10603. * function notation is recommended for use in `render` rather than
  10604. * `data` as it is much simpler to use as a renderer.
  10605. * * `null` - use the original data source for the row rather than plucking
  10606. * data directly from it. This action has effects on two other
  10607. * initialisation options:
  10608. * * `defaultContent` - When null is given as the `data` option and
  10609. * `defaultContent` is specified for the column, the value defined by
  10610. * `defaultContent` will be used for the cell.
  10611. * * `render` - When null is used for the `data` option and the `render`
  10612. * option is specified for the column, the whole data source for the
  10613. * row is used for the renderer.
  10614. * * `function` - the function given will be executed whenever DataTables
  10615. * needs to set or get the data for a cell in the column. The function
  10616. * takes three parameters:
  10617. * * Parameters:
  10618. * * `{array|object}` The data source for the row
  10619. * * `{string}` The type call data requested - this will be 'set' when
  10620. * setting data or 'filter', 'display', 'type', 'sort' or undefined
  10621. * when gathering data. Note that when `undefined` is given for the
  10622. * type DataTables expects to get the raw data for the object back<
  10623. * * `{*}` Data to set when the second parameter is 'set'.
  10624. * * Return:
  10625. * * The return value from the function is not required when 'set' is
  10626. * the type of call, but otherwise the return is what will be used
  10627. * for the data requested.
  10628. *
  10629. * Note that `data` is a getter and setter option. If you just require
  10630. * formatting of data for output, you will likely want to use `render` which
  10631. * is simply a getter and thus simpler to use.
  10632. *
  10633. * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
  10634. * name change reflects the flexibility of this property and is consistent
  10635. * with the naming of mRender. If 'mDataProp' is given, then it will still
  10636. * be used by DataTables, as it automatically maps the old name to the new
  10637. * if required.
  10638. *
  10639. * @type string|int|function|null
  10640. * @default null <i>Use automatically calculated column index</i>
  10641. *
  10642. * @name DataTable.defaults.column.data
  10643. * @dtopt Columns
  10644. *
  10645. * @example
  10646. * // Read table data from objects
  10647. * // JSON structure for each row:
  10648. * // {
  10649. * // "engine": {value},
  10650. * // "browser": {value},
  10651. * // "platform": {value},
  10652. * // "version": {value},
  10653. * // "grade": {value}
  10654. * // }
  10655. * $(document).ready( function() {
  10656. * $('#example').dataTable( {
  10657. * "ajaxSource": "sources/objects.txt",
  10658. * "columns": [
  10659. * { "data": "engine" },
  10660. * { "data": "browser" },
  10661. * { "data": "platform" },
  10662. * { "data": "version" },
  10663. * { "data": "grade" }
  10664. * ]
  10665. * } );
  10666. * } );
  10667. *
  10668. * @example
  10669. * // Read information from deeply nested objects
  10670. * // JSON structure for each row:
  10671. * // {
  10672. * // "engine": {value},
  10673. * // "browser": {value},
  10674. * // "platform": {
  10675. * // "inner": {value}
  10676. * // },
  10677. * // "details": [
  10678. * // {value}, {value}
  10679. * // ]
  10680. * // }
  10681. * $(document).ready( function() {
  10682. * $('#example').dataTable( {
  10683. * "ajaxSource": "sources/deep.txt",
  10684. * "columns": [
  10685. * { "data": "engine" },
  10686. * { "data": "browser" },
  10687. * { "data": "platform.inner" },
  10688. * { "data": "platform.details.0" },
  10689. * { "data": "platform.details.1" }
  10690. * ]
  10691. * } );
  10692. * } );
  10693. *
  10694. * @example
  10695. * // Using `data` as a function to provide different information for
  10696. * // sorting, filtering and display. In this case, currency (price)
  10697. * $(document).ready( function() {
  10698. * $('#example').dataTable( {
  10699. * "columnDefs": [ {
  10700. * "targets": [ 0 ],
  10701. * "data": function ( source, type, val ) {
  10702. * if (type === 'set') {
  10703. * source.price = val;
  10704. * // Store the computed dislay and filter values for efficiency
  10705. * source.price_display = val=="" ? "" : "$"+numberFormat(val);
  10706. * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
  10707. * return;
  10708. * }
  10709. * else if (type === 'display') {
  10710. * return source.price_display;
  10711. * }
  10712. * else if (type === 'filter') {
  10713. * return source.price_filter;
  10714. * }
  10715. * // 'sort', 'type' and undefined all just use the integer
  10716. * return source.price;
  10717. * }
  10718. * } ]
  10719. * } );
  10720. * } );
  10721. *
  10722. * @example
  10723. * // Using default content
  10724. * $(document).ready( function() {
  10725. * $('#example').dataTable( {
  10726. * "columnDefs": [ {
  10727. * "targets": [ 0 ],
  10728. * "data": null,
  10729. * "defaultContent": "Click to edit"
  10730. * } ]
  10731. * } );
  10732. * } );
  10733. *
  10734. * @example
  10735. * // Using array notation - outputting a list from an array
  10736. * $(document).ready( function() {
  10737. * $('#example').dataTable( {
  10738. * "columnDefs": [ {
  10739. * "targets": [ 0 ],
  10740. * "data": "name[, ]"
  10741. * } ]
  10742. * } );
  10743. * } );
  10744. *
  10745. */
  10746. "mData": null,
  10747. /**
  10748. * This property is the rendering partner to `data` and it is suggested that
  10749. * when you want to manipulate data for display (including filtering,
  10750. * sorting etc) without altering the underlying data for the table, use this
  10751. * property. `render` can be considered to be the the read only companion to
  10752. * `data` which is read / write (then as such more complex). Like `data`
  10753. * this option can be given in a number of different ways to effect its
  10754. * behaviour:
  10755. *
  10756. * * `integer` - treated as an array index for the data source. This is the
  10757. * default that DataTables uses (incrementally increased for each column).
  10758. * * `string` - read an object property from the data source. There are
  10759. * three 'special' options that can be used in the string to alter how
  10760. * DataTables reads the data from the source object:
  10761. * * `.` - Dotted Javascript notation. Just as you use a `.` in
  10762. * Javascript to read from nested objects, so to can the options
  10763. * specified in `data`. For example: `browser.version` or
  10764. * `browser.name`. If your object parameter name contains a period, use
  10765. * `\\` to escape it - i.e. `first\\.name`.
  10766. * * `[]` - Array notation. DataTables can automatically combine data
  10767. * from and array source, joining the data with the characters provided
  10768. * between the two brackets. For example: `name[, ]` would provide a
  10769. * comma-space separated list from the source array. If no characters
  10770. * are provided between the brackets, the original array source is
  10771. * returned.
  10772. * * `()` - Function notation. Adding `()` to the end of a parameter will
  10773. * execute a function of the name given. For example: `browser()` for a
  10774. * simple function on the data source, `browser.version()` for a
  10775. * function in a nested property or even `browser().version` to get an
  10776. * object property if the function called returns an object.
  10777. * * `object` - use different data for the different data types requested by
  10778. * DataTables ('filter', 'display', 'type' or 'sort'). The property names
  10779. * of the object is the data type the property refers to and the value can
  10780. * defined using an integer, string or function using the same rules as
  10781. * `render` normally does. Note that an `_` option _must_ be specified.
  10782. * This is the default value to use if you haven't specified a value for
  10783. * the data type requested by DataTables.
  10784. * * `function` - the function given will be executed whenever DataTables
  10785. * needs to set or get the data for a cell in the column. The function
  10786. * takes three parameters:
  10787. * * Parameters:
  10788. * * {array|object} The data source for the row (based on `data`)
  10789. * * {string} The type call data requested - this will be 'filter',
  10790. * 'display', 'type' or 'sort'.
  10791. * * {array|object} The full data source for the row (not based on
  10792. * `data`)
  10793. * * Return:
  10794. * * The return value from the function is what will be used for the
  10795. * data requested.
  10796. *
  10797. * @type string|int|function|object|null
  10798. * @default null Use the data source value.
  10799. *
  10800. * @name DataTable.defaults.column.render
  10801. * @dtopt Columns
  10802. *
  10803. * @example
  10804. * // Create a comma separated list from an array of objects
  10805. * $(document).ready( function() {
  10806. * $('#example').dataTable( {
  10807. * "ajaxSource": "sources/deep.txt",
  10808. * "columns": [
  10809. * { "data": "engine" },
  10810. * { "data": "browser" },
  10811. * {
  10812. * "data": "platform",
  10813. * "render": "[, ].name"
  10814. * }
  10815. * ]
  10816. * } );
  10817. * } );
  10818. *
  10819. * @example
  10820. * // Execute a function to obtain data
  10821. * $(document).ready( function() {
  10822. * $('#example').dataTable( {
  10823. * "columnDefs": [ {
  10824. * "targets": [ 0 ],
  10825. * "data": null, // Use the full data source object for the renderer's source
  10826. * "render": "browserName()"
  10827. * } ]
  10828. * } );
  10829. * } );
  10830. *
  10831. * @example
  10832. * // As an object, extracting different data for the different types
  10833. * // This would be used with a data source such as:
  10834. * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
  10835. * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
  10836. * // (which has both forms) is used for filtering for if a user inputs either format, while
  10837. * // the formatted phone number is the one that is shown in the table.
  10838. * $(document).ready( function() {
  10839. * $('#example').dataTable( {
  10840. * "columnDefs": [ {
  10841. * "targets": [ 0 ],
  10842. * "data": null, // Use the full data source object for the renderer's source
  10843. * "render": {
  10844. * "_": "phone",
  10845. * "filter": "phone_filter",
  10846. * "display": "phone_display"
  10847. * }
  10848. * } ]
  10849. * } );
  10850. * } );
  10851. *
  10852. * @example
  10853. * // Use as a function to create a link from the data source
  10854. * $(document).ready( function() {
  10855. * $('#example').dataTable( {
  10856. * "columnDefs": [ {
  10857. * "targets": [ 0 ],
  10858. * "data": "download_link",
  10859. * "render": function ( data, type, full ) {
  10860. * return '<a href="'+data+'">Download</a>';
  10861. * }
  10862. * } ]
  10863. * } );
  10864. * } );
  10865. */
  10866. "mRender": null,
  10867. /**
  10868. * Change the cell type created for the column - either TD cells or TH cells. This
  10869. * can be useful as TH cells have semantic meaning in the table body, allowing them
  10870. * to act as a header for a row (you may wish to add scope='row' to the TH elements).
  10871. * @type string
  10872. * @default td
  10873. *
  10874. * @name DataTable.defaults.column.cellType
  10875. * @dtopt Columns
  10876. *
  10877. * @example
  10878. * // Make the first column use TH cells
  10879. * $(document).ready( function() {
  10880. * $('#example').dataTable( {
  10881. * "columnDefs": [ {
  10882. * "targets": [ 0 ],
  10883. * "cellType": "th"
  10884. * } ]
  10885. * } );
  10886. * } );
  10887. */
  10888. "sCellType": "td",
  10889. /**
  10890. * Class to give to each cell in this column.
  10891. * @type string
  10892. * @default <i>Empty string</i>
  10893. *
  10894. * @name DataTable.defaults.column.class
  10895. * @dtopt Columns
  10896. *
  10897. * @example
  10898. * // Using `columnDefs`
  10899. * $(document).ready( function() {
  10900. * $('#example').dataTable( {
  10901. * "columnDefs": [
  10902. * { "class": "my_class", "targets": [ 0 ] }
  10903. * ]
  10904. * } );
  10905. * } );
  10906. *
  10907. * @example
  10908. * // Using `columns`
  10909. * $(document).ready( function() {
  10910. * $('#example').dataTable( {
  10911. * "columns": [
  10912. * { "class": "my_class" },
  10913. * null,
  10914. * null,
  10915. * null,
  10916. * null
  10917. * ]
  10918. * } );
  10919. * } );
  10920. */
  10921. "sClass": "",
  10922. /**
  10923. * When DataTables calculates the column widths to assign to each column,
  10924. * it finds the longest string in each column and then constructs a
  10925. * temporary table and reads the widths from that. The problem with this
  10926. * is that "mmm" is much wider then "iiii", but the latter is a longer
  10927. * string - thus the calculation can go wrong (doing it properly and putting
  10928. * it into an DOM object and measuring that is horribly(!) slow). Thus as
  10929. * a "work around" we provide this option. It will append its value to the
  10930. * text that is found to be the longest string for the column - i.e. padding.
  10931. * Generally you shouldn't need this!
  10932. * @type string
  10933. * @default <i>Empty string<i>
  10934. *
  10935. * @name DataTable.defaults.column.contentPadding
  10936. * @dtopt Columns
  10937. *
  10938. * @example
  10939. * // Using `columns`
  10940. * $(document).ready( function() {
  10941. * $('#example').dataTable( {
  10942. * "columns": [
  10943. * null,
  10944. * null,
  10945. * null,
  10946. * {
  10947. * "contentPadding": "mmm"
  10948. * }
  10949. * ]
  10950. * } );
  10951. * } );
  10952. */
  10953. "sContentPadding": "",
  10954. /**
  10955. * Allows a default value to be given for a column's data, and will be used
  10956. * whenever a null data source is encountered (this can be because `data`
  10957. * is set to null, or because the data source itself is null).
  10958. * @type string
  10959. * @default null
  10960. *
  10961. * @name DataTable.defaults.column.defaultContent
  10962. * @dtopt Columns
  10963. *
  10964. * @example
  10965. * // Using `columnDefs`
  10966. * $(document).ready( function() {
  10967. * $('#example').dataTable( {
  10968. * "columnDefs": [
  10969. * {
  10970. * "data": null,
  10971. * "defaultContent": "Edit",
  10972. * "targets": [ -1 ]
  10973. * }
  10974. * ]
  10975. * } );
  10976. * } );
  10977. *
  10978. * @example
  10979. * // Using `columns`
  10980. * $(document).ready( function() {
  10981. * $('#example').dataTable( {
  10982. * "columns": [
  10983. * null,
  10984. * null,
  10985. * null,
  10986. * {
  10987. * "data": null,
  10988. * "defaultContent": "Edit"
  10989. * }
  10990. * ]
  10991. * } );
  10992. * } );
  10993. */
  10994. "sDefaultContent": null,
  10995. /**
  10996. * This parameter is only used in DataTables' server-side processing. It can
  10997. * be exceptionally useful to know what columns are being displayed on the
  10998. * client side, and to map these to database fields. When defined, the names
  10999. * also allow DataTables to reorder information from the server if it comes
  11000. * back in an unexpected order (i.e. if you switch your columns around on the
  11001. * client-side, your server-side code does not also need updating).
  11002. * @type string
  11003. * @default <i>Empty string</i>
  11004. *
  11005. * @name DataTable.defaults.column.name
  11006. * @dtopt Columns
  11007. *
  11008. * @example
  11009. * // Using `columnDefs`
  11010. * $(document).ready( function() {
  11011. * $('#example').dataTable( {
  11012. * "columnDefs": [
  11013. * { "name": "engine", "targets": [ 0 ] },
  11014. * { "name": "browser", "targets": [ 1 ] },
  11015. * { "name": "platform", "targets": [ 2 ] },
  11016. * { "name": "version", "targets": [ 3 ] },
  11017. * { "name": "grade", "targets": [ 4 ] }
  11018. * ]
  11019. * } );
  11020. * } );
  11021. *
  11022. * @example
  11023. * // Using `columns`
  11024. * $(document).ready( function() {
  11025. * $('#example').dataTable( {
  11026. * "columns": [
  11027. * { "name": "engine" },
  11028. * { "name": "browser" },
  11029. * { "name": "platform" },
  11030. * { "name": "version" },
  11031. * { "name": "grade" }
  11032. * ]
  11033. * } );
  11034. * } );
  11035. */
  11036. "sName": "",
  11037. /**
  11038. * Defines a data source type for the ordering which can be used to read
  11039. * real-time information from the table (updating the internally cached
  11040. * version) prior to ordering. This allows ordering to occur on user
  11041. * editable elements such as form inputs.
  11042. * @type string
  11043. * @default std
  11044. *
  11045. * @name DataTable.defaults.column.orderDataType
  11046. * @dtopt Columns
  11047. *
  11048. * @example
  11049. * // Using `columnDefs`
  11050. * $(document).ready( function() {
  11051. * $('#example').dataTable( {
  11052. * "columnDefs": [
  11053. * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
  11054. * { "type": "numeric", "targets": [ 3 ] },
  11055. * { "orderDataType": "dom-select", "targets": [ 4 ] },
  11056. * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
  11057. * ]
  11058. * } );
  11059. * } );
  11060. *
  11061. * @example
  11062. * // Using `columns`
  11063. * $(document).ready( function() {
  11064. * $('#example').dataTable( {
  11065. * "columns": [
  11066. * null,
  11067. * null,
  11068. * { "orderDataType": "dom-text" },
  11069. * { "orderDataType": "dom-text", "type": "numeric" },
  11070. * { "orderDataType": "dom-select" },
  11071. * { "orderDataType": "dom-checkbox" }
  11072. * ]
  11073. * } );
  11074. * } );
  11075. */
  11076. "sSortDataType": "std",
  11077. /**
  11078. * The title of this column.
  11079. * @type string
  11080. * @default null <i>Derived from the 'TH' value for this column in the
  11081. * original HTML table.</i>
  11082. *
  11083. * @name DataTable.defaults.column.title
  11084. * @dtopt Columns
  11085. *
  11086. * @example
  11087. * // Using `columnDefs`
  11088. * $(document).ready( function() {
  11089. * $('#example').dataTable( {
  11090. * "columnDefs": [
  11091. * { "title": "My column title", "targets": [ 0 ] }
  11092. * ]
  11093. * } );
  11094. * } );
  11095. *
  11096. * @example
  11097. * // Using `columns`
  11098. * $(document).ready( function() {
  11099. * $('#example').dataTable( {
  11100. * "columns": [
  11101. * { "title": "My column title" },
  11102. * null,
  11103. * null,
  11104. * null,
  11105. * null
  11106. * ]
  11107. * } );
  11108. * } );
  11109. */
  11110. "sTitle": null,
  11111. /**
  11112. * The type allows you to specify how the data for this column will be
  11113. * ordered. Four types (string, numeric, date and html (which will strip
  11114. * HTML tags before ordering)) are currently available. Note that only date
  11115. * formats understood by Javascript's Date() object will be accepted as type
  11116. * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
  11117. * 'numeric', 'date' or 'html' (by default). Further types can be adding
  11118. * through plug-ins.
  11119. * @type string
  11120. * @default null <i>Auto-detected from raw data</i>
  11121. *
  11122. * @name DataTable.defaults.column.type
  11123. * @dtopt Columns
  11124. *
  11125. * @example
  11126. * // Using `columnDefs`
  11127. * $(document).ready( function() {
  11128. * $('#example').dataTable( {
  11129. * "columnDefs": [
  11130. * { "type": "html", "targets": [ 0 ] }
  11131. * ]
  11132. * } );
  11133. * } );
  11134. *
  11135. * @example
  11136. * // Using `columns`
  11137. * $(document).ready( function() {
  11138. * $('#example').dataTable( {
  11139. * "columns": [
  11140. * { "type": "html" },
  11141. * null,
  11142. * null,
  11143. * null,
  11144. * null
  11145. * ]
  11146. * } );
  11147. * } );
  11148. */
  11149. "sType": null,
  11150. /**
  11151. * Defining the width of the column, this parameter may take any CSS value
  11152. * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
  11153. * been given a specific width through this interface ensuring that the table
  11154. * remains readable.
  11155. * @type string
  11156. * @default null <i>Automatic</i>
  11157. *
  11158. * @name DataTable.defaults.column.width
  11159. * @dtopt Columns
  11160. *
  11161. * @example
  11162. * // Using `columnDefs`
  11163. * $(document).ready( function() {
  11164. * $('#example').dataTable( {
  11165. * "columnDefs": [
  11166. * { "width": "20%", "targets": [ 0 ] }
  11167. * ]
  11168. * } );
  11169. * } );
  11170. *
  11171. * @example
  11172. * // Using `columns`
  11173. * $(document).ready( function() {
  11174. * $('#example').dataTable( {
  11175. * "columns": [
  11176. * { "width": "20%" },
  11177. * null,
  11178. * null,
  11179. * null,
  11180. * null
  11181. * ]
  11182. * } );
  11183. * } );
  11184. */
  11185. "sWidth": null
  11186. };
  11187. _fnHungarianMap( DataTable.defaults.column );
  11188. /**
  11189. * DataTables settings object - this holds all the information needed for a
  11190. * given table, including configuration, data and current application of the
  11191. * table options. DataTables does not have a single instance for each DataTable
  11192. * with the settings attached to that instance, but rather instances of the
  11193. * DataTable "class" are created on-the-fly as needed (typically by a
  11194. * $().dataTable() call) and the settings object is then applied to that
  11195. * instance.
  11196. *
  11197. * Note that this object is related to {@link DataTable.defaults} but this
  11198. * one is the internal data store for DataTables's cache of columns. It should
  11199. * NOT be manipulated outside of DataTables. Any configuration should be done
  11200. * through the initialisation options.
  11201. * @namespace
  11202. * @todo Really should attach the settings object to individual instances so we
  11203. * don't need to create new instances on each $().dataTable() call (if the
  11204. * table already exists). It would also save passing oSettings around and
  11205. * into every single function. However, this is a very significant
  11206. * architecture change for DataTables and will almost certainly break
  11207. * backwards compatibility with older installations. This is something that
  11208. * will be done in 2.0.
  11209. */
  11210. DataTable.models.oSettings = {
  11211. /**
  11212. * Primary features of DataTables and their enablement state.
  11213. * @namespace
  11214. */
  11215. "oFeatures": {
  11216. /**
  11217. * Flag to say if DataTables should automatically try to calculate the
  11218. * optimum table and columns widths (true) or not (false).
  11219. * Note that this parameter will be set by the initialisation routine. To
  11220. * set a default use {@link DataTable.defaults}.
  11221. * @type boolean
  11222. */
  11223. "bAutoWidth": null,
  11224. /**
  11225. * Delay the creation of TR and TD elements until they are actually
  11226. * needed by a driven page draw. This can give a significant speed
  11227. * increase for Ajax source and Javascript source data, but makes no
  11228. * difference at all fro DOM and server-side processing tables.
  11229. * Note that this parameter will be set by the initialisation routine. To
  11230. * set a default use {@link DataTable.defaults}.
  11231. * @type boolean
  11232. */
  11233. "bDeferRender": null,
  11234. /**
  11235. * Enable filtering on the table or not. Note that if this is disabled
  11236. * then there is no filtering at all on the table, including fnFilter.
  11237. * To just remove the filtering input use sDom and remove the 'f' option.
  11238. * Note that this parameter will be set by the initialisation routine. To
  11239. * set a default use {@link DataTable.defaults}.
  11240. * @type boolean
  11241. */
  11242. "bFilter": null,
  11243. /**
  11244. * Table information element (the 'Showing x of y records' div) enable
  11245. * flag.
  11246. * Note that this parameter will be set by the initialisation routine. To
  11247. * set a default use {@link DataTable.defaults}.
  11248. * @type boolean
  11249. */
  11250. "bInfo": null,
  11251. /**
  11252. * Present a user control allowing the end user to change the page size
  11253. * when pagination is enabled.
  11254. * Note that this parameter will be set by the initialisation routine. To
  11255. * set a default use {@link DataTable.defaults}.
  11256. * @type boolean
  11257. */
  11258. "bLengthChange": null,
  11259. /**
  11260. * Pagination enabled or not. Note that if this is disabled then length
  11261. * changing must also be disabled.
  11262. * Note that this parameter will be set by the initialisation routine. To
  11263. * set a default use {@link DataTable.defaults}.
  11264. * @type boolean
  11265. */
  11266. "bPaginate": null,
  11267. /**
  11268. * Processing indicator enable flag whenever DataTables is enacting a
  11269. * user request - typically an Ajax request for server-side processing.
  11270. * Note that this parameter will be set by the initialisation routine. To
  11271. * set a default use {@link DataTable.defaults}.
  11272. * @type boolean
  11273. */
  11274. "bProcessing": null,
  11275. /**
  11276. * Server-side processing enabled flag - when enabled DataTables will
  11277. * get all data from the server for every draw - there is no filtering,
  11278. * sorting or paging done on the client-side.
  11279. * Note that this parameter will be set by the initialisation routine. To
  11280. * set a default use {@link DataTable.defaults}.
  11281. * @type boolean
  11282. */
  11283. "bServerSide": null,
  11284. /**
  11285. * Sorting enablement flag.
  11286. * Note that this parameter will be set by the initialisation routine. To
  11287. * set a default use {@link DataTable.defaults}.
  11288. * @type boolean
  11289. */
  11290. "bSort": null,
  11291. /**
  11292. * Multi-column sorting
  11293. * Note that this parameter will be set by the initialisation routine. To
  11294. * set a default use {@link DataTable.defaults}.
  11295. * @type boolean
  11296. */
  11297. "bSortMulti": null,
  11298. /**
  11299. * Apply a class to the columns which are being sorted to provide a
  11300. * visual highlight or not. This can slow things down when enabled since
  11301. * there is a lot of DOM interaction.
  11302. * Note that this parameter will be set by the initialisation routine. To
  11303. * set a default use {@link DataTable.defaults}.
  11304. * @type boolean
  11305. */
  11306. "bSortClasses": null,
  11307. /**
  11308. * State saving enablement flag.
  11309. * Note that this parameter will be set by the initialisation routine. To
  11310. * set a default use {@link DataTable.defaults}.
  11311. * @type boolean
  11312. */
  11313. "bStateSave": null
  11314. },
  11315. /**
  11316. * Scrolling settings for a table.
  11317. * @namespace
  11318. */
  11319. "oScroll": {
  11320. /**
  11321. * When the table is shorter in height than sScrollY, collapse the
  11322. * table container down to the height of the table (when true).
  11323. * Note that this parameter will be set by the initialisation routine. To
  11324. * set a default use {@link DataTable.defaults}.
  11325. * @type boolean
  11326. */
  11327. "bCollapse": null,
  11328. /**
  11329. * Width of the scrollbar for the web-browser's platform. Calculated
  11330. * during table initialisation.
  11331. * @type int
  11332. * @default 0
  11333. */
  11334. "iBarWidth": 0,
  11335. /**
  11336. * Viewport width for horizontal scrolling. Horizontal scrolling is
  11337. * disabled if an empty string.
  11338. * Note that this parameter will be set by the initialisation routine. To
  11339. * set a default use {@link DataTable.defaults}.
  11340. * @type string
  11341. */
  11342. "sX": null,
  11343. /**
  11344. * Width to expand the table to when using x-scrolling. Typically you
  11345. * should not need to use this.
  11346. * Note that this parameter will be set by the initialisation routine. To
  11347. * set a default use {@link DataTable.defaults}.
  11348. * @type string
  11349. * @deprecated
  11350. */
  11351. "sXInner": null,
  11352. /**
  11353. * Viewport height for vertical scrolling. Vertical scrolling is disabled
  11354. * if an empty string.
  11355. * Note that this parameter will be set by the initialisation routine. To
  11356. * set a default use {@link DataTable.defaults}.
  11357. * @type string
  11358. */
  11359. "sY": null
  11360. },
  11361. /**
  11362. * Language information for the table.
  11363. * @namespace
  11364. * @extends DataTable.defaults.oLanguage
  11365. */
  11366. "oLanguage": {
  11367. /**
  11368. * Information callback function. See
  11369. * {@link DataTable.defaults.fnInfoCallback}
  11370. * @type function
  11371. * @default null
  11372. */
  11373. "fnInfoCallback": null
  11374. },
  11375. /**
  11376. * Browser support parameters
  11377. * @namespace
  11378. */
  11379. "oBrowser": {
  11380. /**
  11381. * Indicate if the browser incorrectly calculates width:100% inside a
  11382. * scrolling element (IE6/7)
  11383. * @type boolean
  11384. * @default false
  11385. */
  11386. "bScrollOversize": false,
  11387. /**
  11388. * Determine if the vertical scrollbar is on the right or left of the
  11389. * scrolling container - needed for rtl language layout, although not
  11390. * all browsers move the scrollbar (Safari).
  11391. * @type boolean
  11392. * @default false
  11393. */
  11394. "bScrollbarLeft": false,
  11395. /**
  11396. * Flag for if `getBoundingClientRect` is fully supported or not
  11397. * @type boolean
  11398. * @default false
  11399. */
  11400. "bBounding": false,
  11401. /**
  11402. * Browser scrollbar width
  11403. * @type integer
  11404. * @default 0
  11405. */
  11406. "barWidth": 0
  11407. },
  11408. "ajax": null,
  11409. /**
  11410. * Array referencing the nodes which are used for the features. The
  11411. * parameters of this object match what is allowed by sDom - i.e.
  11412. * <ul>
  11413. * <li>'l' - Length changing</li>
  11414. * <li>'f' - Filtering input</li>
  11415. * <li>'t' - The table!</li>
  11416. * <li>'i' - Information</li>
  11417. * <li>'p' - Pagination</li>
  11418. * <li>'r' - pRocessing</li>
  11419. * </ul>
  11420. * @type array
  11421. * @default []
  11422. */
  11423. "aanFeatures": [],
  11424. /**
  11425. * Store data information - see {@link DataTable.models.oRow} for detailed
  11426. * information.
  11427. * @type array
  11428. * @default []
  11429. */
  11430. "aoData": [],
  11431. /**
  11432. * Array of indexes which are in the current display (after filtering etc)
  11433. * @type array
  11434. * @default []
  11435. */
  11436. "aiDisplay": [],
  11437. /**
  11438. * Array of indexes for display - no filtering
  11439. * @type array
  11440. * @default []
  11441. */
  11442. "aiDisplayMaster": [],
  11443. /**
  11444. * Map of row ids to data indexes
  11445. * @type object
  11446. * @default {}
  11447. */
  11448. "aIds": {},
  11449. /**
  11450. * Store information about each column that is in use
  11451. * @type array
  11452. * @default []
  11453. */
  11454. "aoColumns": [],
  11455. /**
  11456. * Store information about the table's header
  11457. * @type array
  11458. * @default []
  11459. */
  11460. "aoHeader": [],
  11461. /**
  11462. * Store information about the table's footer
  11463. * @type array
  11464. * @default []
  11465. */
  11466. "aoFooter": [],
  11467. /**
  11468. * Store the applied global search information in case we want to force a
  11469. * research or compare the old search to a new one.
  11470. * Note that this parameter will be set by the initialisation routine. To
  11471. * set a default use {@link DataTable.defaults}.
  11472. * @namespace
  11473. * @extends DataTable.models.oSearch
  11474. */
  11475. "oPreviousSearch": {},
  11476. /**
  11477. * Store the applied search for each column - see
  11478. * {@link DataTable.models.oSearch} for the format that is used for the
  11479. * filtering information for each column.
  11480. * @type array
  11481. * @default []
  11482. */
  11483. "aoPreSearchCols": [],
  11484. /**
  11485. * Sorting that is applied to the table. Note that the inner arrays are
  11486. * used in the following manner:
  11487. * <ul>
  11488. * <li>Index 0 - column number</li>
  11489. * <li>Index 1 - current sorting direction</li>
  11490. * </ul>
  11491. * Note that this parameter will be set by the initialisation routine. To
  11492. * set a default use {@link DataTable.defaults}.
  11493. * @type array
  11494. * @todo These inner arrays should really be objects
  11495. */
  11496. "aaSorting": null,
  11497. /**
  11498. * Sorting that is always applied to the table (i.e. prefixed in front of
  11499. * aaSorting).
  11500. * Note that this parameter will be set by the initialisation routine. To
  11501. * set a default use {@link DataTable.defaults}.
  11502. * @type array
  11503. * @default []
  11504. */
  11505. "aaSortingFixed": [],
  11506. /**
  11507. * Classes to use for the striping of a table.
  11508. * Note that this parameter will be set by the initialisation routine. To
  11509. * set a default use {@link DataTable.defaults}.
  11510. * @type array
  11511. * @default []
  11512. */
  11513. "asStripeClasses": null,
  11514. /**
  11515. * If restoring a table - we should restore its striping classes as well
  11516. * @type array
  11517. * @default []
  11518. */
  11519. "asDestroyStripes": [],
  11520. /**
  11521. * If restoring a table - we should restore its width
  11522. * @type int
  11523. * @default 0
  11524. */
  11525. "sDestroyWidth": 0,
  11526. /**
  11527. * Callback functions array for every time a row is inserted (i.e. on a draw).
  11528. * @type array
  11529. * @default []
  11530. */
  11531. "aoRowCallback": [],
  11532. /**
  11533. * Callback functions for the header on each draw.
  11534. * @type array
  11535. * @default []
  11536. */
  11537. "aoHeaderCallback": [],
  11538. /**
  11539. * Callback function for the footer on each draw.
  11540. * @type array
  11541. * @default []
  11542. */
  11543. "aoFooterCallback": [],
  11544. /**
  11545. * Array of callback functions for draw callback functions
  11546. * @type array
  11547. * @default []
  11548. */
  11549. "aoDrawCallback": [],
  11550. /**
  11551. * Array of callback functions for row created function
  11552. * @type array
  11553. * @default []
  11554. */
  11555. "aoRowCreatedCallback": [],
  11556. /**
  11557. * Callback functions for just before the table is redrawn. A return of
  11558. * false will be used to cancel the draw.
  11559. * @type array
  11560. * @default []
  11561. */
  11562. "aoPreDrawCallback": [],
  11563. /**
  11564. * Callback functions for when the table has been initialised.
  11565. * @type array
  11566. * @default []
  11567. */
  11568. "aoInitComplete": [],
  11569. /**
  11570. * Callbacks for modifying the settings to be stored for state saving, prior to
  11571. * saving state.
  11572. * @type array
  11573. * @default []
  11574. */
  11575. "aoStateSaveParams": [],
  11576. /**
  11577. * Callbacks for modifying the settings that have been stored for state saving
  11578. * prior to using the stored values to restore the state.
  11579. * @type array
  11580. * @default []
  11581. */
  11582. "aoStateLoadParams": [],
  11583. /**
  11584. * Callbacks for operating on the settings object once the saved state has been
  11585. * loaded
  11586. * @type array
  11587. * @default []
  11588. */
  11589. "aoStateLoaded": [],
  11590. /**
  11591. * Cache the table ID for quick access
  11592. * @type string
  11593. * @default <i>Empty string</i>
  11594. */
  11595. "sTableId": "",
  11596. /**
  11597. * The TABLE node for the main table
  11598. * @type node
  11599. * @default null
  11600. */
  11601. "nTable": null,
  11602. /**
  11603. * Permanent ref to the thead element
  11604. * @type node
  11605. * @default null
  11606. */
  11607. "nTHead": null,
  11608. /**
  11609. * Permanent ref to the tfoot element - if it exists
  11610. * @type node
  11611. * @default null
  11612. */
  11613. "nTFoot": null,
  11614. /**
  11615. * Permanent ref to the tbody element
  11616. * @type node
  11617. * @default null
  11618. */
  11619. "nTBody": null,
  11620. /**
  11621. * Cache the wrapper node (contains all DataTables controlled elements)
  11622. * @type node
  11623. * @default null
  11624. */
  11625. "nTableWrapper": null,
  11626. /**
  11627. * Indicate if when using server-side processing the loading of data
  11628. * should be deferred until the second draw.
  11629. * Note that this parameter will be set by the initialisation routine. To
  11630. * set a default use {@link DataTable.defaults}.
  11631. * @type boolean
  11632. * @default false
  11633. */
  11634. "bDeferLoading": false,
  11635. /**
  11636. * Indicate if all required information has been read in
  11637. * @type boolean
  11638. * @default false
  11639. */
  11640. "bInitialised": false,
  11641. /**
  11642. * Information about open rows. Each object in the array has the parameters
  11643. * 'nTr' and 'nParent'
  11644. * @type array
  11645. * @default []
  11646. */
  11647. "aoOpenRows": [],
  11648. /**
  11649. * Dictate the positioning of DataTables' control elements - see
  11650. * {@link DataTable.model.oInit.sDom}.
  11651. * Note that this parameter will be set by the initialisation routine. To
  11652. * set a default use {@link DataTable.defaults}.
  11653. * @type string
  11654. * @default null
  11655. */
  11656. "sDom": null,
  11657. /**
  11658. * Search delay (in mS)
  11659. * @type integer
  11660. * @default null
  11661. */
  11662. "searchDelay": null,
  11663. /**
  11664. * Which type of pagination should be used.
  11665. * Note that this parameter will be set by the initialisation routine. To
  11666. * set a default use {@link DataTable.defaults}.
  11667. * @type string
  11668. * @default two_button
  11669. */
  11670. "sPaginationType": "two_button",
  11671. /**
  11672. * The state duration (for `stateSave`) in seconds.
  11673. * Note that this parameter will be set by the initialisation routine. To
  11674. * set a default use {@link DataTable.defaults}.
  11675. * @type int
  11676. * @default 0
  11677. */
  11678. "iStateDuration": 0,
  11679. /**
  11680. * Array of callback functions for state saving. Each array element is an
  11681. * object with the following parameters:
  11682. * <ul>
  11683. * <li>function:fn - function to call. Takes two parameters, oSettings
  11684. * and the JSON string to save that has been thus far created. Returns
  11685. * a JSON string to be inserted into a json object
  11686. * (i.e. '"param": [ 0, 1, 2]')</li>
  11687. * <li>string:sName - name of callback</li>
  11688. * </ul>
  11689. * @type array
  11690. * @default []
  11691. */
  11692. "aoStateSave": [],
  11693. /**
  11694. * Array of callback functions for state loading. Each array element is an
  11695. * object with the following parameters:
  11696. * <ul>
  11697. * <li>function:fn - function to call. Takes two parameters, oSettings
  11698. * and the object stored. May return false to cancel state loading</li>
  11699. * <li>string:sName - name of callback</li>
  11700. * </ul>
  11701. * @type array
  11702. * @default []
  11703. */
  11704. "aoStateLoad": [],
  11705. /**
  11706. * State that was saved. Useful for back reference
  11707. * @type object
  11708. * @default null
  11709. */
  11710. "oSavedState": null,
  11711. /**
  11712. * State that was loaded. Useful for back reference
  11713. * @type object
  11714. * @default null
  11715. */
  11716. "oLoadedState": null,
  11717. /**
  11718. * Source url for AJAX data for the table.
  11719. * Note that this parameter will be set by the initialisation routine. To
  11720. * set a default use {@link DataTable.defaults}.
  11721. * @type string
  11722. * @default null
  11723. */
  11724. "sAjaxSource": null,
  11725. /**
  11726. * Property from a given object from which to read the table data from. This
  11727. * can be an empty string (when not server-side processing), in which case
  11728. * it is assumed an an array is given directly.
  11729. * Note that this parameter will be set by the initialisation routine. To
  11730. * set a default use {@link DataTable.defaults}.
  11731. * @type string
  11732. */
  11733. "sAjaxDataProp": null,
  11734. /**
  11735. * Note if draw should be blocked while getting data
  11736. * @type boolean
  11737. * @default true
  11738. */
  11739. "bAjaxDataGet": true,
  11740. /**
  11741. * The last jQuery XHR object that was used for server-side data gathering.
  11742. * This can be used for working with the XHR information in one of the
  11743. * callbacks
  11744. * @type object
  11745. * @default null
  11746. */
  11747. "jqXHR": null,
  11748. /**
  11749. * JSON returned from the server in the last Ajax request
  11750. * @type object
  11751. * @default undefined
  11752. */
  11753. "json": undefined,
  11754. /**
  11755. * Data submitted as part of the last Ajax request
  11756. * @type object
  11757. * @default undefined
  11758. */
  11759. "oAjaxData": undefined,
  11760. /**
  11761. * Function to get the server-side data.
  11762. * Note that this parameter will be set by the initialisation routine. To
  11763. * set a default use {@link DataTable.defaults}.
  11764. * @type function
  11765. */
  11766. "fnServerData": null,
  11767. /**
  11768. * Functions which are called prior to sending an Ajax request so extra
  11769. * parameters can easily be sent to the server
  11770. * @type array
  11771. * @default []
  11772. */
  11773. "aoServerParams": [],
  11774. /**
  11775. * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
  11776. * required).
  11777. * Note that this parameter will be set by the initialisation routine. To
  11778. * set a default use {@link DataTable.defaults}.
  11779. * @type string
  11780. */
  11781. "sServerMethod": null,
  11782. /**
  11783. * Format numbers for display.
  11784. * Note that this parameter will be set by the initialisation routine. To
  11785. * set a default use {@link DataTable.defaults}.
  11786. * @type function
  11787. */
  11788. "fnFormatNumber": null,
  11789. /**
  11790. * List of options that can be used for the user selectable length menu.
  11791. * Note that this parameter will be set by the initialisation routine. To
  11792. * set a default use {@link DataTable.defaults}.
  11793. * @type array
  11794. * @default []
  11795. */
  11796. "aLengthMenu": null,
  11797. /**
  11798. * Counter for the draws that the table does. Also used as a tracker for
  11799. * server-side processing
  11800. * @type int
  11801. * @default 0
  11802. */
  11803. "iDraw": 0,
  11804. /**
  11805. * Indicate if a redraw is being done - useful for Ajax
  11806. * @type boolean
  11807. * @default false
  11808. */
  11809. "bDrawing": false,
  11810. /**
  11811. * Draw index (iDraw) of the last error when parsing the returned data
  11812. * @type int
  11813. * @default -1
  11814. */
  11815. "iDrawError": -1,
  11816. /**
  11817. * Paging display length
  11818. * @type int
  11819. * @default 10
  11820. */
  11821. "_iDisplayLength": 10,
  11822. /**
  11823. * Paging start point - aiDisplay index
  11824. * @type int
  11825. * @default 0
  11826. */
  11827. "_iDisplayStart": 0,
  11828. /**
  11829. * Server-side processing - number of records in the result set
  11830. * (i.e. before filtering), Use fnRecordsTotal rather than
  11831. * this property to get the value of the number of records, regardless of
  11832. * the server-side processing setting.
  11833. * @type int
  11834. * @default 0
  11835. * @private
  11836. */
  11837. "_iRecordsTotal": 0,
  11838. /**
  11839. * Server-side processing - number of records in the current display set
  11840. * (i.e. after filtering). Use fnRecordsDisplay rather than
  11841. * this property to get the value of the number of records, regardless of
  11842. * the server-side processing setting.
  11843. * @type boolean
  11844. * @default 0
  11845. * @private
  11846. */
  11847. "_iRecordsDisplay": 0,
  11848. /**
  11849. * The classes to use for the table
  11850. * @type object
  11851. * @default {}
  11852. */
  11853. "oClasses": {},
  11854. /**
  11855. * Flag attached to the settings object so you can check in the draw
  11856. * callback if filtering has been done in the draw. Deprecated in favour of
  11857. * events.
  11858. * @type boolean
  11859. * @default false
  11860. * @deprecated
  11861. */
  11862. "bFiltered": false,
  11863. /**
  11864. * Flag attached to the settings object so you can check in the draw
  11865. * callback if sorting has been done in the draw. Deprecated in favour of
  11866. * events.
  11867. * @type boolean
  11868. * @default false
  11869. * @deprecated
  11870. */
  11871. "bSorted": false,
  11872. /**
  11873. * Indicate that if multiple rows are in the header and there is more than
  11874. * one unique cell per column, if the top one (true) or bottom one (false)
  11875. * should be used for sorting / title by DataTables.
  11876. * Note that this parameter will be set by the initialisation routine. To
  11877. * set a default use {@link DataTable.defaults}.
  11878. * @type boolean
  11879. */
  11880. "bSortCellsTop": null,
  11881. /**
  11882. * Initialisation object that is used for the table
  11883. * @type object
  11884. * @default null
  11885. */
  11886. "oInit": null,
  11887. /**
  11888. * Destroy callback functions - for plug-ins to attach themselves to the
  11889. * destroy so they can clean up markup and events.
  11890. * @type array
  11891. * @default []
  11892. */
  11893. "aoDestroyCallback": [],
  11894. /**
  11895. * Get the number of records in the current record set, before filtering
  11896. * @type function
  11897. */
  11898. "fnRecordsTotal": function ()
  11899. {
  11900. return _fnDataSource( this ) == 'ssp' ?
  11901. this._iRecordsTotal * 1 :
  11902. this.aiDisplayMaster.length;
  11903. },
  11904. /**
  11905. * Get the number of records in the current record set, after filtering
  11906. * @type function
  11907. */
  11908. "fnRecordsDisplay": function ()
  11909. {
  11910. return _fnDataSource( this ) == 'ssp' ?
  11911. this._iRecordsDisplay * 1 :
  11912. this.aiDisplay.length;
  11913. },
  11914. /**
  11915. * Get the display end point - aiDisplay index
  11916. * @type function
  11917. */
  11918. "fnDisplayEnd": function ()
  11919. {
  11920. var
  11921. len = this._iDisplayLength,
  11922. start = this._iDisplayStart,
  11923. calc = start + len,
  11924. records = this.aiDisplay.length,
  11925. features = this.oFeatures,
  11926. paginate = features.bPaginate;
  11927. if ( features.bServerSide ) {
  11928. return paginate === false || len === -1 ?
  11929. start + records :
  11930. Math.min( start+len, this._iRecordsDisplay );
  11931. }
  11932. else {
  11933. return ! paginate || calc>records || len===-1 ?
  11934. records :
  11935. calc;
  11936. }
  11937. },
  11938. /**
  11939. * The DataTables object for this table
  11940. * @type object
  11941. * @default null
  11942. */
  11943. "oInstance": null,
  11944. /**
  11945. * Unique identifier for each instance of the DataTables object. If there
  11946. * is an ID on the table node, then it takes that value, otherwise an
  11947. * incrementing internal counter is used.
  11948. * @type string
  11949. * @default null
  11950. */
  11951. "sInstance": null,
  11952. /**
  11953. * tabindex attribute value that is added to DataTables control elements, allowing
  11954. * keyboard navigation of the table and its controls.
  11955. */
  11956. "iTabIndex": 0,
  11957. /**
  11958. * DIV container for the footer scrolling table if scrolling
  11959. */
  11960. "nScrollHead": null,
  11961. /**
  11962. * DIV container for the footer scrolling table if scrolling
  11963. */
  11964. "nScrollFoot": null,
  11965. /**
  11966. * Last applied sort
  11967. * @type array
  11968. * @default []
  11969. */
  11970. "aLastSort": [],
  11971. /**
  11972. * Stored plug-in instances
  11973. * @type object
  11974. * @default {}
  11975. */
  11976. "oPlugins": {},
  11977. /**
  11978. * Function used to get a row's id from the row's data
  11979. * @type function
  11980. * @default null
  11981. */
  11982. "rowIdFn": null,
  11983. /**
  11984. * Data location where to store a row's id
  11985. * @type string
  11986. * @default null
  11987. */
  11988. "rowId": null
  11989. };
  11990. /**
  11991. * Extension object for DataTables that is used to provide all extension
  11992. * options.
  11993. *
  11994. * Note that the `DataTable.ext` object is available through
  11995. * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
  11996. * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
  11997. * @namespace
  11998. * @extends DataTable.models.ext
  11999. */
  12000. /**
  12001. * DataTables extensions
  12002. *
  12003. * This namespace acts as a collection area for plug-ins that can be used to
  12004. * extend DataTables capabilities. Indeed many of the build in methods
  12005. * use this method to provide their own capabilities (sorting methods for
  12006. * example).
  12007. *
  12008. * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
  12009. * reasons
  12010. *
  12011. * @namespace
  12012. */
  12013. DataTable.ext = _ext = {
  12014. /**
  12015. * Buttons. For use with the Buttons extension for DataTables. This is
  12016. * defined here so other extensions can define buttons regardless of load
  12017. * order. It is _not_ used by DataTables core.
  12018. *
  12019. * @type object
  12020. * @default {}
  12021. */
  12022. buttons: {},
  12023. /**
  12024. * Element class names
  12025. *
  12026. * @type object
  12027. * @default {}
  12028. */
  12029. classes: {},
  12030. /**
  12031. * DataTables build type (expanded by the download builder)
  12032. *
  12033. * @type string
  12034. */
  12035. build:"dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5",
  12036. /**
  12037. * Error reporting.
  12038. *
  12039. * How should DataTables report an error. Can take the value 'alert',
  12040. * 'throw', 'none' or a function.
  12041. *
  12042. * @type string|function
  12043. * @default alert
  12044. */
  12045. errMode: "alert",
  12046. /**
  12047. * Feature plug-ins.
  12048. *
  12049. * This is an array of objects which describe the feature plug-ins that are
  12050. * available to DataTables. These feature plug-ins are then available for
  12051. * use through the `dom` initialisation option.
  12052. *
  12053. * Each feature plug-in is described by an object which must have the
  12054. * following properties:
  12055. *
  12056. * * `fnInit` - function that is used to initialise the plug-in,
  12057. * * `cFeature` - a character so the feature can be enabled by the `dom`
  12058. * instillation option. This is case sensitive.
  12059. *
  12060. * The `fnInit` function has the following input parameters:
  12061. *
  12062. * 1. `{object}` DataTables settings object: see
  12063. * {@link DataTable.models.oSettings}
  12064. *
  12065. * And the following return is expected:
  12066. *
  12067. * * {node|null} The element which contains your feature. Note that the
  12068. * return may also be void if your plug-in does not require to inject any
  12069. * DOM elements into DataTables control (`dom`) - for example this might
  12070. * be useful when developing a plug-in which allows table control via
  12071. * keyboard entry
  12072. *
  12073. * @type array
  12074. *
  12075. * @example
  12076. * $.fn.dataTable.ext.features.push( {
  12077. * "fnInit": function( oSettings ) {
  12078. * return new TableTools( { "oDTSettings": oSettings } );
  12079. * },
  12080. * "cFeature": "T"
  12081. * } );
  12082. */
  12083. feature: [],
  12084. /**
  12085. * Row searching.
  12086. *
  12087. * This method of searching is complimentary to the default type based
  12088. * searching, and a lot more comprehensive as it allows you complete control
  12089. * over the searching logic. Each element in this array is a function
  12090. * (parameters described below) that is called for every row in the table,
  12091. * and your logic decides if it should be included in the searching data set
  12092. * or not.
  12093. *
  12094. * Searching functions have the following input parameters:
  12095. *
  12096. * 1. `{object}` DataTables settings object: see
  12097. * {@link DataTable.models.oSettings}
  12098. * 2. `{array|object}` Data for the row to be processed (same as the
  12099. * original format that was passed in as the data source, or an array
  12100. * from a DOM data source
  12101. * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
  12102. * can be useful to retrieve the `TR` element if you need DOM interaction.
  12103. *
  12104. * And the following return is expected:
  12105. *
  12106. * * {boolean} Include the row in the searched result set (true) or not
  12107. * (false)
  12108. *
  12109. * Note that as with the main search ability in DataTables, technically this
  12110. * is "filtering", since it is subtractive. However, for consistency in
  12111. * naming we call it searching here.
  12112. *
  12113. * @type array
  12114. * @default []
  12115. *
  12116. * @example
  12117. * // The following example shows custom search being applied to the
  12118. * // fourth column (i.e. the data[3] index) based on two input values
  12119. * // from the end-user, matching the data in a certain range.
  12120. * $.fn.dataTable.ext.search.push(
  12121. * function( settings, data, dataIndex ) {
  12122. * var min = document.getElementById('min').value * 1;
  12123. * var max = document.getElementById('max').value * 1;
  12124. * var version = data[3] == "-" ? 0 : data[3]*1;
  12125. *
  12126. * if ( min == "" && max == "" ) {
  12127. * return true;
  12128. * }
  12129. * else if ( min == "" && version < max ) {
  12130. * return true;
  12131. * }
  12132. * else if ( min < version && "" == max ) {
  12133. * return true;
  12134. * }
  12135. * else if ( min < version && version < max ) {
  12136. * return true;
  12137. * }
  12138. * return false;
  12139. * }
  12140. * );
  12141. */
  12142. search: [],
  12143. /**
  12144. * Selector extensions
  12145. *
  12146. * The `selector` option can be used to extend the options available for the
  12147. * selector modifier options (`selector-modifier` object data type) that
  12148. * each of the three built in selector types offer (row, column and cell +
  12149. * their plural counterparts). For example the Select extension uses this
  12150. * mechanism to provide an option to select only rows, columns and cells
  12151. * that have been marked as selected by the end user (`{selected: true}`),
  12152. * which can be used in conjunction with the existing built in selector
  12153. * options.
  12154. *
  12155. * Each property is an array to which functions can be pushed. The functions
  12156. * take three attributes:
  12157. *
  12158. * * Settings object for the host table
  12159. * * Options object (`selector-modifier` object type)
  12160. * * Array of selected item indexes
  12161. *
  12162. * The return is an array of the resulting item indexes after the custom
  12163. * selector has been applied.
  12164. *
  12165. * @type object
  12166. */
  12167. selector: {
  12168. cell: [],
  12169. column: [],
  12170. row: []
  12171. },
  12172. /**
  12173. * Internal functions, exposed for used in plug-ins.
  12174. *
  12175. * Please note that you should not need to use the internal methods for
  12176. * anything other than a plug-in (and even then, try to avoid if possible).
  12177. * The internal function may change between releases.
  12178. *
  12179. * @type object
  12180. * @default {}
  12181. */
  12182. internal: {},
  12183. /**
  12184. * Legacy configuration options. Enable and disable legacy options that
  12185. * are available in DataTables.
  12186. *
  12187. * @type object
  12188. */
  12189. legacy: {
  12190. /**
  12191. * Enable / disable DataTables 1.9 compatible server-side processing
  12192. * requests
  12193. *
  12194. * @type boolean
  12195. * @default null
  12196. */
  12197. ajax: null
  12198. },
  12199. /**
  12200. * Pagination plug-in methods.
  12201. *
  12202. * Each entry in this object is a function and defines which buttons should
  12203. * be shown by the pagination rendering method that is used for the table:
  12204. * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
  12205. * buttons are displayed in the document, while the functions here tell it
  12206. * what buttons to display. This is done by returning an array of button
  12207. * descriptions (what each button will do).
  12208. *
  12209. * Pagination types (the four built in options and any additional plug-in
  12210. * options defined here) can be used through the `paginationType`
  12211. * initialisation parameter.
  12212. *
  12213. * The functions defined take two parameters:
  12214. *
  12215. * 1. `{int} page` The current page index
  12216. * 2. `{int} pages` The number of pages in the table
  12217. *
  12218. * Each function is expected to return an array where each element of the
  12219. * array can be one of:
  12220. *
  12221. * * `first` - Jump to first page when activated
  12222. * * `last` - Jump to last page when activated
  12223. * * `previous` - Show previous page when activated
  12224. * * `next` - Show next page when activated
  12225. * * `{int}` - Show page of the index given
  12226. * * `{array}` - A nested array containing the above elements to add a
  12227. * containing 'DIV' element (might be useful for styling).
  12228. *
  12229. * Note that DataTables v1.9- used this object slightly differently whereby
  12230. * an object with two functions would be defined for each plug-in. That
  12231. * ability is still supported by DataTables 1.10+ to provide backwards
  12232. * compatibility, but this option of use is now decremented and no longer
  12233. * documented in DataTables 1.10+.
  12234. *
  12235. * @type object
  12236. * @default {}
  12237. *
  12238. * @example
  12239. * // Show previous, next and current page buttons only
  12240. * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
  12241. * return [ 'previous', page, 'next' ];
  12242. * };
  12243. */
  12244. pager: {},
  12245. renderer: {
  12246. pageButton: {},
  12247. header: {}
  12248. },
  12249. /**
  12250. * Ordering plug-ins - custom data source
  12251. *
  12252. * The extension options for ordering of data available here is complimentary
  12253. * to the default type based ordering that DataTables typically uses. It
  12254. * allows much greater control over the the data that is being used to
  12255. * order a column, but is necessarily therefore more complex.
  12256. *
  12257. * This type of ordering is useful if you want to do ordering based on data
  12258. * live from the DOM (for example the contents of an 'input' element) rather
  12259. * than just the static string that DataTables knows of.
  12260. *
  12261. * The way these plug-ins work is that you create an array of the values you
  12262. * wish to be ordering for the column in question and then return that
  12263. * array. The data in the array much be in the index order of the rows in
  12264. * the table (not the currently ordering order!). Which order data gathering
  12265. * function is run here depends on the `dt-init columns.orderDataType`
  12266. * parameter that is used for the column (if any).
  12267. *
  12268. * The functions defined take two parameters:
  12269. *
  12270. * 1. `{object}` DataTables settings object: see
  12271. * {@link DataTable.models.oSettings}
  12272. * 2. `{int}` Target column index
  12273. *
  12274. * Each function is expected to return an array:
  12275. *
  12276. * * `{array}` Data for the column to be ordering upon
  12277. *
  12278. * @type array
  12279. *
  12280. * @example
  12281. * // Ordering using `input` node values
  12282. * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
  12283. * {
  12284. * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
  12285. * return $('input', td).val();
  12286. * } );
  12287. * }
  12288. */
  12289. order: {},
  12290. /**
  12291. * Type based plug-ins.
  12292. *
  12293. * Each column in DataTables has a type assigned to it, either by automatic
  12294. * detection or by direct assignment using the `type` option for the column.
  12295. * The type of a column will effect how it is ordering and search (plug-ins
  12296. * can also make use of the column type if required).
  12297. *
  12298. * @namespace
  12299. */
  12300. type: {
  12301. /**
  12302. * Type detection functions.
  12303. *
  12304. * The functions defined in this object are used to automatically detect
  12305. * a column's type, making initialisation of DataTables super easy, even
  12306. * when complex data is in the table.
  12307. *
  12308. * The functions defined take two parameters:
  12309. *
  12310. * 1. `{*}` Data from the column cell to be analysed
  12311. * 2. `{settings}` DataTables settings object. This can be used to
  12312. * perform context specific type detection - for example detection
  12313. * based on language settings such as using a comma for a decimal
  12314. * place. Generally speaking the options from the settings will not
  12315. * be required
  12316. *
  12317. * Each function is expected to return:
  12318. *
  12319. * * `{string|null}` Data type detected, or null if unknown (and thus
  12320. * pass it on to the other type detection functions.
  12321. *
  12322. * @type array
  12323. *
  12324. * @example
  12325. * // Currency type detection plug-in:
  12326. * $.fn.dataTable.ext.type.detect.push(
  12327. * function ( data, settings ) {
  12328. * // Check the numeric part
  12329. * if ( ! $.isNumeric( data.substring(1) ) ) {
  12330. * return null;
  12331. * }
  12332. *
  12333. * // Check prefixed by currency
  12334. * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
  12335. * return 'currency';
  12336. * }
  12337. * return null;
  12338. * }
  12339. * );
  12340. */
  12341. detect: [],
  12342. /**
  12343. * Type based search formatting.
  12344. *
  12345. * The type based searching functions can be used to pre-format the
  12346. * data to be search on. For example, it can be used to strip HTML
  12347. * tags or to de-format telephone numbers for numeric only searching.
  12348. *
  12349. * Note that is a search is not defined for a column of a given type,
  12350. * no search formatting will be performed.
  12351. *
  12352. * Pre-processing of searching data plug-ins - When you assign the sType
  12353. * for a column (or have it automatically detected for you by DataTables
  12354. * or a type detection plug-in), you will typically be using this for
  12355. * custom sorting, but it can also be used to provide custom searching
  12356. * by allowing you to pre-processing the data and returning the data in
  12357. * the format that should be searched upon. This is done by adding
  12358. * functions this object with a parameter name which matches the sType
  12359. * for that target column. This is the corollary of <i>afnSortData</i>
  12360. * for searching data.
  12361. *
  12362. * The functions defined take a single parameter:
  12363. *
  12364. * 1. `{*}` Data from the column cell to be prepared for searching
  12365. *
  12366. * Each function is expected to return:
  12367. *
  12368. * * `{string|null}` Formatted string that will be used for the searching.
  12369. *
  12370. * @type object
  12371. * @default {}
  12372. *
  12373. * @example
  12374. * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
  12375. * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
  12376. * }
  12377. */
  12378. search: {},
  12379. /**
  12380. * Type based ordering.
  12381. *
  12382. * The column type tells DataTables what ordering to apply to the table
  12383. * when a column is sorted upon. The order for each type that is defined,
  12384. * is defined by the functions available in this object.
  12385. *
  12386. * Each ordering option can be described by three properties added to
  12387. * this object:
  12388. *
  12389. * * `{type}-pre` - Pre-formatting function
  12390. * * `{type}-asc` - Ascending order function
  12391. * * `{type}-desc` - Descending order function
  12392. *
  12393. * All three can be used together, only `{type}-pre` or only
  12394. * `{type}-asc` and `{type}-desc` together. It is generally recommended
  12395. * that only `{type}-pre` is used, as this provides the optimal
  12396. * implementation in terms of speed, although the others are provided
  12397. * for compatibility with existing Javascript sort functions.
  12398. *
  12399. * `{type}-pre`: Functions defined take a single parameter:
  12400. *
  12401. * 1. `{*}` Data from the column cell to be prepared for ordering
  12402. *
  12403. * And return:
  12404. *
  12405. * * `{*}` Data to be sorted upon
  12406. *
  12407. * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
  12408. * functions, taking two parameters:
  12409. *
  12410. * 1. `{*}` Data to compare to the second parameter
  12411. * 2. `{*}` Data to compare to the first parameter
  12412. *
  12413. * And returning:
  12414. *
  12415. * * `{*}` Ordering match: <0 if first parameter should be sorted lower
  12416. * than the second parameter, ===0 if the two parameters are equal and
  12417. * >0 if the first parameter should be sorted height than the second
  12418. * parameter.
  12419. *
  12420. * @type object
  12421. * @default {}
  12422. *
  12423. * @example
  12424. * // Numeric ordering of formatted numbers with a pre-formatter
  12425. * $.extend( $.fn.dataTable.ext.type.order, {
  12426. * "string-pre": function(x) {
  12427. * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
  12428. * return parseFloat( a );
  12429. * }
  12430. * } );
  12431. *
  12432. * @example
  12433. * // Case-sensitive string ordering, with no pre-formatting method
  12434. * $.extend( $.fn.dataTable.ext.order, {
  12435. * "string-case-asc": function(x,y) {
  12436. * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  12437. * },
  12438. * "string-case-desc": function(x,y) {
  12439. * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  12440. * }
  12441. * } );
  12442. */
  12443. order: {}
  12444. },
  12445. /**
  12446. * Unique DataTables instance counter
  12447. *
  12448. * @type int
  12449. * @private
  12450. */
  12451. _unique: 0,
  12452. //
  12453. // Depreciated
  12454. // The following properties are retained for backwards compatiblity only.
  12455. // The should not be used in new projects and will be removed in a future
  12456. // version
  12457. //
  12458. /**
  12459. * Version check function.
  12460. * @type function
  12461. * @depreciated Since 1.10
  12462. */
  12463. fnVersionCheck: DataTable.fnVersionCheck,
  12464. /**
  12465. * Index for what 'this' index API functions should use
  12466. * @type int
  12467. * @deprecated Since v1.10
  12468. */
  12469. iApiIndex: 0,
  12470. /**
  12471. * jQuery UI class container
  12472. * @type object
  12473. * @deprecated Since v1.10
  12474. */
  12475. oJUIClasses: {},
  12476. /**
  12477. * Software version
  12478. * @type string
  12479. * @deprecated Since v1.10
  12480. */
  12481. sVersion: DataTable.version
  12482. };
  12483. //
  12484. // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
  12485. //
  12486. $.extend( _ext, {
  12487. afnFiltering: _ext.search,
  12488. aTypes: _ext.type.detect,
  12489. ofnSearch: _ext.type.search,
  12490. oSort: _ext.type.order,
  12491. afnSortData: _ext.order,
  12492. aoFeatures: _ext.feature,
  12493. oApi: _ext.internal,
  12494. oStdClasses: _ext.classes,
  12495. oPagination: _ext.pager
  12496. } );
  12497. $.extend( DataTable.ext.classes, {
  12498. "sTable": "dataTable",
  12499. "sNoFooter": "no-footer",
  12500. /* Paging buttons */
  12501. "sPageButton": "paginate_button",
  12502. "sPageButtonActive": "current",
  12503. "sPageButtonDisabled": "disabled",
  12504. /* Striping classes */
  12505. "sStripeOdd": "odd",
  12506. "sStripeEven": "even",
  12507. /* Empty row */
  12508. "sRowEmpty": "dataTables_empty",
  12509. /* Features */
  12510. "sWrapper": "dataTables_wrapper",
  12511. "sFilter": "dataTables_filter",
  12512. "sInfo": "dataTables_info",
  12513. "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
  12514. "sLength": "dataTables_length",
  12515. "sProcessing": "dataTables_processing",
  12516. /* Sorting */
  12517. "sSortAsc": "sorting_asc",
  12518. "sSortDesc": "sorting_desc",
  12519. "sSortable": "sorting", /* Sortable in both directions */
  12520. "sSortableAsc": "sorting_asc_disabled",
  12521. "sSortableDesc": "sorting_desc_disabled",
  12522. "sSortableNone": "sorting_disabled",
  12523. "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
  12524. /* Filtering */
  12525. "sFilterInput": "",
  12526. /* Page length */
  12527. "sLengthSelect": "",
  12528. /* Scrolling */
  12529. "sScrollWrapper": "dataTables_scroll",
  12530. "sScrollHead": "dataTables_scrollHead",
  12531. "sScrollHeadInner": "dataTables_scrollHeadInner",
  12532. "sScrollBody": "dataTables_scrollBody",
  12533. "sScrollFoot": "dataTables_scrollFoot",
  12534. "sScrollFootInner": "dataTables_scrollFootInner",
  12535. /* Misc */
  12536. "sHeaderTH": "",
  12537. "sFooterTH": "",
  12538. // Deprecated
  12539. "sSortJUIAsc": "",
  12540. "sSortJUIDesc": "",
  12541. "sSortJUI": "",
  12542. "sSortJUIAscAllowed": "",
  12543. "sSortJUIDescAllowed": "",
  12544. "sSortJUIWrapper": "",
  12545. "sSortIcon": "",
  12546. "sJUIHeader": "",
  12547. "sJUIFooter": ""
  12548. } );
  12549. var extPagination = DataTable.ext.pager;
  12550. function _numbers ( page, pages ) {
  12551. var
  12552. numbers = [],
  12553. buttons = extPagination.numbers_length,
  12554. half = Math.floor( buttons / 2 ),
  12555. i = 1;
  12556. if ( pages <= buttons ) {
  12557. numbers = _range( 0, pages );
  12558. }
  12559. else if ( page <= half ) {
  12560. numbers = _range( 0, buttons-2 );
  12561. numbers.push( 'ellipsis' );
  12562. numbers.push( pages-1 );
  12563. }
  12564. else if ( page >= pages - 1 - half ) {
  12565. numbers = _range( pages-(buttons-2), pages );
  12566. numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
  12567. numbers.splice( 0, 0, 0 );
  12568. }
  12569. else {
  12570. numbers = _range( page-half+2, page+half-1 );
  12571. numbers.push( 'ellipsis' );
  12572. numbers.push( pages-1 );
  12573. numbers.splice( 0, 0, 'ellipsis' );
  12574. numbers.splice( 0, 0, 0 );
  12575. }
  12576. numbers.DT_el = 'span';
  12577. return numbers;
  12578. }
  12579. $.extend( extPagination, {
  12580. simple: function ( page, pages ) {
  12581. return [ 'previous', 'next' ];
  12582. },
  12583. full: function ( page, pages ) {
  12584. return [ 'first', 'previous', 'next', 'last' ];
  12585. },
  12586. numbers: function ( page, pages ) {
  12587. return [ _numbers(page, pages) ];
  12588. },
  12589. simple_numbers: function ( page, pages ) {
  12590. return [ 'previous', _numbers(page, pages), 'next' ];
  12591. },
  12592. full_numbers: function ( page, pages ) {
  12593. return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
  12594. },
  12595. first_last_numbers: function (page, pages) {
  12596. return ['first', _numbers(page, pages), 'last'];
  12597. },
  12598. // For testing and plug-ins to use
  12599. _numbers: _numbers,
  12600. // Number of number buttons (including ellipsis) to show. _Must be odd!_
  12601. numbers_length: 7
  12602. } );
  12603. $.extend( true, DataTable.ext.renderer, {
  12604. pageButton: {
  12605. _: function ( settings, host, idx, buttons, page, pages ) {
  12606. var classes = settings.oClasses;
  12607. var lang = settings.oLanguage.oPaginate;
  12608. var aria = settings.oLanguage.oAria.paginate || {};
  12609. var btnDisplay, btnClass, counter=0;
  12610. var attach = function( container, buttons ) {
  12611. var i, ien, node, button;
  12612. var clickHandler = function ( e ) {
  12613. _fnPageChange( settings, e.data.action, true );
  12614. };
  12615. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  12616. button = buttons[i];
  12617. if ( $.isArray( button ) ) {
  12618. var inner = $( '<'+(button.DT_el || 'div')+'/>' )
  12619. .appendTo( container );
  12620. attach( inner, button );
  12621. }
  12622. else {
  12623. btnDisplay = null;
  12624. btnClass = '';
  12625. switch ( button ) {
  12626. case 'ellipsis':
  12627. container.append('<span class="ellipsis">&#x2026;</span>');
  12628. break;
  12629. case 'first':
  12630. btnDisplay = lang.sFirst;
  12631. btnClass = button + (page > 0 ?
  12632. '' : ' '+classes.sPageButtonDisabled);
  12633. break;
  12634. case 'previous':
  12635. btnDisplay = lang.sPrevious;
  12636. btnClass = button + (page > 0 ?
  12637. '' : ' '+classes.sPageButtonDisabled);
  12638. break;
  12639. case 'next':
  12640. btnDisplay = lang.sNext;
  12641. btnClass = button + (page < pages-1 ?
  12642. '' : ' '+classes.sPageButtonDisabled);
  12643. break;
  12644. case 'last':
  12645. btnDisplay = lang.sLast;
  12646. btnClass = button + (page < pages-1 ?
  12647. '' : ' '+classes.sPageButtonDisabled);
  12648. break;
  12649. default:
  12650. btnDisplay = button + 1;
  12651. btnClass = page === button ?
  12652. classes.sPageButtonActive : '';
  12653. break;
  12654. }
  12655. if ( btnDisplay !== null ) {
  12656. node = $('<a>', {
  12657. 'class': classes.sPageButton+' '+btnClass,
  12658. 'aria-controls': settings.sTableId,
  12659. 'aria-label': aria[ button ],
  12660. 'data-dt-idx': counter,
  12661. 'tabindex': settings.iTabIndex,
  12662. 'id': idx === 0 && typeof button === 'string' ?
  12663. settings.sTableId +'_'+ button :
  12664. null
  12665. } )
  12666. .html( btnDisplay )
  12667. .appendTo( container );
  12668. _fnBindAction(
  12669. node, {action: button}, clickHandler
  12670. );
  12671. counter++;
  12672. }
  12673. }
  12674. }
  12675. };
  12676. // IE9 throws an 'unknown error' if document.activeElement is used
  12677. // inside an iframe or frame. Try / catch the error. Not good for
  12678. // accessibility, but neither are frames.
  12679. var activeEl;
  12680. try {
  12681. // Because this approach is destroying and recreating the paging
  12682. // elements, focus is lost on the select button which is bad for
  12683. // accessibility. So we want to restore focus once the draw has
  12684. // completed
  12685. activeEl = $(host).find(document.activeElement).data('dt-idx');
  12686. }
  12687. catch (e) {}
  12688. attach( $(host).empty(), buttons );
  12689. if ( activeEl !== undefined ) {
  12690. $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
  12691. }
  12692. }
  12693. }
  12694. } );
  12695. // Built in type detection. See model.ext.aTypes for information about
  12696. // what is required from this methods.
  12697. $.extend( DataTable.ext.type.detect, [
  12698. // Plain numbers - first since V8 detects some plain numbers as dates
  12699. // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
  12700. function ( d, settings )
  12701. {
  12702. var decimal = settings.oLanguage.sDecimal;
  12703. return _isNumber( d, decimal ) ? 'num'+decimal : null;
  12704. },
  12705. // Dates (only those recognised by the browser's Date.parse)
  12706. function ( d, settings )
  12707. {
  12708. // V8 tries _very_ hard to make a string passed into `Date.parse()`
  12709. // valid, so we need to use a regex to restrict date formats. Use a
  12710. // plug-in for anything other than ISO8601 style strings
  12711. if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
  12712. return null;
  12713. }
  12714. var parsed = Date.parse(d);
  12715. return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
  12716. },
  12717. // Formatted numbers
  12718. function ( d, settings )
  12719. {
  12720. var decimal = settings.oLanguage.sDecimal;
  12721. return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
  12722. },
  12723. // HTML numeric
  12724. function ( d, settings )
  12725. {
  12726. var decimal = settings.oLanguage.sDecimal;
  12727. return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
  12728. },
  12729. // HTML numeric, formatted
  12730. function ( d, settings )
  12731. {
  12732. var decimal = settings.oLanguage.sDecimal;
  12733. return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
  12734. },
  12735. // HTML (this is strict checking - there must be html)
  12736. function ( d, settings )
  12737. {
  12738. return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
  12739. 'html' : null;
  12740. }
  12741. ] );
  12742. // Filter formatting functions. See model.ext.ofnSearch for information about
  12743. // what is required from these methods.
  12744. //
  12745. // Note that additional search methods are added for the html numbers and
  12746. // html formatted numbers by `_addNumericSort()` when we know what the decimal
  12747. // place is
  12748. $.extend( DataTable.ext.type.search, {
  12749. html: function ( data ) {
  12750. return _empty(data) ?
  12751. data :
  12752. typeof data === 'string' ?
  12753. data
  12754. .replace( _re_new_lines, " " )
  12755. .replace( _re_html, "" ) :
  12756. '';
  12757. },
  12758. string: function ( data ) {
  12759. return _empty(data) ?
  12760. data :
  12761. typeof data === 'string' ?
  12762. data.replace( _re_new_lines, " " ) :
  12763. data;
  12764. }
  12765. } );
  12766. var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
  12767. if ( d !== 0 && (!d || d === '-') ) {
  12768. return -Infinity;
  12769. }
  12770. // If a decimal place other than `.` is used, it needs to be given to the
  12771. // function so we can detect it and replace with a `.` which is the only
  12772. // decimal place Javascript recognises - it is not locale aware.
  12773. if ( decimalPlace ) {
  12774. d = _numToDecimal( d, decimalPlace );
  12775. }
  12776. if ( d.replace ) {
  12777. if ( re1 ) {
  12778. d = d.replace( re1, '' );
  12779. }
  12780. if ( re2 ) {
  12781. d = d.replace( re2, '' );
  12782. }
  12783. }
  12784. return d * 1;
  12785. };
  12786. // Add the numeric 'deformatting' functions for sorting and search. This is done
  12787. // in a function to provide an easy ability for the language options to add
  12788. // additional methods if a non-period decimal place is used.
  12789. function _addNumericSort ( decimalPlace ) {
  12790. $.each(
  12791. {
  12792. // Plain numbers
  12793. "num": function ( d ) {
  12794. return __numericReplace( d, decimalPlace );
  12795. },
  12796. // Formatted numbers
  12797. "num-fmt": function ( d ) {
  12798. return __numericReplace( d, decimalPlace, _re_formatted_numeric );
  12799. },
  12800. // HTML numeric
  12801. "html-num": function ( d ) {
  12802. return __numericReplace( d, decimalPlace, _re_html );
  12803. },
  12804. // HTML numeric, formatted
  12805. "html-num-fmt": function ( d ) {
  12806. return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
  12807. }
  12808. },
  12809. function ( key, fn ) {
  12810. // Add the ordering method
  12811. _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
  12812. // For HTML types add a search formatter that will strip the HTML
  12813. if ( key.match(/^html\-/) ) {
  12814. _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
  12815. }
  12816. }
  12817. );
  12818. }
  12819. // Default sort methods
  12820. $.extend( _ext.type.order, {
  12821. // Dates
  12822. "date-pre": function ( d ) {
  12823. return Date.parse( d ) || -Infinity;
  12824. },
  12825. // html
  12826. "html-pre": function ( a ) {
  12827. return _empty(a) ?
  12828. '' :
  12829. a.replace ?
  12830. a.replace( /<.*?>/g, "" ).toLowerCase() :
  12831. a+'';
  12832. },
  12833. // string
  12834. "string-pre": function ( a ) {
  12835. // This is a little complex, but faster than always calling toString,
  12836. // http://jsperf.com/tostring-v-check
  12837. return _empty(a) ?
  12838. '' :
  12839. typeof a === 'string' ?
  12840. a.toLowerCase() :
  12841. ! a.toString ?
  12842. '' :
  12843. a.toString();
  12844. },
  12845. // string-asc and -desc are retained only for compatibility with the old
  12846. // sort methods
  12847. "string-asc": function ( x, y ) {
  12848. return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  12849. },
  12850. "string-desc": function ( x, y ) {
  12851. return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  12852. }
  12853. } );
  12854. // Numeric sorting types - order doesn't matter here
  12855. _addNumericSort( '' );
  12856. $.extend( true, DataTable.ext.renderer, {
  12857. header: {
  12858. _: function ( settings, cell, column, classes ) {
  12859. // No additional mark-up required
  12860. // Attach a sort listener to update on sort - note that using the
  12861. // `DT` namespace will allow the event to be removed automatically
  12862. // on destroy, while the `dt` namespaced event is the one we are
  12863. // listening for
  12864. $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
  12865. if ( settings !== ctx ) { // need to check this this is the host
  12866. return; // table, not a nested one
  12867. }
  12868. var colIdx = column.idx;
  12869. cell
  12870. .removeClass(
  12871. column.sSortingClass +' '+
  12872. classes.sSortAsc +' '+
  12873. classes.sSortDesc
  12874. )
  12875. .addClass( columns[ colIdx ] == 'asc' ?
  12876. classes.sSortAsc : columns[ colIdx ] == 'desc' ?
  12877. classes.sSortDesc :
  12878. column.sSortingClass
  12879. );
  12880. } );
  12881. },
  12882. jqueryui: function ( settings, cell, column, classes ) {
  12883. $('<div/>')
  12884. .addClass( classes.sSortJUIWrapper )
  12885. .append( cell.contents() )
  12886. .append( $('<span/>')
  12887. .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
  12888. )
  12889. .appendTo( cell );
  12890. // Attach a sort listener to update on sort
  12891. $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
  12892. if ( settings !== ctx ) {
  12893. return;
  12894. }
  12895. var colIdx = column.idx;
  12896. cell
  12897. .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
  12898. .addClass( columns[ colIdx ] == 'asc' ?
  12899. classes.sSortAsc : columns[ colIdx ] == 'desc' ?
  12900. classes.sSortDesc :
  12901. column.sSortingClass
  12902. );
  12903. cell
  12904. .find( 'span.'+classes.sSortIcon )
  12905. .removeClass(
  12906. classes.sSortJUIAsc +" "+
  12907. classes.sSortJUIDesc +" "+
  12908. classes.sSortJUI +" "+
  12909. classes.sSortJUIAscAllowed +" "+
  12910. classes.sSortJUIDescAllowed
  12911. )
  12912. .addClass( columns[ colIdx ] == 'asc' ?
  12913. classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
  12914. classes.sSortJUIDesc :
  12915. column.sSortingClassJUI
  12916. );
  12917. } );
  12918. }
  12919. }
  12920. } );
  12921. /*
  12922. * Public helper functions. These aren't used internally by DataTables, or
  12923. * called by any of the options passed into DataTables, but they can be used
  12924. * externally by developers working with DataTables. They are helper functions
  12925. * to make working with DataTables a little bit easier.
  12926. */
  12927. var __htmlEscapeEntities = function ( d ) {
  12928. return typeof d === 'string' ?
  12929. d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
  12930. d;
  12931. };
  12932. /**
  12933. * Helpers for `columns.render`.
  12934. *
  12935. * The options defined here can be used with the `columns.render` initialisation
  12936. * option to provide a display renderer. The following functions are defined:
  12937. *
  12938. * * `number` - Will format numeric data (defined by `columns.data`) for
  12939. * display, retaining the original unformatted data for sorting and filtering.
  12940. * It takes 5 parameters:
  12941. * * `string` - Thousands grouping separator
  12942. * * `string` - Decimal point indicator
  12943. * * `integer` - Number of decimal points to show
  12944. * * `string` (optional) - Prefix.
  12945. * * `string` (optional) - Postfix (/suffix).
  12946. * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
  12947. * parameters.
  12948. *
  12949. * @example
  12950. * // Column definition using the number renderer
  12951. * {
  12952. * data: "salary",
  12953. * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
  12954. * }
  12955. *
  12956. * @namespace
  12957. */
  12958. DataTable.render = {
  12959. number: function ( thousands, decimal, precision, prefix, postfix ) {
  12960. return {
  12961. display: function ( d ) {
  12962. if ( typeof d !== 'number' && typeof d !== 'string' ) {
  12963. return d;
  12964. }
  12965. var negative = d < 0 ? '-' : '';
  12966. var flo = parseFloat( d );
  12967. // If NaN then there isn't much formatting that we can do - just
  12968. // return immediately, escaping any HTML (this was supposed to
  12969. // be a number after all)
  12970. if ( isNaN( flo ) ) {
  12971. return __htmlEscapeEntities( d );
  12972. }
  12973. flo = flo.toFixed( precision );
  12974. d = Math.abs( flo );
  12975. var intPart = parseInt( d, 10 );
  12976. var floatPart = precision ?
  12977. decimal+(d - intPart).toFixed( precision ).substring( 2 ):
  12978. '';
  12979. return negative + (prefix||'') +
  12980. intPart.toString().replace(
  12981. /\B(?=(\d{3})+(?!\d))/g, thousands
  12982. ) +
  12983. floatPart +
  12984. (postfix||'');
  12985. }
  12986. };
  12987. },
  12988. text: function () {
  12989. return {
  12990. display: __htmlEscapeEntities
  12991. };
  12992. }
  12993. };
  12994. /*
  12995. * This is really a good bit rubbish this method of exposing the internal methods
  12996. * publicly... - To be fixed in 2.0 using methods on the prototype
  12997. */
  12998. /**
  12999. * Create a wrapper function for exporting an internal functions to an external API.
  13000. * @param {string} fn API function name
  13001. * @returns {function} wrapped function
  13002. * @memberof DataTable#internal
  13003. */
  13004. function _fnExternApiFunc (fn)
  13005. {
  13006. return function() {
  13007. var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
  13008. Array.prototype.slice.call(arguments)
  13009. );
  13010. return DataTable.ext.internal[fn].apply( this, args );
  13011. };
  13012. }
  13013. /**
  13014. * Reference to internal functions for use by plug-in developers. Note that
  13015. * these methods are references to internal functions and are considered to be
  13016. * private. If you use these methods, be aware that they are liable to change
  13017. * between versions.
  13018. * @namespace
  13019. */
  13020. $.extend( DataTable.ext.internal, {
  13021. _fnExternApiFunc: _fnExternApiFunc,
  13022. _fnBuildAjax: _fnBuildAjax,
  13023. _fnAjaxUpdate: _fnAjaxUpdate,
  13024. _fnAjaxParameters: _fnAjaxParameters,
  13025. _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
  13026. _fnAjaxDataSrc: _fnAjaxDataSrc,
  13027. _fnAddColumn: _fnAddColumn,
  13028. _fnColumnOptions: _fnColumnOptions,
  13029. _fnAdjustColumnSizing: _fnAdjustColumnSizing,
  13030. _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
  13031. _fnColumnIndexToVisible: _fnColumnIndexToVisible,
  13032. _fnVisbleColumns: _fnVisbleColumns,
  13033. _fnGetColumns: _fnGetColumns,
  13034. _fnColumnTypes: _fnColumnTypes,
  13035. _fnApplyColumnDefs: _fnApplyColumnDefs,
  13036. _fnHungarianMap: _fnHungarianMap,
  13037. _fnCamelToHungarian: _fnCamelToHungarian,
  13038. _fnLanguageCompat: _fnLanguageCompat,
  13039. _fnBrowserDetect: _fnBrowserDetect,
  13040. _fnAddData: _fnAddData,
  13041. _fnAddTr: _fnAddTr,
  13042. _fnNodeToDataIndex: _fnNodeToDataIndex,
  13043. _fnNodeToColumnIndex: _fnNodeToColumnIndex,
  13044. _fnGetCellData: _fnGetCellData,
  13045. _fnSetCellData: _fnSetCellData,
  13046. _fnSplitObjNotation: _fnSplitObjNotation,
  13047. _fnGetObjectDataFn: _fnGetObjectDataFn,
  13048. _fnSetObjectDataFn: _fnSetObjectDataFn,
  13049. _fnGetDataMaster: _fnGetDataMaster,
  13050. _fnClearTable: _fnClearTable,
  13051. _fnDeleteIndex: _fnDeleteIndex,
  13052. _fnInvalidate: _fnInvalidate,
  13053. _fnGetRowElements: _fnGetRowElements,
  13054. _fnCreateTr: _fnCreateTr,
  13055. _fnBuildHead: _fnBuildHead,
  13056. _fnDrawHead: _fnDrawHead,
  13057. _fnDraw: _fnDraw,
  13058. _fnReDraw: _fnReDraw,
  13059. _fnAddOptionsHtml: _fnAddOptionsHtml,
  13060. _fnDetectHeader: _fnDetectHeader,
  13061. _fnGetUniqueThs: _fnGetUniqueThs,
  13062. _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
  13063. _fnFilterComplete: _fnFilterComplete,
  13064. _fnFilterCustom: _fnFilterCustom,
  13065. _fnFilterColumn: _fnFilterColumn,
  13066. _fnFilter: _fnFilter,
  13067. _fnFilterCreateSearch: _fnFilterCreateSearch,
  13068. _fnEscapeRegex: _fnEscapeRegex,
  13069. _fnFilterData: _fnFilterData,
  13070. _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
  13071. _fnUpdateInfo: _fnUpdateInfo,
  13072. _fnInfoMacros: _fnInfoMacros,
  13073. _fnInitialise: _fnInitialise,
  13074. _fnInitComplete: _fnInitComplete,
  13075. _fnLengthChange: _fnLengthChange,
  13076. _fnFeatureHtmlLength: _fnFeatureHtmlLength,
  13077. _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
  13078. _fnPageChange: _fnPageChange,
  13079. _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
  13080. _fnProcessingDisplay: _fnProcessingDisplay,
  13081. _fnFeatureHtmlTable: _fnFeatureHtmlTable,
  13082. _fnScrollDraw: _fnScrollDraw,
  13083. _fnApplyToChildren: _fnApplyToChildren,
  13084. _fnCalculateColumnWidths: _fnCalculateColumnWidths,
  13085. _fnThrottle: _fnThrottle,
  13086. _fnConvertToWidth: _fnConvertToWidth,
  13087. _fnGetWidestNode: _fnGetWidestNode,
  13088. _fnGetMaxLenString: _fnGetMaxLenString,
  13089. _fnStringToCss: _fnStringToCss,
  13090. _fnSortFlatten: _fnSortFlatten,
  13091. _fnSort: _fnSort,
  13092. _fnSortAria: _fnSortAria,
  13093. _fnSortListener: _fnSortListener,
  13094. _fnSortAttachListener: _fnSortAttachListener,
  13095. _fnSortingClasses: _fnSortingClasses,
  13096. _fnSortData: _fnSortData,
  13097. _fnSaveState: _fnSaveState,
  13098. _fnLoadState: _fnLoadState,
  13099. _fnSettingsFromNode: _fnSettingsFromNode,
  13100. _fnLog: _fnLog,
  13101. _fnMap: _fnMap,
  13102. _fnBindAction: _fnBindAction,
  13103. _fnCallbackReg: _fnCallbackReg,
  13104. _fnCallbackFire: _fnCallbackFire,
  13105. _fnLengthOverflow: _fnLengthOverflow,
  13106. _fnRenderer: _fnRenderer,
  13107. _fnDataSource: _fnDataSource,
  13108. _fnRowAttributes: _fnRowAttributes,
  13109. _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
  13110. // in 1.10, so this dead-end function is
  13111. // added to prevent errors
  13112. } );
  13113. // jQuery access
  13114. $.fn.dataTable = DataTable;
  13115. // Provide access to the host jQuery object (circular reference)
  13116. DataTable.$ = $;
  13117. // Legacy aliases
  13118. $.fn.dataTableSettings = DataTable.settings;
  13119. $.fn.dataTableExt = DataTable.ext;
  13120. // With a capital `D` we return a DataTables API instance rather than a
  13121. // jQuery object
  13122. $.fn.DataTable = function ( opts ) {
  13123. return $(this).dataTable( opts ).api();
  13124. };
  13125. // All properties that are available to $.fn.dataTable should also be
  13126. // available on $.fn.DataTable
  13127. $.each( DataTable, function ( prop, val ) {
  13128. $.fn.DataTable[ prop ] = val;
  13129. } );
  13130. // Information about events fired by DataTables - for documentation.
  13131. /**
  13132. * Draw event, fired whenever the table is redrawn on the page, at the same
  13133. * point as fnDrawCallback. This may be useful for binding events or
  13134. * performing calculations when the table is altered at all.
  13135. * @name DataTable#draw.dt
  13136. * @event
  13137. * @param {event} e jQuery event object
  13138. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13139. */
  13140. /**
  13141. * Search event, fired when the searching applied to the table (using the
  13142. * built-in global search, or column filters) is altered.
  13143. * @name DataTable#search.dt
  13144. * @event
  13145. * @param {event} e jQuery event object
  13146. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13147. */
  13148. /**
  13149. * Page change event, fired when the paging of the table is altered.
  13150. * @name DataTable#page.dt
  13151. * @event
  13152. * @param {event} e jQuery event object
  13153. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13154. */
  13155. /**
  13156. * Order event, fired when the ordering applied to the table is altered.
  13157. * @name DataTable#order.dt
  13158. * @event
  13159. * @param {event} e jQuery event object
  13160. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13161. */
  13162. /**
  13163. * DataTables initialisation complete event, fired when the table is fully
  13164. * drawn, including Ajax data loaded, if Ajax data is required.
  13165. * @name DataTable#init.dt
  13166. * @event
  13167. * @param {event} e jQuery event object
  13168. * @param {object} oSettings DataTables settings object
  13169. * @param {object} json The JSON object request from the server - only
  13170. * present if client-side Ajax sourced data is used</li></ol>
  13171. */
  13172. /**
  13173. * State save event, fired when the table has changed state a new state save
  13174. * is required. This event allows modification of the state saving object
  13175. * prior to actually doing the save, including addition or other state
  13176. * properties (for plug-ins) or modification of a DataTables core property.
  13177. * @name DataTable#stateSaveParams.dt
  13178. * @event
  13179. * @param {event} e jQuery event object
  13180. * @param {object} oSettings DataTables settings object
  13181. * @param {object} json The state information to be saved
  13182. */
  13183. /**
  13184. * State load event, fired when the table is loading state from the stored
  13185. * data, but prior to the settings object being modified by the saved state
  13186. * - allowing modification of the saved state is required or loading of
  13187. * state for a plug-in.
  13188. * @name DataTable#stateLoadParams.dt
  13189. * @event
  13190. * @param {event} e jQuery event object
  13191. * @param {object} oSettings DataTables settings object
  13192. * @param {object} json The saved state information
  13193. */
  13194. /**
  13195. * State loaded event, fired when state has been loaded from stored data and
  13196. * the settings object has been modified by the loaded data.
  13197. * @name DataTable#stateLoaded.dt
  13198. * @event
  13199. * @param {event} e jQuery event object
  13200. * @param {object} oSettings DataTables settings object
  13201. * @param {object} json The saved state information
  13202. */
  13203. /**
  13204. * Processing event, fired when DataTables is doing some kind of processing
  13205. * (be it, order, searcg or anything else). It can be used to indicate to
  13206. * the end user that there is something happening, or that something has
  13207. * finished.
  13208. * @name DataTable#processing.dt
  13209. * @event
  13210. * @param {event} e jQuery event object
  13211. * @param {object} oSettings DataTables settings object
  13212. * @param {boolean} bShow Flag for if DataTables is doing processing or not
  13213. */
  13214. /**
  13215. * Ajax (XHR) event, fired whenever an Ajax request is completed from a
  13216. * request to made to the server for new data. This event is called before
  13217. * DataTables processed the returned data, so it can also be used to pre-
  13218. * process the data returned from the server, if needed.
  13219. *
  13220. * Note that this trigger is called in `fnServerData`, if you override
  13221. * `fnServerData` and which to use this event, you need to trigger it in you
  13222. * success function.
  13223. * @name DataTable#xhr.dt
  13224. * @event
  13225. * @param {event} e jQuery event object
  13226. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13227. * @param {object} json JSON returned from the server
  13228. *
  13229. * @example
  13230. * // Use a custom property returned from the server in another DOM element
  13231. * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
  13232. * $('#status').html( json.status );
  13233. * } );
  13234. *
  13235. * @example
  13236. * // Pre-process the data returned from the server
  13237. * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
  13238. * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
  13239. * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
  13240. * }
  13241. * // Note no return - manipulate the data directly in the JSON object.
  13242. * } );
  13243. */
  13244. /**
  13245. * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
  13246. * or passing the bDestroy:true parameter in the initialisation object. This
  13247. * can be used to remove bound events, added DOM nodes, etc.
  13248. * @name DataTable#destroy.dt
  13249. * @event
  13250. * @param {event} e jQuery event object
  13251. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13252. */
  13253. /**
  13254. * Page length change event, fired when number of records to show on each
  13255. * page (the length) is changed.
  13256. * @name DataTable#length.dt
  13257. * @event
  13258. * @param {event} e jQuery event object
  13259. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13260. * @param {integer} len New length
  13261. */
  13262. /**
  13263. * Column sizing has changed.
  13264. * @name DataTable#column-sizing.dt
  13265. * @event
  13266. * @param {event} e jQuery event object
  13267. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13268. */
  13269. /**
  13270. * Column visibility has changed.
  13271. * @name DataTable#column-visibility.dt
  13272. * @event
  13273. * @param {event} e jQuery event object
  13274. * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
  13275. * @param {int} column Column index
  13276. * @param {bool} vis `false` if column now hidden, or `true` if visible
  13277. */
  13278. return $.fn.dataTable;
  13279. }));
  13280. /*! AutoFill 2.2.2
  13281. * ©2008-2017 SpryMedia Ltd - datatables.net/license
  13282. */
  13283. /**
  13284. * @summary AutoFill
  13285. * @description Add Excel like click and drag auto-fill options to DataTables
  13286. * @version 2.2.2
  13287. * @file dataTables.autoFill.js
  13288. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  13289. * @contact www.sprymedia.co.uk/contact
  13290. * @copyright Copyright 2010-2017 SpryMedia Ltd.
  13291. *
  13292. * This source file is free software, available under the following license:
  13293. * MIT license - http://datatables.net/license/mit
  13294. *
  13295. * This source file is distributed in the hope that it will be useful, but
  13296. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13297. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  13298. *
  13299. * For details please refer to: http://www.datatables.net
  13300. */
  13301. (function( factory ){
  13302. if ( typeof define === 'function' && define.amd ) {
  13303. // AMD
  13304. define( ['jquery', 'datatables.net'], function ( $ ) {
  13305. return factory( $, window, document );
  13306. } );
  13307. }
  13308. else if ( typeof exports === 'object' ) {
  13309. // CommonJS
  13310. module.exports = function (root, $) {
  13311. if ( ! root ) {
  13312. root = window;
  13313. }
  13314. if ( ! $ || ! $.fn.dataTable ) {
  13315. $ = require('datatables.net')(root, $).$;
  13316. }
  13317. return factory( $, root, root.document );
  13318. };
  13319. }
  13320. else {
  13321. // Browser
  13322. factory( jQuery, window, document );
  13323. }
  13324. }(function( $, window, document, undefined ) {
  13325. 'use strict';
  13326. var DataTable = $.fn.dataTable;
  13327. var _instance = 0;
  13328. /**
  13329. * AutoFill provides Excel like auto-fill features for a DataTable
  13330. *
  13331. * @class AutoFill
  13332. * @constructor
  13333. * @param {object} oTD DataTables settings object
  13334. * @param {object} oConfig Configuration object for AutoFill
  13335. */
  13336. var AutoFill = function( dt, opts )
  13337. {
  13338. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
  13339. throw( "Warning: AutoFill requires DataTables 1.10.8 or greater");
  13340. }
  13341. // User and defaults configuration object
  13342. this.c = $.extend( true, {},
  13343. DataTable.defaults.autoFill,
  13344. AutoFill.defaults,
  13345. opts
  13346. );
  13347. /**
  13348. * @namespace Settings object which contains customisable information for AutoFill instance
  13349. */
  13350. this.s = {
  13351. /** @type {DataTable.Api} DataTables' API instance */
  13352. dt: new DataTable.Api( dt ),
  13353. /** @type {String} Unique namespace for events attached to the document */
  13354. namespace: '.autoFill'+(_instance++),
  13355. /** @type {Object} Cached dimension information for use in the mouse move event handler */
  13356. scroll: {},
  13357. /** @type {integer} Interval object used for smooth scrolling */
  13358. scrollInterval: null,
  13359. handle: {
  13360. height: 0,
  13361. width: 0
  13362. },
  13363. /**
  13364. * Enabled setting
  13365. * @type {Boolean}
  13366. */
  13367. enabled: false
  13368. };
  13369. /**
  13370. * @namespace Common and useful DOM elements for the class instance
  13371. */
  13372. this.dom = {
  13373. /** @type {jQuery} AutoFill handle */
  13374. handle: $('<div class="dt-autofill-handle"/>'),
  13375. /**
  13376. * @type {Object} Selected cells outline - Need to use 4 elements,
  13377. * otherwise the mouse over if you back into the selected rectangle
  13378. * will be over that element, rather than the cells!
  13379. */
  13380. select: {
  13381. top: $('<div class="dt-autofill-select top"/>'),
  13382. right: $('<div class="dt-autofill-select right"/>'),
  13383. bottom: $('<div class="dt-autofill-select bottom"/>'),
  13384. left: $('<div class="dt-autofill-select left"/>')
  13385. },
  13386. /** @type {jQuery} Fill type chooser background */
  13387. background: $('<div class="dt-autofill-background"/>'),
  13388. /** @type {jQuery} Fill type chooser */
  13389. list: $('<div class="dt-autofill-list">'+this.s.dt.i18n('autoFill.info', '')+'<ul/></div>'),
  13390. /** @type {jQuery} DataTables scrolling container */
  13391. dtScroll: null,
  13392. /** @type {jQuery} Offset parent element */
  13393. offsetParent: null
  13394. };
  13395. /* Constructor logic */
  13396. this._constructor();
  13397. };
  13398. $.extend( AutoFill.prototype, {
  13399. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13400. * Public methods (exposed via the DataTables API below)
  13401. */
  13402. enabled: function ()
  13403. {
  13404. return this.s.enabled;
  13405. },
  13406. enable: function ( flag )
  13407. {
  13408. var that = this;
  13409. if ( flag === false ) {
  13410. return this.disable();
  13411. }
  13412. this.s.enabled = true;
  13413. this._focusListener();
  13414. this.dom.handle.on( 'mousedown', function (e) {
  13415. that._mousedown( e );
  13416. return false;
  13417. } );
  13418. return this;
  13419. },
  13420. disable: function ()
  13421. {
  13422. this.s.enabled = false;
  13423. this._focusListenerRemove();
  13424. return this;
  13425. },
  13426. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13427. * Constructor
  13428. */
  13429. /**
  13430. * Initialise the RowReorder instance
  13431. *
  13432. * @private
  13433. */
  13434. _constructor: function ()
  13435. {
  13436. var that = this;
  13437. var dt = this.s.dt;
  13438. var dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container());
  13439. // Make the instance accessible to the API
  13440. dt.settings()[0].autoFill = this;
  13441. if ( dtScroll.length ) {
  13442. this.dom.dtScroll = dtScroll;
  13443. // Need to scroll container to be the offset parent
  13444. if ( dtScroll.css('position') === 'static' ) {
  13445. dtScroll.css( 'position', 'relative' );
  13446. }
  13447. }
  13448. if ( this.c.enable !== false ) {
  13449. this.enable();
  13450. }
  13451. dt.on( 'destroy.autoFill', function () {
  13452. that._focusListenerRemove();
  13453. } );
  13454. },
  13455. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13456. * Private methods
  13457. */
  13458. /**
  13459. * Display the AutoFill drag handle by appending it to a table cell. This
  13460. * is the opposite of the _detach method.
  13461. *
  13462. * @param {node} node TD/TH cell to insert the handle into
  13463. * @private
  13464. */
  13465. _attach: function ( node )
  13466. {
  13467. var dt = this.s.dt;
  13468. var idx = dt.cell( node ).index();
  13469. var handle = this.dom.handle;
  13470. var handleDim = this.s.handle;
  13471. if ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {
  13472. this._detach();
  13473. return;
  13474. }
  13475. if ( ! this.dom.offsetParent ) {
  13476. // We attach to the table's offset parent
  13477. this.dom.offsetParent = $( dt.table().node() ).offsetParent();
  13478. }
  13479. if ( ! handleDim.height || ! handleDim.width ) {
  13480. // Append to document so we can get its size. Not expecting it to
  13481. // change during the life time of the page
  13482. handle.appendTo( 'body' );
  13483. handleDim.height = handle.outerHeight();
  13484. handleDim.width = handle.outerWidth();
  13485. }
  13486. // Might need to go through multiple offset parents
  13487. var offset = this._getPosition( node, this.dom.offsetParent );
  13488. this.dom.attachedTo = node;
  13489. handle
  13490. .css( {
  13491. top: offset.top + node.offsetHeight - handleDim.height,
  13492. left: offset.left + node.offsetWidth - handleDim.width
  13493. } )
  13494. .appendTo( this.dom.offsetParent );
  13495. },
  13496. /**
  13497. * Determine can the fill type should be. This can be automatic, or ask the
  13498. * end user.
  13499. *
  13500. * @param {array} cells Information about the selected cells from the key
  13501. * up function
  13502. * @private
  13503. */
  13504. _actionSelector: function ( cells )
  13505. {
  13506. var that = this;
  13507. var dt = this.s.dt;
  13508. var actions = AutoFill.actions;
  13509. var available = [];
  13510. // "Ask" each plug-in if it wants to handle this data
  13511. $.each( actions, function ( key, action ) {
  13512. if ( action.available( dt, cells ) ) {
  13513. available.push( key );
  13514. }
  13515. } );
  13516. if ( available.length === 1 && this.c.alwaysAsk === false ) {
  13517. // Only one action available - enact it immediately
  13518. var result = actions[ available[0] ].execute( dt, cells );
  13519. this._update( result, cells );
  13520. }
  13521. else {
  13522. // Multiple actions available - ask the end user what they want to do
  13523. var list = this.dom.list.children('ul').empty();
  13524. // Add a cancel option
  13525. available.push( 'cancel' );
  13526. $.each( available, function ( i, name ) {
  13527. list.append( $('<li/>')
  13528. .append(
  13529. '<div class="dt-autofill-question">'+
  13530. actions[ name ].option( dt, cells )+
  13531. '<div>'
  13532. )
  13533. .append( $('<div class="dt-autofill-button">' )
  13534. .append( $('<button class="'+AutoFill.classes.btn+'">'+dt.i18n('autoFill.button', '&gt;')+'</button>')
  13535. .on( 'click', function () {
  13536. var result = actions[ name ].execute(
  13537. dt, cells, $(this).closest('li')
  13538. );
  13539. that._update( result, cells );
  13540. that.dom.background.remove();
  13541. that.dom.list.remove();
  13542. } )
  13543. )
  13544. )
  13545. );
  13546. } );
  13547. this.dom.background.appendTo( 'body' );
  13548. this.dom.list.appendTo( 'body' );
  13549. this.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );
  13550. }
  13551. },
  13552. /**
  13553. * Remove the AutoFill handle from the document
  13554. *
  13555. * @private
  13556. */
  13557. _detach: function ()
  13558. {
  13559. this.dom.attachedTo = null;
  13560. this.dom.handle.detach();
  13561. },
  13562. /**
  13563. * Draw the selection outline by calculating the range between the start
  13564. * and end cells, then placing the highlighting elements to draw a rectangle
  13565. *
  13566. * @param {node} target End cell
  13567. * @param {object} e Originating event
  13568. * @private
  13569. */
  13570. _drawSelection: function ( target, e )
  13571. {
  13572. // Calculate boundary for start cell to this one
  13573. var dt = this.s.dt;
  13574. var start = this.s.start;
  13575. var startCell = $(this.dom.start);
  13576. var endCell = $(target);
  13577. var end = {
  13578. row: dt.rows( { page: 'current' } ).nodes().indexOf( endCell.parent()[0] ),
  13579. column: endCell.index()
  13580. };
  13581. var colIndx = dt.column.index( 'toData', end.column );
  13582. // Be sure that is a DataTables controlled cell
  13583. if ( ! dt.cell( endCell ).any() ) {
  13584. return;
  13585. }
  13586. // if target is not in the columns available - do nothing
  13587. if ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 ) {
  13588. return;
  13589. }
  13590. this.s.end = end;
  13591. var top, bottom, left, right, height, width;
  13592. top = start.row < end.row ? startCell : endCell;
  13593. bottom = start.row < end.row ? endCell : startCell;
  13594. left = start.column < end.column ? startCell : endCell;
  13595. right = start.column < end.column ? endCell : startCell;
  13596. top = this._getPosition( top ).top;
  13597. left = this._getPosition( left ).left;
  13598. height = this._getPosition( bottom ).top + bottom.outerHeight() - top;
  13599. width = this._getPosition( right ).left + right.outerWidth() - left;
  13600. var select = this.dom.select;
  13601. select.top.css( {
  13602. top: top,
  13603. left: left,
  13604. width: width
  13605. } );
  13606. select.left.css( {
  13607. top: top,
  13608. left: left,
  13609. height: height
  13610. } );
  13611. select.bottom.css( {
  13612. top: top + height,
  13613. left: left,
  13614. width: width
  13615. } );
  13616. select.right.css( {
  13617. top: top,
  13618. left: left + width,
  13619. height: height
  13620. } );
  13621. },
  13622. /**
  13623. * Use the Editor API to perform an update based on the new data for the
  13624. * cells
  13625. *
  13626. * @param {array} cells Information about the selected cells from the key
  13627. * up function
  13628. * @private
  13629. */
  13630. _editor: function ( cells )
  13631. {
  13632. var dt = this.s.dt;
  13633. var editor = this.c.editor;
  13634. if ( ! editor ) {
  13635. return;
  13636. }
  13637. // Build the object structure for Editor's multi-row editing
  13638. var idValues = {};
  13639. var nodes = [];
  13640. var fields = editor.fields();
  13641. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  13642. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  13643. var cell = cells[i][j];
  13644. // Determine the field name for the cell being edited
  13645. var col = dt.settings()[0].aoColumns[ cell.index.column ];
  13646. var fieldName = col.editField;
  13647. if ( fieldName === undefined ) {
  13648. var dataSrc = col.mData;
  13649. // dataSrc is the `field.data` property, but we need to set
  13650. // using the field name, so we need to translate from the
  13651. // data to the name
  13652. for ( var k=0, ken=fields.length ; k<ken ; k++ ) {
  13653. var field = editor.field( fields[k] );
  13654. if ( field.dataSrc() === dataSrc ) {
  13655. fieldName = field.name();
  13656. break;
  13657. }
  13658. }
  13659. }
  13660. if ( ! fieldName ) {
  13661. throw 'Could not automatically determine field data. '+
  13662. 'Please see https://datatables.net/tn/11';
  13663. }
  13664. if ( ! idValues[ fieldName ] ) {
  13665. idValues[ fieldName ] = {};
  13666. }
  13667. var id = dt.row( cell.index.row ).id();
  13668. idValues[ fieldName ][ id ] = cell.set;
  13669. // Keep a list of cells so we can activate the bubble editing
  13670. // with them
  13671. nodes.push( cell.index );
  13672. }
  13673. }
  13674. // Perform the edit using bubble editing as it allows us to specify
  13675. // the cells to be edited, rather than using full rows
  13676. editor
  13677. .bubble( nodes, false )
  13678. .multiSet( idValues )
  13679. .submit();
  13680. },
  13681. /**
  13682. * Emit an event on the DataTable for listeners
  13683. *
  13684. * @param {string} name Event name
  13685. * @param {array} args Event arguments
  13686. * @private
  13687. */
  13688. _emitEvent: function ( name, args )
  13689. {
  13690. this.s.dt.iterator( 'table', function ( ctx, i ) {
  13691. $(ctx.nTable).triggerHandler( name+'.dt', args );
  13692. } );
  13693. },
  13694. /**
  13695. * Attach suitable listeners (based on the configuration) that will attach
  13696. * and detach the AutoFill handle in the document.
  13697. *
  13698. * @private
  13699. */
  13700. _focusListener: function ()
  13701. {
  13702. var that = this;
  13703. var dt = this.s.dt;
  13704. var namespace = this.s.namespace;
  13705. var focus = this.c.focus !== null ?
  13706. this.c.focus :
  13707. dt.init().keys || dt.settings()[0].keytable ?
  13708. 'focus' :
  13709. 'hover';
  13710. // All event listeners attached here are removed in the `destroy`
  13711. // callback in the constructor
  13712. if ( focus === 'focus' ) {
  13713. dt
  13714. .on( 'key-focus.autoFill', function ( e, dt, cell ) {
  13715. that._attach( cell.node() );
  13716. } )
  13717. .on( 'key-blur.autoFill', function ( e, dt, cell ) {
  13718. that._detach();
  13719. } );
  13720. }
  13721. else if ( focus === 'click' ) {
  13722. $(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {
  13723. that._attach( this );
  13724. } );
  13725. $(document.body).on( 'click'+namespace, function (e) {
  13726. if ( ! $(e.target).parents().filter( dt.table().body() ).length ) {
  13727. that._detach();
  13728. }
  13729. } );
  13730. }
  13731. else {
  13732. $(dt.table().body())
  13733. .on( 'mouseenter'+namespace, 'td, th', function (e) {
  13734. that._attach( this );
  13735. } )
  13736. .on( 'mouseleave'+namespace, function (e) {
  13737. if ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {
  13738. return;
  13739. }
  13740. that._detach();
  13741. } );
  13742. }
  13743. },
  13744. _focusListenerRemove: function ()
  13745. {
  13746. var dt = this.s.dt;
  13747. dt.off( '.autoFill' );
  13748. $(dt.table().body()).off( this.s.namespace );
  13749. $(document.body).off( this.s.namespace );
  13750. },
  13751. /**
  13752. * Get the position of a node, relative to another, including any scrolling
  13753. * offsets.
  13754. * @param {Node} node Node to get the position of
  13755. * @param {jQuery} targetParent Node to use as the parent
  13756. * @return {object} Offset calculation
  13757. * @private
  13758. */
  13759. _getPosition: function ( node, targetParent )
  13760. {
  13761. var
  13762. currNode = $(node),
  13763. currOffsetParent,
  13764. position,
  13765. top = 0,
  13766. left = 0;
  13767. if ( ! targetParent ) {
  13768. targetParent = $( this.s.dt.table().node() ).offsetParent();
  13769. }
  13770. do {
  13771. position = currNode.position();
  13772. currOffsetParent = currNode.offsetParent();
  13773. top += position.top + currOffsetParent.scrollTop();
  13774. left += position.left + currOffsetParent.scrollLeft();
  13775. // Emergency fall back. Shouldn't happen, but just in case!
  13776. if ( currNode.get(0).nodeName.toLowerCase() === 'body' ) {
  13777. break;
  13778. }
  13779. currNode = currOffsetParent; // for next loop
  13780. }
  13781. while ( currOffsetParent.get(0) !== targetParent.get(0) )
  13782. return {
  13783. top: top,
  13784. left: left
  13785. };
  13786. },
  13787. /**
  13788. * Start mouse drag - selects the start cell
  13789. *
  13790. * @param {object} e Mouse down event
  13791. * @private
  13792. */
  13793. _mousedown: function ( e )
  13794. {
  13795. var that = this;
  13796. var dt = this.s.dt;
  13797. this.dom.start = this.dom.attachedTo;
  13798. this.s.start = {
  13799. row: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),
  13800. column: $(this.dom.start).index()
  13801. };
  13802. $(document.body)
  13803. .on( 'mousemove.autoFill', function (e) {
  13804. that._mousemove( e );
  13805. } )
  13806. .on( 'mouseup.autoFill', function (e) {
  13807. that._mouseup( e );
  13808. } );
  13809. var select = this.dom.select;
  13810. var offsetParent = $( dt.table().node() ).offsetParent();
  13811. select.top.appendTo( offsetParent );
  13812. select.left.appendTo( offsetParent );
  13813. select.right.appendTo( offsetParent );
  13814. select.bottom.appendTo( offsetParent );
  13815. this._drawSelection( this.dom.start, e );
  13816. this.dom.handle.css( 'display', 'none' );
  13817. // Cache scrolling information so mouse move doesn't need to read.
  13818. // This assumes that the window and DT scroller will not change size
  13819. // during an AutoFill drag, which I think is a fair assumption
  13820. var scrollWrapper = this.dom.dtScroll;
  13821. this.s.scroll = {
  13822. windowHeight: $(window).height(),
  13823. windowWidth: $(window).width(),
  13824. dtTop: scrollWrapper ? scrollWrapper.offset().top : null,
  13825. dtLeft: scrollWrapper ? scrollWrapper.offset().left : null,
  13826. dtHeight: scrollWrapper ? scrollWrapper.outerHeight() : null,
  13827. dtWidth: scrollWrapper ? scrollWrapper.outerWidth() : null
  13828. };
  13829. },
  13830. /**
  13831. * Mouse drag - selects the end cell and update the selection display for
  13832. * the end user
  13833. *
  13834. * @param {object} e Mouse move event
  13835. * @private
  13836. */
  13837. _mousemove: function ( e )
  13838. {
  13839. var that = this;
  13840. var dt = this.s.dt;
  13841. var name = e.target.nodeName.toLowerCase();
  13842. if ( name !== 'td' && name !== 'th' ) {
  13843. return;
  13844. }
  13845. this._drawSelection( e.target, e );
  13846. this._shiftScroll( e );
  13847. },
  13848. /**
  13849. * End mouse drag - perform the update actions
  13850. *
  13851. * @param {object} e Mouse up event
  13852. * @private
  13853. */
  13854. _mouseup: function ( e )
  13855. {
  13856. $(document.body).off( '.autoFill' );
  13857. var dt = this.s.dt;
  13858. var select = this.dom.select;
  13859. select.top.remove();
  13860. select.left.remove();
  13861. select.right.remove();
  13862. select.bottom.remove();
  13863. this.dom.handle.css( 'display', 'block' );
  13864. // Display complete - now do something useful with the selection!
  13865. var start = this.s.start;
  13866. var end = this.s.end;
  13867. // Haven't selected multiple cells, so nothing to do
  13868. if ( start.row === end.row && start.column === end.column ) {
  13869. return;
  13870. }
  13871. // Build a matrix representation of the selected rows
  13872. var rows = this._range( start.row, end.row );
  13873. var columns = this._range( start.column, end.column );
  13874. var selected = [];
  13875. var dtSettings = dt.settings()[0];
  13876. var dtColumns = dtSettings.aoColumns;
  13877. // Can't use Array.prototype.map as IE8 doesn't support it
  13878. // Can't use $.map as jQuery flattens 2D arrays
  13879. // Need to use a good old fashioned for loop
  13880. for ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {
  13881. selected.push(
  13882. $.map( columns, function (column) {
  13883. var cell = dt.cell( ':eq('+rows[rowIdx]+')', column+':visible', {page:'current'} );
  13884. var data = cell.data();
  13885. var cellIndex = cell.index();
  13886. var editField = dtColumns[ cellIndex.column ].editField;
  13887. if ( editField !== undefined ) {
  13888. data = dtSettings.oApi._fnGetObjectDataFn( editField )( dt.row( cellIndex.row ).data() );
  13889. }
  13890. return {
  13891. cell: cell,
  13892. data: data,
  13893. label: cell.data(),
  13894. index: cellIndex
  13895. };
  13896. } )
  13897. );
  13898. }
  13899. this._actionSelector( selected );
  13900. // Stop shiftScroll
  13901. clearInterval( this.s.scrollInterval );
  13902. this.s.scrollInterval = null;
  13903. },
  13904. /**
  13905. * Create an array with a range of numbers defined by the start and end
  13906. * parameters passed in (inclusive!).
  13907. *
  13908. * @param {integer} start Start
  13909. * @param {integer} end End
  13910. * @private
  13911. */
  13912. _range: function ( start, end )
  13913. {
  13914. var out = [];
  13915. var i;
  13916. if ( start <= end ) {
  13917. for ( i=start ; i<=end ; i++ ) {
  13918. out.push( i );
  13919. }
  13920. }
  13921. else {
  13922. for ( i=start ; i>=end ; i-- ) {
  13923. out.push( i );
  13924. }
  13925. }
  13926. return out;
  13927. },
  13928. /**
  13929. * Move the window and DataTables scrolling during a drag to scroll new
  13930. * content into view. This is done by proximity to the edge of the scrolling
  13931. * container of the mouse - for example near the top edge of the window
  13932. * should scroll up. This is a little complicated as there are two elements
  13933. * that can be scrolled - the window and the DataTables scrolling view port
  13934. * (if scrollX and / or scrollY is enabled).
  13935. *
  13936. * @param {object} e Mouse move event object
  13937. * @private
  13938. */
  13939. _shiftScroll: function ( e )
  13940. {
  13941. var that = this;
  13942. var dt = this.s.dt;
  13943. var scroll = this.s.scroll;
  13944. var runInterval = false;
  13945. var scrollSpeed = 5;
  13946. var buffer = 65;
  13947. var
  13948. windowY = e.pageY - document.body.scrollTop,
  13949. windowX = e.pageX - document.body.scrollLeft,
  13950. windowVert, windowHoriz,
  13951. dtVert, dtHoriz;
  13952. // Window calculations - based on the mouse position in the window,
  13953. // regardless of scrolling
  13954. if ( windowY < buffer ) {
  13955. windowVert = scrollSpeed * -1;
  13956. }
  13957. else if ( windowY > scroll.windowHeight - buffer ) {
  13958. windowVert = scrollSpeed;
  13959. }
  13960. if ( windowX < buffer ) {
  13961. windowHoriz = scrollSpeed * -1;
  13962. }
  13963. else if ( windowX > scroll.windowWidth - buffer ) {
  13964. windowHoriz = scrollSpeed;
  13965. }
  13966. // DataTables scrolling calculations - based on the table's position in
  13967. // the document and the mouse position on the page
  13968. if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {
  13969. dtVert = scrollSpeed * -1;
  13970. }
  13971. else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
  13972. dtVert = scrollSpeed;
  13973. }
  13974. if ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) {
  13975. dtHoriz = scrollSpeed * -1;
  13976. }
  13977. else if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {
  13978. dtHoriz = scrollSpeed;
  13979. }
  13980. // This is where it gets interesting. We want to continue scrolling
  13981. // without requiring a mouse move, so we need an interval to be
  13982. // triggered. The interval should continue until it is no longer needed,
  13983. // but it must also use the latest scroll commands (for example consider
  13984. // that the mouse might move from scrolling up to scrolling left, all
  13985. // with the same interval running. We use the `scroll` object to "pass"
  13986. // this information to the interval. Can't use local variables as they
  13987. // wouldn't be the ones that are used by an already existing interval!
  13988. if ( windowVert || windowHoriz || dtVert || dtHoriz ) {
  13989. scroll.windowVert = windowVert;
  13990. scroll.windowHoriz = windowHoriz;
  13991. scroll.dtVert = dtVert;
  13992. scroll.dtHoriz = dtHoriz;
  13993. runInterval = true;
  13994. }
  13995. else if ( this.s.scrollInterval ) {
  13996. // Don't need to scroll - remove any existing timer
  13997. clearInterval( this.s.scrollInterval );
  13998. this.s.scrollInterval = null;
  13999. }
  14000. // If we need to run the interval to scroll and there is no existing
  14001. // interval (if there is an existing one, it will continue to run)
  14002. if ( ! this.s.scrollInterval && runInterval ) {
  14003. this.s.scrollInterval = setInterval( function () {
  14004. // Don't need to worry about setting scroll <0 or beyond the
  14005. // scroll bound as the browser will just reject that.
  14006. if ( scroll.windowVert ) {
  14007. document.body.scrollTop += scroll.windowVert;
  14008. }
  14009. if ( scroll.windowHoriz ) {
  14010. document.body.scrollLeft += scroll.windowHoriz;
  14011. }
  14012. // DataTables scrolling
  14013. if ( scroll.dtVert || scroll.dtHoriz ) {
  14014. var scroller = that.dom.dtScroll[0];
  14015. if ( scroll.dtVert ) {
  14016. scroller.scrollTop += scroll.dtVert;
  14017. }
  14018. if ( scroll.dtHoriz ) {
  14019. scroller.scrollLeft += scroll.dtHoriz;
  14020. }
  14021. }
  14022. }, 20 );
  14023. }
  14024. },
  14025. /**
  14026. * Update the DataTable after the user has selected what they want to do
  14027. *
  14028. * @param {false|undefined} result Return from the `execute` method - can
  14029. * be false internally to do nothing. This is not documented for plug-ins
  14030. * and is used only by the cancel option.
  14031. * @param {array} cells Information about the selected cells from the key
  14032. * up function, argumented with the set values
  14033. * @private
  14034. */
  14035. _update: function ( result, cells )
  14036. {
  14037. // Do nothing on `false` return from an execute function
  14038. if ( result === false ) {
  14039. return;
  14040. }
  14041. var dt = this.s.dt;
  14042. var cell;
  14043. // Potentially allow modifications to the cells matrix
  14044. this._emitEvent( 'preAutoFill', [ dt, cells ] );
  14045. this._editor( cells );
  14046. // Automatic updates are not performed if `update` is null and the
  14047. // `editor` parameter is passed in - the reason being that Editor will
  14048. // update the data once submitted
  14049. var update = this.c.update !== null ?
  14050. this.c.update :
  14051. this.c.editor ?
  14052. false :
  14053. true;
  14054. if ( update ) {
  14055. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14056. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14057. cell = cells[i][j];
  14058. cell.cell.data( cell.set );
  14059. }
  14060. }
  14061. dt.draw(false);
  14062. }
  14063. this._emitEvent( 'autoFill', [ dt, cells ] );
  14064. }
  14065. } );
  14066. /**
  14067. * AutoFill actions. The options here determine how AutoFill will fill the data
  14068. * in the table when the user has selected a range of cells. Please see the
  14069. * documentation on the DataTables site for full details on how to create plug-
  14070. * ins.
  14071. *
  14072. * @type {Object}
  14073. */
  14074. AutoFill.actions = {
  14075. increment: {
  14076. available: function ( dt, cells ) {
  14077. return $.isNumeric( cells[0][0].label );
  14078. },
  14079. option: function ( dt, cells ) {
  14080. return dt.i18n(
  14081. 'autoFill.increment',
  14082. 'Increment / decrement each cell by: <input type="number" value="1">'
  14083. );
  14084. },
  14085. execute: function ( dt, cells, node ) {
  14086. var value = cells[0][0].data * 1;
  14087. var increment = $('input', node).val() * 1;
  14088. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14089. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14090. cells[i][j].set = value;
  14091. value += increment;
  14092. }
  14093. }
  14094. }
  14095. },
  14096. fill: {
  14097. available: function ( dt, cells ) {
  14098. return true;
  14099. },
  14100. option: function ( dt, cells ) {
  14101. return dt.i18n('autoFill.fill', 'Fill all cells with <i>'+cells[0][0].label+'</i>' );
  14102. },
  14103. execute: function ( dt, cells, node ) {
  14104. var value = cells[0][0].data;
  14105. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14106. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14107. cells[i][j].set = value;
  14108. }
  14109. }
  14110. }
  14111. },
  14112. fillHorizontal: {
  14113. available: function ( dt, cells ) {
  14114. return cells.length > 1 && cells[0].length > 1;
  14115. },
  14116. option: function ( dt, cells ) {
  14117. return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );
  14118. },
  14119. execute: function ( dt, cells, node ) {
  14120. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14121. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14122. cells[i][j].set = cells[i][0].data;
  14123. }
  14124. }
  14125. }
  14126. },
  14127. fillVertical: {
  14128. available: function ( dt, cells ) {
  14129. return cells.length > 1 && cells[0].length > 1;
  14130. },
  14131. option: function ( dt, cells ) {
  14132. return dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );
  14133. },
  14134. execute: function ( dt, cells, node ) {
  14135. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  14136. for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
  14137. cells[i][j].set = cells[0][j].data;
  14138. }
  14139. }
  14140. }
  14141. },
  14142. // Special type that does not make itself available, but is added
  14143. // automatically by AutoFill if a multi-choice list is shown. This allows
  14144. // sensible code reuse
  14145. cancel: {
  14146. available: function () {
  14147. return false;
  14148. },
  14149. option: function ( dt ) {
  14150. return dt.i18n('autoFill.cancel', 'Cancel' );
  14151. },
  14152. execute: function () {
  14153. return false;
  14154. }
  14155. }
  14156. };
  14157. /**
  14158. * AutoFill version
  14159. *
  14160. * @static
  14161. * @type String
  14162. */
  14163. AutoFill.version = '2.2.2';
  14164. /**
  14165. * AutoFill defaults
  14166. *
  14167. * @namespace
  14168. */
  14169. AutoFill.defaults = {
  14170. /** @type {Boolean} Ask user what they want to do, even for a single option */
  14171. alwaysAsk: false,
  14172. /** @type {string|null} What will trigger a focus */
  14173. focus: null, // focus, click, hover
  14174. /** @type {column-selector} Columns to provide auto fill for */
  14175. columns: '', // all
  14176. /** @type {Boolean} Enable AutoFill on load */
  14177. enable: true,
  14178. /** @type {boolean|null} Update the cells after a drag */
  14179. update: null, // false is editor given, true otherwise
  14180. /** @type {DataTable.Editor} Editor instance for automatic submission */
  14181. editor: null
  14182. };
  14183. /**
  14184. * Classes used by AutoFill that are configurable
  14185. *
  14186. * @namespace
  14187. */
  14188. AutoFill.classes = {
  14189. /** @type {String} Class used by the selection button */
  14190. btn: 'btn'
  14191. };
  14192. /*
  14193. * API
  14194. */
  14195. var Api = $.fn.dataTable.Api;
  14196. // Doesn't do anything - Not documented
  14197. Api.register( 'autoFill()', function () {
  14198. return this;
  14199. } );
  14200. Api.register( 'autoFill().enabled()', function () {
  14201. var ctx = this.context[0];
  14202. return ctx.autoFill ?
  14203. ctx.autoFill.enabled() :
  14204. false;
  14205. } );
  14206. Api.register( 'autoFill().enable()', function ( flag ) {
  14207. return this.iterator( 'table', function ( ctx ) {
  14208. if ( ctx.autoFill ) {
  14209. ctx.autoFill.enable( flag );
  14210. }
  14211. } );
  14212. } );
  14213. Api.register( 'autoFill().disable()', function () {
  14214. return this.iterator( 'table', function ( ctx ) {
  14215. if ( ctx.autoFill ) {
  14216. ctx.autoFill.disable();
  14217. }
  14218. } );
  14219. } );
  14220. // Attach a listener to the document which listens for DataTables initialisation
  14221. // events so we can automatically initialise
  14222. $(document).on( 'preInit.dt.autofill', function (e, settings, json) {
  14223. if ( e.namespace !== 'dt' ) {
  14224. return;
  14225. }
  14226. var init = settings.oInit.autoFill;
  14227. var defaults = DataTable.defaults.autoFill;
  14228. if ( init || defaults ) {
  14229. var opts = $.extend( {}, init, defaults );
  14230. if ( init !== false ) {
  14231. new AutoFill( settings, opts );
  14232. }
  14233. }
  14234. } );
  14235. // Alias for access
  14236. DataTable.AutoFill = AutoFill;
  14237. DataTable.AutoFill = AutoFill;
  14238. return AutoFill;
  14239. }));
  14240. /*! Buttons for DataTables 1.5.1
  14241. * ©2016-2017 SpryMedia Ltd - datatables.net/license
  14242. */
  14243. (function( factory ){
  14244. if ( typeof define === 'function' && define.amd ) {
  14245. // AMD
  14246. define( ['jquery', 'datatables.net'], function ( $ ) {
  14247. return factory( $, window, document );
  14248. } );
  14249. }
  14250. else if ( typeof exports === 'object' ) {
  14251. // CommonJS
  14252. module.exports = function (root, $) {
  14253. if ( ! root ) {
  14254. root = window;
  14255. }
  14256. if ( ! $ || ! $.fn.dataTable ) {
  14257. $ = require('datatables.net')(root, $).$;
  14258. }
  14259. return factory( $, root, root.document );
  14260. };
  14261. }
  14262. else {
  14263. // Browser
  14264. factory( jQuery, window, document );
  14265. }
  14266. }(function( $, window, document, undefined ) {
  14267. 'use strict';
  14268. var DataTable = $.fn.dataTable;
  14269. // Used for namespacing events added to the document by each instance, so they
  14270. // can be removed on destroy
  14271. var _instCounter = 0;
  14272. // Button namespacing counter for namespacing events on individual buttons
  14273. var _buttonCounter = 0;
  14274. var _dtButtons = DataTable.ext.buttons;
  14275. /**
  14276. * [Buttons description]
  14277. * @param {[type]}
  14278. * @param {[type]}
  14279. */
  14280. var Buttons = function( dt, config )
  14281. {
  14282. // If there is no config set it to an empty object
  14283. if ( typeof( config ) === 'undefined' ) {
  14284. config = {};
  14285. }
  14286. // Allow a boolean true for defaults
  14287. if ( config === true ) {
  14288. config = {};
  14289. }
  14290. // For easy configuration of buttons an array can be given
  14291. if ( $.isArray( config ) ) {
  14292. config = { buttons: config };
  14293. }
  14294. this.c = $.extend( true, {}, Buttons.defaults, config );
  14295. // Don't want a deep copy for the buttons
  14296. if ( config.buttons ) {
  14297. this.c.buttons = config.buttons;
  14298. }
  14299. this.s = {
  14300. dt: new DataTable.Api( dt ),
  14301. buttons: [],
  14302. listenKeys: '',
  14303. namespace: 'dtb'+(_instCounter++)
  14304. };
  14305. this.dom = {
  14306. container: $('<'+this.c.dom.container.tag+'/>')
  14307. .addClass( this.c.dom.container.className )
  14308. };
  14309. this._constructor();
  14310. };
  14311. $.extend( Buttons.prototype, {
  14312. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14313. * Public methods
  14314. */
  14315. /**
  14316. * Get the action of a button
  14317. * @param {int|string} Button index
  14318. * @return {function}
  14319. *//**
  14320. * Set the action of a button
  14321. * @param {node} node Button element
  14322. * @param {function} action Function to set
  14323. * @return {Buttons} Self for chaining
  14324. */
  14325. action: function ( node, action )
  14326. {
  14327. var button = this._nodeToButton( node );
  14328. if ( action === undefined ) {
  14329. return button.conf.action;
  14330. }
  14331. button.conf.action = action;
  14332. return this;
  14333. },
  14334. /**
  14335. * Add an active class to the button to make to look active or get current
  14336. * active state.
  14337. * @param {node} node Button element
  14338. * @param {boolean} [flag] Enable / disable flag
  14339. * @return {Buttons} Self for chaining or boolean for getter
  14340. */
  14341. active: function ( node, flag ) {
  14342. var button = this._nodeToButton( node );
  14343. var klass = this.c.dom.button.active;
  14344. var jqNode = $(button.node);
  14345. if ( flag === undefined ) {
  14346. return jqNode.hasClass( klass );
  14347. }
  14348. jqNode.toggleClass( klass, flag === undefined ? true : flag );
  14349. return this;
  14350. },
  14351. /**
  14352. * Add a new button
  14353. * @param {object} config Button configuration object, base string name or function
  14354. * @param {int|string} [idx] Button index for where to insert the button
  14355. * @return {Buttons} Self for chaining
  14356. */
  14357. add: function ( config, idx )
  14358. {
  14359. var buttons = this.s.buttons;
  14360. if ( typeof idx === 'string' ) {
  14361. var split = idx.split('-');
  14362. var base = this.s;
  14363. for ( var i=0, ien=split.length-1 ; i<ien ; i++ ) {
  14364. base = base.buttons[ split[i]*1 ];
  14365. }
  14366. buttons = base.buttons;
  14367. idx = split[ split.length-1 ]*1;
  14368. }
  14369. this._expandButton( buttons, config, false, idx );
  14370. this._draw();
  14371. return this;
  14372. },
  14373. /**
  14374. * Get the container node for the buttons
  14375. * @return {jQuery} Buttons node
  14376. */
  14377. container: function ()
  14378. {
  14379. return this.dom.container;
  14380. },
  14381. /**
  14382. * Disable a button
  14383. * @param {node} node Button node
  14384. * @return {Buttons} Self for chaining
  14385. */
  14386. disable: function ( node ) {
  14387. var button = this._nodeToButton( node );
  14388. $(button.node).addClass( this.c.dom.button.disabled );
  14389. return this;
  14390. },
  14391. /**
  14392. * Destroy the instance, cleaning up event handlers and removing DOM
  14393. * elements
  14394. * @return {Buttons} Self for chaining
  14395. */
  14396. destroy: function ()
  14397. {
  14398. // Key event listener
  14399. $('body').off( 'keyup.'+this.s.namespace );
  14400. // Individual button destroy (so they can remove their own events if
  14401. // needed). Take a copy as the array is modified by `remove`
  14402. var buttons = this.s.buttons.slice();
  14403. var i, ien;
  14404. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  14405. this.remove( buttons[i].node );
  14406. }
  14407. // Container
  14408. this.dom.container.remove();
  14409. // Remove from the settings object collection
  14410. var buttonInsts = this.s.dt.settings()[0];
  14411. for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {
  14412. if ( buttonInsts.inst === this ) {
  14413. buttonInsts.splice( i, 1 );
  14414. break;
  14415. }
  14416. }
  14417. return this;
  14418. },
  14419. /**
  14420. * Enable / disable a button
  14421. * @param {node} node Button node
  14422. * @param {boolean} [flag=true] Enable / disable flag
  14423. * @return {Buttons} Self for chaining
  14424. */
  14425. enable: function ( node, flag )
  14426. {
  14427. if ( flag === false ) {
  14428. return this.disable( node );
  14429. }
  14430. var button = this._nodeToButton( node );
  14431. $(button.node).removeClass( this.c.dom.button.disabled );
  14432. return this;
  14433. },
  14434. /**
  14435. * Get the instance name for the button set selector
  14436. * @return {string} Instance name
  14437. */
  14438. name: function ()
  14439. {
  14440. return this.c.name;
  14441. },
  14442. /**
  14443. * Get a button's node
  14444. * @param {node} node Button node
  14445. * @return {jQuery} Button element
  14446. */
  14447. node: function ( node )
  14448. {
  14449. var button = this._nodeToButton( node );
  14450. return $(button.node);
  14451. },
  14452. /**
  14453. * Set / get a processing class on the selected button
  14454. * @param {boolean} flag true to add, false to remove, undefined to get
  14455. * @return {boolean|Buttons} Getter value or this if a setter.
  14456. */
  14457. processing: function ( node, flag )
  14458. {
  14459. var button = this._nodeToButton( node );
  14460. if ( flag === undefined ) {
  14461. return $(button.node).hasClass( 'processing' );
  14462. }
  14463. $(button.node).toggleClass( 'processing', flag );
  14464. return this;
  14465. },
  14466. /**
  14467. * Remove a button.
  14468. * @param {node} node Button node
  14469. * @return {Buttons} Self for chaining
  14470. */
  14471. remove: function ( node )
  14472. {
  14473. var button = this._nodeToButton( node );
  14474. var host = this._nodeToHost( node );
  14475. var dt = this.s.dt;
  14476. // Remove any child buttons first
  14477. if ( button.buttons.length ) {
  14478. for ( var i=button.buttons.length-1 ; i>=0 ; i-- ) {
  14479. this.remove( button.buttons[i].node );
  14480. }
  14481. }
  14482. // Allow the button to remove event handlers, etc
  14483. if ( button.conf.destroy ) {
  14484. button.conf.destroy.call( dt.button(node), dt, $(node), button.conf );
  14485. }
  14486. this._removeKey( button.conf );
  14487. $(button.node).remove();
  14488. var idx = $.inArray( button, host );
  14489. host.splice( idx, 1 );
  14490. return this;
  14491. },
  14492. /**
  14493. * Get the text for a button
  14494. * @param {int|string} node Button index
  14495. * @return {string} Button text
  14496. *//**
  14497. * Set the text for a button
  14498. * @param {int|string|function} node Button index
  14499. * @param {string} label Text
  14500. * @return {Buttons} Self for chaining
  14501. */
  14502. text: function ( node, label )
  14503. {
  14504. var button = this._nodeToButton( node );
  14505. var buttonLiner = this.c.dom.collection.buttonLiner;
  14506. var linerTag = button.inCollection && buttonLiner && buttonLiner.tag ?
  14507. buttonLiner.tag :
  14508. this.c.dom.buttonLiner.tag;
  14509. var dt = this.s.dt;
  14510. var jqNode = $(button.node);
  14511. var text = function ( opt ) {
  14512. return typeof opt === 'function' ?
  14513. opt( dt, jqNode, button.conf ) :
  14514. opt;
  14515. };
  14516. if ( label === undefined ) {
  14517. return text( button.conf.text );
  14518. }
  14519. button.conf.text = label;
  14520. if ( linerTag ) {
  14521. jqNode.children( linerTag ).html( text(label) );
  14522. }
  14523. else {
  14524. jqNode.html( text(label) );
  14525. }
  14526. return this;
  14527. },
  14528. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14529. * Constructor
  14530. */
  14531. /**
  14532. * Buttons constructor
  14533. * @private
  14534. */
  14535. _constructor: function ()
  14536. {
  14537. var that = this;
  14538. var dt = this.s.dt;
  14539. var dtSettings = dt.settings()[0];
  14540. var buttons = this.c.buttons;
  14541. if ( ! dtSettings._buttons ) {
  14542. dtSettings._buttons = [];
  14543. }
  14544. dtSettings._buttons.push( {
  14545. inst: this,
  14546. name: this.c.name
  14547. } );
  14548. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14549. this.add( buttons[i] );
  14550. }
  14551. dt.on( 'destroy', function () {
  14552. that.destroy();
  14553. } );
  14554. // Global key event binding to listen for button keys
  14555. $('body').on( 'keyup.'+this.s.namespace, function ( e ) {
  14556. if ( ! document.activeElement || document.activeElement === document.body ) {
  14557. // SUse a string of characters for fast lookup of if we need to
  14558. // handle this
  14559. var character = String.fromCharCode(e.keyCode).toLowerCase();
  14560. if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {
  14561. that._keypress( character, e );
  14562. }
  14563. }
  14564. } );
  14565. },
  14566. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14567. * Private methods
  14568. */
  14569. /**
  14570. * Add a new button to the key press listener
  14571. * @param {object} conf Resolved button configuration object
  14572. * @private
  14573. */
  14574. _addKey: function ( conf )
  14575. {
  14576. if ( conf.key ) {
  14577. this.s.listenKeys += $.isPlainObject( conf.key ) ?
  14578. conf.key.key :
  14579. conf.key;
  14580. }
  14581. },
  14582. /**
  14583. * Insert the buttons into the container. Call without parameters!
  14584. * @param {node} [container] Recursive only - Insert point
  14585. * @param {array} [buttons] Recursive only - Buttons array
  14586. * @private
  14587. */
  14588. _draw: function ( container, buttons )
  14589. {
  14590. if ( ! container ) {
  14591. container = this.dom.container;
  14592. buttons = this.s.buttons;
  14593. }
  14594. container.children().detach();
  14595. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14596. container.append( buttons[i].inserter );
  14597. container.append( ' ' );
  14598. if ( buttons[i].buttons && buttons[i].buttons.length ) {
  14599. this._draw( buttons[i].collection, buttons[i].buttons );
  14600. }
  14601. }
  14602. },
  14603. /**
  14604. * Create buttons from an array of buttons
  14605. * @param {array} attachTo Buttons array to attach to
  14606. * @param {object} button Button definition
  14607. * @param {boolean} inCollection true if the button is in a collection
  14608. * @private
  14609. */
  14610. _expandButton: function ( attachTo, button, inCollection, attachPoint )
  14611. {
  14612. var dt = this.s.dt;
  14613. var buttonCounter = 0;
  14614. var buttons = ! $.isArray( button ) ?
  14615. [ button ] :
  14616. button;
  14617. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14618. var conf = this._resolveExtends( buttons[i] );
  14619. if ( ! conf ) {
  14620. continue;
  14621. }
  14622. // If the configuration is an array, then expand the buttons at this
  14623. // point
  14624. if ( $.isArray( conf ) ) {
  14625. this._expandButton( attachTo, conf, inCollection, attachPoint );
  14626. continue;
  14627. }
  14628. var built = this._buildButton( conf, inCollection );
  14629. if ( ! built ) {
  14630. continue;
  14631. }
  14632. if ( attachPoint !== undefined ) {
  14633. attachTo.splice( attachPoint, 0, built );
  14634. attachPoint++;
  14635. }
  14636. else {
  14637. attachTo.push( built );
  14638. }
  14639. if ( built.conf.buttons ) {
  14640. var collectionDom = this.c.dom.collection;
  14641. built.collection = $('<'+collectionDom.tag+'/>')
  14642. .addClass( collectionDom.className )
  14643. .attr( 'role', 'menu') ;
  14644. built.conf._collection = built.collection;
  14645. this._expandButton( built.buttons, built.conf.buttons, true, attachPoint );
  14646. }
  14647. // init call is made here, rather than buildButton as it needs to
  14648. // be selectable, and for that it needs to be in the buttons array
  14649. if ( conf.init ) {
  14650. conf.init.call( dt.button( built.node ), dt, $(built.node), conf );
  14651. }
  14652. buttonCounter++;
  14653. }
  14654. },
  14655. /**
  14656. * Create an individual button
  14657. * @param {object} config Resolved button configuration
  14658. * @param {boolean} inCollection `true` if a collection button
  14659. * @return {jQuery} Created button node (jQuery)
  14660. * @private
  14661. */
  14662. _buildButton: function ( config, inCollection )
  14663. {
  14664. var buttonDom = this.c.dom.button;
  14665. var linerDom = this.c.dom.buttonLiner;
  14666. var collectionDom = this.c.dom.collection;
  14667. var dt = this.s.dt;
  14668. var text = function ( opt ) {
  14669. return typeof opt === 'function' ?
  14670. opt( dt, button, config ) :
  14671. opt;
  14672. };
  14673. if ( inCollection && collectionDom.button ) {
  14674. buttonDom = collectionDom.button;
  14675. }
  14676. if ( inCollection && collectionDom.buttonLiner ) {
  14677. linerDom = collectionDom.buttonLiner;
  14678. }
  14679. // Make sure that the button is available based on whatever requirements
  14680. // it has. For example, Flash buttons require Flash
  14681. if ( config.available && ! config.available( dt, config ) ) {
  14682. return false;
  14683. }
  14684. var action = function ( e, dt, button, config ) {
  14685. config.action.call( dt.button( button ), e, dt, button, config );
  14686. $(dt.table().node()).triggerHandler( 'buttons-action.dt', [
  14687. dt.button( button ), dt, button, config
  14688. ] );
  14689. };
  14690. var button = $('<'+buttonDom.tag+'/>')
  14691. .addClass( buttonDom.className )
  14692. .attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
  14693. .attr( 'aria-controls', this.s.dt.table().node().id )
  14694. .on( 'click.dtb', function (e) {
  14695. e.preventDefault();
  14696. if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
  14697. action( e, dt, button, config );
  14698. }
  14699. button.blur();
  14700. } )
  14701. .on( 'keyup.dtb', function (e) {
  14702. if ( e.keyCode === 13 ) {
  14703. if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
  14704. action( e, dt, button, config );
  14705. }
  14706. }
  14707. } );
  14708. // Make `a` tags act like a link
  14709. if ( buttonDom.tag.toLowerCase() === 'a' ) {
  14710. button.attr( 'href', '#' );
  14711. }
  14712. if ( linerDom.tag ) {
  14713. var liner = $('<'+linerDom.tag+'/>')
  14714. .html( text( config.text ) )
  14715. .addClass( linerDom.className );
  14716. if ( linerDom.tag.toLowerCase() === 'a' ) {
  14717. liner.attr( 'href', '#' );
  14718. }
  14719. button.append( liner );
  14720. }
  14721. else {
  14722. button.html( text( config.text ) );
  14723. }
  14724. if ( config.enabled === false ) {
  14725. button.addClass( buttonDom.disabled );
  14726. }
  14727. if ( config.className ) {
  14728. button.addClass( config.className );
  14729. }
  14730. if ( config.titleAttr ) {
  14731. button.attr( 'title', text( config.titleAttr ) );
  14732. }
  14733. if ( config.attr ) {
  14734. button.attr( config.attr );
  14735. }
  14736. if ( ! config.namespace ) {
  14737. config.namespace = '.dt-button-'+(_buttonCounter++);
  14738. }
  14739. var buttonContainer = this.c.dom.buttonContainer;
  14740. var inserter;
  14741. if ( buttonContainer && buttonContainer.tag ) {
  14742. inserter = $('<'+buttonContainer.tag+'/>')
  14743. .addClass( buttonContainer.className )
  14744. .append( button );
  14745. }
  14746. else {
  14747. inserter = button;
  14748. }
  14749. this._addKey( config );
  14750. return {
  14751. conf: config,
  14752. node: button.get(0),
  14753. inserter: inserter,
  14754. buttons: [],
  14755. inCollection: inCollection,
  14756. collection: null
  14757. };
  14758. },
  14759. /**
  14760. * Get the button object from a node (recursive)
  14761. * @param {node} node Button node
  14762. * @param {array} [buttons] Button array, uses base if not defined
  14763. * @return {object} Button object
  14764. * @private
  14765. */
  14766. _nodeToButton: function ( node, buttons )
  14767. {
  14768. if ( ! buttons ) {
  14769. buttons = this.s.buttons;
  14770. }
  14771. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14772. if ( buttons[i].node === node ) {
  14773. return buttons[i];
  14774. }
  14775. if ( buttons[i].buttons.length ) {
  14776. var ret = this._nodeToButton( node, buttons[i].buttons );
  14777. if ( ret ) {
  14778. return ret;
  14779. }
  14780. }
  14781. }
  14782. },
  14783. /**
  14784. * Get container array for a button from a button node (recursive)
  14785. * @param {node} node Button node
  14786. * @param {array} [buttons] Button array, uses base if not defined
  14787. * @return {array} Button's host array
  14788. * @private
  14789. */
  14790. _nodeToHost: function ( node, buttons )
  14791. {
  14792. if ( ! buttons ) {
  14793. buttons = this.s.buttons;
  14794. }
  14795. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  14796. if ( buttons[i].node === node ) {
  14797. return buttons;
  14798. }
  14799. if ( buttons[i].buttons.length ) {
  14800. var ret = this._nodeToHost( node, buttons[i].buttons );
  14801. if ( ret ) {
  14802. return ret;
  14803. }
  14804. }
  14805. }
  14806. },
  14807. /**
  14808. * Handle a key press - determine if any button's key configured matches
  14809. * what was typed and trigger the action if so.
  14810. * @param {string} character The character pressed
  14811. * @param {object} e Key event that triggered this call
  14812. * @private
  14813. */
  14814. _keypress: function ( character, e )
  14815. {
  14816. // Check if this button press already activated on another instance of Buttons
  14817. if ( e._buttonsHandled ) {
  14818. return;
  14819. }
  14820. var run = function ( conf, node ) {
  14821. if ( ! conf.key ) {
  14822. return;
  14823. }
  14824. if ( conf.key === character ) {
  14825. e._buttonsHandled = true;
  14826. $(node).click();
  14827. }
  14828. else if ( $.isPlainObject( conf.key ) ) {
  14829. if ( conf.key.key !== character ) {
  14830. return;
  14831. }
  14832. if ( conf.key.shiftKey && ! e.shiftKey ) {
  14833. return;
  14834. }
  14835. if ( conf.key.altKey && ! e.altKey ) {
  14836. return;
  14837. }
  14838. if ( conf.key.ctrlKey && ! e.ctrlKey ) {
  14839. return;
  14840. }
  14841. if ( conf.key.metaKey && ! e.metaKey ) {
  14842. return;
  14843. }
  14844. // Made it this far - it is good
  14845. e._buttonsHandled = true;
  14846. $(node).click();
  14847. }
  14848. };
  14849. var recurse = function ( a ) {
  14850. for ( var i=0, ien=a.length ; i<ien ; i++ ) {
  14851. run( a[i].conf, a[i].node );
  14852. if ( a[i].buttons.length ) {
  14853. recurse( a[i].buttons );
  14854. }
  14855. }
  14856. };
  14857. recurse( this.s.buttons );
  14858. },
  14859. /**
  14860. * Remove a key from the key listener for this instance (to be used when a
  14861. * button is removed)
  14862. * @param {object} conf Button configuration
  14863. * @private
  14864. */
  14865. _removeKey: function ( conf )
  14866. {
  14867. if ( conf.key ) {
  14868. var character = $.isPlainObject( conf.key ) ?
  14869. conf.key.key :
  14870. conf.key;
  14871. // Remove only one character, as multiple buttons could have the
  14872. // same listening key
  14873. var a = this.s.listenKeys.split('');
  14874. var idx = $.inArray( character, a );
  14875. a.splice( idx, 1 );
  14876. this.s.listenKeys = a.join('');
  14877. }
  14878. },
  14879. /**
  14880. * Resolve a button configuration
  14881. * @param {string|function|object} conf Button config to resolve
  14882. * @return {object} Button configuration
  14883. * @private
  14884. */
  14885. _resolveExtends: function ( conf )
  14886. {
  14887. var dt = this.s.dt;
  14888. var i, ien;
  14889. var toConfObject = function ( base ) {
  14890. var loop = 0;
  14891. // Loop until we have resolved to a button configuration, or an
  14892. // array of button configurations (which will be iterated
  14893. // separately)
  14894. while ( ! $.isPlainObject(base) && ! $.isArray(base) ) {
  14895. if ( base === undefined ) {
  14896. return;
  14897. }
  14898. if ( typeof base === 'function' ) {
  14899. base = base( dt, conf );
  14900. if ( ! base ) {
  14901. return false;
  14902. }
  14903. }
  14904. else if ( typeof base === 'string' ) {
  14905. if ( ! _dtButtons[ base ] ) {
  14906. throw 'Unknown button type: '+base;
  14907. }
  14908. base = _dtButtons[ base ];
  14909. }
  14910. loop++;
  14911. if ( loop > 30 ) {
  14912. // Protect against misconfiguration killing the browser
  14913. throw 'Buttons: Too many iterations';
  14914. }
  14915. }
  14916. return $.isArray( base ) ?
  14917. base :
  14918. $.extend( {}, base );
  14919. };
  14920. conf = toConfObject( conf );
  14921. while ( conf && conf.extend ) {
  14922. // Use `toConfObject` in case the button definition being extended
  14923. // is itself a string or a function
  14924. if ( ! _dtButtons[ conf.extend ] ) {
  14925. throw 'Cannot extend unknown button type: '+conf.extend;
  14926. }
  14927. var objArray = toConfObject( _dtButtons[ conf.extend ] );
  14928. if ( $.isArray( objArray ) ) {
  14929. return objArray;
  14930. }
  14931. else if ( ! objArray ) {
  14932. // This is a little brutal as it might be possible to have a
  14933. // valid button without the extend, but if there is no extend
  14934. // then the host button would be acting in an undefined state
  14935. return false;
  14936. }
  14937. // Stash the current class name
  14938. var originalClassName = objArray.className;
  14939. conf = $.extend( {}, objArray, conf );
  14940. // The extend will have overwritten the original class name if the
  14941. // `conf` object also assigned a class, but we want to concatenate
  14942. // them so they are list that is combined from all extended buttons
  14943. if ( originalClassName && conf.className !== originalClassName ) {
  14944. conf.className = originalClassName+' '+conf.className;
  14945. }
  14946. // Buttons to be added to a collection -gives the ability to define
  14947. // if buttons should be added to the start or end of a collection
  14948. var postfixButtons = conf.postfixButtons;
  14949. if ( postfixButtons ) {
  14950. if ( ! conf.buttons ) {
  14951. conf.buttons = [];
  14952. }
  14953. for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {
  14954. conf.buttons.push( postfixButtons[i] );
  14955. }
  14956. conf.postfixButtons = null;
  14957. }
  14958. var prefixButtons = conf.prefixButtons;
  14959. if ( prefixButtons ) {
  14960. if ( ! conf.buttons ) {
  14961. conf.buttons = [];
  14962. }
  14963. for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {
  14964. conf.buttons.splice( i, 0, prefixButtons[i] );
  14965. }
  14966. conf.prefixButtons = null;
  14967. }
  14968. // Although we want the `conf` object to overwrite almost all of
  14969. // the properties of the object being extended, the `extend`
  14970. // property should come from the object being extended
  14971. conf.extend = objArray.extend;
  14972. }
  14973. return conf;
  14974. }
  14975. } );
  14976. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14977. * Statics
  14978. */
  14979. /**
  14980. * Show / hide a background layer behind a collection
  14981. * @param {boolean} Flag to indicate if the background should be shown or
  14982. * hidden
  14983. * @param {string} Class to assign to the background
  14984. * @static
  14985. */
  14986. Buttons.background = function ( show, className, fade ) {
  14987. if ( fade === undefined ) {
  14988. fade = 400;
  14989. }
  14990. if ( show ) {
  14991. $('<div/>')
  14992. .addClass( className )
  14993. .css( 'display', 'none' )
  14994. .appendTo( 'body' )
  14995. .fadeIn( fade );
  14996. }
  14997. else {
  14998. $('body > div.'+className)
  14999. .fadeOut( fade, function () {
  15000. $(this)
  15001. .removeClass( className )
  15002. .remove();
  15003. } );
  15004. }
  15005. };
  15006. /**
  15007. * Instance selector - select Buttons instances based on an instance selector
  15008. * value from the buttons assigned to a DataTable. This is only useful if
  15009. * multiple instances are attached to a DataTable.
  15010. * @param {string|int|array} Instance selector - see `instance-selector`
  15011. * documentation on the DataTables site
  15012. * @param {array} Button instance array that was attached to the DataTables
  15013. * settings object
  15014. * @return {array} Buttons instances
  15015. * @static
  15016. */
  15017. Buttons.instanceSelector = function ( group, buttons )
  15018. {
  15019. if ( ! group ) {
  15020. return $.map( buttons, function ( v ) {
  15021. return v.inst;
  15022. } );
  15023. }
  15024. var ret = [];
  15025. var names = $.map( buttons, function ( v ) {
  15026. return v.name;
  15027. } );
  15028. // Flatten the group selector into an array of single options
  15029. var process = function ( input ) {
  15030. if ( $.isArray( input ) ) {
  15031. for ( var i=0, ien=input.length ; i<ien ; i++ ) {
  15032. process( input[i] );
  15033. }
  15034. return;
  15035. }
  15036. if ( typeof input === 'string' ) {
  15037. if ( input.indexOf( ',' ) !== -1 ) {
  15038. // String selector, list of names
  15039. process( input.split(',') );
  15040. }
  15041. else {
  15042. // String selector individual name
  15043. var idx = $.inArray( $.trim(input), names );
  15044. if ( idx !== -1 ) {
  15045. ret.push( buttons[ idx ].inst );
  15046. }
  15047. }
  15048. }
  15049. else if ( typeof input === 'number' ) {
  15050. // Index selector
  15051. ret.push( buttons[ input ].inst );
  15052. }
  15053. };
  15054. process( group );
  15055. return ret;
  15056. };
  15057. /**
  15058. * Button selector - select one or more buttons from a selector input so some
  15059. * operation can be performed on them.
  15060. * @param {array} Button instances array that the selector should operate on
  15061. * @param {string|int|node|jQuery|array} Button selector - see
  15062. * `button-selector` documentation on the DataTables site
  15063. * @return {array} Array of objects containing `inst` and `idx` properties of
  15064. * the selected buttons so you know which instance each button belongs to.
  15065. * @static
  15066. */
  15067. Buttons.buttonSelector = function ( insts, selector )
  15068. {
  15069. var ret = [];
  15070. var nodeBuilder = function ( a, buttons, baseIdx ) {
  15071. var button;
  15072. var idx;
  15073. for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
  15074. button = buttons[i];
  15075. if ( button ) {
  15076. idx = baseIdx !== undefined ?
  15077. baseIdx+i :
  15078. i+'';
  15079. a.push( {
  15080. node: button.node,
  15081. name: button.conf.name,
  15082. idx: idx
  15083. } );
  15084. if ( button.buttons ) {
  15085. nodeBuilder( a, button.buttons, idx+'-' );
  15086. }
  15087. }
  15088. }
  15089. };
  15090. var run = function ( selector, inst ) {
  15091. var i, ien;
  15092. var buttons = [];
  15093. nodeBuilder( buttons, inst.s.buttons );
  15094. var nodes = $.map( buttons, function (v) {
  15095. return v.node;
  15096. } );
  15097. if ( $.isArray( selector ) || selector instanceof $ ) {
  15098. for ( i=0, ien=selector.length ; i<ien ; i++ ) {
  15099. run( selector[i], inst );
  15100. }
  15101. return;
  15102. }
  15103. if ( selector === null || selector === undefined || selector === '*' ) {
  15104. // Select all
  15105. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  15106. ret.push( {
  15107. inst: inst,
  15108. node: buttons[i].node
  15109. } );
  15110. }
  15111. }
  15112. else if ( typeof selector === 'number' ) {
  15113. // Main button index selector
  15114. ret.push( {
  15115. inst: inst,
  15116. node: inst.s.buttons[ selector ].node
  15117. } );
  15118. }
  15119. else if ( typeof selector === 'string' ) {
  15120. if ( selector.indexOf( ',' ) !== -1 ) {
  15121. // Split
  15122. var a = selector.split(',');
  15123. for ( i=0, ien=a.length ; i<ien ; i++ ) {
  15124. run( $.trim(a[i]), inst );
  15125. }
  15126. }
  15127. else if ( selector.match( /^\d+(\-\d+)*$/ ) ) {
  15128. // Sub-button index selector
  15129. var indexes = $.map( buttons, function (v) {
  15130. return v.idx;
  15131. } );
  15132. ret.push( {
  15133. inst: inst,
  15134. node: buttons[ $.inArray( selector, indexes ) ].node
  15135. } );
  15136. }
  15137. else if ( selector.indexOf( ':name' ) !== -1 ) {
  15138. // Button name selector
  15139. var name = selector.replace( ':name', '' );
  15140. for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
  15141. if ( buttons[i].name === name ) {
  15142. ret.push( {
  15143. inst: inst,
  15144. node: buttons[i].node
  15145. } );
  15146. }
  15147. }
  15148. }
  15149. else {
  15150. // jQuery selector on the nodes
  15151. $( nodes ).filter( selector ).each( function () {
  15152. ret.push( {
  15153. inst: inst,
  15154. node: this
  15155. } );
  15156. } );
  15157. }
  15158. }
  15159. else if ( typeof selector === 'object' && selector.nodeName ) {
  15160. // Node selector
  15161. var idx = $.inArray( selector, nodes );
  15162. if ( idx !== -1 ) {
  15163. ret.push( {
  15164. inst: inst,
  15165. node: nodes[ idx ]
  15166. } );
  15167. }
  15168. }
  15169. };
  15170. for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
  15171. var inst = insts[i];
  15172. run( selector, inst );
  15173. }
  15174. return ret;
  15175. };
  15176. /**
  15177. * Buttons defaults. For full documentation, please refer to the docs/option
  15178. * directory or the DataTables site.
  15179. * @type {Object}
  15180. * @static
  15181. */
  15182. Buttons.defaults = {
  15183. buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],
  15184. name: 'main',
  15185. tabIndex: 0,
  15186. dom: {
  15187. container: {
  15188. tag: 'div',
  15189. className: 'dt-buttons'
  15190. },
  15191. collection: {
  15192. tag: 'div',
  15193. className: 'dt-button-collection'
  15194. },
  15195. button: {
  15196. tag: 'button',
  15197. className: 'dt-button',
  15198. active: 'active',
  15199. disabled: 'disabled'
  15200. },
  15201. buttonLiner: {
  15202. tag: 'span',
  15203. className: ''
  15204. }
  15205. }
  15206. };
  15207. /**
  15208. * Version information
  15209. * @type {string}
  15210. * @static
  15211. */
  15212. Buttons.version = '1.5.1';
  15213. $.extend( _dtButtons, {
  15214. collection: {
  15215. text: function ( dt ) {
  15216. return dt.i18n( 'buttons.collection', 'Collection' );
  15217. },
  15218. className: 'buttons-collection',
  15219. action: function ( e, dt, button, config ) {
  15220. var host = button;
  15221. var collectionParent = $(button).parents('div.dt-button-collection');
  15222. var hostPosition = host.position();
  15223. var tableContainer = $( dt.table().container() );
  15224. var multiLevel = false;
  15225. var insertPoint = host;
  15226. // Remove any old collection
  15227. if ( collectionParent.length ) {
  15228. multiLevel = $('.dt-button-collection').position();
  15229. insertPoint = collectionParent;
  15230. $('body').trigger( 'click.dtb-collection' );
  15231. }
  15232. config._collection
  15233. .addClass( config.collectionLayout )
  15234. .css( 'display', 'none' )
  15235. .insertAfter( insertPoint )
  15236. .fadeIn( config.fade );
  15237. var position = config._collection.css( 'position' );
  15238. if ( multiLevel && position === 'absolute' ) {
  15239. config._collection.css( {
  15240. top: multiLevel.top,
  15241. left: multiLevel.left
  15242. } );
  15243. }
  15244. else if ( position === 'absolute' ) {
  15245. config._collection.css( {
  15246. top: hostPosition.top + host.outerHeight(),
  15247. left: hostPosition.left
  15248. } );
  15249. // calculate overflow when positioned beneath
  15250. var tableBottom = tableContainer.offset().top + tableContainer.height();
  15251. var listBottom = hostPosition.top + host.outerHeight() + config._collection.outerHeight();
  15252. var bottomOverflow = listBottom - tableBottom;
  15253. // calculate overflow when positioned above
  15254. var listTop = hostPosition.top - config._collection.outerHeight();
  15255. var tableTop = tableContainer.offset().top;
  15256. var topOverflow = tableTop - listTop;
  15257. // if bottom overflow is larger, move to the top because it fits better
  15258. if (bottomOverflow > topOverflow) {
  15259. config._collection.css( 'top', hostPosition.top - config._collection.outerHeight() - 5);
  15260. }
  15261. var listRight = hostPosition.left + config._collection.outerWidth();
  15262. var tableRight = tableContainer.offset().left + tableContainer.width();
  15263. if ( listRight > tableRight ) {
  15264. config._collection.css( 'left', hostPosition.left - ( listRight - tableRight ) );
  15265. }
  15266. }
  15267. else {
  15268. // Fix position - centre on screen
  15269. var top = config._collection.height() / 2;
  15270. if ( top > $(window).height() / 2 ) {
  15271. top = $(window).height() / 2;
  15272. }
  15273. config._collection.css( 'marginTop', top*-1 );
  15274. }
  15275. if ( config.background ) {
  15276. Buttons.background( true, config.backgroundClassName, config.fade );
  15277. }
  15278. // Need to break the 'thread' for the collection button being
  15279. // activated by a click - it would also trigger this event
  15280. setTimeout( function () {
  15281. // This is bonkers, but if we don't have a click listener on the
  15282. // background element, iOS Safari will ignore the body click
  15283. // listener below. An empty function here is all that is
  15284. // required to make it work...
  15285. $('div.dt-button-background').on( 'click.dtb-collection', function () {} );
  15286. $('body').on( 'click.dtb-collection', function (e) {
  15287. // andSelf is deprecated in jQ1.8, but we want 1.7 compat
  15288. var back = $.fn.addBack ? 'addBack' : 'andSelf';
  15289. if ( ! $(e.target).parents()[back]().filter( config._collection ).length ) {
  15290. config._collection
  15291. .fadeOut( config.fade, function () {
  15292. config._collection.detach();
  15293. } );
  15294. $('div.dt-button-background').off( 'click.dtb-collection' );
  15295. Buttons.background( false, config.backgroundClassName, config.fade );
  15296. $('body').off( 'click.dtb-collection' );
  15297. dt.off( 'buttons-action.b-internal' );
  15298. }
  15299. } );
  15300. }, 10 );
  15301. if ( config.autoClose ) {
  15302. dt.on( 'buttons-action.b-internal', function () {
  15303. $('div.dt-button-background').click();
  15304. } );
  15305. }
  15306. },
  15307. background: true,
  15308. collectionLayout: '',
  15309. backgroundClassName: 'dt-button-background',
  15310. autoClose: false,
  15311. fade: 400,
  15312. attr: {
  15313. 'aria-haspopup': true
  15314. }
  15315. },
  15316. copy: function ( dt, conf ) {
  15317. if ( _dtButtons.copyHtml5 ) {
  15318. return 'copyHtml5';
  15319. }
  15320. if ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {
  15321. return 'copyFlash';
  15322. }
  15323. },
  15324. csv: function ( dt, conf ) {
  15325. // Common option that will use the HTML5 or Flash export buttons
  15326. if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {
  15327. return 'csvHtml5';
  15328. }
  15329. if ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {
  15330. return 'csvFlash';
  15331. }
  15332. },
  15333. excel: function ( dt, conf ) {
  15334. // Common option that will use the HTML5 or Flash export buttons
  15335. if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {
  15336. return 'excelHtml5';
  15337. }
  15338. if ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {
  15339. return 'excelFlash';
  15340. }
  15341. },
  15342. pdf: function ( dt, conf ) {
  15343. // Common option that will use the HTML5 or Flash export buttons
  15344. if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {
  15345. return 'pdfHtml5';
  15346. }
  15347. if ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {
  15348. return 'pdfFlash';
  15349. }
  15350. },
  15351. pageLength: function ( dt ) {
  15352. var lengthMenu = dt.settings()[0].aLengthMenu;
  15353. var vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;
  15354. var lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;
  15355. var text = function ( dt ) {
  15356. return dt.i18n( 'buttons.pageLength', {
  15357. "-1": 'Show all rows',
  15358. _: 'Show %d rows'
  15359. }, dt.page.len() );
  15360. };
  15361. return {
  15362. extend: 'collection',
  15363. text: text,
  15364. className: 'buttons-page-length',
  15365. autoClose: true,
  15366. buttons: $.map( vals, function ( val, i ) {
  15367. return {
  15368. text: lang[i],
  15369. className: 'button-page-length',
  15370. action: function ( e, dt ) {
  15371. dt.page.len( val ).draw();
  15372. },
  15373. init: function ( dt, node, conf ) {
  15374. var that = this;
  15375. var fn = function () {
  15376. that.active( dt.page.len() === val );
  15377. };
  15378. dt.on( 'length.dt'+conf.namespace, fn );
  15379. fn();
  15380. },
  15381. destroy: function ( dt, node, conf ) {
  15382. dt.off( 'length.dt'+conf.namespace );
  15383. }
  15384. };
  15385. } ),
  15386. init: function ( dt, node, conf ) {
  15387. var that = this;
  15388. dt.on( 'length.dt'+conf.namespace, function () {
  15389. that.text( text( dt ) );
  15390. } );
  15391. },
  15392. destroy: function ( dt, node, conf ) {
  15393. dt.off( 'length.dt'+conf.namespace );
  15394. }
  15395. };
  15396. }
  15397. } );
  15398. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15399. * DataTables API
  15400. *
  15401. * For complete documentation, please refer to the docs/api directory or the
  15402. * DataTables site
  15403. */
  15404. // Buttons group and individual button selector
  15405. DataTable.Api.register( 'buttons()', function ( group, selector ) {
  15406. // Argument shifting
  15407. if ( selector === undefined ) {
  15408. selector = group;
  15409. group = undefined;
  15410. }
  15411. this.selector.buttonGroup = group;
  15412. var res = this.iterator( true, 'table', function ( ctx ) {
  15413. if ( ctx._buttons ) {
  15414. return Buttons.buttonSelector(
  15415. Buttons.instanceSelector( group, ctx._buttons ),
  15416. selector
  15417. );
  15418. }
  15419. }, true );
  15420. res._groupSelector = group;
  15421. return res;
  15422. } );
  15423. // Individual button selector
  15424. DataTable.Api.register( 'button()', function ( group, selector ) {
  15425. // just run buttons() and truncate
  15426. var buttons = this.buttons( group, selector );
  15427. if ( buttons.length > 1 ) {
  15428. buttons.splice( 1, buttons.length );
  15429. }
  15430. return buttons;
  15431. } );
  15432. // Active buttons
  15433. DataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {
  15434. if ( flag === undefined ) {
  15435. return this.map( function ( set ) {
  15436. return set.inst.active( set.node );
  15437. } );
  15438. }
  15439. return this.each( function ( set ) {
  15440. set.inst.active( set.node, flag );
  15441. } );
  15442. } );
  15443. // Get / set button action
  15444. DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {
  15445. if ( action === undefined ) {
  15446. return this.map( function ( set ) {
  15447. return set.inst.action( set.node );
  15448. } );
  15449. }
  15450. return this.each( function ( set ) {
  15451. set.inst.action( set.node, action );
  15452. } );
  15453. } );
  15454. // Enable / disable buttons
  15455. DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {
  15456. return this.each( function ( set ) {
  15457. set.inst.enable( set.node, flag );
  15458. } );
  15459. } );
  15460. // Disable buttons
  15461. DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {
  15462. return this.each( function ( set ) {
  15463. set.inst.disable( set.node );
  15464. } );
  15465. } );
  15466. // Get button nodes
  15467. DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {
  15468. var jq = $();
  15469. // jQuery will automatically reduce duplicates to a single entry
  15470. $( this.each( function ( set ) {
  15471. jq = jq.add( set.inst.node( set.node ) );
  15472. } ) );
  15473. return jq;
  15474. } );
  15475. // Get / set button processing state
  15476. DataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {
  15477. if ( flag === undefined ) {
  15478. return this.map( function ( set ) {
  15479. return set.inst.processing( set.node );
  15480. } );
  15481. }
  15482. return this.each( function ( set ) {
  15483. set.inst.processing( set.node, flag );
  15484. } );
  15485. } );
  15486. // Get / set button text (i.e. the button labels)
  15487. DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
  15488. if ( label === undefined ) {
  15489. return this.map( function ( set ) {
  15490. return set.inst.text( set.node );
  15491. } );
  15492. }
  15493. return this.each( function ( set ) {
  15494. set.inst.text( set.node, label );
  15495. } );
  15496. } );
  15497. // Trigger a button's action
  15498. DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {
  15499. return this.each( function ( set ) {
  15500. set.inst.node( set.node ).trigger( 'click' );
  15501. } );
  15502. } );
  15503. // Get the container elements
  15504. DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {
  15505. var jq = $();
  15506. var groupSelector = this._groupSelector;
  15507. // We need to use the group selector directly, since if there are no buttons
  15508. // the result set will be empty
  15509. this.iterator( true, 'table', function ( ctx ) {
  15510. if ( ctx._buttons ) {
  15511. var insts = Buttons.instanceSelector( groupSelector, ctx._buttons );
  15512. for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
  15513. jq = jq.add( insts[i].container() );
  15514. }
  15515. }
  15516. } );
  15517. return jq;
  15518. } );
  15519. // Add a new button
  15520. DataTable.Api.register( 'button().add()', function ( idx, conf ) {
  15521. var ctx = this.context;
  15522. // Don't use `this` as it could be empty - select the instances directly
  15523. if ( ctx.length ) {
  15524. var inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons );
  15525. if ( inst.length ) {
  15526. inst[0].add( conf, idx );
  15527. }
  15528. }
  15529. return this.button( this._groupSelector, idx );
  15530. } );
  15531. // Destroy the button sets selected
  15532. DataTable.Api.register( 'buttons().destroy()', function () {
  15533. this.pluck( 'inst' ).unique().each( function ( inst ) {
  15534. inst.destroy();
  15535. } );
  15536. return this;
  15537. } );
  15538. // Remove a button
  15539. DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {
  15540. this.each( function ( set ) {
  15541. set.inst.remove( set.node );
  15542. } );
  15543. return this;
  15544. } );
  15545. // Information box that can be used by buttons
  15546. var _infoTimer;
  15547. DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
  15548. var that = this;
  15549. if ( title === false ) {
  15550. $('#datatables_buttons_info').fadeOut( function () {
  15551. $(this).remove();
  15552. } );
  15553. clearTimeout( _infoTimer );
  15554. _infoTimer = null;
  15555. return this;
  15556. }
  15557. if ( _infoTimer ) {
  15558. clearTimeout( _infoTimer );
  15559. }
  15560. if ( $('#datatables_buttons_info').length ) {
  15561. $('#datatables_buttons_info').remove();
  15562. }
  15563. title = title ? '<h2>'+title+'</h2>' : '';
  15564. $('<div id="datatables_buttons_info" class="dt-button-info"/>')
  15565. .html( title )
  15566. .append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )
  15567. .css( 'display', 'none' )
  15568. .appendTo( 'body' )
  15569. .fadeIn();
  15570. if ( time !== undefined && time !== 0 ) {
  15571. _infoTimer = setTimeout( function () {
  15572. that.buttons.info( false );
  15573. }, time );
  15574. }
  15575. return this;
  15576. } );
  15577. // Get data from the table for export - this is common to a number of plug-in
  15578. // buttons so it is included in the Buttons core library
  15579. DataTable.Api.register( 'buttons.exportData()', function ( options ) {
  15580. if ( this.context.length ) {
  15581. return _exportData( new DataTable.Api( this.context[0] ), options );
  15582. }
  15583. } );
  15584. // Get information about the export that is common to many of the export data
  15585. // types (DRY)
  15586. DataTable.Api.register( 'buttons.exportInfo()', function ( conf ) {
  15587. if ( ! conf ) {
  15588. conf = {};
  15589. }
  15590. return {
  15591. filename: _filename( conf ),
  15592. title: _title( conf ),
  15593. messageTop: _message(this, conf.message || conf.messageTop, 'top'),
  15594. messageBottom: _message(this, conf.messageBottom, 'bottom')
  15595. };
  15596. } );
  15597. /**
  15598. * Get the file name for an exported file.
  15599. *
  15600. * @param {object} config Button configuration
  15601. * @param {boolean} incExtension Include the file name extension
  15602. */
  15603. var _filename = function ( config )
  15604. {
  15605. // Backwards compatibility
  15606. var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ?
  15607. config.title :
  15608. config.filename;
  15609. if ( typeof filename === 'function' ) {
  15610. filename = filename();
  15611. }
  15612. if ( filename === undefined || filename === null ) {
  15613. return null;
  15614. }
  15615. if ( filename.indexOf( '*' ) !== -1 ) {
  15616. filename = $.trim( filename.replace( '*', $('head > title').text() ) );
  15617. }
  15618. // Strip characters which the OS will object to
  15619. filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
  15620. var extension = _stringOrFunction( config.extension );
  15621. if ( ! extension ) {
  15622. extension = '';
  15623. }
  15624. return filename + extension;
  15625. };
  15626. /**
  15627. * Simply utility method to allow parameters to be given as a function
  15628. *
  15629. * @param {undefined|string|function} option Option
  15630. * @return {null|string} Resolved value
  15631. */
  15632. var _stringOrFunction = function ( option )
  15633. {
  15634. if ( option === null || option === undefined ) {
  15635. return null;
  15636. }
  15637. else if ( typeof option === 'function' ) {
  15638. return option();
  15639. }
  15640. return option;
  15641. };
  15642. /**
  15643. * Get the title for an exported file.
  15644. *
  15645. * @param {object} config Button configuration
  15646. */
  15647. var _title = function ( config )
  15648. {
  15649. var title = _stringOrFunction( config.title );
  15650. return title === null ?
  15651. null : title.indexOf( '*' ) !== -1 ?
  15652. title.replace( '*', $('head > title').text() || 'Exported data' ) :
  15653. title;
  15654. };
  15655. var _message = function ( dt, option, position )
  15656. {
  15657. var message = _stringOrFunction( option );
  15658. if ( message === null ) {
  15659. return null;
  15660. }
  15661. var caption = $('caption', dt.table().container()).eq(0);
  15662. if ( message === '*' ) {
  15663. var side = caption.css( 'caption-side' );
  15664. if ( side !== position ) {
  15665. return null;
  15666. }
  15667. return caption.length ?
  15668. caption.text() :
  15669. '';
  15670. }
  15671. return message;
  15672. };
  15673. var _exportTextarea = $('<textarea/>')[0];
  15674. var _exportData = function ( dt, inOpts )
  15675. {
  15676. var config = $.extend( true, {}, {
  15677. rows: null,
  15678. columns: '',
  15679. modifier: {
  15680. search: 'applied',
  15681. order: 'applied'
  15682. },
  15683. orthogonal: 'display',
  15684. stripHtml: true,
  15685. stripNewlines: true,
  15686. decodeEntities: true,
  15687. trim: true,
  15688. format: {
  15689. header: function ( d ) {
  15690. return strip( d );
  15691. },
  15692. footer: function ( d ) {
  15693. return strip( d );
  15694. },
  15695. body: function ( d ) {
  15696. return strip( d );
  15697. }
  15698. }
  15699. }, inOpts );
  15700. var strip = function ( str ) {
  15701. if ( typeof str !== 'string' ) {
  15702. return str;
  15703. }
  15704. // Always remove script tags
  15705. str = str.replace( /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '' );
  15706. if ( config.stripHtml ) {
  15707. str = str.replace( /<[^>]*>/g, '' );
  15708. }
  15709. if ( config.trim ) {
  15710. str = str.replace( /^\s+|\s+$/g, '' );
  15711. }
  15712. if ( config.stripNewlines ) {
  15713. str = str.replace( /\n/g, ' ' );
  15714. }
  15715. if ( config.decodeEntities ) {
  15716. _exportTextarea.innerHTML = str;
  15717. str = _exportTextarea.value;
  15718. }
  15719. return str;
  15720. };
  15721. var header = dt.columns( config.columns ).indexes().map( function (idx) {
  15722. var el = dt.column( idx ).header();
  15723. return config.format.header( el.innerHTML, idx, el );
  15724. } ).toArray();
  15725. var footer = dt.table().footer() ?
  15726. dt.columns( config.columns ).indexes().map( function (idx) {
  15727. var el = dt.column( idx ).footer();
  15728. return config.format.footer( el ? el.innerHTML : '', idx, el );
  15729. } ).toArray() :
  15730. null;
  15731. // If Select is available on this table, and any rows are selected, limit the export
  15732. // to the selected rows. If no rows are selected, all rows will be exported. Specify
  15733. // a `selected` modifier to control directly.
  15734. var modifier = $.extend( {}, config.modifier );
  15735. if ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) {
  15736. if ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) {
  15737. $.extend( modifier, { selected: true } )
  15738. }
  15739. }
  15740. var rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray();
  15741. var selectedCells = dt.cells( rowIndexes, config.columns );
  15742. var cells = selectedCells
  15743. .render( config.orthogonal )
  15744. .toArray();
  15745. var cellNodes = selectedCells
  15746. .nodes()
  15747. .toArray();
  15748. var columns = header.length;
  15749. var rows = columns > 0 ? cells.length / columns : 0;
  15750. var body = [ rows ];
  15751. var cellCounter = 0;
  15752. for ( var i=0, ien=rows ; i<ien ; i++ ) {
  15753. var row = [ columns ];
  15754. for ( var j=0 ; j<columns ; j++ ) {
  15755. row[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] );
  15756. cellCounter++;
  15757. }
  15758. body[i] = row;
  15759. }
  15760. return {
  15761. header: header,
  15762. footer: footer,
  15763. body: body
  15764. };
  15765. };
  15766. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15767. * DataTables interface
  15768. */
  15769. // Attach to DataTables objects for global access
  15770. $.fn.dataTable.Buttons = Buttons;
  15771. $.fn.DataTable.Buttons = Buttons;
  15772. // DataTables creation - check if the buttons have been defined for this table,
  15773. // they will have been if the `B` option was used in `dom`, otherwise we should
  15774. // create the buttons instance here so they can be inserted into the document
  15775. // using the API. Listen for `init` for compatibility with pre 1.10.10, but to
  15776. // be removed in future.
  15777. $(document).on( 'init.dt plugin-init.dt', function (e, settings) {
  15778. if ( e.namespace !== 'dt' ) {
  15779. return;
  15780. }
  15781. var opts = settings.oInit.buttons || DataTable.defaults.buttons;
  15782. if ( opts && ! settings._buttons ) {
  15783. new Buttons( settings, opts ).container();
  15784. }
  15785. } );
  15786. // DataTables `dom` feature option
  15787. DataTable.ext.feature.push( {
  15788. fnInit: function( settings ) {
  15789. var api = new DataTable.Api( settings );
  15790. var opts = api.init().buttons || DataTable.defaults.buttons;
  15791. return new Buttons( api, opts ).container();
  15792. },
  15793. cFeature: "B"
  15794. } );
  15795. return Buttons;
  15796. }));
  15797. /*! ColReorder 1.4.1
  15798. * ©2010-2017 SpryMedia Ltd - datatables.net/license
  15799. */
  15800. /**
  15801. * @summary ColReorder
  15802. * @description Provide the ability to reorder columns in a DataTable
  15803. * @version 1.4.1
  15804. * @file dataTables.colReorder.js
  15805. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  15806. * @contact www.sprymedia.co.uk/contact
  15807. * @copyright Copyright 2010-2017 SpryMedia Ltd.
  15808. *
  15809. * This source file is free software, available under the following license:
  15810. * MIT license - http://datatables.net/license/mit
  15811. *
  15812. * This source file is distributed in the hope that it will be useful, but
  15813. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  15814. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  15815. *
  15816. * For details please refer to: http://www.datatables.net
  15817. */
  15818. (function( factory ){
  15819. if ( typeof define === 'function' && define.amd ) {
  15820. // AMD
  15821. define( ['jquery', 'datatables.net'], function ( $ ) {
  15822. return factory( $, window, document );
  15823. } );
  15824. }
  15825. else if ( typeof exports === 'object' ) {
  15826. // CommonJS
  15827. module.exports = function (root, $) {
  15828. if ( ! root ) {
  15829. root = window;
  15830. }
  15831. if ( ! $ || ! $.fn.dataTable ) {
  15832. $ = require('datatables.net')(root, $).$;
  15833. }
  15834. return factory( $, root, root.document );
  15835. };
  15836. }
  15837. else {
  15838. // Browser
  15839. factory( jQuery, window, document );
  15840. }
  15841. }(function( $, window, document, undefined ) {
  15842. 'use strict';
  15843. var DataTable = $.fn.dataTable;
  15844. /**
  15845. * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
  15846. * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
  15847. * @method fnInvertKeyValues
  15848. * @param array aIn Array to switch around
  15849. * @returns array
  15850. */
  15851. function fnInvertKeyValues( aIn )
  15852. {
  15853. var aRet=[];
  15854. for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
  15855. {
  15856. aRet[ aIn[i] ] = i;
  15857. }
  15858. return aRet;
  15859. }
  15860. /**
  15861. * Modify an array by switching the position of two elements
  15862. * @method fnArraySwitch
  15863. * @param array aArray Array to consider, will be modified by reference (i.e. no return)
  15864. * @param int iFrom From point
  15865. * @param int iTo Insert point
  15866. * @returns void
  15867. */
  15868. function fnArraySwitch( aArray, iFrom, iTo )
  15869. {
  15870. var mStore = aArray.splice( iFrom, 1 )[0];
  15871. aArray.splice( iTo, 0, mStore );
  15872. }
  15873. /**
  15874. * Switch the positions of nodes in a parent node (note this is specifically designed for
  15875. * table rows). Note this function considers all element nodes under the parent!
  15876. * @method fnDomSwitch
  15877. * @param string sTag Tag to consider
  15878. * @param int iFrom Element to move
  15879. * @param int Point to element the element to (before this point), can be null for append
  15880. * @returns void
  15881. */
  15882. function fnDomSwitch( nParent, iFrom, iTo )
  15883. {
  15884. var anTags = [];
  15885. for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
  15886. {
  15887. if ( nParent.childNodes[i].nodeType == 1 )
  15888. {
  15889. anTags.push( nParent.childNodes[i] );
  15890. }
  15891. }
  15892. var nStore = anTags[ iFrom ];
  15893. if ( iTo !== null )
  15894. {
  15895. nParent.insertBefore( nStore, anTags[iTo] );
  15896. }
  15897. else
  15898. {
  15899. nParent.appendChild( nStore );
  15900. }
  15901. }
  15902. /**
  15903. * Plug-in for DataTables which will reorder the internal column structure by taking the column
  15904. * from one position (iFrom) and insert it into a given point (iTo).
  15905. * @method $.fn.dataTableExt.oApi.fnColReorder
  15906. * @param object oSettings DataTables settings object - automatically added by DataTables!
  15907. * @param int iFrom Take the column to be repositioned from this point
  15908. * @param int iTo and insert it into this point
  15909. * @param bool drop Indicate if the reorder is the final one (i.e. a drop)
  15910. * not a live reorder
  15911. * @param bool invalidateRows speeds up processing if false passed
  15912. * @returns void
  15913. */
  15914. $.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows )
  15915. {
  15916. var i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol;
  15917. var attrMap = function ( obj, prop, mapping ) {
  15918. if ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) {
  15919. return;
  15920. }
  15921. var a = obj[ prop ].split('.');
  15922. var num = a.shift();
  15923. if ( isNaN( num*1 ) ) {
  15924. return;
  15925. }
  15926. obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');
  15927. };
  15928. /* Sanity check in the input */
  15929. if ( iFrom == iTo )
  15930. {
  15931. /* Pointless reorder */
  15932. return;
  15933. }
  15934. if ( iFrom < 0 || iFrom >= iCols )
  15935. {
  15936. this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
  15937. return;
  15938. }
  15939. if ( iTo < 0 || iTo >= iCols )
  15940. {
  15941. this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
  15942. return;
  15943. }
  15944. /*
  15945. * Calculate the new column array index, so we have a mapping between the old and new
  15946. */
  15947. var aiMapping = [];
  15948. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  15949. {
  15950. aiMapping[i] = i;
  15951. }
  15952. fnArraySwitch( aiMapping, iFrom, iTo );
  15953. var aiInvertMapping = fnInvertKeyValues( aiMapping );
  15954. /*
  15955. * Convert all internal indexing to the new column order indexes
  15956. */
  15957. /* Sorting */
  15958. for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
  15959. {
  15960. oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
  15961. }
  15962. /* Fixed sorting */
  15963. if ( oSettings.aaSortingFixed !== null )
  15964. {
  15965. for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
  15966. {
  15967. oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
  15968. }
  15969. }
  15970. /* Data column sorting (the column which the sort for a given column should take place on) */
  15971. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  15972. {
  15973. oCol = oSettings.aoColumns[i];
  15974. for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
  15975. {
  15976. oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
  15977. }
  15978. // Update the column indexes
  15979. oCol.idx = aiInvertMapping[ oCol.idx ];
  15980. }
  15981. // Update 1.10 optimised sort class removal variable
  15982. $.each( oSettings.aLastSort, function (i, val) {
  15983. oSettings.aLastSort[i].src = aiInvertMapping[ val.src ];
  15984. } );
  15985. /* Update the Get and Set functions for each column */
  15986. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  15987. {
  15988. oCol = oSettings.aoColumns[i];
  15989. if ( typeof oCol.mData == 'number' ) {
  15990. oCol.mData = aiInvertMapping[ oCol.mData ];
  15991. }
  15992. else if ( $.isPlainObject( oCol.mData ) ) {
  15993. // HTML5 data sourced
  15994. attrMap( oCol.mData, '_', aiInvertMapping );
  15995. attrMap( oCol.mData, 'filter', aiInvertMapping );
  15996. attrMap( oCol.mData, 'sort', aiInvertMapping );
  15997. attrMap( oCol.mData, 'type', aiInvertMapping );
  15998. }
  15999. }
  16000. /*
  16001. * Move the DOM elements
  16002. */
  16003. if ( oSettings.aoColumns[iFrom].bVisible )
  16004. {
  16005. /* Calculate the current visible index and the point to insert the node before. The insert
  16006. * before needs to take into account that there might not be an element to insert before,
  16007. * in which case it will be null, and an appendChild should be used
  16008. */
  16009. var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
  16010. var iInsertBeforeIndex = null;
  16011. i = iTo < iFrom ? iTo : iTo + 1;
  16012. while ( iInsertBeforeIndex === null && i < iCols )
  16013. {
  16014. iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
  16015. i++;
  16016. }
  16017. /* Header */
  16018. nTrs = oSettings.nTHead.getElementsByTagName('tr');
  16019. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  16020. {
  16021. fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
  16022. }
  16023. /* Footer */
  16024. if ( oSettings.nTFoot !== null )
  16025. {
  16026. nTrs = oSettings.nTFoot.getElementsByTagName('tr');
  16027. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  16028. {
  16029. fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
  16030. }
  16031. }
  16032. /* Body */
  16033. for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
  16034. {
  16035. if ( oSettings.aoData[i].nTr !== null )
  16036. {
  16037. fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
  16038. }
  16039. }
  16040. }
  16041. /*
  16042. * Move the internal array elements
  16043. */
  16044. /* Columns */
  16045. fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
  16046. // regenerate the get / set functions
  16047. for ( i=0, iLen=iCols ; i<iLen ; i++ ) {
  16048. oSettings.oApi._fnColumnOptions( oSettings, i, {} );
  16049. }
  16050. /* Search columns */
  16051. fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
  16052. /* Array array - internal data anodes cache */
  16053. for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
  16054. {
  16055. var data = oSettings.aoData[i];
  16056. var cells = data.anCells;
  16057. if ( cells ) {
  16058. fnArraySwitch( cells, iFrom, iTo );
  16059. // Longer term, should this be moved into the DataTables' invalidate
  16060. // methods?
  16061. for ( j=0, jen=cells.length ; j<jen ; j++ ) {
  16062. if ( cells[j] && cells[j]._DT_CellIndex ) {
  16063. cells[j]._DT_CellIndex.column = j;
  16064. }
  16065. }
  16066. }
  16067. // For DOM sourced data, the invalidate will reread the cell into
  16068. // the data array, but for data sources as an array, they need to
  16069. // be flipped
  16070. if ( data.src !== 'dom' && $.isArray( data._aData ) ) {
  16071. fnArraySwitch( data._aData, iFrom, iTo );
  16072. }
  16073. }
  16074. /* Reposition the header elements in the header layout array */
  16075. for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
  16076. {
  16077. fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
  16078. }
  16079. if ( oSettings.aoFooter !== null )
  16080. {
  16081. for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
  16082. {
  16083. fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
  16084. }
  16085. }
  16086. if ( invalidateRows || invalidateRows === undefined )
  16087. {
  16088. $.fn.dataTable.Api( oSettings ).rows().invalidate();
  16089. }
  16090. /*
  16091. * Update DataTables' event handlers
  16092. */
  16093. /* Sort listener */
  16094. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  16095. {
  16096. $(oSettings.aoColumns[i].nTh).off('click.DT');
  16097. this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
  16098. }
  16099. /* Fire an event so other plug-ins can update */
  16100. $(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, {
  16101. from: iFrom,
  16102. to: iTo,
  16103. mapping: aiInvertMapping,
  16104. drop: drop,
  16105. // Old style parameters for compatibility
  16106. iFrom: iFrom,
  16107. iTo: iTo,
  16108. aiInvertMapping: aiInvertMapping
  16109. } ] );
  16110. };
  16111. /**
  16112. * ColReorder provides column visibility control for DataTables
  16113. * @class ColReorder
  16114. * @constructor
  16115. * @param {object} dt DataTables settings object
  16116. * @param {object} opts ColReorder options
  16117. */
  16118. var ColReorder = function( dt, opts )
  16119. {
  16120. var settings = new $.fn.dataTable.Api( dt ).settings()[0];
  16121. // Ensure that we can't initialise on the same table twice
  16122. if ( settings._colReorder ) {
  16123. return settings._colReorder;
  16124. }
  16125. // Allow the options to be a boolean for defaults
  16126. if ( opts === true ) {
  16127. opts = {};
  16128. }
  16129. // Convert from camelCase to Hungarian, just as DataTables does
  16130. var camelToHungarian = $.fn.dataTable.camelToHungarian;
  16131. if ( camelToHungarian ) {
  16132. camelToHungarian( ColReorder.defaults, ColReorder.defaults, true );
  16133. camelToHungarian( ColReorder.defaults, opts || {} );
  16134. }
  16135. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16136. * Public class variables
  16137. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16138. /**
  16139. * @namespace Settings object which contains customisable information for ColReorder instance
  16140. */
  16141. this.s = {
  16142. /**
  16143. * DataTables settings object
  16144. * @property dt
  16145. * @type Object
  16146. * @default null
  16147. */
  16148. "dt": null,
  16149. /**
  16150. * Initialisation object used for this instance
  16151. * @property init
  16152. * @type object
  16153. * @default {}
  16154. */
  16155. "init": $.extend( true, {}, ColReorder.defaults, opts ),
  16156. /**
  16157. * Number of columns to fix (not allow to be reordered)
  16158. * @property fixed
  16159. * @type int
  16160. * @default 0
  16161. */
  16162. "fixed": 0,
  16163. /**
  16164. * Number of columns to fix counting from right (not allow to be reordered)
  16165. * @property fixedRight
  16166. * @type int
  16167. * @default 0
  16168. */
  16169. "fixedRight": 0,
  16170. /**
  16171. * Callback function for once the reorder has been done
  16172. * @property reorderCallback
  16173. * @type function
  16174. * @default null
  16175. */
  16176. "reorderCallback": null,
  16177. /**
  16178. * @namespace Information used for the mouse drag
  16179. */
  16180. "mouse": {
  16181. "startX": -1,
  16182. "startY": -1,
  16183. "offsetX": -1,
  16184. "offsetY": -1,
  16185. "target": -1,
  16186. "targetIndex": -1,
  16187. "fromIndex": -1
  16188. },
  16189. /**
  16190. * Information which is used for positioning the insert cusor and knowing where to do the
  16191. * insert. Array of objects with the properties:
  16192. * x: x-axis position
  16193. * to: insert point
  16194. * @property aoTargets
  16195. * @type array
  16196. * @default []
  16197. */
  16198. "aoTargets": []
  16199. };
  16200. /**
  16201. * @namespace Common and useful DOM elements for the class instance
  16202. */
  16203. this.dom = {
  16204. /**
  16205. * Dragging element (the one the mouse is moving)
  16206. * @property drag
  16207. * @type element
  16208. * @default null
  16209. */
  16210. "drag": null,
  16211. /**
  16212. * The insert cursor
  16213. * @property pointer
  16214. * @type element
  16215. * @default null
  16216. */
  16217. "pointer": null
  16218. };
  16219. /* Constructor logic */
  16220. this.s.dt = settings;
  16221. this.s.dt._colReorder = this;
  16222. this._fnConstruct();
  16223. return this;
  16224. };
  16225. $.extend( ColReorder.prototype, {
  16226. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16227. * Public methods
  16228. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16229. /**
  16230. * Reset the column ordering to the original ordering that was detected on
  16231. * start up.
  16232. * @return {this} Returns `this` for chaining.
  16233. *
  16234. * @example
  16235. * // DataTables initialisation with ColReorder
  16236. * var table = $('#example').dataTable( {
  16237. * "sDom": 'Rlfrtip'
  16238. * } );
  16239. *
  16240. * // Add click event to a button to reset the ordering
  16241. * $('#resetOrdering').click( function (e) {
  16242. * e.preventDefault();
  16243. * $.fn.dataTable.ColReorder( table ).fnReset();
  16244. * } );
  16245. */
  16246. "fnReset": function ()
  16247. {
  16248. this._fnOrderColumns( this.fnOrder() );
  16249. return this;
  16250. },
  16251. /**
  16252. * `Deprecated` - Get the current order of the columns, as an array.
  16253. * @return {array} Array of column identifiers
  16254. * @deprecated `fnOrder` should be used in preference to this method.
  16255. * `fnOrder` acts as a getter/setter.
  16256. */
  16257. "fnGetCurrentOrder": function ()
  16258. {
  16259. return this.fnOrder();
  16260. },
  16261. /**
  16262. * Get the current order of the columns, as an array. Note that the values
  16263. * given in the array are unique identifiers for each column. Currently
  16264. * these are the original ordering of the columns that was detected on
  16265. * start up, but this could potentially change in future.
  16266. * @return {array} Array of column identifiers
  16267. *
  16268. * @example
  16269. * // Get column ordering for the table
  16270. * var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();
  16271. *//**
  16272. * Set the order of the columns, from the positions identified in the
  16273. * ordering array given. Note that ColReorder takes a brute force approach
  16274. * to reordering, so it is possible multiple reordering events will occur
  16275. * before the final order is settled upon.
  16276. * @param {array} [set] Array of column identifiers in the new order. Note
  16277. * that every column must be included, uniquely, in this array.
  16278. * @return {this} Returns `this` for chaining.
  16279. *
  16280. * @example
  16281. * // Swap the first and second columns
  16282. * $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );
  16283. *
  16284. * @example
  16285. * // Move the first column to the end for the table `#example`
  16286. * var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();
  16287. * var first = curr.shift();
  16288. * curr.push( first );
  16289. * $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );
  16290. *
  16291. * @example
  16292. * // Reverse the table's order
  16293. * $.fn.dataTable.ColReorder( '#example' ).fnOrder(
  16294. * $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()
  16295. * );
  16296. */
  16297. "fnOrder": function ( set, original )
  16298. {
  16299. var a = [], i, ien, j, jen;
  16300. var columns = this.s.dt.aoColumns;
  16301. if ( set === undefined ){
  16302. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  16303. a.push( columns[i]._ColReorder_iOrigCol );
  16304. }
  16305. return a;
  16306. }
  16307. // The order given is based on the original indexes, rather than the
  16308. // existing ones, so we need to translate from the original to current
  16309. // before then doing the order
  16310. if ( original ) {
  16311. var order = this.fnOrder();
  16312. for ( i=0, ien=set.length ; i<ien ; i++ ) {
  16313. a.push( $.inArray( set[i], order ) );
  16314. }
  16315. set = a;
  16316. }
  16317. this._fnOrderColumns( fnInvertKeyValues( set ) );
  16318. return this;
  16319. },
  16320. /**
  16321. * Convert from the original column index, to the original
  16322. *
  16323. * @param {int|array} idx Index(es) to convert
  16324. * @param {string} dir Transpose direction - `fromOriginal` / `toCurrent`
  16325. * or `'toOriginal` / `fromCurrent`
  16326. * @return {int|array} Converted values
  16327. */
  16328. fnTranspose: function ( idx, dir )
  16329. {
  16330. if ( ! dir ) {
  16331. dir = 'toCurrent';
  16332. }
  16333. var order = this.fnOrder();
  16334. var columns = this.s.dt.aoColumns;
  16335. if ( dir === 'toCurrent' ) {
  16336. // Given an original index, want the current
  16337. return ! $.isArray( idx ) ?
  16338. $.inArray( idx, order ) :
  16339. $.map( idx, function ( index ) {
  16340. return $.inArray( index, order );
  16341. } );
  16342. }
  16343. else {
  16344. // Given a current index, want the original
  16345. return ! $.isArray( idx ) ?
  16346. columns[idx]._ColReorder_iOrigCol :
  16347. $.map( idx, function ( index ) {
  16348. return columns[index]._ColReorder_iOrigCol;
  16349. } );
  16350. }
  16351. },
  16352. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16353. * Private methods (they are of course public in JS, but recommended as private)
  16354. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16355. /**
  16356. * Constructor logic
  16357. * @method _fnConstruct
  16358. * @returns void
  16359. * @private
  16360. */
  16361. "_fnConstruct": function ()
  16362. {
  16363. var that = this;
  16364. var iLen = this.s.dt.aoColumns.length;
  16365. var table = this.s.dt.nTable;
  16366. var i;
  16367. /* Columns discounted from reordering - counting left to right */
  16368. if ( this.s.init.iFixedColumns )
  16369. {
  16370. this.s.fixed = this.s.init.iFixedColumns;
  16371. }
  16372. if ( this.s.init.iFixedColumnsLeft )
  16373. {
  16374. this.s.fixed = this.s.init.iFixedColumnsLeft;
  16375. }
  16376. /* Columns discounted from reordering - counting right to left */
  16377. this.s.fixedRight = this.s.init.iFixedColumnsRight ?
  16378. this.s.init.iFixedColumnsRight :
  16379. 0;
  16380. /* Drop callback initialisation option */
  16381. if ( this.s.init.fnReorderCallback )
  16382. {
  16383. this.s.reorderCallback = this.s.init.fnReorderCallback;
  16384. }
  16385. /* Add event handlers for the drag and drop, and also mark the original column order */
  16386. for ( i = 0; i < iLen; i++ )
  16387. {
  16388. if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )
  16389. {
  16390. this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
  16391. }
  16392. /* Mark the original column order for later reference */
  16393. this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
  16394. }
  16395. /* State saving */
  16396. this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
  16397. that._fnStateSave.call( that, oData );
  16398. }, "ColReorder_State" );
  16399. /* An initial column order has been specified */
  16400. var aiOrder = null;
  16401. if ( this.s.init.aiOrder )
  16402. {
  16403. aiOrder = this.s.init.aiOrder.slice();
  16404. }
  16405. /* State loading, overrides the column order given */
  16406. if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
  16407. this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
  16408. {
  16409. aiOrder = this.s.dt.oLoadedState.ColReorder;
  16410. }
  16411. /* If we have an order to apply - do so */
  16412. if ( aiOrder )
  16413. {
  16414. /* We might be called during or after the DataTables initialisation. If before, then we need
  16415. * to wait until the draw is done, if after, then do what we need to do right away
  16416. */
  16417. if ( !that.s.dt._bInitComplete )
  16418. {
  16419. var bDone = false;
  16420. $(table).on( 'draw.dt.colReorder', function () {
  16421. if ( !that.s.dt._bInitComplete && !bDone )
  16422. {
  16423. bDone = true;
  16424. var resort = fnInvertKeyValues( aiOrder );
  16425. that._fnOrderColumns.call( that, resort );
  16426. }
  16427. } );
  16428. }
  16429. else
  16430. {
  16431. var resort = fnInvertKeyValues( aiOrder );
  16432. that._fnOrderColumns.call( that, resort );
  16433. }
  16434. }
  16435. else {
  16436. this._fnSetColumnIndexes();
  16437. }
  16438. // Destroy clean up
  16439. $(table).on( 'destroy.dt.colReorder', function () {
  16440. $(table).off( 'destroy.dt.colReorder draw.dt.colReorder' );
  16441. $(that.s.dt.nTHead).find( '*' ).off( '.ColReorder' );
  16442. $.each( that.s.dt.aoColumns, function (i, column) {
  16443. $(column.nTh).removeAttr('data-column-index');
  16444. } );
  16445. that.s.dt._colReorder = null;
  16446. that.s = null;
  16447. } );
  16448. },
  16449. /**
  16450. * Set the column order from an array
  16451. * @method _fnOrderColumns
  16452. * @param array a An array of integers which dictate the column order that should be applied
  16453. * @returns void
  16454. * @private
  16455. */
  16456. "_fnOrderColumns": function ( a )
  16457. {
  16458. var changed = false;
  16459. if ( a.length != this.s.dt.aoColumns.length )
  16460. {
  16461. this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+
  16462. "match known number of columns. Skipping." );
  16463. return;
  16464. }
  16465. for ( var i=0, iLen=a.length ; i<iLen ; i++ )
  16466. {
  16467. var currIndex = $.inArray( i, a );
  16468. if ( i != currIndex )
  16469. {
  16470. /* Reorder our switching array */
  16471. fnArraySwitch( a, currIndex, i );
  16472. /* Do the column reorder in the table */
  16473. this.s.dt.oInstance.fnColReorder( currIndex, i, true, false );
  16474. changed = true;
  16475. }
  16476. }
  16477. $.fn.dataTable.Api( this.s.dt ).rows().invalidate();
  16478. this._fnSetColumnIndexes();
  16479. // Has anything actually changed? If not, then nothing else to do
  16480. if ( ! changed ) {
  16481. return;
  16482. }
  16483. /* When scrolling we need to recalculate the column sizes to allow for the shift */
  16484. if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
  16485. {
  16486. this.s.dt.oInstance.fnAdjustColumnSizing( false );
  16487. }
  16488. /* Save the state */
  16489. this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
  16490. if ( this.s.reorderCallback !== null )
  16491. {
  16492. this.s.reorderCallback.call( this );
  16493. }
  16494. },
  16495. /**
  16496. * Because we change the indexes of columns in the table, relative to their starting point
  16497. * we need to reorder the state columns to what they are at the starting point so we can
  16498. * then rearrange them again on state load!
  16499. * @method _fnStateSave
  16500. * @param object oState DataTables state
  16501. * @returns string JSON encoded cookie string for DataTables
  16502. * @private
  16503. */
  16504. "_fnStateSave": function ( oState )
  16505. {
  16506. var i, iLen, aCopy, iOrigColumn;
  16507. var oSettings = this.s.dt;
  16508. var columns = oSettings.aoColumns;
  16509. oState.ColReorder = [];
  16510. /* Sorting */
  16511. if ( oState.aaSorting ) {
  16512. // 1.10.0-
  16513. for ( i=0 ; i<oState.aaSorting.length ; i++ ) {
  16514. oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
  16515. }
  16516. var aSearchCopy = $.extend( true, [], oState.aoSearchCols );
  16517. for ( i=0, iLen=columns.length ; i<iLen ; i++ )
  16518. {
  16519. iOrigColumn = columns[i]._ColReorder_iOrigCol;
  16520. /* Column filter */
  16521. oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
  16522. /* Visibility */
  16523. oState.abVisCols[ iOrigColumn ] = columns[i].bVisible;
  16524. /* Column reordering */
  16525. oState.ColReorder.push( iOrigColumn );
  16526. }
  16527. }
  16528. else if ( oState.order ) {
  16529. // 1.10.1+
  16530. for ( i=0 ; i<oState.order.length ; i++ ) {
  16531. oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;
  16532. }
  16533. var stateColumnsCopy = $.extend( true, [], oState.columns );
  16534. for ( i=0, iLen=columns.length ; i<iLen ; i++ )
  16535. {
  16536. iOrigColumn = columns[i]._ColReorder_iOrigCol;
  16537. /* Columns */
  16538. oState.columns[ iOrigColumn ] = stateColumnsCopy[i];
  16539. /* Column reordering */
  16540. oState.ColReorder.push( iOrigColumn );
  16541. }
  16542. }
  16543. },
  16544. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16545. * Mouse drop and drag
  16546. */
  16547. /**
  16548. * Add a mouse down listener to a particluar TH element
  16549. * @method _fnMouseListener
  16550. * @param int i Column index
  16551. * @param element nTh TH element clicked on
  16552. * @returns void
  16553. * @private
  16554. */
  16555. "_fnMouseListener": function ( i, nTh )
  16556. {
  16557. var that = this;
  16558. $(nTh)
  16559. .on( 'mousedown.ColReorder', function (e) {
  16560. that._fnMouseDown.call( that, e, nTh );
  16561. } )
  16562. .on( 'touchstart.ColReorder', function (e) {
  16563. that._fnMouseDown.call( that, e, nTh );
  16564. } );
  16565. },
  16566. /**
  16567. * Mouse down on a TH element in the table header
  16568. * @method _fnMouseDown
  16569. * @param event e Mouse event
  16570. * @param element nTh TH element to be dragged
  16571. * @returns void
  16572. * @private
  16573. */
  16574. "_fnMouseDown": function ( e, nTh )
  16575. {
  16576. var that = this;
  16577. /* Store information about the mouse position */
  16578. var target = $(e.target).closest('th, td');
  16579. var offset = target.offset();
  16580. var idx = parseInt( $(nTh).attr('data-column-index'), 10 );
  16581. if ( idx === undefined ) {
  16582. return;
  16583. }
  16584. this.s.mouse.startX = this._fnCursorPosition( e, 'pageX' );
  16585. this.s.mouse.startY = this._fnCursorPosition( e, 'pageY' );
  16586. this.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left;
  16587. this.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top;
  16588. this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];
  16589. this.s.mouse.targetIndex = idx;
  16590. this.s.mouse.fromIndex = idx;
  16591. this._fnRegions();
  16592. /* Add event handlers to the document */
  16593. $(document)
  16594. .on( 'mousemove.ColReorder touchmove.ColReorder', function (e) {
  16595. that._fnMouseMove.call( that, e );
  16596. } )
  16597. .on( 'mouseup.ColReorder touchend.ColReorder', function (e) {
  16598. that._fnMouseUp.call( that, e );
  16599. } );
  16600. },
  16601. /**
  16602. * Deal with a mouse move event while dragging a node
  16603. * @method _fnMouseMove
  16604. * @param event e Mouse event
  16605. * @returns void
  16606. * @private
  16607. */
  16608. "_fnMouseMove": function ( e )
  16609. {
  16610. var that = this;
  16611. if ( this.dom.drag === null )
  16612. {
  16613. /* Only create the drag element if the mouse has moved a specific distance from the start
  16614. * point - this allows the user to make small mouse movements when sorting and not have a
  16615. * possibly confusing drag element showing up
  16616. */
  16617. if ( Math.pow(
  16618. Math.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) +
  16619. Math.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 )
  16620. {
  16621. return;
  16622. }
  16623. this._fnCreateDragNode();
  16624. }
  16625. /* Position the element - we respect where in the element the click occured */
  16626. this.dom.drag.css( {
  16627. left: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX,
  16628. top: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY
  16629. } );
  16630. /* Based on the current mouse position, calculate where the insert should go */
  16631. var bSet = false;
  16632. var lastToIndex = this.s.mouse.toIndex;
  16633. for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
  16634. {
  16635. if ( this._fnCursorPosition(e, 'pageX') < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
  16636. {
  16637. this.dom.pointer.css( 'left', this.s.aoTargets[i-1].x );
  16638. this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
  16639. bSet = true;
  16640. break;
  16641. }
  16642. }
  16643. // The insert element wasn't positioned in the array (less than
  16644. // operator), so we put it at the end
  16645. if ( !bSet )
  16646. {
  16647. this.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x );
  16648. this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
  16649. }
  16650. // Perform reordering if realtime updating is on and the column has moved
  16651. if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {
  16652. this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, false );
  16653. this.s.mouse.fromIndex = this.s.mouse.toIndex;
  16654. this._fnRegions();
  16655. }
  16656. },
  16657. /**
  16658. * Finish off the mouse drag and insert the column where needed
  16659. * @method _fnMouseUp
  16660. * @param event e Mouse event
  16661. * @returns void
  16662. * @private
  16663. */
  16664. "_fnMouseUp": function ( e )
  16665. {
  16666. var that = this;
  16667. $(document).off( '.ColReorder' );
  16668. if ( this.dom.drag !== null )
  16669. {
  16670. /* Remove the guide elements */
  16671. this.dom.drag.remove();
  16672. this.dom.pointer.remove();
  16673. this.dom.drag = null;
  16674. this.dom.pointer = null;
  16675. /* Actually do the reorder */
  16676. this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true );
  16677. this._fnSetColumnIndexes();
  16678. /* When scrolling we need to recalculate the column sizes to allow for the shift */
  16679. if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
  16680. {
  16681. this.s.dt.oInstance.fnAdjustColumnSizing( false );
  16682. }
  16683. /* Save the state */
  16684. this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
  16685. if ( this.s.reorderCallback !== null )
  16686. {
  16687. this.s.reorderCallback.call( this );
  16688. }
  16689. }
  16690. },
  16691. /**
  16692. * Calculate a cached array with the points of the column inserts, and the
  16693. * 'to' points
  16694. * @method _fnRegions
  16695. * @returns void
  16696. * @private
  16697. */
  16698. "_fnRegions": function ()
  16699. {
  16700. var aoColumns = this.s.dt.aoColumns;
  16701. this.s.aoTargets.splice( 0, this.s.aoTargets.length );
  16702. this.s.aoTargets.push( {
  16703. "x": $(this.s.dt.nTable).offset().left,
  16704. "to": 0
  16705. } );
  16706. var iToPoint = 0;
  16707. var total = this.s.aoTargets[0].x;
  16708. for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
  16709. {
  16710. /* For the column / header in question, we want it's position to remain the same if the
  16711. * position is just to it's immediate left or right, so we only increment the counter for
  16712. * other columns
  16713. */
  16714. if ( i != this.s.mouse.fromIndex )
  16715. {
  16716. iToPoint++;
  16717. }
  16718. if ( aoColumns[i].bVisible && aoColumns[i].nTh.style.display !=='none' )
  16719. {
  16720. total += $(aoColumns[i].nTh).outerWidth();
  16721. this.s.aoTargets.push( {
  16722. "x": total,
  16723. "to": iToPoint
  16724. } );
  16725. }
  16726. }
  16727. /* Disallow columns for being reordered by drag and drop, counting right to left */
  16728. if ( this.s.fixedRight !== 0 )
  16729. {
  16730. this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );
  16731. }
  16732. /* Disallow columns for being reordered by drag and drop, counting left to right */
  16733. if ( this.s.fixed !== 0 )
  16734. {
  16735. this.s.aoTargets.splice( 0, this.s.fixed );
  16736. }
  16737. },
  16738. /**
  16739. * Copy the TH element that is being drags so the user has the idea that they are actually
  16740. * moving it around the page.
  16741. * @method _fnCreateDragNode
  16742. * @returns void
  16743. * @private
  16744. */
  16745. "_fnCreateDragNode": function ()
  16746. {
  16747. var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "";
  16748. var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;
  16749. var origTr = origCell.parentNode;
  16750. var origThead = origTr.parentNode;
  16751. var origTable = origThead.parentNode;
  16752. var cloneCell = $(origCell).clone();
  16753. // This is a slightly odd combination of jQuery and DOM, but it is the
  16754. // fastest and least resource intensive way I could think of cloning
  16755. // the table with just a single header cell in it.
  16756. this.dom.drag = $(origTable.cloneNode(false))
  16757. .addClass( 'DTCR_clonedTable' )
  16758. .append(
  16759. $(origThead.cloneNode(false)).append(
  16760. $(origTr.cloneNode(false)).append(
  16761. cloneCell[0]
  16762. )
  16763. )
  16764. )
  16765. .css( {
  16766. position: 'absolute',
  16767. top: 0,
  16768. left: 0,
  16769. width: $(origCell).outerWidth(),
  16770. height: $(origCell).outerHeight()
  16771. } )
  16772. .appendTo( 'body' );
  16773. this.dom.pointer = $('<div></div>')
  16774. .addClass( 'DTCR_pointer' )
  16775. .css( {
  16776. position: 'absolute',
  16777. top: scrolling ?
  16778. $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :
  16779. $(this.s.dt.nTable).offset().top,
  16780. height : scrolling ?
  16781. $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :
  16782. $(this.s.dt.nTable).height()
  16783. } )
  16784. .appendTo( 'body' );
  16785. },
  16786. /**
  16787. * Add a data attribute to the column headers, so we know the index of
  16788. * the row to be reordered. This allows fast detection of the index, and
  16789. * for this plug-in to work with FixedHeader which clones the nodes.
  16790. * @private
  16791. */
  16792. "_fnSetColumnIndexes": function ()
  16793. {
  16794. $.each( this.s.dt.aoColumns, function (i, column) {
  16795. $(column.nTh).attr('data-column-index', i);
  16796. } );
  16797. },
  16798. /**
  16799. * Get cursor position regardless of mouse or touch input
  16800. * @param {Event} e jQuery Event
  16801. * @param {string} prop Property to get
  16802. * @return {number} Value
  16803. */
  16804. _fnCursorPosition: function ( e, prop ) {
  16805. if ( e.type.indexOf('touch') !== -1 ) {
  16806. return e.originalEvent.touches[0][ prop ];
  16807. }
  16808. return e[ prop ];
  16809. }
  16810. } );
  16811. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16812. * Static parameters
  16813. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16814. /**
  16815. * ColReorder default settings for initialisation
  16816. * @namespace
  16817. * @static
  16818. */
  16819. ColReorder.defaults = {
  16820. /**
  16821. * Predefined ordering for the columns that will be applied automatically
  16822. * on initialisation. If not specified then the order that the columns are
  16823. * found to be in the HTML is the order used.
  16824. * @type array
  16825. * @default null
  16826. * @static
  16827. */
  16828. aiOrder: null,
  16829. /**
  16830. * Redraw the table's column ordering as the end user draws the column
  16831. * (`true`) or wait until the mouse is released (`false` - default). Note
  16832. * that this will perform a redraw on each reordering, which involves an
  16833. * Ajax request each time if you are using server-side processing in
  16834. * DataTables.
  16835. * @type boolean
  16836. * @default false
  16837. * @static
  16838. */
  16839. bRealtime: true,
  16840. /**
  16841. * Indicate how many columns should be fixed in position (counting from the
  16842. * left). This will typically be 1 if used, but can be as high as you like.
  16843. * @type int
  16844. * @default 0
  16845. * @static
  16846. */
  16847. iFixedColumnsLeft: 0,
  16848. /**
  16849. * As `iFixedColumnsRight` but counting from the right.
  16850. * @type int
  16851. * @default 0
  16852. * @static
  16853. */
  16854. iFixedColumnsRight: 0,
  16855. /**
  16856. * Callback function that is fired when columns are reordered. The `column-
  16857. * reorder` event is preferred over this callback
  16858. * @type function():void
  16859. * @default null
  16860. * @static
  16861. */
  16862. fnReorderCallback: null
  16863. };
  16864. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16865. * Constants
  16866. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16867. /**
  16868. * ColReorder version
  16869. * @constant version
  16870. * @type String
  16871. * @default As code
  16872. */
  16873. ColReorder.version = "1.4.1";
  16874. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16875. * DataTables interfaces
  16876. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16877. // Expose
  16878. $.fn.dataTable.ColReorder = ColReorder;
  16879. $.fn.DataTable.ColReorder = ColReorder;
  16880. // Register a new feature with DataTables
  16881. if ( typeof $.fn.dataTable == "function" &&
  16882. typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
  16883. $.fn.dataTableExt.fnVersionCheck('1.10.8') )
  16884. {
  16885. $.fn.dataTableExt.aoFeatures.push( {
  16886. "fnInit": function( settings ) {
  16887. var table = settings.oInstance;
  16888. if ( ! settings._colReorder ) {
  16889. var dtInit = settings.oInit;
  16890. var opts = dtInit.colReorder || dtInit.oColReorder || {};
  16891. new ColReorder( settings, opts );
  16892. }
  16893. else {
  16894. table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
  16895. }
  16896. return null; /* No node for DataTables to insert */
  16897. },
  16898. "cFeature": "R",
  16899. "sFeature": "ColReorder"
  16900. } );
  16901. }
  16902. else {
  16903. alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download");
  16904. }
  16905. // Attach a listener to the document which listens for DataTables initialisation
  16906. // events so we can automatically initialise
  16907. $(document).on( 'preInit.dt.colReorder', function (e, settings) {
  16908. if ( e.namespace !== 'dt' ) {
  16909. return;
  16910. }
  16911. var init = settings.oInit.colReorder;
  16912. var defaults = DataTable.defaults.colReorder;
  16913. if ( init || defaults ) {
  16914. var opts = $.extend( {}, init, defaults );
  16915. if ( init !== false ) {
  16916. new ColReorder( settings, opts );
  16917. }
  16918. }
  16919. } );
  16920. // API augmentation
  16921. $.fn.dataTable.Api.register( 'colReorder.reset()', function () {
  16922. return this.iterator( 'table', function ( ctx ) {
  16923. ctx._colReorder.fnReset();
  16924. } );
  16925. } );
  16926. $.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) {
  16927. if ( set ) {
  16928. return this.iterator( 'table', function ( ctx ) {
  16929. ctx._colReorder.fnOrder( set, original );
  16930. } );
  16931. }
  16932. return this.context.length ?
  16933. this.context[0]._colReorder.fnOrder() :
  16934. null;
  16935. } );
  16936. $.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) {
  16937. return this.context.length && this.context[0]._colReorder ?
  16938. this.context[0]._colReorder.fnTranspose( idx, dir ) :
  16939. idx;
  16940. } );
  16941. $.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) {
  16942. if (this.context.length) {
  16943. this.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows );
  16944. }
  16945. return this;
  16946. } );
  16947. return ColReorder;
  16948. }));
  16949. /*! FixedColumns 3.2.4
  16950. * ©2010-2017 SpryMedia Ltd - datatables.net/license
  16951. */
  16952. /**
  16953. * @summary FixedColumns
  16954. * @description Freeze columns in place on a scrolling DataTable
  16955. * @version 3.2.4
  16956. * @file dataTables.fixedColumns.js
  16957. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  16958. * @contact www.sprymedia.co.uk/contact
  16959. * @copyright Copyright 2010-2017 SpryMedia Ltd.
  16960. *
  16961. * This source file is free software, available under the following license:
  16962. * MIT license - http://datatables.net/license/mit
  16963. *
  16964. * This source file is distributed in the hope that it will be useful, but
  16965. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16966. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  16967. *
  16968. * For details please refer to: http://www.datatables.net
  16969. */
  16970. (function( factory ){
  16971. if ( typeof define === 'function' && define.amd ) {
  16972. // AMD
  16973. define( ['jquery', 'datatables.net'], function ( $ ) {
  16974. return factory( $, window, document );
  16975. } );
  16976. }
  16977. else if ( typeof exports === 'object' ) {
  16978. // CommonJS
  16979. module.exports = function (root, $) {
  16980. if ( ! root ) {
  16981. root = window;
  16982. }
  16983. if ( ! $ || ! $.fn.dataTable ) {
  16984. $ = require('datatables.net')(root, $).$;
  16985. }
  16986. return factory( $, root, root.document );
  16987. };
  16988. }
  16989. else {
  16990. // Browser
  16991. factory( jQuery, window, document );
  16992. }
  16993. }(function( $, window, document, undefined ) {
  16994. 'use strict';
  16995. var DataTable = $.fn.dataTable;
  16996. var _firefoxScroll;
  16997. /**
  16998. * When making use of DataTables' x-axis scrolling feature, you may wish to
  16999. * fix the left most column in place. This plug-in for DataTables provides
  17000. * exactly this option (note for non-scrolling tables, please use the
  17001. * FixedHeader plug-in, which can fix headers and footers). Key
  17002. * features include:
  17003. *
  17004. * * Freezes the left or right most columns to the side of the table
  17005. * * Option to freeze two or more columns
  17006. * * Full integration with DataTables' scrolling options
  17007. * * Speed - FixedColumns is fast in its operation
  17008. *
  17009. * @class
  17010. * @constructor
  17011. * @global
  17012. * @param {object} dt DataTables instance. With DataTables 1.10 this can also
  17013. * be a jQuery collection, a jQuery selector, DataTables API instance or
  17014. * settings object.
  17015. * @param {object} [init={}] Configuration object for FixedColumns. Options are
  17016. * defined by {@link FixedColumns.defaults}
  17017. *
  17018. * @requires jQuery 1.7+
  17019. * @requires DataTables 1.8.0+
  17020. *
  17021. * @example
  17022. * var table = $('#example').dataTable( {
  17023. * "scrollX": "100%"
  17024. * } );
  17025. * new $.fn.dataTable.fixedColumns( table );
  17026. */
  17027. var FixedColumns = function ( dt, init ) {
  17028. var that = this;
  17029. /* Sanity check - you just know it will happen */
  17030. if ( ! ( this instanceof FixedColumns ) ) {
  17031. alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." );
  17032. return;
  17033. }
  17034. if ( init === undefined || init === true ) {
  17035. init = {};
  17036. }
  17037. // Use the DataTables Hungarian notation mapping method, if it exists to
  17038. // provide forwards compatibility for camel case variables
  17039. var camelToHungarian = $.fn.dataTable.camelToHungarian;
  17040. if ( camelToHungarian ) {
  17041. camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );
  17042. camelToHungarian( FixedColumns.defaults, init );
  17043. }
  17044. // v1.10 allows the settings object to be got form a number of sources
  17045. var dtSettings = new $.fn.dataTable.Api( dt ).settings()[0];
  17046. /**
  17047. * Settings object which contains customisable information for FixedColumns instance
  17048. * @namespace
  17049. * @extends FixedColumns.defaults
  17050. * @private
  17051. */
  17052. this.s = {
  17053. /**
  17054. * DataTables settings objects
  17055. * @type object
  17056. * @default Obtained from DataTables instance
  17057. */
  17058. "dt": dtSettings,
  17059. /**
  17060. * Number of columns in the DataTable - stored for quick access
  17061. * @type int
  17062. * @default Obtained from DataTables instance
  17063. */
  17064. "iTableColumns": dtSettings.aoColumns.length,
  17065. /**
  17066. * Original outer widths of the columns as rendered by DataTables - used to calculate
  17067. * the FixedColumns grid bounding box
  17068. * @type array.<int>
  17069. * @default []
  17070. */
  17071. "aiOuterWidths": [],
  17072. /**
  17073. * Original inner widths of the columns as rendered by DataTables - used to apply widths
  17074. * to the columns
  17075. * @type array.<int>
  17076. * @default []
  17077. */
  17078. "aiInnerWidths": [],
  17079. /**
  17080. * Is the document layout right-to-left
  17081. * @type boolean
  17082. */
  17083. rtl: $(dtSettings.nTable).css('direction') === 'rtl'
  17084. };
  17085. /**
  17086. * DOM elements used by the class instance
  17087. * @namespace
  17088. * @private
  17089. *
  17090. */
  17091. this.dom = {
  17092. /**
  17093. * DataTables scrolling element
  17094. * @type node
  17095. * @default null
  17096. */
  17097. "scroller": null,
  17098. /**
  17099. * DataTables header table
  17100. * @type node
  17101. * @default null
  17102. */
  17103. "header": null,
  17104. /**
  17105. * DataTables body table
  17106. * @type node
  17107. * @default null
  17108. */
  17109. "body": null,
  17110. /**
  17111. * DataTables footer table
  17112. * @type node
  17113. * @default null
  17114. */
  17115. "footer": null,
  17116. /**
  17117. * Display grid elements
  17118. * @namespace
  17119. */
  17120. "grid": {
  17121. /**
  17122. * Grid wrapper. This is the container element for the 3x3 grid
  17123. * @type node
  17124. * @default null
  17125. */
  17126. "wrapper": null,
  17127. /**
  17128. * DataTables scrolling element. This element is the DataTables
  17129. * component in the display grid (making up the main table - i.e.
  17130. * not the fixed columns).
  17131. * @type node
  17132. * @default null
  17133. */
  17134. "dt": null,
  17135. /**
  17136. * Left fixed column grid components
  17137. * @namespace
  17138. */
  17139. "left": {
  17140. "wrapper": null,
  17141. "head": null,
  17142. "body": null,
  17143. "foot": null
  17144. },
  17145. /**
  17146. * Right fixed column grid components
  17147. * @namespace
  17148. */
  17149. "right": {
  17150. "wrapper": null,
  17151. "head": null,
  17152. "body": null,
  17153. "foot": null
  17154. }
  17155. },
  17156. /**
  17157. * Cloned table nodes
  17158. * @namespace
  17159. */
  17160. "clone": {
  17161. /**
  17162. * Left column cloned table nodes
  17163. * @namespace
  17164. */
  17165. "left": {
  17166. /**
  17167. * Cloned header table
  17168. * @type node
  17169. * @default null
  17170. */
  17171. "header": null,
  17172. /**
  17173. * Cloned body table
  17174. * @type node
  17175. * @default null
  17176. */
  17177. "body": null,
  17178. /**
  17179. * Cloned footer table
  17180. * @type node
  17181. * @default null
  17182. */
  17183. "footer": null
  17184. },
  17185. /**
  17186. * Right column cloned table nodes
  17187. * @namespace
  17188. */
  17189. "right": {
  17190. /**
  17191. * Cloned header table
  17192. * @type node
  17193. * @default null
  17194. */
  17195. "header": null,
  17196. /**
  17197. * Cloned body table
  17198. * @type node
  17199. * @default null
  17200. */
  17201. "body": null,
  17202. /**
  17203. * Cloned footer table
  17204. * @type node
  17205. * @default null
  17206. */
  17207. "footer": null
  17208. }
  17209. }
  17210. };
  17211. if ( dtSettings._oFixedColumns ) {
  17212. throw 'FixedColumns already initialised on this table';
  17213. }
  17214. /* Attach the instance to the DataTables instance so it can be accessed easily */
  17215. dtSettings._oFixedColumns = this;
  17216. /* Let's do it */
  17217. if ( ! dtSettings._bInitComplete )
  17218. {
  17219. dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {
  17220. that._fnConstruct( init );
  17221. }, 'FixedColumns' );
  17222. }
  17223. else
  17224. {
  17225. this._fnConstruct( init );
  17226. }
  17227. };
  17228. $.extend( FixedColumns.prototype , {
  17229. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17230. * Public methods
  17231. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  17232. /**
  17233. * Update the fixed columns - including headers and footers. Note that FixedColumns will
  17234. * automatically update the display whenever the host DataTable redraws.
  17235. * @returns {void}
  17236. * @example
  17237. * var table = $('#example').dataTable( {
  17238. * "scrollX": "100%"
  17239. * } );
  17240. * var fc = new $.fn.dataTable.fixedColumns( table );
  17241. *
  17242. * // at some later point when the table has been manipulated....
  17243. * fc.fnUpdate();
  17244. */
  17245. "fnUpdate": function ()
  17246. {
  17247. this._fnDraw( true );
  17248. },
  17249. /**
  17250. * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.
  17251. * This is useful if you update the width of the table container. Note that FixedColumns will
  17252. * perform this function automatically when the window.resize event is fired.
  17253. * @returns {void}
  17254. * @example
  17255. * var table = $('#example').dataTable( {
  17256. * "scrollX": "100%"
  17257. * } );
  17258. * var fc = new $.fn.dataTable.fixedColumns( table );
  17259. *
  17260. * // Resize the table container and then have FixedColumns adjust its layout....
  17261. * $('#content').width( 1200 );
  17262. * fc.fnRedrawLayout();
  17263. */
  17264. "fnRedrawLayout": function ()
  17265. {
  17266. this._fnColCalc();
  17267. this._fnGridLayout();
  17268. this.fnUpdate();
  17269. },
  17270. /**
  17271. * Mark a row such that it's height should be recalculated when using 'semiauto' row
  17272. * height matching. This function will have no effect when 'none' or 'auto' row height
  17273. * matching is used.
  17274. * @param {Node} nTr TR element that should have it's height recalculated
  17275. * @returns {void}
  17276. * @example
  17277. * var table = $('#example').dataTable( {
  17278. * "scrollX": "100%"
  17279. * } );
  17280. * var fc = new $.fn.dataTable.fixedColumns( table );
  17281. *
  17282. * // manipulate the table - mark the row as needing an update then update the table
  17283. * // this allows the redraw performed by DataTables fnUpdate to recalculate the row
  17284. * // height
  17285. * fc.fnRecalculateHeight();
  17286. * table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
  17287. */
  17288. "fnRecalculateHeight": function ( nTr )
  17289. {
  17290. delete nTr._DTTC_iHeight;
  17291. nTr.style.height = 'auto';
  17292. },
  17293. /**
  17294. * Set the height of a given row - provides cross browser compatibility
  17295. * @param {Node} nTarget TR element that should have it's height recalculated
  17296. * @param {int} iHeight Height in pixels to set
  17297. * @returns {void}
  17298. * @example
  17299. * var table = $('#example').dataTable( {
  17300. * "scrollX": "100%"
  17301. * } );
  17302. * var fc = new $.fn.dataTable.fixedColumns( table );
  17303. *
  17304. * // You may want to do this after manipulating a row in the fixed column
  17305. * fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
  17306. */
  17307. "fnSetRowHeight": function ( nTarget, iHeight )
  17308. {
  17309. nTarget.style.height = iHeight+"px";
  17310. },
  17311. /**
  17312. * Get data index information about a row or cell in the table body.
  17313. * This function is functionally identical to fnGetPosition in DataTables,
  17314. * taking the same parameter (TH, TD or TR node) and returning exactly the
  17315. * the same information (data index information). THe difference between
  17316. * the two is that this method takes into account the fixed columns in the
  17317. * table, so you can pass in nodes from the master table, or the cloned
  17318. * tables and get the index position for the data in the main table.
  17319. * @param {node} node TR, TH or TD element to get the information about
  17320. * @returns {int} If nNode is given as a TR, then a single index is
  17321. * returned, or if given as a cell, an array of [row index, column index
  17322. * (visible), column index (all)] is given.
  17323. */
  17324. "fnGetPosition": function ( node )
  17325. {
  17326. var idx;
  17327. var inst = this.s.dt.oInstance;
  17328. if ( ! $(node).parents('.DTFC_Cloned').length )
  17329. {
  17330. // Not in a cloned table
  17331. return inst.fnGetPosition( node );
  17332. }
  17333. else
  17334. {
  17335. // Its in the cloned table, so need to look up position
  17336. if ( node.nodeName.toLowerCase() === 'tr' ) {
  17337. idx = $(node).index();
  17338. return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
  17339. }
  17340. else
  17341. {
  17342. var colIdx = $(node).index();
  17343. idx = $(node.parentNode).index();
  17344. var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
  17345. return [
  17346. row,
  17347. colIdx,
  17348. inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )
  17349. ];
  17350. }
  17351. }
  17352. },
  17353. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17354. * Private methods (they are of course public in JS, but recommended as private)
  17355. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  17356. /**
  17357. * Initialisation for FixedColumns
  17358. * @param {Object} oInit User settings for initialisation
  17359. * @returns {void}
  17360. * @private
  17361. */
  17362. "_fnConstruct": function ( oInit )
  17363. {
  17364. var i, iLen, iWidth,
  17365. that = this;
  17366. /* Sanity checking */
  17367. if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||
  17368. this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )
  17369. {
  17370. alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+
  17371. "Please upgrade your DataTables installation" );
  17372. return;
  17373. }
  17374. if ( this.s.dt.oScroll.sX === "" )
  17375. {
  17376. this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+
  17377. "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+
  17378. "column fixing when scrolling is not enabled" );
  17379. return;
  17380. }
  17381. /* Apply the settings from the user / defaults */
  17382. this.s = $.extend( true, this.s, FixedColumns.defaults, oInit );
  17383. /* Set up the DOM as we need it and cache nodes */
  17384. var classes = this.s.dt.oClasses;
  17385. this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];
  17386. this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];
  17387. /* Set up the DOM that we want for the fixed column layout grid */
  17388. this._fnColCalc();
  17389. this._fnGridSetup();
  17390. /* Event handlers */
  17391. var mouseController;
  17392. var mouseDown = false;
  17393. // When the mouse is down (drag scroll) the mouse controller cannot
  17394. // change, as the browser keeps the original element as the scrolling one
  17395. $(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function (e) {
  17396. if ( e.button === 0 ) {
  17397. mouseDown = true;
  17398. $(document).one( 'mouseup', function () {
  17399. mouseDown = false;
  17400. } );
  17401. }
  17402. } );
  17403. // When the body is scrolled - scroll the left and right columns
  17404. $(this.dom.scroller)
  17405. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  17406. if ( ! mouseDown ) {
  17407. mouseController = 'main';
  17408. }
  17409. } )
  17410. .on( 'scroll.DTFC', function (e) {
  17411. if ( ! mouseController && e.originalEvent ) {
  17412. mouseController = 'main';
  17413. }
  17414. if ( mouseController === 'main' ) {
  17415. if ( that.s.iLeftColumns > 0 ) {
  17416. that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;
  17417. }
  17418. if ( that.s.iRightColumns > 0 ) {
  17419. that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;
  17420. }
  17421. }
  17422. } );
  17423. var wheelType = 'onwheel' in document.createElement('div') ?
  17424. 'wheel.DTFC' :
  17425. 'mousewheel.DTFC';
  17426. if ( that.s.iLeftColumns > 0 ) {
  17427. // When scrolling the left column, scroll the body and right column
  17428. $(that.dom.grid.left.liner)
  17429. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  17430. if ( ! mouseDown ) {
  17431. mouseController = 'left';
  17432. }
  17433. } )
  17434. .on( 'scroll.DTFC', function ( e ) {
  17435. if ( ! mouseController && e.originalEvent ) {
  17436. mouseController = 'left';
  17437. }
  17438. if ( mouseController === 'left' ) {
  17439. that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;
  17440. if ( that.s.iRightColumns > 0 ) {
  17441. that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;
  17442. }
  17443. }
  17444. } )
  17445. .on( wheelType, function(e) {
  17446. // Pass horizontal scrolling through
  17447. var xDelta = e.type === 'wheel' ?
  17448. -e.originalEvent.deltaX :
  17449. e.originalEvent.wheelDeltaX;
  17450. that.dom.scroller.scrollLeft -= xDelta;
  17451. } );
  17452. }
  17453. if ( that.s.iRightColumns > 0 ) {
  17454. // When scrolling the right column, scroll the body and the left column
  17455. $(that.dom.grid.right.liner)
  17456. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  17457. if ( ! mouseDown ) {
  17458. mouseController = 'right';
  17459. }
  17460. } )
  17461. .on( 'scroll.DTFC', function ( e ) {
  17462. if ( ! mouseController && e.originalEvent ) {
  17463. mouseController = 'right';
  17464. }
  17465. if ( mouseController === 'right' ) {
  17466. that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;
  17467. if ( that.s.iLeftColumns > 0 ) {
  17468. that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;
  17469. }
  17470. }
  17471. } )
  17472. .on( wheelType, function(e) {
  17473. // Pass horizontal scrolling through
  17474. var xDelta = e.type === 'wheel' ?
  17475. -e.originalEvent.deltaX :
  17476. e.originalEvent.wheelDeltaX;
  17477. that.dom.scroller.scrollLeft -= xDelta;
  17478. } );
  17479. }
  17480. $(window).on( 'resize.DTFC', function () {
  17481. that._fnGridLayout.call( that );
  17482. } );
  17483. var bFirstDraw = true;
  17484. var jqTable = $(this.s.dt.nTable);
  17485. jqTable
  17486. .on( 'draw.dt.DTFC', function () {
  17487. that._fnColCalc();
  17488. that._fnDraw.call( that, bFirstDraw );
  17489. bFirstDraw = false;
  17490. } )
  17491. .on( 'column-sizing.dt.DTFC', function () {
  17492. that._fnColCalc();
  17493. that._fnGridLayout( that );
  17494. } )
  17495. .on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) {
  17496. if ( recalc === undefined || recalc ) {
  17497. that._fnColCalc();
  17498. that._fnGridLayout( that );
  17499. that._fnDraw( true );
  17500. }
  17501. } )
  17502. .on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) {
  17503. if ( e.namespace === 'dt' ) {
  17504. that._fnDraw( false );
  17505. }
  17506. } )
  17507. .on( 'destroy.dt.DTFC', function () {
  17508. jqTable.off( '.DTFC' );
  17509. $(that.dom.scroller).off( '.DTFC' );
  17510. $(window).off( '.DTFC' );
  17511. $(that.s.dt.nTableWrapper).off( '.DTFC' );
  17512. $(that.dom.grid.left.liner).off( '.DTFC '+wheelType );
  17513. $(that.dom.grid.left.wrapper).remove();
  17514. $(that.dom.grid.right.liner).off( '.DTFC '+wheelType );
  17515. $(that.dom.grid.right.wrapper).remove();
  17516. } );
  17517. /* Get things right to start with - note that due to adjusting the columns, there must be
  17518. * another redraw of the main table. It doesn't need to be a full redraw however.
  17519. */
  17520. this._fnGridLayout();
  17521. this.s.dt.oInstance.fnDraw(false);
  17522. },
  17523. /**
  17524. * Calculate the column widths for the grid layout
  17525. * @returns {void}
  17526. * @private
  17527. */
  17528. "_fnColCalc": function ()
  17529. {
  17530. var that = this;
  17531. var iLeftWidth = 0;
  17532. var iRightWidth = 0;
  17533. this.s.aiInnerWidths = [];
  17534. this.s.aiOuterWidths = [];
  17535. $.each( this.s.dt.aoColumns, function (i, col) {
  17536. var th = $(col.nTh);
  17537. var border;
  17538. if ( ! th.filter(':visible').length ) {
  17539. that.s.aiInnerWidths.push( 0 );
  17540. that.s.aiOuterWidths.push( 0 );
  17541. }
  17542. else
  17543. {
  17544. // Inner width is used to assign widths to cells
  17545. // Outer width is used to calculate the container
  17546. var iWidth = th.outerWidth();
  17547. // When working with the left most-cell, need to add on the
  17548. // table's border to the outerWidth, since we need to take
  17549. // account of it, but it isn't in any cell
  17550. if ( that.s.aiOuterWidths.length === 0 ) {
  17551. border = $(that.s.dt.nTable).css('border-left-width');
  17552. iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
  17553. 1 :
  17554. parseInt( border, 10 );
  17555. }
  17556. // Likewise with the final column on the right
  17557. if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {
  17558. border = $(that.s.dt.nTable).css('border-right-width');
  17559. iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
  17560. 1 :
  17561. parseInt( border, 10 );
  17562. }
  17563. that.s.aiOuterWidths.push( iWidth );
  17564. that.s.aiInnerWidths.push( th.width() );
  17565. if ( i < that.s.iLeftColumns )
  17566. {
  17567. iLeftWidth += iWidth;
  17568. }
  17569. if ( that.s.iTableColumns-that.s.iRightColumns <= i )
  17570. {
  17571. iRightWidth += iWidth;
  17572. }
  17573. }
  17574. } );
  17575. this.s.iLeftWidth = iLeftWidth;
  17576. this.s.iRightWidth = iRightWidth;
  17577. },
  17578. /**
  17579. * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid
  17580. * for the left column, the DataTable (for which we just reuse the scrolling element DataTable
  17581. * puts into the DOM) and the right column. In each of he two fixed column elements there is a
  17582. * grouping wrapper element and then a head, body and footer wrapper. In each of these we then
  17583. * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.
  17584. * @returns {void}
  17585. * @private
  17586. */
  17587. "_fnGridSetup": function ()
  17588. {
  17589. var that = this;
  17590. var oOverflow = this._fnDTOverflow();
  17591. var block;
  17592. this.dom.body = this.s.dt.nTable;
  17593. this.dom.header = this.s.dt.nTHead.parentNode;
  17594. this.dom.header.parentNode.parentNode.style.position = "relative";
  17595. var nSWrapper =
  17596. $('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;">'+
  17597. '<div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;" aria-hidden="true">'+
  17598. '<div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
  17599. '<div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
  17600. '<div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
  17601. '</div>'+
  17602. '<div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
  17603. '</div>'+
  17604. '<div class="DTFC_RightWrapper" style="position:absolute; top:0; right:0;" aria-hidden="true">'+
  17605. '<div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;">'+
  17606. '<div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
  17607. '</div>'+
  17608. '<div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
  17609. '<div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
  17610. '</div>'+
  17611. '<div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;">'+
  17612. '<div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
  17613. '</div>'+
  17614. '</div>'+
  17615. '</div>')[0];
  17616. var nLeft = nSWrapper.childNodes[0];
  17617. var nRight = nSWrapper.childNodes[1];
  17618. this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );
  17619. nSWrapper.appendChild( this.dom.grid.dt );
  17620. this.dom.grid.wrapper = nSWrapper;
  17621. if ( this.s.iLeftColumns > 0 )
  17622. {
  17623. this.dom.grid.left.wrapper = nLeft;
  17624. this.dom.grid.left.head = nLeft.childNodes[0];
  17625. this.dom.grid.left.body = nLeft.childNodes[1];
  17626. this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];
  17627. nSWrapper.appendChild( nLeft );
  17628. }
  17629. if ( this.s.iRightColumns > 0 )
  17630. {
  17631. this.dom.grid.right.wrapper = nRight;
  17632. this.dom.grid.right.head = nRight.childNodes[0];
  17633. this.dom.grid.right.body = nRight.childNodes[1];
  17634. this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];
  17635. nRight.style.right = oOverflow.bar+"px";
  17636. block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];
  17637. block.style.width = oOverflow.bar+"px";
  17638. block.style.right = -oOverflow.bar+"px";
  17639. this.dom.grid.right.headBlock = block;
  17640. block = $('div.DTFC_RightFootBlocker', nSWrapper)[0];
  17641. block.style.width = oOverflow.bar+"px";
  17642. block.style.right = -oOverflow.bar+"px";
  17643. this.dom.grid.right.footBlock = block;
  17644. nSWrapper.appendChild( nRight );
  17645. }
  17646. if ( this.s.dt.nTFoot )
  17647. {
  17648. this.dom.footer = this.s.dt.nTFoot.parentNode;
  17649. if ( this.s.iLeftColumns > 0 )
  17650. {
  17651. this.dom.grid.left.foot = nLeft.childNodes[2];
  17652. }
  17653. if ( this.s.iRightColumns > 0 )
  17654. {
  17655. this.dom.grid.right.foot = nRight.childNodes[2];
  17656. }
  17657. }
  17658. // RTL support - swap the position of the left and right columns (#48)
  17659. if ( this.s.rtl ) {
  17660. $('div.DTFC_RightHeadBlocker', nSWrapper).css( {
  17661. left: -oOverflow.bar+'px',
  17662. right: ''
  17663. } );
  17664. }
  17665. },
  17666. /**
  17667. * Style and position the grid used for the FixedColumns layout
  17668. * @returns {void}
  17669. * @private
  17670. */
  17671. "_fnGridLayout": function ()
  17672. {
  17673. var that = this;
  17674. var oGrid = this.dom.grid;
  17675. var iWidth = $(oGrid.wrapper).width();
  17676. var iBodyHeight = this.s.dt.nTable.parentNode.offsetHeight;
  17677. var iFullHeight = this.s.dt.nTable.parentNode.parentNode.offsetHeight;
  17678. var oOverflow = this._fnDTOverflow();
  17679. var iLeftWidth = this.s.iLeftWidth;
  17680. var iRightWidth = this.s.iRightWidth;
  17681. var rtl = $(this.dom.body).css('direction') === 'rtl';
  17682. var wrapper;
  17683. var scrollbarAdjust = function ( node, width ) {
  17684. if ( ! oOverflow.bar ) {
  17685. // If there is no scrollbar (Macs) we need to hide the auto scrollbar
  17686. node.style.width = (width+20)+"px";
  17687. node.style.paddingRight = "20px";
  17688. node.style.boxSizing = "border-box";
  17689. }
  17690. else if ( that._firefoxScrollError() ) {
  17691. // See the above function for why this is required
  17692. if ( $(node).height() > 34 ) {
  17693. node.style.width = (width+oOverflow.bar)+"px";
  17694. }
  17695. }
  17696. else {
  17697. // Otherwise just overflow by the scrollbar
  17698. node.style.width = (width+oOverflow.bar)+"px";
  17699. }
  17700. };
  17701. // When x scrolling - don't paint the fixed columns over the x scrollbar
  17702. if ( oOverflow.x )
  17703. {
  17704. iBodyHeight -= oOverflow.bar;
  17705. }
  17706. oGrid.wrapper.style.height = iFullHeight+"px";
  17707. if ( this.s.iLeftColumns > 0 )
  17708. {
  17709. wrapper = oGrid.left.wrapper;
  17710. wrapper.style.width = iLeftWidth+'px';
  17711. wrapper.style.height = '1px';
  17712. // Swap the position of the left and right columns for rtl (#48)
  17713. // This is always up against the edge, scrollbar on the far side
  17714. if ( rtl ) {
  17715. wrapper.style.left = '';
  17716. wrapper.style.right = 0;
  17717. }
  17718. else {
  17719. wrapper.style.left = 0;
  17720. wrapper.style.right = '';
  17721. }
  17722. oGrid.left.body.style.height = iBodyHeight+"px";
  17723. if ( oGrid.left.foot ) {
  17724. oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar
  17725. }
  17726. scrollbarAdjust( oGrid.left.liner, iLeftWidth );
  17727. oGrid.left.liner.style.height = iBodyHeight+"px";
  17728. oGrid.left.liner.style.maxHeight = iBodyHeight+"px";
  17729. }
  17730. if ( this.s.iRightColumns > 0 )
  17731. {
  17732. wrapper = oGrid.right.wrapper;
  17733. wrapper.style.width = iRightWidth+'px';
  17734. wrapper.style.height = '1px';
  17735. // Need to take account of the vertical scrollbar
  17736. if ( this.s.rtl ) {
  17737. wrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0;
  17738. wrapper.style.right = '';
  17739. }
  17740. else {
  17741. wrapper.style.left = '';
  17742. wrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0;
  17743. }
  17744. oGrid.right.body.style.height = iBodyHeight+"px";
  17745. if ( oGrid.right.foot ) {
  17746. oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px";
  17747. }
  17748. scrollbarAdjust( oGrid.right.liner, iRightWidth );
  17749. oGrid.right.liner.style.height = iBodyHeight+"px";
  17750. oGrid.right.liner.style.maxHeight = iBodyHeight+"px";
  17751. oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';
  17752. oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';
  17753. }
  17754. },
  17755. /**
  17756. * Get information about the DataTable's scrolling state - specifically if the table is scrolling
  17757. * on either the x or y axis, and also the scrollbar width.
  17758. * @returns {object} Information about the DataTables scrolling state with the properties:
  17759. * 'x', 'y' and 'bar'
  17760. * @private
  17761. */
  17762. "_fnDTOverflow": function ()
  17763. {
  17764. var nTable = this.s.dt.nTable;
  17765. var nTableScrollBody = nTable.parentNode;
  17766. var out = {
  17767. "x": false,
  17768. "y": false,
  17769. "bar": this.s.dt.oScroll.iBarWidth
  17770. };
  17771. if ( nTable.offsetWidth > nTableScrollBody.clientWidth )
  17772. {
  17773. out.x = true;
  17774. }
  17775. if ( nTable.offsetHeight > nTableScrollBody.clientHeight )
  17776. {
  17777. out.y = true;
  17778. }
  17779. return out;
  17780. },
  17781. /**
  17782. * Clone and position the fixed columns
  17783. * @returns {void}
  17784. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  17785. * @private
  17786. */
  17787. "_fnDraw": function ( bAll )
  17788. {
  17789. this._fnGridLayout();
  17790. this._fnCloneLeft( bAll );
  17791. this._fnCloneRight( bAll );
  17792. /* Draw callback function */
  17793. if ( this.s.fnDrawCallback !== null )
  17794. {
  17795. this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );
  17796. }
  17797. /* Event triggering */
  17798. $(this).trigger( 'draw.dtfc', {
  17799. "leftClone": this.dom.clone.left,
  17800. "rightClone": this.dom.clone.right
  17801. } );
  17802. },
  17803. /**
  17804. * Clone the right columns
  17805. * @returns {void}
  17806. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  17807. * @private
  17808. */
  17809. "_fnCloneRight": function ( bAll )
  17810. {
  17811. if ( this.s.iRightColumns <= 0 ) {
  17812. return;
  17813. }
  17814. var that = this,
  17815. i, jq,
  17816. aiColumns = [];
  17817. for ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {
  17818. if ( this.s.dt.aoColumns[i].bVisible ) {
  17819. aiColumns.push( i );
  17820. }
  17821. }
  17822. this._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );
  17823. },
  17824. /**
  17825. * Clone the left columns
  17826. * @returns {void}
  17827. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  17828. * @private
  17829. */
  17830. "_fnCloneLeft": function ( bAll )
  17831. {
  17832. if ( this.s.iLeftColumns <= 0 ) {
  17833. return;
  17834. }
  17835. var that = this,
  17836. i, jq,
  17837. aiColumns = [];
  17838. for ( i=0 ; i<this.s.iLeftColumns ; i++ ) {
  17839. if ( this.s.dt.aoColumns[i].bVisible ) {
  17840. aiColumns.push( i );
  17841. }
  17842. }
  17843. this._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );
  17844. },
  17845. /**
  17846. * Make a copy of the layout object for a header or footer element from DataTables. Note that
  17847. * this method will clone the nodes in the layout object.
  17848. * @returns {Array} Copy of the layout array
  17849. * @param {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)
  17850. * @param {Object} aiColumns Columns to copy
  17851. * @param {boolean} events Copy cell events or not
  17852. * @private
  17853. */
  17854. "_fnCopyLayout": function ( aoOriginal, aiColumns, events )
  17855. {
  17856. var aReturn = [];
  17857. var aClones = [];
  17858. var aCloned = [];
  17859. for ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )
  17860. {
  17861. var aRow = [];
  17862. aRow.nTr = $(aoOriginal[i].nTr).clone(events, false)[0];
  17863. for ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )
  17864. {
  17865. if ( $.inArray( j, aiColumns ) === -1 )
  17866. {
  17867. continue;
  17868. }
  17869. var iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );
  17870. if ( iCloned === -1 )
  17871. {
  17872. var nClone = $(aoOriginal[i][j].cell).clone(events, false)[0];
  17873. aClones.push( nClone );
  17874. aCloned.push( aoOriginal[i][j].cell );
  17875. aRow.push( {
  17876. "cell": nClone,
  17877. "unique": aoOriginal[i][j].unique
  17878. } );
  17879. }
  17880. else
  17881. {
  17882. aRow.push( {
  17883. "cell": aClones[ iCloned ],
  17884. "unique": aoOriginal[i][j].unique
  17885. } );
  17886. }
  17887. }
  17888. aReturn.push( aRow );
  17889. }
  17890. return aReturn;
  17891. },
  17892. /**
  17893. * Clone the DataTable nodes and place them in the DOM (sized correctly)
  17894. * @returns {void}
  17895. * @param {Object} oClone Object containing the header, footer and body cloned DOM elements
  17896. * @param {Object} oGrid Grid object containing the display grid elements for the cloned
  17897. * column (left or right)
  17898. * @param {Array} aiColumns Column indexes which should be operated on from the DataTable
  17899. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  17900. * @private
  17901. */
  17902. "_fnClone": function ( oClone, oGrid, aiColumns, bAll )
  17903. {
  17904. var that = this,
  17905. i, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,
  17906. jqCloneThead, aoFixedHeader,
  17907. dt = this.s.dt;
  17908. /*
  17909. * Header
  17910. */
  17911. if ( bAll )
  17912. {
  17913. $(oClone.header).remove();
  17914. oClone.header = $(this.dom.header).clone(true, false)[0];
  17915. oClone.header.className += " DTFC_Cloned";
  17916. oClone.header.style.width = "100%";
  17917. oGrid.head.appendChild( oClone.header );
  17918. /* Copy the DataTables layout cache for the header for our floating column */
  17919. aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, true );
  17920. jqCloneThead = $('>thead', oClone.header);
  17921. jqCloneThead.empty();
  17922. /* Add the created cloned TR elements to the table */
  17923. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  17924. {
  17925. jqCloneThead[0].appendChild( aoCloneLayout[i].nTr );
  17926. }
  17927. /* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan
  17928. * calculations for us
  17929. */
  17930. dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
  17931. }
  17932. else
  17933. {
  17934. /* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows
  17935. * etc, we make a copy of the header from the DataTable again, but don't insert the
  17936. * cloned cells, just copy the classes across. To get the matching layout for the
  17937. * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping
  17938. */
  17939. aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, false );
  17940. aoFixedHeader=[];
  17941. dt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );
  17942. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  17943. {
  17944. for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
  17945. {
  17946. aoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;
  17947. // If jQuery UI theming is used we need to copy those elements as well
  17948. $('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {
  17949. this.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;
  17950. } );
  17951. }
  17952. }
  17953. }
  17954. this._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );
  17955. /*
  17956. * Body
  17957. */
  17958. if ( this.s.sHeightMatch == 'auto' )
  17959. {
  17960. /* Remove any heights which have been applied already and let the browser figure it out */
  17961. $('>tbody>tr', that.dom.body).css('height', 'auto');
  17962. }
  17963. if ( oClone.body !== null )
  17964. {
  17965. $(oClone.body).remove();
  17966. oClone.body = null;
  17967. }
  17968. oClone.body = $(this.dom.body).clone(true)[0];
  17969. oClone.body.className += " DTFC_Cloned";
  17970. oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px";
  17971. oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */
  17972. if ( oClone.body.getAttribute('id') !== null )
  17973. {
  17974. oClone.body.removeAttribute('id');
  17975. }
  17976. $('>thead>tr', oClone.body).empty();
  17977. $('>tfoot', oClone.body).remove();
  17978. var nBody = $('tbody', oClone.body)[0];
  17979. $(nBody).empty();
  17980. if ( dt.aiDisplay.length > 0 )
  17981. {
  17982. /* Copy the DataTables' header elements to force the column width in exactly the
  17983. * same way that DataTables does it - have the header element, apply the width and
  17984. * colapse it down
  17985. */
  17986. var nInnerThead = $('>thead>tr', oClone.body)[0];
  17987. for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
  17988. {
  17989. iColumn = aiColumns[iIndex];
  17990. nClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];
  17991. nClone.innerHTML = "";
  17992. var oStyle = nClone.style;
  17993. oStyle.paddingTop = "0";
  17994. oStyle.paddingBottom = "0";
  17995. oStyle.borderTopWidth = "0";
  17996. oStyle.borderBottomWidth = "0";
  17997. oStyle.height = 0;
  17998. oStyle.width = that.s.aiInnerWidths[iColumn]+"px";
  17999. nInnerThead.appendChild( nClone );
  18000. }
  18001. /* Add in the tbody elements, cloning form the master table */
  18002. $('>tbody>tr', that.dom.body).each( function (z) {
  18003. var i = that.s.dt.oFeatures.bServerSide===false ?
  18004. that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;
  18005. var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');
  18006. var n = this.cloneNode(false);
  18007. n.removeAttribute('id');
  18008. n.setAttribute( 'data-dt-row', i );
  18009. for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
  18010. {
  18011. iColumn = aiColumns[iIndex];
  18012. if ( aTds.length > 0 )
  18013. {
  18014. nClone = $( aTds[iColumn] ).clone(true, true)[0];
  18015. nClone.removeAttribute( 'id' );
  18016. nClone.setAttribute( 'data-dt-row', i );
  18017. nClone.setAttribute( 'data-dt-column', dt.oApi._fnVisibleToColumnIndex( dt, iColumn ) );
  18018. n.appendChild( nClone );
  18019. }
  18020. }
  18021. nBody.appendChild( n );
  18022. } );
  18023. }
  18024. else
  18025. {
  18026. $('>tbody>tr', that.dom.body).each( function (z) {
  18027. nClone = this.cloneNode(true);
  18028. nClone.className += ' DTFC_NoData';
  18029. $('td', nClone).html('');
  18030. nBody.appendChild( nClone );
  18031. } );
  18032. }
  18033. oClone.body.style.width = "100%";
  18034. oClone.body.style.margin = "0";
  18035. oClone.body.style.padding = "0";
  18036. // Interop with Scroller - need to use a height forcing element in the
  18037. // scrolling area in the same way that Scroller does in the body scroll.
  18038. if ( dt.oScroller !== undefined )
  18039. {
  18040. var scrollerForcer = dt.oScroller.dom.force;
  18041. if ( ! oGrid.forcer ) {
  18042. oGrid.forcer = scrollerForcer.cloneNode( true );
  18043. oGrid.liner.appendChild( oGrid.forcer );
  18044. }
  18045. else {
  18046. oGrid.forcer.style.height = scrollerForcer.style.height;
  18047. }
  18048. }
  18049. oGrid.liner.appendChild( oClone.body );
  18050. this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );
  18051. /*
  18052. * Footer
  18053. */
  18054. if ( dt.nTFoot !== null )
  18055. {
  18056. if ( bAll )
  18057. {
  18058. if ( oClone.footer !== null )
  18059. {
  18060. oClone.footer.parentNode.removeChild( oClone.footer );
  18061. }
  18062. oClone.footer = $(this.dom.footer).clone(true, true)[0];
  18063. oClone.footer.className += " DTFC_Cloned";
  18064. oClone.footer.style.width = "100%";
  18065. oGrid.foot.appendChild( oClone.footer );
  18066. /* Copy the footer just like we do for the header */
  18067. aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true );
  18068. var jqCloneTfoot = $('>tfoot', oClone.footer);
  18069. jqCloneTfoot.empty();
  18070. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  18071. {
  18072. jqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );
  18073. }
  18074. dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
  18075. }
  18076. else
  18077. {
  18078. aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, false );
  18079. var aoCurrFooter=[];
  18080. dt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );
  18081. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  18082. {
  18083. for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
  18084. {
  18085. aoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;
  18086. }
  18087. }
  18088. }
  18089. this._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );
  18090. }
  18091. /* Equalise the column widths between the header footer and body - body get's priority */
  18092. var anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );
  18093. $(anUnique).each( function (i) {
  18094. iColumn = aiColumns[i];
  18095. this.style.width = that.s.aiInnerWidths[iColumn]+"px";
  18096. } );
  18097. if ( that.s.dt.nTFoot !== null )
  18098. {
  18099. anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );
  18100. $(anUnique).each( function (i) {
  18101. iColumn = aiColumns[i];
  18102. this.style.width = that.s.aiInnerWidths[iColumn]+"px";
  18103. } );
  18104. }
  18105. },
  18106. /**
  18107. * From a given table node (THEAD etc), get a list of TR direct child elements
  18108. * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)
  18109. * @returns {Array} List of TR elements found
  18110. * @private
  18111. */
  18112. "_fnGetTrNodes": function ( nIn )
  18113. {
  18114. var aOut = [];
  18115. for ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )
  18116. {
  18117. if ( nIn.childNodes[i].nodeName.toUpperCase() == "TR" )
  18118. {
  18119. aOut.push( nIn.childNodes[i] );
  18120. }
  18121. }
  18122. return aOut;
  18123. },
  18124. /**
  18125. * Equalise the heights of the rows in a given table node in a cross browser way
  18126. * @returns {void}
  18127. * @param {String} nodeName Node type - thead, tbody or tfoot
  18128. * @param {Node} original Original node to take the heights from
  18129. * @param {Node} clone Copy the heights to
  18130. * @private
  18131. */
  18132. "_fnEqualiseHeights": function ( nodeName, original, clone )
  18133. {
  18134. if ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )
  18135. {
  18136. return;
  18137. }
  18138. var that = this,
  18139. i, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,
  18140. rootOriginal = original.getElementsByTagName(nodeName)[0],
  18141. rootClone = clone.getElementsByTagName(nodeName)[0],
  18142. jqBoxHack = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),
  18143. iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(),
  18144. anOriginal = this._fnGetTrNodes( rootOriginal ),
  18145. anClone = this._fnGetTrNodes( rootClone ),
  18146. heights = [];
  18147. for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
  18148. {
  18149. iHeightOriginal = anOriginal[i].offsetHeight;
  18150. iHeightClone = anClone[i].offsetHeight;
  18151. iHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;
  18152. if ( this.s.sHeightMatch == 'semiauto' )
  18153. {
  18154. anOriginal[i]._DTTC_iHeight = iHeight;
  18155. }
  18156. heights.push( iHeight );
  18157. }
  18158. for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
  18159. {
  18160. anClone[i].style.height = heights[i]+"px";
  18161. anOriginal[i].style.height = heights[i]+"px";
  18162. }
  18163. },
  18164. /**
  18165. * Determine if the UA suffers from Firefox's overflow:scroll scrollbars
  18166. * not being shown bug.
  18167. *
  18168. * Firefox doesn't draw scrollbars, even if it is told to using
  18169. * overflow:scroll, if the div is less than 34px height. See bugs 292284 and
  18170. * 781885. Using UA detection here since this is particularly hard to detect
  18171. * using objects - its a straight up rendering error in Firefox.
  18172. *
  18173. * @return {boolean} True if Firefox error is present, false otherwise
  18174. */
  18175. _firefoxScrollError: function () {
  18176. if ( _firefoxScroll === undefined ) {
  18177. var test = $('<div/>')
  18178. .css( {
  18179. position: 'absolute',
  18180. top: 0,
  18181. left: 0,
  18182. height: 10,
  18183. width: 50,
  18184. overflow: 'scroll'
  18185. } )
  18186. .appendTo( 'body' );
  18187. // Make sure this doesn't apply on Macs with 0 width scrollbars
  18188. _firefoxScroll = (
  18189. test[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0
  18190. );
  18191. test.remove();
  18192. }
  18193. return _firefoxScroll;
  18194. }
  18195. } );
  18196. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18197. * Statics
  18198. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  18199. /**
  18200. * FixedColumns default settings for initialisation
  18201. * @name FixedColumns.defaults
  18202. * @namespace
  18203. * @static
  18204. */
  18205. FixedColumns.defaults = /** @lends FixedColumns.defaults */{
  18206. /**
  18207. * Number of left hand columns to fix in position
  18208. * @type int
  18209. * @default 1
  18210. * @static
  18211. * @example
  18212. * var = $('#example').dataTable( {
  18213. * "scrollX": "100%"
  18214. * } );
  18215. * new $.fn.dataTable.fixedColumns( table, {
  18216. * "leftColumns": 2
  18217. * } );
  18218. */
  18219. "iLeftColumns": 1,
  18220. /**
  18221. * Number of right hand columns to fix in position
  18222. * @type int
  18223. * @default 0
  18224. * @static
  18225. * @example
  18226. * var table = $('#example').dataTable( {
  18227. * "scrollX": "100%"
  18228. * } );
  18229. * new $.fn.dataTable.fixedColumns( table, {
  18230. * "rightColumns": 1
  18231. * } );
  18232. */
  18233. "iRightColumns": 0,
  18234. /**
  18235. * Draw callback function which is called when FixedColumns has redrawn the fixed assets
  18236. * @type function(object, object):void
  18237. * @default null
  18238. * @static
  18239. * @example
  18240. * var table = $('#example').dataTable( {
  18241. * "scrollX": "100%"
  18242. * } );
  18243. * new $.fn.dataTable.fixedColumns( table, {
  18244. * "drawCallback": function () {
  18245. * alert( "FixedColumns redraw" );
  18246. * }
  18247. * } );
  18248. */
  18249. "fnDrawCallback": null,
  18250. /**
  18251. * Height matching algorthim to use. This can be "none" which will result in no height
  18252. * matching being applied by FixedColumns (height matching could be forced by CSS in this
  18253. * case), "semiauto" whereby the height calculation will be performed once, and the result
  18254. * cached to be used again (fnRecalculateHeight can be used to force recalculation), or
  18255. * "auto" when height matching is performed on every draw (slowest but must accurate)
  18256. * @type string
  18257. * @default semiauto
  18258. * @static
  18259. * @example
  18260. * var table = $('#example').dataTable( {
  18261. * "scrollX": "100%"
  18262. * } );
  18263. * new $.fn.dataTable.fixedColumns( table, {
  18264. * "heightMatch": "auto"
  18265. * } );
  18266. */
  18267. "sHeightMatch": "semiauto"
  18268. };
  18269. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18270. * Constants
  18271. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  18272. /**
  18273. * FixedColumns version
  18274. * @name FixedColumns.version
  18275. * @type String
  18276. * @default See code
  18277. * @static
  18278. */
  18279. FixedColumns.version = "3.2.4";
  18280. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18281. * DataTables API integration
  18282. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  18283. DataTable.Api.register( 'fixedColumns()', function () {
  18284. return this;
  18285. } );
  18286. DataTable.Api.register( 'fixedColumns().update()', function () {
  18287. return this.iterator( 'table', function ( ctx ) {
  18288. if ( ctx._oFixedColumns ) {
  18289. ctx._oFixedColumns.fnUpdate();
  18290. }
  18291. } );
  18292. } );
  18293. DataTable.Api.register( 'fixedColumns().relayout()', function () {
  18294. return this.iterator( 'table', function ( ctx ) {
  18295. if ( ctx._oFixedColumns ) {
  18296. ctx._oFixedColumns.fnRedrawLayout();
  18297. }
  18298. } );
  18299. } );
  18300. DataTable.Api.register( 'rows().recalcHeight()', function () {
  18301. return this.iterator( 'row', function ( ctx, idx ) {
  18302. if ( ctx._oFixedColumns ) {
  18303. ctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() );
  18304. }
  18305. } );
  18306. } );
  18307. DataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) {
  18308. row = $(row);
  18309. return row.parents('.DTFC_Cloned').length ?
  18310. this.rows( { page: 'current' } ).indexes()[ row.index() ] :
  18311. this.row( row ).index();
  18312. } );
  18313. DataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) {
  18314. cell = $(cell);
  18315. if ( cell.parents('.DTFC_Cloned').length ) {
  18316. var rowClonedIdx = cell.parent().index();
  18317. var rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ];
  18318. var columnIdx;
  18319. if ( cell.parents('.DTFC_LeftWrapper').length ) {
  18320. columnIdx = cell.index();
  18321. }
  18322. else {
  18323. var columns = this.columns().flatten().length;
  18324. columnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index();
  18325. }
  18326. return {
  18327. row: rowIdx,
  18328. column: this.column.index( 'toData', columnIdx ),
  18329. columnVisible: columnIdx
  18330. };
  18331. }
  18332. else {
  18333. return this.cell( cell ).index();
  18334. }
  18335. } );
  18336. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18337. * Initialisation
  18338. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  18339. // Attach a listener to the document which listens for DataTables initialisation
  18340. // events so we can automatically initialise
  18341. $(document).on( 'init.dt.fixedColumns', function (e, settings) {
  18342. if ( e.namespace !== 'dt' ) {
  18343. return;
  18344. }
  18345. var init = settings.oInit.fixedColumns;
  18346. var defaults = DataTable.defaults.fixedColumns;
  18347. if ( init || defaults ) {
  18348. var opts = $.extend( {}, init, defaults );
  18349. if ( init !== false ) {
  18350. new FixedColumns( settings, opts );
  18351. }
  18352. }
  18353. } );
  18354. // Make FixedColumns accessible from the DataTables instance
  18355. $.fn.dataTable.FixedColumns = FixedColumns;
  18356. $.fn.DataTable.FixedColumns = FixedColumns;
  18357. return FixedColumns;
  18358. }));
  18359. /*! FixedHeader 3.1.3
  18360. * ©2009-2017 SpryMedia Ltd - datatables.net/license
  18361. */
  18362. /**
  18363. * @summary FixedHeader
  18364. * @description Fix a table's header or footer, so it is always visible while
  18365. * scrolling
  18366. * @version 3.1.3
  18367. * @file dataTables.fixedHeader.js
  18368. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  18369. * @contact www.sprymedia.co.uk/contact
  18370. * @copyright Copyright 2009-2017 SpryMedia Ltd.
  18371. *
  18372. * This source file is free software, available under the following license:
  18373. * MIT license - http://datatables.net/license/mit
  18374. *
  18375. * This source file is distributed in the hope that it will be useful, but
  18376. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18377. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  18378. *
  18379. * For details please refer to: http://www.datatables.net
  18380. */
  18381. (function( factory ){
  18382. if ( typeof define === 'function' && define.amd ) {
  18383. // AMD
  18384. define( ['jquery', 'datatables.net'], function ( $ ) {
  18385. return factory( $, window, document );
  18386. } );
  18387. }
  18388. else if ( typeof exports === 'object' ) {
  18389. // CommonJS
  18390. module.exports = function (root, $) {
  18391. if ( ! root ) {
  18392. root = window;
  18393. }
  18394. if ( ! $ || ! $.fn.dataTable ) {
  18395. $ = require('datatables.net')(root, $).$;
  18396. }
  18397. return factory( $, root, root.document );
  18398. };
  18399. }
  18400. else {
  18401. // Browser
  18402. factory( jQuery, window, document );
  18403. }
  18404. }(function( $, window, document, undefined ) {
  18405. 'use strict';
  18406. var DataTable = $.fn.dataTable;
  18407. var _instCounter = 0;
  18408. var FixedHeader = function ( dt, config ) {
  18409. // Sanity check - you just know it will happen
  18410. if ( ! (this instanceof FixedHeader) ) {
  18411. throw "FixedHeader must be initialised with the 'new' keyword.";
  18412. }
  18413. // Allow a boolean true for defaults
  18414. if ( config === true ) {
  18415. config = {};
  18416. }
  18417. dt = new DataTable.Api( dt );
  18418. this.c = $.extend( true, {}, FixedHeader.defaults, config );
  18419. this.s = {
  18420. dt: dt,
  18421. position: {
  18422. theadTop: 0,
  18423. tbodyTop: 0,
  18424. tfootTop: 0,
  18425. tfootBottom: 0,
  18426. width: 0,
  18427. left: 0,
  18428. tfootHeight: 0,
  18429. theadHeight: 0,
  18430. windowHeight: $(window).height(),
  18431. visible: true
  18432. },
  18433. headerMode: null,
  18434. footerMode: null,
  18435. autoWidth: dt.settings()[0].oFeatures.bAutoWidth,
  18436. namespace: '.dtfc'+(_instCounter++),
  18437. scrollLeft: {
  18438. header: -1,
  18439. footer: -1
  18440. },
  18441. enable: true
  18442. };
  18443. this.dom = {
  18444. floatingHeader: null,
  18445. thead: $(dt.table().header()),
  18446. tbody: $(dt.table().body()),
  18447. tfoot: $(dt.table().footer()),
  18448. header: {
  18449. host: null,
  18450. floating: null,
  18451. placeholder: null
  18452. },
  18453. footer: {
  18454. host: null,
  18455. floating: null,
  18456. placeholder: null
  18457. }
  18458. };
  18459. this.dom.header.host = this.dom.thead.parent();
  18460. this.dom.footer.host = this.dom.tfoot.parent();
  18461. var dtSettings = dt.settings()[0];
  18462. if ( dtSettings._fixedHeader ) {
  18463. throw "FixedHeader already initialised on table "+dtSettings.nTable.id;
  18464. }
  18465. dtSettings._fixedHeader = this;
  18466. this._constructor();
  18467. };
  18468. /*
  18469. * Variable: FixedHeader
  18470. * Purpose: Prototype for FixedHeader
  18471. * Scope: global
  18472. */
  18473. $.extend( FixedHeader.prototype, {
  18474. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18475. * API methods
  18476. */
  18477. /**
  18478. * Enable / disable the fixed elements
  18479. *
  18480. * @param {boolean} enable `true` to enable, `false` to disable
  18481. */
  18482. enable: function ( enable )
  18483. {
  18484. this.s.enable = enable;
  18485. if ( this.c.header ) {
  18486. this._modeChange( 'in-place', 'header', true );
  18487. }
  18488. if ( this.c.footer && this.dom.tfoot.length ) {
  18489. this._modeChange( 'in-place', 'footer', true );
  18490. }
  18491. this.update();
  18492. },
  18493. /**
  18494. * Set header offset
  18495. *
  18496. * @param {int} new value for headerOffset
  18497. */
  18498. headerOffset: function ( offset )
  18499. {
  18500. if ( offset !== undefined ) {
  18501. this.c.headerOffset = offset;
  18502. this.update();
  18503. }
  18504. return this.c.headerOffset;
  18505. },
  18506. /**
  18507. * Set footer offset
  18508. *
  18509. * @param {int} new value for footerOffset
  18510. */
  18511. footerOffset: function ( offset )
  18512. {
  18513. if ( offset !== undefined ) {
  18514. this.c.footerOffset = offset;
  18515. this.update();
  18516. }
  18517. return this.c.footerOffset;
  18518. },
  18519. /**
  18520. * Recalculate the position of the fixed elements and force them into place
  18521. */
  18522. update: function ()
  18523. {
  18524. this._positions();
  18525. this._scroll( true );
  18526. },
  18527. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18528. * Constructor
  18529. */
  18530. /**
  18531. * FixedHeader constructor - adding the required event listeners and
  18532. * simple initialisation
  18533. *
  18534. * @private
  18535. */
  18536. _constructor: function ()
  18537. {
  18538. var that = this;
  18539. var dt = this.s.dt;
  18540. $(window)
  18541. .on( 'scroll'+this.s.namespace, function () {
  18542. that._scroll();
  18543. } )
  18544. .on( 'resize'+this.s.namespace, function () {
  18545. that.s.position.windowHeight = $(window).height();
  18546. that.update();
  18547. } );
  18548. var autoHeader = $('.fh-fixedHeader');
  18549. if ( ! this.c.headerOffset && autoHeader.length ) {
  18550. this.c.headerOffset = autoHeader.outerHeight();
  18551. }
  18552. var autoFooter = $('.fh-fixedFooter');
  18553. if ( ! this.c.footerOffset && autoFooter.length ) {
  18554. this.c.footerOffset = autoFooter.outerHeight();
  18555. }
  18556. dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc', function () {
  18557. that.update();
  18558. } );
  18559. dt.on( 'destroy.dtfc', function () {
  18560. dt.off( '.dtfc' );
  18561. $(window).off( that.s.namespace );
  18562. } );
  18563. this._positions();
  18564. this._scroll();
  18565. },
  18566. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18567. * Private methods
  18568. */
  18569. /**
  18570. * Clone a fixed item to act as a place holder for the original element
  18571. * which is moved into a clone of the table element, and moved around the
  18572. * document to give the fixed effect.
  18573. *
  18574. * @param {string} item 'header' or 'footer'
  18575. * @param {boolean} force Force the clone to happen, or allow automatic
  18576. * decision (reuse existing if available)
  18577. * @private
  18578. */
  18579. _clone: function ( item, force )
  18580. {
  18581. var dt = this.s.dt;
  18582. var itemDom = this.dom[ item ];
  18583. var itemElement = item === 'header' ?
  18584. this.dom.thead :
  18585. this.dom.tfoot;
  18586. if ( ! force && itemDom.floating ) {
  18587. // existing floating element - reuse it
  18588. itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );
  18589. }
  18590. else {
  18591. if ( itemDom.floating ) {
  18592. itemDom.placeholder.remove();
  18593. this._unsize( item );
  18594. itemDom.floating.children().detach();
  18595. itemDom.floating.remove();
  18596. }
  18597. itemDom.floating = $( dt.table().node().cloneNode( false ) )
  18598. .css( 'table-layout', 'fixed' )
  18599. .removeAttr( 'id' )
  18600. .append( itemElement )
  18601. .appendTo( 'body' );
  18602. // Insert a fake thead/tfoot into the DataTable to stop it jumping around
  18603. itemDom.placeholder = itemElement.clone( false )
  18604. itemDom.placeholder
  18605. .find( '*[id]' )
  18606. .removeAttr( 'id' );
  18607. itemDom.host.prepend( itemDom.placeholder );
  18608. // Clone widths
  18609. this._matchWidths( itemDom.placeholder, itemDom.floating );
  18610. }
  18611. },
  18612. /**
  18613. * Copy widths from the cells in one element to another. This is required
  18614. * for the footer as the footer in the main table takes its sizes from the
  18615. * header columns. That isn't present in the footer so to have it still
  18616. * align correctly, the sizes need to be copied over. It is also required
  18617. * for the header when auto width is not enabled
  18618. *
  18619. * @param {jQuery} from Copy widths from
  18620. * @param {jQuery} to Copy widths to
  18621. * @private
  18622. */
  18623. _matchWidths: function ( from, to ) {
  18624. var get = function ( name ) {
  18625. return $(name, from)
  18626. .map( function () {
  18627. return $(this).width();
  18628. } ).toArray();
  18629. };
  18630. var set = function ( name, toWidths ) {
  18631. $(name, to).each( function ( i ) {
  18632. $(this).css( {
  18633. width: toWidths[i],
  18634. minWidth: toWidths[i]
  18635. } );
  18636. } );
  18637. };
  18638. var thWidths = get( 'th' );
  18639. var tdWidths = get( 'td' );
  18640. set( 'th', thWidths );
  18641. set( 'td', tdWidths );
  18642. },
  18643. /**
  18644. * Remove assigned widths from the cells in an element. This is required
  18645. * when inserting the footer back into the main table so the size is defined
  18646. * by the header columns and also when auto width is disabled in the
  18647. * DataTable.
  18648. *
  18649. * @param {string} item The `header` or `footer`
  18650. * @private
  18651. */
  18652. _unsize: function ( item ) {
  18653. var el = this.dom[ item ].floating;
  18654. if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {
  18655. $('th, td', el).css( {
  18656. width: '',
  18657. minWidth: ''
  18658. } );
  18659. }
  18660. else if ( el && item === 'header' ) {
  18661. $('th, td', el).css( 'min-width', '' );
  18662. }
  18663. },
  18664. /**
  18665. * Reposition the floating elements to take account of horizontal page
  18666. * scroll
  18667. *
  18668. * @param {string} item The `header` or `footer`
  18669. * @param {int} scrollLeft Document scrollLeft
  18670. * @private
  18671. */
  18672. _horizontal: function ( item, scrollLeft )
  18673. {
  18674. var itemDom = this.dom[ item ];
  18675. var position = this.s.position;
  18676. var lastScrollLeft = this.s.scrollLeft;
  18677. if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {
  18678. itemDom.floating.css( 'left', position.left - scrollLeft );
  18679. lastScrollLeft[ item ] = scrollLeft;
  18680. }
  18681. },
  18682. /**
  18683. * Change from one display mode to another. Each fixed item can be in one
  18684. * of:
  18685. *
  18686. * * `in-place` - In the main DataTable
  18687. * * `in` - Floating over the DataTable
  18688. * * `below` - (Header only) Fixed to the bottom of the table body
  18689. * * `above` - (Footer only) Fixed to the top of the table body
  18690. *
  18691. * @param {string} mode Mode that the item should be shown in
  18692. * @param {string} item 'header' or 'footer'
  18693. * @param {boolean} forceChange Force a redraw of the mode, even if already
  18694. * in that mode.
  18695. * @private
  18696. */
  18697. _modeChange: function ( mode, item, forceChange )
  18698. {
  18699. var dt = this.s.dt;
  18700. var itemDom = this.dom[ item ];
  18701. var position = this.s.position;
  18702. // Record focus. Browser's will cause input elements to loose focus if
  18703. // they are inserted else where in the doc
  18704. var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];
  18705. var focus = $.contains( tablePart[0], document.activeElement ) ?
  18706. document.activeElement :
  18707. null;
  18708. if ( mode === 'in-place' ) {
  18709. // Insert the header back into the table's real header
  18710. if ( itemDom.placeholder ) {
  18711. itemDom.placeholder.remove();
  18712. itemDom.placeholder = null;
  18713. }
  18714. this._unsize( item );
  18715. if ( item === 'header' ) {
  18716. itemDom.host.prepend( this.dom.thead );
  18717. }
  18718. else {
  18719. itemDom.host.append( this.dom.tfoot );
  18720. }
  18721. if ( itemDom.floating ) {
  18722. itemDom.floating.remove();
  18723. itemDom.floating = null;
  18724. }
  18725. }
  18726. else if ( mode === 'in' ) {
  18727. // Remove the header from the read header and insert into a fixed
  18728. // positioned floating table clone
  18729. this._clone( item, forceChange );
  18730. itemDom.floating
  18731. .addClass( 'fixedHeader-floating' )
  18732. .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )
  18733. .css( 'left', position.left+'px' )
  18734. .css( 'width', position.width+'px' );
  18735. if ( item === 'footer' ) {
  18736. itemDom.floating.css( 'top', '' );
  18737. }
  18738. }
  18739. else if ( mode === 'below' ) { // only used for the header
  18740. // Fix the position of the floating header at base of the table body
  18741. this._clone( item, forceChange );
  18742. itemDom.floating
  18743. .addClass( 'fixedHeader-locked' )
  18744. .css( 'top', position.tfootTop - position.theadHeight )
  18745. .css( 'left', position.left+'px' )
  18746. .css( 'width', position.width+'px' );
  18747. }
  18748. else if ( mode === 'above' ) { // only used for the footer
  18749. // Fix the position of the floating footer at top of the table body
  18750. this._clone( item, forceChange );
  18751. itemDom.floating
  18752. .addClass( 'fixedHeader-locked' )
  18753. .css( 'top', position.tbodyTop )
  18754. .css( 'left', position.left+'px' )
  18755. .css( 'width', position.width+'px' );
  18756. }
  18757. // Restore focus if it was lost
  18758. if ( focus && focus !== document.activeElement ) {
  18759. focus.focus();
  18760. }
  18761. this.s.scrollLeft.header = -1;
  18762. this.s.scrollLeft.footer = -1;
  18763. this.s[item+'Mode'] = mode;
  18764. },
  18765. /**
  18766. * Cache the positional information that is required for the mode
  18767. * calculations that FixedHeader performs.
  18768. *
  18769. * @private
  18770. */
  18771. _positions: function ()
  18772. {
  18773. var dt = this.s.dt;
  18774. var table = dt.table();
  18775. var position = this.s.position;
  18776. var dom = this.dom;
  18777. var tableNode = $(table.node());
  18778. // Need to use the header and footer that are in the main table,
  18779. // regardless of if they are clones, since they hold the positions we
  18780. // want to measure from
  18781. var thead = tableNode.children('thead');
  18782. var tfoot = tableNode.children('tfoot');
  18783. var tbody = dom.tbody;
  18784. position.visible = tableNode.is(':visible');
  18785. position.width = tableNode.outerWidth();
  18786. position.left = tableNode.offset().left;
  18787. position.theadTop = thead.offset().top;
  18788. position.tbodyTop = tbody.offset().top;
  18789. position.theadHeight = position.tbodyTop - position.theadTop;
  18790. if ( tfoot.length ) {
  18791. position.tfootTop = tfoot.offset().top;
  18792. position.tfootBottom = position.tfootTop + tfoot.outerHeight();
  18793. position.tfootHeight = position.tfootBottom - position.tfootTop;
  18794. }
  18795. else {
  18796. position.tfootTop = position.tbodyTop + tbody.outerHeight();
  18797. position.tfootBottom = position.tfootTop;
  18798. position.tfootHeight = position.tfootTop;
  18799. }
  18800. },
  18801. /**
  18802. * Mode calculation - determine what mode the fixed items should be placed
  18803. * into.
  18804. *
  18805. * @param {boolean} forceChange Force a redraw of the mode, even if already
  18806. * in that mode.
  18807. * @private
  18808. */
  18809. _scroll: function ( forceChange )
  18810. {
  18811. var windowTop = $(document).scrollTop();
  18812. var windowLeft = $(document).scrollLeft();
  18813. var position = this.s.position;
  18814. var headerMode, footerMode;
  18815. if ( ! this.s.enable ) {
  18816. return;
  18817. }
  18818. if ( this.c.header ) {
  18819. if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {
  18820. headerMode = 'in-place';
  18821. }
  18822. else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {
  18823. headerMode = 'in';
  18824. }
  18825. else {
  18826. headerMode = 'below';
  18827. }
  18828. if ( forceChange || headerMode !== this.s.headerMode ) {
  18829. this._modeChange( headerMode, 'header', forceChange );
  18830. }
  18831. this._horizontal( 'header', windowLeft );
  18832. }
  18833. if ( this.c.footer && this.dom.tfoot.length ) {
  18834. if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {
  18835. footerMode = 'in-place';
  18836. }
  18837. else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {
  18838. footerMode = 'in';
  18839. }
  18840. else {
  18841. footerMode = 'above';
  18842. }
  18843. if ( forceChange || footerMode !== this.s.footerMode ) {
  18844. this._modeChange( footerMode, 'footer', forceChange );
  18845. }
  18846. this._horizontal( 'footer', windowLeft );
  18847. }
  18848. }
  18849. } );
  18850. /**
  18851. * Version
  18852. * @type {String}
  18853. * @static
  18854. */
  18855. FixedHeader.version = "3.1.3";
  18856. /**
  18857. * Defaults
  18858. * @type {Object}
  18859. * @static
  18860. */
  18861. FixedHeader.defaults = {
  18862. header: true,
  18863. footer: false,
  18864. headerOffset: 0,
  18865. footerOffset: 0
  18866. };
  18867. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18868. * DataTables interfaces
  18869. */
  18870. // Attach for constructor access
  18871. $.fn.dataTable.FixedHeader = FixedHeader;
  18872. $.fn.DataTable.FixedHeader = FixedHeader;
  18873. // DataTables creation - check if the FixedHeader option has been defined on the
  18874. // table and if so, initialise
  18875. $(document).on( 'init.dt.dtfh', function (e, settings, json) {
  18876. if ( e.namespace !== 'dt' ) {
  18877. return;
  18878. }
  18879. var init = settings.oInit.fixedHeader;
  18880. var defaults = DataTable.defaults.fixedHeader;
  18881. if ( (init || defaults) && ! settings._fixedHeader ) {
  18882. var opts = $.extend( {}, defaults, init );
  18883. if ( init !== false ) {
  18884. new FixedHeader( settings, opts );
  18885. }
  18886. }
  18887. } );
  18888. // DataTables API methods
  18889. DataTable.Api.register( 'fixedHeader()', function () {} );
  18890. DataTable.Api.register( 'fixedHeader.adjust()', function () {
  18891. return this.iterator( 'table', function ( ctx ) {
  18892. var fh = ctx._fixedHeader;
  18893. if ( fh ) {
  18894. fh.update();
  18895. }
  18896. } );
  18897. } );
  18898. DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {
  18899. return this.iterator( 'table', function ( ctx ) {
  18900. var fh = ctx._fixedHeader;
  18901. flag = ( flag !== undefined ? flag : true );
  18902. if ( fh && flag !== fh.s.enable ) {
  18903. fh.enable( flag );
  18904. }
  18905. } );
  18906. } );
  18907. DataTable.Api.register( 'fixedHeader.disable()', function ( ) {
  18908. return this.iterator( 'table', function ( ctx ) {
  18909. var fh = ctx._fixedHeader;
  18910. if ( fh && fh.s.enable ) {
  18911. fh.enable( false );
  18912. }
  18913. } );
  18914. } );
  18915. $.each( ['header', 'footer'], function ( i, el ) {
  18916. DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {
  18917. var ctx = this.context;
  18918. if ( offset === undefined ) {
  18919. return ctx.length && ctx[0]._fixedHeader ?
  18920. ctx[0]._fixedHeader[el +'Offset']() :
  18921. undefined;
  18922. }
  18923. return this.iterator( 'table', function ( ctx ) {
  18924. var fh = ctx._fixedHeader;
  18925. if ( fh ) {
  18926. fh[ el +'Offset' ]( offset );
  18927. }
  18928. } );
  18929. } );
  18930. } );
  18931. return FixedHeader;
  18932. }));
  18933. /*! KeyTable 2.3.2
  18934. * ©2009-2017 SpryMedia Ltd - datatables.net/license
  18935. */
  18936. /**
  18937. * @summary KeyTable
  18938. * @description Spreadsheet like keyboard navigation for DataTables
  18939. * @version 2.3.2
  18940. * @file dataTables.keyTable.js
  18941. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  18942. * @contact www.sprymedia.co.uk/contact
  18943. * @copyright Copyright 2009-2017 SpryMedia Ltd.
  18944. *
  18945. * This source file is free software, available under the following license:
  18946. * MIT license - http://datatables.net/license/mit
  18947. *
  18948. * This source file is distributed in the hope that it will be useful, but
  18949. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18950. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  18951. *
  18952. * For details please refer to: http://www.datatables.net
  18953. */
  18954. (function( factory ){
  18955. if ( typeof define === 'function' && define.amd ) {
  18956. // AMD
  18957. define( ['jquery', 'datatables.net'], function ( $ ) {
  18958. return factory( $, window, document );
  18959. } );
  18960. }
  18961. else if ( typeof exports === 'object' ) {
  18962. // CommonJS
  18963. module.exports = function (root, $) {
  18964. if ( ! root ) {
  18965. root = window;
  18966. }
  18967. if ( ! $ || ! $.fn.dataTable ) {
  18968. $ = require('datatables.net')(root, $).$;
  18969. }
  18970. return factory( $, root, root.document );
  18971. };
  18972. }
  18973. else {
  18974. // Browser
  18975. factory( jQuery, window, document );
  18976. }
  18977. }(function( $, window, document, undefined ) {
  18978. 'use strict';
  18979. var DataTable = $.fn.dataTable;
  18980. var KeyTable = function ( dt, opts ) {
  18981. // Sanity check that we are using DataTables 1.10 or newer
  18982. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
  18983. throw 'KeyTable requires DataTables 1.10.8 or newer';
  18984. }
  18985. // User and defaults configuration object
  18986. this.c = $.extend( true, {},
  18987. DataTable.defaults.keyTable,
  18988. KeyTable.defaults,
  18989. opts
  18990. );
  18991. // Internal settings
  18992. this.s = {
  18993. /** @type {DataTable.Api} DataTables' API instance */
  18994. dt: new DataTable.Api( dt ),
  18995. enable: true,
  18996. /** @type {bool} Flag for if a draw is triggered by focus */
  18997. focusDraw: false,
  18998. /** @type {bool} Flag to indicate when waiting for a draw to happen.
  18999. * Will ignore key presses at this point
  19000. */
  19001. waitingForDraw: false,
  19002. /** @type {object} Information about the last cell that was focused */
  19003. lastFocus: null
  19004. };
  19005. // DOM items
  19006. this.dom = {
  19007. };
  19008. // Check if row reorder has already been initialised on this table
  19009. var settings = this.s.dt.settings()[0];
  19010. var exisiting = settings.keytable;
  19011. if ( exisiting ) {
  19012. return exisiting;
  19013. }
  19014. settings.keytable = this;
  19015. this._constructor();
  19016. };
  19017. $.extend( KeyTable.prototype, {
  19018. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19019. * API methods for DataTables API interface
  19020. */
  19021. /**
  19022. * Blur the table's cell focus
  19023. */
  19024. blur: function ()
  19025. {
  19026. this._blur();
  19027. },
  19028. /**
  19029. * Enable cell focus for the table
  19030. *
  19031. * @param {string} state Can be `true`, `false` or `-string navigation-only`
  19032. */
  19033. enable: function ( state )
  19034. {
  19035. this.s.enable = state;
  19036. },
  19037. /**
  19038. * Focus on a cell
  19039. * @param {integer} row Row index
  19040. * @param {integer} column Column index
  19041. */
  19042. focus: function ( row, column )
  19043. {
  19044. this._focus( this.s.dt.cell( row, column ) );
  19045. },
  19046. /**
  19047. * Is the cell focused
  19048. * @param {object} cell Cell index to check
  19049. * @returns {boolean} true if focused, false otherwise
  19050. */
  19051. focused: function ( cell )
  19052. {
  19053. var lastFocus = this.s.lastFocus;
  19054. if ( ! lastFocus ) {
  19055. return false;
  19056. }
  19057. var lastIdx = this.s.lastFocus.cell.index();
  19058. return cell.row === lastIdx.row && cell.column === lastIdx.column;
  19059. },
  19060. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19061. * Constructor
  19062. */
  19063. /**
  19064. * Initialise the KeyTable instance
  19065. *
  19066. * @private
  19067. */
  19068. _constructor: function ()
  19069. {
  19070. this._tabInput();
  19071. var that = this;
  19072. var dt = this.s.dt;
  19073. var table = $( dt.table().node() );
  19074. // Need to be able to calculate the cell positions relative to the table
  19075. if ( table.css('position') === 'static' ) {
  19076. table.css( 'position', 'relative' );
  19077. }
  19078. // Click to focus
  19079. $( dt.table().body() ).on( 'click.keyTable', 'th, td', function (e) {
  19080. if ( that.s.enable === false ) {
  19081. return;
  19082. }
  19083. var cell = dt.cell( this );
  19084. if ( ! cell.any() ) {
  19085. return;
  19086. }
  19087. that._focus( cell, null, false, e );
  19088. } );
  19089. // Key events
  19090. $( document ).on( 'keydown.keyTable', function (e) {
  19091. that._key( e );
  19092. } );
  19093. // Click blur
  19094. if ( this.c.blurable ) {
  19095. $( document ).on( 'mousedown.keyTable', function ( e ) {
  19096. // Click on the search input will blur focus
  19097. if ( $(e.target).parents( '.dataTables_filter' ).length ) {
  19098. that._blur();
  19099. }
  19100. // If the click was inside the DataTables container, don't blur
  19101. if ( $(e.target).parents().filter( dt.table().container() ).length ) {
  19102. return;
  19103. }
  19104. // Don't blur in Editor form
  19105. if ( $(e.target).parents('div.DTE').length ) {
  19106. return;
  19107. }
  19108. // Or an Editor date input
  19109. if ( $(e.target).parents('div.editor-datetime').length ) {
  19110. return;
  19111. }
  19112. //If the click was inside the fixed columns container, don't blur
  19113. if ( $(e.target).parents().filter('.DTFC_Cloned').length ) {
  19114. return;
  19115. }
  19116. that._blur();
  19117. } );
  19118. }
  19119. if ( this.c.editor ) {
  19120. var editor = this.c.editor;
  19121. // Need to disable KeyTable when the main editor is shown
  19122. editor.on( 'open.keyTableMain', function (e, mode, action) {
  19123. if ( mode !== 'inline' && that.s.enable ) {
  19124. that.enable( false );
  19125. editor.one( 'close.keyTable', function () {
  19126. that.enable( true );
  19127. } );
  19128. }
  19129. } );
  19130. if ( this.c.editOnFocus ) {
  19131. dt.on( 'key-focus.keyTable key-refocus.keyTable', function ( e, dt, cell, orig ) {
  19132. that._editor( null, orig );
  19133. } );
  19134. }
  19135. // Activate Editor when a key is pressed (will be ignored, if
  19136. // already active).
  19137. dt.on( 'key.keyTable', function ( e, dt, key, cell, orig ) {
  19138. that._editor( key, orig );
  19139. } );
  19140. }
  19141. // Stave saving
  19142. if ( dt.settings()[0].oFeatures.bStateSave ) {
  19143. dt.on( 'stateSaveParams.keyTable', function (e, s, d) {
  19144. d.keyTable = that.s.lastFocus ?
  19145. that.s.lastFocus.cell.index() :
  19146. null;
  19147. } );
  19148. }
  19149. // Redraw - retain focus on the current cell
  19150. dt.on( 'draw.keyTable', function (e) {
  19151. if ( that.s.focusDraw ) {
  19152. return;
  19153. }
  19154. var lastFocus = that.s.lastFocus;
  19155. if ( lastFocus && lastFocus.node && $(lastFocus.node).closest('body') === document.body ) {
  19156. var relative = that.s.lastFocus.relative;
  19157. var info = dt.page.info();
  19158. var row = relative.row + info.start;
  19159. if ( info.recordsDisplay === 0 ) {
  19160. return;
  19161. }
  19162. // Reverse if needed
  19163. if ( row >= info.recordsDisplay ) {
  19164. row = info.recordsDisplay - 1;
  19165. }
  19166. that._focus( row, relative.column, true, e );
  19167. }
  19168. } );
  19169. dt.on( 'destroy.keyTable', function () {
  19170. dt.off( '.keyTable' );
  19171. $( dt.table().body() ).off( 'click.keyTable', 'th, td' );
  19172. $( document.body )
  19173. .off( 'keydown.keyTable' )
  19174. .off( 'click.keyTable' );
  19175. } );
  19176. // Initial focus comes from state or options
  19177. var state = dt.state.loaded();
  19178. if ( state && state.keyTable ) {
  19179. // Wait until init is done
  19180. dt.one( 'init', function () {
  19181. var cell = dt.cell( state.keyTable );
  19182. // Ensure that the saved cell still exists
  19183. if ( cell.any() ) {
  19184. cell.focus();
  19185. }
  19186. } );
  19187. }
  19188. else if ( this.c.focus ) {
  19189. dt.cell( this.c.focus ).focus();
  19190. }
  19191. },
  19192. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19193. * Private methods
  19194. */
  19195. /**
  19196. * Blur the control
  19197. *
  19198. * @private
  19199. */
  19200. _blur: function ()
  19201. {
  19202. if ( ! this.s.enable || ! this.s.lastFocus ) {
  19203. return;
  19204. }
  19205. var cell = this.s.lastFocus.cell;
  19206. $( cell.node() ).removeClass( this.c.className );
  19207. this.s.lastFocus = null;
  19208. this._updateFixedColumns(cell.index().column);
  19209. this._emitEvent( 'key-blur', [ this.s.dt, cell ] );
  19210. },
  19211. /**
  19212. * Copy text from the focused cell to clipboard
  19213. *
  19214. * @private
  19215. */
  19216. _clipboardCopy: function ()
  19217. {
  19218. var dt = this.s.dt;
  19219. // If there is a cell focused, and there is no other text selected
  19220. // allow the focused cell's text to be copied to clipboard
  19221. if ( this.s.lastFocus && window.getSelection && !window.getSelection().toString() ) {
  19222. var cell = this.s.lastFocus.cell;
  19223. var text = cell.render('display');
  19224. var hiddenDiv = $('<div/>')
  19225. .css( {
  19226. height: 1,
  19227. width: 1,
  19228. overflow: 'hidden',
  19229. position: 'fixed',
  19230. top: 0,
  19231. left: 0
  19232. } );
  19233. var textarea = $('<textarea readonly/>')
  19234. .val( text )
  19235. .appendTo( hiddenDiv );
  19236. try {
  19237. hiddenDiv.appendTo( dt.table().container() );
  19238. textarea[0].focus();
  19239. textarea[0].select();
  19240. document.execCommand( 'copy' );
  19241. }
  19242. catch (e) {}
  19243. hiddenDiv.remove();
  19244. }
  19245. },
  19246. /**
  19247. * Get an array of the column indexes that KeyTable can operate on. This
  19248. * is a merge of the user supplied columns and the visible columns.
  19249. *
  19250. * @private
  19251. */
  19252. _columns: function ()
  19253. {
  19254. var dt = this.s.dt;
  19255. var user = dt.columns( this.c.columns ).indexes();
  19256. var out = [];
  19257. dt.columns( ':visible' ).every( function (i) {
  19258. if ( user.indexOf( i ) !== -1 ) {
  19259. out.push( i );
  19260. }
  19261. } );
  19262. return out;
  19263. },
  19264. /**
  19265. * Perform excel like navigation for Editor by triggering an edit on key
  19266. * press
  19267. *
  19268. * @param {integer} key Key code for the pressed key
  19269. * @param {object} orig Original event
  19270. * @private
  19271. */
  19272. _editor: function ( key, orig )
  19273. {
  19274. var that = this;
  19275. var dt = this.s.dt;
  19276. var editor = this.c.editor;
  19277. // Do nothing if there is already an inline edit in this cell
  19278. if ( $('div.DTE', this.s.lastFocus.cell.node()).length ) {
  19279. return;
  19280. }
  19281. // Don't activate inline editing when the shift key is pressed
  19282. if ( key === 16 ) {
  19283. return;
  19284. }
  19285. orig.stopPropagation();
  19286. // Return key should do nothing - for textareas it would empty the
  19287. // contents
  19288. if ( key === 13 ) {
  19289. orig.preventDefault();
  19290. }
  19291. editor
  19292. .one( 'open.keyTable', function () {
  19293. // Remove cancel open
  19294. editor.off( 'cancelOpen.keyTable' );
  19295. // Excel style - select all text
  19296. if ( that.c.editAutoSelect ) {
  19297. $('div.DTE_Field_InputControl input, div.DTE_Field_InputControl textarea').select();
  19298. }
  19299. // Reduce the keys the Keys listens for
  19300. dt.keys.enable( that.c.editorKeys );
  19301. // On blur of the navigation submit
  19302. dt.one( 'key-blur.editor', function () {
  19303. if ( editor.displayed() ) {
  19304. editor.submit();
  19305. }
  19306. } );
  19307. // Restore full key navigation on close
  19308. editor.one( 'close', function () {
  19309. dt.keys.enable( true );
  19310. dt.off( 'key-blur.editor' );
  19311. } );
  19312. } )
  19313. .one( 'cancelOpen.keyTable', function () {
  19314. // `preOpen` can cancel the display of the form, so it
  19315. // might be that the open event handler isn't needed
  19316. editor.off( 'open.keyTable' );
  19317. } )
  19318. .inline( this.s.lastFocus.cell.index() );
  19319. },
  19320. /**
  19321. * Emit an event on the DataTable for listeners
  19322. *
  19323. * @param {string} name Event name
  19324. * @param {array} args Event arguments
  19325. * @private
  19326. */
  19327. _emitEvent: function ( name, args )
  19328. {
  19329. this.s.dt.iterator( 'table', function ( ctx, i ) {
  19330. $(ctx.nTable).triggerHandler( name, args );
  19331. } );
  19332. },
  19333. /**
  19334. * Focus on a particular cell, shifting the table's paging if required
  19335. *
  19336. * @param {DataTables.Api|integer} row Can be given as an API instance that
  19337. * contains the cell to focus or as an integer. As the latter it is the
  19338. * visible row index (from the whole data set) - NOT the data index
  19339. * @param {integer} [column] Not required if a cell is given as the first
  19340. * parameter. Otherwise this is the column data index for the cell to
  19341. * focus on
  19342. * @param {boolean} [shift=true] Should the viewport be moved to show cell
  19343. * @private
  19344. */
  19345. _focus: function ( row, column, shift, originalEvent )
  19346. {
  19347. var that = this;
  19348. var dt = this.s.dt;
  19349. var pageInfo = dt.page.info();
  19350. var lastFocus = this.s.lastFocus;
  19351. if ( ! originalEvent) {
  19352. originalEvent = null;
  19353. }
  19354. if ( ! this.s.enable ) {
  19355. return;
  19356. }
  19357. if ( typeof row !== 'number' ) {
  19358. // Convert the cell to a row and column
  19359. var index = row.index();
  19360. column = index.column;
  19361. row = dt
  19362. .rows( { filter: 'applied', order: 'applied' } )
  19363. .indexes()
  19364. .indexOf( index.row );
  19365. // For server-side processing normalise the row by adding the start
  19366. // point, since `rows().indexes()` includes only rows that are
  19367. // available at the client-side
  19368. if ( pageInfo.serverSide ) {
  19369. row += pageInfo.start;
  19370. }
  19371. }
  19372. // Is the row on the current page? If not, we need to redraw to show the
  19373. // page
  19374. if ( pageInfo.length !== -1 && (row < pageInfo.start || row >= pageInfo.start+pageInfo.length) ) {
  19375. this.s.focusDraw = true;
  19376. this.s.waitingForDraw = true;
  19377. dt
  19378. .one( 'draw', function () {
  19379. that.s.focusDraw = false;
  19380. that.s.waitingForDraw = false;
  19381. that._focus( row, column, undefined, originalEvent );
  19382. } )
  19383. .page( Math.floor( row / pageInfo.length ) )
  19384. .draw( false );
  19385. return;
  19386. }
  19387. // In the available columns?
  19388. if ( $.inArray( column, this._columns() ) === -1 ) {
  19389. return;
  19390. }
  19391. // De-normalise the server-side processing row, so we select the row
  19392. // in its displayed position
  19393. if ( pageInfo.serverSide ) {
  19394. row -= pageInfo.start;
  19395. }
  19396. // Get the cell from the current position - ignoring any cells which might
  19397. // not have been rendered (therefore can't use `:eq()` selector).
  19398. var cells = dt.cells( null, column, {search: 'applied', order: 'applied'} ).flatten();
  19399. var cell = dt.cell( cells[ row ] );
  19400. if ( lastFocus ) {
  19401. // Don't trigger a refocus on the same cell
  19402. if ( lastFocus.node === cell.node() ) {
  19403. this._emitEvent( 'key-refocus', [ this.s.dt, cell, originalEvent || null ] );
  19404. return;
  19405. }
  19406. // Otherwise blur the old focus
  19407. this._blur();
  19408. }
  19409. var node = $( cell.node() );
  19410. node.addClass( this.c.className );
  19411. this._updateFixedColumns(column);
  19412. // Shift viewpoint and page to make cell visible
  19413. if ( shift === undefined || shift === true ) {
  19414. this._scroll( $(window), $(document.body), node, 'offset' );
  19415. var bodyParent = dt.table().body().parentNode;
  19416. if ( bodyParent !== dt.table().header().parentNode ) {
  19417. var parent = $(bodyParent.parentNode);
  19418. this._scroll( parent, parent, node, 'position' );
  19419. }
  19420. }
  19421. // Event and finish
  19422. this.s.lastFocus = {
  19423. cell: cell,
  19424. node: cell.node(),
  19425. relative: {
  19426. row: dt.rows( { page: 'current' } ).indexes().indexOf( cell.index().row ),
  19427. column: cell.index().column
  19428. }
  19429. };
  19430. this._emitEvent( 'key-focus', [ this.s.dt, cell, originalEvent || null ] );
  19431. dt.state.save();
  19432. },
  19433. /**
  19434. * Handle key press
  19435. *
  19436. * @param {object} e Event
  19437. * @private
  19438. */
  19439. _key: function ( e )
  19440. {
  19441. // If we are waiting for a draw to happen from another key event, then
  19442. // do nothing for this new key press.
  19443. if ( this.s.waitingForDraw ) {
  19444. e.preventDefault();
  19445. return;
  19446. }
  19447. var enable = this.s.enable;
  19448. var navEnable = enable === true || enable === 'navigation-only';
  19449. if ( ! enable ) {
  19450. return;
  19451. }
  19452. if ( e.ctrlKey && e.keyCode === 67 ) { // c
  19453. this._clipboardCopy();
  19454. return;
  19455. }
  19456. if ( e.keyCode === 0 || e.ctrlKey || e.metaKey || e.altKey ) {
  19457. return;
  19458. }
  19459. // If not focused, then there is no key action to take
  19460. var lastFocus = this.s.lastFocus;
  19461. if ( ! lastFocus ) {
  19462. return;
  19463. }
  19464. var that = this;
  19465. var dt = this.s.dt;
  19466. // If we are not listening for this key, do nothing
  19467. if ( this.c.keys && $.inArray( e.keyCode, this.c.keys ) === -1 ) {
  19468. return;
  19469. }
  19470. switch( e.keyCode ) {
  19471. case 9: // tab
  19472. // `enable` can be tab-only
  19473. this._shift( e, e.shiftKey ? 'left' : 'right', true );
  19474. break;
  19475. case 27: // esc
  19476. if ( this.s.blurable && enable === true ) {
  19477. this._blur();
  19478. }
  19479. break;
  19480. case 33: // page up (previous page)
  19481. case 34: // page down (next page)
  19482. if ( navEnable ) {
  19483. e.preventDefault();
  19484. dt
  19485. .page( e.keyCode === 33 ? 'previous' : 'next' )
  19486. .draw( false );
  19487. }
  19488. break;
  19489. case 35: // end (end of current page)
  19490. case 36: // home (start of current page)
  19491. if ( navEnable ) {
  19492. e.preventDefault();
  19493. var indexes = dt.cells( {page: 'current'} ).indexes();
  19494. var colIndexes = this._columns();
  19495. this._focus( dt.cell(
  19496. indexes[ e.keyCode === 35 ? indexes.length-1 : colIndexes[0] ]
  19497. ), null, true, e );
  19498. }
  19499. break;
  19500. case 37: // left arrow
  19501. if ( navEnable ) {
  19502. this._shift( e, 'left' );
  19503. }
  19504. break;
  19505. case 38: // up arrow
  19506. if ( navEnable ) {
  19507. this._shift( e, 'up' );
  19508. }
  19509. break;
  19510. case 39: // right arrow
  19511. if ( navEnable ) {
  19512. this._shift( e, 'right' );
  19513. }
  19514. break;
  19515. case 40: // down arrow
  19516. if ( navEnable ) {
  19517. this._shift( e, 'down' );
  19518. }
  19519. break;
  19520. default:
  19521. // Everything else - pass through only when fully enabled
  19522. if ( enable === true ) {
  19523. this._emitEvent( 'key', [ dt, e.keyCode, this.s.lastFocus.cell, e ] );
  19524. }
  19525. break;
  19526. }
  19527. },
  19528. /**
  19529. * Scroll a container to make a cell visible in it. This can be used for
  19530. * both DataTables scrolling and native window scrolling.
  19531. *
  19532. * @param {jQuery} container Scrolling container
  19533. * @param {jQuery} scroller Item being scrolled
  19534. * @param {jQuery} cell Cell in the scroller
  19535. * @param {string} posOff `position` or `offset` - which to use for the
  19536. * calculation. `offset` for the document, otherwise `position`
  19537. * @private
  19538. */
  19539. _scroll: function ( container, scroller, cell, posOff )
  19540. {
  19541. var offset = cell[posOff]();
  19542. var height = cell.outerHeight();
  19543. var width = cell.outerWidth();
  19544. var scrollTop = scroller.scrollTop();
  19545. var scrollLeft = scroller.scrollLeft();
  19546. var containerHeight = container.height();
  19547. var containerWidth = container.width();
  19548. // If Scroller is being used, the table can be `position: absolute` and that
  19549. // needs to be taken account of in the offset. If no Scroller, this will be 0
  19550. if ( posOff === 'position' ) {
  19551. offset.top += parseInt( cell.closest('table').css('top'), 10 );
  19552. }
  19553. // Top correction
  19554. if ( offset.top < scrollTop ) {
  19555. scroller.scrollTop( offset.top );
  19556. }
  19557. // Left correction
  19558. if ( offset.left < scrollLeft ) {
  19559. scroller.scrollLeft( offset.left );
  19560. }
  19561. // Bottom correction
  19562. if ( offset.top + height > scrollTop + containerHeight && height < containerHeight ) {
  19563. scroller.scrollTop( offset.top + height - containerHeight );
  19564. }
  19565. // Right correction
  19566. if ( offset.left + width > scrollLeft + containerWidth && width < containerWidth ) {
  19567. scroller.scrollLeft( offset.left + width - containerWidth );
  19568. }
  19569. },
  19570. /**
  19571. * Calculate a single offset movement in the table - up, down, left and
  19572. * right and then perform the focus if possible
  19573. *
  19574. * @param {object} e Event object
  19575. * @param {string} direction Movement direction
  19576. * @param {boolean} keyBlurable `true` if the key press can result in the
  19577. * table being blurred. This is so arrow keys won't blur the table, but
  19578. * tab will.
  19579. * @private
  19580. */
  19581. _shift: function ( e, direction, keyBlurable )
  19582. {
  19583. var that = this;
  19584. var dt = this.s.dt;
  19585. var pageInfo = dt.page.info();
  19586. var rows = pageInfo.recordsDisplay;
  19587. var currentCell = this.s.lastFocus.cell;
  19588. var columns = this._columns();
  19589. if ( ! currentCell ) {
  19590. return;
  19591. }
  19592. var currRow = dt
  19593. .rows( { filter: 'applied', order: 'applied' } )
  19594. .indexes()
  19595. .indexOf( currentCell.index().row );
  19596. // When server-side processing, `rows().indexes()` only gives the rows
  19597. // that are available at the client-side, so we need to normalise the
  19598. // row's current position by the display start point
  19599. if ( pageInfo.serverSide ) {
  19600. currRow += pageInfo.start;
  19601. }
  19602. var currCol = dt
  19603. .columns( columns )
  19604. .indexes()
  19605. .indexOf( currentCell.index().column );
  19606. var
  19607. row = currRow,
  19608. column = columns[ currCol ]; // row is the display, column is an index
  19609. if ( direction === 'right' ) {
  19610. if ( currCol >= columns.length - 1 ) {
  19611. row++;
  19612. column = columns[0];
  19613. }
  19614. else {
  19615. column = columns[ currCol+1 ];
  19616. }
  19617. }
  19618. else if ( direction === 'left' ) {
  19619. if ( currCol === 0 ) {
  19620. row--;
  19621. column = columns[ columns.length - 1 ];
  19622. }
  19623. else {
  19624. column = columns[ currCol-1 ];
  19625. }
  19626. }
  19627. else if ( direction === 'up' ) {
  19628. row--;
  19629. }
  19630. else if ( direction === 'down' ) {
  19631. row++;
  19632. }
  19633. if ( row >= 0 && row < rows && $.inArray( column, columns ) !== -1
  19634. ) {
  19635. e.preventDefault();
  19636. this._focus( row, column, true, e );
  19637. }
  19638. else if ( ! keyBlurable || ! this.c.blurable ) {
  19639. // No new focus, but if the table isn't blurable, then don't loose
  19640. // focus
  19641. e.preventDefault();
  19642. }
  19643. else {
  19644. this._blur();
  19645. }
  19646. },
  19647. /**
  19648. * Create a hidden input element that can receive focus on behalf of the
  19649. * table
  19650. *
  19651. * @private
  19652. */
  19653. _tabInput: function ()
  19654. {
  19655. var that = this;
  19656. var dt = this.s.dt;
  19657. var tabIndex = this.c.tabIndex !== null ?
  19658. this.c.tabIndex :
  19659. dt.settings()[0].iTabIndex;
  19660. if ( tabIndex == -1 ) {
  19661. return;
  19662. }
  19663. var div = $('<div><input type="text" tabindex="'+tabIndex+'"/></div>')
  19664. .css( {
  19665. position: 'absolute',
  19666. height: 1,
  19667. width: 0,
  19668. overflow: 'hidden'
  19669. } )
  19670. .insertBefore( dt.table().node() );
  19671. div.children().on( 'focus', function (e) {
  19672. if ( dt.cell(':eq(0)', {page: 'current'}).any() ) {
  19673. that._focus( dt.cell(':eq(0)', '0:visible', {page: 'current'}), null, true, e );
  19674. }
  19675. } );
  19676. },
  19677. /**
  19678. * Update fixed columns if they are enabled and if the cell we are
  19679. * focusing is inside a fixed column
  19680. * @param {integer} column Index of the column being changed
  19681. * @private
  19682. */
  19683. _updateFixedColumns: function( column )
  19684. {
  19685. var dt = this.s.dt;
  19686. var settings = dt.settings()[0];
  19687. if ( settings._oFixedColumns ) {
  19688. var leftCols = settings._oFixedColumns.s.iLeftColumns;
  19689. var rightCols = settings.aoColumns.length - settings._oFixedColumns.s.iRightColumns;
  19690. if (column < leftCols || column >= rightCols) {
  19691. dt.fixedColumns().update();
  19692. }
  19693. }
  19694. }
  19695. } );
  19696. /**
  19697. * KeyTable default settings for initialisation
  19698. *
  19699. * @namespace
  19700. * @name KeyTable.defaults
  19701. * @static
  19702. */
  19703. KeyTable.defaults = {
  19704. /**
  19705. * Can focus be removed from the table
  19706. * @type {Boolean}
  19707. */
  19708. blurable: true,
  19709. /**
  19710. * Class to give to the focused cell
  19711. * @type {String}
  19712. */
  19713. className: 'focus',
  19714. /**
  19715. * Columns that can be focused. This is automatically merged with the
  19716. * visible columns as only visible columns can gain focus.
  19717. * @type {String}
  19718. */
  19719. columns: '', // all
  19720. /**
  19721. * Editor instance to automatically perform Excel like navigation
  19722. * @type {Editor}
  19723. */
  19724. editor: null,
  19725. /**
  19726. * Option that defines what KeyTable's behaviour will be when used with
  19727. * Editor's inline editing. Can be `navigation-only` or `tab-only`.
  19728. * @type {String}
  19729. */
  19730. editorKeys: 'navigation-only',
  19731. /**
  19732. * Set if Editor should automatically select the text in the input
  19733. * @type {Boolean}
  19734. */
  19735. editAutoSelect: true,
  19736. /**
  19737. * Control if editing should be activated immediately upon focus
  19738. * @type {Boolean}
  19739. */
  19740. editOnFocus: false,
  19741. /**
  19742. * Select a cell to automatically select on start up. `null` for no
  19743. * automatic selection
  19744. * @type {cell-selector}
  19745. */
  19746. focus: null,
  19747. /**
  19748. * Array of keys to listen for
  19749. * @type {null|array}
  19750. */
  19751. keys: null,
  19752. /**
  19753. * Tab index for where the table should sit in the document's tab flow
  19754. * @type {integer|null}
  19755. */
  19756. tabIndex: null
  19757. };
  19758. KeyTable.version = "2.3.2";
  19759. $.fn.dataTable.KeyTable = KeyTable;
  19760. $.fn.DataTable.KeyTable = KeyTable;
  19761. DataTable.Api.register( 'cell.blur()', function () {
  19762. return this.iterator( 'table', function (ctx) {
  19763. if ( ctx.keytable ) {
  19764. ctx.keytable.blur();
  19765. }
  19766. } );
  19767. } );
  19768. DataTable.Api.register( 'cell().focus()', function () {
  19769. return this.iterator( 'cell', function (ctx, row, column) {
  19770. if ( ctx.keytable ) {
  19771. ctx.keytable.focus( row, column );
  19772. }
  19773. } );
  19774. } );
  19775. DataTable.Api.register( 'keys.disable()', function () {
  19776. return this.iterator( 'table', function (ctx) {
  19777. if ( ctx.keytable ) {
  19778. ctx.keytable.enable( false );
  19779. }
  19780. } );
  19781. } );
  19782. DataTable.Api.register( 'keys.enable()', function ( opts ) {
  19783. return this.iterator( 'table', function (ctx) {
  19784. if ( ctx.keytable ) {
  19785. ctx.keytable.enable( opts === undefined ? true : opts );
  19786. }
  19787. } );
  19788. } );
  19789. // Cell selector
  19790. DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
  19791. var focused = opts.focused;
  19792. var kt = settings.keytable;
  19793. var out = [];
  19794. if ( ! kt || focused === undefined ) {
  19795. return cells;
  19796. }
  19797. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  19798. if ( (focused === true && kt.focused( cells[i] ) ) ||
  19799. (focused === false && ! kt.focused( cells[i] ) )
  19800. ) {
  19801. out.push( cells[i] );
  19802. }
  19803. }
  19804. return out;
  19805. } );
  19806. // Attach a listener to the document which listens for DataTables initialisation
  19807. // events so we can automatically initialise
  19808. $(document).on( 'preInit.dt.dtk', function (e, settings, json) {
  19809. if ( e.namespace !== 'dt' ) {
  19810. return;
  19811. }
  19812. var init = settings.oInit.keys;
  19813. var defaults = DataTable.defaults.keys;
  19814. if ( init || defaults ) {
  19815. var opts = $.extend( {}, defaults, init );
  19816. if ( init !== false ) {
  19817. new KeyTable( settings, opts );
  19818. }
  19819. }
  19820. } );
  19821. return KeyTable;
  19822. }));
  19823. /*! Responsive 2.2.1
  19824. * 2014-2017 SpryMedia Ltd - datatables.net/license
  19825. */
  19826. /**
  19827. * @summary Responsive
  19828. * @description Responsive tables plug-in for DataTables
  19829. * @version 2.2.1
  19830. * @file dataTables.responsive.js
  19831. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  19832. * @contact www.sprymedia.co.uk/contact
  19833. * @copyright Copyright 2014-2017 SpryMedia Ltd.
  19834. *
  19835. * This source file is free software, available under the following license:
  19836. * MIT license - http://datatables.net/license/mit
  19837. *
  19838. * This source file is distributed in the hope that it will be useful, but
  19839. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  19840. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  19841. *
  19842. * For details please refer to: http://www.datatables.net
  19843. */
  19844. (function( factory ){
  19845. if ( typeof define === 'function' && define.amd ) {
  19846. // AMD
  19847. define( ['jquery', 'datatables.net'], function ( $ ) {
  19848. return factory( $, window, document );
  19849. } );
  19850. }
  19851. else if ( typeof exports === 'object' ) {
  19852. // CommonJS
  19853. module.exports = function (root, $) {
  19854. if ( ! root ) {
  19855. root = window;
  19856. }
  19857. if ( ! $ || ! $.fn.dataTable ) {
  19858. $ = require('datatables.net')(root, $).$;
  19859. }
  19860. return factory( $, root, root.document );
  19861. };
  19862. }
  19863. else {
  19864. // Browser
  19865. factory( jQuery, window, document );
  19866. }
  19867. }(function( $, window, document, undefined ) {
  19868. 'use strict';
  19869. var DataTable = $.fn.dataTable;
  19870. /**
  19871. * Responsive is a plug-in for the DataTables library that makes use of
  19872. * DataTables' ability to change the visibility of columns, changing the
  19873. * visibility of columns so the displayed columns fit into the table container.
  19874. * The end result is that complex tables will be dynamically adjusted to fit
  19875. * into the viewport, be it on a desktop, tablet or mobile browser.
  19876. *
  19877. * Responsive for DataTables has two modes of operation, which can used
  19878. * individually or combined:
  19879. *
  19880. * * Class name based control - columns assigned class names that match the
  19881. * breakpoint logic can be shown / hidden as required for each breakpoint.
  19882. * * Automatic control - columns are automatically hidden when there is no
  19883. * room left to display them. Columns removed from the right.
  19884. *
  19885. * In additional to column visibility control, Responsive also has built into
  19886. * options to use DataTables' child row display to show / hide the information
  19887. * from the table that has been hidden. There are also two modes of operation
  19888. * for this child row display:
  19889. *
  19890. * * Inline - when the control element that the user can use to show / hide
  19891. * child rows is displayed inside the first column of the table.
  19892. * * Column - where a whole column is dedicated to be the show / hide control.
  19893. *
  19894. * Initialisation of Responsive is performed by:
  19895. *
  19896. * * Adding the class `responsive` or `dt-responsive` to the table. In this case
  19897. * Responsive will automatically be initialised with the default configuration
  19898. * options when the DataTable is created.
  19899. * * Using the `responsive` option in the DataTables configuration options. This
  19900. * can also be used to specify the configuration options, or simply set to
  19901. * `true` to use the defaults.
  19902. *
  19903. * @class
  19904. * @param {object} settings DataTables settings object for the host table
  19905. * @param {object} [opts] Configuration options
  19906. * @requires jQuery 1.7+
  19907. * @requires DataTables 1.10.3+
  19908. *
  19909. * @example
  19910. * $('#example').DataTable( {
  19911. * responsive: true
  19912. * } );
  19913. * } );
  19914. */
  19915. var Responsive = function ( settings, opts ) {
  19916. // Sanity check that we are using DataTables 1.10 or newer
  19917. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) {
  19918. throw 'DataTables Responsive requires DataTables 1.10.10 or newer';
  19919. }
  19920. this.s = {
  19921. dt: new DataTable.Api( settings ),
  19922. columns: [],
  19923. current: []
  19924. };
  19925. // Check if responsive has already been initialised on this table
  19926. if ( this.s.dt.settings()[0].responsive ) {
  19927. return;
  19928. }
  19929. // details is an object, but for simplicity the user can give it as a string
  19930. // or a boolean
  19931. if ( opts && typeof opts.details === 'string' ) {
  19932. opts.details = { type: opts.details };
  19933. }
  19934. else if ( opts && opts.details === false ) {
  19935. opts.details = { type: false };
  19936. }
  19937. else if ( opts && opts.details === true ) {
  19938. opts.details = { type: 'inline' };
  19939. }
  19940. this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
  19941. settings.responsive = this;
  19942. this._constructor();
  19943. };
  19944. $.extend( Responsive.prototype, {
  19945. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19946. * Constructor
  19947. */
  19948. /**
  19949. * Initialise the Responsive instance
  19950. *
  19951. * @private
  19952. */
  19953. _constructor: function ()
  19954. {
  19955. var that = this;
  19956. var dt = this.s.dt;
  19957. var dtPrivateSettings = dt.settings()[0];
  19958. var oldWindowWidth = $(window).width();
  19959. dt.settings()[0]._responsive = this;
  19960. // Use DataTables' throttle function to avoid processor thrashing on
  19961. // resize
  19962. $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
  19963. // iOS has a bug whereby resize can fire when only scrolling
  19964. // See: http://stackoverflow.com/questions/8898412
  19965. var width = $(window).width();
  19966. if ( width !== oldWindowWidth ) {
  19967. that._resize();
  19968. oldWindowWidth = width;
  19969. }
  19970. } ) );
  19971. // DataTables doesn't currently trigger an event when a row is added, so
  19972. // we need to hook into its private API to enforce the hidden rows when
  19973. // new data is added
  19974. dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
  19975. if ( $.inArray( false, that.s.current ) !== -1 ) {
  19976. $('>td, >th', tr).each( function ( i ) {
  19977. var idx = dt.column.index( 'toData', i );
  19978. if ( that.s.current[idx] === false ) {
  19979. $(this).css('display', 'none');
  19980. }
  19981. } );
  19982. }
  19983. } );
  19984. // Destroy event handler
  19985. dt.on( 'destroy.dtr', function () {
  19986. dt.off( '.dtr' );
  19987. $( dt.table().body() ).off( '.dtr' );
  19988. $(window).off( 'resize.dtr orientationchange.dtr' );
  19989. // Restore the columns that we've hidden
  19990. $.each( that.s.current, function ( i, val ) {
  19991. if ( val === false ) {
  19992. that._setColumnVis( i, true );
  19993. }
  19994. } );
  19995. } );
  19996. // Reorder the breakpoints array here in case they have been added out
  19997. // of order
  19998. this.c.breakpoints.sort( function (a, b) {
  19999. return a.width < b.width ? 1 :
  20000. a.width > b.width ? -1 : 0;
  20001. } );
  20002. this._classLogic();
  20003. this._resizeAuto();
  20004. // Details handler
  20005. var details = this.c.details;
  20006. if ( details.type !== false ) {
  20007. that._detailsInit();
  20008. // DataTables will trigger this event on every column it shows and
  20009. // hides individually
  20010. dt.on( 'column-visibility.dtr', function (e, ctx, col, vis, recalc) {
  20011. if ( recalc ) {
  20012. that._classLogic();
  20013. that._resizeAuto();
  20014. that._resize();
  20015. }
  20016. } );
  20017. // Redraw the details box on each draw which will happen if the data
  20018. // has changed. This is used until DataTables implements a native
  20019. // `updated` event for rows
  20020. dt.on( 'draw.dtr', function () {
  20021. that._redrawChildren();
  20022. } );
  20023. $(dt.table().node()).addClass( 'dtr-'+details.type );
  20024. }
  20025. dt.on( 'column-reorder.dtr', function (e, settings, details) {
  20026. that._classLogic();
  20027. that._resizeAuto();
  20028. that._resize();
  20029. } );
  20030. // Change in column sizes means we need to calc
  20031. dt.on( 'column-sizing.dtr', function () {
  20032. that._resizeAuto();
  20033. that._resize();
  20034. });
  20035. // On Ajax reload we want to reopen any child rows which are displayed
  20036. // by responsive
  20037. dt.on( 'preXhr.dtr', function () {
  20038. var rowIds = [];
  20039. dt.rows().every( function () {
  20040. if ( this.child.isShown() ) {
  20041. rowIds.push( this.id(true) );
  20042. }
  20043. } );
  20044. dt.one( 'draw.dtr', function () {
  20045. that._resizeAuto();
  20046. that._resize();
  20047. dt.rows( rowIds ).every( function () {
  20048. that._detailsDisplay( this, false );
  20049. } );
  20050. } );
  20051. });
  20052. dt.on( 'init.dtr', function (e, settings, details) {
  20053. that._resizeAuto();
  20054. that._resize();
  20055. // If columns were hidden, then DataTables needs to adjust the
  20056. // column sizing
  20057. if ( $.inArray( false, that.s.current ) ) {
  20058. dt.columns.adjust();
  20059. }
  20060. } );
  20061. // First pass - draw the table for the current viewport size
  20062. this._resize();
  20063. },
  20064. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20065. * Private methods
  20066. */
  20067. /**
  20068. * Calculate the visibility for the columns in a table for a given
  20069. * breakpoint. The result is pre-determined based on the class logic if
  20070. * class names are used to control all columns, but the width of the table
  20071. * is also used if there are columns which are to be automatically shown
  20072. * and hidden.
  20073. *
  20074. * @param {string} breakpoint Breakpoint name to use for the calculation
  20075. * @return {array} Array of boolean values initiating the visibility of each
  20076. * column.
  20077. * @private
  20078. */
  20079. _columnsVisiblity: function ( breakpoint )
  20080. {
  20081. var dt = this.s.dt;
  20082. var columns = this.s.columns;
  20083. var i, ien;
  20084. // Create an array that defines the column ordering based first on the
  20085. // column's priority, and secondly the column index. This allows the
  20086. // columns to be removed from the right if the priority matches
  20087. var order = columns
  20088. .map( function ( col, idx ) {
  20089. return {
  20090. columnIdx: idx,
  20091. priority: col.priority
  20092. };
  20093. } )
  20094. .sort( function ( a, b ) {
  20095. if ( a.priority !== b.priority ) {
  20096. return a.priority - b.priority;
  20097. }
  20098. return a.columnIdx - b.columnIdx;
  20099. } );
  20100. // Class logic - determine which columns are in this breakpoint based
  20101. // on the classes. If no class control (i.e. `auto`) then `-` is used
  20102. // to indicate this to the rest of the function
  20103. var display = $.map( columns, function ( col ) {
  20104. return col.auto && col.minWidth === null ?
  20105. false :
  20106. col.auto === true ?
  20107. '-' :
  20108. $.inArray( breakpoint, col.includeIn ) !== -1;
  20109. } );
  20110. // Auto column control - first pass: how much width is taken by the
  20111. // ones that must be included from the non-auto columns
  20112. var requiredWidth = 0;
  20113. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  20114. if ( display[i] === true ) {
  20115. requiredWidth += columns[i].minWidth;
  20116. }
  20117. }
  20118. // Second pass, use up any remaining width for other columns. For
  20119. // scrolling tables we need to subtract the width of the scrollbar. It
  20120. // may not be requires which makes this sub-optimal, but it would
  20121. // require another full redraw to make complete use of those extra few
  20122. // pixels
  20123. var scrolling = dt.settings()[0].oScroll;
  20124. var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
  20125. var widthAvailable = dt.table().container().offsetWidth - bar;
  20126. var usedWidth = widthAvailable - requiredWidth;
  20127. // Control column needs to always be included. This makes it sub-
  20128. // optimal in terms of using the available with, but to stop layout
  20129. // thrashing or overflow. Also we need to account for the control column
  20130. // width first so we know how much width is available for the other
  20131. // columns, since the control column might not be the first one shown
  20132. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  20133. if ( columns[i].control ) {
  20134. usedWidth -= columns[i].minWidth;
  20135. }
  20136. }
  20137. // Allow columns to be shown (counting by priority and then right to
  20138. // left) until we run out of room
  20139. var empty = false;
  20140. for ( i=0, ien=order.length ; i<ien ; i++ ) {
  20141. var colIdx = order[i].columnIdx;
  20142. if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
  20143. // Once we've found a column that won't fit we don't let any
  20144. // others display either, or columns might disappear in the
  20145. // middle of the table
  20146. if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
  20147. empty = true;
  20148. display[colIdx] = false;
  20149. }
  20150. else {
  20151. display[colIdx] = true;
  20152. }
  20153. usedWidth -= columns[colIdx].minWidth;
  20154. }
  20155. }
  20156. // Determine if the 'control' column should be shown (if there is one).
  20157. // This is the case when there is a hidden column (that is not the
  20158. // control column). The two loops look inefficient here, but they are
  20159. // trivial and will fly through. We need to know the outcome from the
  20160. // first , before the action in the second can be taken
  20161. var showControl = false;
  20162. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  20163. if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
  20164. showControl = true;
  20165. break;
  20166. }
  20167. }
  20168. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  20169. if ( columns[i].control ) {
  20170. display[i] = showControl;
  20171. }
  20172. }
  20173. // Finally we need to make sure that there is at least one column that
  20174. // is visible
  20175. if ( $.inArray( true, display ) === -1 ) {
  20176. display[0] = true;
  20177. }
  20178. return display;
  20179. },
  20180. /**
  20181. * Create the internal `columns` array with information about the columns
  20182. * for the table. This includes determining which breakpoints the column
  20183. * will appear in, based upon class names in the column, which makes up the
  20184. * vast majority of this method.
  20185. *
  20186. * @private
  20187. */
  20188. _classLogic: function ()
  20189. {
  20190. var that = this;
  20191. var calc = {};
  20192. var breakpoints = this.c.breakpoints;
  20193. var dt = this.s.dt;
  20194. var columns = dt.columns().eq(0).map( function (i) {
  20195. var column = this.column(i);
  20196. var className = column.header().className;
  20197. var priority = dt.settings()[0].aoColumns[i].responsivePriority;
  20198. if ( priority === undefined ) {
  20199. var dataPriority = $(column.header()).data('priority');
  20200. priority = dataPriority !== undefined ?
  20201. dataPriority * 1 :
  20202. 10000;
  20203. }
  20204. return {
  20205. className: className,
  20206. includeIn: [],
  20207. auto: false,
  20208. control: false,
  20209. never: className.match(/\bnever\b/) ? true : false,
  20210. priority: priority
  20211. };
  20212. } );
  20213. // Simply add a breakpoint to `includeIn` array, ensuring that there are
  20214. // no duplicates
  20215. var add = function ( colIdx, name ) {
  20216. var includeIn = columns[ colIdx ].includeIn;
  20217. if ( $.inArray( name, includeIn ) === -1 ) {
  20218. includeIn.push( name );
  20219. }
  20220. };
  20221. var column = function ( colIdx, name, operator, matched ) {
  20222. var size, i, ien;
  20223. if ( ! operator ) {
  20224. columns[ colIdx ].includeIn.push( name );
  20225. }
  20226. else if ( operator === 'max-' ) {
  20227. // Add this breakpoint and all smaller
  20228. size = that._find( name ).width;
  20229. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  20230. if ( breakpoints[i].width <= size ) {
  20231. add( colIdx, breakpoints[i].name );
  20232. }
  20233. }
  20234. }
  20235. else if ( operator === 'min-' ) {
  20236. // Add this breakpoint and all larger
  20237. size = that._find( name ).width;
  20238. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  20239. if ( breakpoints[i].width >= size ) {
  20240. add( colIdx, breakpoints[i].name );
  20241. }
  20242. }
  20243. }
  20244. else if ( operator === 'not-' ) {
  20245. // Add all but this breakpoint
  20246. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  20247. if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
  20248. add( colIdx, breakpoints[i].name );
  20249. }
  20250. }
  20251. }
  20252. };
  20253. // Loop over each column and determine if it has a responsive control
  20254. // class
  20255. columns.each( function ( col, i ) {
  20256. var classNames = col.className.split(' ');
  20257. var hasClass = false;
  20258. // Split the class name up so multiple rules can be applied if needed
  20259. for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
  20260. var className = $.trim( classNames[k] );
  20261. if ( className === 'all' ) {
  20262. // Include in all
  20263. hasClass = true;
  20264. col.includeIn = $.map( breakpoints, function (a) {
  20265. return a.name;
  20266. } );
  20267. return;
  20268. }
  20269. else if ( className === 'none' || col.never ) {
  20270. // Include in none (default) and no auto
  20271. hasClass = true;
  20272. return;
  20273. }
  20274. else if ( className === 'control' ) {
  20275. // Special column that is only visible, when one of the other
  20276. // columns is hidden. This is used for the details control
  20277. hasClass = true;
  20278. col.control = true;
  20279. return;
  20280. }
  20281. $.each( breakpoints, function ( j, breakpoint ) {
  20282. // Does this column have a class that matches this breakpoint?
  20283. var brokenPoint = breakpoint.name.split('-');
  20284. var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
  20285. var match = className.match( re );
  20286. if ( match ) {
  20287. hasClass = true;
  20288. if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
  20289. // Class name matches breakpoint name fully
  20290. column( i, breakpoint.name, match[1], match[2]+match[3] );
  20291. }
  20292. else if ( match[2] === brokenPoint[0] && ! match[3] ) {
  20293. // Class name matched primary breakpoint name with no qualifier
  20294. column( i, breakpoint.name, match[1], match[2] );
  20295. }
  20296. }
  20297. } );
  20298. }
  20299. // If there was no control class, then automatic sizing is used
  20300. if ( ! hasClass ) {
  20301. col.auto = true;
  20302. }
  20303. } );
  20304. this.s.columns = columns;
  20305. },
  20306. /**
  20307. * Show the details for the child row
  20308. *
  20309. * @param {DataTables.Api} row API instance for the row
  20310. * @param {boolean} update Update flag
  20311. * @private
  20312. */
  20313. _detailsDisplay: function ( row, update )
  20314. {
  20315. var that = this;
  20316. var dt = this.s.dt;
  20317. var details = this.c.details;
  20318. if ( details && details.type !== false ) {
  20319. var res = details.display( row, update, function () {
  20320. return details.renderer(
  20321. dt, row[0], that._detailsObj(row[0])
  20322. );
  20323. } );
  20324. if ( res === true || res === false ) {
  20325. $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
  20326. }
  20327. }
  20328. },
  20329. /**
  20330. * Initialisation for the details handler
  20331. *
  20332. * @private
  20333. */
  20334. _detailsInit: function ()
  20335. {
  20336. var that = this;
  20337. var dt = this.s.dt;
  20338. var details = this.c.details;
  20339. // The inline type always uses the first child as the target
  20340. if ( details.type === 'inline' ) {
  20341. details.target = 'td:first-child, th:first-child';
  20342. }
  20343. // Keyboard accessibility
  20344. dt.on( 'draw.dtr', function () {
  20345. that._tabIndexes();
  20346. } );
  20347. that._tabIndexes(); // Initial draw has already happened
  20348. $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
  20349. if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
  20350. $(this).click();
  20351. }
  20352. } );
  20353. // type.target can be a string jQuery selector or a column index
  20354. var target = details.target;
  20355. var selector = typeof target === 'string' ? target : 'td, th';
  20356. // Click handler to show / hide the details rows when they are available
  20357. $( dt.table().body() )
  20358. .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
  20359. // If the table is not collapsed (i.e. there is no hidden columns)
  20360. // then take no action
  20361. if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
  20362. return;
  20363. }
  20364. // Check that the row is actually a DataTable's controlled node
  20365. if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
  20366. return;
  20367. }
  20368. // For column index, we determine if we should act or not in the
  20369. // handler - otherwise it is already okay
  20370. if ( typeof target === 'number' ) {
  20371. var targetIdx = target < 0 ?
  20372. dt.columns().eq(0).length + target :
  20373. target;
  20374. if ( dt.cell( this ).index().column !== targetIdx ) {
  20375. return;
  20376. }
  20377. }
  20378. // $().closest() includes itself in its check
  20379. var row = dt.row( $(this).closest('tr') );
  20380. // Check event type to do an action
  20381. if ( e.type === 'click' ) {
  20382. // The renderer is given as a function so the caller can execute it
  20383. // only when they need (i.e. if hiding there is no point is running
  20384. // the renderer)
  20385. that._detailsDisplay( row, false );
  20386. }
  20387. else if ( e.type === 'mousedown' ) {
  20388. // For mouse users, prevent the focus ring from showing
  20389. $(this).css('outline', 'none');
  20390. }
  20391. else if ( e.type === 'mouseup' ) {
  20392. // And then re-allow at the end of the click
  20393. $(this).blur().css('outline', '');
  20394. }
  20395. } );
  20396. },
  20397. /**
  20398. * Get the details to pass to a renderer for a row
  20399. * @param {int} rowIdx Row index
  20400. * @private
  20401. */
  20402. _detailsObj: function ( rowIdx )
  20403. {
  20404. var that = this;
  20405. var dt = this.s.dt;
  20406. return $.map( this.s.columns, function( col, i ) {
  20407. // Never and control columns should not be passed to the renderer
  20408. if ( col.never || col.control ) {
  20409. return;
  20410. }
  20411. return {
  20412. title: dt.settings()[0].aoColumns[ i ].sTitle,
  20413. data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
  20414. hidden: dt.column( i ).visible() && !that.s.current[ i ],
  20415. columnIndex: i,
  20416. rowIndex: rowIdx
  20417. };
  20418. } );
  20419. },
  20420. /**
  20421. * Find a breakpoint object from a name
  20422. *
  20423. * @param {string} name Breakpoint name to find
  20424. * @return {object} Breakpoint description object
  20425. * @private
  20426. */
  20427. _find: function ( name )
  20428. {
  20429. var breakpoints = this.c.breakpoints;
  20430. for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  20431. if ( breakpoints[i].name === name ) {
  20432. return breakpoints[i];
  20433. }
  20434. }
  20435. },
  20436. /**
  20437. * Re-create the contents of the child rows as the display has changed in
  20438. * some way.
  20439. *
  20440. * @private
  20441. */
  20442. _redrawChildren: function ()
  20443. {
  20444. var that = this;
  20445. var dt = this.s.dt;
  20446. dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
  20447. var row = dt.row( idx );
  20448. that._detailsDisplay( dt.row( idx ), true );
  20449. } );
  20450. },
  20451. /**
  20452. * Alter the table display for a resized viewport. This involves first
  20453. * determining what breakpoint the window currently is in, getting the
  20454. * column visibilities to apply and then setting them.
  20455. *
  20456. * @private
  20457. */
  20458. _resize: function ()
  20459. {
  20460. var that = this;
  20461. var dt = this.s.dt;
  20462. var width = $(window).width();
  20463. var breakpoints = this.c.breakpoints;
  20464. var breakpoint = breakpoints[0].name;
  20465. var columns = this.s.columns;
  20466. var i, ien;
  20467. var oldVis = this.s.current.slice();
  20468. // Determine what breakpoint we are currently at
  20469. for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
  20470. if ( width <= breakpoints[i].width ) {
  20471. breakpoint = breakpoints[i].name;
  20472. break;
  20473. }
  20474. }
  20475. // Show the columns for that break point
  20476. var columnsVis = this._columnsVisiblity( breakpoint );
  20477. this.s.current = columnsVis;
  20478. // Set the class before the column visibility is changed so event
  20479. // listeners know what the state is. Need to determine if there are
  20480. // any columns that are not visible but can be shown
  20481. var collapsedClass = false;
  20482. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  20483. if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control ) {
  20484. collapsedClass = true;
  20485. break;
  20486. }
  20487. }
  20488. $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
  20489. var changed = false;
  20490. var visible = 0;
  20491. dt.columns().eq(0).each( function ( colIdx, i ) {
  20492. if ( columnsVis[i] === true ) {
  20493. visible++;
  20494. }
  20495. if ( columnsVis[i] !== oldVis[i] ) {
  20496. changed = true;
  20497. that._setColumnVis( colIdx, columnsVis[i] );
  20498. }
  20499. } );
  20500. if ( changed ) {
  20501. this._redrawChildren();
  20502. // Inform listeners of the change
  20503. $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
  20504. // If no records, update the "No records" display element
  20505. if ( dt.page.info().recordsDisplay === 0 ) {
  20506. $('td', dt.table().body()).eq(0).attr('colspan', visible);
  20507. }
  20508. }
  20509. },
  20510. /**
  20511. * Determine the width of each column in the table so the auto column hiding
  20512. * has that information to work with. This method is never going to be 100%
  20513. * perfect since column widths can change slightly per page, but without
  20514. * seriously compromising performance this is quite effective.
  20515. *
  20516. * @private
  20517. */
  20518. _resizeAuto: function ()
  20519. {
  20520. var dt = this.s.dt;
  20521. var columns = this.s.columns;
  20522. // Are we allowed to do auto sizing?
  20523. if ( ! this.c.auto ) {
  20524. return;
  20525. }
  20526. // Are there any columns that actually need auto-sizing, or do they all
  20527. // have classes defined
  20528. if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
  20529. return;
  20530. }
  20531. // Need to restore all children. They will be reinstated by a re-render
  20532. if ( ! $.isEmptyObject( _childNodeStore ) ) {
  20533. $.each( _childNodeStore, function ( key ) {
  20534. var idx = key.split('-');
  20535. _childNodesRestore( dt, idx[0]*1, idx[1]*1 );
  20536. } );
  20537. }
  20538. // Clone the table with the current data in it
  20539. var tableWidth = dt.table().node().offsetWidth;
  20540. var columnWidths = dt.columns;
  20541. var clonedTable = dt.table().node().cloneNode( false );
  20542. var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
  20543. var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
  20544. // Header
  20545. var headerCells = dt.columns()
  20546. .header()
  20547. .filter( function (idx) {
  20548. return dt.column(idx).visible();
  20549. } )
  20550. .to$()
  20551. .clone( false )
  20552. .css( 'display', 'table-cell' )
  20553. .css( 'min-width', 0 );
  20554. // Body rows - we don't need to take account of DataTables' column
  20555. // visibility since we implement our own here (hence the `display` set)
  20556. $(clonedBody)
  20557. .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
  20558. .find( 'th, td' ).css( 'display', '' );
  20559. // Footer
  20560. var footer = dt.table().footer();
  20561. if ( footer ) {
  20562. var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
  20563. var footerCells = dt.columns()
  20564. .footer()
  20565. .filter( function (idx) {
  20566. return dt.column(idx).visible();
  20567. } )
  20568. .to$()
  20569. .clone( false )
  20570. .css( 'display', 'table-cell' );
  20571. $('<tr/>')
  20572. .append( footerCells )
  20573. .appendTo( clonedFooter );
  20574. }
  20575. $('<tr/>')
  20576. .append( headerCells )
  20577. .appendTo( clonedHeader );
  20578. // In the inline case extra padding is applied to the first column to
  20579. // give space for the show / hide icon. We need to use this in the
  20580. // calculation
  20581. if ( this.c.details.type === 'inline' ) {
  20582. $(clonedTable).addClass( 'dtr-inline collapsed' );
  20583. }
  20584. // It is unsafe to insert elements with the same name into the DOM
  20585. // multiple times. For example, cloning and inserting a checked radio
  20586. // clears the chcecked state of the original radio.
  20587. $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
  20588. var inserted = $('<div/>')
  20589. .css( {
  20590. width: 1,
  20591. height: 1,
  20592. overflow: 'hidden',
  20593. clear: 'both'
  20594. } )
  20595. .append( clonedTable );
  20596. inserted.insertBefore( dt.table().node() );
  20597. // The cloned header now contains the smallest that each column can be
  20598. headerCells.each( function (i) {
  20599. var idx = dt.column.index( 'fromVisible', i );
  20600. columns[ idx ].minWidth = this.offsetWidth || 0;
  20601. } );
  20602. inserted.remove();
  20603. },
  20604. /**
  20605. * Set a column's visibility.
  20606. *
  20607. * We don't use DataTables' column visibility controls in order to ensure
  20608. * that column visibility can Responsive can no-exist. Since only IE8+ is
  20609. * supported (and all evergreen browsers of course) the control of the
  20610. * display attribute works well.
  20611. *
  20612. * @param {integer} col Column index
  20613. * @param {boolean} showHide Show or hide (true or false)
  20614. * @private
  20615. */
  20616. _setColumnVis: function ( col, showHide )
  20617. {
  20618. var dt = this.s.dt;
  20619. var display = showHide ? '' : 'none'; // empty string will remove the attr
  20620. $( dt.column( col ).header() ).css( 'display', display );
  20621. $( dt.column( col ).footer() ).css( 'display', display );
  20622. dt.column( col ).nodes().to$().css( 'display', display );
  20623. // If the are child nodes stored, we might need to reinsert them
  20624. if ( ! $.isEmptyObject( _childNodeStore ) ) {
  20625. dt.cells( null, col ).indexes().each( function (idx) {
  20626. _childNodesRestore( dt, idx.row, idx.column );
  20627. } );
  20628. }
  20629. },
  20630. /**
  20631. * Update the cell tab indexes for keyboard accessibility. This is called on
  20632. * every table draw - that is potentially inefficient, but also the least
  20633. * complex option given that column visibility can change on the fly. Its a
  20634. * shame user-focus was removed from CSS 3 UI, as it would have solved this
  20635. * issue with a single CSS statement.
  20636. *
  20637. * @private
  20638. */
  20639. _tabIndexes: function ()
  20640. {
  20641. var dt = this.s.dt;
  20642. var cells = dt.cells( { page: 'current' } ).nodes().to$();
  20643. var ctx = dt.settings()[0];
  20644. var target = this.c.details.target;
  20645. cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
  20646. var selector = typeof target === 'number' ?
  20647. ':eq('+target+')' :
  20648. target;
  20649. // This is a bit of a hack - we need to limit the selected nodes to just
  20650. // those of this table
  20651. if ( selector === 'td:first-child, th:first-child' ) {
  20652. selector = '>td:first-child, >th:first-child';
  20653. }
  20654. $( selector, dt.rows( { page: 'current' } ).nodes() )
  20655. .attr( 'tabIndex', ctx.iTabIndex )
  20656. .data( 'dtr-keyboard', 1 );
  20657. }
  20658. } );
  20659. /**
  20660. * List of default breakpoints. Each item in the array is an object with two
  20661. * properties:
  20662. *
  20663. * * `name` - the breakpoint name.
  20664. * * `width` - the breakpoint width
  20665. *
  20666. * @name Responsive.breakpoints
  20667. * @static
  20668. */
  20669. Responsive.breakpoints = [
  20670. { name: 'desktop', width: Infinity },
  20671. { name: 'tablet-l', width: 1024 },
  20672. { name: 'tablet-p', width: 768 },
  20673. { name: 'mobile-l', width: 480 },
  20674. { name: 'mobile-p', width: 320 }
  20675. ];
  20676. /**
  20677. * Display methods - functions which define how the hidden data should be shown
  20678. * in the table.
  20679. *
  20680. * @namespace
  20681. * @name Responsive.defaults
  20682. * @static
  20683. */
  20684. Responsive.display = {
  20685. childRow: function ( row, update, render ) {
  20686. if ( update ) {
  20687. if ( $(row.node()).hasClass('parent') ) {
  20688. row.child( render(), 'child' ).show();
  20689. return true;
  20690. }
  20691. }
  20692. else {
  20693. if ( ! row.child.isShown() ) {
  20694. row.child( render(), 'child' ).show();
  20695. $( row.node() ).addClass( 'parent' );
  20696. return true;
  20697. }
  20698. else {
  20699. row.child( false );
  20700. $( row.node() ).removeClass( 'parent' );
  20701. return false;
  20702. }
  20703. }
  20704. },
  20705. childRowImmediate: function ( row, update, render ) {
  20706. if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
  20707. // User interaction and the row is show, or nothing to show
  20708. row.child( false );
  20709. $( row.node() ).removeClass( 'parent' );
  20710. return false;
  20711. }
  20712. else {
  20713. // Display
  20714. row.child( render(), 'child' ).show();
  20715. $( row.node() ).addClass( 'parent' );
  20716. return true;
  20717. }
  20718. },
  20719. // This is a wrapper so the modal options for Bootstrap and jQuery UI can
  20720. // have options passed into them. This specific one doesn't need to be a
  20721. // function but it is for consistency in the `modal` name
  20722. modal: function ( options ) {
  20723. return function ( row, update, render ) {
  20724. if ( ! update ) {
  20725. // Show a modal
  20726. var close = function () {
  20727. modal.remove(); // will tidy events for us
  20728. $(document).off( 'keypress.dtr' );
  20729. };
  20730. var modal = $('<div class="dtr-modal"/>')
  20731. .append( $('<div class="dtr-modal-display"/>')
  20732. .append( $('<div class="dtr-modal-content"/>')
  20733. .append( render() )
  20734. )
  20735. .append( $('<div class="dtr-modal-close">&times;</div>' )
  20736. .click( function () {
  20737. close();
  20738. } )
  20739. )
  20740. )
  20741. .append( $('<div class="dtr-modal-background"/>')
  20742. .click( function () {
  20743. close();
  20744. } )
  20745. )
  20746. .appendTo( 'body' );
  20747. $(document).on( 'keyup.dtr', function (e) {
  20748. if ( e.keyCode === 27 ) {
  20749. e.stopPropagation();
  20750. close();
  20751. }
  20752. } );
  20753. }
  20754. else {
  20755. $('div.dtr-modal-content')
  20756. .empty()
  20757. .append( render() );
  20758. }
  20759. if ( options && options.header ) {
  20760. $('div.dtr-modal-content').prepend(
  20761. '<h2>'+options.header( row )+'</h2>'
  20762. );
  20763. }
  20764. };
  20765. }
  20766. };
  20767. var _childNodeStore = {};
  20768. function _childNodes( dt, row, col ) {
  20769. var name = row+'-'+col;
  20770. if ( _childNodeStore[ name ] ) {
  20771. return _childNodeStore[ name ];
  20772. }
  20773. // https://jsperf.com/childnodes-array-slice-vs-loop
  20774. var nodes = [];
  20775. var children = dt.cell( row, col ).node().childNodes;
  20776. for ( var i=0, ien=children.length ; i<ien ; i++ ) {
  20777. nodes.push( children[i] );
  20778. }
  20779. _childNodeStore[ name ] = nodes;
  20780. return nodes;
  20781. }
  20782. function _childNodesRestore( dt, row, col ) {
  20783. var name = row+'-'+col;
  20784. if ( ! _childNodeStore[ name ] ) {
  20785. return;
  20786. }
  20787. var node = dt.cell( row, col ).node();
  20788. var store = _childNodeStore[ name ];
  20789. var parent = store[0].parentNode;
  20790. var parentChildren = parent.childNodes;
  20791. var a = [];
  20792. for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
  20793. a.push( parentChildren[i] );
  20794. }
  20795. for ( var j=0, jen=a.length ; j<jen ; j++ ) {
  20796. node.appendChild( a[j] );
  20797. }
  20798. _childNodeStore[ name ] = undefined;
  20799. }
  20800. /**
  20801. * Display methods - functions which define how the hidden data should be shown
  20802. * in the table.
  20803. *
  20804. * @namespace
  20805. * @name Responsive.defaults
  20806. * @static
  20807. */
  20808. Responsive.renderer = {
  20809. listHiddenNodes: function () {
  20810. return function ( api, rowIdx, columns ) {
  20811. var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>');
  20812. var found = false;
  20813. var data = $.each( columns, function ( i, col ) {
  20814. if ( col.hidden ) {
  20815. $(
  20816. '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
  20817. '<span class="dtr-title">'+
  20818. col.title+
  20819. '</span> '+
  20820. '</li>'
  20821. )
  20822. .append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
  20823. .appendTo( ul );
  20824. found = true;
  20825. }
  20826. } );
  20827. return found ?
  20828. ul :
  20829. false;
  20830. };
  20831. },
  20832. listHidden: function () {
  20833. return function ( api, rowIdx, columns ) {
  20834. var data = $.map( columns, function ( col ) {
  20835. return col.hidden ?
  20836. '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
  20837. '<span class="dtr-title">'+
  20838. col.title+
  20839. '</span> '+
  20840. '<span class="dtr-data">'+
  20841. col.data+
  20842. '</span>'+
  20843. '</li>' :
  20844. '';
  20845. } ).join('');
  20846. return data ?
  20847. $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
  20848. false;
  20849. }
  20850. },
  20851. tableAll: function ( options ) {
  20852. options = $.extend( {
  20853. tableClass: ''
  20854. }, options );
  20855. return function ( api, rowIdx, columns ) {
  20856. var data = $.map( columns, function ( col ) {
  20857. return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
  20858. '<td>'+col.title+':'+'</td> '+
  20859. '<td>'+col.data+'</td>'+
  20860. '</tr>';
  20861. } ).join('');
  20862. return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
  20863. }
  20864. }
  20865. };
  20866. /**
  20867. * Responsive default settings for initialisation
  20868. *
  20869. * @namespace
  20870. * @name Responsive.defaults
  20871. * @static
  20872. */
  20873. Responsive.defaults = {
  20874. /**
  20875. * List of breakpoints for the instance. Note that this means that each
  20876. * instance can have its own breakpoints. Additionally, the breakpoints
  20877. * cannot be changed once an instance has been creased.
  20878. *
  20879. * @type {Array}
  20880. * @default Takes the value of `Responsive.breakpoints`
  20881. */
  20882. breakpoints: Responsive.breakpoints,
  20883. /**
  20884. * Enable / disable auto hiding calculations. It can help to increase
  20885. * performance slightly if you disable this option, but all columns would
  20886. * need to have breakpoint classes assigned to them
  20887. *
  20888. * @type {Boolean}
  20889. * @default `true`
  20890. */
  20891. auto: true,
  20892. /**
  20893. * Details control. If given as a string value, the `type` property of the
  20894. * default object is set to that value, and the defaults used for the rest
  20895. * of the object - this is for ease of implementation.
  20896. *
  20897. * The object consists of the following properties:
  20898. *
  20899. * * `display` - A function that is used to show and hide the hidden details
  20900. * * `renderer` - function that is called for display of the child row data.
  20901. * The default function will show the data from the hidden columns
  20902. * * `target` - Used as the selector for what objects to attach the child
  20903. * open / close to
  20904. * * `type` - `false` to disable the details display, `inline` or `column`
  20905. * for the two control types
  20906. *
  20907. * @type {Object|string}
  20908. */
  20909. details: {
  20910. display: Responsive.display.childRow,
  20911. renderer: Responsive.renderer.listHidden(),
  20912. target: 0,
  20913. type: 'inline'
  20914. },
  20915. /**
  20916. * Orthogonal data request option. This is used to define the data type
  20917. * requested when Responsive gets the data to show in the child row.
  20918. *
  20919. * @type {String}
  20920. */
  20921. orthogonal: 'display'
  20922. };
  20923. /*
  20924. * API
  20925. */
  20926. var Api = $.fn.dataTable.Api;
  20927. // Doesn't do anything - work around for a bug in DT... Not documented
  20928. Api.register( 'responsive()', function () {
  20929. return this;
  20930. } );
  20931. Api.register( 'responsive.index()', function ( li ) {
  20932. li = $(li);
  20933. return {
  20934. column: li.data('dtr-index'),
  20935. row: li.parent().data('dtr-index')
  20936. };
  20937. } );
  20938. Api.register( 'responsive.rebuild()', function () {
  20939. return this.iterator( 'table', function ( ctx ) {
  20940. if ( ctx._responsive ) {
  20941. ctx._responsive._classLogic();
  20942. }
  20943. } );
  20944. } );
  20945. Api.register( 'responsive.recalc()', function () {
  20946. return this.iterator( 'table', function ( ctx ) {
  20947. if ( ctx._responsive ) {
  20948. ctx._responsive._resizeAuto();
  20949. ctx._responsive._resize();
  20950. }
  20951. } );
  20952. } );
  20953. Api.register( 'responsive.hasHidden()', function () {
  20954. var ctx = this.context[0];
  20955. return ctx._responsive ?
  20956. $.inArray( false, ctx._responsive.s.current ) !== -1 :
  20957. false;
  20958. } );
  20959. Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {
  20960. return this.iterator( 'column', function ( settings, column ) {
  20961. return settings._responsive ?
  20962. settings._responsive.s.current[ column ] :
  20963. false;
  20964. }, 1 );
  20965. } );
  20966. /**
  20967. * Version information
  20968. *
  20969. * @name Responsive.version
  20970. * @static
  20971. */
  20972. Responsive.version = '2.2.1';
  20973. $.fn.dataTable.Responsive = Responsive;
  20974. $.fn.DataTable.Responsive = Responsive;
  20975. // Attach a listener to the document which listens for DataTables initialisation
  20976. // events so we can automatically initialise
  20977. $(document).on( 'preInit.dt.dtr', function (e, settings, json) {
  20978. if ( e.namespace !== 'dt' ) {
  20979. return;
  20980. }
  20981. if ( $(settings.nTable).hasClass( 'responsive' ) ||
  20982. $(settings.nTable).hasClass( 'dt-responsive' ) ||
  20983. settings.oInit.responsive ||
  20984. DataTable.defaults.responsive
  20985. ) {
  20986. var init = settings.oInit.responsive;
  20987. if ( init !== false ) {
  20988. new Responsive( settings, $.isPlainObject( init ) ? init : {} );
  20989. }
  20990. }
  20991. } );
  20992. return Responsive;
  20993. }));
  20994. /*! RowReorder 1.2.3
  20995. * 2015-2017 SpryMedia Ltd - datatables.net/license
  20996. */
  20997. /**
  20998. * @summary RowReorder
  20999. * @description Row reordering extension for DataTables
  21000. * @version 1.2.3
  21001. * @file dataTables.rowReorder.js
  21002. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  21003. * @contact www.sprymedia.co.uk/contact
  21004. * @copyright Copyright 2015-2017 SpryMedia Ltd.
  21005. *
  21006. * This source file is free software, available under the following license:
  21007. * MIT license - http://datatables.net/license/mit
  21008. *
  21009. * This source file is distributed in the hope that it will be useful, but
  21010. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  21011. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  21012. *
  21013. * For details please refer to: http://www.datatables.net
  21014. */
  21015. (function( factory ){
  21016. if ( typeof define === 'function' && define.amd ) {
  21017. // AMD
  21018. define( ['jquery', 'datatables.net'], function ( $ ) {
  21019. return factory( $, window, document );
  21020. } );
  21021. }
  21022. else if ( typeof exports === 'object' ) {
  21023. // CommonJS
  21024. module.exports = function (root, $) {
  21025. if ( ! root ) {
  21026. root = window;
  21027. }
  21028. if ( ! $ || ! $.fn.dataTable ) {
  21029. $ = require('datatables.net')(root, $).$;
  21030. }
  21031. return factory( $, root, root.document );
  21032. };
  21033. }
  21034. else {
  21035. // Browser
  21036. factory( jQuery, window, document );
  21037. }
  21038. }(function( $, window, document, undefined ) {
  21039. 'use strict';
  21040. var DataTable = $.fn.dataTable;
  21041. /**
  21042. * RowReorder provides the ability in DataTables to click and drag rows to
  21043. * reorder them. When a row is dropped the data for the rows effected will be
  21044. * updated to reflect the change. Normally this data point should also be the
  21045. * column being sorted upon in the DataTable but this does not need to be the
  21046. * case. RowReorder implements a "data swap" method - so the rows being
  21047. * reordered take the value of the data point from the row that used to occupy
  21048. * the row's new position.
  21049. *
  21050. * Initialisation is done by either:
  21051. *
  21052. * * `rowReorder` parameter in the DataTable initialisation object
  21053. * * `new $.fn.dataTable.RowReorder( table, opts )` after DataTables
  21054. * initialisation.
  21055. *
  21056. * @class
  21057. * @param {object} settings DataTables settings object for the host table
  21058. * @param {object} [opts] Configuration options
  21059. * @requires jQuery 1.7+
  21060. * @requires DataTables 1.10.7+
  21061. */
  21062. var RowReorder = function ( dt, opts ) {
  21063. // Sanity check that we are using DataTables 1.10 or newer
  21064. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
  21065. throw 'DataTables RowReorder requires DataTables 1.10.8 or newer';
  21066. }
  21067. // User and defaults configuration object
  21068. this.c = $.extend( true, {},
  21069. DataTable.defaults.rowReorder,
  21070. RowReorder.defaults,
  21071. opts
  21072. );
  21073. // Internal settings
  21074. this.s = {
  21075. /** @type {integer} Scroll body top cache */
  21076. bodyTop: null,
  21077. /** @type {DataTable.Api} DataTables' API instance */
  21078. dt: new DataTable.Api( dt ),
  21079. /** @type {function} Data fetch function */
  21080. getDataFn: DataTable.ext.oApi._fnGetObjectDataFn( this.c.dataSrc ),
  21081. /** @type {array} Pixel positions for row insertion calculation */
  21082. middles: null,
  21083. /** @type {Object} Cached dimension information for use in the mouse move event handler */
  21084. scroll: {},
  21085. /** @type {integer} Interval object used for smooth scrolling */
  21086. scrollInterval: null,
  21087. /** @type {function} Data set function */
  21088. setDataFn: DataTable.ext.oApi._fnSetObjectDataFn( this.c.dataSrc ),
  21089. /** @type {Object} Mouse down information */
  21090. start: {
  21091. top: 0,
  21092. left: 0,
  21093. offsetTop: 0,
  21094. offsetLeft: 0,
  21095. nodes: []
  21096. },
  21097. /** @type {integer} Window height cached value */
  21098. windowHeight: 0,
  21099. /** @type {integer} Document outer height cached value */
  21100. documentOuterHeight: 0,
  21101. /** @type {integer} DOM clone outer height cached value */
  21102. domCloneOuterHeight: 0
  21103. };
  21104. // DOM items
  21105. this.dom = {
  21106. /** @type {jQuery} Cloned row being moved around */
  21107. clone: null,
  21108. /** @type {jQuery} DataTables scrolling container */
  21109. dtScroll: $('div.dataTables_scrollBody', this.s.dt.table().container())
  21110. };
  21111. // Check if row reorder has already been initialised on this table
  21112. var settings = this.s.dt.settings()[0];
  21113. var exisiting = settings.rowreorder;
  21114. if ( exisiting ) {
  21115. return exisiting;
  21116. }
  21117. settings.rowreorder = this;
  21118. this._constructor();
  21119. };
  21120. $.extend( RowReorder.prototype, {
  21121. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21122. * Constructor
  21123. */
  21124. /**
  21125. * Initialise the RowReorder instance
  21126. *
  21127. * @private
  21128. */
  21129. _constructor: function ()
  21130. {
  21131. var that = this;
  21132. var dt = this.s.dt;
  21133. var table = $( dt.table().node() );
  21134. // Need to be able to calculate the row positions relative to the table
  21135. if ( table.css('position') === 'static' ) {
  21136. table.css( 'position', 'relative' );
  21137. }
  21138. // listen for mouse down on the target column - we have to implement
  21139. // this rather than using HTML5 drag and drop as drag and drop doesn't
  21140. // appear to work on table rows at this time. Also mobile browsers are
  21141. // not supported.
  21142. // Use `table().container()` rather than just the table node for IE8 -
  21143. // otherwise it only works once...
  21144. $(dt.table().container()).on( 'mousedown.rowReorder touchstart.rowReorder', this.c.selector, function (e) {
  21145. if ( ! that.c.enable ) {
  21146. return;
  21147. }
  21148. var tr = $(this).closest('tr');
  21149. var row = dt.row( tr );
  21150. // Double check that it is a DataTable row
  21151. if ( row.any() ) {
  21152. that._emitEvent( 'pre-row-reorder', {
  21153. node: row.node(),
  21154. index: row.index()
  21155. } );
  21156. that._mouseDown( e, tr );
  21157. return false;
  21158. }
  21159. } );
  21160. dt.on( 'destroy.rowReorder', function () {
  21161. $(dt.table().container()).off( '.rowReorder' );
  21162. dt.off( '.rowReorder' );
  21163. } );
  21164. },
  21165. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21166. * Private methods
  21167. */
  21168. /**
  21169. * Cache the measurements that RowReorder needs in the mouse move handler
  21170. * to attempt to speed things up, rather than reading from the DOM.
  21171. *
  21172. * @private
  21173. */
  21174. _cachePositions: function ()
  21175. {
  21176. var dt = this.s.dt;
  21177. // Frustratingly, if we add `position:relative` to the tbody, the
  21178. // position is still relatively to the parent. So we need to adjust
  21179. // for that
  21180. var headerHeight = $( dt.table().node() ).find('thead').outerHeight();
  21181. // Need to pass the nodes through jQuery to get them in document order,
  21182. // not what DataTables thinks it is, since we have been altering the
  21183. // order
  21184. var nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  21185. var tops = $.map( nodes, function ( node, i ) {
  21186. return $(node).position().top - headerHeight;
  21187. } );
  21188. var middles = $.map( tops, function ( top, i ) {
  21189. return tops.length < i-1 ?
  21190. (top + tops[i+1]) / 2 :
  21191. (top + top + $( dt.row( ':last-child' ).node() ).outerHeight() ) / 2;
  21192. } );
  21193. this.s.middles = middles;
  21194. this.s.bodyTop = $( dt.table().body() ).offset().top;
  21195. this.s.windowHeight = $(window).height();
  21196. this.s.documentOuterHeight = $(document).outerHeight();
  21197. },
  21198. /**
  21199. * Clone a row so it can be floated around the screen
  21200. *
  21201. * @param {jQuery} target Node to be cloned
  21202. * @private
  21203. */
  21204. _clone: function ( target )
  21205. {
  21206. var dt = this.s.dt;
  21207. var clone = $( dt.table().node().cloneNode(false) )
  21208. .addClass( 'dt-rowReorder-float' )
  21209. .append('<tbody/>')
  21210. .append( target.clone( false ) );
  21211. // Match the table and column widths - read all sizes before setting
  21212. // to reduce reflows
  21213. var tableWidth = target.outerWidth();
  21214. var tableHeight = target.outerHeight();
  21215. var sizes = target.children().map( function () {
  21216. return $(this).width();
  21217. } );
  21218. clone
  21219. .width( tableWidth )
  21220. .height( tableHeight )
  21221. .find('tr').children().each( function (i) {
  21222. this.style.width = sizes[i]+'px';
  21223. } );
  21224. // Insert into the document to have it floating around
  21225. clone.appendTo( 'body' );
  21226. this.dom.clone = clone;
  21227. this.s.domCloneOuterHeight = clone.outerHeight();
  21228. },
  21229. /**
  21230. * Update the cloned item's position in the document
  21231. *
  21232. * @param {object} e Event giving the mouse's position
  21233. * @private
  21234. */
  21235. _clonePosition: function ( e )
  21236. {
  21237. var start = this.s.start;
  21238. var topDiff = this._eventToPage( e, 'Y' ) - start.top;
  21239. var leftDiff = this._eventToPage( e, 'X' ) - start.left;
  21240. var snap = this.c.snapX;
  21241. var left;
  21242. var top = topDiff + start.offsetTop;
  21243. if ( snap === true ) {
  21244. left = start.offsetLeft;
  21245. }
  21246. else if ( typeof snap === 'number' ) {
  21247. left = start.offsetLeft + snap;
  21248. }
  21249. else {
  21250. left = leftDiff + start.offsetLeft;
  21251. }
  21252. if(top < 0) {
  21253. top = 0
  21254. }
  21255. else if(top + this.s.domCloneOuterHeight > this.s.documentOuterHeight) {
  21256. top = this.s.documentOuterHeight - this.s.domCloneOuterHeight;
  21257. }
  21258. this.dom.clone.css( {
  21259. top: top,
  21260. left: left
  21261. } );
  21262. },
  21263. /**
  21264. * Emit an event on the DataTable for listeners
  21265. *
  21266. * @param {string} name Event name
  21267. * @param {array} args Event arguments
  21268. * @private
  21269. */
  21270. _emitEvent: function ( name, args )
  21271. {
  21272. this.s.dt.iterator( 'table', function ( ctx, i ) {
  21273. $(ctx.nTable).triggerHandler( name+'.dt', args );
  21274. } );
  21275. },
  21276. /**
  21277. * Get pageX/Y position from an event, regardless of if it is a mouse or
  21278. * touch event.
  21279. *
  21280. * @param {object} e Event
  21281. * @param {string} pos X or Y (must be a capital)
  21282. * @private
  21283. */
  21284. _eventToPage: function ( e, pos )
  21285. {
  21286. if ( e.type.indexOf( 'touch' ) !== -1 ) {
  21287. return e.originalEvent.touches[0][ 'page'+pos ];
  21288. }
  21289. return e[ 'page'+pos ];
  21290. },
  21291. /**
  21292. * Mouse down event handler. Read initial positions and add event handlers
  21293. * for the move.
  21294. *
  21295. * @param {object} e Mouse event
  21296. * @param {jQuery} target TR element that is to be moved
  21297. * @private
  21298. */
  21299. _mouseDown: function ( e, target )
  21300. {
  21301. var that = this;
  21302. var dt = this.s.dt;
  21303. var start = this.s.start;
  21304. var offset = target.offset();
  21305. start.top = this._eventToPage( e, 'Y' );
  21306. start.left = this._eventToPage( e, 'X' );
  21307. start.offsetTop = offset.top;
  21308. start.offsetLeft = offset.left;
  21309. start.nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  21310. this._cachePositions();
  21311. this._clone( target );
  21312. this._clonePosition( e );
  21313. this.dom.target = target;
  21314. target.addClass( 'dt-rowReorder-moving' );
  21315. $( document )
  21316. .on( 'mouseup.rowReorder touchend.rowReorder', function (e) {
  21317. that._mouseUp(e);
  21318. } )
  21319. .on( 'mousemove.rowReorder touchmove.rowReorder', function (e) {
  21320. that._mouseMove(e);
  21321. } );
  21322. // Check if window is x-scrolling - if not, disable it for the duration
  21323. // of the drag
  21324. if ( $(window).width() === $(document).width() ) {
  21325. $(document.body).addClass( 'dt-rowReorder-noOverflow' );
  21326. }
  21327. // Cache scrolling information so mouse move doesn't need to read.
  21328. // This assumes that the window and DT scroller will not change size
  21329. // during an row drag, which I think is a fair assumption
  21330. var scrollWrapper = this.dom.dtScroll;
  21331. this.s.scroll = {
  21332. windowHeight: $(window).height(),
  21333. windowWidth: $(window).width(),
  21334. dtTop: scrollWrapper.length ? scrollWrapper.offset().top : null,
  21335. dtLeft: scrollWrapper.length ? scrollWrapper.offset().left : null,
  21336. dtHeight: scrollWrapper.length ? scrollWrapper.outerHeight() : null,
  21337. dtWidth: scrollWrapper.length ? scrollWrapper.outerWidth() : null
  21338. };
  21339. },
  21340. /**
  21341. * Mouse move event handler - move the cloned row and shuffle the table's
  21342. * rows if required.
  21343. *
  21344. * @param {object} e Mouse event
  21345. * @private
  21346. */
  21347. _mouseMove: function ( e )
  21348. {
  21349. this._clonePosition( e );
  21350. // Transform the mouse position into a position in the table's body
  21351. var bodyY = this._eventToPage( e, 'Y' ) - this.s.bodyTop;
  21352. var middles = this.s.middles;
  21353. var insertPoint = null;
  21354. var dt = this.s.dt;
  21355. var body = dt.table().body();
  21356. // Determine where the row should be inserted based on the mouse
  21357. // position
  21358. for ( var i=0, ien=middles.length ; i<ien ; i++ ) {
  21359. if ( bodyY < middles[i] ) {
  21360. insertPoint = i;
  21361. break;
  21362. }
  21363. }
  21364. if ( insertPoint === null ) {
  21365. insertPoint = middles.length;
  21366. }
  21367. // Perform the DOM shuffle if it has changed from last time
  21368. if ( this.s.lastInsert === null || this.s.lastInsert !== insertPoint ) {
  21369. if ( insertPoint === 0 ) {
  21370. this.dom.target.prependTo( body );
  21371. }
  21372. else {
  21373. var nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  21374. if ( insertPoint > this.s.lastInsert ) {
  21375. this.dom.target.insertAfter( nodes[ insertPoint-1 ] );
  21376. }
  21377. else {
  21378. this.dom.target.insertBefore( nodes[ insertPoint ] );
  21379. }
  21380. }
  21381. this._cachePositions();
  21382. this.s.lastInsert = insertPoint;
  21383. }
  21384. this._shiftScroll( e );
  21385. },
  21386. /**
  21387. * Mouse up event handler - release the event handlers and perform the
  21388. * table updates
  21389. *
  21390. * @param {object} e Mouse event
  21391. * @private
  21392. */
  21393. _mouseUp: function ( e )
  21394. {
  21395. var that = this;
  21396. var dt = this.s.dt;
  21397. var i, ien;
  21398. var dataSrc = this.c.dataSrc;
  21399. this.dom.clone.remove();
  21400. this.dom.clone = null;
  21401. this.dom.target.removeClass( 'dt-rowReorder-moving' );
  21402. //this.dom.target = null;
  21403. $(document).off( '.rowReorder' );
  21404. $(document.body).removeClass( 'dt-rowReorder-noOverflow' );
  21405. clearInterval( this.s.scrollInterval );
  21406. this.s.scrollInterval = null;
  21407. // Calculate the difference
  21408. var startNodes = this.s.start.nodes;
  21409. var endNodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
  21410. var idDiff = {};
  21411. var fullDiff = [];
  21412. var diffNodes = [];
  21413. var getDataFn = this.s.getDataFn;
  21414. var setDataFn = this.s.setDataFn;
  21415. for ( i=0, ien=startNodes.length ; i<ien ; i++ ) {
  21416. if ( startNodes[i] !== endNodes[i] ) {
  21417. var id = dt.row( endNodes[i] ).id();
  21418. var endRowData = dt.row( endNodes[i] ).data();
  21419. var startRowData = dt.row( startNodes[i] ).data();
  21420. if ( id ) {
  21421. idDiff[ id ] = getDataFn( startRowData );
  21422. }
  21423. fullDiff.push( {
  21424. node: endNodes[i],
  21425. oldData: getDataFn( endRowData ),
  21426. newData: getDataFn( startRowData ),
  21427. newPosition: i,
  21428. oldPosition: $.inArray( endNodes[i], startNodes )
  21429. } );
  21430. diffNodes.push( endNodes[i] );
  21431. }
  21432. }
  21433. // Create event args
  21434. var eventArgs = [ fullDiff, {
  21435. dataSrc: dataSrc,
  21436. nodes: diffNodes,
  21437. values: idDiff,
  21438. triggerRow: dt.row( this.dom.target )
  21439. } ];
  21440. // Emit event
  21441. this._emitEvent( 'row-reorder', eventArgs );
  21442. var update = function () {
  21443. if ( that.c.update ) {
  21444. for ( i=0, ien=fullDiff.length ; i<ien ; i++ ) {
  21445. var row = dt.row( fullDiff[i].node );
  21446. var rowData = row.data();
  21447. setDataFn( rowData, fullDiff[i].newData );
  21448. // Invalidate the cell that has the same data source as the dataSrc
  21449. dt.columns().every( function () {
  21450. if ( this.dataSrc() === dataSrc ) {
  21451. dt.cell( fullDiff[i].node, this.index() ).invalidate( 'data' );
  21452. }
  21453. } );
  21454. }
  21455. // Trigger row reordered event
  21456. that._emitEvent( 'row-reordered', eventArgs );
  21457. dt.draw( false );
  21458. }
  21459. };
  21460. // Editor interface
  21461. if ( this.c.editor ) {
  21462. // Disable user interaction while Editor is submitting
  21463. this.c.enable = false;
  21464. this.c.editor
  21465. .edit(
  21466. diffNodes,
  21467. false,
  21468. $.extend( {submit: 'changed'}, this.c.formOptions )
  21469. )
  21470. .multiSet( dataSrc, idDiff )
  21471. .one( 'submitUnsuccessful.rowReorder', function () {
  21472. dt.draw( false );
  21473. } )
  21474. .one( 'submitSuccess.rowReorder', function () {
  21475. update();
  21476. } )
  21477. .one( 'submitComplete', function () {
  21478. that.c.enable = true;
  21479. that.c.editor.off( '.rowReorder' );
  21480. } )
  21481. .submit();
  21482. }
  21483. else {
  21484. update();
  21485. }
  21486. },
  21487. /**
  21488. * Move the window and DataTables scrolling during a drag to scroll new
  21489. * content into view.
  21490. *
  21491. * This matches the `_shiftScroll` method used in AutoFill, but only
  21492. * horizontal scrolling is considered here.
  21493. *
  21494. * @param {object} e Mouse move event object
  21495. * @private
  21496. */
  21497. _shiftScroll: function ( e )
  21498. {
  21499. var that = this;
  21500. var dt = this.s.dt;
  21501. var scroll = this.s.scroll;
  21502. var runInterval = false;
  21503. var scrollSpeed = 5;
  21504. var buffer = 65;
  21505. var
  21506. windowY = e.pageY - document.body.scrollTop,
  21507. windowVert,
  21508. dtVert;
  21509. // Window calculations - based on the mouse position in the window,
  21510. // regardless of scrolling
  21511. if ( windowY < buffer ) {
  21512. windowVert = scrollSpeed * -1;
  21513. }
  21514. else if ( windowY > scroll.windowHeight - buffer ) {
  21515. windowVert = scrollSpeed;
  21516. }
  21517. // DataTables scrolling calculations - based on the table's position in
  21518. // the document and the mouse position on the page
  21519. if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {
  21520. dtVert = scrollSpeed * -1;
  21521. }
  21522. else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
  21523. dtVert = scrollSpeed;
  21524. }
  21525. // This is where it gets interesting. We want to continue scrolling
  21526. // without requiring a mouse move, so we need an interval to be
  21527. // triggered. The interval should continue until it is no longer needed,
  21528. // but it must also use the latest scroll commands (for example consider
  21529. // that the mouse might move from scrolling up to scrolling left, all
  21530. // with the same interval running. We use the `scroll` object to "pass"
  21531. // this information to the interval. Can't use local variables as they
  21532. // wouldn't be the ones that are used by an already existing interval!
  21533. if ( windowVert || dtVert ) {
  21534. scroll.windowVert = windowVert;
  21535. scroll.dtVert = dtVert;
  21536. runInterval = true;
  21537. }
  21538. else if ( this.s.scrollInterval ) {
  21539. // Don't need to scroll - remove any existing timer
  21540. clearInterval( this.s.scrollInterval );
  21541. this.s.scrollInterval = null;
  21542. }
  21543. // If we need to run the interval to scroll and there is no existing
  21544. // interval (if there is an existing one, it will continue to run)
  21545. if ( ! this.s.scrollInterval && runInterval ) {
  21546. this.s.scrollInterval = setInterval( function () {
  21547. // Don't need to worry about setting scroll <0 or beyond the
  21548. // scroll bound as the browser will just reject that.
  21549. if ( scroll.windowVert ) {
  21550. document.body.scrollTop += scroll.windowVert;
  21551. }
  21552. // DataTables scrolling
  21553. if ( scroll.dtVert ) {
  21554. var scroller = that.dom.dtScroll[0];
  21555. if ( scroll.dtVert ) {
  21556. scroller.scrollTop += scroll.dtVert;
  21557. }
  21558. }
  21559. }, 20 );
  21560. }
  21561. }
  21562. } );
  21563. /**
  21564. * RowReorder default settings for initialisation
  21565. *
  21566. * @namespace
  21567. * @name RowReorder.defaults
  21568. * @static
  21569. */
  21570. RowReorder.defaults = {
  21571. /**
  21572. * Data point in the host row's data source object for where to get and set
  21573. * the data to reorder. This will normally also be the sorting column.
  21574. *
  21575. * @type {Number}
  21576. */
  21577. dataSrc: 0,
  21578. /**
  21579. * Editor instance that will be used to perform the update
  21580. *
  21581. * @type {DataTable.Editor}
  21582. */
  21583. editor: null,
  21584. /**
  21585. * Enable / disable RowReorder's user interaction
  21586. * @type {Boolean}
  21587. */
  21588. enable: true,
  21589. /**
  21590. * Form options to pass to Editor when submitting a change in the row order.
  21591. * See the Editor `from-options` object for details of the options
  21592. * available.
  21593. * @type {Object}
  21594. */
  21595. formOptions: {},
  21596. /**
  21597. * Drag handle selector. This defines the element that when dragged will
  21598. * reorder a row.
  21599. *
  21600. * @type {String}
  21601. */
  21602. selector: 'td:first-child',
  21603. /**
  21604. * Optionally lock the dragged row's x-position. This can be `true` to
  21605. * fix the position match the host table's, `false` to allow free movement
  21606. * of the row, or a number to define an offset from the host table.
  21607. *
  21608. * @type {Boolean|number}
  21609. */
  21610. snapX: false,
  21611. /**
  21612. * Update the table's data on drop
  21613. *
  21614. * @type {Boolean}
  21615. */
  21616. update: true
  21617. };
  21618. /*
  21619. * API
  21620. */
  21621. var Api = $.fn.dataTable.Api;
  21622. // Doesn't do anything - work around for a bug in DT... Not documented
  21623. Api.register( 'rowReorder()', function () {
  21624. return this;
  21625. } );
  21626. Api.register( 'rowReorder.enable()', function ( toggle ) {
  21627. if ( toggle === undefined ) {
  21628. toggle = true;
  21629. }
  21630. return this.iterator( 'table', function ( ctx ) {
  21631. if ( ctx.rowreorder ) {
  21632. ctx.rowreorder.c.enable = toggle;
  21633. }
  21634. } );
  21635. } );
  21636. Api.register( 'rowReorder.disable()', function () {
  21637. return this.iterator( 'table', function ( ctx ) {
  21638. if ( ctx.rowreorder ) {
  21639. ctx.rowreorder.c.enable = false;
  21640. }
  21641. } );
  21642. } );
  21643. /**
  21644. * Version information
  21645. *
  21646. * @name RowReorder.version
  21647. * @static
  21648. */
  21649. RowReorder.version = '1.2.3';
  21650. $.fn.dataTable.RowReorder = RowReorder;
  21651. $.fn.DataTable.RowReorder = RowReorder;
  21652. // Attach a listener to the document which listens for DataTables initialisation
  21653. // events so we can automatically initialise
  21654. $(document).on( 'init.dt.dtr', function (e, settings, json) {
  21655. if ( e.namespace !== 'dt' ) {
  21656. return;
  21657. }
  21658. var init = settings.oInit.rowReorder;
  21659. var defaults = DataTable.defaults.rowReorder;
  21660. if ( init || defaults ) {
  21661. var opts = $.extend( {}, init, defaults );
  21662. if ( init !== false ) {
  21663. new RowReorder( settings, opts );
  21664. }
  21665. }
  21666. } );
  21667. return RowReorder;
  21668. }));
  21669. /*! Scroller 1.4.4
  21670. * ©2011-2018 SpryMedia Ltd - datatables.net/license
  21671. */
  21672. /**
  21673. * @summary Scroller
  21674. * @description Virtual rendering for DataTables
  21675. * @version 1.4.4
  21676. * @file dataTables.scroller.js
  21677. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  21678. * @contact www.sprymedia.co.uk/contact
  21679. * @copyright Copyright 2011-2018 SpryMedia Ltd.
  21680. *
  21681. * This source file is free software, available under the following license:
  21682. * MIT license - http://datatables.net/license/mit
  21683. *
  21684. * This source file is distributed in the hope that it will be useful, but
  21685. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  21686. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  21687. *
  21688. * For details please refer to: http://www.datatables.net
  21689. */
  21690. (function( factory ){
  21691. if ( typeof define === 'function' && define.amd ) {
  21692. // AMD
  21693. define( ['jquery', 'datatables.net'], function ( $ ) {
  21694. return factory( $, window, document );
  21695. } );
  21696. }
  21697. else if ( typeof exports === 'object' ) {
  21698. // CommonJS
  21699. module.exports = function (root, $) {
  21700. if ( ! root ) {
  21701. root = window;
  21702. }
  21703. if ( ! $ || ! $.fn.dataTable ) {
  21704. $ = require('datatables.net')(root, $).$;
  21705. }
  21706. return factory( $, root, root.document );
  21707. };
  21708. }
  21709. else {
  21710. // Browser
  21711. factory( jQuery, window, document );
  21712. }
  21713. }(function( $, window, document, undefined ) {
  21714. 'use strict';
  21715. var DataTable = $.fn.dataTable;
  21716. /**
  21717. * Scroller is a virtual rendering plug-in for DataTables which allows large
  21718. * datasets to be drawn on screen every quickly. What the virtual rendering means
  21719. * is that only the visible portion of the table (and a bit to either side to make
  21720. * the scrolling smooth) is drawn, while the scrolling container gives the
  21721. * visual impression that the whole table is visible. This is done by making use
  21722. * of the pagination abilities of DataTables and moving the table around in the
  21723. * scrolling container DataTables adds to the page. The scrolling container is
  21724. * forced to the height it would be for the full table display using an extra
  21725. * element.
  21726. *
  21727. * Note that rows in the table MUST all be the same height. Information in a cell
  21728. * which expands on to multiple lines will cause some odd behaviour in the scrolling.
  21729. *
  21730. * Scroller is initialised by simply including the letter 'S' in the sDom for the
  21731. * table you want to have this feature enabled on. Note that the 'S' must come
  21732. * AFTER the 't' parameter in `dom`.
  21733. *
  21734. * Key features include:
  21735. * <ul class="limit_length">
  21736. * <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>
  21737. * <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>
  21738. * <li>Display millions of rows</li>
  21739. * <li>Integration with state saving in DataTables (scrolling position is saved)</li>
  21740. * <li>Easy to use</li>
  21741. * </ul>
  21742. *
  21743. * @class
  21744. * @constructor
  21745. * @global
  21746. * @param {object} dt DataTables settings object or API instance
  21747. * @param {object} [opts={}] Configuration object for FixedColumns. Options
  21748. * are defined by {@link Scroller.defaults}
  21749. *
  21750. * @requires jQuery 1.7+
  21751. * @requires DataTables 1.10.0+
  21752. *
  21753. * @example
  21754. * $(document).ready(function() {
  21755. * $('#example').DataTable( {
  21756. * "scrollY": "200px",
  21757. * "ajax": "media/dataset/large.txt",
  21758. * "dom": "frtiS",
  21759. * "deferRender": true
  21760. * } );
  21761. * } );
  21762. */
  21763. var Scroller = function ( dt, opts ) {
  21764. /* Sanity check - you just know it will happen */
  21765. if ( ! (this instanceof Scroller) ) {
  21766. alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." );
  21767. return;
  21768. }
  21769. if ( opts === undefined ) {
  21770. opts = {};
  21771. }
  21772. /**
  21773. * Settings object which contains customisable information for the Scroller instance
  21774. * @namespace
  21775. * @private
  21776. * @extends Scroller.defaults
  21777. */
  21778. this.s = {
  21779. /**
  21780. * DataTables settings object
  21781. * @type object
  21782. * @default Passed in as first parameter to constructor
  21783. */
  21784. "dt": $.fn.dataTable.Api( dt ).settings()[0],
  21785. /**
  21786. * Pixel location of the top of the drawn table in the viewport
  21787. * @type int
  21788. * @default 0
  21789. */
  21790. "tableTop": 0,
  21791. /**
  21792. * Pixel location of the bottom of the drawn table in the viewport
  21793. * @type int
  21794. * @default 0
  21795. */
  21796. "tableBottom": 0,
  21797. /**
  21798. * Pixel location of the boundary for when the next data set should be loaded and drawn
  21799. * when scrolling up the way.
  21800. * @type int
  21801. * @default 0
  21802. * @private
  21803. */
  21804. "redrawTop": 0,
  21805. /**
  21806. * Pixel location of the boundary for when the next data set should be loaded and drawn
  21807. * when scrolling down the way. Note that this is actually calculated as the offset from
  21808. * the top.
  21809. * @type int
  21810. * @default 0
  21811. * @private
  21812. */
  21813. "redrawBottom": 0,
  21814. /**
  21815. * Auto row height or not indicator
  21816. * @type bool
  21817. * @default 0
  21818. */
  21819. "autoHeight": true,
  21820. /**
  21821. * Number of rows calculated as visible in the visible viewport
  21822. * @type int
  21823. * @default 0
  21824. */
  21825. "viewportRows": 0,
  21826. /**
  21827. * setTimeout reference for state saving, used when state saving is enabled in the DataTable
  21828. * and when the user scrolls the viewport in order to stop the cookie set taking too much
  21829. * CPU!
  21830. * @type int
  21831. * @default 0
  21832. */
  21833. "stateTO": null,
  21834. /**
  21835. * setTimeout reference for the redraw, used when server-side processing is enabled in the
  21836. * DataTables in order to prevent DoSing the server
  21837. * @type int
  21838. * @default null
  21839. */
  21840. "drawTO": null,
  21841. heights: {
  21842. jump: null,
  21843. page: null,
  21844. virtual: null,
  21845. scroll: null,
  21846. /**
  21847. * Height of rows in the table
  21848. * @type int
  21849. * @default 0
  21850. */
  21851. row: null,
  21852. /**
  21853. * Pixel height of the viewport
  21854. * @type int
  21855. * @default 0
  21856. */
  21857. viewport: null
  21858. },
  21859. topRowFloat: 0,
  21860. scrollDrawDiff: null,
  21861. loaderVisible: false,
  21862. forceReposition: false
  21863. };
  21864. // @todo The defaults should extend a `c` property and the internal settings
  21865. // only held in the `s` property. At the moment they are mixed
  21866. this.s = $.extend( this.s, Scroller.oDefaults, opts );
  21867. // Workaround for row height being read from height object (see above comment)
  21868. this.s.heights.row = this.s.rowHeight;
  21869. /**
  21870. * DOM elements used by the class instance
  21871. * @private
  21872. * @namespace
  21873. *
  21874. */
  21875. this.dom = {
  21876. "force": document.createElement('div'),
  21877. "scroller": null,
  21878. "table": null,
  21879. "loader": null
  21880. };
  21881. // Attach the instance to the DataTables instance so it can be accessed in
  21882. // future. Don't initialise Scroller twice on the same table
  21883. if ( this.s.dt.oScroller ) {
  21884. return;
  21885. }
  21886. this.s.dt.oScroller = this;
  21887. /* Let's do it */
  21888. this._fnConstruct();
  21889. };
  21890. $.extend( Scroller.prototype, {
  21891. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21892. * Public methods
  21893. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  21894. /**
  21895. * Calculate the pixel position from the top of the scrolling container for
  21896. * a given row
  21897. * @param {int} iRow Row number to calculate the position of
  21898. * @returns {int} Pixels
  21899. * @example
  21900. * $(document).ready(function() {
  21901. * $('#example').dataTable( {
  21902. * "sScrollY": "200px",
  21903. * "sAjaxSource": "media/dataset/large.txt",
  21904. * "sDom": "frtiS",
  21905. * "bDeferRender": true,
  21906. * "fnInitComplete": function (o) {
  21907. * // Find where row 25 is
  21908. * alert( o.oScroller.fnRowToPixels( 25 ) );
  21909. * }
  21910. * } );
  21911. * } );
  21912. */
  21913. "fnRowToPixels": function ( rowIdx, intParse, virtual )
  21914. {
  21915. var pixels;
  21916. if ( virtual ) {
  21917. pixels = this._domain( 'virtualToPhysical', rowIdx * this.s.heights.row );
  21918. }
  21919. else {
  21920. var diff = rowIdx - this.s.baseRowTop;
  21921. pixels = this.s.baseScrollTop + (diff * this.s.heights.row);
  21922. }
  21923. return intParse || intParse === undefined ?
  21924. parseInt( pixels, 10 ) :
  21925. pixels;
  21926. },
  21927. /**
  21928. * Calculate the row number that will be found at the given pixel position
  21929. * (y-scroll).
  21930. *
  21931. * Please note that when the height of the full table exceeds 1 million
  21932. * pixels, Scroller switches into a non-linear mode for the scrollbar to fit
  21933. * all of the records into a finite area, but this function returns a linear
  21934. * value (relative to the last non-linear positioning).
  21935. * @param {int} iPixels Offset from top to calculate the row number of
  21936. * @param {int} [intParse=true] If an integer value should be returned
  21937. * @param {int} [virtual=false] Perform the calculations in the virtual domain
  21938. * @returns {int} Row index
  21939. * @example
  21940. * $(document).ready(function() {
  21941. * $('#example').dataTable( {
  21942. * "sScrollY": "200px",
  21943. * "sAjaxSource": "media/dataset/large.txt",
  21944. * "sDom": "frtiS",
  21945. * "bDeferRender": true,
  21946. * "fnInitComplete": function (o) {
  21947. * // Find what row number is at 500px
  21948. * alert( o.oScroller.fnPixelsToRow( 500 ) );
  21949. * }
  21950. * } );
  21951. * } );
  21952. */
  21953. "fnPixelsToRow": function ( pixels, intParse, virtual )
  21954. {
  21955. var diff = pixels - this.s.baseScrollTop;
  21956. var row = virtual ?
  21957. this._domain( 'physicalToVirtual', pixels ) / this.s.heights.row :
  21958. ( diff / this.s.heights.row ) + this.s.baseRowTop;
  21959. return intParse || intParse === undefined ?
  21960. parseInt( row, 10 ) :
  21961. row;
  21962. },
  21963. /**
  21964. * Calculate the row number that will be found at the given pixel position (y-scroll)
  21965. * @param {int} iRow Row index to scroll to
  21966. * @param {bool} [bAnimate=true] Animate the transition or not
  21967. * @returns {void}
  21968. * @example
  21969. * $(document).ready(function() {
  21970. * $('#example').dataTable( {
  21971. * "sScrollY": "200px",
  21972. * "sAjaxSource": "media/dataset/large.txt",
  21973. * "sDom": "frtiS",
  21974. * "bDeferRender": true,
  21975. * "fnInitComplete": function (o) {
  21976. * // Immediately scroll to row 1000
  21977. * o.oScroller.fnScrollToRow( 1000 );
  21978. * }
  21979. * } );
  21980. *
  21981. * // Sometime later on use the following to scroll to row 500...
  21982. * var oSettings = $('#example').dataTable().fnSettings();
  21983. * oSettings.oScroller.fnScrollToRow( 500 );
  21984. * } );
  21985. */
  21986. "fnScrollToRow": function ( iRow, bAnimate )
  21987. {
  21988. var that = this;
  21989. var ani = false;
  21990. var px = this.fnRowToPixels( iRow );
  21991. // We need to know if the table will redraw or not before doing the
  21992. // scroll. If it will not redraw, then we need to use the currently
  21993. // displayed table, and scroll with the physical pixels. Otherwise, we
  21994. // need to calculate the table's new position from the virtual
  21995. // transform.
  21996. var preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;
  21997. var drawRow = iRow - preRows;
  21998. if ( drawRow < 0 ) {
  21999. drawRow = 0;
  22000. }
  22001. if ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {
  22002. ani = true;
  22003. px = this.fnRowToPixels( iRow, false, true );
  22004. // If we need records outside the current draw region, but the new
  22005. // scrolling position is inside that (due to the non-linear nature
  22006. // for larger numbers of records), we need to force position update.
  22007. if ( this.s.redrawTop < px && px < this.s.redrawBottom ) {
  22008. this.s.forceReposition = true;
  22009. bAnimate = false;
  22010. }
  22011. }
  22012. if ( typeof bAnimate == 'undefined' || bAnimate )
  22013. {
  22014. this.s.ani = ani;
  22015. $(this.dom.scroller).animate( {
  22016. "scrollTop": px
  22017. }, function () {
  22018. // This needs to happen after the animation has completed and
  22019. // the final scroll event fired
  22020. setTimeout( function () {
  22021. that.s.ani = false;
  22022. }, 25 );
  22023. } );
  22024. }
  22025. else
  22026. {
  22027. $(this.dom.scroller).scrollTop( px );
  22028. }
  22029. },
  22030. /**
  22031. * Calculate and store information about how many rows are to be displayed
  22032. * in the scrolling viewport, based on current dimensions in the browser's
  22033. * rendering. This can be particularly useful if the table is initially
  22034. * drawn in a hidden element - for example in a tab.
  22035. * @param {bool} [bRedraw=true] Redraw the table automatically after the recalculation, with
  22036. * the new dimensions forming the basis for the draw.
  22037. * @returns {void}
  22038. * @example
  22039. * $(document).ready(function() {
  22040. * // Make the example container hidden to throw off the browser's sizing
  22041. * document.getElementById('container').style.display = "none";
  22042. * var oTable = $('#example').dataTable( {
  22043. * "sScrollY": "200px",
  22044. * "sAjaxSource": "media/dataset/large.txt",
  22045. * "sDom": "frtiS",
  22046. * "bDeferRender": true,
  22047. * "fnInitComplete": function (o) {
  22048. * // Immediately scroll to row 1000
  22049. * o.oScroller.fnScrollToRow( 1000 );
  22050. * }
  22051. * } );
  22052. *
  22053. * setTimeout( function () {
  22054. * // Make the example container visible and recalculate the scroller sizes
  22055. * document.getElementById('container').style.display = "block";
  22056. * oTable.fnSettings().oScroller.fnMeasure();
  22057. * }, 3000 );
  22058. */
  22059. "fnMeasure": function ( bRedraw )
  22060. {
  22061. if ( this.s.autoHeight )
  22062. {
  22063. this._fnCalcRowHeight();
  22064. }
  22065. var heights = this.s.heights;
  22066. if ( heights.row ) {
  22067. heights.viewport = $.contains(document, this.dom.scroller) ?
  22068. $(this.dom.scroller).height() :
  22069. this._parseHeight($(this.dom.scroller).css('height'));
  22070. // If collapsed (no height) use the max-height parameter
  22071. if ( ! heights.viewport ) {
  22072. heights.viewport = this._parseHeight($(this.dom.scroller).css('max-height'));
  22073. }
  22074. this.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;
  22075. this.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;
  22076. }
  22077. if ( bRedraw === undefined || bRedraw )
  22078. {
  22079. this.s.dt.oInstance.fnDraw( false );
  22080. }
  22081. },
  22082. /**
  22083. * Get information about current displayed record range. This corresponds to
  22084. * the information usually displayed in the "Info" block of the table.
  22085. *
  22086. * @returns {object} info as an object:
  22087. * {
  22088. * start: {int}, // the 0-indexed record at the top of the viewport
  22089. * end: {int}, // the 0-indexed record at the bottom of the viewport
  22090. * }
  22091. */
  22092. "fnPageInfo": function()
  22093. {
  22094. var
  22095. dt = this.s.dt,
  22096. iScrollTop = this.dom.scroller.scrollTop,
  22097. iTotal = dt.fnRecordsDisplay(),
  22098. iPossibleEnd = Math.ceil(this.fnPixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani));
  22099. return {
  22100. start: Math.floor(this.fnPixelsToRow(iScrollTop, false, this.s.ani)),
  22101. end: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1
  22102. };
  22103. },
  22104. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22105. * Private methods (they are of course public in JS, but recommended as private)
  22106. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  22107. /**
  22108. * Initialisation for Scroller
  22109. * @returns {void}
  22110. * @private
  22111. */
  22112. "_fnConstruct": function ()
  22113. {
  22114. var that = this;
  22115. /* Sanity check */
  22116. if ( !this.s.dt.oFeatures.bPaginate ) {
  22117. this.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );
  22118. return;
  22119. }
  22120. /* Insert a div element that we can use to force the DT scrolling container to
  22121. * the height that would be required if the whole table was being displayed
  22122. */
  22123. this.dom.force.style.position = "relative";
  22124. this.dom.force.style.top = "0px";
  22125. this.dom.force.style.left = "0px";
  22126. this.dom.force.style.width = "1px";
  22127. this.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];
  22128. this.dom.scroller.appendChild( this.dom.force );
  22129. this.dom.scroller.style.position = "relative";
  22130. this.dom.table = $('>table', this.dom.scroller)[0];
  22131. this.dom.table.style.position = "absolute";
  22132. this.dom.table.style.top = "0px";
  22133. this.dom.table.style.left = "0px";
  22134. // Add class to 'announce' that we are a Scroller table
  22135. $(this.s.dt.nTableWrapper).addClass('DTS');
  22136. // Add a 'loading' indicator
  22137. if ( this.s.loadingIndicator )
  22138. {
  22139. this.dom.loader = $('<div class="dataTables_processing DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')
  22140. .css('display', 'none');
  22141. $(this.dom.scroller.parentNode)
  22142. .css('position', 'relative')
  22143. .append( this.dom.loader );
  22144. }
  22145. /* Initial size calculations */
  22146. if ( this.s.heights.row && this.s.heights.row != 'auto' )
  22147. {
  22148. this.s.autoHeight = false;
  22149. }
  22150. this.fnMeasure( false );
  22151. /* Scrolling callback to see if a page change is needed - use a throttled
  22152. * function for the save save callback so we aren't hitting it on every
  22153. * scroll
  22154. */
  22155. this.s.ingnoreScroll = true;
  22156. this.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () {
  22157. that.s.dt.oApi._fnSaveState( that.s.dt );
  22158. }, 500 );
  22159. $(this.dom.scroller).on( 'scroll.DTS', function (e) {
  22160. that._fnScroll.call( that );
  22161. } );
  22162. /* In iOS we catch the touchstart event in case the user tries to scroll
  22163. * while the display is already scrolling
  22164. */
  22165. $(this.dom.scroller).on('touchstart.DTS', function () {
  22166. that._fnScroll.call( that );
  22167. } );
  22168. /* Update the scroller when the DataTable is redrawn */
  22169. this.s.dt.aoDrawCallback.push( {
  22170. "fn": function () {
  22171. if ( that.s.dt.bInitialised ) {
  22172. that._fnDrawCallback.call( that );
  22173. }
  22174. },
  22175. "sName": "Scroller"
  22176. } );
  22177. /* On resize, update the information element, since the number of rows shown might change */
  22178. $(window).on( 'resize.DTS', function () {
  22179. that.fnMeasure( false );
  22180. that._fnInfo();
  22181. } );
  22182. /* Add a state saving parameter to the DT state saving so we can restore the exact
  22183. * position of the scrolling
  22184. */
  22185. var initialStateSave = true;
  22186. this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
  22187. /* Set iScroller to saved scroll position on initialization.
  22188. */
  22189. if(initialStateSave && that.s.dt.oLoadedState){
  22190. oData.iScroller = that.s.dt.oLoadedState.iScroller;
  22191. oData.iScrollerTopRow = that.s.dt.oLoadedState.iScrollerTopRow;
  22192. initialStateSave = false;
  22193. } else {
  22194. oData.iScroller = that.dom.scroller.scrollTop;
  22195. oData.iScrollerTopRow = that.s.topRowFloat;
  22196. }
  22197. }, "Scroller_State" );
  22198. if ( this.s.dt.oLoadedState ) {
  22199. this.s.topRowFloat = this.s.dt.oLoadedState.iScrollerTopRow || 0;
  22200. }
  22201. // Measure immediately. Scroller will have been added using preInit, so
  22202. // we can reliably do this here. We could potentially also measure on
  22203. // init complete, which would be useful for cases where the data is Ajax
  22204. // loaded and longer than a single line.
  22205. $(this.s.dt.nTable).one( 'init.dt', function () {
  22206. that.fnMeasure();
  22207. } );
  22208. /* Destructor */
  22209. this.s.dt.aoDestroyCallback.push( {
  22210. "sName": "Scroller",
  22211. "fn": function () {
  22212. $(window).off( 'resize.DTS' );
  22213. $(that.dom.scroller).off('touchstart.DTS scroll.DTS');
  22214. $(that.s.dt.nTableWrapper).removeClass('DTS');
  22215. $('div.DTS_Loading', that.dom.scroller.parentNode).remove();
  22216. $(that.s.dt.nTable).off( 'init.dt' );
  22217. that.dom.table.style.position = "";
  22218. that.dom.table.style.top = "";
  22219. that.dom.table.style.left = "";
  22220. }
  22221. } );
  22222. },
  22223. /**
  22224. * Scrolling function - fired whenever the scrolling position is changed.
  22225. * This method needs to use the stored values to see if the table should be
  22226. * redrawn as we are moving towards the end of the information that is
  22227. * currently drawn or not. If needed, then it will redraw the table based on
  22228. * the new position.
  22229. * @returns {void}
  22230. * @private
  22231. */
  22232. "_fnScroll": function ()
  22233. {
  22234. var
  22235. that = this,
  22236. heights = this.s.heights,
  22237. iScrollTop = this.dom.scroller.scrollTop,
  22238. iTopRow;
  22239. if ( this.s.skip ) {
  22240. return;
  22241. }
  22242. if ( this.s.ingnoreScroll ) {
  22243. return;
  22244. }
  22245. /* If the table has been sorted or filtered, then we use the redraw that
  22246. * DataTables as done, rather than performing our own
  22247. */
  22248. if ( this.s.dt.bFiltered || this.s.dt.bSorted ) {
  22249. this.s.lastScrollTop = 0;
  22250. return;
  22251. }
  22252. /* Update the table's information display for what is now in the viewport */
  22253. this._fnInfo();
  22254. /* We don't want to state save on every scroll event - that's heavy
  22255. * handed, so use a timeout to update the state saving only when the
  22256. * scrolling has finished
  22257. */
  22258. clearTimeout( this.s.stateTO );
  22259. this.s.stateTO = setTimeout( function () {
  22260. that.s.dt.oApi._fnSaveState( that.s.dt );
  22261. }, 250 );
  22262. /* Check if the scroll point is outside the trigger boundary which would required
  22263. * a DataTables redraw
  22264. */
  22265. if ( this.s.forceReposition || iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {
  22266. var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );
  22267. if ( Math.abs( iScrollTop - this.s.lastScrollTop ) > heights.viewport || this.s.ani || this.s.forceReposition ) {
  22268. iTopRow = parseInt(this._domain( 'physicalToVirtual', iScrollTop ) / heights.row, 10) - preRows;
  22269. this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
  22270. }
  22271. else {
  22272. iTopRow = this.fnPixelsToRow( iScrollTop ) - preRows;
  22273. this.s.topRowFloat = this.fnPixelsToRow( iScrollTop, false );
  22274. }
  22275. this.s.forceReposition = false;
  22276. if ( iTopRow <= 0 ) {
  22277. /* At the start of the table */
  22278. iTopRow = 0;
  22279. }
  22280. else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {
  22281. /* At the end of the table */
  22282. iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;
  22283. if ( iTopRow < 0 ) {
  22284. iTopRow = 0;
  22285. }
  22286. }
  22287. else if ( iTopRow % 2 !== 0 ) {
  22288. // For the row-striping classes (odd/even) we want only to start
  22289. // on evens otherwise the stripes will change between draws and
  22290. // look rubbish
  22291. iTopRow++;
  22292. }
  22293. if ( iTopRow != this.s.dt._iDisplayStart ) {
  22294. /* Cache the new table position for quick lookups */
  22295. this.s.tableTop = $(this.s.dt.nTable).offset().top;
  22296. this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;
  22297. var draw = function () {
  22298. if ( that.s.scrollDrawReq === null ) {
  22299. that.s.scrollDrawReq = iScrollTop;
  22300. }
  22301. that.s.dt._iDisplayStart = iTopRow;
  22302. that.s.dt.oApi._fnDraw( that.s.dt );
  22303. };
  22304. /* Do the DataTables redraw based on the calculated start point - note that when
  22305. * using server-side processing we introduce a small delay to not DoS the server...
  22306. */
  22307. if ( this.s.dt.oFeatures.bServerSide ) {
  22308. clearTimeout( this.s.drawTO );
  22309. this.s.drawTO = setTimeout( draw, this.s.serverWait );
  22310. }
  22311. else {
  22312. draw();
  22313. }
  22314. if ( this.dom.loader && ! this.s.loaderVisible ) {
  22315. this.dom.loader.css( 'display', 'block' );
  22316. this.s.loaderVisible = true;
  22317. }
  22318. }
  22319. }
  22320. else {
  22321. this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
  22322. }
  22323. this.s.lastScrollTop = iScrollTop;
  22324. this.s.stateSaveThrottle();
  22325. },
  22326. /**
  22327. * Convert from one domain to another. The physical domain is the actual
  22328. * pixel count on the screen, while the virtual is if we had browsers which
  22329. * had scrolling containers of infinite height (i.e. the absolute value)
  22330. *
  22331. * @param {string} dir Domain transform direction, `virtualToPhysical` or
  22332. * `physicalToVirtual`
  22333. * @returns {number} Calculated transform
  22334. * @private
  22335. */
  22336. _domain: function ( dir, val )
  22337. {
  22338. var heights = this.s.heights;
  22339. var coeff;
  22340. // If the virtual and physical height match, then we use a linear
  22341. // transform between the two, allowing the scrollbar to be linear
  22342. if ( heights.virtual === heights.scroll ) {
  22343. return val;
  22344. }
  22345. // Otherwise, we want a non-linear scrollbar to take account of the
  22346. // redrawing regions at the start and end of the table, otherwise these
  22347. // can stutter badly - on large tables 30px (for example) scroll might
  22348. // be hundreds of rows, so the table would be redrawing every few px at
  22349. // the start and end. Use a simple quadratic to stop this. It does mean
  22350. // the scrollbar is non-linear, but with such massive data sets, the
  22351. // scrollbar is going to be a best guess anyway
  22352. var xMax = (heights.scroll - heights.viewport) / 2;
  22353. var yMax = (heights.virtual - heights.viewport) / 2;
  22354. coeff = yMax / ( xMax * xMax );
  22355. if ( dir === 'virtualToPhysical' ) {
  22356. if ( val < yMax ) {
  22357. return Math.pow(val / coeff, 0.5);
  22358. }
  22359. else {
  22360. val = (yMax*2) - val;
  22361. return val < 0 ?
  22362. heights.scroll :
  22363. (xMax*2) - Math.pow(val / coeff, 0.5);
  22364. }
  22365. }
  22366. else if ( dir === 'physicalToVirtual' ) {
  22367. if ( val < xMax ) {
  22368. return val * val * coeff;
  22369. }
  22370. else {
  22371. val = (xMax*2) - val;
  22372. return val < 0 ?
  22373. heights.virtual :
  22374. (yMax*2) - (val * val * coeff);
  22375. }
  22376. }
  22377. },
  22378. /**
  22379. * Parse CSS height property string as number
  22380. *
  22381. * An attempt is made to parse the string as a number. Currently supported units are 'px',
  22382. * 'vh', and 'rem'. 'em' is partially supported; it works as long as the parent element's
  22383. * font size matches the body element. Zero is returned for unrecognized strings.
  22384. * @param {string} cssHeight CSS height property string
  22385. * @returns {number} height
  22386. * @private
  22387. */
  22388. _parseHeight: function(cssHeight) {
  22389. var height;
  22390. var matches = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(px|em|rem|vh)$/.exec(cssHeight);
  22391. if (matches === null) {
  22392. return 0;
  22393. }
  22394. var value = parseFloat(matches[1]);
  22395. var unit = matches[2];
  22396. if ( unit === 'px' ) {
  22397. height = value;
  22398. }
  22399. else if ( unit === 'vh' ) {
  22400. height = ( value / 100 ) * $(window).height();
  22401. }
  22402. else if ( unit === 'rem' ) {
  22403. height = value * parseFloat($(':root').css('font-size'));
  22404. }
  22405. else if ( unit === 'em' ) {
  22406. height = value * parseFloat($('body').css('font-size'));
  22407. }
  22408. return height ?
  22409. height :
  22410. 0;
  22411. },
  22412. /**
  22413. * Draw callback function which is fired when the DataTable is redrawn. The main function of
  22414. * this method is to position the drawn table correctly the scrolling container for the rows
  22415. * that is displays as a result of the scrolling position.
  22416. * @returns {void}
  22417. * @private
  22418. */
  22419. "_fnDrawCallback": function ()
  22420. {
  22421. var
  22422. that = this,
  22423. heights = this.s.heights,
  22424. iScrollTop = this.dom.scroller.scrollTop,
  22425. iActualScrollTop = iScrollTop,
  22426. iScrollBottom = iScrollTop + heights.viewport,
  22427. iTableHeight = $(this.s.dt.nTable).height(),
  22428. displayStart = this.s.dt._iDisplayStart,
  22429. displayLen = this.s.dt._iDisplayLength,
  22430. displayEnd = this.s.dt.fnRecordsDisplay();
  22431. // Disable the scroll event listener while we are updating the DOM
  22432. this.s.skip = true;
  22433. // Resize the scroll forcing element
  22434. this._fnScrollForce();
  22435. // Reposition the scrolling for the updated virtual position if needed
  22436. if ( displayStart === 0 ) {
  22437. // Linear calculation at the top of the table
  22438. iScrollTop = this.s.topRowFloat * heights.row;
  22439. }
  22440. else if ( displayStart + displayLen >= displayEnd ) {
  22441. // Linear calculation that the bottom as well
  22442. iScrollTop = heights.scroll - ((displayEnd - this.s.topRowFloat) * heights.row);
  22443. }
  22444. else {
  22445. // Domain scaled in the middle
  22446. iScrollTop = this._domain( 'virtualToPhysical', this.s.topRowFloat * heights.row );
  22447. }
  22448. this.dom.scroller.scrollTop = iScrollTop;
  22449. // Store positional information so positional calculations can be based
  22450. // upon the current table draw position
  22451. this.s.baseScrollTop = iScrollTop;
  22452. this.s.baseRowTop = this.s.topRowFloat;
  22453. // Position the table in the virtual scroller
  22454. var tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);
  22455. if ( displayStart === 0 ) {
  22456. tableTop = 0;
  22457. }
  22458. else if ( displayStart + displayLen >= displayEnd ) {
  22459. tableTop = heights.scroll - iTableHeight;
  22460. }
  22461. this.dom.table.style.top = tableTop+'px';
  22462. /* Cache some information for the scroller */
  22463. this.s.tableTop = tableTop;
  22464. this.s.tableBottom = iTableHeight + this.s.tableTop;
  22465. // Calculate the boundaries for where a redraw will be triggered by the
  22466. // scroll event listener
  22467. var boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;
  22468. this.s.redrawTop = iScrollTop - boundaryPx;
  22469. this.s.redrawBottom = iScrollTop + boundaryPx > heights.scroll - heights.viewport - heights.row ?
  22470. heights.scroll - heights.viewport - heights.row :
  22471. iScrollTop + boundaryPx;
  22472. this.s.skip = false;
  22473. // Restore the scrolling position that was saved by DataTable's state
  22474. // saving Note that this is done on the second draw when data is Ajax
  22475. // sourced, and the first draw when DOM soured
  22476. if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&
  22477. typeof this.s.dt.oLoadedState.iScroller != 'undefined' )
  22478. {
  22479. // A quirk of DataTables is that the draw callback will occur on an
  22480. // empty set if Ajax sourced, but not if server-side processing.
  22481. var ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ?
  22482. true :
  22483. false;
  22484. if ( ( ajaxSourced && this.s.dt.iDraw == 2) ||
  22485. (!ajaxSourced && this.s.dt.iDraw == 1) )
  22486. {
  22487. setTimeout( function () {
  22488. $(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );
  22489. that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);
  22490. // In order to prevent layout thrashing we need another
  22491. // small delay
  22492. setTimeout( function () {
  22493. that.s.ingnoreScroll = false;
  22494. }, 0 );
  22495. }, 0 );
  22496. }
  22497. }
  22498. else {
  22499. that.s.ingnoreScroll = false;
  22500. }
  22501. // Because of the order of the DT callbacks, the info update will
  22502. // take precedence over the one we want here. So a 'thread' break is
  22503. // needed. Only add the thread break if bInfo is set
  22504. if ( this.s.dt.oFeatures.bInfo ) {
  22505. setTimeout( function () {
  22506. that._fnInfo.call( that );
  22507. }, 0 );
  22508. }
  22509. // Hide the loading indicator
  22510. if ( this.dom.loader && this.s.loaderVisible ) {
  22511. this.dom.loader.css( 'display', 'none' );
  22512. this.s.loaderVisible = false;
  22513. }
  22514. },
  22515. /**
  22516. * Force the scrolling container to have height beyond that of just the
  22517. * table that has been drawn so the user can scroll the whole data set.
  22518. *
  22519. * Note that if the calculated required scrolling height exceeds a maximum
  22520. * value (1 million pixels - hard-coded) the forcing element will be set
  22521. * only to that maximum value and virtual / physical domain transforms will
  22522. * be used to allow Scroller to display tables of any number of records.
  22523. * @returns {void}
  22524. * @private
  22525. */
  22526. _fnScrollForce: function ()
  22527. {
  22528. var heights = this.s.heights;
  22529. var max = 1000000;
  22530. heights.virtual = heights.row * this.s.dt.fnRecordsDisplay();
  22531. heights.scroll = heights.virtual;
  22532. if ( heights.scroll > max ) {
  22533. heights.scroll = max;
  22534. }
  22535. // Minimum height so there is always a row visible (the 'no rows found'
  22536. // if reduced to zero filtering)
  22537. this.dom.force.style.height = heights.scroll > this.s.heights.row ?
  22538. heights.scroll+'px' :
  22539. this.s.heights.row+'px';
  22540. },
  22541. /**
  22542. * Automatic calculation of table row height. This is just a little tricky here as using
  22543. * initialisation DataTables has tale the table out of the document, so we need to create
  22544. * a new table and insert it into the document, calculate the row height and then whip the
  22545. * table out.
  22546. * @returns {void}
  22547. * @private
  22548. */
  22549. "_fnCalcRowHeight": function ()
  22550. {
  22551. var dt = this.s.dt;
  22552. var origTable = dt.nTable;
  22553. var nTable = origTable.cloneNode( false );
  22554. var tbody = $('<tbody/>').appendTo( nTable );
  22555. var container = $(
  22556. '<div class="'+dt.oClasses.sWrapper+' DTS">'+
  22557. '<div class="'+dt.oClasses.sScrollWrapper+'">'+
  22558. '<div class="'+dt.oClasses.sScrollBody+'"></div>'+
  22559. '</div>'+
  22560. '</div>'
  22561. );
  22562. // Want 3 rows in the sizing table so :first-child and :last-child
  22563. // CSS styles don't come into play - take the size of the middle row
  22564. $('tbody tr:lt(4)', origTable).clone().appendTo( tbody );
  22565. while( $('tr', tbody).length < 3 ) {
  22566. tbody.append( '<tr><td>&nbsp;</td></tr>' );
  22567. }
  22568. $('div.'+dt.oClasses.sScrollBody, container).append( nTable );
  22569. // If initialised using `dom`, use the holding element as the insert point
  22570. var insertEl = this.s.dt.nHolding || origTable.parentNode;
  22571. if ( ! $(insertEl).is(':visible') ) {
  22572. insertEl = 'body';
  22573. }
  22574. container.appendTo( insertEl );
  22575. this.s.heights.row = $('tr', tbody).eq(1).outerHeight();
  22576. container.remove();
  22577. },
  22578. /**
  22579. * Update any information elements that are controlled by the DataTable based on the scrolling
  22580. * viewport and what rows are visible in it. This function basically acts in the same way as
  22581. * _fnUpdateInfo in DataTables, and effectively replaces that function.
  22582. * @returns {void}
  22583. * @private
  22584. */
  22585. "_fnInfo": function ()
  22586. {
  22587. if ( !this.s.dt.oFeatures.bInfo )
  22588. {
  22589. return;
  22590. }
  22591. var
  22592. dt = this.s.dt,
  22593. language = dt.oLanguage,
  22594. iScrollTop = this.dom.scroller.scrollTop,
  22595. iStart = Math.floor( this.fnPixelsToRow(iScrollTop, false, this.s.ani)+1 ),
  22596. iMax = dt.fnRecordsTotal(),
  22597. iTotal = dt.fnRecordsDisplay(),
  22598. iPossibleEnd = Math.ceil( this.fnPixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),
  22599. iEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,
  22600. sStart = dt.fnFormatNumber( iStart ),
  22601. sEnd = dt.fnFormatNumber( iEnd ),
  22602. sMax = dt.fnFormatNumber( iMax ),
  22603. sTotal = dt.fnFormatNumber( iTotal ),
  22604. sOut;
  22605. if ( dt.fnRecordsDisplay() === 0 &&
  22606. dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
  22607. {
  22608. /* Empty record set */
  22609. sOut = language.sInfoEmpty+ language.sInfoPostFix;
  22610. }
  22611. else if ( dt.fnRecordsDisplay() === 0 )
  22612. {
  22613. /* Empty record set after filtering */
  22614. sOut = language.sInfoEmpty +' '+
  22615. language.sInfoFiltered.replace('_MAX_', sMax)+
  22616. language.sInfoPostFix;
  22617. }
  22618. else if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
  22619. {
  22620. /* Normal record set */
  22621. sOut = language.sInfo.
  22622. replace('_START_', sStart).
  22623. replace('_END_', sEnd).
  22624. replace('_MAX_', sMax).
  22625. replace('_TOTAL_', sTotal)+
  22626. language.sInfoPostFix;
  22627. }
  22628. else
  22629. {
  22630. /* Record set after filtering */
  22631. sOut = language.sInfo.
  22632. replace('_START_', sStart).
  22633. replace('_END_', sEnd).
  22634. replace('_MAX_', sMax).
  22635. replace('_TOTAL_', sTotal) +' '+
  22636. language.sInfoFiltered.replace(
  22637. '_MAX_',
  22638. dt.fnFormatNumber(dt.fnRecordsTotal())
  22639. )+
  22640. language.sInfoPostFix;
  22641. }
  22642. var callback = language.fnInfoCallback;
  22643. if ( callback ) {
  22644. sOut = callback.call( dt.oInstance,
  22645. dt, iStart, iEnd, iMax, iTotal, sOut
  22646. );
  22647. }
  22648. var n = dt.aanFeatures.i;
  22649. if ( typeof n != 'undefined' )
  22650. {
  22651. for ( var i=0, iLen=n.length ; i<iLen ; i++ )
  22652. {
  22653. $(n[i]).html( sOut );
  22654. }
  22655. }
  22656. // DT doesn't actually (yet) trigger this event, but it will in future
  22657. $(dt.nTable).triggerHandler( 'info.dt' );
  22658. }
  22659. } );
  22660. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22661. * Statics
  22662. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  22663. /**
  22664. * Scroller default settings for initialisation
  22665. * @namespace
  22666. * @name Scroller.defaults
  22667. * @static
  22668. */
  22669. Scroller.defaults = /** @lends Scroller.defaults */{
  22670. /**
  22671. * Indicate if Scroller show show trace information on the console or not. This can be
  22672. * useful when debugging Scroller or if just curious as to what it is doing, but should
  22673. * be turned off for production.
  22674. * @type bool
  22675. * @default false
  22676. * @static
  22677. * @example
  22678. * var oTable = $('#example').dataTable( {
  22679. * "sScrollY": "200px",
  22680. * "sDom": "frtiS",
  22681. * "bDeferRender": true,
  22682. * "oScroller": {
  22683. * "trace": true
  22684. * }
  22685. * } );
  22686. */
  22687. "trace": false,
  22688. /**
  22689. * Scroller will attempt to automatically calculate the height of rows for it's internal
  22690. * calculations. However the height that is used can be overridden using this parameter.
  22691. * @type int|string
  22692. * @default auto
  22693. * @static
  22694. * @example
  22695. * var oTable = $('#example').dataTable( {
  22696. * "sScrollY": "200px",
  22697. * "sDom": "frtiS",
  22698. * "bDeferRender": true,
  22699. * "oScroller": {
  22700. * "rowHeight": 30
  22701. * }
  22702. * } );
  22703. */
  22704. "rowHeight": "auto",
  22705. /**
  22706. * When using server-side processing, Scroller will wait a small amount of time to allow
  22707. * the scrolling to finish before requesting more data from the server. This prevents
  22708. * you from DoSing your own server! The wait time can be configured by this parameter.
  22709. * @type int
  22710. * @default 200
  22711. * @static
  22712. * @example
  22713. * var oTable = $('#example').dataTable( {
  22714. * "sScrollY": "200px",
  22715. * "sDom": "frtiS",
  22716. * "bDeferRender": true,
  22717. * "oScroller": {
  22718. * "serverWait": 100
  22719. * }
  22720. * } );
  22721. */
  22722. "serverWait": 200,
  22723. /**
  22724. * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch
  22725. * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch
  22726. * rows that will be shown in "near scrolling" (i.e. just beyond the current display area).
  22727. * The value is based upon the number of rows that can be displayed in the viewport (i.e.
  22728. * a value of 1), and will apply the display range to records before before and after the
  22729. * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth
  22730. * of rows before the current viewport, the current viewport's rows and 1 viewport's worth
  22731. * of rows after the current viewport. Adjusting this value can be useful for ensuring
  22732. * smooth scrolling based on your data set.
  22733. * @type int
  22734. * @default 7
  22735. * @static
  22736. * @example
  22737. * var oTable = $('#example').dataTable( {
  22738. * "sScrollY": "200px",
  22739. * "sDom": "frtiS",
  22740. * "bDeferRender": true,
  22741. * "oScroller": {
  22742. * "displayBuffer": 10
  22743. * }
  22744. * } );
  22745. */
  22746. "displayBuffer": 9,
  22747. /**
  22748. * Scroller uses the boundary scaling factor to decide when to redraw the table - which it
  22749. * typically does before you reach the end of the currently loaded data set (in order to
  22750. * allow the data to look continuous to a user scrolling through the data). If given as 0
  22751. * then the table will be redrawn whenever the viewport is scrolled, while 1 would not
  22752. * redraw the table until the currently loaded data has all been shown. You will want
  22753. * something in the middle - the default factor of 0.5 is usually suitable.
  22754. * @type float
  22755. * @default 0.5
  22756. * @static
  22757. * @example
  22758. * var oTable = $('#example').dataTable( {
  22759. * "sScrollY": "200px",
  22760. * "sDom": "frtiS",
  22761. * "bDeferRender": true,
  22762. * "oScroller": {
  22763. * "boundaryScale": 0.75
  22764. * }
  22765. * } );
  22766. */
  22767. "boundaryScale": 0.5,
  22768. /**
  22769. * Show (or not) the loading element in the background of the table. Note that you should
  22770. * include the dataTables.scroller.css file for this to be displayed correctly.
  22771. * @type boolean
  22772. * @default false
  22773. * @static
  22774. * @example
  22775. * var oTable = $('#example').dataTable( {
  22776. * "sScrollY": "200px",
  22777. * "sDom": "frtiS",
  22778. * "bDeferRender": true,
  22779. * "oScroller": {
  22780. * "loadingIndicator": true
  22781. * }
  22782. * } );
  22783. */
  22784. "loadingIndicator": false
  22785. };
  22786. Scroller.oDefaults = Scroller.defaults;
  22787. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22788. * Constants
  22789. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  22790. /**
  22791. * Scroller version
  22792. * @type String
  22793. * @default See code
  22794. * @name Scroller.version
  22795. * @static
  22796. */
  22797. Scroller.version = "1.4.4";
  22798. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22799. * Initialisation
  22800. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  22801. // Legacy `dom` parameter initialisation support
  22802. if ( typeof $.fn.dataTable == "function" &&
  22803. typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
  22804. $.fn.dataTableExt.fnVersionCheck('1.10.0') )
  22805. {
  22806. $.fn.dataTableExt.aoFeatures.push( {
  22807. "fnInit": function( oDTSettings ) {
  22808. var init = oDTSettings.oInit;
  22809. var opts = init.scroller || init.oScroller || {};
  22810. new Scroller( oDTSettings, opts );
  22811. },
  22812. "cFeature": "S",
  22813. "sFeature": "Scroller"
  22814. } );
  22815. }
  22816. else
  22817. {
  22818. alert( "Warning: Scroller requires DataTables 1.10.0 or greater - www.datatables.net/download");
  22819. }
  22820. // Attach a listener to the document which listens for DataTables initialisation
  22821. // events so we can automatically initialise
  22822. $(document).on( 'preInit.dt.dtscroller', function (e, settings) {
  22823. if ( e.namespace !== 'dt' ) {
  22824. return;
  22825. }
  22826. var init = settings.oInit.scroller;
  22827. var defaults = DataTable.defaults.scroller;
  22828. if ( init || defaults ) {
  22829. var opts = $.extend( {}, init, defaults );
  22830. if ( init !== false ) {
  22831. new Scroller( settings, opts );
  22832. }
  22833. }
  22834. } );
  22835. // Attach Scroller to DataTables so it can be accessed as an 'extra'
  22836. $.fn.dataTable.Scroller = Scroller;
  22837. $.fn.DataTable.Scroller = Scroller;
  22838. // DataTables 1.10 API method aliases
  22839. var Api = $.fn.dataTable.Api;
  22840. Api.register( 'scroller()', function () {
  22841. return this;
  22842. } );
  22843. // Undocumented and deprecated - is it actually useful at all?
  22844. Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {
  22845. var ctx = this.context;
  22846. if ( ctx.length && ctx[0].oScroller ) {
  22847. return ctx[0].oScroller.fnRowToPixels( rowIdx, intParse, virtual );
  22848. }
  22849. // undefined
  22850. } );
  22851. // Undocumented and deprecated - is it actually useful at all?
  22852. Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {
  22853. var ctx = this.context;
  22854. if ( ctx.length && ctx[0].oScroller ) {
  22855. return ctx[0].oScroller.fnPixelsToRow( pixels, intParse, virtual );
  22856. }
  22857. // undefined
  22858. } );
  22859. // Undocumented and deprecated - use `row().scrollTo()` instead
  22860. Api.register( 'scroller().scrollToRow()', function ( row, ani ) {
  22861. this.iterator( 'table', function ( ctx ) {
  22862. if ( ctx.oScroller ) {
  22863. ctx.oScroller.fnScrollToRow( row, ani );
  22864. }
  22865. } );
  22866. return this;
  22867. } );
  22868. Api.register( 'row().scrollTo()', function ( ani ) {
  22869. var that = this;
  22870. this.iterator( 'row', function ( ctx, rowIdx ) {
  22871. if ( ctx.oScroller ) {
  22872. var displayIdx = that
  22873. .rows( { order: 'applied', search: 'applied' } )
  22874. .indexes()
  22875. .indexOf( rowIdx );
  22876. ctx.oScroller.fnScrollToRow( displayIdx, ani );
  22877. }
  22878. } );
  22879. return this;
  22880. } );
  22881. Api.register( 'scroller.measure()', function ( redraw ) {
  22882. this.iterator( 'table', function ( ctx ) {
  22883. if ( ctx.oScroller ) {
  22884. ctx.oScroller.fnMeasure( redraw );
  22885. }
  22886. } );
  22887. return this;
  22888. } );
  22889. Api.register( 'scroller.page()', function() {
  22890. var ctx = this.context;
  22891. if ( ctx.length && ctx[0].oScroller ) {
  22892. return ctx[0].oScroller.fnPageInfo();
  22893. }
  22894. // undefined
  22895. } );
  22896. return Scroller;
  22897. }));
  22898. /*! Select for DataTables 1.2.5
  22899. * 2015-2018 SpryMedia Ltd - datatables.net/license/mit
  22900. */
  22901. /**
  22902. * @summary Select for DataTables
  22903. * @description A collection of API methods, events and buttons for DataTables
  22904. * that provides selection options of the items in a DataTable
  22905. * @version 1.2.5
  22906. * @file dataTables.select.js
  22907. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  22908. * @contact datatables.net/forums
  22909. * @copyright Copyright 2015-2018 SpryMedia Ltd.
  22910. *
  22911. * This source file is free software, available under the following license:
  22912. * MIT license - http://datatables.net/license/mit
  22913. *
  22914. * This source file is distributed in the hope that it will be useful, but
  22915. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  22916. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  22917. *
  22918. * For details please refer to: http://www.datatables.net/extensions/select
  22919. */
  22920. (function( factory ){
  22921. if ( typeof define === 'function' && define.amd ) {
  22922. // AMD
  22923. define( ['jquery', 'datatables.net'], function ( $ ) {
  22924. return factory( $, window, document );
  22925. } );
  22926. }
  22927. else if ( typeof exports === 'object' ) {
  22928. // CommonJS
  22929. module.exports = function (root, $) {
  22930. if ( ! root ) {
  22931. root = window;
  22932. }
  22933. if ( ! $ || ! $.fn.dataTable ) {
  22934. $ = require('datatables.net')(root, $).$;
  22935. }
  22936. return factory( $, root, root.document );
  22937. };
  22938. }
  22939. else {
  22940. // Browser
  22941. factory( jQuery, window, document );
  22942. }
  22943. }(function( $, window, document, undefined ) {
  22944. 'use strict';
  22945. var DataTable = $.fn.dataTable;
  22946. // Version information for debugger
  22947. DataTable.select = {};
  22948. DataTable.select.version = '1.2.5';
  22949. DataTable.select.init = function ( dt ) {
  22950. var ctx = dt.settings()[0];
  22951. var init = ctx.oInit.select;
  22952. var defaults = DataTable.defaults.select;
  22953. var opts = init === undefined ?
  22954. defaults :
  22955. init;
  22956. // Set defaults
  22957. var items = 'row';
  22958. var style = 'api';
  22959. var blurable = false;
  22960. var info = true;
  22961. var selector = 'td, th';
  22962. var className = 'selected';
  22963. var setStyle = false;
  22964. ctx._select = {};
  22965. // Initialisation customisations
  22966. if ( opts === true ) {
  22967. style = 'os';
  22968. setStyle = true;
  22969. }
  22970. else if ( typeof opts === 'string' ) {
  22971. style = opts;
  22972. setStyle = true;
  22973. }
  22974. else if ( $.isPlainObject( opts ) ) {
  22975. if ( opts.blurable !== undefined ) {
  22976. blurable = opts.blurable;
  22977. }
  22978. if ( opts.info !== undefined ) {
  22979. info = opts.info;
  22980. }
  22981. if ( opts.items !== undefined ) {
  22982. items = opts.items;
  22983. }
  22984. if ( opts.style !== undefined ) {
  22985. style = opts.style;
  22986. setStyle = true;
  22987. }
  22988. if ( opts.selector !== undefined ) {
  22989. selector = opts.selector;
  22990. }
  22991. if ( opts.className !== undefined ) {
  22992. className = opts.className;
  22993. }
  22994. }
  22995. dt.select.selector( selector );
  22996. dt.select.items( items );
  22997. dt.select.style( style );
  22998. dt.select.blurable( blurable );
  22999. dt.select.info( info );
  23000. ctx._select.className = className;
  23001. // Sort table based on selected rows. Requires Select Datatables extension
  23002. $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
  23003. return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
  23004. if ( settings._select.items === 'row' ) {
  23005. return $( td ).parent().hasClass( settings._select.className );
  23006. } else if ( settings._select.items === 'cell' ) {
  23007. return $( td ).hasClass( settings._select.className );
  23008. }
  23009. return false;
  23010. });
  23011. };
  23012. // If the init options haven't enabled select, but there is a selectable
  23013. // class name, then enable
  23014. if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
  23015. dt.select.style( 'os' );
  23016. }
  23017. };
  23018. /*
  23019. Select is a collection of API methods, event handlers, event emitters and
  23020. buttons (for the `Buttons` extension) for DataTables. It provides the following
  23021. features, with an overview of how they are implemented:
  23022. ## Selection of rows, columns and cells. Whether an item is selected or not is
  23023. stored in:
  23024. * rows: a `_select_selected` property which contains a boolean value of the
  23025. DataTables' `aoData` object for each row
  23026. * columns: a `_select_selected` property which contains a boolean value of the
  23027. DataTables' `aoColumns` object for each column
  23028. * cells: a `_selected_cells` property which contains an array of boolean values
  23029. of the `aoData` object for each row. The array is the same length as the
  23030. columns array, with each element of it representing a cell.
  23031. This method of using boolean flags allows Select to operate when nodes have not
  23032. been created for rows / cells (DataTables' defer rendering feature).
  23033. ## API methods
  23034. A range of API methods are available for triggering selection and de-selection
  23035. of rows. Methods are also available to configure the selection events that can
  23036. be triggered by an end user (such as which items are to be selected). To a large
  23037. extent, these of API methods *is* Select. It is basically a collection of helper
  23038. functions that can be used to select items in a DataTable.
  23039. Configuration of select is held in the object `_select` which is attached to the
  23040. DataTables settings object on initialisation. Select being available on a table
  23041. is not optional when Select is loaded, but its default is for selection only to
  23042. be available via the API - so the end user wouldn't be able to select rows
  23043. without additional configuration.
  23044. The `_select` object contains the following properties:
  23045. ```
  23046. {
  23047. items:string - Can be `rows`, `columns` or `cells`. Defines what item
  23048. will be selected if the user is allowed to activate row
  23049. selection using the mouse.
  23050. style:string - Can be `none`, `single`, `multi` or `os`. Defines the
  23051. interaction style when selecting items
  23052. blurable:boolean - If row selection can be cleared by clicking outside of
  23053. the table
  23054. info:boolean - If the selection summary should be shown in the table
  23055. information elements
  23056. }
  23057. ```
  23058. In addition to the API methods, Select also extends the DataTables selector
  23059. options for rows, columns and cells adding a `selected` option to the selector
  23060. options object, allowing the developer to select only selected items or
  23061. unselected items.
  23062. ## Mouse selection of items
  23063. Clicking on items can be used to select items. This is done by a simple event
  23064. handler that will select the items using the API methods.
  23065. */
  23066. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23067. * Local functions
  23068. */
  23069. /**
  23070. * Add one or more cells to the selection when shift clicking in OS selection
  23071. * style cell selection.
  23072. *
  23073. * Cell range is more complicated than row and column as we want to select
  23074. * in the visible grid rather than by index in sequence. For example, if you
  23075. * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
  23076. * should also be selected (and not 1-3, 1-4. etc)
  23077. *
  23078. * @param {DataTable.Api} dt DataTable
  23079. * @param {object} idx Cell index to select to
  23080. * @param {object} last Cell index to select from
  23081. * @private
  23082. */
  23083. function cellRange( dt, idx, last )
  23084. {
  23085. var indexes;
  23086. var columnIndexes;
  23087. var rowIndexes;
  23088. var selectColumns = function ( start, end ) {
  23089. if ( start > end ) {
  23090. var tmp = end;
  23091. end = start;
  23092. start = tmp;
  23093. }
  23094. var record = false;
  23095. return dt.columns( ':visible' ).indexes().filter( function (i) {
  23096. if ( i === start ) {
  23097. record = true;
  23098. }
  23099. if ( i === end ) { // not else if, as start might === end
  23100. record = false;
  23101. return true;
  23102. }
  23103. return record;
  23104. } );
  23105. };
  23106. var selectRows = function ( start, end ) {
  23107. var indexes = dt.rows( { search: 'applied' } ).indexes();
  23108. // Which comes first - might need to swap
  23109. if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
  23110. var tmp = end;
  23111. end = start;
  23112. start = tmp;
  23113. }
  23114. var record = false;
  23115. return indexes.filter( function (i) {
  23116. if ( i === start ) {
  23117. record = true;
  23118. }
  23119. if ( i === end ) {
  23120. record = false;
  23121. return true;
  23122. }
  23123. return record;
  23124. } );
  23125. };
  23126. if ( ! dt.cells( { selected: true } ).any() && ! last ) {
  23127. // select from the top left cell to this one
  23128. columnIndexes = selectColumns( 0, idx.column );
  23129. rowIndexes = selectRows( 0 , idx.row );
  23130. }
  23131. else {
  23132. // Get column indexes between old and new
  23133. columnIndexes = selectColumns( last.column, idx.column );
  23134. rowIndexes = selectRows( last.row , idx.row );
  23135. }
  23136. indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
  23137. if ( ! dt.cells( idx, { selected: true } ).any() ) {
  23138. // Select range
  23139. dt.cells( indexes ).select();
  23140. }
  23141. else {
  23142. // Deselect range
  23143. dt.cells( indexes ).deselect();
  23144. }
  23145. }
  23146. /**
  23147. * Disable mouse selection by removing the selectors
  23148. *
  23149. * @param {DataTable.Api} dt DataTable to remove events from
  23150. * @private
  23151. */
  23152. function disableMouseSelection( dt )
  23153. {
  23154. var ctx = dt.settings()[0];
  23155. var selector = ctx._select.selector;
  23156. $( dt.table().container() )
  23157. .off( 'mousedown.dtSelect', selector )
  23158. .off( 'mouseup.dtSelect', selector )
  23159. .off( 'click.dtSelect', selector );
  23160. $('body').off( 'click.dtSelect' + dt.table().node().id );
  23161. }
  23162. /**
  23163. * Attach mouse listeners to the table to allow mouse selection of items
  23164. *
  23165. * @param {DataTable.Api} dt DataTable to remove events from
  23166. * @private
  23167. */
  23168. function enableMouseSelection ( dt )
  23169. {
  23170. var container = $( dt.table().container() );
  23171. var ctx = dt.settings()[0];
  23172. var selector = ctx._select.selector;
  23173. container
  23174. .on( 'mousedown.dtSelect', selector, function(e) {
  23175. // Disallow text selection for shift clicking on the table so multi
  23176. // element selection doesn't look terrible!
  23177. if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
  23178. container
  23179. .css( '-moz-user-select', 'none' )
  23180. .one('selectstart.dtSelect', selector, function () {
  23181. return false;
  23182. } );
  23183. }
  23184. } )
  23185. .on( 'mouseup.dtSelect', selector, function() {
  23186. // Allow text selection to occur again, Mozilla style (tested in FF
  23187. // 35.0.1 - still required)
  23188. container.css( '-moz-user-select', '' );
  23189. } )
  23190. .on( 'click.dtSelect', selector, function ( e ) {
  23191. var items = dt.select.items();
  23192. var idx;
  23193. // If text was selected (click and drag), then we shouldn't change
  23194. // the row's selected state
  23195. if ( window.getSelection ) {
  23196. var selection = window.getSelection();
  23197. // If the element that contains the selection is not in the table, we can ignore it
  23198. // This can happen if the developer selects text from the click event
  23199. if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
  23200. if ( $.trim(selection.toString()) !== '' ) {
  23201. return;
  23202. }
  23203. }
  23204. }
  23205. var ctx = dt.settings()[0];
  23206. // Ignore clicks inside a sub-table
  23207. if ( $(e.target).closest('div.dataTables_wrapper')[0] != dt.table().container() ) {
  23208. return;
  23209. }
  23210. var cell = dt.cell( $(e.target).closest('td, th') );
  23211. // Check the cell actually belongs to the host DataTable (so child
  23212. // rows, etc, are ignored)
  23213. if ( ! cell.any() ) {
  23214. return;
  23215. }
  23216. var event = $.Event('user-select.dt');
  23217. eventTrigger( dt, event, [ items, cell, e ] );
  23218. if ( event.isDefaultPrevented() ) {
  23219. return;
  23220. }
  23221. var cellIndex = cell.index();
  23222. if ( items === 'row' ) {
  23223. idx = cellIndex.row;
  23224. typeSelect( e, dt, ctx, 'row', idx );
  23225. }
  23226. else if ( items === 'column' ) {
  23227. idx = cell.index().column;
  23228. typeSelect( e, dt, ctx, 'column', idx );
  23229. }
  23230. else if ( items === 'cell' ) {
  23231. idx = cell.index();
  23232. typeSelect( e, dt, ctx, 'cell', idx );
  23233. }
  23234. ctx._select_lastCell = cellIndex;
  23235. } );
  23236. // Blurable
  23237. $('body').on( 'click.dtSelect' + dt.table().node().id, function ( e ) {
  23238. if ( ctx._select.blurable ) {
  23239. // If the click was inside the DataTables container, don't blur
  23240. if ( $(e.target).parents().filter( dt.table().container() ).length ) {
  23241. return;
  23242. }
  23243. // Ignore elements which have been removed from the DOM (i.e. paging
  23244. // buttons)
  23245. if ( $(e.target).parents('html').length === 0 ) {
  23246. return;
  23247. }
  23248. // Don't blur in Editor form
  23249. if ( $(e.target).parents('div.DTE').length ) {
  23250. return;
  23251. }
  23252. clear( ctx, true );
  23253. }
  23254. } );
  23255. }
  23256. /**
  23257. * Trigger an event on a DataTable
  23258. *
  23259. * @param {DataTable.Api} api DataTable to trigger events on
  23260. * @param {boolean} selected true if selected, false if deselected
  23261. * @param {string} type Item type acting on
  23262. * @param {boolean} any Require that there are values before
  23263. * triggering
  23264. * @private
  23265. */
  23266. function eventTrigger ( api, type, args, any )
  23267. {
  23268. if ( any && ! api.flatten().length ) {
  23269. return;
  23270. }
  23271. if ( typeof type === 'string' ) {
  23272. type = type +'.dt';
  23273. }
  23274. args.unshift( api );
  23275. $(api.table().node()).trigger( type, args );
  23276. }
  23277. /**
  23278. * Update the information element of the DataTable showing information about the
  23279. * items selected. This is done by adding tags to the existing text
  23280. *
  23281. * @param {DataTable.Api} api DataTable to update
  23282. * @private
  23283. */
  23284. function info ( api )
  23285. {
  23286. var ctx = api.settings()[0];
  23287. if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
  23288. return;
  23289. }
  23290. if ( api.select.style() === 'api' ) {
  23291. return;
  23292. }
  23293. var rows = api.rows( { selected: true } ).flatten().length;
  23294. var columns = api.columns( { selected: true } ).flatten().length;
  23295. var cells = api.cells( { selected: true } ).flatten().length;
  23296. var add = function ( el, name, num ) {
  23297. el.append( $('<span class="select-item"/>').append( api.i18n(
  23298. 'select.'+name+'s',
  23299. { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
  23300. num
  23301. ) ) );
  23302. };
  23303. // Internal knowledge of DataTables to loop over all information elements
  23304. $.each( ctx.aanFeatures.i, function ( i, el ) {
  23305. el = $(el);
  23306. var output = $('<span class="select-info"/>');
  23307. add( output, 'row', rows );
  23308. add( output, 'column', columns );
  23309. add( output, 'cell', cells );
  23310. var exisiting = el.children('span.select-info');
  23311. if ( exisiting.length ) {
  23312. exisiting.remove();
  23313. }
  23314. if ( output.text() !== '' ) {
  23315. el.append( output );
  23316. }
  23317. } );
  23318. }
  23319. /**
  23320. * Initialisation of a new table. Attach event handlers and callbacks to allow
  23321. * Select to operate correctly.
  23322. *
  23323. * This will occur _after_ the initial DataTables initialisation, although
  23324. * before Ajax data is rendered, if there is ajax data
  23325. *
  23326. * @param {DataTable.settings} ctx Settings object to operate on
  23327. * @private
  23328. */
  23329. function init ( ctx ) {
  23330. var api = new DataTable.Api( ctx );
  23331. // Row callback so that classes can be added to rows and cells if the item
  23332. // was selected before the element was created. This will happen with the
  23333. // `deferRender` option enabled.
  23334. //
  23335. // This method of attaching to `aoRowCreatedCallback` is a hack until
  23336. // DataTables has proper events for row manipulation If you are reviewing
  23337. // this code to create your own plug-ins, please do not do this!
  23338. ctx.aoRowCreatedCallback.push( {
  23339. fn: function ( row, data, index ) {
  23340. var i, ien;
  23341. var d = ctx.aoData[ index ];
  23342. // Row
  23343. if ( d._select_selected ) {
  23344. $( row ).addClass( ctx._select.className );
  23345. }
  23346. // Cells and columns - if separated out, we would need to do two
  23347. // loops, so it makes sense to combine them into a single one
  23348. for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
  23349. if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
  23350. $(d.anCells[i]).addClass( ctx._select.className );
  23351. }
  23352. }
  23353. },
  23354. sName: 'select-deferRender'
  23355. } );
  23356. // On Ajax reload we want to reselect all rows which are currently selected,
  23357. // if there is an rowId (i.e. a unique value to identify each row with)
  23358. api.on( 'preXhr.dt.dtSelect', function () {
  23359. // note that column selection doesn't need to be cached and then
  23360. // reselected, as they are already selected
  23361. var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
  23362. return d !== undefined;
  23363. } );
  23364. var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
  23365. var id = api.row( cellIdx.row ).id( true );
  23366. return id ?
  23367. { row: id, column: cellIdx.column } :
  23368. undefined;
  23369. } ).filter( function ( d ) {
  23370. return d !== undefined;
  23371. } );
  23372. // On the next draw, reselect the currently selected items
  23373. api.one( 'draw.dt.dtSelect', function () {
  23374. api.rows( rows ).select();
  23375. // `cells` is not a cell index selector, so it needs a loop
  23376. if ( cells.any() ) {
  23377. cells.each( function ( id ) {
  23378. api.cells( id.row, id.column ).select();
  23379. } );
  23380. }
  23381. } );
  23382. } );
  23383. // Update the table information element with selected item summary
  23384. api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
  23385. info( api );
  23386. } );
  23387. // Clean up and release
  23388. api.on( 'destroy.dtSelect', function () {
  23389. disableMouseSelection( api );
  23390. api.off( '.dtSelect' );
  23391. } );
  23392. }
  23393. /**
  23394. * Add one or more items (rows or columns) to the selection when shift clicking
  23395. * in OS selection style
  23396. *
  23397. * @param {DataTable.Api} dt DataTable
  23398. * @param {string} type Row or column range selector
  23399. * @param {object} idx Item index to select to
  23400. * @param {object} last Item index to select from
  23401. * @private
  23402. */
  23403. function rowColumnRange( dt, type, idx, last )
  23404. {
  23405. // Add a range of rows from the last selected row to this one
  23406. var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
  23407. var idx1 = $.inArray( last, indexes );
  23408. var idx2 = $.inArray( idx, indexes );
  23409. if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
  23410. // select from top to here - slightly odd, but both Windows and Mac OS
  23411. // do this
  23412. indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
  23413. }
  23414. else {
  23415. // reverse so we can shift click 'up' as well as down
  23416. if ( idx1 > idx2 ) {
  23417. var tmp = idx2;
  23418. idx2 = idx1;
  23419. idx1 = tmp;
  23420. }
  23421. indexes.splice( idx2+1, indexes.length );
  23422. indexes.splice( 0, idx1 );
  23423. }
  23424. if ( ! dt[type]( idx, { selected: true } ).any() ) {
  23425. // Select range
  23426. dt[type+'s']( indexes ).select();
  23427. }
  23428. else {
  23429. // Deselect range - need to keep the clicked on row selected
  23430. indexes.splice( $.inArray( idx, indexes ), 1 );
  23431. dt[type+'s']( indexes ).deselect();
  23432. }
  23433. }
  23434. /**
  23435. * Clear all selected items
  23436. *
  23437. * @param {DataTable.settings} ctx Settings object of the host DataTable
  23438. * @param {boolean} [force=false] Force the de-selection to happen, regardless
  23439. * of selection style
  23440. * @private
  23441. */
  23442. function clear( ctx, force )
  23443. {
  23444. if ( force || ctx._select.style === 'single' ) {
  23445. var api = new DataTable.Api( ctx );
  23446. api.rows( { selected: true } ).deselect();
  23447. api.columns( { selected: true } ).deselect();
  23448. api.cells( { selected: true } ).deselect();
  23449. }
  23450. }
  23451. /**
  23452. * Select items based on the current configuration for style and items.
  23453. *
  23454. * @param {object} e Mouse event object
  23455. * @param {DataTables.Api} dt DataTable
  23456. * @param {DataTable.settings} ctx Settings object of the host DataTable
  23457. * @param {string} type Items to select
  23458. * @param {int|object} idx Index of the item to select
  23459. * @private
  23460. */
  23461. function typeSelect ( e, dt, ctx, type, idx )
  23462. {
  23463. var style = dt.select.style();
  23464. var isSelected = dt[type]( idx, { selected: true } ).any();
  23465. if ( style === 'os' ) {
  23466. if ( e.ctrlKey || e.metaKey ) {
  23467. // Add or remove from the selection
  23468. dt[type]( idx ).select( ! isSelected );
  23469. }
  23470. else if ( e.shiftKey ) {
  23471. if ( type === 'cell' ) {
  23472. cellRange( dt, idx, ctx._select_lastCell || null );
  23473. }
  23474. else {
  23475. rowColumnRange( dt, type, idx, ctx._select_lastCell ?
  23476. ctx._select_lastCell[type] :
  23477. null
  23478. );
  23479. }
  23480. }
  23481. else {
  23482. // No cmd or shift click - deselect if selected, or select
  23483. // this row only
  23484. var selected = dt[type+'s']( { selected: true } );
  23485. if ( isSelected && selected.flatten().length === 1 ) {
  23486. dt[type]( idx ).deselect();
  23487. }
  23488. else {
  23489. selected.deselect();
  23490. dt[type]( idx ).select();
  23491. }
  23492. }
  23493. } else if ( style == 'multi+shift' ) {
  23494. if ( e.shiftKey ) {
  23495. if ( type === 'cell' ) {
  23496. cellRange( dt, idx, ctx._select_lastCell || null );
  23497. }
  23498. else {
  23499. rowColumnRange( dt, type, idx, ctx._select_lastCell ?
  23500. ctx._select_lastCell[type] :
  23501. null
  23502. );
  23503. }
  23504. }
  23505. else {
  23506. dt[ type ]( idx ).select( ! isSelected );
  23507. }
  23508. }
  23509. else {
  23510. dt[ type ]( idx ).select( ! isSelected );
  23511. }
  23512. }
  23513. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23514. * DataTables selectors
  23515. */
  23516. // row and column are basically identical just assigned to different properties
  23517. // and checking a different array, so we can dynamically create the functions to
  23518. // reduce the code size
  23519. $.each( [
  23520. { type: 'row', prop: 'aoData' },
  23521. { type: 'column', prop: 'aoColumns' }
  23522. ], function ( i, o ) {
  23523. DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
  23524. var selected = opts.selected;
  23525. var data;
  23526. var out = [];
  23527. if ( selected !== true && selected !== false ) {
  23528. return indexes;
  23529. }
  23530. for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
  23531. data = settings[ o.prop ][ indexes[i] ];
  23532. if ( (selected === true && data._select_selected === true) ||
  23533. (selected === false && ! data._select_selected )
  23534. ) {
  23535. out.push( indexes[i] );
  23536. }
  23537. }
  23538. return out;
  23539. } );
  23540. } );
  23541. DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
  23542. var selected = opts.selected;
  23543. var rowData;
  23544. var out = [];
  23545. if ( selected === undefined ) {
  23546. return cells;
  23547. }
  23548. for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
  23549. rowData = settings.aoData[ cells[i].row ];
  23550. if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
  23551. (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
  23552. ) {
  23553. out.push( cells[i] );
  23554. }
  23555. }
  23556. return out;
  23557. } );
  23558. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23559. * DataTables API
  23560. *
  23561. * For complete documentation, please refer to the docs/api directory or the
  23562. * DataTables site
  23563. */
  23564. // Local variables to improve compression
  23565. var apiRegister = DataTable.Api.register;
  23566. var apiRegisterPlural = DataTable.Api.registerPlural;
  23567. apiRegister( 'select()', function () {
  23568. return this.iterator( 'table', function ( ctx ) {
  23569. DataTable.select.init( new DataTable.Api( ctx ) );
  23570. } );
  23571. } );
  23572. apiRegister( 'select.blurable()', function ( flag ) {
  23573. if ( flag === undefined ) {
  23574. return this.context[0]._select.blurable;
  23575. }
  23576. return this.iterator( 'table', function ( ctx ) {
  23577. ctx._select.blurable = flag;
  23578. } );
  23579. } );
  23580. apiRegister( 'select.info()', function ( flag ) {
  23581. if ( info === undefined ) {
  23582. return this.context[0]._select.info;
  23583. }
  23584. return this.iterator( 'table', function ( ctx ) {
  23585. ctx._select.info = flag;
  23586. } );
  23587. } );
  23588. apiRegister( 'select.items()', function ( items ) {
  23589. if ( items === undefined ) {
  23590. return this.context[0]._select.items;
  23591. }
  23592. return this.iterator( 'table', function ( ctx ) {
  23593. ctx._select.items = items;
  23594. eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
  23595. } );
  23596. } );
  23597. // Takes effect from the _next_ selection. None disables future selection, but
  23598. // does not clear the current selection. Use the `deselect` methods for that
  23599. apiRegister( 'select.style()', function ( style ) {
  23600. if ( style === undefined ) {
  23601. return this.context[0]._select.style;
  23602. }
  23603. return this.iterator( 'table', function ( ctx ) {
  23604. ctx._select.style = style;
  23605. if ( ! ctx._select_init ) {
  23606. init( ctx );
  23607. }
  23608. // Add / remove mouse event handlers. They aren't required when only
  23609. // API selection is available
  23610. var dt = new DataTable.Api( ctx );
  23611. disableMouseSelection( dt );
  23612. if ( style !== 'api' ) {
  23613. enableMouseSelection( dt );
  23614. }
  23615. eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
  23616. } );
  23617. } );
  23618. apiRegister( 'select.selector()', function ( selector ) {
  23619. if ( selector === undefined ) {
  23620. return this.context[0]._select.selector;
  23621. }
  23622. return this.iterator( 'table', function ( ctx ) {
  23623. disableMouseSelection( new DataTable.Api( ctx ) );
  23624. ctx._select.selector = selector;
  23625. if ( ctx._select.style !== 'api' ) {
  23626. enableMouseSelection( new DataTable.Api( ctx ) );
  23627. }
  23628. } );
  23629. } );
  23630. apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
  23631. var api = this;
  23632. if ( select === false ) {
  23633. return this.deselect();
  23634. }
  23635. this.iterator( 'row', function ( ctx, idx ) {
  23636. clear( ctx );
  23637. ctx.aoData[ idx ]._select_selected = true;
  23638. $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
  23639. } );
  23640. this.iterator( 'table', function ( ctx, i ) {
  23641. eventTrigger( api, 'select', [ 'row', api[i] ], true );
  23642. } );
  23643. return this;
  23644. } );
  23645. apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
  23646. var api = this;
  23647. if ( select === false ) {
  23648. return this.deselect();
  23649. }
  23650. this.iterator( 'column', function ( ctx, idx ) {
  23651. clear( ctx );
  23652. ctx.aoColumns[ idx ]._select_selected = true;
  23653. var column = new DataTable.Api( ctx ).column( idx );
  23654. $( column.header() ).addClass( ctx._select.className );
  23655. $( column.footer() ).addClass( ctx._select.className );
  23656. column.nodes().to$().addClass( ctx._select.className );
  23657. } );
  23658. this.iterator( 'table', function ( ctx, i ) {
  23659. eventTrigger( api, 'select', [ 'column', api[i] ], true );
  23660. } );
  23661. return this;
  23662. } );
  23663. apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
  23664. var api = this;
  23665. if ( select === false ) {
  23666. return this.deselect();
  23667. }
  23668. this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
  23669. clear( ctx );
  23670. var data = ctx.aoData[ rowIdx ];
  23671. if ( data._selected_cells === undefined ) {
  23672. data._selected_cells = [];
  23673. }
  23674. data._selected_cells[ colIdx ] = true;
  23675. if ( data.anCells ) {
  23676. $( data.anCells[ colIdx ] ).addClass( ctx._select.className );
  23677. }
  23678. } );
  23679. this.iterator( 'table', function ( ctx, i ) {
  23680. eventTrigger( api, 'select', [ 'cell', api[i] ], true );
  23681. } );
  23682. return this;
  23683. } );
  23684. apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
  23685. var api = this;
  23686. this.iterator( 'row', function ( ctx, idx ) {
  23687. ctx.aoData[ idx ]._select_selected = false;
  23688. $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
  23689. } );
  23690. this.iterator( 'table', function ( ctx, i ) {
  23691. eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
  23692. } );
  23693. return this;
  23694. } );
  23695. apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
  23696. var api = this;
  23697. this.iterator( 'column', function ( ctx, idx ) {
  23698. ctx.aoColumns[ idx ]._select_selected = false;
  23699. var api = new DataTable.Api( ctx );
  23700. var column = api.column( idx );
  23701. $( column.header() ).removeClass( ctx._select.className );
  23702. $( column.footer() ).removeClass( ctx._select.className );
  23703. // Need to loop over each cell, rather than just using
  23704. // `column().nodes()` as cells which are individually selected should
  23705. // not have the `selected` class removed from them
  23706. api.cells( null, idx ).indexes().each( function (cellIdx) {
  23707. var data = ctx.aoData[ cellIdx.row ];
  23708. var cellSelected = data._selected_cells;
  23709. if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
  23710. $( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className );
  23711. }
  23712. } );
  23713. } );
  23714. this.iterator( 'table', function ( ctx, i ) {
  23715. eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
  23716. } );
  23717. return this;
  23718. } );
  23719. apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
  23720. var api = this;
  23721. this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
  23722. var data = ctx.aoData[ rowIdx ];
  23723. data._selected_cells[ colIdx ] = false;
  23724. // Remove class only if the cells exist, and the cell is not column
  23725. // selected, in which case the class should remain (since it is selected
  23726. // in the column)
  23727. if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
  23728. $( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
  23729. }
  23730. } );
  23731. this.iterator( 'table', function ( ctx, i ) {
  23732. eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
  23733. } );
  23734. return this;
  23735. } );
  23736. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23737. * Buttons
  23738. */
  23739. function i18n( label, def ) {
  23740. return function (dt) {
  23741. return dt.i18n( 'buttons.'+label, def );
  23742. };
  23743. }
  23744. // Common events with suitable namespaces
  23745. function namespacedEvents ( config ) {
  23746. var unique = config._eventNamespace;
  23747. return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
  23748. }
  23749. function enabled ( dt, config ) {
  23750. if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
  23751. return true;
  23752. }
  23753. if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
  23754. return true;
  23755. }
  23756. if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
  23757. return true;
  23758. }
  23759. return false;
  23760. }
  23761. var _buttonNamespace = 0;
  23762. $.extend( DataTable.ext.buttons, {
  23763. selected: {
  23764. text: i18n( 'selected', 'Selected' ),
  23765. className: 'buttons-selected',
  23766. limitTo: [ 'rows', 'columns', 'cells' ],
  23767. init: function ( dt, node, config ) {
  23768. var that = this;
  23769. config._eventNamespace = '.select'+(_buttonNamespace++);
  23770. // .DT namespace listeners are removed by DataTables automatically
  23771. // on table destroy
  23772. dt.on( namespacedEvents(config), function () {
  23773. that.enable( enabled(dt, config) );
  23774. } );
  23775. this.disable();
  23776. },
  23777. destroy: function ( dt, node, config ) {
  23778. dt.off( config._eventNamespace );
  23779. }
  23780. },
  23781. selectedSingle: {
  23782. text: i18n( 'selectedSingle', 'Selected single' ),
  23783. className: 'buttons-selected-single',
  23784. init: function ( dt, node, config ) {
  23785. var that = this;
  23786. config._eventNamespace = '.select'+(_buttonNamespace++);
  23787. dt.on( namespacedEvents(config), function () {
  23788. var count = dt.rows( { selected: true } ).flatten().length +
  23789. dt.columns( { selected: true } ).flatten().length +
  23790. dt.cells( { selected: true } ).flatten().length;
  23791. that.enable( count === 1 );
  23792. } );
  23793. this.disable();
  23794. },
  23795. destroy: function ( dt, node, config ) {
  23796. dt.off( config._eventNamespace );
  23797. }
  23798. },
  23799. selectAll: {
  23800. text: i18n( 'selectAll', 'Select all' ),
  23801. className: 'buttons-select-all',
  23802. action: function () {
  23803. var items = this.select.items();
  23804. this[ items+'s' ]().select();
  23805. }
  23806. },
  23807. selectNone: {
  23808. text: i18n( 'selectNone', 'Deselect all' ),
  23809. className: 'buttons-select-none',
  23810. action: function () {
  23811. clear( this.settings()[0], true );
  23812. },
  23813. init: function ( dt, node, config ) {
  23814. var that = this;
  23815. config._eventNamespace = '.select'+(_buttonNamespace++);
  23816. dt.on( namespacedEvents(config), function () {
  23817. var count = dt.rows( { selected: true } ).flatten().length +
  23818. dt.columns( { selected: true } ).flatten().length +
  23819. dt.cells( { selected: true } ).flatten().length;
  23820. that.enable( count > 0 );
  23821. } );
  23822. this.disable();
  23823. },
  23824. destroy: function ( dt, node, config ) {
  23825. dt.off( config._eventNamespace );
  23826. }
  23827. }
  23828. } );
  23829. $.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
  23830. var lc = item.toLowerCase();
  23831. DataTable.ext.buttons[ 'select'+item+'s' ] = {
  23832. text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
  23833. className: 'buttons-select-'+lc+'s',
  23834. action: function () {
  23835. this.select.items( lc );
  23836. },
  23837. init: function ( dt ) {
  23838. var that = this;
  23839. dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
  23840. that.active( items === lc );
  23841. } );
  23842. }
  23843. };
  23844. } );
  23845. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23846. * Initialisation
  23847. */
  23848. // DataTables creation - check if select has been defined in the options. Note
  23849. // this required that the table be in the document! If it isn't then something
  23850. // needs to trigger this method unfortunately. The next major release of
  23851. // DataTables will rework the events and address this.
  23852. $(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
  23853. if ( e.namespace !== 'dt' ) {
  23854. return;
  23855. }
  23856. DataTable.select.init( new DataTable.Api( ctx ) );
  23857. } );
  23858. return DataTable.select;
  23859. }));