semantic.js 895 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469
  1. /*
  2. * # Fomantic UI - 2.7.8
  3. * https://github.com/fomantic/Fomantic-UI
  4. * http://fomantic-ui.com/
  5. *
  6. * Copyright 2014 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. /*!
  12. * # Fomantic-UI - Site
  13. * http://github.com/fomantic/Fomantic-UI/
  14. *
  15. *
  16. * Released under the MIT license
  17. * http://opensource.org/licenses/MIT
  18. *
  19. */
  20. ;(function ($, window, document, undefined) {
  21. $.isFunction = $.isFunction || function(obj) {
  22. return typeof obj === "function" && typeof obj.nodeType !== "number";
  23. };
  24. $.site = $.fn.site = function(parameters) {
  25. var
  26. time = new Date().getTime(),
  27. performance = [],
  28. query = arguments[0],
  29. methodInvoked = (typeof query == 'string'),
  30. queryArguments = [].slice.call(arguments, 1),
  31. settings = ( $.isPlainObject(parameters) )
  32. ? $.extend(true, {}, $.site.settings, parameters)
  33. : $.extend({}, $.site.settings),
  34. namespace = settings.namespace,
  35. error = settings.error,
  36. moduleNamespace = 'module-' + namespace,
  37. $document = $(document),
  38. $module = $document,
  39. element = this,
  40. instance = $module.data(moduleNamespace),
  41. module,
  42. returnedValue
  43. ;
  44. module = {
  45. initialize: function() {
  46. module.instantiate();
  47. },
  48. instantiate: function() {
  49. module.verbose('Storing instance of site', module);
  50. instance = module;
  51. $module
  52. .data(moduleNamespace, module)
  53. ;
  54. },
  55. normalize: function() {
  56. module.fix.console();
  57. module.fix.requestAnimationFrame();
  58. },
  59. fix: {
  60. console: function() {
  61. module.debug('Normalizing window.console');
  62. if (console === undefined || console.log === undefined) {
  63. module.verbose('Console not available, normalizing events');
  64. module.disable.console();
  65. }
  66. if (typeof console.group == 'undefined' || typeof console.groupEnd == 'undefined' || typeof console.groupCollapsed == 'undefined') {
  67. module.verbose('Console group not available, normalizing events');
  68. window.console.group = function() {};
  69. window.console.groupEnd = function() {};
  70. window.console.groupCollapsed = function() {};
  71. }
  72. if (typeof console.markTimeline == 'undefined') {
  73. module.verbose('Mark timeline not available, normalizing events');
  74. window.console.markTimeline = function() {};
  75. }
  76. },
  77. consoleClear: function() {
  78. module.debug('Disabling programmatic console clearing');
  79. window.console.clear = function() {};
  80. },
  81. requestAnimationFrame: function() {
  82. module.debug('Normalizing requestAnimationFrame');
  83. if(window.requestAnimationFrame === undefined) {
  84. module.debug('RequestAnimationFrame not available, normalizing event');
  85. window.requestAnimationFrame = window.requestAnimationFrame
  86. || window.mozRequestAnimationFrame
  87. || window.webkitRequestAnimationFrame
  88. || window.msRequestAnimationFrame
  89. || function(callback) { setTimeout(callback, 0); }
  90. ;
  91. }
  92. }
  93. },
  94. moduleExists: function(name) {
  95. return ($.fn[name] !== undefined && $.fn[name].settings !== undefined);
  96. },
  97. enabled: {
  98. modules: function(modules) {
  99. var
  100. enabledModules = []
  101. ;
  102. modules = modules || settings.modules;
  103. $.each(modules, function(index, name) {
  104. if(module.moduleExists(name)) {
  105. enabledModules.push(name);
  106. }
  107. });
  108. return enabledModules;
  109. }
  110. },
  111. disabled: {
  112. modules: function(modules) {
  113. var
  114. disabledModules = []
  115. ;
  116. modules = modules || settings.modules;
  117. $.each(modules, function(index, name) {
  118. if(!module.moduleExists(name)) {
  119. disabledModules.push(name);
  120. }
  121. });
  122. return disabledModules;
  123. }
  124. },
  125. change: {
  126. setting: function(setting, value, modules, modifyExisting) {
  127. modules = (typeof modules === 'string')
  128. ? (modules === 'all')
  129. ? settings.modules
  130. : [modules]
  131. : modules || settings.modules
  132. ;
  133. modifyExisting = (modifyExisting !== undefined)
  134. ? modifyExisting
  135. : true
  136. ;
  137. $.each(modules, function(index, name) {
  138. var
  139. namespace = (module.moduleExists(name))
  140. ? $.fn[name].settings.namespace || false
  141. : true,
  142. $existingModules
  143. ;
  144. if(module.moduleExists(name)) {
  145. module.verbose('Changing default setting', setting, value, name);
  146. $.fn[name].settings[setting] = value;
  147. if(modifyExisting && namespace) {
  148. $existingModules = $(':data(module-' + namespace + ')');
  149. if($existingModules.length > 0) {
  150. module.verbose('Modifying existing settings', $existingModules);
  151. $existingModules[name]('setting', setting, value);
  152. }
  153. }
  154. }
  155. });
  156. },
  157. settings: function(newSettings, modules, modifyExisting) {
  158. modules = (typeof modules === 'string')
  159. ? [modules]
  160. : modules || settings.modules
  161. ;
  162. modifyExisting = (modifyExisting !== undefined)
  163. ? modifyExisting
  164. : true
  165. ;
  166. $.each(modules, function(index, name) {
  167. var
  168. $existingModules
  169. ;
  170. if(module.moduleExists(name)) {
  171. module.verbose('Changing default setting', newSettings, name);
  172. $.extend(true, $.fn[name].settings, newSettings);
  173. if(modifyExisting && namespace) {
  174. $existingModules = $(':data(module-' + namespace + ')');
  175. if($existingModules.length > 0) {
  176. module.verbose('Modifying existing settings', $existingModules);
  177. $existingModules[name]('setting', newSettings);
  178. }
  179. }
  180. }
  181. });
  182. }
  183. },
  184. enable: {
  185. console: function() {
  186. module.console(true);
  187. },
  188. debug: function(modules, modifyExisting) {
  189. modules = modules || settings.modules;
  190. module.debug('Enabling debug for modules', modules);
  191. module.change.setting('debug', true, modules, modifyExisting);
  192. },
  193. verbose: function(modules, modifyExisting) {
  194. modules = modules || settings.modules;
  195. module.debug('Enabling verbose debug for modules', modules);
  196. module.change.setting('verbose', true, modules, modifyExisting);
  197. }
  198. },
  199. disable: {
  200. console: function() {
  201. module.console(false);
  202. },
  203. debug: function(modules, modifyExisting) {
  204. modules = modules || settings.modules;
  205. module.debug('Disabling debug for modules', modules);
  206. module.change.setting('debug', false, modules, modifyExisting);
  207. },
  208. verbose: function(modules, modifyExisting) {
  209. modules = modules || settings.modules;
  210. module.debug('Disabling verbose debug for modules', modules);
  211. module.change.setting('verbose', false, modules, modifyExisting);
  212. }
  213. },
  214. console: function(enable) {
  215. if(enable) {
  216. if(instance.cache.console === undefined) {
  217. module.error(error.console);
  218. return;
  219. }
  220. module.debug('Restoring console function');
  221. window.console = instance.cache.console;
  222. }
  223. else {
  224. module.debug('Disabling console function');
  225. instance.cache.console = window.console;
  226. window.console = {
  227. clear : function(){},
  228. error : function(){},
  229. group : function(){},
  230. groupCollapsed : function(){},
  231. groupEnd : function(){},
  232. info : function(){},
  233. log : function(){},
  234. markTimeline : function(){},
  235. warn : function(){}
  236. };
  237. }
  238. },
  239. destroy: function() {
  240. module.verbose('Destroying previous site for', $module);
  241. $module
  242. .removeData(moduleNamespace)
  243. ;
  244. },
  245. cache: {},
  246. setting: function(name, value) {
  247. if( $.isPlainObject(name) ) {
  248. $.extend(true, settings, name);
  249. }
  250. else if(value !== undefined) {
  251. settings[name] = value;
  252. }
  253. else {
  254. return settings[name];
  255. }
  256. },
  257. internal: function(name, value) {
  258. if( $.isPlainObject(name) ) {
  259. $.extend(true, module, name);
  260. }
  261. else if(value !== undefined) {
  262. module[name] = value;
  263. }
  264. else {
  265. return module[name];
  266. }
  267. },
  268. debug: function() {
  269. if(settings.debug) {
  270. if(settings.performance) {
  271. module.performance.log(arguments);
  272. }
  273. else {
  274. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  275. module.debug.apply(console, arguments);
  276. }
  277. }
  278. },
  279. verbose: function() {
  280. if(settings.verbose && settings.debug) {
  281. if(settings.performance) {
  282. module.performance.log(arguments);
  283. }
  284. else {
  285. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  286. module.verbose.apply(console, arguments);
  287. }
  288. }
  289. },
  290. error: function() {
  291. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  292. module.error.apply(console, arguments);
  293. },
  294. performance: {
  295. log: function(message) {
  296. var
  297. currentTime,
  298. executionTime,
  299. previousTime
  300. ;
  301. if(settings.performance) {
  302. currentTime = new Date().getTime();
  303. previousTime = time || currentTime;
  304. executionTime = currentTime - previousTime;
  305. time = currentTime;
  306. performance.push({
  307. 'Element' : element,
  308. 'Name' : message[0],
  309. 'Arguments' : [].slice.call(message, 1) || '',
  310. 'Execution Time' : executionTime
  311. });
  312. }
  313. clearTimeout(module.performance.timer);
  314. module.performance.timer = setTimeout(module.performance.display, 500);
  315. },
  316. display: function() {
  317. var
  318. title = settings.name + ':',
  319. totalTime = 0
  320. ;
  321. time = false;
  322. clearTimeout(module.performance.timer);
  323. $.each(performance, function(index, data) {
  324. totalTime += data['Execution Time'];
  325. });
  326. title += ' ' + totalTime + 'ms';
  327. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  328. console.groupCollapsed(title);
  329. if(console.table) {
  330. console.table(performance);
  331. }
  332. else {
  333. $.each(performance, function(index, data) {
  334. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  335. });
  336. }
  337. console.groupEnd();
  338. }
  339. performance = [];
  340. }
  341. },
  342. invoke: function(query, passedArguments, context) {
  343. var
  344. object = instance,
  345. maxDepth,
  346. found,
  347. response
  348. ;
  349. passedArguments = passedArguments || queryArguments;
  350. context = element || context;
  351. if(typeof query == 'string' && object !== undefined) {
  352. query = query.split(/[\. ]/);
  353. maxDepth = query.length - 1;
  354. $.each(query, function(depth, value) {
  355. var camelCaseValue = (depth != maxDepth)
  356. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  357. : query
  358. ;
  359. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  360. object = object[camelCaseValue];
  361. }
  362. else if( object[camelCaseValue] !== undefined ) {
  363. found = object[camelCaseValue];
  364. return false;
  365. }
  366. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  367. object = object[value];
  368. }
  369. else if( object[value] !== undefined ) {
  370. found = object[value];
  371. return false;
  372. }
  373. else {
  374. module.error(error.method, query);
  375. return false;
  376. }
  377. });
  378. }
  379. if ( $.isFunction( found ) ) {
  380. response = found.apply(context, passedArguments);
  381. }
  382. else if(found !== undefined) {
  383. response = found;
  384. }
  385. if(Array.isArray(returnedValue)) {
  386. returnedValue.push(response);
  387. }
  388. else if(returnedValue !== undefined) {
  389. returnedValue = [returnedValue, response];
  390. }
  391. else if(response !== undefined) {
  392. returnedValue = response;
  393. }
  394. return found;
  395. }
  396. };
  397. if(methodInvoked) {
  398. if(instance === undefined) {
  399. module.initialize();
  400. }
  401. module.invoke(query);
  402. }
  403. else {
  404. if(instance !== undefined) {
  405. module.destroy();
  406. }
  407. module.initialize();
  408. }
  409. return (returnedValue !== undefined)
  410. ? returnedValue
  411. : this
  412. ;
  413. };
  414. $.site.settings = {
  415. name : 'Site',
  416. namespace : 'site',
  417. error : {
  418. console : 'Console cannot be restored, most likely it was overwritten outside of module',
  419. method : 'The method you called is not defined.'
  420. },
  421. debug : false,
  422. verbose : false,
  423. performance : true,
  424. modules: [
  425. 'accordion',
  426. 'api',
  427. 'calendar',
  428. 'checkbox',
  429. 'dimmer',
  430. 'dropdown',
  431. 'embed',
  432. 'form',
  433. 'modal',
  434. 'nag',
  435. 'popup',
  436. 'slider',
  437. 'rating',
  438. 'shape',
  439. 'sidebar',
  440. 'state',
  441. 'sticky',
  442. 'tab',
  443. 'toast',
  444. 'transition',
  445. 'visibility',
  446. 'visit'
  447. ],
  448. siteNamespace : 'site',
  449. namespaceStub : {
  450. cache : {},
  451. config : {},
  452. sections : {},
  453. section : {},
  454. utilities : {}
  455. }
  456. };
  457. // allows for selection of elements with data attributes
  458. $.extend($.expr[ ":" ], {
  459. data: ($.expr.createPseudo)
  460. ? $.expr.createPseudo(function(dataName) {
  461. return function(elem) {
  462. return !!$.data(elem, dataName);
  463. };
  464. })
  465. : function(elem, i, match) {
  466. // support: jQuery < 1.8
  467. return !!$.data(elem, match[ 3 ]);
  468. }
  469. });
  470. })( jQuery, window, document );
  471. /*!
  472. * # Fomantic-UI - Form Validation
  473. * http://github.com/fomantic/Fomantic-UI/
  474. *
  475. *
  476. * Released under the MIT license
  477. * http://opensource.org/licenses/MIT
  478. *
  479. */
  480. ;(function ($, window, document, undefined) {
  481. 'use strict';
  482. $.isFunction = $.isFunction || function(obj) {
  483. return typeof obj === "function" && typeof obj.nodeType !== "number";
  484. };
  485. window = (typeof window != 'undefined' && window.Math == Math)
  486. ? window
  487. : (typeof self != 'undefined' && self.Math == Math)
  488. ? self
  489. : Function('return this')()
  490. ;
  491. $.fn.form = function(parameters) {
  492. var
  493. $allModules = $(this),
  494. moduleSelector = $allModules.selector || '',
  495. time = new Date().getTime(),
  496. performance = [],
  497. query = arguments[0],
  498. legacyParameters = arguments[1],
  499. methodInvoked = (typeof query == 'string'),
  500. queryArguments = [].slice.call(arguments, 1),
  501. returnedValue
  502. ;
  503. $allModules
  504. .each(function() {
  505. var
  506. $module = $(this),
  507. element = this,
  508. formErrors = [],
  509. keyHeldDown = false,
  510. // set at run-time
  511. $field,
  512. $group,
  513. $message,
  514. $prompt,
  515. $submit,
  516. $clear,
  517. $reset,
  518. settings,
  519. validation,
  520. metadata,
  521. selector,
  522. className,
  523. regExp,
  524. error,
  525. namespace,
  526. moduleNamespace,
  527. eventNamespace,
  528. submitting = false,
  529. dirty = false,
  530. history = ['clean', 'clean'],
  531. instance,
  532. module
  533. ;
  534. module = {
  535. initialize: function() {
  536. // settings grabbed at run time
  537. module.get.settings();
  538. if(methodInvoked) {
  539. if(instance === undefined) {
  540. module.instantiate();
  541. }
  542. module.invoke(query);
  543. }
  544. else {
  545. if(instance !== undefined) {
  546. instance.invoke('destroy');
  547. }
  548. module.verbose('Initializing form validation', $module, settings);
  549. module.bindEvents();
  550. module.set.defaults();
  551. module.instantiate();
  552. }
  553. },
  554. instantiate: function() {
  555. module.verbose('Storing instance of module', module);
  556. instance = module;
  557. $module
  558. .data(moduleNamespace, module)
  559. ;
  560. },
  561. destroy: function() {
  562. module.verbose('Destroying previous module', instance);
  563. module.removeEvents();
  564. $module
  565. .removeData(moduleNamespace)
  566. ;
  567. },
  568. refresh: function() {
  569. module.verbose('Refreshing selector cache');
  570. $field = $module.find(selector.field);
  571. $group = $module.find(selector.group);
  572. $message = $module.find(selector.message);
  573. $prompt = $module.find(selector.prompt);
  574. $submit = $module.find(selector.submit);
  575. $clear = $module.find(selector.clear);
  576. $reset = $module.find(selector.reset);
  577. },
  578. submit: function() {
  579. module.verbose('Submitting form', $module);
  580. submitting = true;
  581. $module.submit();
  582. },
  583. attachEvents: function(selector, action) {
  584. action = action || 'submit';
  585. $(selector).on('click' + eventNamespace, function(event) {
  586. module[action]();
  587. event.preventDefault();
  588. });
  589. },
  590. bindEvents: function() {
  591. module.verbose('Attaching form events');
  592. $module
  593. .on('submit' + eventNamespace, module.validate.form)
  594. .on('blur' + eventNamespace, selector.field, module.event.field.blur)
  595. .on('click' + eventNamespace, selector.submit, module.submit)
  596. .on('click' + eventNamespace, selector.reset, module.reset)
  597. .on('click' + eventNamespace, selector.clear, module.clear)
  598. ;
  599. if(settings.keyboardShortcuts) {
  600. $module.on('keydown' + eventNamespace, selector.field, module.event.field.keydown);
  601. }
  602. $field.each(function(index, el) {
  603. var
  604. $input = $(el),
  605. type = $input.prop('type'),
  606. inputEvent = module.get.changeEvent(type, $input)
  607. ;
  608. $input.on(inputEvent + eventNamespace, module.event.field.change);
  609. });
  610. // Dirty events
  611. if (settings.preventLeaving) {
  612. $(window).on('beforeunload' + eventNamespace, module.event.beforeUnload);
  613. }
  614. $field.on('change click keyup keydown blur', function(e) {
  615. $(this).trigger(e.type + ".dirty");
  616. });
  617. $field.on('change.dirty click.dirty keyup.dirty keydown.dirty blur.dirty', module.determine.isDirty);
  618. $module.on('dirty' + eventNamespace, function(e) {
  619. settings.onDirty.call();
  620. });
  621. $module.on('clean' + eventNamespace, function(e) {
  622. settings.onClean.call();
  623. })
  624. },
  625. clear: function() {
  626. $field.each(function (index, el) {
  627. var
  628. $field = $(el),
  629. $element = $field.parent(),
  630. $fieldGroup = $field.closest($group),
  631. $prompt = $fieldGroup.find(selector.prompt),
  632. $calendar = $field.closest(selector.uiCalendar),
  633. defaultValue = $field.data(metadata.defaultValue) || '',
  634. isCheckbox = $element.is(selector.uiCheckbox),
  635. isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  636. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  637. isErrored = $fieldGroup.hasClass(className.error)
  638. ;
  639. if(isErrored) {
  640. module.verbose('Resetting error on field', $fieldGroup);
  641. $fieldGroup.removeClass(className.error);
  642. $prompt.remove();
  643. }
  644. if(isDropdown) {
  645. module.verbose('Resetting dropdown value', $element, defaultValue);
  646. $element.dropdown('clear');
  647. }
  648. else if(isCheckbox) {
  649. $field.prop('checked', false);
  650. }
  651. else if (isCalendar) {
  652. $calendar.calendar('clear');
  653. }
  654. else {
  655. module.verbose('Resetting field value', $field, defaultValue);
  656. $field.val('');
  657. }
  658. });
  659. },
  660. reset: function() {
  661. $field.each(function (index, el) {
  662. var
  663. $field = $(el),
  664. $element = $field.parent(),
  665. $fieldGroup = $field.closest($group),
  666. $calendar = $field.closest(selector.uiCalendar),
  667. $prompt = $fieldGroup.find(selector.prompt),
  668. defaultValue = $field.data(metadata.defaultValue),
  669. isCheckbox = $element.is(selector.uiCheckbox),
  670. isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  671. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  672. isErrored = $fieldGroup.hasClass(className.error)
  673. ;
  674. if(defaultValue === undefined) {
  675. return;
  676. }
  677. if(isErrored) {
  678. module.verbose('Resetting error on field', $fieldGroup);
  679. $fieldGroup.removeClass(className.error);
  680. $prompt.remove();
  681. }
  682. if(isDropdown) {
  683. module.verbose('Resetting dropdown value', $element, defaultValue);
  684. $element.dropdown('restore defaults');
  685. }
  686. else if(isCheckbox) {
  687. module.verbose('Resetting checkbox value', $element, defaultValue);
  688. $field.prop('checked', defaultValue);
  689. }
  690. else if (isCalendar) {
  691. $calendar.calendar('set date', defaultValue);
  692. }
  693. else {
  694. module.verbose('Resetting field value', $field, defaultValue);
  695. $field.val(defaultValue);
  696. }
  697. });
  698. module.determine.isDirty();
  699. },
  700. determine: {
  701. isValid: function() {
  702. var
  703. allValid = true
  704. ;
  705. $.each(validation, function(fieldName, field) {
  706. if( !( module.validate.field(field, fieldName, true) ) ) {
  707. allValid = false;
  708. }
  709. });
  710. return allValid;
  711. },
  712. isDirty: function(e) {
  713. var formIsDirty = false;
  714. $field.each(function(index, el) {
  715. var
  716. $el = $(el),
  717. isCheckbox = ($el.filter(selector.checkbox).length > 0),
  718. isDirty
  719. ;
  720. if (isCheckbox) {
  721. isDirty = module.is.checkboxDirty($el);
  722. } else {
  723. isDirty = module.is.fieldDirty($el);
  724. }
  725. $el.data(settings.metadata.isDirty, isDirty);
  726. formIsDirty |= isDirty;
  727. });
  728. if (formIsDirty) {
  729. module.set.dirty();
  730. } else {
  731. module.set.clean();
  732. }
  733. if (e && e.namespace === 'dirty') {
  734. e.stopImmediatePropagation();
  735. e.preventDefault();
  736. }
  737. }
  738. },
  739. is: {
  740. bracketedRule: function(rule) {
  741. return (rule.type && rule.type.match(settings.regExp.bracket));
  742. },
  743. shorthandFields: function(fields) {
  744. var
  745. fieldKeys = Object.keys(fields),
  746. firstRule = fields[fieldKeys[0]]
  747. ;
  748. return module.is.shorthandRules(firstRule);
  749. },
  750. // duck type rule test
  751. shorthandRules: function(rules) {
  752. return (typeof rules == 'string' || Array.isArray(rules));
  753. },
  754. empty: function($field) {
  755. if(!$field || $field.length === 0) {
  756. return true;
  757. }
  758. else if($field.is(selector.checkbox)) {
  759. return !$field.is(':checked');
  760. }
  761. else {
  762. return module.is.blank($field);
  763. }
  764. },
  765. blank: function($field) {
  766. return $.trim($field.val()) === '';
  767. },
  768. valid: function(field) {
  769. var
  770. allValid = true
  771. ;
  772. if(field) {
  773. module.verbose('Checking if field is valid', field);
  774. return module.validate.field(validation[field], field, false);
  775. }
  776. else {
  777. module.verbose('Checking if form is valid');
  778. $.each(validation, function(fieldName, field) {
  779. if( !module.is.valid(fieldName) ) {
  780. allValid = false;
  781. }
  782. });
  783. return allValid;
  784. }
  785. },
  786. dirty: function() {
  787. return dirty;
  788. },
  789. clean: function() {
  790. return !dirty;
  791. },
  792. fieldDirty: function($el) {
  793. var initialValue = $el.data(metadata.defaultValue);
  794. // Explicitly check for null/undefined here as value may be `false`, so ($el.data(dataInitialValue) || '') would not work
  795. if (initialValue == null) { initialValue = ''; }
  796. var currentValue = $el.val();
  797. if (currentValue == null) { currentValue = ''; }
  798. // Boolean values can be encoded as "true/false" or "True/False" depending on underlying frameworks so we need a case insensitive comparison
  799. var boolRegex = /^(true|false)$/i;
  800. var isBoolValue = boolRegex.test(initialValue) && boolRegex.test(currentValue);
  801. if (isBoolValue) {
  802. var regex = new RegExp("^" + initialValue + "$", "i");
  803. return !regex.test(currentValue);
  804. }
  805. return currentValue !== initialValue;
  806. },
  807. checkboxDirty: function($el) {
  808. var initialValue = $el.data(metadata.defaultValue);
  809. var currentValue = $el.is(":checked");
  810. return initialValue !== currentValue;
  811. },
  812. justDirty: function() {
  813. return (history[0] === 'dirty');
  814. },
  815. justClean: function() {
  816. return (history[0] === 'clean');
  817. }
  818. },
  819. removeEvents: function() {
  820. $module.off(eventNamespace);
  821. $field.off(eventNamespace);
  822. $submit.off(eventNamespace);
  823. $field.off(eventNamespace);
  824. },
  825. event: {
  826. field: {
  827. keydown: function(event) {
  828. var
  829. $field = $(this),
  830. key = event.which,
  831. isInput = $field.is(selector.input),
  832. isCheckbox = $field.is(selector.checkbox),
  833. isInDropdown = ($field.closest(selector.uiDropdown).length > 0),
  834. keyCode = {
  835. enter : 13,
  836. escape : 27
  837. }
  838. ;
  839. if( key == keyCode.escape) {
  840. module.verbose('Escape key pressed blurring field');
  841. $field
  842. .blur()
  843. ;
  844. }
  845. if(!event.ctrlKey && key == keyCode.enter && isInput && !isInDropdown && !isCheckbox) {
  846. if(!keyHeldDown) {
  847. $field.one('keyup' + eventNamespace, module.event.field.keyup);
  848. module.submit();
  849. module.debug('Enter pressed on input submitting form');
  850. }
  851. keyHeldDown = true;
  852. }
  853. },
  854. keyup: function() {
  855. keyHeldDown = false;
  856. },
  857. blur: function(event) {
  858. var
  859. $field = $(this),
  860. $fieldGroup = $field.closest($group),
  861. validationRules = module.get.validation($field)
  862. ;
  863. if( $fieldGroup.hasClass(className.error) ) {
  864. module.debug('Revalidating field', $field, validationRules);
  865. if(validationRules) {
  866. module.validate.field( validationRules );
  867. }
  868. }
  869. else if(settings.on == 'blur') {
  870. if(validationRules) {
  871. module.validate.field( validationRules );
  872. }
  873. }
  874. },
  875. change: function(event) {
  876. var
  877. $field = $(this),
  878. $fieldGroup = $field.closest($group),
  879. validationRules = module.get.validation($field)
  880. ;
  881. if(validationRules && (settings.on == 'change' || ( $fieldGroup.hasClass(className.error) && settings.revalidate) )) {
  882. clearTimeout(module.timer);
  883. module.timer = setTimeout(function() {
  884. module.debug('Revalidating field', $field, module.get.validation($field));
  885. module.validate.field( validationRules );
  886. }, settings.delay);
  887. }
  888. }
  889. },
  890. beforeUnload: function(event) {
  891. if (module.is.dirty() && !submitting) {
  892. var event = event || window.event;
  893. // For modern browsers
  894. if (event) {
  895. event.returnValue = settings.text.leavingMessage;
  896. }
  897. // For olders...
  898. return settings.text.leavingMessage;
  899. }
  900. }
  901. },
  902. get: {
  903. ancillaryValue: function(rule) {
  904. if(!rule.type || (!rule.value && !module.is.bracketedRule(rule))) {
  905. return false;
  906. }
  907. return (rule.value !== undefined)
  908. ? rule.value
  909. : rule.type.match(settings.regExp.bracket)[1] + ''
  910. ;
  911. },
  912. ruleName: function(rule) {
  913. if( module.is.bracketedRule(rule) ) {
  914. return rule.type.replace(rule.type.match(settings.regExp.bracket)[0], '');
  915. }
  916. return rule.type;
  917. },
  918. changeEvent: function(type, $input) {
  919. if(type == 'checkbox' || type == 'radio' || type == 'hidden' || $input.is('select')) {
  920. return 'change';
  921. }
  922. else {
  923. return module.get.inputEvent();
  924. }
  925. },
  926. inputEvent: function() {
  927. return (document.createElement('input').oninput !== undefined)
  928. ? 'input'
  929. : (document.createElement('input').onpropertychange !== undefined)
  930. ? 'propertychange'
  931. : 'keyup'
  932. ;
  933. },
  934. fieldsFromShorthand: function(fields) {
  935. var
  936. fullFields = {}
  937. ;
  938. $.each(fields, function(name, rules) {
  939. if(typeof rules == 'string') {
  940. rules = [rules];
  941. }
  942. fullFields[name] = {
  943. rules: []
  944. };
  945. $.each(rules, function(index, rule) {
  946. fullFields[name].rules.push({ type: rule });
  947. });
  948. });
  949. return fullFields;
  950. },
  951. prompt: function(rule, field) {
  952. var
  953. ruleName = module.get.ruleName(rule),
  954. ancillary = module.get.ancillaryValue(rule),
  955. $field = module.get.field(field.identifier),
  956. value = $field.val(),
  957. prompt = $.isFunction(rule.prompt)
  958. ? rule.prompt(value)
  959. : rule.prompt || settings.prompt[ruleName] || settings.text.unspecifiedRule,
  960. requiresValue = (prompt.search('{value}') !== -1),
  961. requiresName = (prompt.search('{name}') !== -1),
  962. $label,
  963. name
  964. ;
  965. if(requiresValue) {
  966. prompt = prompt.replace('{value}', $field.val());
  967. }
  968. if(requiresName) {
  969. $label = $field.closest(selector.group).find('label').eq(0);
  970. name = ($label.length == 1)
  971. ? $label.text()
  972. : $field.prop('placeholder') || settings.text.unspecifiedField
  973. ;
  974. prompt = prompt.replace('{name}', name);
  975. }
  976. prompt = prompt.replace('{identifier}', field.identifier);
  977. prompt = prompt.replace('{ruleValue}', ancillary);
  978. if(!rule.prompt) {
  979. module.verbose('Using default validation prompt for type', prompt, ruleName);
  980. }
  981. return prompt;
  982. },
  983. settings: function() {
  984. if($.isPlainObject(parameters)) {
  985. var
  986. keys = Object.keys(parameters),
  987. isLegacySettings = (keys.length > 0)
  988. ? (parameters[keys[0]].identifier !== undefined && parameters[keys[0]].rules !== undefined)
  989. : false
  990. ;
  991. if(isLegacySettings) {
  992. // 1.x (ducktyped)
  993. settings = $.extend(true, {}, $.fn.form.settings, legacyParameters);
  994. validation = $.extend({}, $.fn.form.settings.defaults, parameters);
  995. module.error(settings.error.oldSyntax, element);
  996. module.verbose('Extending settings from legacy parameters', validation, settings);
  997. }
  998. else {
  999. // 2.x
  1000. if(parameters.fields && module.is.shorthandFields(parameters.fields)) {
  1001. parameters.fields = module.get.fieldsFromShorthand(parameters.fields);
  1002. }
  1003. settings = $.extend(true, {}, $.fn.form.settings, parameters);
  1004. validation = $.extend({}, $.fn.form.settings.defaults, settings.fields);
  1005. module.verbose('Extending settings', validation, settings);
  1006. }
  1007. }
  1008. else {
  1009. settings = $.fn.form.settings;
  1010. validation = $.fn.form.settings.defaults;
  1011. module.verbose('Using default form validation', validation, settings);
  1012. }
  1013. // shorthand
  1014. namespace = settings.namespace;
  1015. metadata = settings.metadata;
  1016. selector = settings.selector;
  1017. className = settings.className;
  1018. regExp = settings.regExp;
  1019. error = settings.error;
  1020. moduleNamespace = 'module-' + namespace;
  1021. eventNamespace = '.' + namespace;
  1022. // grab instance
  1023. instance = $module.data(moduleNamespace);
  1024. // refresh selector cache
  1025. module.refresh();
  1026. },
  1027. field: function(identifier) {
  1028. module.verbose('Finding field with identifier', identifier);
  1029. identifier = module.escape.string(identifier);
  1030. var t;
  1031. if((t=$field.filter('#' + identifier)).length > 0 ) {
  1032. return t;
  1033. }
  1034. if((t=$field.filter('[name="' + identifier +'"]')).length > 0 ) {
  1035. return t;
  1036. }
  1037. if((t=$field.filter('[name="' + identifier +'[]"]')).length > 0 ) {
  1038. return t;
  1039. }
  1040. if((t=$field.filter('[data-' + metadata.validate + '="'+ identifier +'"]')).length > 0 ) {
  1041. return t;
  1042. }
  1043. return $('<input/>');
  1044. },
  1045. fields: function(fields) {
  1046. var
  1047. $fields = $()
  1048. ;
  1049. $.each(fields, function(index, name) {
  1050. $fields = $fields.add( module.get.field(name) );
  1051. });
  1052. return $fields;
  1053. },
  1054. validation: function($field) {
  1055. var
  1056. fieldValidation,
  1057. identifier
  1058. ;
  1059. if(!validation) {
  1060. return false;
  1061. }
  1062. $.each(validation, function(fieldName, field) {
  1063. identifier = field.identifier || fieldName;
  1064. $.each(module.get.field(identifier), function(index, groupField) {
  1065. if(groupField == $field[0]) {
  1066. field.identifier = identifier;
  1067. fieldValidation = field;
  1068. return false;
  1069. }
  1070. });
  1071. });
  1072. return fieldValidation || false;
  1073. },
  1074. value: function (field) {
  1075. var
  1076. fields = [],
  1077. results
  1078. ;
  1079. fields.push(field);
  1080. results = module.get.values.call(element, fields);
  1081. return results[field];
  1082. },
  1083. values: function (fields) {
  1084. var
  1085. $fields = Array.isArray(fields)
  1086. ? module.get.fields(fields)
  1087. : $field,
  1088. values = {}
  1089. ;
  1090. $fields.each(function(index, field) {
  1091. var
  1092. $field = $(field),
  1093. $calendar = $field.closest(selector.uiCalendar),
  1094. name = $field.prop('name'),
  1095. value = $field.val(),
  1096. isCheckbox = $field.is(selector.checkbox),
  1097. isRadio = $field.is(selector.radio),
  1098. isMultiple = (name.indexOf('[]') !== -1),
  1099. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  1100. isChecked = (isCheckbox)
  1101. ? $field.is(':checked')
  1102. : false
  1103. ;
  1104. if(name) {
  1105. if(isMultiple) {
  1106. name = name.replace('[]', '');
  1107. if(!values[name]) {
  1108. values[name] = [];
  1109. }
  1110. if(isCheckbox) {
  1111. if(isChecked) {
  1112. values[name].push(value || true);
  1113. }
  1114. else {
  1115. values[name].push(false);
  1116. }
  1117. }
  1118. else {
  1119. values[name].push(value);
  1120. }
  1121. }
  1122. else {
  1123. if(isRadio) {
  1124. if(values[name] === undefined || values[name] == false) {
  1125. values[name] = (isChecked)
  1126. ? value || true
  1127. : false
  1128. ;
  1129. }
  1130. }
  1131. else if(isCheckbox) {
  1132. if(isChecked) {
  1133. values[name] = value || true;
  1134. }
  1135. else {
  1136. values[name] = false;
  1137. }
  1138. }
  1139. else if(isCalendar) {
  1140. var date = $calendar.calendar('get date');
  1141. if (date !== null) {
  1142. if (settings.dateHandling == 'date') {
  1143. values[name] = date;
  1144. } else if(settings.dateHandling == 'input') {
  1145. values[name] = $calendar.calendar('get input date')
  1146. } else if (settings.dateHandling == 'formatter') {
  1147. var type = $calendar.calendar('setting', 'type');
  1148. switch(type) {
  1149. case 'date':
  1150. values[name] = settings.formatter.date(date);
  1151. break;
  1152. case 'datetime':
  1153. values[name] = settings.formatter.datetime(date);
  1154. break;
  1155. case 'time':
  1156. values[name] = settings.formatter.time(date);
  1157. break;
  1158. case 'month':
  1159. values[name] = settings.formatter.month(date);
  1160. break;
  1161. case 'year':
  1162. values[name] = settings.formatter.year(date);
  1163. break;
  1164. default:
  1165. module.debug('Wrong calendar mode', $calendar, type);
  1166. values[name] = '';
  1167. }
  1168. }
  1169. } else {
  1170. values[name] = '';
  1171. }
  1172. } else {
  1173. values[name] = value;
  1174. }
  1175. }
  1176. }
  1177. });
  1178. return values;
  1179. },
  1180. dirtyFields: function() {
  1181. return $field.filter(function(index, e) {
  1182. return $(e).data(metadata.isDirty);
  1183. });
  1184. }
  1185. },
  1186. has: {
  1187. field: function(identifier) {
  1188. module.verbose('Checking for existence of a field with identifier', identifier);
  1189. identifier = module.escape.string(identifier);
  1190. if(typeof identifier !== 'string') {
  1191. module.error(error.identifier, identifier);
  1192. }
  1193. if($field.filter('#' + identifier).length > 0 ) {
  1194. return true;
  1195. }
  1196. else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
  1197. return true;
  1198. }
  1199. else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
  1200. return true;
  1201. }
  1202. return false;
  1203. }
  1204. },
  1205. can: {
  1206. useElement: function(element){
  1207. if ($.fn[element] !== undefined) {
  1208. return true;
  1209. }
  1210. module.error(error.noElement.replace('{element}',element));
  1211. return false;
  1212. }
  1213. },
  1214. escape: {
  1215. string: function(text) {
  1216. text = String(text);
  1217. return text.replace(regExp.escape, '\\$&');
  1218. }
  1219. },
  1220. add: {
  1221. // alias
  1222. rule: function(name, rules) {
  1223. module.add.field(name, rules);
  1224. },
  1225. field: function(name, rules) {
  1226. var
  1227. newValidation = {}
  1228. ;
  1229. if(module.is.shorthandRules(rules)) {
  1230. rules = Array.isArray(rules)
  1231. ? rules
  1232. : [rules]
  1233. ;
  1234. newValidation[name] = {
  1235. rules: []
  1236. };
  1237. $.each(rules, function(index, rule) {
  1238. newValidation[name].rules.push({ type: rule });
  1239. });
  1240. }
  1241. else {
  1242. newValidation[name] = rules;
  1243. }
  1244. validation = $.extend({}, validation, newValidation);
  1245. module.debug('Adding rules', newValidation, validation);
  1246. },
  1247. fields: function(fields) {
  1248. var
  1249. newValidation
  1250. ;
  1251. if(fields && module.is.shorthandFields(fields)) {
  1252. newValidation = module.get.fieldsFromShorthand(fields);
  1253. }
  1254. else {
  1255. newValidation = fields;
  1256. }
  1257. validation = $.extend({}, validation, newValidation);
  1258. },
  1259. prompt: function(identifier, errors, internal) {
  1260. var
  1261. $field = module.get.field(identifier),
  1262. $fieldGroup = $field.closest($group),
  1263. $prompt = $fieldGroup.children(selector.prompt),
  1264. promptExists = ($prompt.length !== 0)
  1265. ;
  1266. errors = (typeof errors == 'string')
  1267. ? [errors]
  1268. : errors
  1269. ;
  1270. module.verbose('Adding field error state', identifier);
  1271. if(!internal) {
  1272. $fieldGroup
  1273. .addClass(className.error)
  1274. ;
  1275. }
  1276. if(settings.inline) {
  1277. if(!promptExists) {
  1278. $prompt = settings.templates.prompt(errors, className.label);
  1279. $prompt
  1280. .appendTo($fieldGroup)
  1281. ;
  1282. }
  1283. $prompt
  1284. .html(errors[0])
  1285. ;
  1286. if(!promptExists) {
  1287. if(settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
  1288. module.verbose('Displaying error with css transition', settings.transition);
  1289. $prompt.transition(settings.transition + ' in', settings.duration);
  1290. }
  1291. else {
  1292. module.verbose('Displaying error with fallback javascript animation');
  1293. $prompt
  1294. .fadeIn(settings.duration)
  1295. ;
  1296. }
  1297. }
  1298. else {
  1299. module.verbose('Inline errors are disabled, no inline error added', identifier);
  1300. }
  1301. }
  1302. },
  1303. errors: function(errors) {
  1304. module.debug('Adding form error messages', errors);
  1305. module.set.error();
  1306. $message
  1307. .html( settings.templates.error(errors) )
  1308. ;
  1309. }
  1310. },
  1311. remove: {
  1312. rule: function(field, rule) {
  1313. var
  1314. rules = Array.isArray(rule)
  1315. ? rule
  1316. : [rule]
  1317. ;
  1318. if(validation[field] === undefined || !Array.isArray(validation[field].rules)) {
  1319. return;
  1320. }
  1321. if(rule === undefined) {
  1322. module.debug('Removed all rules');
  1323. validation[field].rules = [];
  1324. return;
  1325. }
  1326. $.each(validation[field].rules, function(index, rule) {
  1327. if(rule && rules.indexOf(rule.type) !== -1) {
  1328. module.debug('Removed rule', rule.type);
  1329. validation[field].rules.splice(index, 1);
  1330. }
  1331. });
  1332. },
  1333. field: function(field) {
  1334. var
  1335. fields = Array.isArray(field)
  1336. ? field
  1337. : [field]
  1338. ;
  1339. $.each(fields, function(index, field) {
  1340. module.remove.rule(field);
  1341. });
  1342. },
  1343. // alias
  1344. rules: function(field, rules) {
  1345. if(Array.isArray(field)) {
  1346. $.each(field, function(index, field) {
  1347. module.remove.rule(field, rules);
  1348. });
  1349. }
  1350. else {
  1351. module.remove.rule(field, rules);
  1352. }
  1353. },
  1354. fields: function(fields) {
  1355. module.remove.field(fields);
  1356. },
  1357. prompt: function(identifier) {
  1358. var
  1359. $field = module.get.field(identifier),
  1360. $fieldGroup = $field.closest($group),
  1361. $prompt = $fieldGroup.children(selector.prompt)
  1362. ;
  1363. $fieldGroup
  1364. .removeClass(className.error)
  1365. ;
  1366. if(settings.inline && $prompt.is(':visible')) {
  1367. module.verbose('Removing prompt for field', identifier);
  1368. if(settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
  1369. $prompt.transition(settings.transition + ' out', settings.duration, function() {
  1370. $prompt.remove();
  1371. });
  1372. }
  1373. else {
  1374. $prompt
  1375. .fadeOut(settings.duration, function(){
  1376. $prompt.remove();
  1377. })
  1378. ;
  1379. }
  1380. }
  1381. }
  1382. },
  1383. set: {
  1384. success: function() {
  1385. $module
  1386. .removeClass(className.error)
  1387. .addClass(className.success)
  1388. ;
  1389. },
  1390. defaults: function () {
  1391. $field.each(function (index, el) {
  1392. var
  1393. $el = $(el),
  1394. $parent = $el.parent(),
  1395. isCheckbox = ($el.filter(selector.checkbox).length > 0),
  1396. isDropdown = $parent.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  1397. value = (isCheckbox)
  1398. ? $el.is(':checked')
  1399. : $el.val()
  1400. ;
  1401. if (isDropdown) {
  1402. $parent.dropdown('save defaults');
  1403. }
  1404. $el.data(metadata.defaultValue, value);
  1405. $el.data(metadata.isDirty, false);
  1406. });
  1407. },
  1408. error: function() {
  1409. $module
  1410. .removeClass(className.success)
  1411. .addClass(className.error)
  1412. ;
  1413. },
  1414. value: function (field, value) {
  1415. var
  1416. fields = {}
  1417. ;
  1418. fields[field] = value;
  1419. return module.set.values.call(element, fields);
  1420. },
  1421. values: function (fields) {
  1422. if($.isEmptyObject(fields)) {
  1423. return;
  1424. }
  1425. $.each(fields, function(key, value) {
  1426. var
  1427. $field = module.get.field(key),
  1428. $element = $field.parent(),
  1429. $calendar = $field.closest(selector.uiCalendar),
  1430. isMultiple = Array.isArray(value),
  1431. isCheckbox = $element.is(selector.uiCheckbox) && module.can.useElement('checkbox'),
  1432. isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  1433. isRadio = ($field.is(selector.radio) && isCheckbox),
  1434. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  1435. fieldExists = ($field.length > 0),
  1436. $multipleField
  1437. ;
  1438. if(fieldExists) {
  1439. if(isMultiple && isCheckbox) {
  1440. module.verbose('Selecting multiple', value, $field);
  1441. $element.checkbox('uncheck');
  1442. $.each(value, function(index, value) {
  1443. $multipleField = $field.filter('[value="' + value + '"]');
  1444. $element = $multipleField.parent();
  1445. if($multipleField.length > 0) {
  1446. $element.checkbox('check');
  1447. }
  1448. });
  1449. }
  1450. else if(isRadio) {
  1451. module.verbose('Selecting radio value', value, $field);
  1452. $field.filter('[value="' + value + '"]')
  1453. .parent(selector.uiCheckbox)
  1454. .checkbox('check')
  1455. ;
  1456. }
  1457. else if(isCheckbox) {
  1458. module.verbose('Setting checkbox value', value, $element);
  1459. if(value === true) {
  1460. $element.checkbox('check');
  1461. }
  1462. else {
  1463. $element.checkbox('uncheck');
  1464. }
  1465. }
  1466. else if(isDropdown) {
  1467. module.verbose('Setting dropdown value', value, $element);
  1468. $element.dropdown('set selected', value);
  1469. }
  1470. else if (isCalendar) {
  1471. $calendar.calendar('set date',value);
  1472. }
  1473. else {
  1474. module.verbose('Setting field value', value, $field);
  1475. $field.val(value);
  1476. }
  1477. }
  1478. });
  1479. },
  1480. dirty: function() {
  1481. module.verbose('Setting state dirty');
  1482. dirty = true;
  1483. history[0] = history[1];
  1484. history[1] = 'dirty';
  1485. if (module.is.justClean()) {
  1486. $module.trigger('dirty');
  1487. }
  1488. },
  1489. clean: function() {
  1490. module.verbose('Setting state clean');
  1491. dirty = false;
  1492. history[0] = history[1];
  1493. history[1] = 'clean';
  1494. if (module.is.justDirty()) {
  1495. $module.trigger('clean');
  1496. }
  1497. },
  1498. asClean: function() {
  1499. module.set.defaults();
  1500. module.set.clean();
  1501. },
  1502. asDirty: function() {
  1503. module.set.defaults();
  1504. module.set.dirty();
  1505. }
  1506. },
  1507. validate: {
  1508. form: function(event, ignoreCallbacks) {
  1509. var values = module.get.values();
  1510. // input keydown event will fire submit repeatedly by browser default
  1511. if(keyHeldDown) {
  1512. return false;
  1513. }
  1514. // reset errors
  1515. formErrors = [];
  1516. if( module.determine.isValid() ) {
  1517. module.debug('Form has no validation errors, submitting');
  1518. module.set.success();
  1519. if(ignoreCallbacks !== true) {
  1520. return settings.onSuccess.call(element, event, values);
  1521. }
  1522. }
  1523. else {
  1524. module.debug('Form has errors');
  1525. module.set.error();
  1526. if(!settings.inline) {
  1527. module.add.errors(formErrors);
  1528. }
  1529. // prevent ajax submit
  1530. if(event && $module.data('moduleApi') !== undefined) {
  1531. event.stopImmediatePropagation();
  1532. }
  1533. if(ignoreCallbacks !== true) {
  1534. return settings.onFailure.call(element, formErrors, values);
  1535. }
  1536. }
  1537. },
  1538. // takes a validation object and returns whether field passes validation
  1539. field: function(field, fieldName, showErrors) {
  1540. showErrors = (showErrors !== undefined)
  1541. ? showErrors
  1542. : true
  1543. ;
  1544. if(typeof field == 'string') {
  1545. module.verbose('Validating field', field);
  1546. fieldName = field;
  1547. field = validation[field];
  1548. }
  1549. var
  1550. identifier = field.identifier || fieldName,
  1551. $field = module.get.field(identifier),
  1552. $dependsField = (field.depends)
  1553. ? module.get.field(field.depends)
  1554. : false,
  1555. fieldValid = true,
  1556. fieldErrors = []
  1557. ;
  1558. if(!field.identifier) {
  1559. module.debug('Using field name as identifier', identifier);
  1560. field.identifier = identifier;
  1561. }
  1562. var isDisabled = true;
  1563. $.each($field, function(){
  1564. if(!$(this).prop('disabled')) {
  1565. isDisabled = false;
  1566. return false;
  1567. }
  1568. });
  1569. if(isDisabled) {
  1570. module.debug('Field is disabled. Skipping', identifier);
  1571. }
  1572. else if(field.optional && module.is.blank($field)){
  1573. module.debug('Field is optional and blank. Skipping', identifier);
  1574. }
  1575. else if(field.depends && module.is.empty($dependsField)) {
  1576. module.debug('Field depends on another value that is not present or empty. Skipping', $dependsField);
  1577. }
  1578. else if(field.rules !== undefined) {
  1579. $field.closest($group).removeClass(className.error);
  1580. $.each(field.rules, function(index, rule) {
  1581. if( module.has.field(identifier)) {
  1582. var invalidFields = module.validate.rule(field, rule,true) || [];
  1583. if (invalidFields.length>0){
  1584. module.debug('Field is invalid', identifier, rule.type);
  1585. fieldErrors.push(module.get.prompt(rule, field));
  1586. fieldValid = false;
  1587. if(showErrors){
  1588. $(invalidFields).closest($group).addClass(className.error);
  1589. }
  1590. }
  1591. }
  1592. });
  1593. }
  1594. if(fieldValid) {
  1595. if(showErrors) {
  1596. module.remove.prompt(identifier, fieldErrors);
  1597. settings.onValid.call($field);
  1598. }
  1599. }
  1600. else {
  1601. if(showErrors) {
  1602. formErrors = formErrors.concat(fieldErrors);
  1603. module.add.prompt(identifier, fieldErrors, true);
  1604. settings.onInvalid.call($field, fieldErrors);
  1605. }
  1606. return false;
  1607. }
  1608. return true;
  1609. },
  1610. // takes validation rule and returns whether field passes rule
  1611. rule: function(field, rule, internal) {
  1612. var
  1613. $field = module.get.field(field.identifier),
  1614. ancillary = module.get.ancillaryValue(rule),
  1615. ruleName = module.get.ruleName(rule),
  1616. ruleFunction = settings.rules[ruleName],
  1617. invalidFields = [],
  1618. isCheckbox = $field.is(selector.checkbox),
  1619. isValid = function(field){
  1620. var value = (isCheckbox ? $(field).filter(':checked').val() : $(field).val());
  1621. // cast to string avoiding encoding special values
  1622. value = (value === undefined || value === '' || value === null)
  1623. ? ''
  1624. : (settings.shouldTrim) ? $.trim(value + '') : String(value + '')
  1625. ;
  1626. return ruleFunction.call(field, value, ancillary, $module);
  1627. }
  1628. ;
  1629. if( !$.isFunction(ruleFunction) ) {
  1630. module.error(error.noRule, ruleName);
  1631. return;
  1632. }
  1633. if(isCheckbox) {
  1634. if (!isValid($field)) {
  1635. invalidFields = $field;
  1636. }
  1637. } else {
  1638. $.each($field, function (index, field) {
  1639. if (!isValid(field)) {
  1640. invalidFields.push(field);
  1641. }
  1642. });
  1643. }
  1644. return internal ? invalidFields : !(invalidFields.length>0);
  1645. }
  1646. },
  1647. setting: function(name, value) {
  1648. if( $.isPlainObject(name) ) {
  1649. $.extend(true, settings, name);
  1650. }
  1651. else if(value !== undefined) {
  1652. settings[name] = value;
  1653. }
  1654. else {
  1655. return settings[name];
  1656. }
  1657. },
  1658. internal: function(name, value) {
  1659. if( $.isPlainObject(name) ) {
  1660. $.extend(true, module, name);
  1661. }
  1662. else if(value !== undefined) {
  1663. module[name] = value;
  1664. }
  1665. else {
  1666. return module[name];
  1667. }
  1668. },
  1669. debug: function() {
  1670. if(!settings.silent && settings.debug) {
  1671. if(settings.performance) {
  1672. module.performance.log(arguments);
  1673. }
  1674. else {
  1675. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1676. module.debug.apply(console, arguments);
  1677. }
  1678. }
  1679. },
  1680. verbose: function() {
  1681. if(!settings.silent && settings.verbose && settings.debug) {
  1682. if(settings.performance) {
  1683. module.performance.log(arguments);
  1684. }
  1685. else {
  1686. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1687. module.verbose.apply(console, arguments);
  1688. }
  1689. }
  1690. },
  1691. error: function() {
  1692. if(!settings.silent) {
  1693. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  1694. module.error.apply(console, arguments);
  1695. }
  1696. },
  1697. performance: {
  1698. log: function(message) {
  1699. var
  1700. currentTime,
  1701. executionTime,
  1702. previousTime
  1703. ;
  1704. if(settings.performance) {
  1705. currentTime = new Date().getTime();
  1706. previousTime = time || currentTime;
  1707. executionTime = currentTime - previousTime;
  1708. time = currentTime;
  1709. performance.push({
  1710. 'Name' : message[0],
  1711. 'Arguments' : [].slice.call(message, 1) || '',
  1712. 'Element' : element,
  1713. 'Execution Time' : executionTime
  1714. });
  1715. }
  1716. clearTimeout(module.performance.timer);
  1717. module.performance.timer = setTimeout(module.performance.display, 500);
  1718. },
  1719. display: function() {
  1720. var
  1721. title = settings.name + ':',
  1722. totalTime = 0
  1723. ;
  1724. time = false;
  1725. clearTimeout(module.performance.timer);
  1726. $.each(performance, function(index, data) {
  1727. totalTime += data['Execution Time'];
  1728. });
  1729. title += ' ' + totalTime + 'ms';
  1730. if(moduleSelector) {
  1731. title += ' \'' + moduleSelector + '\'';
  1732. }
  1733. if($allModules.length > 1) {
  1734. title += ' ' + '(' + $allModules.length + ')';
  1735. }
  1736. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  1737. console.groupCollapsed(title);
  1738. if(console.table) {
  1739. console.table(performance);
  1740. }
  1741. else {
  1742. $.each(performance, function(index, data) {
  1743. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  1744. });
  1745. }
  1746. console.groupEnd();
  1747. }
  1748. performance = [];
  1749. }
  1750. },
  1751. invoke: function(query, passedArguments, context) {
  1752. var
  1753. object = instance,
  1754. maxDepth,
  1755. found,
  1756. response
  1757. ;
  1758. passedArguments = passedArguments || queryArguments;
  1759. context = element || context;
  1760. if(typeof query == 'string' && object !== undefined) {
  1761. query = query.split(/[\. ]/);
  1762. maxDepth = query.length - 1;
  1763. $.each(query, function(depth, value) {
  1764. var camelCaseValue = (depth != maxDepth)
  1765. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  1766. : query
  1767. ;
  1768. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  1769. object = object[camelCaseValue];
  1770. }
  1771. else if( object[camelCaseValue] !== undefined ) {
  1772. found = object[camelCaseValue];
  1773. return false;
  1774. }
  1775. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  1776. object = object[value];
  1777. }
  1778. else if( object[value] !== undefined ) {
  1779. found = object[value];
  1780. return false;
  1781. }
  1782. else {
  1783. return false;
  1784. }
  1785. });
  1786. }
  1787. if( $.isFunction( found ) ) {
  1788. response = found.apply(context, passedArguments);
  1789. }
  1790. else if(found !== undefined) {
  1791. response = found;
  1792. }
  1793. if(Array.isArray(returnedValue)) {
  1794. returnedValue.push(response);
  1795. }
  1796. else if(returnedValue !== undefined) {
  1797. returnedValue = [returnedValue, response];
  1798. }
  1799. else if(response !== undefined) {
  1800. returnedValue = response;
  1801. }
  1802. return found;
  1803. }
  1804. };
  1805. module.initialize();
  1806. })
  1807. ;
  1808. return (returnedValue !== undefined)
  1809. ? returnedValue
  1810. : this
  1811. ;
  1812. };
  1813. $.fn.form.settings = {
  1814. name : 'Form',
  1815. namespace : 'form',
  1816. debug : false,
  1817. verbose : false,
  1818. performance : true,
  1819. fields : false,
  1820. keyboardShortcuts : true,
  1821. on : 'submit',
  1822. inline : false,
  1823. delay : 200,
  1824. revalidate : true,
  1825. shouldTrim : true,
  1826. transition : 'scale',
  1827. duration : 200,
  1828. preventLeaving : false,
  1829. dateHandling : 'date', // 'date', 'input', 'formatter'
  1830. onValid : function() {},
  1831. onInvalid : function() {},
  1832. onSuccess : function() { return true; },
  1833. onFailure : function() { return false; },
  1834. onDirty : function() {},
  1835. onClean : function() {},
  1836. metadata : {
  1837. defaultValue : 'default',
  1838. validate : 'validate',
  1839. isDirty : 'isDirty'
  1840. },
  1841. regExp: {
  1842. htmlID : /^[a-zA-Z][\w:.-]*$/g,
  1843. bracket : /\[(.*)\]/i,
  1844. decimal : /^\d+\.?\d*$/,
  1845. email : /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,
  1846. escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|:,=@]/g,
  1847. flags : /^\/(.*)\/(.*)?/,
  1848. integer : /^\-?\d+$/,
  1849. number : /^\-?\d*(\.\d+)?$/,
  1850. url : /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/i
  1851. },
  1852. text: {
  1853. unspecifiedRule : 'Please enter a valid value',
  1854. unspecifiedField : 'This field',
  1855. leavingMessage : 'There are unsaved changes on this page which will be discarded if you continue.'
  1856. },
  1857. prompt: {
  1858. empty : '{name} must have a value',
  1859. checked : '{name} must be checked',
  1860. email : '{name} must be a valid e-mail',
  1861. url : '{name} must be a valid url',
  1862. regExp : '{name} is not formatted correctly',
  1863. integer : '{name} must be an integer',
  1864. decimal : '{name} must be a decimal number',
  1865. number : '{name} must be set to a number',
  1866. is : '{name} must be "{ruleValue}"',
  1867. isExactly : '{name} must be exactly "{ruleValue}"',
  1868. not : '{name} cannot be set to "{ruleValue}"',
  1869. notExactly : '{name} cannot be set to exactly "{ruleValue}"',
  1870. contain : '{name} must contain "{ruleValue}"',
  1871. containExactly : '{name} must contain exactly "{ruleValue}"',
  1872. doesntContain : '{name} cannot contain "{ruleValue}"',
  1873. doesntContainExactly : '{name} cannot contain exactly "{ruleValue}"',
  1874. minLength : '{name} must be at least {ruleValue} characters',
  1875. length : '{name} must be at least {ruleValue} characters',
  1876. exactLength : '{name} must be exactly {ruleValue} characters',
  1877. maxLength : '{name} cannot be longer than {ruleValue} characters',
  1878. match : '{name} must match {ruleValue} field',
  1879. different : '{name} must have a different value than {ruleValue} field',
  1880. creditCard : '{name} must be a valid credit card number',
  1881. minCount : '{name} must have at least {ruleValue} choices',
  1882. exactCount : '{name} must have exactly {ruleValue} choices',
  1883. maxCount : '{name} must have {ruleValue} or less choices'
  1884. },
  1885. selector : {
  1886. checkbox : 'input[type="checkbox"], input[type="radio"]',
  1887. clear : '.clear',
  1888. field : 'input, textarea, select',
  1889. group : '.field',
  1890. input : 'input',
  1891. message : '.error.message',
  1892. prompt : '.prompt.label',
  1893. radio : 'input[type="radio"]',
  1894. reset : '.reset:not([type="reset"])',
  1895. submit : '.submit:not([type="submit"])',
  1896. uiCheckbox : '.ui.checkbox',
  1897. uiDropdown : '.ui.dropdown',
  1898. uiCalendar : '.ui.calendar'
  1899. },
  1900. className : {
  1901. error : 'error',
  1902. label : 'ui basic red pointing prompt label',
  1903. pressed : 'down',
  1904. success : 'success'
  1905. },
  1906. error: {
  1907. identifier : 'You must specify a string identifier for each field',
  1908. method : 'The method you called is not defined.',
  1909. noRule : 'There is no rule matching the one you specified',
  1910. oldSyntax : 'Starting in 2.0 forms now only take a single settings object. Validation settings converted to new syntax automatically.',
  1911. noElement : 'This module requires ui {element}'
  1912. },
  1913. templates: {
  1914. // template that produces error message
  1915. error: function(errors) {
  1916. var
  1917. html = '<ul class="list">'
  1918. ;
  1919. $.each(errors, function(index, value) {
  1920. html += '<li>' + value + '</li>';
  1921. });
  1922. html += '</ul>';
  1923. return $(html);
  1924. },
  1925. // template that produces label
  1926. prompt: function(errors, labelClasses) {
  1927. return $('<div/>')
  1928. .addClass(labelClasses)
  1929. .html(errors[0])
  1930. ;
  1931. }
  1932. },
  1933. formatter: {
  1934. date: function(date) {
  1935. return Intl.DateTimeFormat('en-GB').format(date);
  1936. },
  1937. datetime: function(date) {
  1938. return Intl.DateTimeFormat('en-GB', {
  1939. year: "numeric",
  1940. month: "2-digit",
  1941. day: "2-digit",
  1942. hour: '2-digit',
  1943. minute: '2-digit',
  1944. second: '2-digit'
  1945. }).format(date);
  1946. },
  1947. time: function(date) {
  1948. return Intl.DateTimeFormat('en-GB', {
  1949. hour: '2-digit',
  1950. minute: '2-digit',
  1951. second: '2-digit'
  1952. }).format(date);
  1953. },
  1954. month: function(date) {
  1955. return Intl.DateTimeFormat('en-GB', {
  1956. month: '2-digit',
  1957. year: 'numeric'
  1958. }).format(date);
  1959. },
  1960. year: function(date) {
  1961. return Intl.DateTimeFormat('en-GB', {
  1962. year: 'numeric'
  1963. }).format(date);
  1964. }
  1965. },
  1966. rules: {
  1967. // is not empty or blank string
  1968. empty: function(value) {
  1969. return !(value === undefined || '' === value || Array.isArray(value) && value.length === 0);
  1970. },
  1971. // checkbox checked
  1972. checked: function() {
  1973. return ($(this).filter(':checked').length > 0);
  1974. },
  1975. // is most likely an email
  1976. email: function(value){
  1977. return $.fn.form.settings.regExp.email.test(value);
  1978. },
  1979. // value is most likely url
  1980. url: function(value) {
  1981. return $.fn.form.settings.regExp.url.test(value);
  1982. },
  1983. // matches specified regExp
  1984. regExp: function(value, regExp) {
  1985. if(regExp instanceof RegExp) {
  1986. return value.match(regExp);
  1987. }
  1988. var
  1989. regExpParts = regExp.match($.fn.form.settings.regExp.flags),
  1990. flags
  1991. ;
  1992. // regular expression specified as /baz/gi (flags)
  1993. if(regExpParts) {
  1994. regExp = (regExpParts.length >= 2)
  1995. ? regExpParts[1]
  1996. : regExp
  1997. ;
  1998. flags = (regExpParts.length >= 3)
  1999. ? regExpParts[2]
  2000. : ''
  2001. ;
  2002. }
  2003. return value.match( new RegExp(regExp, flags) );
  2004. },
  2005. // is valid integer or matches range
  2006. integer: function(value, range) {
  2007. var
  2008. intRegExp = $.fn.form.settings.regExp.integer,
  2009. min,
  2010. max,
  2011. parts
  2012. ;
  2013. if( !range || ['', '..'].indexOf(range) !== -1) {
  2014. // do nothing
  2015. }
  2016. else if(range.indexOf('..') == -1) {
  2017. if(intRegExp.test(range)) {
  2018. min = max = range - 0;
  2019. }
  2020. }
  2021. else {
  2022. parts = range.split('..', 2);
  2023. if(intRegExp.test(parts[0])) {
  2024. min = parts[0] - 0;
  2025. }
  2026. if(intRegExp.test(parts[1])) {
  2027. max = parts[1] - 0;
  2028. }
  2029. }
  2030. return (
  2031. intRegExp.test(value) &&
  2032. (min === undefined || value >= min) &&
  2033. (max === undefined || value <= max)
  2034. );
  2035. },
  2036. // is valid number (with decimal)
  2037. decimal: function(value) {
  2038. return $.fn.form.settings.regExp.decimal.test(value);
  2039. },
  2040. // is valid number
  2041. number: function(value) {
  2042. return $.fn.form.settings.regExp.number.test(value);
  2043. },
  2044. // is value (case insensitive)
  2045. is: function(value, text) {
  2046. text = (typeof text == 'string')
  2047. ? text.toLowerCase()
  2048. : text
  2049. ;
  2050. value = (typeof value == 'string')
  2051. ? value.toLowerCase()
  2052. : value
  2053. ;
  2054. return (value == text);
  2055. },
  2056. // is value
  2057. isExactly: function(value, text) {
  2058. return (value == text);
  2059. },
  2060. // value is not another value (case insensitive)
  2061. not: function(value, notValue) {
  2062. value = (typeof value == 'string')
  2063. ? value.toLowerCase()
  2064. : value
  2065. ;
  2066. notValue = (typeof notValue == 'string')
  2067. ? notValue.toLowerCase()
  2068. : notValue
  2069. ;
  2070. return (value != notValue);
  2071. },
  2072. // value is not another value (case sensitive)
  2073. notExactly: function(value, notValue) {
  2074. return (value != notValue);
  2075. },
  2076. // value contains text (insensitive)
  2077. contains: function(value, text) {
  2078. // escape regex characters
  2079. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  2080. return (value.search( new RegExp(text, 'i') ) !== -1);
  2081. },
  2082. // value contains text (case sensitive)
  2083. containsExactly: function(value, text) {
  2084. // escape regex characters
  2085. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  2086. return (value.search( new RegExp(text) ) !== -1);
  2087. },
  2088. // value contains text (insensitive)
  2089. doesntContain: function(value, text) {
  2090. // escape regex characters
  2091. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  2092. return (value.search( new RegExp(text, 'i') ) === -1);
  2093. },
  2094. // value contains text (case sensitive)
  2095. doesntContainExactly: function(value, text) {
  2096. // escape regex characters
  2097. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  2098. return (value.search( new RegExp(text) ) === -1);
  2099. },
  2100. // is at least string length
  2101. minLength: function(value, requiredLength) {
  2102. return (value !== undefined)
  2103. ? (value.length >= requiredLength)
  2104. : false
  2105. ;
  2106. },
  2107. // see rls notes for 2.0.6 (this is a duplicate of minLength)
  2108. length: function(value, requiredLength) {
  2109. return (value !== undefined)
  2110. ? (value.length >= requiredLength)
  2111. : false
  2112. ;
  2113. },
  2114. // is exactly length
  2115. exactLength: function(value, requiredLength) {
  2116. return (value !== undefined)
  2117. ? (value.length == requiredLength)
  2118. : false
  2119. ;
  2120. },
  2121. // is less than length
  2122. maxLength: function(value, maxLength) {
  2123. return (value !== undefined)
  2124. ? (value.length <= maxLength)
  2125. : false
  2126. ;
  2127. },
  2128. // matches another field
  2129. match: function(value, identifier, $module) {
  2130. var
  2131. matchingValue,
  2132. matchingElement
  2133. ;
  2134. if((matchingElement = $module.find('[data-validate="'+ identifier +'"]')).length > 0 ) {
  2135. matchingValue = matchingElement.val();
  2136. }
  2137. else if((matchingElement = $module.find('#' + identifier)).length > 0) {
  2138. matchingValue = matchingElement.val();
  2139. }
  2140. else if((matchingElement = $module.find('[name="' + identifier +'"]')).length > 0) {
  2141. matchingValue = matchingElement.val();
  2142. }
  2143. else if((matchingElement = $module.find('[name="' + identifier +'[]"]')).length > 0 ) {
  2144. matchingValue = matchingElement;
  2145. }
  2146. return (matchingValue !== undefined)
  2147. ? ( value.toString() == matchingValue.toString() )
  2148. : false
  2149. ;
  2150. },
  2151. // different than another field
  2152. different: function(value, identifier, $module) {
  2153. // use either id or name of field
  2154. var
  2155. matchingValue,
  2156. matchingElement
  2157. ;
  2158. if((matchingElement = $module.find('[data-validate="'+ identifier +'"]')).length > 0 ) {
  2159. matchingValue = matchingElement.val();
  2160. }
  2161. else if((matchingElement = $module.find('#' + identifier)).length > 0) {
  2162. matchingValue = matchingElement.val();
  2163. }
  2164. else if((matchingElement = $module.find('[name="' + identifier +'"]')).length > 0) {
  2165. matchingValue = matchingElement.val();
  2166. }
  2167. else if((matchingElement = $module.find('[name="' + identifier +'[]"]')).length > 0 ) {
  2168. matchingValue = matchingElement;
  2169. }
  2170. return (matchingValue !== undefined)
  2171. ? ( value.toString() !== matchingValue.toString() )
  2172. : false
  2173. ;
  2174. },
  2175. creditCard: function(cardNumber, cardTypes) {
  2176. var
  2177. cards = {
  2178. visa: {
  2179. pattern : /^4/,
  2180. length : [16]
  2181. },
  2182. amex: {
  2183. pattern : /^3[47]/,
  2184. length : [15]
  2185. },
  2186. mastercard: {
  2187. pattern : /^5[1-5]/,
  2188. length : [16]
  2189. },
  2190. discover: {
  2191. pattern : /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,
  2192. length : [16]
  2193. },
  2194. unionPay: {
  2195. pattern : /^(62|88)/,
  2196. length : [16, 17, 18, 19]
  2197. },
  2198. jcb: {
  2199. pattern : /^35(2[89]|[3-8][0-9])/,
  2200. length : [16]
  2201. },
  2202. maestro: {
  2203. pattern : /^(5018|5020|5038|6304|6759|676[1-3])/,
  2204. length : [12, 13, 14, 15, 16, 17, 18, 19]
  2205. },
  2206. dinersClub: {
  2207. pattern : /^(30[0-5]|^36)/,
  2208. length : [14]
  2209. },
  2210. laser: {
  2211. pattern : /^(6304|670[69]|6771)/,
  2212. length : [16, 17, 18, 19]
  2213. },
  2214. visaElectron: {
  2215. pattern : /^(4026|417500|4508|4844|491(3|7))/,
  2216. length : [16]
  2217. }
  2218. },
  2219. valid = {},
  2220. validCard = false,
  2221. requiredTypes = (typeof cardTypes == 'string')
  2222. ? cardTypes.split(',')
  2223. : false,
  2224. unionPay,
  2225. validation
  2226. ;
  2227. if(typeof cardNumber !== 'string' || cardNumber.length === 0) {
  2228. return;
  2229. }
  2230. // allow dashes in card
  2231. cardNumber = cardNumber.replace(/[\-]/g, '');
  2232. // verify card types
  2233. if(requiredTypes) {
  2234. $.each(requiredTypes, function(index, type){
  2235. // verify each card type
  2236. validation = cards[type];
  2237. if(validation) {
  2238. valid = {
  2239. length : ($.inArray(cardNumber.length, validation.length) !== -1),
  2240. pattern : (cardNumber.search(validation.pattern) !== -1)
  2241. };
  2242. if(valid.length && valid.pattern) {
  2243. validCard = true;
  2244. }
  2245. }
  2246. });
  2247. if(!validCard) {
  2248. return false;
  2249. }
  2250. }
  2251. // skip luhn for UnionPay
  2252. unionPay = {
  2253. number : ($.inArray(cardNumber.length, cards.unionPay.length) !== -1),
  2254. pattern : (cardNumber.search(cards.unionPay.pattern) !== -1)
  2255. };
  2256. if(unionPay.number && unionPay.pattern) {
  2257. return true;
  2258. }
  2259. // verify luhn, adapted from <https://gist.github.com/2134376>
  2260. var
  2261. length = cardNumber.length,
  2262. multiple = 0,
  2263. producedValue = [
  2264. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
  2265. [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
  2266. ],
  2267. sum = 0
  2268. ;
  2269. while (length--) {
  2270. sum += producedValue[multiple][parseInt(cardNumber.charAt(length), 10)];
  2271. multiple ^= 1;
  2272. }
  2273. return (sum % 10 === 0 && sum > 0);
  2274. },
  2275. minCount: function(value, minCount) {
  2276. if(minCount == 0) {
  2277. return true;
  2278. }
  2279. if(minCount == 1) {
  2280. return (value !== '');
  2281. }
  2282. return (value.split(',').length >= minCount);
  2283. },
  2284. exactCount: function(value, exactCount) {
  2285. if(exactCount == 0) {
  2286. return (value === '');
  2287. }
  2288. if(exactCount == 1) {
  2289. return (value !== '' && value.search(',') === -1);
  2290. }
  2291. return (value.split(',').length == exactCount);
  2292. },
  2293. maxCount: function(value, maxCount) {
  2294. if(maxCount == 0) {
  2295. return false;
  2296. }
  2297. if(maxCount == 1) {
  2298. return (value.search(',') === -1);
  2299. }
  2300. return (value.split(',').length <= maxCount);
  2301. }
  2302. }
  2303. };
  2304. })( jQuery, window, document );
  2305. /*!
  2306. * # Fomantic-UI - Accordion
  2307. * http://github.com/fomantic/Fomantic-UI/
  2308. *
  2309. *
  2310. * Released under the MIT license
  2311. * http://opensource.org/licenses/MIT
  2312. *
  2313. */
  2314. ;(function ($, window, document, undefined) {
  2315. 'use strict';
  2316. $.isFunction = $.isFunction || function(obj) {
  2317. return typeof obj === "function" && typeof obj.nodeType !== "number";
  2318. };
  2319. window = (typeof window != 'undefined' && window.Math == Math)
  2320. ? window
  2321. : (typeof self != 'undefined' && self.Math == Math)
  2322. ? self
  2323. : Function('return this')()
  2324. ;
  2325. $.fn.accordion = function(parameters) {
  2326. var
  2327. $allModules = $(this),
  2328. time = new Date().getTime(),
  2329. performance = [],
  2330. query = arguments[0],
  2331. methodInvoked = (typeof query == 'string'),
  2332. queryArguments = [].slice.call(arguments, 1),
  2333. returnedValue
  2334. ;
  2335. $allModules
  2336. .each(function() {
  2337. var
  2338. settings = ( $.isPlainObject(parameters) )
  2339. ? $.extend(true, {}, $.fn.accordion.settings, parameters)
  2340. : $.extend({}, $.fn.accordion.settings),
  2341. className = settings.className,
  2342. namespace = settings.namespace,
  2343. selector = settings.selector,
  2344. error = settings.error,
  2345. eventNamespace = '.' + namespace,
  2346. moduleNamespace = 'module-' + namespace,
  2347. moduleSelector = $allModules.selector || '',
  2348. $module = $(this),
  2349. $title = $module.find(selector.title),
  2350. $content = $module.find(selector.content),
  2351. element = this,
  2352. instance = $module.data(moduleNamespace),
  2353. observer,
  2354. module
  2355. ;
  2356. module = {
  2357. initialize: function() {
  2358. module.debug('Initializing', $module);
  2359. module.bind.events();
  2360. if(settings.observeChanges) {
  2361. module.observeChanges();
  2362. }
  2363. module.instantiate();
  2364. },
  2365. instantiate: function() {
  2366. instance = module;
  2367. $module
  2368. .data(moduleNamespace, module)
  2369. ;
  2370. },
  2371. destroy: function() {
  2372. module.debug('Destroying previous instance', $module);
  2373. $module
  2374. .off(eventNamespace)
  2375. .removeData(moduleNamespace)
  2376. ;
  2377. },
  2378. refresh: function() {
  2379. $title = $module.find(selector.title);
  2380. $content = $module.find(selector.content);
  2381. },
  2382. observeChanges: function() {
  2383. if('MutationObserver' in window) {
  2384. observer = new MutationObserver(function(mutations) {
  2385. module.debug('DOM tree modified, updating selector cache');
  2386. module.refresh();
  2387. });
  2388. observer.observe(element, {
  2389. childList : true,
  2390. subtree : true
  2391. });
  2392. module.debug('Setting up mutation observer', observer);
  2393. }
  2394. },
  2395. bind: {
  2396. events: function() {
  2397. module.debug('Binding delegated events');
  2398. $module
  2399. .on(settings.on + eventNamespace, selector.trigger, module.event.click)
  2400. ;
  2401. }
  2402. },
  2403. event: {
  2404. click: function() {
  2405. module.toggle.call(this);
  2406. }
  2407. },
  2408. toggle: function(query) {
  2409. var
  2410. $activeTitle = (query !== undefined)
  2411. ? (typeof query === 'number')
  2412. ? $title.eq(query)
  2413. : $(query).closest(selector.title)
  2414. : $(this).closest(selector.title),
  2415. $activeContent = $activeTitle.next($content),
  2416. isAnimating = $activeContent.hasClass(className.animating),
  2417. isActive = $activeContent.hasClass(className.active),
  2418. isOpen = (isActive && !isAnimating),
  2419. isOpening = (!isActive && isAnimating)
  2420. ;
  2421. module.debug('Toggling visibility of content', $activeTitle);
  2422. if(isOpen || isOpening) {
  2423. if(settings.collapsible) {
  2424. module.close.call($activeTitle);
  2425. }
  2426. else {
  2427. module.debug('Cannot close accordion content collapsing is disabled');
  2428. }
  2429. }
  2430. else {
  2431. module.open.call($activeTitle);
  2432. }
  2433. },
  2434. open: function(query) {
  2435. var
  2436. $activeTitle = (query !== undefined)
  2437. ? (typeof query === 'number')
  2438. ? $title.eq(query)
  2439. : $(query).closest(selector.title)
  2440. : $(this).closest(selector.title),
  2441. $activeContent = $activeTitle.next($content),
  2442. isAnimating = $activeContent.hasClass(className.animating),
  2443. isActive = $activeContent.hasClass(className.active),
  2444. isOpen = (isActive || isAnimating)
  2445. ;
  2446. if(isOpen) {
  2447. module.debug('Accordion already open, skipping', $activeContent);
  2448. return;
  2449. }
  2450. module.debug('Opening accordion content', $activeTitle);
  2451. settings.onOpening.call($activeContent);
  2452. settings.onChanging.call($activeContent);
  2453. if(settings.exclusive) {
  2454. module.closeOthers.call($activeTitle);
  2455. }
  2456. $activeTitle
  2457. .addClass(className.active)
  2458. ;
  2459. $activeContent
  2460. .stop(true, true)
  2461. .addClass(className.animating)
  2462. ;
  2463. if(settings.animateChildren) {
  2464. if($.fn.transition !== undefined && $module.transition('is supported')) {
  2465. $activeContent
  2466. .children()
  2467. .transition({
  2468. animation : 'fade in',
  2469. queue : false,
  2470. useFailSafe : true,
  2471. debug : settings.debug,
  2472. verbose : settings.verbose,
  2473. duration : settings.duration,
  2474. skipInlineHidden : true,
  2475. onComplete: function() {
  2476. $activeContent.children().removeClass(className.transition);
  2477. }
  2478. })
  2479. ;
  2480. }
  2481. else {
  2482. $activeContent
  2483. .children()
  2484. .stop(true, true)
  2485. .animate({
  2486. opacity: 1
  2487. }, settings.duration, module.resetOpacity)
  2488. ;
  2489. }
  2490. }
  2491. $activeContent
  2492. .slideDown(settings.duration, settings.easing, function() {
  2493. $activeContent
  2494. .removeClass(className.animating)
  2495. .addClass(className.active)
  2496. ;
  2497. module.reset.display.call(this);
  2498. settings.onOpen.call(this);
  2499. settings.onChange.call(this);
  2500. })
  2501. ;
  2502. },
  2503. close: function(query) {
  2504. var
  2505. $activeTitle = (query !== undefined)
  2506. ? (typeof query === 'number')
  2507. ? $title.eq(query)
  2508. : $(query).closest(selector.title)
  2509. : $(this).closest(selector.title),
  2510. $activeContent = $activeTitle.next($content),
  2511. isAnimating = $activeContent.hasClass(className.animating),
  2512. isActive = $activeContent.hasClass(className.active),
  2513. isOpening = (!isActive && isAnimating),
  2514. isClosing = (isActive && isAnimating)
  2515. ;
  2516. if((isActive || isOpening) && !isClosing) {
  2517. module.debug('Closing accordion content', $activeContent);
  2518. settings.onClosing.call($activeContent);
  2519. settings.onChanging.call($activeContent);
  2520. $activeTitle
  2521. .removeClass(className.active)
  2522. ;
  2523. $activeContent
  2524. .stop(true, true)
  2525. .addClass(className.animating)
  2526. ;
  2527. if(settings.animateChildren) {
  2528. if($.fn.transition !== undefined && $module.transition('is supported')) {
  2529. $activeContent
  2530. .children()
  2531. .transition({
  2532. animation : 'fade out',
  2533. queue : false,
  2534. useFailSafe : true,
  2535. debug : settings.debug,
  2536. verbose : settings.verbose,
  2537. duration : settings.duration,
  2538. skipInlineHidden : true
  2539. })
  2540. ;
  2541. }
  2542. else {
  2543. $activeContent
  2544. .children()
  2545. .stop(true, true)
  2546. .animate({
  2547. opacity: 0
  2548. }, settings.duration, module.resetOpacity)
  2549. ;
  2550. }
  2551. }
  2552. $activeContent
  2553. .slideUp(settings.duration, settings.easing, function() {
  2554. $activeContent
  2555. .removeClass(className.animating)
  2556. .removeClass(className.active)
  2557. ;
  2558. module.reset.display.call(this);
  2559. settings.onClose.call(this);
  2560. settings.onChange.call(this);
  2561. })
  2562. ;
  2563. }
  2564. },
  2565. closeOthers: function(index) {
  2566. var
  2567. $activeTitle = (index !== undefined)
  2568. ? $title.eq(index)
  2569. : $(this).closest(selector.title),
  2570. $parentTitles = $activeTitle.parents(selector.content).prev(selector.title),
  2571. $activeAccordion = $activeTitle.closest(selector.accordion),
  2572. activeSelector = selector.title + '.' + className.active + ':visible',
  2573. activeContent = selector.content + '.' + className.active + ':visible',
  2574. $openTitles,
  2575. $nestedTitles,
  2576. $openContents
  2577. ;
  2578. if(settings.closeNested) {
  2579. $openTitles = $activeAccordion.find(activeSelector).not($parentTitles);
  2580. $openContents = $openTitles.next($content);
  2581. }
  2582. else {
  2583. $openTitles = $activeAccordion.find(activeSelector).not($parentTitles);
  2584. $nestedTitles = $activeAccordion.find(activeContent).find(activeSelector).not($parentTitles);
  2585. $openTitles = $openTitles.not($nestedTitles);
  2586. $openContents = $openTitles.next($content);
  2587. }
  2588. if( ($openTitles.length > 0) ) {
  2589. module.debug('Exclusive enabled, closing other content', $openTitles);
  2590. $openTitles
  2591. .removeClass(className.active)
  2592. ;
  2593. $openContents
  2594. .removeClass(className.animating)
  2595. .stop(true, true)
  2596. ;
  2597. if(settings.animateChildren) {
  2598. if($.fn.transition !== undefined && $module.transition('is supported')) {
  2599. $openContents
  2600. .children()
  2601. .transition({
  2602. animation : 'fade out',
  2603. useFailSafe : true,
  2604. debug : settings.debug,
  2605. verbose : settings.verbose,
  2606. duration : settings.duration,
  2607. skipInlineHidden : true
  2608. })
  2609. ;
  2610. }
  2611. else {
  2612. $openContents
  2613. .children()
  2614. .stop(true, true)
  2615. .animate({
  2616. opacity: 0
  2617. }, settings.duration, module.resetOpacity)
  2618. ;
  2619. }
  2620. }
  2621. $openContents
  2622. .slideUp(settings.duration , settings.easing, function() {
  2623. $(this).removeClass(className.active);
  2624. module.reset.display.call(this);
  2625. })
  2626. ;
  2627. }
  2628. },
  2629. reset: {
  2630. display: function() {
  2631. module.verbose('Removing inline display from element', this);
  2632. $(this).css('display', '');
  2633. if( $(this).attr('style') === '') {
  2634. $(this)
  2635. .attr('style', '')
  2636. .removeAttr('style')
  2637. ;
  2638. }
  2639. },
  2640. opacity: function() {
  2641. module.verbose('Removing inline opacity from element', this);
  2642. $(this).css('opacity', '');
  2643. if( $(this).attr('style') === '') {
  2644. $(this)
  2645. .attr('style', '')
  2646. .removeAttr('style')
  2647. ;
  2648. }
  2649. },
  2650. },
  2651. setting: function(name, value) {
  2652. module.debug('Changing setting', name, value);
  2653. if( $.isPlainObject(name) ) {
  2654. $.extend(true, settings, name);
  2655. }
  2656. else if(value !== undefined) {
  2657. if($.isPlainObject(settings[name])) {
  2658. $.extend(true, settings[name], value);
  2659. }
  2660. else {
  2661. settings[name] = value;
  2662. }
  2663. }
  2664. else {
  2665. return settings[name];
  2666. }
  2667. },
  2668. internal: function(name, value) {
  2669. module.debug('Changing internal', name, value);
  2670. if(value !== undefined) {
  2671. if( $.isPlainObject(name) ) {
  2672. $.extend(true, module, name);
  2673. }
  2674. else {
  2675. module[name] = value;
  2676. }
  2677. }
  2678. else {
  2679. return module[name];
  2680. }
  2681. },
  2682. debug: function() {
  2683. if(!settings.silent && settings.debug) {
  2684. if(settings.performance) {
  2685. module.performance.log(arguments);
  2686. }
  2687. else {
  2688. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  2689. module.debug.apply(console, arguments);
  2690. }
  2691. }
  2692. },
  2693. verbose: function() {
  2694. if(!settings.silent && settings.verbose && settings.debug) {
  2695. if(settings.performance) {
  2696. module.performance.log(arguments);
  2697. }
  2698. else {
  2699. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  2700. module.verbose.apply(console, arguments);
  2701. }
  2702. }
  2703. },
  2704. error: function() {
  2705. if(!settings.silent) {
  2706. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  2707. module.error.apply(console, arguments);
  2708. }
  2709. },
  2710. performance: {
  2711. log: function(message) {
  2712. var
  2713. currentTime,
  2714. executionTime,
  2715. previousTime
  2716. ;
  2717. if(settings.performance) {
  2718. currentTime = new Date().getTime();
  2719. previousTime = time || currentTime;
  2720. executionTime = currentTime - previousTime;
  2721. time = currentTime;
  2722. performance.push({
  2723. 'Name' : message[0],
  2724. 'Arguments' : [].slice.call(message, 1) || '',
  2725. 'Element' : element,
  2726. 'Execution Time' : executionTime
  2727. });
  2728. }
  2729. clearTimeout(module.performance.timer);
  2730. module.performance.timer = setTimeout(module.performance.display, 500);
  2731. },
  2732. display: function() {
  2733. var
  2734. title = settings.name + ':',
  2735. totalTime = 0
  2736. ;
  2737. time = false;
  2738. clearTimeout(module.performance.timer);
  2739. $.each(performance, function(index, data) {
  2740. totalTime += data['Execution Time'];
  2741. });
  2742. title += ' ' + totalTime + 'ms';
  2743. if(moduleSelector) {
  2744. title += ' \'' + moduleSelector + '\'';
  2745. }
  2746. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  2747. console.groupCollapsed(title);
  2748. if(console.table) {
  2749. console.table(performance);
  2750. }
  2751. else {
  2752. $.each(performance, function(index, data) {
  2753. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  2754. });
  2755. }
  2756. console.groupEnd();
  2757. }
  2758. performance = [];
  2759. }
  2760. },
  2761. invoke: function(query, passedArguments, context) {
  2762. var
  2763. object = instance,
  2764. maxDepth,
  2765. found,
  2766. response
  2767. ;
  2768. passedArguments = passedArguments || queryArguments;
  2769. context = element || context;
  2770. if(typeof query == 'string' && object !== undefined) {
  2771. query = query.split(/[\. ]/);
  2772. maxDepth = query.length - 1;
  2773. $.each(query, function(depth, value) {
  2774. var camelCaseValue = (depth != maxDepth)
  2775. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  2776. : query
  2777. ;
  2778. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  2779. object = object[camelCaseValue];
  2780. }
  2781. else if( object[camelCaseValue] !== undefined ) {
  2782. found = object[camelCaseValue];
  2783. return false;
  2784. }
  2785. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  2786. object = object[value];
  2787. }
  2788. else if( object[value] !== undefined ) {
  2789. found = object[value];
  2790. return false;
  2791. }
  2792. else {
  2793. module.error(error.method, query);
  2794. return false;
  2795. }
  2796. });
  2797. }
  2798. if ( $.isFunction( found ) ) {
  2799. response = found.apply(context, passedArguments);
  2800. }
  2801. else if(found !== undefined) {
  2802. response = found;
  2803. }
  2804. if(Array.isArray(returnedValue)) {
  2805. returnedValue.push(response);
  2806. }
  2807. else if(returnedValue !== undefined) {
  2808. returnedValue = [returnedValue, response];
  2809. }
  2810. else if(response !== undefined) {
  2811. returnedValue = response;
  2812. }
  2813. return found;
  2814. }
  2815. };
  2816. if(methodInvoked) {
  2817. if(instance === undefined) {
  2818. module.initialize();
  2819. }
  2820. module.invoke(query);
  2821. }
  2822. else {
  2823. if(instance !== undefined) {
  2824. instance.invoke('destroy');
  2825. }
  2826. module.initialize();
  2827. }
  2828. })
  2829. ;
  2830. return (returnedValue !== undefined)
  2831. ? returnedValue
  2832. : this
  2833. ;
  2834. };
  2835. $.fn.accordion.settings = {
  2836. name : 'Accordion',
  2837. namespace : 'accordion',
  2838. silent : false,
  2839. debug : false,
  2840. verbose : false,
  2841. performance : true,
  2842. on : 'click', // event on title that opens accordion
  2843. observeChanges : true, // whether accordion should automatically refresh on DOM insertion
  2844. exclusive : true, // whether a single accordion content panel should be open at once
  2845. collapsible : true, // whether accordion content can be closed
  2846. closeNested : false, // whether nested content should be closed when a panel is closed
  2847. animateChildren : true, // whether children opacity should be animated
  2848. duration : 350, // duration of animation
  2849. easing : 'easeOutQuad', // easing equation for animation
  2850. onOpening : function(){}, // callback before open animation
  2851. onClosing : function(){}, // callback before closing animation
  2852. onChanging : function(){}, // callback before closing or opening animation
  2853. onOpen : function(){}, // callback after open animation
  2854. onClose : function(){}, // callback after closing animation
  2855. onChange : function(){}, // callback after closing or opening animation
  2856. error: {
  2857. method : 'The method you called is not defined'
  2858. },
  2859. className : {
  2860. active : 'active',
  2861. animating : 'animating',
  2862. transition: 'transition'
  2863. },
  2864. selector : {
  2865. accordion : '.accordion',
  2866. title : '.title',
  2867. trigger : '.title',
  2868. content : '.content'
  2869. }
  2870. };
  2871. // Adds easing
  2872. $.extend( $.easing, {
  2873. easeOutQuad: function (x, t, b, c, d) {
  2874. return -c *(t/=d)*(t-2) + b;
  2875. }
  2876. });
  2877. })( jQuery, window, document );
  2878. /*!
  2879. * # Fomantic-UI - Calendar
  2880. * http://github.com/fomantic/Fomantic-UI/
  2881. *
  2882. *
  2883. * Released under the MIT license
  2884. * http://opensource.org/licenses/MIT
  2885. *
  2886. */
  2887. ;(function ($, window, document, undefined) {
  2888. 'use strict';
  2889. $.isFunction = $.isFunction || function(obj) {
  2890. return typeof obj === "function" && typeof obj.nodeType !== "number";
  2891. };
  2892. window = (typeof window != 'undefined' && window.Math == Math)
  2893. ? window
  2894. : (typeof self != 'undefined' && self.Math == Math)
  2895. ? self
  2896. : Function('return this')()
  2897. ;
  2898. $.fn.calendar = function(parameters) {
  2899. var
  2900. $allModules = $(this),
  2901. moduleSelector = $allModules.selector || '',
  2902. time = new Date().getTime(),
  2903. performance = [],
  2904. query = arguments[0],
  2905. methodInvoked = (typeof query == 'string'),
  2906. queryArguments = [].slice.call(arguments, 1),
  2907. returnedValue,
  2908. timeGapTable = {
  2909. '5': {'row': 4, 'column': 3 },
  2910. '10': {'row': 3, 'column': 2 },
  2911. '15': {'row': 2, 'column': 2 },
  2912. '20': {'row': 3, 'column': 1 },
  2913. '30': {'row': 2, 'column': 1 }
  2914. }
  2915. ;
  2916. $allModules
  2917. .each(function () {
  2918. var
  2919. settings = ( $.isPlainObject(parameters) )
  2920. ? $.extend(true, {}, $.fn.calendar.settings, parameters)
  2921. : $.extend({}, $.fn.calendar.settings),
  2922. className = settings.className,
  2923. namespace = settings.namespace,
  2924. selector = settings.selector,
  2925. formatter = settings.formatter,
  2926. parser = settings.parser,
  2927. metadata = settings.metadata,
  2928. timeGap = timeGapTable[settings.minTimeGap],
  2929. error = settings.error,
  2930. eventNamespace = '.' + namespace,
  2931. moduleNamespace = 'module-' + namespace,
  2932. $module = $(this),
  2933. $input = $module.find(selector.input),
  2934. $container = $module.find(selector.popup),
  2935. $activator = $module.find(selector.activator),
  2936. element = this,
  2937. instance = $module.data(moduleNamespace),
  2938. isTouch,
  2939. isTouchDown = false,
  2940. focusDateUsedForRange = false,
  2941. module
  2942. ;
  2943. module = {
  2944. initialize: function () {
  2945. module.debug('Initializing calendar for', element, $module);
  2946. isTouch = module.get.isTouch();
  2947. module.setup.config();
  2948. module.setup.popup();
  2949. module.setup.inline();
  2950. module.setup.input();
  2951. module.setup.date();
  2952. module.create.calendar();
  2953. module.bind.events();
  2954. module.instantiate();
  2955. },
  2956. instantiate: function () {
  2957. module.verbose('Storing instance of calendar');
  2958. instance = module;
  2959. $module.data(moduleNamespace, instance);
  2960. },
  2961. destroy: function () {
  2962. module.verbose('Destroying previous calendar for', element);
  2963. $module.removeData(moduleNamespace);
  2964. module.unbind.events();
  2965. },
  2966. setup: {
  2967. config: function () {
  2968. if (module.get.minDate() !== null) {
  2969. module.set.minDate($module.data(metadata.minDate));
  2970. }
  2971. if (module.get.maxDate() !== null) {
  2972. module.set.maxDate($module.data(metadata.maxDate));
  2973. }
  2974. },
  2975. popup: function () {
  2976. if (settings.inline) {
  2977. return;
  2978. }
  2979. if (!$activator.length) {
  2980. $activator = $module.children().first();
  2981. if (!$activator.length) {
  2982. return;
  2983. }
  2984. }
  2985. if ($.fn.popup === undefined) {
  2986. module.error(error.popup);
  2987. return;
  2988. }
  2989. if (!$container.length) {
  2990. //prepend the popup element to the activator's parent so that it has less chance of messing with
  2991. //the styling (eg input action button needs to be the last child to have correct border radius)
  2992. var $activatorParent = $activator.parent(),
  2993. domPositionFunction = $activatorParent.closest(selector.append).length !== 0 ? 'appendTo' : 'prependTo';
  2994. $container = $('<div/>').addClass(className.popup)[domPositionFunction]($activatorParent);
  2995. }
  2996. $container.addClass(className.calendar);
  2997. var onVisible = settings.onVisible;
  2998. var onHidden = settings.onHidden;
  2999. if (!$input.length) {
  3000. //no input, $container has to handle focus/blur
  3001. $container.attr('tabindex', '0');
  3002. onVisible = function () {
  3003. module.focus();
  3004. return settings.onVisible.apply($container, arguments);
  3005. };
  3006. onHidden = function () {
  3007. module.blur();
  3008. return settings.onHidden.apply($container, arguments);
  3009. };
  3010. }
  3011. var onShow = function () {
  3012. //reset the focus date onShow
  3013. module.set.focusDate(module.get.date());
  3014. module.set.mode(settings.startMode);
  3015. return settings.onShow.apply($container, arguments);
  3016. };
  3017. var on = settings.on || ($input.length ? 'focus' : 'click');
  3018. var options = $.extend({}, settings.popupOptions, {
  3019. popup: $container,
  3020. on: on,
  3021. hoverable: on === 'hover',
  3022. onShow: onShow,
  3023. onVisible: onVisible,
  3024. onHide: settings.onHide,
  3025. onHidden: onHidden
  3026. });
  3027. module.popup(options);
  3028. },
  3029. inline: function () {
  3030. if ($activator.length && !settings.inline) {
  3031. return;
  3032. }
  3033. $container = $('<div/>').addClass(className.calendar).appendTo($module);
  3034. if (!$input.length) {
  3035. $container.attr('tabindex', '0');
  3036. }
  3037. },
  3038. input: function () {
  3039. if (settings.touchReadonly && $input.length && isTouch) {
  3040. $input.prop('readonly', true);
  3041. }
  3042. },
  3043. date: function () {
  3044. if (settings.initialDate) {
  3045. var date = parser.date(settings.initialDate, settings);
  3046. module.set.date(date, settings.formatInput, false);
  3047. } else if ($module.data(metadata.date) !== undefined) {
  3048. var date = parser.date($module.data(metadata.date), settings);
  3049. module.set.date(date, settings.formatInput, false);
  3050. } else if ($input.length) {
  3051. var val = $input.val();
  3052. var date = parser.date(val, settings);
  3053. module.set.date(date, settings.formatInput, false);
  3054. }
  3055. }
  3056. },
  3057. create: {
  3058. calendar: function () {
  3059. var i, r, c, p, row, cell, pageGrid;
  3060. var mode = module.get.mode();
  3061. var today = new Date();
  3062. var date = module.get.date();
  3063. var focusDate = module.get.focusDate();
  3064. var display = focusDate || date || settings.initialDate || today;
  3065. display = module.helper.dateInRange(display);
  3066. if (!focusDate) {
  3067. focusDate = display;
  3068. module.set.focusDate(focusDate, false, false);
  3069. }
  3070. var isYear = mode === 'year';
  3071. var isMonth = mode === 'month';
  3072. var isDay = mode === 'day';
  3073. var isHour = mode === 'hour';
  3074. var isMinute = mode === 'minute';
  3075. var isTimeOnly = settings.type === 'time';
  3076. var multiMonth = Math.max(settings.multiMonth, 1);
  3077. var monthOffset = !isDay ? 0 : module.get.monthOffset();
  3078. var minute = display.getMinutes();
  3079. var hour = display.getHours();
  3080. var day = display.getDate();
  3081. var startMonth = display.getMonth() + monthOffset;
  3082. var year = display.getFullYear();
  3083. var columns = isDay ? settings.showWeekNumbers ? 8 : 7 : isHour ? 4 : timeGap['column'];
  3084. var rows = isDay || isHour ? 6 : timeGap['row'];
  3085. var pages = isDay ? multiMonth : 1;
  3086. var container = $container;
  3087. var tooltipPosition = container.hasClass("left") ? "right center" : "left center";
  3088. container.empty();
  3089. if (pages > 1) {
  3090. pageGrid = $('<div/>').addClass(className.grid).appendTo(container);
  3091. }
  3092. for (p = 0; p < pages; p++) {
  3093. if (pages > 1) {
  3094. var pageColumn = $('<div/>').addClass(className.column).appendTo(pageGrid);
  3095. container = pageColumn;
  3096. }
  3097. var month = startMonth + p;
  3098. var firstMonthDayColumn = (new Date(year, month, 1).getDay() - settings.firstDayOfWeek % 7 + 7) % 7;
  3099. if (!settings.constantHeight && isDay) {
  3100. var requiredCells = new Date(year, month + 1, 0).getDate() + firstMonthDayColumn;
  3101. rows = Math.ceil(requiredCells / 7);
  3102. }
  3103. var yearChange = isYear ? 10 : isMonth ? 1 : 0;
  3104. var monthChange = isDay ? 1 : 0;
  3105. var dayChange = isHour || isMinute ? 1 : 0;
  3106. var prevNextDay = isHour || isMinute ? day : 1;
  3107. var prevDate = new Date(year - yearChange, month - monthChange, prevNextDay - dayChange, hour);
  3108. var nextDate = new Date(year + yearChange, month + monthChange, prevNextDay + dayChange, hour);
  3109. var prevLast = isYear ? new Date(Math.ceil(year / 10) * 10 - 9, 0, 0) :
  3110. isMonth ? new Date(year, 0, 0) : isDay ? new Date(year, month, 0) : new Date(year, month, day, -1);
  3111. var nextFirst = isYear ? new Date(Math.ceil(year / 10) * 10 + 1, 0, 1) :
  3112. isMonth ? new Date(year + 1, 0, 1) : isDay ? new Date(year, month + 1, 1) : new Date(year, month, day + 1);
  3113. var tempMode = mode;
  3114. if (isDay && settings.showWeekNumbers){
  3115. tempMode += ' andweek';
  3116. }
  3117. var table = $('<table/>').addClass(className.table).addClass(tempMode).appendTo(container);
  3118. var textColumns = columns;
  3119. //no header for time-only mode
  3120. if (!isTimeOnly) {
  3121. var thead = $('<thead/>').appendTo(table);
  3122. row = $('<tr/>').appendTo(thead);
  3123. cell = $('<th/>').attr('colspan', '' + columns).appendTo(row);
  3124. var headerDate = isYear || isMonth ? new Date(year, 0, 1) :
  3125. isDay ? new Date(year, month, 1) : new Date(year, month, day, hour, minute);
  3126. var headerText = $('<span/>').addClass(className.link).appendTo(cell);
  3127. headerText.text(formatter.header(headerDate, mode, settings));
  3128. var newMode = isMonth ? (settings.disableYear ? 'day' : 'year') :
  3129. isDay ? (settings.disableMonth ? 'year' : 'month') : 'day';
  3130. headerText.data(metadata.mode, newMode);
  3131. if (p === 0) {
  3132. var prev = $('<span/>').addClass(className.prev).appendTo(cell);
  3133. prev.data(metadata.focusDate, prevDate);
  3134. prev.toggleClass(className.disabledCell, !module.helper.isDateInRange(prevLast, mode));
  3135. $('<i/>').addClass(className.prevIcon).appendTo(prev);
  3136. }
  3137. if (p === pages - 1) {
  3138. var next = $('<span/>').addClass(className.next).appendTo(cell);
  3139. next.data(metadata.focusDate, nextDate);
  3140. next.toggleClass(className.disabledCell, !module.helper.isDateInRange(nextFirst, mode));
  3141. $('<i/>').addClass(className.nextIcon).appendTo(next);
  3142. }
  3143. if (isDay) {
  3144. row = $('<tr/>').appendTo(thead);
  3145. if(settings.showWeekNumbers) {
  3146. cell = $('<th/>').appendTo(row);
  3147. cell.text(settings.text.weekNo);
  3148. cell.addClass(className.weekCell);
  3149. textColumns--;
  3150. }
  3151. for (i = 0; i < textColumns; i++) {
  3152. cell = $('<th/>').appendTo(row);
  3153. cell.text(formatter.dayColumnHeader((i + settings.firstDayOfWeek) % 7, settings));
  3154. }
  3155. }
  3156. }
  3157. var tbody = $('<tbody/>').appendTo(table);
  3158. i = isYear ? Math.ceil(year / 10) * 10 - 9 : isDay ? 1 - firstMonthDayColumn : 0;
  3159. for (r = 0; r < rows; r++) {
  3160. row = $('<tr/>').appendTo(tbody);
  3161. if(isDay && settings.showWeekNumbers){
  3162. cell = $('<th/>').appendTo(row);
  3163. cell.text(module.get.weekOfYear(year,month,i+1-settings.firstDayOfWeek));
  3164. cell.addClass(className.weekCell);
  3165. }
  3166. for (c = 0; c < textColumns; c++, i++) {
  3167. var cellDate = isYear ? new Date(i, month, 1, hour, minute) :
  3168. isMonth ? new Date(year, i, 1, hour, minute) : isDay ? new Date(year, month, i, hour, minute) :
  3169. isHour ? new Date(year, month, day, i) : new Date(year, month, day, hour, i * settings.minTimeGap);
  3170. var cellText = isYear ? i :
  3171. isMonth ? settings.text.monthsShort[i] : isDay ? cellDate.getDate() :
  3172. formatter.time(cellDate, settings, true);
  3173. cell = $('<td/>').addClass(className.cell).appendTo(row);
  3174. cell.text(cellText);
  3175. cell.data(metadata.date, cellDate);
  3176. var adjacent = isDay && cellDate.getMonth() !== ((month + 12) % 12);
  3177. var disabled = (!settings.selectAdjacentDays && adjacent) || !module.helper.isDateInRange(cellDate, mode) || settings.isDisabled(cellDate, mode) || module.helper.isDisabled(cellDate, mode) || !module.helper.isEnabled(cellDate, mode);
  3178. if (disabled) {
  3179. var disabledDate = module.helper.findDayAsObject(cellDate, mode, settings.disabledDates);
  3180. if (disabledDate !== null && disabledDate[metadata.message]) {
  3181. cell.attr("data-tooltip", disabledDate[metadata.message]);
  3182. cell.attr("data-position", tooltipPosition);
  3183. }
  3184. } else {
  3185. var eventDate = module.helper.findDayAsObject(cellDate, mode, settings.eventDates);
  3186. if (eventDate !== null) {
  3187. cell.addClass(eventDate[metadata.class] || settings.eventClass);
  3188. if (eventDate[metadata.message]) {
  3189. cell.attr("data-tooltip", eventDate[metadata.message]);
  3190. cell.attr("data-position", tooltipPosition);
  3191. }
  3192. }
  3193. }
  3194. var active = module.helper.dateEqual(cellDate, date, mode);
  3195. var isToday = module.helper.dateEqual(cellDate, today, mode);
  3196. cell.toggleClass(className.adjacentCell, adjacent);
  3197. cell.toggleClass(className.disabledCell, disabled);
  3198. cell.toggleClass(className.activeCell, active && !adjacent);
  3199. if (!isHour && !isMinute) {
  3200. cell.toggleClass(className.todayCell, !adjacent && isToday);
  3201. }
  3202. // Allow for external modifications of each cell
  3203. var cellOptions = {
  3204. mode: mode,
  3205. adjacent: adjacent,
  3206. disabled: disabled,
  3207. active: active,
  3208. today: isToday
  3209. };
  3210. formatter.cell(cell, cellDate, cellOptions);
  3211. if (module.helper.dateEqual(cellDate, focusDate, mode)) {
  3212. //ensure that the focus date is exactly equal to the cell date
  3213. //so that, if selected, the correct value is set
  3214. module.set.focusDate(cellDate, false, false);
  3215. }
  3216. }
  3217. }
  3218. if (settings.today) {
  3219. var todayRow = $('<tr/>').appendTo(tbody);
  3220. var todayButton = $('<td/>').attr('colspan', '' + columns).addClass(className.today).appendTo(todayRow);
  3221. todayButton.text(formatter.today(settings));
  3222. todayButton.data(metadata.date, today);
  3223. }
  3224. module.update.focus(false, table);
  3225. }
  3226. }
  3227. },
  3228. update: {
  3229. focus: function (updateRange, container) {
  3230. container = container || $container;
  3231. var mode = module.get.mode();
  3232. var date = module.get.date();
  3233. var focusDate = module.get.focusDate();
  3234. var startDate = module.get.startDate();
  3235. var endDate = module.get.endDate();
  3236. var rangeDate = (updateRange ? focusDate : null) || date || (!isTouch ? focusDate : null);
  3237. container.find('td').each(function () {
  3238. var cell = $(this);
  3239. var cellDate = cell.data(metadata.date);
  3240. if (!cellDate) {
  3241. return;
  3242. }
  3243. var disabled = cell.hasClass(className.disabledCell);
  3244. var active = cell.hasClass(className.activeCell);
  3245. var adjacent = cell.hasClass(className.adjacentCell);
  3246. var focused = module.helper.dateEqual(cellDate, focusDate, mode);
  3247. var inRange = !rangeDate ? false :
  3248. ((!!startDate && module.helper.isDateInRange(cellDate, mode, startDate, rangeDate)) ||
  3249. (!!endDate && module.helper.isDateInRange(cellDate, mode, rangeDate, endDate)));
  3250. cell.toggleClass(className.focusCell, focused && (!isTouch || isTouchDown) && (!adjacent || (settings.selectAdjacentDays && adjacent)) && !disabled);
  3251. cell.toggleClass(className.rangeCell, inRange && !active && !disabled);
  3252. });
  3253. }
  3254. },
  3255. refresh: function () {
  3256. module.create.calendar();
  3257. },
  3258. bind: {
  3259. events: function () {
  3260. module.debug('Binding events');
  3261. $container.on('mousedown' + eventNamespace, module.event.mousedown);
  3262. $container.on('touchstart' + eventNamespace, module.event.mousedown);
  3263. $container.on('mouseup' + eventNamespace, module.event.mouseup);
  3264. $container.on('touchend' + eventNamespace, module.event.mouseup);
  3265. $container.on('mouseover' + eventNamespace, module.event.mouseover);
  3266. if ($input.length) {
  3267. $input.on('input' + eventNamespace, module.event.inputChange);
  3268. $input.on('focus' + eventNamespace, module.event.inputFocus);
  3269. $input.on('blur' + eventNamespace, module.event.inputBlur);
  3270. $input.on('click' + eventNamespace, module.event.inputClick);
  3271. $input.on('keydown' + eventNamespace, module.event.keydown);
  3272. } else {
  3273. $container.on('keydown' + eventNamespace, module.event.keydown);
  3274. }
  3275. }
  3276. },
  3277. unbind: {
  3278. events: function () {
  3279. module.debug('Unbinding events');
  3280. $container.off(eventNamespace);
  3281. if ($input.length) {
  3282. $input.off(eventNamespace);
  3283. }
  3284. }
  3285. },
  3286. event: {
  3287. mouseover: function (event) {
  3288. var target = $(event.target);
  3289. var date = target.data(metadata.date);
  3290. var mousedown = event.buttons === 1;
  3291. if (date) {
  3292. module.set.focusDate(date, false, true, mousedown);
  3293. }
  3294. },
  3295. mousedown: function (event) {
  3296. if ($input.length) {
  3297. //prevent the mousedown on the calendar causing the input to lose focus
  3298. event.preventDefault();
  3299. }
  3300. isTouchDown = event.type.indexOf('touch') >= 0;
  3301. var target = $(event.target);
  3302. var date = target.data(metadata.date);
  3303. if (date) {
  3304. module.set.focusDate(date, false, true, true);
  3305. }
  3306. },
  3307. mouseup: function (event) {
  3308. //ensure input has focus so that it receives keydown events for calendar navigation
  3309. module.focus();
  3310. event.preventDefault();
  3311. event.stopPropagation();
  3312. isTouchDown = false;
  3313. var target = $(event.target);
  3314. if (target.hasClass("disabled")) {
  3315. return;
  3316. }
  3317. var parent = target.parent();
  3318. if (parent.data(metadata.date) || parent.data(metadata.focusDate) || parent.data(metadata.mode)) {
  3319. //clicked on a child element, switch to parent (used when clicking directly on prev/next <i> icon element)
  3320. target = parent;
  3321. }
  3322. var date = target.data(metadata.date);
  3323. var focusDate = target.data(metadata.focusDate);
  3324. var mode = target.data(metadata.mode);
  3325. if (date && settings.onSelect.call(element, date, module.get.mode()) !== false) {
  3326. var forceSet = target.hasClass(className.today);
  3327. module.selectDate(date, forceSet);
  3328. }
  3329. else if (focusDate) {
  3330. module.set.focusDate(focusDate);
  3331. }
  3332. else if (mode) {
  3333. module.set.mode(mode);
  3334. }
  3335. },
  3336. keydown: function (event) {
  3337. var keyCode = event.which;
  3338. if (keyCode === 27 || keyCode === 9) {
  3339. //esc || tab
  3340. module.popup('hide');
  3341. }
  3342. if (module.popup('is visible')) {
  3343. if (keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40) {
  3344. //arrow keys
  3345. var mode = module.get.mode();
  3346. var bigIncrement = mode === 'day' ? 7 : mode === 'hour' ? 4 : mode === 'minute' ? timeGap['column'] : 3;
  3347. var increment = keyCode === 37 ? -1 : keyCode === 38 ? -bigIncrement : keyCode == 39 ? 1 : bigIncrement;
  3348. increment *= mode === 'minute' ? settings.minTimeGap : 1;
  3349. var focusDate = module.get.focusDate() || module.get.date() || new Date();
  3350. var year = focusDate.getFullYear() + (mode === 'year' ? increment : 0);
  3351. var month = focusDate.getMonth() + (mode === 'month' ? increment : 0);
  3352. var day = focusDate.getDate() + (mode === 'day' ? increment : 0);
  3353. var hour = focusDate.getHours() + (mode === 'hour' ? increment : 0);
  3354. var minute = focusDate.getMinutes() + (mode === 'minute' ? increment : 0);
  3355. var newFocusDate = new Date(year, month, day, hour, minute);
  3356. if (settings.type === 'time') {
  3357. newFocusDate = module.helper.mergeDateTime(focusDate, newFocusDate);
  3358. }
  3359. if (module.helper.isDateInRange(newFocusDate, mode)) {
  3360. module.set.focusDate(newFocusDate);
  3361. }
  3362. } else if (keyCode === 13) {
  3363. //enter
  3364. var mode = module.get.mode();
  3365. var date = module.get.focusDate();
  3366. if (date && !settings.isDisabled(date, mode) && !module.helper.isDisabled(date, mode) && module.helper.isEnabled(date, mode)) {
  3367. module.selectDate(date);
  3368. }
  3369. //disable form submission:
  3370. event.preventDefault();
  3371. event.stopPropagation();
  3372. }
  3373. }
  3374. if (keyCode === 38 || keyCode === 40) {
  3375. //arrow-up || arrow-down
  3376. event.preventDefault(); //don't scroll
  3377. module.popup('show');
  3378. }
  3379. },
  3380. inputChange: function () {
  3381. var val = $input.val();
  3382. var date = parser.date(val, settings);
  3383. module.set.date(date, false);
  3384. },
  3385. inputFocus: function () {
  3386. $container.addClass(className.active);
  3387. },
  3388. inputBlur: function () {
  3389. $container.removeClass(className.active);
  3390. if (settings.formatInput) {
  3391. var date = module.get.date();
  3392. var text = formatter.datetime(date, settings);
  3393. $input.val(text);
  3394. }
  3395. },
  3396. inputClick: function () {
  3397. module.popup('show');
  3398. }
  3399. },
  3400. get: {
  3401. weekOfYear: function(weekYear,weekMonth,weekDay) {
  3402. // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
  3403. var ms1d = 864e5, // milliseconds in a day
  3404. ms7d = 7 * ms1d; // milliseconds in a week
  3405. return function() { // return a closure so constants get calculated only once
  3406. var DC3 = Date.UTC(weekYear, weekMonth, weekDay + 3) / ms1d, // an Absolute Day Number
  3407. AWN = Math.floor(DC3 / 7), // an Absolute Week Number
  3408. Wyr = new Date(AWN * ms7d).getUTCFullYear();
  3409. return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
  3410. }();
  3411. },
  3412. date: function () {
  3413. return module.helper.sanitiseDate($module.data(metadata.date)) || null;
  3414. },
  3415. inputDate: function() {
  3416. return $input.val();
  3417. },
  3418. focusDate: function () {
  3419. return $module.data(metadata.focusDate) || null;
  3420. },
  3421. startDate: function () {
  3422. var startModule = module.get.calendarModule(settings.startCalendar);
  3423. return (startModule ? startModule.get.date() : $module.data(metadata.startDate)) || null;
  3424. },
  3425. endDate: function () {
  3426. var endModule = module.get.calendarModule(settings.endCalendar);
  3427. return (endModule ? endModule.get.date() : $module.data(metadata.endDate)) || null;
  3428. },
  3429. minDate: function() {
  3430. return $module.data(metadata.minDate) || null;
  3431. },
  3432. maxDate: function() {
  3433. return $module.data(metadata.maxDate) || null;
  3434. },
  3435. monthOffset: function () {
  3436. return $module.data(metadata.monthOffset) || 0;
  3437. },
  3438. mode: function () {
  3439. //only returns valid modes for the current settings
  3440. var mode = $module.data(metadata.mode) || settings.startMode;
  3441. var validModes = module.get.validModes();
  3442. if ($.inArray(mode, validModes) >= 0) {
  3443. return mode;
  3444. }
  3445. return settings.type === 'time' ? 'hour' :
  3446. settings.type === 'month' ? 'month' :
  3447. settings.type === 'year' ? 'year' : 'day';
  3448. },
  3449. validModes: function () {
  3450. var validModes = [];
  3451. if (settings.type !== 'time') {
  3452. if (!settings.disableYear || settings.type === 'year') {
  3453. validModes.push('year');
  3454. }
  3455. if (!(settings.disableMonth || settings.type === 'year') || settings.type === 'month') {
  3456. validModes.push('month');
  3457. }
  3458. if (settings.type.indexOf('date') >= 0) {
  3459. validModes.push('day');
  3460. }
  3461. }
  3462. if (settings.type.indexOf('time') >= 0) {
  3463. validModes.push('hour');
  3464. if (!settings.disableMinute) {
  3465. validModes.push('minute');
  3466. }
  3467. }
  3468. return validModes;
  3469. },
  3470. isTouch: function () {
  3471. try {
  3472. document.createEvent('TouchEvent');
  3473. return true;
  3474. }
  3475. catch (e) {
  3476. return false;
  3477. }
  3478. },
  3479. calendarModule: function (selector) {
  3480. if (!selector) {
  3481. return null;
  3482. }
  3483. if (!(selector instanceof $)) {
  3484. selector = $(selector).first();
  3485. }
  3486. //assume range related calendars are using the same namespace
  3487. return selector.data(moduleNamespace);
  3488. }
  3489. },
  3490. set: {
  3491. date: function (date, updateInput, fireChange) {
  3492. updateInput = updateInput !== false;
  3493. fireChange = fireChange !== false;
  3494. date = module.helper.sanitiseDate(date);
  3495. date = module.helper.dateInRange(date);
  3496. var mode = module.get.mode();
  3497. var text = formatter.datetime(date, settings);
  3498. if (fireChange && settings.onChange.call(element, date, text, mode) === false) {
  3499. return false;
  3500. }
  3501. module.set.focusDate(date);
  3502. if (settings.isDisabled(date, mode)) {
  3503. return false;
  3504. }
  3505. var endDate = module.get.endDate();
  3506. if (!!endDate && !!date && date > endDate) {
  3507. //selected date is greater than end date in range, so clear end date
  3508. module.set.endDate(undefined);
  3509. }
  3510. module.set.dataKeyValue(metadata.date, date);
  3511. if (updateInput && $input.length) {
  3512. $input.val(text);
  3513. }
  3514. },
  3515. startDate: function (date, refreshCalendar) {
  3516. date = module.helper.sanitiseDate(date);
  3517. var startModule = module.get.calendarModule(settings.startCalendar);
  3518. if (startModule) {
  3519. startModule.set.date(date);
  3520. }
  3521. module.set.dataKeyValue(metadata.startDate, date, refreshCalendar);
  3522. },
  3523. endDate: function (date, refreshCalendar) {
  3524. date = module.helper.sanitiseDate(date);
  3525. var endModule = module.get.calendarModule(settings.endCalendar);
  3526. if (endModule) {
  3527. endModule.set.date(date);
  3528. }
  3529. module.set.dataKeyValue(metadata.endDate, date, refreshCalendar);
  3530. },
  3531. focusDate: function (date, refreshCalendar, updateFocus, updateRange) {
  3532. date = module.helper.sanitiseDate(date);
  3533. date = module.helper.dateInRange(date);
  3534. var isDay = module.get.mode() === 'day';
  3535. var oldFocusDate = module.get.focusDate();
  3536. if (isDay && date && oldFocusDate) {
  3537. var yearDelta = date.getFullYear() - oldFocusDate.getFullYear();
  3538. var monthDelta = yearDelta * 12 + date.getMonth() - oldFocusDate.getMonth();
  3539. if (monthDelta) {
  3540. var monthOffset = module.get.monthOffset() - monthDelta;
  3541. module.set.monthOffset(monthOffset, false);
  3542. }
  3543. }
  3544. var changed = module.set.dataKeyValue(metadata.focusDate, date, refreshCalendar);
  3545. updateFocus = (updateFocus !== false && changed && refreshCalendar === false) || focusDateUsedForRange != updateRange;
  3546. focusDateUsedForRange = updateRange;
  3547. if (updateFocus) {
  3548. module.update.focus(updateRange);
  3549. }
  3550. },
  3551. minDate: function (date) {
  3552. date = module.helper.sanitiseDate(date);
  3553. if (settings.maxDate !== null && settings.maxDate <= date) {
  3554. module.verbose('Unable to set minDate variable bigger that maxDate variable', date, settings.maxDate);
  3555. } else {
  3556. module.setting('minDate', date);
  3557. module.set.dataKeyValue(metadata.minDate, date);
  3558. }
  3559. },
  3560. maxDate: function (date) {
  3561. date = module.helper.sanitiseDate(date);
  3562. if (settings.minDate !== null && settings.minDate >= date) {
  3563. module.verbose('Unable to set maxDate variable lower that minDate variable', date, settings.minDate);
  3564. } else {
  3565. module.setting('maxDate', date);
  3566. module.set.dataKeyValue(metadata.maxDate, date);
  3567. }
  3568. },
  3569. monthOffset: function (monthOffset, refreshCalendar) {
  3570. var multiMonth = Math.max(settings.multiMonth, 1);
  3571. monthOffset = Math.max(1 - multiMonth, Math.min(0, monthOffset));
  3572. module.set.dataKeyValue(metadata.monthOffset, monthOffset, refreshCalendar);
  3573. },
  3574. mode: function (mode, refreshCalendar) {
  3575. module.set.dataKeyValue(metadata.mode, mode, refreshCalendar);
  3576. },
  3577. dataKeyValue: function (key, value, refreshCalendar) {
  3578. var oldValue = $module.data(key);
  3579. var equal = oldValue === value || (oldValue <= value && oldValue >= value); //equality test for dates and string objects
  3580. if (value) {
  3581. $module.data(key, value);
  3582. } else {
  3583. $module.removeData(key);
  3584. }
  3585. refreshCalendar = refreshCalendar !== false && !equal;
  3586. if (refreshCalendar) {
  3587. module.refresh();
  3588. }
  3589. return !equal;
  3590. }
  3591. },
  3592. selectDate: function (date, forceSet) {
  3593. module.verbose('New date selection', date);
  3594. var mode = module.get.mode();
  3595. var complete = forceSet || mode === 'minute' ||
  3596. (settings.disableMinute && mode === 'hour') ||
  3597. (settings.type === 'date' && mode === 'day') ||
  3598. (settings.type === 'month' && mode === 'month') ||
  3599. (settings.type === 'year' && mode === 'year');
  3600. if (complete) {
  3601. var canceled = module.set.date(date) === false;
  3602. if (!canceled && settings.closable) {
  3603. module.popup('hide');
  3604. //if this is a range calendar, show the end date calendar popup and focus the input
  3605. var endModule = module.get.calendarModule(settings.endCalendar);
  3606. if (endModule) {
  3607. endModule.popup('show');
  3608. endModule.focus();
  3609. }
  3610. }
  3611. } else {
  3612. var newMode = mode === 'year' ? (!settings.disableMonth ? 'month' : 'day') :
  3613. mode === 'month' ? 'day' : mode === 'day' ? 'hour' : 'minute';
  3614. module.set.mode(newMode);
  3615. if (mode === 'hour' || (mode === 'day' && module.get.date())) {
  3616. //the user has chosen enough to consider a valid date/time has been chosen
  3617. module.set.date(date);
  3618. } else {
  3619. module.set.focusDate(date);
  3620. }
  3621. }
  3622. },
  3623. changeDate: function (date) {
  3624. module.set.date(date);
  3625. },
  3626. clear: function () {
  3627. module.set.date(undefined);
  3628. },
  3629. popup: function () {
  3630. return $activator.popup.apply($activator, arguments);
  3631. },
  3632. focus: function () {
  3633. if ($input.length) {
  3634. $input.focus();
  3635. } else {
  3636. $container.focus();
  3637. }
  3638. },
  3639. blur: function () {
  3640. if ($input.length) {
  3641. $input.blur();
  3642. } else {
  3643. $container.blur();
  3644. }
  3645. },
  3646. helper: {
  3647. isDisabled: function(date, mode) {
  3648. return mode === 'day' && ((settings.disabledDaysOfWeek.indexOf(date.getDay()) !== -1) || settings.disabledDates.some(function(d){
  3649. if(typeof d === 'string') {
  3650. d = module.helper.sanitiseDate(d);
  3651. }
  3652. if (d instanceof Date) {
  3653. return module.helper.dateEqual(date, d, mode);
  3654. }
  3655. if (d !== null && typeof d === 'object' && d[metadata.date]) {
  3656. return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
  3657. }
  3658. }));
  3659. },
  3660. isEnabled: function(date, mode) {
  3661. if (mode === 'day') {
  3662. return settings.enabledDates.length === 0 || settings.enabledDates.some(function(d){
  3663. if(typeof d === 'string') {
  3664. d = module.helper.sanitiseDate(d);
  3665. }
  3666. if (d instanceof Date) {
  3667. return module.helper.dateEqual(date, d, mode);
  3668. }
  3669. if (d !== null && typeof d === 'object' && d[metadata.date]) {
  3670. return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
  3671. }
  3672. });
  3673. } else {
  3674. return true;
  3675. }
  3676. },
  3677. findDayAsObject: function(date, mode, dates) {
  3678. if (mode === 'day') {
  3679. var i = 0, il = dates.length;
  3680. var d;
  3681. for (; i < il; i++) {
  3682. d = dates[i];
  3683. if(typeof d === 'string') {
  3684. d = module.helper.sanitiseDate(d);
  3685. }
  3686. if (d instanceof Date && module.helper.dateEqual(date, d, mode)) {
  3687. var dateObject = {};
  3688. dateObject[metadata.date] = d;
  3689. return dateObject;
  3690. }
  3691. else if (d !== null && typeof d === 'object' && d[metadata.date] && module.helper.dateEqual(date,module.helper.sanitiseDate(d[metadata.date]), mode) ) {
  3692. return d;
  3693. }
  3694. }
  3695. }
  3696. return null;
  3697. },
  3698. sanitiseDate: function (date) {
  3699. if (!date) {
  3700. return undefined;
  3701. }
  3702. if (!(date instanceof Date)) {
  3703. date = parser.date('' + date, settings);
  3704. }
  3705. if (!date || date === null || isNaN(date.getTime())) {
  3706. return undefined;
  3707. }
  3708. return date;
  3709. },
  3710. dateDiff: function (date1, date2, mode) {
  3711. mode = mode || 'day';
  3712. var isTimeOnly = settings.type === 'time';
  3713. var isYear = mode === 'year';
  3714. var isYearOrMonth = isYear || mode === 'month';
  3715. var isMinute = mode === 'minute';
  3716. var isHourOrMinute = isMinute || mode === 'hour';
  3717. //only care about a minute accuracy of settings.minTimeGap
  3718. date1 = new Date(
  3719. isTimeOnly ? 2000 : date1.getFullYear(),
  3720. isTimeOnly ? 0 : isYear ? 0 : date1.getMonth(),
  3721. isTimeOnly ? 1 : isYearOrMonth ? 1 : date1.getDate(),
  3722. !isHourOrMinute ? 0 : date1.getHours(),
  3723. !isMinute ? 0 : settings.minTimeGap * Math.floor(date1.getMinutes() / settings.minTimeGap));
  3724. date2 = new Date(
  3725. isTimeOnly ? 2000 : date2.getFullYear(),
  3726. isTimeOnly ? 0 : isYear ? 0 : date2.getMonth(),
  3727. isTimeOnly ? 1 : isYearOrMonth ? 1 : date2.getDate(),
  3728. !isHourOrMinute ? 0 : date2.getHours(),
  3729. !isMinute ? 0 : settings.minTimeGap * Math.floor(date2.getMinutes() / settings.minTimeGap));
  3730. return date2.getTime() - date1.getTime();
  3731. },
  3732. dateEqual: function (date1, date2, mode) {
  3733. return !!date1 && !!date2 && module.helper.dateDiff(date1, date2, mode) === 0;
  3734. },
  3735. isDateInRange: function (date, mode, minDate, maxDate) {
  3736. if (!minDate && !maxDate) {
  3737. var startDate = module.get.startDate();
  3738. minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
  3739. maxDate = settings.maxDate;
  3740. }
  3741. minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
  3742. return !(!date ||
  3743. (minDate && module.helper.dateDiff(date, minDate, mode) > 0) ||
  3744. (maxDate && module.helper.dateDiff(maxDate, date, mode) > 0));
  3745. },
  3746. dateInRange: function (date, minDate, maxDate) {
  3747. if (!minDate && !maxDate) {
  3748. var startDate = module.get.startDate();
  3749. minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
  3750. maxDate = settings.maxDate;
  3751. }
  3752. minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
  3753. var isTimeOnly = settings.type === 'time';
  3754. return !date ? date :
  3755. (minDate && module.helper.dateDiff(date, minDate, 'minute') > 0) ?
  3756. (isTimeOnly ? module.helper.mergeDateTime(date, minDate) : minDate) :
  3757. (maxDate && module.helper.dateDiff(maxDate, date, 'minute') > 0) ?
  3758. (isTimeOnly ? module.helper.mergeDateTime(date, maxDate) : maxDate) :
  3759. date;
  3760. },
  3761. mergeDateTime: function (date, time) {
  3762. return (!date || !time) ? time :
  3763. new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes());
  3764. }
  3765. },
  3766. setting: function (name, value) {
  3767. module.debug('Changing setting', name, value);
  3768. if ($.isPlainObject(name)) {
  3769. $.extend(true, settings, name);
  3770. }
  3771. else if (value !== undefined) {
  3772. if ($.isPlainObject(settings[name])) {
  3773. $.extend(true, settings[name], value);
  3774. }
  3775. else {
  3776. settings[name] = value;
  3777. }
  3778. }
  3779. else {
  3780. return settings[name];
  3781. }
  3782. },
  3783. internal: function (name, value) {
  3784. if( $.isPlainObject(name) ) {
  3785. $.extend(true, module, name);
  3786. }
  3787. else if(value !== undefined) {
  3788. module[name] = value;
  3789. }
  3790. else {
  3791. return module[name];
  3792. }
  3793. },
  3794. debug: function () {
  3795. if (!settings.silent && settings.debug) {
  3796. if (settings.performance) {
  3797. module.performance.log(arguments);
  3798. }
  3799. else {
  3800. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  3801. module.debug.apply(console, arguments);
  3802. }
  3803. }
  3804. },
  3805. verbose: function () {
  3806. if (!settings.silent && settings.verbose && settings.debug) {
  3807. if (settings.performance) {
  3808. module.performance.log(arguments);
  3809. }
  3810. else {
  3811. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  3812. module.verbose.apply(console, arguments);
  3813. }
  3814. }
  3815. },
  3816. error: function () {
  3817. if (!settings.silent) {
  3818. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  3819. module.error.apply(console, arguments);
  3820. }
  3821. },
  3822. performance: {
  3823. log: function (message) {
  3824. var
  3825. currentTime,
  3826. executionTime,
  3827. previousTime
  3828. ;
  3829. if (settings.performance) {
  3830. currentTime = new Date().getTime();
  3831. previousTime = time || currentTime;
  3832. executionTime = currentTime - previousTime;
  3833. time = currentTime;
  3834. performance.push({
  3835. 'Name': message[0],
  3836. 'Arguments': [].slice.call(message, 1) || '',
  3837. 'Element': element,
  3838. 'Execution Time': executionTime
  3839. });
  3840. }
  3841. clearTimeout(module.performance.timer);
  3842. module.performance.timer = setTimeout(module.performance.display, 500);
  3843. },
  3844. display: function () {
  3845. var
  3846. title = settings.name + ':',
  3847. totalTime = 0
  3848. ;
  3849. time = false;
  3850. clearTimeout(module.performance.timer);
  3851. $.each(performance, function (index, data) {
  3852. totalTime += data['Execution Time'];
  3853. });
  3854. title += ' ' + totalTime + 'ms';
  3855. if (moduleSelector) {
  3856. title += ' \'' + moduleSelector + '\'';
  3857. }
  3858. if ((console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  3859. console.groupCollapsed(title);
  3860. if (console.table) {
  3861. console.table(performance);
  3862. }
  3863. else {
  3864. $.each(performance, function (index, data) {
  3865. console.log(data['Name'] + ': ' + data['Execution Time'] + 'ms');
  3866. });
  3867. }
  3868. console.groupEnd();
  3869. }
  3870. performance = [];
  3871. }
  3872. },
  3873. invoke: function (query, passedArguments, context) {
  3874. var
  3875. object = instance,
  3876. maxDepth,
  3877. found,
  3878. response
  3879. ;
  3880. passedArguments = passedArguments || queryArguments;
  3881. context = element || context;
  3882. if (typeof query == 'string' && object !== undefined) {
  3883. query = query.split(/[\. ]/);
  3884. maxDepth = query.length - 1;
  3885. $.each(query, function (depth, value) {
  3886. var camelCaseValue = (depth != maxDepth)
  3887. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  3888. : query
  3889. ;
  3890. if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) {
  3891. object = object[camelCaseValue];
  3892. }
  3893. else if (object[camelCaseValue] !== undefined) {
  3894. found = object[camelCaseValue];
  3895. return false;
  3896. }
  3897. else if ($.isPlainObject(object[value]) && (depth != maxDepth)) {
  3898. object = object[value];
  3899. }
  3900. else if (object[value] !== undefined) {
  3901. found = object[value];
  3902. return false;
  3903. }
  3904. else {
  3905. module.error(error.method, query);
  3906. return false;
  3907. }
  3908. });
  3909. }
  3910. if ($.isFunction(found)) {
  3911. response = found.apply(context, passedArguments);
  3912. }
  3913. else if (found !== undefined) {
  3914. response = found;
  3915. }
  3916. if (Array.isArray(returnedValue)) {
  3917. returnedValue.push(response);
  3918. }
  3919. else if (returnedValue !== undefined) {
  3920. returnedValue = [returnedValue, response];
  3921. }
  3922. else if (response !== undefined) {
  3923. returnedValue = response;
  3924. }
  3925. return found;
  3926. }
  3927. };
  3928. if (methodInvoked) {
  3929. if (instance === undefined) {
  3930. module.initialize();
  3931. }
  3932. module.invoke(query);
  3933. }
  3934. else {
  3935. if (instance !== undefined) {
  3936. instance.invoke('destroy');
  3937. }
  3938. module.initialize();
  3939. }
  3940. })
  3941. ;
  3942. return (returnedValue !== undefined)
  3943. ? returnedValue
  3944. : this
  3945. ;
  3946. };
  3947. $.fn.calendar.settings = {
  3948. name : 'Calendar',
  3949. namespace : 'calendar',
  3950. silent: false,
  3951. debug: false,
  3952. verbose: false,
  3953. performance: false,
  3954. type : 'datetime', // picker type, can be 'datetime', 'date', 'time', 'month', or 'year'
  3955. firstDayOfWeek : 0, // day for first day column (0 = Sunday)
  3956. constantHeight : true, // add rows to shorter months to keep day calendar height consistent (6 rows)
  3957. today : false, // show a 'today/now' button at the bottom of the calendar
  3958. closable : true, // close the popup after selecting a date/time
  3959. monthFirst : true, // month before day when parsing/converting date from/to text
  3960. touchReadonly : true, // set input to readonly on touch devices
  3961. inline : false, // create the calendar inline instead of inside a popup
  3962. on : null, // when to show the popup (defaults to 'focus' for input, 'click' for others)
  3963. initialDate : null, // date to display initially when no date is selected (null = now)
  3964. startMode : false, // display mode to start in, can be 'year', 'month', 'day', 'hour', 'minute' (false = 'day')
  3965. minDate : null, // minimum date/time that can be selected, dates/times before are disabled
  3966. maxDate : null, // maximum date/time that can be selected, dates/times after are disabled
  3967. ampm : true, // show am/pm in time mode
  3968. disableYear : false, // disable year selection mode
  3969. disableMonth : false, // disable month selection mode
  3970. disableMinute : false, // disable minute selection mode
  3971. formatInput : true, // format the input text upon input blur and module creation
  3972. startCalendar : null, // jquery object or selector for another calendar that represents the start date of a date range
  3973. endCalendar : null, // jquery object or selector for another calendar that represents the end date of a date range
  3974. multiMonth : 1, // show multiple months when in 'day' mode
  3975. minTimeGap : 5,
  3976. showWeekNumbers : null, // show Number of Week at the very first column of a dayView
  3977. disabledDates : [], // specific day(s) which won't be selectable and contain additional information.
  3978. disabledDaysOfWeek : [], // day(s) which won't be selectable(s) (0 = Sunday)
  3979. enabledDates : [], // specific day(s) which will be selectable, all other days will be disabled
  3980. eventDates : [], // specific day(s) which will be shown in a different color and using tooltips
  3981. centuryBreak : 60, // starting short year until 99 where it will be assumed to belong to the last century
  3982. currentCentury : 2000, // century to be added to 2-digit years (00 to {centuryBreak}-1)
  3983. selectAdjacentDays : false, // The calendar can show dates from adjacent month. These adjacent month dates can also be made selectable.
  3984. // popup options ('popup', 'on', 'hoverable', and show/hide callbacks are overridden)
  3985. popupOptions: {
  3986. position: 'bottom left',
  3987. lastResort: 'bottom left',
  3988. prefer: 'opposite',
  3989. hideOnScroll: false
  3990. },
  3991. text: {
  3992. days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
  3993. months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
  3994. monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
  3995. today: 'Today',
  3996. now: 'Now',
  3997. am: 'AM',
  3998. pm: 'PM',
  3999. weekNo: 'Week'
  4000. },
  4001. formatter: {
  4002. header: function (date, mode, settings) {
  4003. return mode === 'year' ? settings.formatter.yearHeader(date, settings) :
  4004. mode === 'month' ? settings.formatter.monthHeader(date, settings) :
  4005. mode === 'day' ? settings.formatter.dayHeader(date, settings) :
  4006. mode === 'hour' ? settings.formatter.hourHeader(date, settings) :
  4007. settings.formatter.minuteHeader(date, settings);
  4008. },
  4009. yearHeader: function (date, settings) {
  4010. var decadeYear = Math.ceil(date.getFullYear() / 10) * 10;
  4011. return (decadeYear - 9) + ' - ' + (decadeYear + 2);
  4012. },
  4013. monthHeader: function (date, settings) {
  4014. return date.getFullYear();
  4015. },
  4016. dayHeader: function (date, settings) {
  4017. var month = settings.text.months[date.getMonth()];
  4018. var year = date.getFullYear();
  4019. return month + ' ' + year;
  4020. },
  4021. hourHeader: function (date, settings) {
  4022. return settings.formatter.date(date, settings);
  4023. },
  4024. minuteHeader: function (date, settings) {
  4025. return settings.formatter.date(date, settings);
  4026. },
  4027. dayColumnHeader: function (day, settings) {
  4028. return settings.text.days[day];
  4029. },
  4030. datetime: function (date, settings) {
  4031. if (!date) {
  4032. return '';
  4033. }
  4034. var day = settings.type === 'time' ? '' : settings.formatter.date(date, settings);
  4035. var time = settings.type.indexOf('time') < 0 ? '' : settings.formatter.time(date, settings, false);
  4036. var separator = settings.type === 'datetime' ? ' ' : '';
  4037. return day + separator + time;
  4038. },
  4039. date: function (date, settings) {
  4040. if (!date) {
  4041. return '';
  4042. }
  4043. var day = date.getDate();
  4044. var month = settings.text.months[date.getMonth()];
  4045. var year = date.getFullYear();
  4046. return settings.type === 'year' ? year :
  4047. settings.type === 'month' ? month + ' ' + year :
  4048. (settings.monthFirst ? month + ' ' + day : day + ' ' + month) + ', ' + year;
  4049. },
  4050. time: function (date, settings, forCalendar) {
  4051. if (!date) {
  4052. return '';
  4053. }
  4054. var hour = date.getHours();
  4055. var minute = date.getMinutes();
  4056. var ampm = '';
  4057. if (settings.ampm) {
  4058. ampm = ' ' + (hour < 12 ? settings.text.am : settings.text.pm);
  4059. hour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
  4060. }
  4061. return hour + ':' + (minute < 10 ? '0' : '') + minute + ampm;
  4062. },
  4063. today: function (settings) {
  4064. return settings.type === 'date' ? settings.text.today : settings.text.now;
  4065. },
  4066. cell: function (cell, date, cellOptions) {
  4067. }
  4068. },
  4069. parser: {
  4070. date: function (text, settings) {
  4071. if (text instanceof Date) {
  4072. return text;
  4073. }
  4074. if (!text) {
  4075. return null;
  4076. }
  4077. text = ('' + text).trim().toLowerCase();
  4078. if (text.length === 0) {
  4079. return null;
  4080. }
  4081. var textDate = new Date(text);
  4082. if(!isNaN(textDate.getDate())) {
  4083. return textDate;
  4084. }
  4085. var i, j, k;
  4086. var minute = -1, hour = -1, day = -1, month = -1, year = -1;
  4087. var isAm = undefined;
  4088. var isTimeOnly = settings.type === 'time';
  4089. var isDateOnly = settings.type.indexOf('time') < 0;
  4090. var words = text.split(settings.regExp.dateWords);
  4091. var numbers = text.split(settings.regExp.dateNumbers);
  4092. if (!isDateOnly) {
  4093. //am/pm
  4094. isAm = $.inArray(settings.text.am.toLowerCase(), words) >= 0 ? true :
  4095. $.inArray(settings.text.pm.toLowerCase(), words) >= 0 ? false : undefined;
  4096. //time with ':'
  4097. for (i = 0; i < numbers.length; i++) {
  4098. var number = numbers[i];
  4099. if (number.indexOf(':') >= 0) {
  4100. if (hour < 0 || minute < 0) {
  4101. var parts = number.split(':');
  4102. for (k = 0; k < Math.min(2, parts.length); k++) {
  4103. j = parseInt(parts[k]);
  4104. if (isNaN(j)) {
  4105. j = 0;
  4106. }
  4107. if (k === 0) {
  4108. hour = j % 24;
  4109. } else {
  4110. minute = j % 60;
  4111. }
  4112. }
  4113. }
  4114. numbers.splice(i, 1);
  4115. }
  4116. }
  4117. }
  4118. if (!isTimeOnly) {
  4119. //textual month
  4120. for (i = 0; i < words.length; i++) {
  4121. var word = words[i];
  4122. if (word.length <= 0) {
  4123. continue;
  4124. }
  4125. word = word.substring(0, Math.min(word.length, 3));
  4126. for (j = 0; j < settings.text.months.length; j++) {
  4127. var monthString = settings.text.months[j];
  4128. monthString = monthString.substring(0, Math.min(word.length, Math.min(monthString.length, 3))).toLowerCase();
  4129. if (monthString === word) {
  4130. month = j + 1;
  4131. break;
  4132. }
  4133. }
  4134. if (month >= 0) {
  4135. break;
  4136. }
  4137. }
  4138. //year > settings.centuryBreak
  4139. for (i = 0; i < numbers.length; i++) {
  4140. j = parseInt(numbers[i]);
  4141. if (isNaN(j)) {
  4142. continue;
  4143. }
  4144. if (j >= settings.centuryBreak && i === numbers.length-1) {
  4145. if (j <= 99) {
  4146. j += settings.currentCentury - 100;
  4147. }
  4148. year = j;
  4149. numbers.splice(i, 1);
  4150. break;
  4151. }
  4152. }
  4153. //numeric month
  4154. if (month < 0) {
  4155. for (i = 0; i < numbers.length; i++) {
  4156. k = i > 1 || settings.monthFirst ? i : i === 1 ? 0 : 1;
  4157. j = parseInt(numbers[k]);
  4158. if (isNaN(j)) {
  4159. continue;
  4160. }
  4161. if (1 <= j && j <= 12) {
  4162. month = j;
  4163. numbers.splice(k, 1);
  4164. break;
  4165. }
  4166. }
  4167. }
  4168. //day
  4169. for (i = 0; i < numbers.length; i++) {
  4170. j = parseInt(numbers[i]);
  4171. if (isNaN(j)) {
  4172. continue;
  4173. }
  4174. if (1 <= j && j <= 31) {
  4175. day = j;
  4176. numbers.splice(i, 1);
  4177. break;
  4178. }
  4179. }
  4180. //year <= settings.centuryBreak
  4181. if (year < 0) {
  4182. for (i = numbers.length - 1; i >= 0; i--) {
  4183. j = parseInt(numbers[i]);
  4184. if (isNaN(j)) {
  4185. continue;
  4186. }
  4187. if (j <= 99) {
  4188. j += settings.currentCentury;
  4189. }
  4190. year = j;
  4191. numbers.splice(i, 1);
  4192. break;
  4193. }
  4194. }
  4195. }
  4196. if (!isDateOnly) {
  4197. //hour
  4198. if (hour < 0) {
  4199. for (i = 0; i < numbers.length; i++) {
  4200. j = parseInt(numbers[i]);
  4201. if (isNaN(j)) {
  4202. continue;
  4203. }
  4204. if (0 <= j && j <= 23) {
  4205. hour = j;
  4206. numbers.splice(i, 1);
  4207. break;
  4208. }
  4209. }
  4210. }
  4211. //minute
  4212. if (minute < 0) {
  4213. for (i = 0; i < numbers.length; i++) {
  4214. j = parseInt(numbers[i]);
  4215. if (isNaN(j)) {
  4216. continue;
  4217. }
  4218. if (0 <= j && j <= 59) {
  4219. minute = j;
  4220. numbers.splice(i, 1);
  4221. break;
  4222. }
  4223. }
  4224. }
  4225. }
  4226. if (minute < 0 && hour < 0 && day < 0 && month < 0 && year < 0) {
  4227. return null;
  4228. }
  4229. if (minute < 0) {
  4230. minute = 0;
  4231. }
  4232. if (hour < 0) {
  4233. hour = 0;
  4234. }
  4235. if (day < 0) {
  4236. day = 1;
  4237. }
  4238. if (month < 0) {
  4239. month = 1;
  4240. }
  4241. if (year < 0) {
  4242. year = new Date().getFullYear();
  4243. }
  4244. if (isAm !== undefined) {
  4245. if (isAm) {
  4246. if (hour === 12) {
  4247. hour = 0;
  4248. }
  4249. } else if (hour < 12) {
  4250. hour += 12;
  4251. }
  4252. }
  4253. var date = new Date(year, month - 1, day, hour, minute);
  4254. if (date.getMonth() !== month - 1 || date.getFullYear() !== year) {
  4255. //month or year don't match up, switch to last day of the month
  4256. date = new Date(year, month, 0, hour, minute);
  4257. }
  4258. return isNaN(date.getTime()) ? null : date;
  4259. }
  4260. },
  4261. // callback when date changes, return false to cancel the change
  4262. onChange: function (date, text, mode) {
  4263. return true;
  4264. },
  4265. // callback before show animation, return false to prevent show
  4266. onShow: function () {
  4267. },
  4268. // callback after show animation
  4269. onVisible: function () {
  4270. },
  4271. // callback before hide animation, return false to prevent hide
  4272. onHide: function () {
  4273. },
  4274. // callback after hide animation
  4275. onHidden: function () {
  4276. },
  4277. // callback before item is selected, return false to prevent selection
  4278. onSelect: function (date, mode) {
  4279. },
  4280. // is the given date disabled?
  4281. isDisabled: function (date, mode) {
  4282. return false;
  4283. },
  4284. selector: {
  4285. popup: '.ui.popup',
  4286. input: 'input',
  4287. activator: 'input',
  4288. append: '.inline.field,.inline.fields'
  4289. },
  4290. regExp: {
  4291. dateWords: /[^A-Za-z\u00C0-\u024F]+/g,
  4292. dateNumbers: /[^\d:]+/g
  4293. },
  4294. error: {
  4295. popup: 'UI Popup, a required component is not included in this page',
  4296. method: 'The method you called is not defined.'
  4297. },
  4298. className: {
  4299. calendar: 'calendar',
  4300. active: 'active',
  4301. popup: 'ui popup',
  4302. grid: 'ui equal width grid',
  4303. column: 'column',
  4304. table: 'ui celled center aligned unstackable table',
  4305. prev: 'prev link',
  4306. next: 'next link',
  4307. prevIcon: 'chevron left icon',
  4308. nextIcon: 'chevron right icon',
  4309. link: 'link',
  4310. cell: 'link',
  4311. disabledCell: 'disabled',
  4312. weekCell: 'disabled',
  4313. adjacentCell: 'adjacent',
  4314. activeCell: 'active',
  4315. rangeCell: 'range',
  4316. focusCell: 'focus',
  4317. todayCell: 'today',
  4318. today: 'today link'
  4319. },
  4320. metadata: {
  4321. date: 'date',
  4322. focusDate: 'focusDate',
  4323. startDate: 'startDate',
  4324. endDate: 'endDate',
  4325. minDate: 'minDate',
  4326. maxDate: 'maxDate',
  4327. mode: 'mode',
  4328. monthOffset: 'monthOffset',
  4329. message: 'message',
  4330. class: 'class'
  4331. },
  4332. eventClass: 'blue'
  4333. };
  4334. })(jQuery, window, document);
  4335. /*!
  4336. * # Fomantic-UI - Checkbox
  4337. * http://github.com/fomantic/Fomantic-UI/
  4338. *
  4339. *
  4340. * Released under the MIT license
  4341. * http://opensource.org/licenses/MIT
  4342. *
  4343. */
  4344. ;(function ($, window, document, undefined) {
  4345. 'use strict';
  4346. $.isFunction = $.isFunction || function(obj) {
  4347. return typeof obj === "function" && typeof obj.nodeType !== "number";
  4348. };
  4349. window = (typeof window != 'undefined' && window.Math == Math)
  4350. ? window
  4351. : (typeof self != 'undefined' && self.Math == Math)
  4352. ? self
  4353. : Function('return this')()
  4354. ;
  4355. $.fn.checkbox = function(parameters) {
  4356. var
  4357. $allModules = $(this),
  4358. moduleSelector = $allModules.selector || '',
  4359. time = new Date().getTime(),
  4360. performance = [],
  4361. query = arguments[0],
  4362. methodInvoked = (typeof query == 'string'),
  4363. queryArguments = [].slice.call(arguments, 1),
  4364. returnedValue
  4365. ;
  4366. $allModules
  4367. .each(function() {
  4368. var
  4369. settings = $.extend(true, {}, $.fn.checkbox.settings, parameters),
  4370. className = settings.className,
  4371. namespace = settings.namespace,
  4372. selector = settings.selector,
  4373. error = settings.error,
  4374. eventNamespace = '.' + namespace,
  4375. moduleNamespace = 'module-' + namespace,
  4376. $module = $(this),
  4377. $label = $(this).children(selector.label),
  4378. $input = $(this).children(selector.input),
  4379. input = $input[0],
  4380. initialLoad = false,
  4381. shortcutPressed = false,
  4382. instance = $module.data(moduleNamespace),
  4383. observer,
  4384. element = this,
  4385. module
  4386. ;
  4387. module = {
  4388. initialize: function() {
  4389. module.verbose('Initializing checkbox', settings);
  4390. module.create.label();
  4391. module.bind.events();
  4392. module.set.tabbable();
  4393. module.hide.input();
  4394. module.observeChanges();
  4395. module.instantiate();
  4396. module.setup();
  4397. },
  4398. instantiate: function() {
  4399. module.verbose('Storing instance of module', module);
  4400. instance = module;
  4401. $module
  4402. .data(moduleNamespace, module)
  4403. ;
  4404. },
  4405. destroy: function() {
  4406. module.verbose('Destroying module');
  4407. module.unbind.events();
  4408. module.show.input();
  4409. $module.removeData(moduleNamespace);
  4410. },
  4411. fix: {
  4412. reference: function() {
  4413. if( $module.is(selector.input) ) {
  4414. module.debug('Behavior called on <input> adjusting invoked element');
  4415. $module = $module.closest(selector.checkbox);
  4416. module.refresh();
  4417. }
  4418. }
  4419. },
  4420. setup: function() {
  4421. module.set.initialLoad();
  4422. if( module.is.indeterminate() ) {
  4423. module.debug('Initial value is indeterminate');
  4424. module.indeterminate();
  4425. }
  4426. else if( module.is.checked() ) {
  4427. module.debug('Initial value is checked');
  4428. module.check();
  4429. }
  4430. else {
  4431. module.debug('Initial value is unchecked');
  4432. module.uncheck();
  4433. }
  4434. module.remove.initialLoad();
  4435. },
  4436. refresh: function() {
  4437. $label = $module.children(selector.label);
  4438. $input = $module.children(selector.input);
  4439. input = $input[0];
  4440. },
  4441. hide: {
  4442. input: function() {
  4443. module.verbose('Modifying <input> z-index to be unselectable');
  4444. $input.addClass(className.hidden);
  4445. }
  4446. },
  4447. show: {
  4448. input: function() {
  4449. module.verbose('Modifying <input> z-index to be selectable');
  4450. $input.removeClass(className.hidden);
  4451. }
  4452. },
  4453. observeChanges: function() {
  4454. if('MutationObserver' in window) {
  4455. observer = new MutationObserver(function(mutations) {
  4456. module.debug('DOM tree modified, updating selector cache');
  4457. module.refresh();
  4458. });
  4459. observer.observe(element, {
  4460. childList : true,
  4461. subtree : true
  4462. });
  4463. module.debug('Setting up mutation observer', observer);
  4464. }
  4465. },
  4466. attachEvents: function(selector, event) {
  4467. var
  4468. $element = $(selector)
  4469. ;
  4470. event = $.isFunction(module[event])
  4471. ? module[event]
  4472. : module.toggle
  4473. ;
  4474. if($element.length > 0) {
  4475. module.debug('Attaching checkbox events to element', selector, event);
  4476. $element
  4477. .on('click' + eventNamespace, event)
  4478. ;
  4479. }
  4480. else {
  4481. module.error(error.notFound);
  4482. }
  4483. },
  4484. preventDefaultOnInputTarget: function() {
  4485. if(typeof event !== 'undefined' && $(event.target).is(selector.input)) {
  4486. module.verbose('Preventing default check action after manual check action');
  4487. event.preventDefault();
  4488. }
  4489. },
  4490. event: {
  4491. change: function(event) {
  4492. if( !module.should.ignoreCallbacks() ) {
  4493. settings.onChange.call(input);
  4494. }
  4495. },
  4496. click: function(event) {
  4497. var
  4498. $target = $(event.target)
  4499. ;
  4500. if( $target.is(selector.input) ) {
  4501. module.verbose('Using default check action on initialized checkbox');
  4502. return;
  4503. }
  4504. if( $target.is(selector.link) ) {
  4505. module.debug('Clicking link inside checkbox, skipping toggle');
  4506. return;
  4507. }
  4508. module.toggle();
  4509. $input.focus();
  4510. event.preventDefault();
  4511. },
  4512. keydown: function(event) {
  4513. var
  4514. key = event.which,
  4515. keyCode = {
  4516. enter : 13,
  4517. space : 32,
  4518. escape : 27,
  4519. left : 37,
  4520. up : 38,
  4521. right : 39,
  4522. down : 40
  4523. }
  4524. ;
  4525. var r = module.get.radios(),
  4526. rIndex = r.index($module),
  4527. rLen = r.length,
  4528. checkIndex = false;
  4529. if(key == keyCode.left || key == keyCode.up) {
  4530. checkIndex = (rIndex === 0 ? rLen : rIndex) - 1;
  4531. } else if(key == keyCode.right || key == keyCode.down) {
  4532. checkIndex = rIndex === rLen-1 ? 0 : rIndex+1;
  4533. }
  4534. if (!module.should.ignoreCallbacks() && checkIndex !== false) {
  4535. if(settings.beforeUnchecked.apply(input)===false) {
  4536. module.verbose('Option not allowed to be unchecked, cancelling key navigation');
  4537. return false;
  4538. }
  4539. if (settings.beforeChecked.apply($(r[checkIndex]).children(selector.input)[0])===false) {
  4540. module.verbose('Next option should not allow check, cancelling key navigation');
  4541. return false;
  4542. }
  4543. }
  4544. if(key == keyCode.escape) {
  4545. module.verbose('Escape key pressed blurring field');
  4546. $input.blur();
  4547. shortcutPressed = true;
  4548. }
  4549. else if(!event.ctrlKey && ( key == keyCode.space || (key == keyCode.enter && settings.enableEnterKey)) ) {
  4550. module.verbose('Enter/space key pressed, toggling checkbox');
  4551. module.toggle();
  4552. shortcutPressed = true;
  4553. }
  4554. else {
  4555. shortcutPressed = false;
  4556. }
  4557. },
  4558. keyup: function(event) {
  4559. if(shortcutPressed) {
  4560. event.preventDefault();
  4561. }
  4562. }
  4563. },
  4564. check: function() {
  4565. if( !module.should.allowCheck() ) {
  4566. return;
  4567. }
  4568. module.debug('Checking checkbox', $input);
  4569. module.set.checked();
  4570. if( !module.should.ignoreCallbacks() ) {
  4571. settings.onChecked.call(input);
  4572. module.trigger.change();
  4573. }
  4574. module.preventDefaultOnInputTarget();
  4575. },
  4576. uncheck: function() {
  4577. if( !module.should.allowUncheck() ) {
  4578. return;
  4579. }
  4580. module.debug('Unchecking checkbox');
  4581. module.set.unchecked();
  4582. if( !module.should.ignoreCallbacks() ) {
  4583. settings.onUnchecked.call(input);
  4584. module.trigger.change();
  4585. }
  4586. module.preventDefaultOnInputTarget();
  4587. },
  4588. indeterminate: function() {
  4589. if( module.should.allowIndeterminate() ) {
  4590. module.debug('Checkbox is already indeterminate');
  4591. return;
  4592. }
  4593. module.debug('Making checkbox indeterminate');
  4594. module.set.indeterminate();
  4595. if( !module.should.ignoreCallbacks() ) {
  4596. settings.onIndeterminate.call(input);
  4597. module.trigger.change();
  4598. }
  4599. },
  4600. determinate: function() {
  4601. if( module.should.allowDeterminate() ) {
  4602. module.debug('Checkbox is already determinate');
  4603. return;
  4604. }
  4605. module.debug('Making checkbox determinate');
  4606. module.set.determinate();
  4607. if( !module.should.ignoreCallbacks() ) {
  4608. settings.onDeterminate.call(input);
  4609. module.trigger.change();
  4610. }
  4611. },
  4612. enable: function() {
  4613. if( module.is.enabled() ) {
  4614. module.debug('Checkbox is already enabled');
  4615. return;
  4616. }
  4617. module.debug('Enabling checkbox');
  4618. module.set.enabled();
  4619. if( !module.should.ignoreCallbacks() ) {
  4620. settings.onEnable.call(input);
  4621. // preserve legacy callbacks
  4622. settings.onEnabled.call(input);
  4623. module.trigger.change();
  4624. }
  4625. },
  4626. disable: function() {
  4627. if( module.is.disabled() ) {
  4628. module.debug('Checkbox is already disabled');
  4629. return;
  4630. }
  4631. module.debug('Disabling checkbox');
  4632. module.set.disabled();
  4633. if( !module.should.ignoreCallbacks() ) {
  4634. settings.onDisable.call(input);
  4635. // preserve legacy callbacks
  4636. settings.onDisabled.call(input);
  4637. module.trigger.change();
  4638. }
  4639. },
  4640. get: {
  4641. radios: function() {
  4642. var
  4643. name = module.get.name()
  4644. ;
  4645. return $('input[name="' + name + '"]').closest(selector.checkbox);
  4646. },
  4647. otherRadios: function() {
  4648. return module.get.radios().not($module);
  4649. },
  4650. name: function() {
  4651. return $input.attr('name');
  4652. }
  4653. },
  4654. is: {
  4655. initialLoad: function() {
  4656. return initialLoad;
  4657. },
  4658. radio: function() {
  4659. return ($input.hasClass(className.radio) || $input.attr('type') == 'radio');
  4660. },
  4661. indeterminate: function() {
  4662. return $input.prop('indeterminate') !== undefined && $input.prop('indeterminate');
  4663. },
  4664. checked: function() {
  4665. return $input.prop('checked') !== undefined && $input.prop('checked');
  4666. },
  4667. disabled: function() {
  4668. return $input.prop('disabled') !== undefined && $input.prop('disabled');
  4669. },
  4670. enabled: function() {
  4671. return !module.is.disabled();
  4672. },
  4673. determinate: function() {
  4674. return !module.is.indeterminate();
  4675. },
  4676. unchecked: function() {
  4677. return !module.is.checked();
  4678. }
  4679. },
  4680. should: {
  4681. allowCheck: function() {
  4682. if(module.is.determinate() && module.is.checked() && !module.is.initialLoad() ) {
  4683. module.debug('Should not allow check, checkbox is already checked');
  4684. return false;
  4685. }
  4686. if(!module.should.ignoreCallbacks() && settings.beforeChecked.apply(input) === false) {
  4687. module.debug('Should not allow check, beforeChecked cancelled');
  4688. return false;
  4689. }
  4690. return true;
  4691. },
  4692. allowUncheck: function() {
  4693. if(module.is.determinate() && module.is.unchecked() && !module.is.initialLoad() ) {
  4694. module.debug('Should not allow uncheck, checkbox is already unchecked');
  4695. return false;
  4696. }
  4697. if(!module.should.ignoreCallbacks() && settings.beforeUnchecked.apply(input) === false) {
  4698. module.debug('Should not allow uncheck, beforeUnchecked cancelled');
  4699. return false;
  4700. }
  4701. return true;
  4702. },
  4703. allowIndeterminate: function() {
  4704. if(module.is.indeterminate() && !module.is.initialLoad() ) {
  4705. module.debug('Should not allow indeterminate, checkbox is already indeterminate');
  4706. return false;
  4707. }
  4708. if(!module.should.ignoreCallbacks() && settings.beforeIndeterminate.apply(input) === false) {
  4709. module.debug('Should not allow indeterminate, beforeIndeterminate cancelled');
  4710. return false;
  4711. }
  4712. return true;
  4713. },
  4714. allowDeterminate: function() {
  4715. if(module.is.determinate() && !module.is.initialLoad() ) {
  4716. module.debug('Should not allow determinate, checkbox is already determinate');
  4717. return false;
  4718. }
  4719. if(!module.should.ignoreCallbacks() && settings.beforeDeterminate.apply(input) === false) {
  4720. module.debug('Should not allow determinate, beforeDeterminate cancelled');
  4721. return false;
  4722. }
  4723. return true;
  4724. },
  4725. ignoreCallbacks: function() {
  4726. return (initialLoad && !settings.fireOnInit);
  4727. }
  4728. },
  4729. can: {
  4730. change: function() {
  4731. return !( $module.hasClass(className.disabled) || $module.hasClass(className.readOnly) || $input.prop('disabled') || $input.prop('readonly') );
  4732. },
  4733. uncheck: function() {
  4734. return (typeof settings.uncheckable === 'boolean')
  4735. ? settings.uncheckable
  4736. : !module.is.radio()
  4737. ;
  4738. }
  4739. },
  4740. set: {
  4741. initialLoad: function() {
  4742. initialLoad = true;
  4743. },
  4744. checked: function() {
  4745. module.verbose('Setting class to checked');
  4746. $module
  4747. .removeClass(className.indeterminate)
  4748. .addClass(className.checked)
  4749. ;
  4750. if( module.is.radio() ) {
  4751. module.uncheckOthers();
  4752. }
  4753. if(!module.is.indeterminate() && module.is.checked()) {
  4754. module.debug('Input is already checked, skipping input property change');
  4755. return;
  4756. }
  4757. module.verbose('Setting state to checked', input);
  4758. $input
  4759. .prop('indeterminate', false)
  4760. .prop('checked', true)
  4761. ;
  4762. },
  4763. unchecked: function() {
  4764. module.verbose('Removing checked class');
  4765. $module
  4766. .removeClass(className.indeterminate)
  4767. .removeClass(className.checked)
  4768. ;
  4769. if(!module.is.indeterminate() && module.is.unchecked() ) {
  4770. module.debug('Input is already unchecked');
  4771. return;
  4772. }
  4773. module.debug('Setting state to unchecked');
  4774. $input
  4775. .prop('indeterminate', false)
  4776. .prop('checked', false)
  4777. ;
  4778. },
  4779. indeterminate: function() {
  4780. module.verbose('Setting class to indeterminate');
  4781. $module
  4782. .addClass(className.indeterminate)
  4783. ;
  4784. if( module.is.indeterminate() ) {
  4785. module.debug('Input is already indeterminate, skipping input property change');
  4786. return;
  4787. }
  4788. module.debug('Setting state to indeterminate');
  4789. $input
  4790. .prop('indeterminate', true)
  4791. ;
  4792. },
  4793. determinate: function() {
  4794. module.verbose('Removing indeterminate class');
  4795. $module
  4796. .removeClass(className.indeterminate)
  4797. ;
  4798. if( module.is.determinate() ) {
  4799. module.debug('Input is already determinate, skipping input property change');
  4800. return;
  4801. }
  4802. module.debug('Setting state to determinate');
  4803. $input
  4804. .prop('indeterminate', false)
  4805. ;
  4806. },
  4807. disabled: function() {
  4808. module.verbose('Setting class to disabled');
  4809. $module
  4810. .addClass(className.disabled)
  4811. ;
  4812. if( module.is.disabled() ) {
  4813. module.debug('Input is already disabled, skipping input property change');
  4814. return;
  4815. }
  4816. module.debug('Setting state to disabled');
  4817. $input
  4818. .prop('disabled', 'disabled')
  4819. ;
  4820. },
  4821. enabled: function() {
  4822. module.verbose('Removing disabled class');
  4823. $module.removeClass(className.disabled);
  4824. if( module.is.enabled() ) {
  4825. module.debug('Input is already enabled, skipping input property change');
  4826. return;
  4827. }
  4828. module.debug('Setting state to enabled');
  4829. $input
  4830. .prop('disabled', false)
  4831. ;
  4832. },
  4833. tabbable: function() {
  4834. module.verbose('Adding tabindex to checkbox');
  4835. if( $input.attr('tabindex') === undefined) {
  4836. $input.attr('tabindex', 0);
  4837. }
  4838. }
  4839. },
  4840. remove: {
  4841. initialLoad: function() {
  4842. initialLoad = false;
  4843. }
  4844. },
  4845. trigger: {
  4846. change: function() {
  4847. var
  4848. events = document.createEvent('HTMLEvents'),
  4849. inputElement = $input[0]
  4850. ;
  4851. if(inputElement) {
  4852. module.verbose('Triggering native change event');
  4853. events.initEvent('change', true, false);
  4854. inputElement.dispatchEvent(events);
  4855. }
  4856. }
  4857. },
  4858. create: {
  4859. label: function() {
  4860. if($input.prevAll(selector.label).length > 0) {
  4861. $input.prev(selector.label).detach().insertAfter($input);
  4862. module.debug('Moving existing label', $label);
  4863. }
  4864. else if( !module.has.label() ) {
  4865. $label = $('<label>').insertAfter($input);
  4866. module.debug('Creating label', $label);
  4867. }
  4868. }
  4869. },
  4870. has: {
  4871. label: function() {
  4872. return ($label.length > 0);
  4873. }
  4874. },
  4875. bind: {
  4876. events: function() {
  4877. module.verbose('Attaching checkbox events');
  4878. $module
  4879. .on('click' + eventNamespace, module.event.click)
  4880. .on('change' + eventNamespace, module.event.change)
  4881. .on('keydown' + eventNamespace, selector.input, module.event.keydown)
  4882. .on('keyup' + eventNamespace, selector.input, module.event.keyup)
  4883. ;
  4884. }
  4885. },
  4886. unbind: {
  4887. events: function() {
  4888. module.debug('Removing events');
  4889. $module
  4890. .off(eventNamespace)
  4891. ;
  4892. }
  4893. },
  4894. uncheckOthers: function() {
  4895. var
  4896. $radios = module.get.otherRadios()
  4897. ;
  4898. module.debug('Unchecking other radios', $radios);
  4899. $radios.removeClass(className.checked);
  4900. },
  4901. toggle: function() {
  4902. if( !module.can.change() ) {
  4903. if(!module.is.radio()) {
  4904. module.debug('Checkbox is read-only or disabled, ignoring toggle');
  4905. }
  4906. return;
  4907. }
  4908. if( module.is.indeterminate() || module.is.unchecked() ) {
  4909. module.debug('Currently unchecked');
  4910. module.check();
  4911. }
  4912. else if( module.is.checked() && module.can.uncheck() ) {
  4913. module.debug('Currently checked');
  4914. module.uncheck();
  4915. }
  4916. },
  4917. setting: function(name, value) {
  4918. module.debug('Changing setting', name, value);
  4919. if( $.isPlainObject(name) ) {
  4920. $.extend(true, settings, name);
  4921. }
  4922. else if(value !== undefined) {
  4923. if($.isPlainObject(settings[name])) {
  4924. $.extend(true, settings[name], value);
  4925. }
  4926. else {
  4927. settings[name] = value;
  4928. }
  4929. }
  4930. else {
  4931. return settings[name];
  4932. }
  4933. },
  4934. internal: function(name, value) {
  4935. if( $.isPlainObject(name) ) {
  4936. $.extend(true, module, name);
  4937. }
  4938. else if(value !== undefined) {
  4939. module[name] = value;
  4940. }
  4941. else {
  4942. return module[name];
  4943. }
  4944. },
  4945. debug: function() {
  4946. if(!settings.silent && settings.debug) {
  4947. if(settings.performance) {
  4948. module.performance.log(arguments);
  4949. }
  4950. else {
  4951. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  4952. module.debug.apply(console, arguments);
  4953. }
  4954. }
  4955. },
  4956. verbose: function() {
  4957. if(!settings.silent && settings.verbose && settings.debug) {
  4958. if(settings.performance) {
  4959. module.performance.log(arguments);
  4960. }
  4961. else {
  4962. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  4963. module.verbose.apply(console, arguments);
  4964. }
  4965. }
  4966. },
  4967. error: function() {
  4968. if(!settings.silent) {
  4969. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  4970. module.error.apply(console, arguments);
  4971. }
  4972. },
  4973. performance: {
  4974. log: function(message) {
  4975. var
  4976. currentTime,
  4977. executionTime,
  4978. previousTime
  4979. ;
  4980. if(settings.performance) {
  4981. currentTime = new Date().getTime();
  4982. previousTime = time || currentTime;
  4983. executionTime = currentTime - previousTime;
  4984. time = currentTime;
  4985. performance.push({
  4986. 'Name' : message[0],
  4987. 'Arguments' : [].slice.call(message, 1) || '',
  4988. 'Element' : element,
  4989. 'Execution Time' : executionTime
  4990. });
  4991. }
  4992. clearTimeout(module.performance.timer);
  4993. module.performance.timer = setTimeout(module.performance.display, 500);
  4994. },
  4995. display: function() {
  4996. var
  4997. title = settings.name + ':',
  4998. totalTime = 0
  4999. ;
  5000. time = false;
  5001. clearTimeout(module.performance.timer);
  5002. $.each(performance, function(index, data) {
  5003. totalTime += data['Execution Time'];
  5004. });
  5005. title += ' ' + totalTime + 'ms';
  5006. if(moduleSelector) {
  5007. title += ' \'' + moduleSelector + '\'';
  5008. }
  5009. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  5010. console.groupCollapsed(title);
  5011. if(console.table) {
  5012. console.table(performance);
  5013. }
  5014. else {
  5015. $.each(performance, function(index, data) {
  5016. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  5017. });
  5018. }
  5019. console.groupEnd();
  5020. }
  5021. performance = [];
  5022. }
  5023. },
  5024. invoke: function(query, passedArguments, context) {
  5025. var
  5026. object = instance,
  5027. maxDepth,
  5028. found,
  5029. response
  5030. ;
  5031. passedArguments = passedArguments || queryArguments;
  5032. context = element || context;
  5033. if(typeof query == 'string' && object !== undefined) {
  5034. query = query.split(/[\. ]/);
  5035. maxDepth = query.length - 1;
  5036. $.each(query, function(depth, value) {
  5037. var camelCaseValue = (depth != maxDepth)
  5038. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  5039. : query
  5040. ;
  5041. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  5042. object = object[camelCaseValue];
  5043. }
  5044. else if( object[camelCaseValue] !== undefined ) {
  5045. found = object[camelCaseValue];
  5046. return false;
  5047. }
  5048. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  5049. object = object[value];
  5050. }
  5051. else if( object[value] !== undefined ) {
  5052. found = object[value];
  5053. return false;
  5054. }
  5055. else {
  5056. module.error(error.method, query);
  5057. return false;
  5058. }
  5059. });
  5060. }
  5061. if ( $.isFunction( found ) ) {
  5062. response = found.apply(context, passedArguments);
  5063. }
  5064. else if(found !== undefined) {
  5065. response = found;
  5066. }
  5067. if(Array.isArray(returnedValue)) {
  5068. returnedValue.push(response);
  5069. }
  5070. else if(returnedValue !== undefined) {
  5071. returnedValue = [returnedValue, response];
  5072. }
  5073. else if(response !== undefined) {
  5074. returnedValue = response;
  5075. }
  5076. return found;
  5077. }
  5078. };
  5079. if(methodInvoked) {
  5080. if(instance === undefined) {
  5081. module.initialize();
  5082. }
  5083. module.invoke(query);
  5084. }
  5085. else {
  5086. if(instance !== undefined) {
  5087. instance.invoke('destroy');
  5088. }
  5089. module.initialize();
  5090. }
  5091. })
  5092. ;
  5093. return (returnedValue !== undefined)
  5094. ? returnedValue
  5095. : this
  5096. ;
  5097. };
  5098. $.fn.checkbox.settings = {
  5099. name : 'Checkbox',
  5100. namespace : 'checkbox',
  5101. silent : false,
  5102. debug : false,
  5103. verbose : true,
  5104. performance : true,
  5105. // delegated event context
  5106. uncheckable : 'auto',
  5107. fireOnInit : false,
  5108. enableEnterKey : true,
  5109. onChange : function(){},
  5110. beforeChecked : function(){},
  5111. beforeUnchecked : function(){},
  5112. beforeDeterminate : function(){},
  5113. beforeIndeterminate : function(){},
  5114. onChecked : function(){},
  5115. onUnchecked : function(){},
  5116. onDeterminate : function() {},
  5117. onIndeterminate : function() {},
  5118. onEnable : function(){},
  5119. onDisable : function(){},
  5120. // preserve misspelled callbacks (will be removed in 3.0)
  5121. onEnabled : function(){},
  5122. onDisabled : function(){},
  5123. className : {
  5124. checked : 'checked',
  5125. indeterminate : 'indeterminate',
  5126. disabled : 'disabled',
  5127. hidden : 'hidden',
  5128. radio : 'radio',
  5129. readOnly : 'read-only'
  5130. },
  5131. error : {
  5132. method : 'The method you called is not defined'
  5133. },
  5134. selector : {
  5135. checkbox : '.ui.checkbox',
  5136. label : 'label, .box',
  5137. input : 'input[type="checkbox"], input[type="radio"]',
  5138. link : 'a[href]'
  5139. }
  5140. };
  5141. })( jQuery, window, document );
  5142. /*!
  5143. * # Fomantic-UI - Dimmer
  5144. * http://github.com/fomantic/Fomantic-UI/
  5145. *
  5146. *
  5147. * Released under the MIT license
  5148. * http://opensource.org/licenses/MIT
  5149. *
  5150. */
  5151. ;(function ($, window, document, undefined) {
  5152. 'use strict';
  5153. $.isFunction = $.isFunction || function(obj) {
  5154. return typeof obj === "function" && typeof obj.nodeType !== "number";
  5155. };
  5156. window = (typeof window != 'undefined' && window.Math == Math)
  5157. ? window
  5158. : (typeof self != 'undefined' && self.Math == Math)
  5159. ? self
  5160. : Function('return this')()
  5161. ;
  5162. $.fn.dimmer = function(parameters) {
  5163. var
  5164. $allModules = $(this),
  5165. time = new Date().getTime(),
  5166. performance = [],
  5167. query = arguments[0],
  5168. methodInvoked = (typeof query == 'string'),
  5169. queryArguments = [].slice.call(arguments, 1),
  5170. returnedValue
  5171. ;
  5172. $allModules
  5173. .each(function() {
  5174. var
  5175. settings = ( $.isPlainObject(parameters) )
  5176. ? $.extend(true, {}, $.fn.dimmer.settings, parameters)
  5177. : $.extend({}, $.fn.dimmer.settings),
  5178. selector = settings.selector,
  5179. namespace = settings.namespace,
  5180. className = settings.className,
  5181. error = settings.error,
  5182. eventNamespace = '.' + namespace,
  5183. moduleNamespace = 'module-' + namespace,
  5184. moduleSelector = $allModules.selector || '',
  5185. clickEvent = ('ontouchstart' in document.documentElement)
  5186. ? 'touchstart'
  5187. : 'click',
  5188. $module = $(this),
  5189. $dimmer,
  5190. $dimmable,
  5191. element = this,
  5192. instance = $module.data(moduleNamespace),
  5193. module
  5194. ;
  5195. module = {
  5196. preinitialize: function() {
  5197. if( module.is.dimmer() ) {
  5198. $dimmable = $module.parent();
  5199. $dimmer = $module;
  5200. }
  5201. else {
  5202. $dimmable = $module;
  5203. if( module.has.dimmer() ) {
  5204. if(settings.dimmerName) {
  5205. $dimmer = $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName);
  5206. }
  5207. else {
  5208. $dimmer = $dimmable.find(selector.dimmer);
  5209. }
  5210. }
  5211. else {
  5212. $dimmer = module.create();
  5213. }
  5214. }
  5215. },
  5216. initialize: function() {
  5217. module.debug('Initializing dimmer', settings);
  5218. module.bind.events();
  5219. module.set.dimmable();
  5220. module.instantiate();
  5221. },
  5222. instantiate: function() {
  5223. module.verbose('Storing instance of module', module);
  5224. instance = module;
  5225. $module
  5226. .data(moduleNamespace, instance)
  5227. ;
  5228. },
  5229. destroy: function() {
  5230. module.verbose('Destroying previous module', $dimmer);
  5231. module.unbind.events();
  5232. module.remove.variation();
  5233. $dimmable
  5234. .off(eventNamespace)
  5235. ;
  5236. },
  5237. bind: {
  5238. events: function() {
  5239. if(settings.on == 'hover') {
  5240. $dimmable
  5241. .on('mouseenter' + eventNamespace, module.show)
  5242. .on('mouseleave' + eventNamespace, module.hide)
  5243. ;
  5244. }
  5245. else if(settings.on == 'click') {
  5246. $dimmable
  5247. .on(clickEvent + eventNamespace, module.toggle)
  5248. ;
  5249. }
  5250. if( module.is.page() ) {
  5251. module.debug('Setting as a page dimmer', $dimmable);
  5252. module.set.pageDimmer();
  5253. }
  5254. if( module.is.closable() ) {
  5255. module.verbose('Adding dimmer close event', $dimmer);
  5256. $dimmable
  5257. .on(clickEvent + eventNamespace, selector.dimmer, module.event.click)
  5258. ;
  5259. }
  5260. }
  5261. },
  5262. unbind: {
  5263. events: function() {
  5264. $module
  5265. .removeData(moduleNamespace)
  5266. ;
  5267. $dimmable
  5268. .off(eventNamespace)
  5269. ;
  5270. }
  5271. },
  5272. event: {
  5273. click: function(event) {
  5274. module.verbose('Determining if event occured on dimmer', event);
  5275. if( $dimmer.find(event.target).length === 0 || $(event.target).is(selector.content) ) {
  5276. module.hide();
  5277. event.stopImmediatePropagation();
  5278. }
  5279. }
  5280. },
  5281. addContent: function(element) {
  5282. var
  5283. $content = $(element)
  5284. ;
  5285. module.debug('Add content to dimmer', $content);
  5286. if($content.parent()[0] !== $dimmer[0]) {
  5287. $content.detach().appendTo($dimmer);
  5288. }
  5289. },
  5290. create: function() {
  5291. var
  5292. $element = $( settings.template.dimmer(settings) )
  5293. ;
  5294. if(settings.dimmerName) {
  5295. module.debug('Creating named dimmer', settings.dimmerName);
  5296. $element.addClass(settings.dimmerName);
  5297. }
  5298. $element
  5299. .appendTo($dimmable)
  5300. ;
  5301. return $element;
  5302. },
  5303. show: function(callback) {
  5304. callback = $.isFunction(callback)
  5305. ? callback
  5306. : function(){}
  5307. ;
  5308. module.debug('Showing dimmer', $dimmer, settings);
  5309. module.set.variation();
  5310. if( (!module.is.dimmed() || module.is.animating()) && module.is.enabled() ) {
  5311. module.animate.show(callback);
  5312. settings.onShow.call(element);
  5313. settings.onChange.call(element);
  5314. }
  5315. else {
  5316. module.debug('Dimmer is already shown or disabled');
  5317. }
  5318. },
  5319. hide: function(callback) {
  5320. callback = $.isFunction(callback)
  5321. ? callback
  5322. : function(){}
  5323. ;
  5324. if( module.is.dimmed() || module.is.animating() ) {
  5325. module.debug('Hiding dimmer', $dimmer);
  5326. module.animate.hide(callback);
  5327. settings.onHide.call(element);
  5328. settings.onChange.call(element);
  5329. }
  5330. else {
  5331. module.debug('Dimmer is not visible');
  5332. }
  5333. },
  5334. toggle: function() {
  5335. module.verbose('Toggling dimmer visibility', $dimmer);
  5336. if( !module.is.dimmed() ) {
  5337. module.show();
  5338. }
  5339. else {
  5340. if ( module.is.closable() ) {
  5341. module.hide();
  5342. }
  5343. }
  5344. },
  5345. animate: {
  5346. show: function(callback) {
  5347. callback = $.isFunction(callback)
  5348. ? callback
  5349. : function(){}
  5350. ;
  5351. if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
  5352. if(settings.useFlex) {
  5353. module.debug('Using flex dimmer');
  5354. module.remove.legacy();
  5355. }
  5356. else {
  5357. module.debug('Using legacy non-flex dimmer');
  5358. module.set.legacy();
  5359. }
  5360. if(settings.opacity !== 'auto') {
  5361. module.set.opacity();
  5362. }
  5363. $dimmer
  5364. .transition({
  5365. displayType : settings.useFlex
  5366. ? 'flex'
  5367. : 'block',
  5368. animation : settings.transition + ' in',
  5369. queue : false,
  5370. duration : module.get.duration(),
  5371. useFailSafe : true,
  5372. onStart : function() {
  5373. module.set.dimmed();
  5374. },
  5375. onComplete : function() {
  5376. module.set.active();
  5377. callback();
  5378. }
  5379. })
  5380. ;
  5381. }
  5382. else {
  5383. module.verbose('Showing dimmer animation with javascript');
  5384. module.set.dimmed();
  5385. if(settings.opacity == 'auto') {
  5386. settings.opacity = 0.8;
  5387. }
  5388. $dimmer
  5389. .stop()
  5390. .css({
  5391. opacity : 0,
  5392. width : '100%',
  5393. height : '100%'
  5394. })
  5395. .fadeTo(module.get.duration(), settings.opacity, function() {
  5396. $dimmer.removeAttr('style');
  5397. module.set.active();
  5398. callback();
  5399. })
  5400. ;
  5401. }
  5402. },
  5403. hide: function(callback) {
  5404. callback = $.isFunction(callback)
  5405. ? callback
  5406. : function(){}
  5407. ;
  5408. if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
  5409. module.verbose('Hiding dimmer with css');
  5410. $dimmer
  5411. .transition({
  5412. displayType : settings.useFlex
  5413. ? 'flex'
  5414. : 'block',
  5415. animation : settings.transition + ' out',
  5416. queue : false,
  5417. duration : module.get.duration(),
  5418. useFailSafe : true,
  5419. onComplete : function() {
  5420. module.remove.dimmed();
  5421. module.remove.variation();
  5422. module.remove.active();
  5423. callback();
  5424. }
  5425. })
  5426. ;
  5427. }
  5428. else {
  5429. module.verbose('Hiding dimmer with javascript');
  5430. $dimmer
  5431. .stop()
  5432. .fadeOut(module.get.duration(), function() {
  5433. module.remove.dimmed();
  5434. module.remove.active();
  5435. $dimmer.removeAttr('style');
  5436. callback();
  5437. })
  5438. ;
  5439. }
  5440. }
  5441. },
  5442. get: {
  5443. dimmer: function() {
  5444. return $dimmer;
  5445. },
  5446. duration: function() {
  5447. if(typeof settings.duration == 'object') {
  5448. if( module.is.active() ) {
  5449. return settings.duration.hide;
  5450. }
  5451. else {
  5452. return settings.duration.show;
  5453. }
  5454. }
  5455. return settings.duration;
  5456. }
  5457. },
  5458. has: {
  5459. dimmer: function() {
  5460. if(settings.dimmerName) {
  5461. return ($module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0);
  5462. }
  5463. else {
  5464. return ( $module.find(selector.dimmer).length > 0 );
  5465. }
  5466. }
  5467. },
  5468. is: {
  5469. active: function() {
  5470. return $dimmer.hasClass(className.active);
  5471. },
  5472. animating: function() {
  5473. return ( $dimmer.is(':animated') || $dimmer.hasClass(className.animating) );
  5474. },
  5475. closable: function() {
  5476. if(settings.closable == 'auto') {
  5477. if(settings.on == 'hover') {
  5478. return false;
  5479. }
  5480. return true;
  5481. }
  5482. return settings.closable;
  5483. },
  5484. dimmer: function() {
  5485. return $module.hasClass(className.dimmer);
  5486. },
  5487. dimmable: function() {
  5488. return $module.hasClass(className.dimmable);
  5489. },
  5490. dimmed: function() {
  5491. return $dimmable.hasClass(className.dimmed);
  5492. },
  5493. disabled: function() {
  5494. return $dimmable.hasClass(className.disabled);
  5495. },
  5496. enabled: function() {
  5497. return !module.is.disabled();
  5498. },
  5499. page: function () {
  5500. return $dimmable.is('body');
  5501. },
  5502. pageDimmer: function() {
  5503. return $dimmer.hasClass(className.pageDimmer);
  5504. }
  5505. },
  5506. can: {
  5507. show: function() {
  5508. return !$dimmer.hasClass(className.disabled);
  5509. }
  5510. },
  5511. set: {
  5512. opacity: function(opacity) {
  5513. var
  5514. color = $dimmer.css('background-color'),
  5515. colorArray = color.split(','),
  5516. isRGB = (colorArray && colorArray.length == 3),
  5517. isRGBA = (colorArray && colorArray.length == 4)
  5518. ;
  5519. opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity;
  5520. if(isRGB || isRGBA) {
  5521. colorArray[3] = opacity + ')';
  5522. color = colorArray.join(',');
  5523. }
  5524. else {
  5525. color = 'rgba(0, 0, 0, ' + opacity + ')';
  5526. }
  5527. module.debug('Setting opacity to', opacity);
  5528. $dimmer.css('background-color', color);
  5529. },
  5530. legacy: function() {
  5531. $dimmer.addClass(className.legacy);
  5532. },
  5533. active: function() {
  5534. $dimmer.addClass(className.active);
  5535. },
  5536. dimmable: function() {
  5537. $dimmable.addClass(className.dimmable);
  5538. },
  5539. dimmed: function() {
  5540. $dimmable.addClass(className.dimmed);
  5541. },
  5542. pageDimmer: function() {
  5543. $dimmer.addClass(className.pageDimmer);
  5544. },
  5545. disabled: function() {
  5546. $dimmer.addClass(className.disabled);
  5547. },
  5548. variation: function(variation) {
  5549. variation = variation || settings.variation;
  5550. if(variation) {
  5551. $dimmer.addClass(variation);
  5552. }
  5553. }
  5554. },
  5555. remove: {
  5556. active: function() {
  5557. $dimmer
  5558. .removeClass(className.active)
  5559. ;
  5560. },
  5561. legacy: function() {
  5562. $dimmer.removeClass(className.legacy);
  5563. },
  5564. dimmed: function() {
  5565. $dimmable.removeClass(className.dimmed);
  5566. },
  5567. disabled: function() {
  5568. $dimmer.removeClass(className.disabled);
  5569. },
  5570. variation: function(variation) {
  5571. variation = variation || settings.variation;
  5572. if(variation) {
  5573. $dimmer.removeClass(variation);
  5574. }
  5575. }
  5576. },
  5577. setting: function(name, value) {
  5578. module.debug('Changing setting', name, value);
  5579. if( $.isPlainObject(name) ) {
  5580. $.extend(true, settings, name);
  5581. }
  5582. else if(value !== undefined) {
  5583. if($.isPlainObject(settings[name])) {
  5584. $.extend(true, settings[name], value);
  5585. }
  5586. else {
  5587. settings[name] = value;
  5588. }
  5589. }
  5590. else {
  5591. return settings[name];
  5592. }
  5593. },
  5594. internal: function(name, value) {
  5595. if( $.isPlainObject(name) ) {
  5596. $.extend(true, module, name);
  5597. }
  5598. else if(value !== undefined) {
  5599. module[name] = value;
  5600. }
  5601. else {
  5602. return module[name];
  5603. }
  5604. },
  5605. debug: function() {
  5606. if(!settings.silent && settings.debug) {
  5607. if(settings.performance) {
  5608. module.performance.log(arguments);
  5609. }
  5610. else {
  5611. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  5612. module.debug.apply(console, arguments);
  5613. }
  5614. }
  5615. },
  5616. verbose: function() {
  5617. if(!settings.silent && settings.verbose && settings.debug) {
  5618. if(settings.performance) {
  5619. module.performance.log(arguments);
  5620. }
  5621. else {
  5622. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  5623. module.verbose.apply(console, arguments);
  5624. }
  5625. }
  5626. },
  5627. error: function() {
  5628. if(!settings.silent) {
  5629. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  5630. module.error.apply(console, arguments);
  5631. }
  5632. },
  5633. performance: {
  5634. log: function(message) {
  5635. var
  5636. currentTime,
  5637. executionTime,
  5638. previousTime
  5639. ;
  5640. if(settings.performance) {
  5641. currentTime = new Date().getTime();
  5642. previousTime = time || currentTime;
  5643. executionTime = currentTime - previousTime;
  5644. time = currentTime;
  5645. performance.push({
  5646. 'Name' : message[0],
  5647. 'Arguments' : [].slice.call(message, 1) || '',
  5648. 'Element' : element,
  5649. 'Execution Time' : executionTime
  5650. });
  5651. }
  5652. clearTimeout(module.performance.timer);
  5653. module.performance.timer = setTimeout(module.performance.display, 500);
  5654. },
  5655. display: function() {
  5656. var
  5657. title = settings.name + ':',
  5658. totalTime = 0
  5659. ;
  5660. time = false;
  5661. clearTimeout(module.performance.timer);
  5662. $.each(performance, function(index, data) {
  5663. totalTime += data['Execution Time'];
  5664. });
  5665. title += ' ' + totalTime + 'ms';
  5666. if(moduleSelector) {
  5667. title += ' \'' + moduleSelector + '\'';
  5668. }
  5669. if($allModules.length > 1) {
  5670. title += ' ' + '(' + $allModules.length + ')';
  5671. }
  5672. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  5673. console.groupCollapsed(title);
  5674. if(console.table) {
  5675. console.table(performance);
  5676. }
  5677. else {
  5678. $.each(performance, function(index, data) {
  5679. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  5680. });
  5681. }
  5682. console.groupEnd();
  5683. }
  5684. performance = [];
  5685. }
  5686. },
  5687. invoke: function(query, passedArguments, context) {
  5688. var
  5689. object = instance,
  5690. maxDepth,
  5691. found,
  5692. response
  5693. ;
  5694. passedArguments = passedArguments || queryArguments;
  5695. context = element || context;
  5696. if(typeof query == 'string' && object !== undefined) {
  5697. query = query.split(/[\. ]/);
  5698. maxDepth = query.length - 1;
  5699. $.each(query, function(depth, value) {
  5700. var camelCaseValue = (depth != maxDepth)
  5701. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  5702. : query
  5703. ;
  5704. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  5705. object = object[camelCaseValue];
  5706. }
  5707. else if( object[camelCaseValue] !== undefined ) {
  5708. found = object[camelCaseValue];
  5709. return false;
  5710. }
  5711. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  5712. object = object[value];
  5713. }
  5714. else if( object[value] !== undefined ) {
  5715. found = object[value];
  5716. return false;
  5717. }
  5718. else {
  5719. module.error(error.method, query);
  5720. return false;
  5721. }
  5722. });
  5723. }
  5724. if ( $.isFunction( found ) ) {
  5725. response = found.apply(context, passedArguments);
  5726. }
  5727. else if(found !== undefined) {
  5728. response = found;
  5729. }
  5730. if(Array.isArray(returnedValue)) {
  5731. returnedValue.push(response);
  5732. }
  5733. else if(returnedValue !== undefined) {
  5734. returnedValue = [returnedValue, response];
  5735. }
  5736. else if(response !== undefined) {
  5737. returnedValue = response;
  5738. }
  5739. return found;
  5740. }
  5741. };
  5742. module.preinitialize();
  5743. if(methodInvoked) {
  5744. if(instance === undefined) {
  5745. module.initialize();
  5746. }
  5747. module.invoke(query);
  5748. }
  5749. else {
  5750. if(instance !== undefined) {
  5751. instance.invoke('destroy');
  5752. }
  5753. module.initialize();
  5754. }
  5755. })
  5756. ;
  5757. return (returnedValue !== undefined)
  5758. ? returnedValue
  5759. : this
  5760. ;
  5761. };
  5762. $.fn.dimmer.settings = {
  5763. name : 'Dimmer',
  5764. namespace : 'dimmer',
  5765. silent : false,
  5766. debug : false,
  5767. verbose : false,
  5768. performance : true,
  5769. // whether should use flex layout
  5770. useFlex : true,
  5771. // name to distinguish between multiple dimmers in context
  5772. dimmerName : false,
  5773. // whether to add a variation type
  5774. variation : false,
  5775. // whether to bind close events
  5776. closable : 'auto',
  5777. // whether to use css animations
  5778. useCSS : true,
  5779. // css animation to use
  5780. transition : 'fade',
  5781. // event to bind to
  5782. on : false,
  5783. // overriding opacity value
  5784. opacity : 'auto',
  5785. // transition durations
  5786. duration : {
  5787. show : 500,
  5788. hide : 500
  5789. },
  5790. // whether the dynamically created dimmer should have a loader
  5791. displayLoader: false,
  5792. loaderText : false,
  5793. loaderVariation : '',
  5794. onChange : function(){},
  5795. onShow : function(){},
  5796. onHide : function(){},
  5797. error : {
  5798. method : 'The method you called is not defined.'
  5799. },
  5800. className : {
  5801. active : 'active',
  5802. animating : 'animating',
  5803. dimmable : 'dimmable',
  5804. dimmed : 'dimmed',
  5805. dimmer : 'dimmer',
  5806. disabled : 'disabled',
  5807. hide : 'hide',
  5808. legacy : 'legacy',
  5809. pageDimmer : 'page',
  5810. show : 'show',
  5811. loader : 'ui loader'
  5812. },
  5813. selector: {
  5814. dimmer : '> .ui.dimmer',
  5815. content : '.ui.dimmer > .content, .ui.dimmer > .content > .center'
  5816. },
  5817. template: {
  5818. dimmer: function(settings) {
  5819. var d = $('<div/>').addClass('ui dimmer'),l;
  5820. if(settings.displayLoader) {
  5821. l = $('<div/>')
  5822. .addClass(settings.className.loader)
  5823. .addClass(settings.loaderVariation);
  5824. if(!!settings.loaderText){
  5825. l.text(settings.loaderText);
  5826. l.addClass('text');
  5827. }
  5828. d.append(l);
  5829. }
  5830. return d;
  5831. }
  5832. }
  5833. };
  5834. })( jQuery, window, document );
  5835. /*!
  5836. * # Fomantic-UI - Dropdown
  5837. * http://github.com/fomantic/Fomantic-UI/
  5838. *
  5839. *
  5840. * Released under the MIT license
  5841. * http://opensource.org/licenses/MIT
  5842. *
  5843. */
  5844. ;(function ($, window, document, undefined) {
  5845. 'use strict';
  5846. $.isFunction = $.isFunction || function(obj) {
  5847. return typeof obj === "function" && typeof obj.nodeType !== "number";
  5848. };
  5849. window = (typeof window != 'undefined' && window.Math == Math)
  5850. ? window
  5851. : (typeof self != 'undefined' && self.Math == Math)
  5852. ? self
  5853. : Function('return this')()
  5854. ;
  5855. $.fn.dropdown = function(parameters) {
  5856. var
  5857. $allModules = $(this),
  5858. $document = $(document),
  5859. moduleSelector = $allModules.selector || '',
  5860. hasTouch = ('ontouchstart' in document.documentElement),
  5861. time = new Date().getTime(),
  5862. performance = [],
  5863. query = arguments[0],
  5864. methodInvoked = (typeof query == 'string'),
  5865. queryArguments = [].slice.call(arguments, 1),
  5866. returnedValue
  5867. ;
  5868. $allModules
  5869. .each(function(elementIndex) {
  5870. var
  5871. settings = ( $.isPlainObject(parameters) )
  5872. ? $.extend(true, {}, $.fn.dropdown.settings, parameters)
  5873. : $.extend({}, $.fn.dropdown.settings),
  5874. className = settings.className,
  5875. message = settings.message,
  5876. fields = settings.fields,
  5877. keys = settings.keys,
  5878. metadata = settings.metadata,
  5879. namespace = settings.namespace,
  5880. regExp = settings.regExp,
  5881. selector = settings.selector,
  5882. error = settings.error,
  5883. templates = settings.templates,
  5884. eventNamespace = '.' + namespace,
  5885. moduleNamespace = 'module-' + namespace,
  5886. $module = $(this),
  5887. $context = $(settings.context),
  5888. $text = $module.find(selector.text),
  5889. $search = $module.find(selector.search),
  5890. $sizer = $module.find(selector.sizer),
  5891. $input = $module.find(selector.input),
  5892. $icon = $module.find(selector.icon),
  5893. $clear = $module.find(selector.clearIcon),
  5894. $combo = ($module.prev().find(selector.text).length > 0)
  5895. ? $module.prev().find(selector.text)
  5896. : $module.prev(),
  5897. $menu = $module.children(selector.menu),
  5898. $item = $menu.find(selector.item),
  5899. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $(),
  5900. activated = false,
  5901. itemActivated = false,
  5902. internalChange = false,
  5903. iconClicked = false,
  5904. element = this,
  5905. instance = $module.data(moduleNamespace),
  5906. selectActionActive,
  5907. initialLoad,
  5908. pageLostFocus,
  5909. willRefocus,
  5910. elementNamespace,
  5911. id,
  5912. selectObserver,
  5913. menuObserver,
  5914. module
  5915. ;
  5916. module = {
  5917. initialize: function() {
  5918. module.debug('Initializing dropdown', settings);
  5919. if( module.is.alreadySetup() ) {
  5920. module.setup.reference();
  5921. }
  5922. else {
  5923. if (settings.ignoreDiacritics && !String.prototype.normalize) {
  5924. settings.ignoreDiacritics = false;
  5925. module.error(error.noNormalize, element);
  5926. }
  5927. module.setup.layout();
  5928. if(settings.values) {
  5929. module.change.values(settings.values);
  5930. }
  5931. module.refreshData();
  5932. module.save.defaults();
  5933. module.restore.selected();
  5934. module.create.id();
  5935. module.bind.events();
  5936. module.observeChanges();
  5937. module.instantiate();
  5938. }
  5939. },
  5940. instantiate: function() {
  5941. module.verbose('Storing instance of dropdown', module);
  5942. instance = module;
  5943. $module
  5944. .data(moduleNamespace, module)
  5945. ;
  5946. },
  5947. destroy: function() {
  5948. module.verbose('Destroying previous dropdown', $module);
  5949. module.remove.tabbable();
  5950. module.remove.active();
  5951. $menu.transition('stop all');
  5952. $menu.removeClass(className.visible).addClass(className.hidden);
  5953. $module
  5954. .off(eventNamespace)
  5955. .removeData(moduleNamespace)
  5956. ;
  5957. $menu
  5958. .off(eventNamespace)
  5959. ;
  5960. $document
  5961. .off(elementNamespace)
  5962. ;
  5963. module.disconnect.menuObserver();
  5964. module.disconnect.selectObserver();
  5965. },
  5966. observeChanges: function() {
  5967. if('MutationObserver' in window) {
  5968. selectObserver = new MutationObserver(module.event.select.mutation);
  5969. menuObserver = new MutationObserver(module.event.menu.mutation);
  5970. module.debug('Setting up mutation observer', selectObserver, menuObserver);
  5971. module.observe.select();
  5972. module.observe.menu();
  5973. }
  5974. },
  5975. disconnect: {
  5976. menuObserver: function() {
  5977. if(menuObserver) {
  5978. menuObserver.disconnect();
  5979. }
  5980. },
  5981. selectObserver: function() {
  5982. if(selectObserver) {
  5983. selectObserver.disconnect();
  5984. }
  5985. }
  5986. },
  5987. observe: {
  5988. select: function() {
  5989. if(module.has.input() && selectObserver) {
  5990. selectObserver.observe($module[0], {
  5991. childList : true,
  5992. subtree : true
  5993. });
  5994. }
  5995. },
  5996. menu: function() {
  5997. if(module.has.menu() && menuObserver) {
  5998. menuObserver.observe($menu[0], {
  5999. childList : true,
  6000. subtree : true
  6001. });
  6002. }
  6003. }
  6004. },
  6005. create: {
  6006. id: function() {
  6007. id = (Math.random().toString(16) + '000000000').substr(2, 8);
  6008. elementNamespace = '.' + id;
  6009. module.verbose('Creating unique id for element', id);
  6010. },
  6011. userChoice: function(values) {
  6012. var
  6013. $userChoices,
  6014. $userChoice,
  6015. isUserValue,
  6016. html
  6017. ;
  6018. values = values || module.get.userValues();
  6019. if(!values) {
  6020. return false;
  6021. }
  6022. values = Array.isArray(values)
  6023. ? values
  6024. : [values]
  6025. ;
  6026. $.each(values, function(index, value) {
  6027. if(module.get.item(value) === false) {
  6028. html = settings.templates.addition( module.add.variables(message.addResult, value) );
  6029. $userChoice = $('<div />')
  6030. .html(html)
  6031. .attr('data-' + metadata.value, value)
  6032. .attr('data-' + metadata.text, value)
  6033. .addClass(className.addition)
  6034. .addClass(className.item)
  6035. ;
  6036. if(settings.hideAdditions) {
  6037. $userChoice.addClass(className.hidden);
  6038. }
  6039. $userChoices = ($userChoices === undefined)
  6040. ? $userChoice
  6041. : $userChoices.add($userChoice)
  6042. ;
  6043. module.verbose('Creating user choices for value', value, $userChoice);
  6044. }
  6045. });
  6046. return $userChoices;
  6047. },
  6048. userLabels: function(value) {
  6049. var
  6050. userValues = module.get.userValues()
  6051. ;
  6052. if(userValues) {
  6053. module.debug('Adding user labels', userValues);
  6054. $.each(userValues, function(index, value) {
  6055. module.verbose('Adding custom user value');
  6056. module.add.label(value, value);
  6057. });
  6058. }
  6059. },
  6060. menu: function() {
  6061. $menu = $('<div />')
  6062. .addClass(className.menu)
  6063. .appendTo($module)
  6064. ;
  6065. },
  6066. sizer: function() {
  6067. $sizer = $('<span />')
  6068. .addClass(className.sizer)
  6069. .insertAfter($search)
  6070. ;
  6071. }
  6072. },
  6073. search: function(query) {
  6074. query = (query !== undefined)
  6075. ? query
  6076. : module.get.query()
  6077. ;
  6078. module.verbose('Searching for query', query);
  6079. if(module.has.minCharacters(query)) {
  6080. module.filter(query);
  6081. }
  6082. else {
  6083. module.hide();
  6084. }
  6085. },
  6086. select: {
  6087. firstUnfiltered: function() {
  6088. module.verbose('Selecting first non-filtered element');
  6089. module.remove.selectedItem();
  6090. $item
  6091. .not(selector.unselectable)
  6092. .not(selector.addition + selector.hidden)
  6093. .eq(0)
  6094. .addClass(className.selected)
  6095. ;
  6096. },
  6097. nextAvailable: function($selected) {
  6098. $selected = $selected.eq(0);
  6099. var
  6100. $nextAvailable = $selected.nextAll(selector.item).not(selector.unselectable).eq(0),
  6101. $prevAvailable = $selected.prevAll(selector.item).not(selector.unselectable).eq(0),
  6102. hasNext = ($nextAvailable.length > 0)
  6103. ;
  6104. if(hasNext) {
  6105. module.verbose('Moving selection to', $nextAvailable);
  6106. $nextAvailable.addClass(className.selected);
  6107. }
  6108. else {
  6109. module.verbose('Moving selection to', $prevAvailable);
  6110. $prevAvailable.addClass(className.selected);
  6111. }
  6112. }
  6113. },
  6114. setup: {
  6115. api: function() {
  6116. var
  6117. apiSettings = {
  6118. debug : settings.debug,
  6119. urlData : {
  6120. value : module.get.value(),
  6121. query : module.get.query()
  6122. },
  6123. on : false
  6124. }
  6125. ;
  6126. module.verbose('First request, initializing API');
  6127. $module
  6128. .api(apiSettings)
  6129. ;
  6130. },
  6131. layout: function() {
  6132. if( $module.is('select') ) {
  6133. module.setup.select();
  6134. module.setup.returnedObject();
  6135. }
  6136. if( !module.has.menu() ) {
  6137. module.create.menu();
  6138. }
  6139. if ( module.is.selection() && module.is.clearable() && !module.has.clearItem() ) {
  6140. module.verbose('Adding clear icon');
  6141. $clear = $('<i />')
  6142. .addClass('remove icon')
  6143. .insertBefore($text)
  6144. ;
  6145. }
  6146. if( module.is.search() && !module.has.search() ) {
  6147. module.verbose('Adding search input');
  6148. $search = $('<input />')
  6149. .addClass(className.search)
  6150. .prop('autocomplete', 'off')
  6151. .insertBefore($text)
  6152. ;
  6153. }
  6154. if( module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
  6155. module.create.sizer();
  6156. }
  6157. if(settings.allowTab) {
  6158. module.set.tabbable();
  6159. }
  6160. },
  6161. select: function() {
  6162. var
  6163. selectValues = module.get.selectValues()
  6164. ;
  6165. module.debug('Dropdown initialized on a select', selectValues);
  6166. if( $module.is('select') ) {
  6167. $input = $module;
  6168. }
  6169. // see if select is placed correctly already
  6170. if($input.parent(selector.dropdown).length > 0) {
  6171. module.debug('UI dropdown already exists. Creating dropdown menu only');
  6172. $module = $input.closest(selector.dropdown);
  6173. if( !module.has.menu() ) {
  6174. module.create.menu();
  6175. }
  6176. $menu = $module.children(selector.menu);
  6177. module.setup.menu(selectValues);
  6178. }
  6179. else {
  6180. module.debug('Creating entire dropdown from select');
  6181. $module = $('<div />')
  6182. .attr('class', $input.attr('class') )
  6183. .addClass(className.selection)
  6184. .addClass(className.dropdown)
  6185. .html( templates.dropdown(selectValues, fields, settings.preserveHTML, settings.className) )
  6186. .insertBefore($input)
  6187. ;
  6188. if($input.hasClass(className.multiple) && $input.prop('multiple') === false) {
  6189. module.error(error.missingMultiple);
  6190. $input.prop('multiple', true);
  6191. }
  6192. if($input.is('[multiple]')) {
  6193. module.set.multiple();
  6194. }
  6195. if ($input.prop('disabled')) {
  6196. module.debug('Disabling dropdown');
  6197. $module.addClass(className.disabled);
  6198. }
  6199. $input
  6200. .removeAttr('class')
  6201. .detach()
  6202. .prependTo($module)
  6203. ;
  6204. }
  6205. module.refresh();
  6206. },
  6207. menu: function(values) {
  6208. $menu.html( templates.menu(values, fields,settings.preserveHTML,settings.className));
  6209. $item = $menu.find(selector.item);
  6210. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
  6211. },
  6212. reference: function() {
  6213. module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
  6214. // replace module reference
  6215. $module = $module.parent(selector.dropdown);
  6216. instance = $module.data(moduleNamespace);
  6217. element = $module.get(0);
  6218. module.refresh();
  6219. module.setup.returnedObject();
  6220. },
  6221. returnedObject: function() {
  6222. var
  6223. $firstModules = $allModules.slice(0, elementIndex),
  6224. $lastModules = $allModules.slice(elementIndex + 1)
  6225. ;
  6226. // adjust all modules to use correct reference
  6227. $allModules = $firstModules.add($module).add($lastModules);
  6228. }
  6229. },
  6230. refresh: function() {
  6231. module.refreshSelectors();
  6232. module.refreshData();
  6233. },
  6234. refreshItems: function() {
  6235. $item = $menu.find(selector.item);
  6236. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
  6237. },
  6238. refreshSelectors: function() {
  6239. module.verbose('Refreshing selector cache');
  6240. $text = $module.find(selector.text);
  6241. $search = $module.find(selector.search);
  6242. $input = $module.find(selector.input);
  6243. $icon = $module.find(selector.icon);
  6244. $combo = ($module.prev().find(selector.text).length > 0)
  6245. ? $module.prev().find(selector.text)
  6246. : $module.prev()
  6247. ;
  6248. $menu = $module.children(selector.menu);
  6249. $item = $menu.find(selector.item);
  6250. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
  6251. },
  6252. refreshData: function() {
  6253. module.verbose('Refreshing cached metadata');
  6254. $item
  6255. .removeData(metadata.text)
  6256. .removeData(metadata.value)
  6257. ;
  6258. },
  6259. clearData: function() {
  6260. module.verbose('Clearing metadata');
  6261. $item
  6262. .removeData(metadata.text)
  6263. .removeData(metadata.value)
  6264. ;
  6265. $module
  6266. .removeData(metadata.defaultText)
  6267. .removeData(metadata.defaultValue)
  6268. .removeData(metadata.placeholderText)
  6269. ;
  6270. },
  6271. toggle: function() {
  6272. module.verbose('Toggling menu visibility');
  6273. if( !module.is.active() ) {
  6274. module.show();
  6275. }
  6276. else {
  6277. module.hide();
  6278. }
  6279. },
  6280. show: function(callback) {
  6281. callback = $.isFunction(callback)
  6282. ? callback
  6283. : function(){}
  6284. ;
  6285. if(!module.can.show() && module.is.remote()) {
  6286. module.debug('No API results retrieved, searching before show');
  6287. module.queryRemote(module.get.query(), module.show);
  6288. }
  6289. if( module.can.show() && !module.is.active() ) {
  6290. module.debug('Showing dropdown');
  6291. if(module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered()) ) {
  6292. module.remove.message();
  6293. }
  6294. if(module.is.allFiltered()) {
  6295. return true;
  6296. }
  6297. if(settings.onShow.call(element) !== false) {
  6298. module.animate.show(function() {
  6299. if( module.can.click() ) {
  6300. module.bind.intent();
  6301. }
  6302. if(module.has.search()) {
  6303. module.focusSearch();
  6304. }
  6305. module.set.visible();
  6306. callback.call(element);
  6307. });
  6308. }
  6309. }
  6310. },
  6311. hide: function(callback) {
  6312. callback = $.isFunction(callback)
  6313. ? callback
  6314. : function(){}
  6315. ;
  6316. if( module.is.active() && !module.is.animatingOutward() ) {
  6317. module.debug('Hiding dropdown');
  6318. if(settings.onHide.call(element) !== false) {
  6319. module.animate.hide(function() {
  6320. module.remove.visible();
  6321. // hidding search focus
  6322. if ( module.is.focusedOnSearch() ) {
  6323. $search.blur();
  6324. }
  6325. callback.call(element);
  6326. });
  6327. }
  6328. } else if( module.can.click() ) {
  6329. module.unbind.intent();
  6330. }
  6331. },
  6332. hideOthers: function() {
  6333. module.verbose('Finding other dropdowns to hide');
  6334. $allModules
  6335. .not($module)
  6336. .has(selector.menu + '.' + className.visible)
  6337. .dropdown('hide')
  6338. ;
  6339. },
  6340. hideMenu: function() {
  6341. module.verbose('Hiding menu instantaneously');
  6342. module.remove.active();
  6343. module.remove.visible();
  6344. $menu.transition('hide');
  6345. },
  6346. hideSubMenus: function() {
  6347. var
  6348. $subMenus = $menu.children(selector.item).find(selector.menu)
  6349. ;
  6350. module.verbose('Hiding sub menus', $subMenus);
  6351. $subMenus.transition('hide');
  6352. },
  6353. bind: {
  6354. events: function() {
  6355. if(hasTouch) {
  6356. module.bind.touchEvents();
  6357. }
  6358. module.bind.keyboardEvents();
  6359. module.bind.inputEvents();
  6360. module.bind.mouseEvents();
  6361. },
  6362. touchEvents: function() {
  6363. module.debug('Touch device detected binding additional touch events');
  6364. if( module.is.searchSelection() ) {
  6365. // do nothing special yet
  6366. }
  6367. else if( module.is.single() ) {
  6368. $module
  6369. .on('touchstart' + eventNamespace, module.event.test.toggle)
  6370. ;
  6371. }
  6372. $menu
  6373. .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
  6374. ;
  6375. },
  6376. keyboardEvents: function() {
  6377. module.verbose('Binding keyboard events');
  6378. $module
  6379. .on('keydown' + eventNamespace, module.event.keydown)
  6380. ;
  6381. if( module.has.search() ) {
  6382. $module
  6383. .on(module.get.inputEvent() + eventNamespace, selector.search, module.event.input)
  6384. ;
  6385. }
  6386. if( module.is.multiple() ) {
  6387. $document
  6388. .on('keydown' + elementNamespace, module.event.document.keydown)
  6389. ;
  6390. }
  6391. },
  6392. inputEvents: function() {
  6393. module.verbose('Binding input change events');
  6394. $module
  6395. .on('change' + eventNamespace, selector.input, module.event.change)
  6396. ;
  6397. },
  6398. mouseEvents: function() {
  6399. module.verbose('Binding mouse events');
  6400. if(module.is.multiple()) {
  6401. $module
  6402. .on('click' + eventNamespace, selector.label, module.event.label.click)
  6403. .on('click' + eventNamespace, selector.remove, module.event.remove.click)
  6404. ;
  6405. }
  6406. if( module.is.searchSelection() ) {
  6407. $module
  6408. .on('mousedown' + eventNamespace, module.event.mousedown)
  6409. .on('mouseup' + eventNamespace, module.event.mouseup)
  6410. .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
  6411. .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
  6412. .on('click' + eventNamespace, selector.icon, module.event.icon.click)
  6413. .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
  6414. .on('focus' + eventNamespace, selector.search, module.event.search.focus)
  6415. .on('click' + eventNamespace, selector.search, module.event.search.focus)
  6416. .on('blur' + eventNamespace, selector.search, module.event.search.blur)
  6417. .on('click' + eventNamespace, selector.text, module.event.text.focus)
  6418. ;
  6419. if(module.is.multiple()) {
  6420. $module
  6421. .on('click' + eventNamespace, module.event.click)
  6422. ;
  6423. }
  6424. }
  6425. else {
  6426. if(settings.on == 'click') {
  6427. $module
  6428. .on('click' + eventNamespace, selector.icon, module.event.icon.click)
  6429. .on('click' + eventNamespace, module.event.test.toggle)
  6430. ;
  6431. }
  6432. else if(settings.on == 'hover') {
  6433. $module
  6434. .on('mouseenter' + eventNamespace, module.delay.show)
  6435. .on('mouseleave' + eventNamespace, module.delay.hide)
  6436. ;
  6437. }
  6438. else {
  6439. $module
  6440. .on(settings.on + eventNamespace, module.toggle)
  6441. ;
  6442. }
  6443. $module
  6444. .on('mousedown' + eventNamespace, module.event.mousedown)
  6445. .on('mouseup' + eventNamespace, module.event.mouseup)
  6446. .on('focus' + eventNamespace, module.event.focus)
  6447. .on('click' + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
  6448. ;
  6449. if(module.has.menuSearch() ) {
  6450. $module
  6451. .on('blur' + eventNamespace, selector.search, module.event.search.blur)
  6452. ;
  6453. }
  6454. else {
  6455. $module
  6456. .on('blur' + eventNamespace, module.event.blur)
  6457. ;
  6458. }
  6459. }
  6460. $menu
  6461. .on('mouseenter' + eventNamespace, selector.item, module.event.item.mouseenter)
  6462. .on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
  6463. .on('click' + eventNamespace, selector.item, module.event.item.click)
  6464. ;
  6465. },
  6466. intent: function() {
  6467. module.verbose('Binding hide intent event to document');
  6468. if(hasTouch) {
  6469. $document
  6470. .on('touchstart' + elementNamespace, module.event.test.touch)
  6471. .on('touchmove' + elementNamespace, module.event.test.touch)
  6472. ;
  6473. }
  6474. $document
  6475. .on('click' + elementNamespace, module.event.test.hide)
  6476. ;
  6477. }
  6478. },
  6479. unbind: {
  6480. intent: function() {
  6481. module.verbose('Removing hide intent event from document');
  6482. if(hasTouch) {
  6483. $document
  6484. .off('touchstart' + elementNamespace)
  6485. .off('touchmove' + elementNamespace)
  6486. ;
  6487. }
  6488. $document
  6489. .off('click' + elementNamespace)
  6490. ;
  6491. }
  6492. },
  6493. filter: function(query) {
  6494. var
  6495. searchTerm = (query !== undefined)
  6496. ? query
  6497. : module.get.query(),
  6498. afterFiltered = function() {
  6499. if(module.is.multiple()) {
  6500. module.filterActive();
  6501. }
  6502. if(query || (!query && module.get.activeItem().length == 0)) {
  6503. module.select.firstUnfiltered();
  6504. }
  6505. if( module.has.allResultsFiltered() ) {
  6506. if( settings.onNoResults.call(element, searchTerm) ) {
  6507. if(settings.allowAdditions) {
  6508. if(settings.hideAdditions) {
  6509. module.verbose('User addition with no menu, setting empty style');
  6510. module.set.empty();
  6511. module.hideMenu();
  6512. }
  6513. }
  6514. else {
  6515. module.verbose('All items filtered, showing message', searchTerm);
  6516. module.add.message(message.noResults);
  6517. }
  6518. }
  6519. else {
  6520. module.verbose('All items filtered, hiding dropdown', searchTerm);
  6521. module.hideMenu();
  6522. }
  6523. }
  6524. else {
  6525. module.remove.empty();
  6526. module.remove.message();
  6527. }
  6528. if(settings.allowAdditions) {
  6529. module.add.userSuggestion(module.escape.htmlEntities(query));
  6530. }
  6531. if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() ) {
  6532. module.show();
  6533. }
  6534. }
  6535. ;
  6536. if(settings.useLabels && module.has.maxSelections()) {
  6537. return;
  6538. }
  6539. if(settings.apiSettings) {
  6540. if( module.can.useAPI() ) {
  6541. module.queryRemote(searchTerm, function() {
  6542. if(settings.filterRemoteData) {
  6543. module.filterItems(searchTerm);
  6544. }
  6545. var preSelected = $input.val();
  6546. if(!Array.isArray(preSelected)) {
  6547. preSelected = preSelected && preSelected!=="" ? preSelected.split(settings.delimiter) : [];
  6548. }
  6549. $.each(preSelected,function(index,value){
  6550. $item.filter('[data-value="'+value+'"]')
  6551. .addClass(className.filtered)
  6552. ;
  6553. });
  6554. afterFiltered();
  6555. });
  6556. }
  6557. else {
  6558. module.error(error.noAPI);
  6559. }
  6560. }
  6561. else {
  6562. module.filterItems(searchTerm);
  6563. afterFiltered();
  6564. }
  6565. },
  6566. queryRemote: function(query, callback) {
  6567. var
  6568. apiSettings = {
  6569. errorDuration : false,
  6570. cache : 'local',
  6571. throttle : settings.throttle,
  6572. urlData : {
  6573. query: query
  6574. },
  6575. onError: function() {
  6576. module.add.message(message.serverError);
  6577. callback();
  6578. },
  6579. onFailure: function() {
  6580. module.add.message(message.serverError);
  6581. callback();
  6582. },
  6583. onSuccess : function(response) {
  6584. var
  6585. values = response[fields.remoteValues]
  6586. ;
  6587. if (!Array.isArray(values)){
  6588. values = [];
  6589. }
  6590. module.remove.message();
  6591. module.setup.menu({
  6592. values: values
  6593. });
  6594. if(values.length===0 && !settings.allowAdditions) {
  6595. module.add.message(message.noResults);
  6596. }
  6597. callback();
  6598. }
  6599. }
  6600. ;
  6601. if( !$module.api('get request') ) {
  6602. module.setup.api();
  6603. }
  6604. apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings);
  6605. $module
  6606. .api('setting', apiSettings)
  6607. .api('query')
  6608. ;
  6609. },
  6610. filterItems: function(query) {
  6611. var
  6612. searchTerm = module.remove.diacritics(query !== undefined
  6613. ? query
  6614. : module.get.query()
  6615. ),
  6616. results = null,
  6617. escapedTerm = module.escape.string(searchTerm),
  6618. beginsWithRegExp = new RegExp('^' + escapedTerm, 'igm')
  6619. ;
  6620. // avoid loop if we're matching nothing
  6621. if( module.has.query() ) {
  6622. results = [];
  6623. module.verbose('Searching for matching values', searchTerm);
  6624. $item
  6625. .each(function(){
  6626. var
  6627. $choice = $(this),
  6628. text,
  6629. value
  6630. ;
  6631. if(settings.match === 'both' || settings.match === 'text') {
  6632. text = module.remove.diacritics(String(module.get.choiceText($choice, false)));
  6633. if(text.search(beginsWithRegExp) !== -1) {
  6634. results.push(this);
  6635. return true;
  6636. }
  6637. else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
  6638. results.push(this);
  6639. return true;
  6640. }
  6641. else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
  6642. results.push(this);
  6643. return true;
  6644. }
  6645. }
  6646. if(settings.match === 'both' || settings.match === 'value') {
  6647. value = module.remove.diacritics(String(module.get.choiceValue($choice, text)));
  6648. if(value.search(beginsWithRegExp) !== -1) {
  6649. results.push(this);
  6650. return true;
  6651. }
  6652. else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value)) {
  6653. results.push(this);
  6654. return true;
  6655. }
  6656. else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value)) {
  6657. results.push(this);
  6658. return true;
  6659. }
  6660. }
  6661. })
  6662. ;
  6663. }
  6664. module.debug('Showing only matched items', searchTerm);
  6665. module.remove.filteredItem();
  6666. if(results) {
  6667. $item
  6668. .not(results)
  6669. .addClass(className.filtered)
  6670. ;
  6671. }
  6672. if(!module.has.query()) {
  6673. $divider
  6674. .removeClass(className.hidden);
  6675. } else if(settings.hideDividers === true) {
  6676. $divider
  6677. .addClass(className.hidden);
  6678. } else if(settings.hideDividers === 'empty') {
  6679. $divider
  6680. .removeClass(className.hidden)
  6681. .filter(function() {
  6682. // First find the last divider in this divider group
  6683. // Dividers which are direct siblings are considered a group
  6684. var lastDivider = $(this).nextUntil(selector.item);
  6685. return (lastDivider.length ? lastDivider : $(this))
  6686. // Count all non-filtered items until the next divider (or end of the dropdown)
  6687. .nextUntil(selector.divider)
  6688. .filter(selector.item + ":not(." + className.filtered + ")")
  6689. // Hide divider if no items are found
  6690. .length === 0;
  6691. })
  6692. .addClass(className.hidden);
  6693. }
  6694. },
  6695. fuzzySearch: function(query, term) {
  6696. var
  6697. termLength = term.length,
  6698. queryLength = query.length
  6699. ;
  6700. query = query.toLowerCase();
  6701. term = term.toLowerCase();
  6702. if(queryLength > termLength) {
  6703. return false;
  6704. }
  6705. if(queryLength === termLength) {
  6706. return (query === term);
  6707. }
  6708. search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
  6709. var
  6710. queryCharacter = query.charCodeAt(characterIndex)
  6711. ;
  6712. while(nextCharacterIndex < termLength) {
  6713. if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
  6714. continue search;
  6715. }
  6716. }
  6717. return false;
  6718. }
  6719. return true;
  6720. },
  6721. exactSearch: function (query, term) {
  6722. query = query.toLowerCase();
  6723. term = term.toLowerCase();
  6724. return term.indexOf(query) > -1;
  6725. },
  6726. filterActive: function() {
  6727. if(settings.useLabels) {
  6728. $item.filter('.' + className.active)
  6729. .addClass(className.filtered)
  6730. ;
  6731. }
  6732. },
  6733. focusSearch: function(skipHandler) {
  6734. if( module.has.search() && !module.is.focusedOnSearch() ) {
  6735. if(skipHandler) {
  6736. $module.off('focus' + eventNamespace, selector.search);
  6737. $search.focus();
  6738. $module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
  6739. }
  6740. else {
  6741. $search.focus();
  6742. }
  6743. }
  6744. },
  6745. blurSearch: function() {
  6746. if( module.has.search() ) {
  6747. $search.blur();
  6748. }
  6749. },
  6750. forceSelection: function() {
  6751. var
  6752. $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
  6753. $activeItem = $item.not(className.filtered).filter('.' + className.active).eq(0),
  6754. $selectedItem = ($currentlySelected.length > 0)
  6755. ? $currentlySelected
  6756. : $activeItem,
  6757. hasSelected = ($selectedItem.length > 0)
  6758. ;
  6759. if(hasSelected && !module.is.multiple()) {
  6760. module.debug('Forcing partial selection to selected item', $selectedItem);
  6761. module.event.item.click.call($selectedItem, {}, true);
  6762. }
  6763. else {
  6764. if(settings.allowAdditions) {
  6765. module.set.selected(module.get.query());
  6766. module.remove.searchTerm();
  6767. }
  6768. else {
  6769. module.remove.searchTerm();
  6770. }
  6771. }
  6772. },
  6773. change: {
  6774. values: function(values) {
  6775. if(!settings.allowAdditions) {
  6776. module.clear();
  6777. }
  6778. module.debug('Creating dropdown with specified values', values);
  6779. module.setup.menu({values: values});
  6780. $.each(values, function(index, item) {
  6781. if(item.selected == true) {
  6782. module.debug('Setting initial selection to', item[fields.value]);
  6783. module.set.selected(item[fields.value]);
  6784. if(!module.is.multiple()) {
  6785. return false;
  6786. }
  6787. }
  6788. });
  6789. }
  6790. },
  6791. event: {
  6792. change: function() {
  6793. if(!internalChange) {
  6794. module.debug('Input changed, updating selection');
  6795. module.set.selected();
  6796. }
  6797. },
  6798. focus: function() {
  6799. if(settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
  6800. module.show();
  6801. }
  6802. },
  6803. blur: function(event) {
  6804. pageLostFocus = (document.activeElement === this);
  6805. if(!activated && !pageLostFocus) {
  6806. module.remove.activeLabel();
  6807. module.hide();
  6808. }
  6809. },
  6810. mousedown: function() {
  6811. if(module.is.searchSelection()) {
  6812. // prevent menu hiding on immediate re-focus
  6813. willRefocus = true;
  6814. }
  6815. else {
  6816. // prevents focus callback from occurring on mousedown
  6817. activated = true;
  6818. }
  6819. },
  6820. mouseup: function() {
  6821. if(module.is.searchSelection()) {
  6822. // prevent menu hiding on immediate re-focus
  6823. willRefocus = false;
  6824. }
  6825. else {
  6826. activated = false;
  6827. }
  6828. },
  6829. click: function(event) {
  6830. var
  6831. $target = $(event.target)
  6832. ;
  6833. // focus search
  6834. if($target.is($module)) {
  6835. if(!module.is.focusedOnSearch()) {
  6836. module.focusSearch();
  6837. }
  6838. else {
  6839. module.show();
  6840. }
  6841. }
  6842. },
  6843. search: {
  6844. focus: function(event) {
  6845. activated = true;
  6846. if(module.is.multiple()) {
  6847. module.remove.activeLabel();
  6848. }
  6849. if(settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin')) {
  6850. module.search();
  6851. }
  6852. },
  6853. blur: function(event) {
  6854. pageLostFocus = (document.activeElement === this);
  6855. if(module.is.searchSelection() && !willRefocus) {
  6856. if(!itemActivated && !pageLostFocus) {
  6857. if(settings.forceSelection) {
  6858. module.forceSelection();
  6859. }
  6860. module.hide();
  6861. }
  6862. }
  6863. willRefocus = false;
  6864. }
  6865. },
  6866. clearIcon: {
  6867. click: function(event) {
  6868. module.clear();
  6869. if(module.is.searchSelection()) {
  6870. module.remove.searchTerm();
  6871. }
  6872. module.hide();
  6873. event.stopPropagation();
  6874. }
  6875. },
  6876. icon: {
  6877. click: function(event) {
  6878. iconClicked=true;
  6879. if(module.has.search()) {
  6880. if(!module.is.active()) {
  6881. if(settings.showOnFocus){
  6882. module.focusSearch();
  6883. } else {
  6884. module.toggle();
  6885. }
  6886. } else {
  6887. module.blurSearch();
  6888. }
  6889. } else {
  6890. module.toggle();
  6891. }
  6892. }
  6893. },
  6894. text: {
  6895. focus: function(event) {
  6896. activated = true;
  6897. module.focusSearch();
  6898. }
  6899. },
  6900. input: function(event) {
  6901. if(module.is.multiple() || module.is.searchSelection()) {
  6902. module.set.filtered();
  6903. }
  6904. clearTimeout(module.timer);
  6905. module.timer = setTimeout(module.search, settings.delay.search);
  6906. },
  6907. label: {
  6908. click: function(event) {
  6909. var
  6910. $label = $(this),
  6911. $labels = $module.find(selector.label),
  6912. $activeLabels = $labels.filter('.' + className.active),
  6913. $nextActive = $label.nextAll('.' + className.active),
  6914. $prevActive = $label.prevAll('.' + className.active),
  6915. $range = ($nextActive.length > 0)
  6916. ? $label.nextUntil($nextActive).add($activeLabels).add($label)
  6917. : $label.prevUntil($prevActive).add($activeLabels).add($label)
  6918. ;
  6919. if(event.shiftKey) {
  6920. $activeLabels.removeClass(className.active);
  6921. $range.addClass(className.active);
  6922. }
  6923. else if(event.ctrlKey) {
  6924. $label.toggleClass(className.active);
  6925. }
  6926. else {
  6927. $activeLabels.removeClass(className.active);
  6928. $label.addClass(className.active);
  6929. }
  6930. settings.onLabelSelect.apply(this, $labels.filter('.' + className.active));
  6931. }
  6932. },
  6933. remove: {
  6934. click: function() {
  6935. var
  6936. $label = $(this).parent()
  6937. ;
  6938. if( $label.hasClass(className.active) ) {
  6939. // remove all selected labels
  6940. module.remove.activeLabels();
  6941. }
  6942. else {
  6943. // remove this label only
  6944. module.remove.activeLabels( $label );
  6945. }
  6946. }
  6947. },
  6948. test: {
  6949. toggle: function(event) {
  6950. var
  6951. toggleBehavior = (module.is.multiple())
  6952. ? module.show
  6953. : module.toggle
  6954. ;
  6955. if(module.is.bubbledLabelClick(event) || module.is.bubbledIconClick(event)) {
  6956. return;
  6957. }
  6958. if( module.determine.eventOnElement(event, toggleBehavior) ) {
  6959. event.preventDefault();
  6960. }
  6961. },
  6962. touch: function(event) {
  6963. module.determine.eventOnElement(event, function() {
  6964. if(event.type == 'touchstart') {
  6965. module.timer = setTimeout(function() {
  6966. module.hide();
  6967. }, settings.delay.touch);
  6968. }
  6969. else if(event.type == 'touchmove') {
  6970. clearTimeout(module.timer);
  6971. }
  6972. });
  6973. event.stopPropagation();
  6974. },
  6975. hide: function(event) {
  6976. if(module.determine.eventInModule(event, module.hide)){
  6977. if(element.id && $(event.target).attr('for') === element.id){
  6978. event.preventDefault();
  6979. }
  6980. }
  6981. }
  6982. },
  6983. select: {
  6984. mutation: function(mutations) {
  6985. module.debug('<select> modified, recreating menu');
  6986. if(module.is.selectMutation(mutations)) {
  6987. module.disconnect.selectObserver();
  6988. module.refresh();
  6989. module.setup.select();
  6990. module.set.selected();
  6991. module.observe.select();
  6992. }
  6993. }
  6994. },
  6995. menu: {
  6996. mutation: function(mutations) {
  6997. var
  6998. mutation = mutations[0],
  6999. $addedNode = mutation.addedNodes
  7000. ? $(mutation.addedNodes[0])
  7001. : $(false),
  7002. $removedNode = mutation.removedNodes
  7003. ? $(mutation.removedNodes[0])
  7004. : $(false),
  7005. $changedNodes = $addedNode.add($removedNode),
  7006. isUserAddition = $changedNodes.is(selector.addition) || $changedNodes.closest(selector.addition).length > 0,
  7007. isMessage = $changedNodes.is(selector.message) || $changedNodes.closest(selector.message).length > 0
  7008. ;
  7009. if(isUserAddition || isMessage) {
  7010. module.debug('Updating item selector cache');
  7011. module.refreshItems();
  7012. }
  7013. else {
  7014. module.debug('Menu modified, updating selector cache');
  7015. module.refresh();
  7016. }
  7017. },
  7018. mousedown: function() {
  7019. itemActivated = true;
  7020. },
  7021. mouseup: function() {
  7022. itemActivated = false;
  7023. }
  7024. },
  7025. item: {
  7026. mouseenter: function(event) {
  7027. var
  7028. $target = $(event.target),
  7029. $item = $(this),
  7030. $subMenu = $item.children(selector.menu),
  7031. $otherMenus = $item.siblings(selector.item).children(selector.menu),
  7032. hasSubMenu = ($subMenu.length > 0),
  7033. isBubbledEvent = ($subMenu.find($target).length > 0)
  7034. ;
  7035. if( !isBubbledEvent && hasSubMenu ) {
  7036. clearTimeout(module.itemTimer);
  7037. module.itemTimer = setTimeout(function() {
  7038. module.verbose('Showing sub-menu', $subMenu);
  7039. $.each($otherMenus, function() {
  7040. module.animate.hide(false, $(this));
  7041. });
  7042. module.animate.show(false, $subMenu);
  7043. }, settings.delay.show);
  7044. event.preventDefault();
  7045. }
  7046. },
  7047. mouseleave: function(event) {
  7048. var
  7049. $subMenu = $(this).children(selector.menu)
  7050. ;
  7051. if($subMenu.length > 0) {
  7052. clearTimeout(module.itemTimer);
  7053. module.itemTimer = setTimeout(function() {
  7054. module.verbose('Hiding sub-menu', $subMenu);
  7055. module.animate.hide(false, $subMenu);
  7056. }, settings.delay.hide);
  7057. }
  7058. },
  7059. click: function (event, skipRefocus) {
  7060. var
  7061. $choice = $(this),
  7062. $target = (event)
  7063. ? $(event.target)
  7064. : $(''),
  7065. $subMenu = $choice.find(selector.menu),
  7066. text = module.get.choiceText($choice),
  7067. value = module.get.choiceValue($choice, text),
  7068. hasSubMenu = ($subMenu.length > 0),
  7069. isBubbledEvent = ($subMenu.find($target).length > 0)
  7070. ;
  7071. // prevents IE11 bug where menu receives focus even though `tabindex=-1`
  7072. if (document.activeElement.tagName.toLowerCase() !== 'input') {
  7073. $(document.activeElement).blur();
  7074. }
  7075. if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
  7076. if(module.is.searchSelection()) {
  7077. if(settings.allowAdditions) {
  7078. module.remove.userAddition();
  7079. }
  7080. module.remove.searchTerm();
  7081. if(!module.is.focusedOnSearch() && !(skipRefocus == true)) {
  7082. module.focusSearch(true);
  7083. }
  7084. }
  7085. if(!settings.useLabels) {
  7086. module.remove.filteredItem();
  7087. module.set.scrollPosition($choice);
  7088. }
  7089. module.determine.selectAction.call(this, text, value);
  7090. }
  7091. }
  7092. },
  7093. document: {
  7094. // label selection should occur even when element has no focus
  7095. keydown: function(event) {
  7096. var
  7097. pressedKey = event.which,
  7098. isShortcutKey = module.is.inObject(pressedKey, keys)
  7099. ;
  7100. if(isShortcutKey) {
  7101. var
  7102. $label = $module.find(selector.label),
  7103. $activeLabel = $label.filter('.' + className.active),
  7104. activeValue = $activeLabel.data(metadata.value),
  7105. labelIndex = $label.index($activeLabel),
  7106. labelCount = $label.length,
  7107. hasActiveLabel = ($activeLabel.length > 0),
  7108. hasMultipleActive = ($activeLabel.length > 1),
  7109. isFirstLabel = (labelIndex === 0),
  7110. isLastLabel = (labelIndex + 1 == labelCount),
  7111. isSearch = module.is.searchSelection(),
  7112. isFocusedOnSearch = module.is.focusedOnSearch(),
  7113. isFocused = module.is.focused(),
  7114. caretAtStart = (isFocusedOnSearch && module.get.caretPosition(false) === 0),
  7115. isSelectedSearch = (caretAtStart && module.get.caretPosition(true) !== 0),
  7116. $nextLabel
  7117. ;
  7118. if(isSearch && !hasActiveLabel && !isFocusedOnSearch) {
  7119. return;
  7120. }
  7121. if(pressedKey == keys.leftArrow) {
  7122. // activate previous label
  7123. if((isFocused || caretAtStart) && !hasActiveLabel) {
  7124. module.verbose('Selecting previous label');
  7125. $label.last().addClass(className.active);
  7126. }
  7127. else if(hasActiveLabel) {
  7128. if(!event.shiftKey) {
  7129. module.verbose('Selecting previous label');
  7130. $label.removeClass(className.active);
  7131. }
  7132. else {
  7133. module.verbose('Adding previous label to selection');
  7134. }
  7135. if(isFirstLabel && !hasMultipleActive) {
  7136. $activeLabel.addClass(className.active);
  7137. }
  7138. else {
  7139. $activeLabel.prev(selector.siblingLabel)
  7140. .addClass(className.active)
  7141. .end()
  7142. ;
  7143. }
  7144. event.preventDefault();
  7145. }
  7146. }
  7147. else if(pressedKey == keys.rightArrow) {
  7148. // activate first label
  7149. if(isFocused && !hasActiveLabel) {
  7150. $label.first().addClass(className.active);
  7151. }
  7152. // activate next label
  7153. if(hasActiveLabel) {
  7154. if(!event.shiftKey) {
  7155. module.verbose('Selecting next label');
  7156. $label.removeClass(className.active);
  7157. }
  7158. else {
  7159. module.verbose('Adding next label to selection');
  7160. }
  7161. if(isLastLabel) {
  7162. if(isSearch) {
  7163. if(!isFocusedOnSearch) {
  7164. module.focusSearch();
  7165. }
  7166. else {
  7167. $label.removeClass(className.active);
  7168. }
  7169. }
  7170. else if(hasMultipleActive) {
  7171. $activeLabel.next(selector.siblingLabel).addClass(className.active);
  7172. }
  7173. else {
  7174. $activeLabel.addClass(className.active);
  7175. }
  7176. }
  7177. else {
  7178. $activeLabel.next(selector.siblingLabel).addClass(className.active);
  7179. }
  7180. event.preventDefault();
  7181. }
  7182. }
  7183. else if(pressedKey == keys.deleteKey || pressedKey == keys.backspace) {
  7184. if(hasActiveLabel) {
  7185. module.verbose('Removing active labels');
  7186. if(isLastLabel) {
  7187. if(isSearch && !isFocusedOnSearch) {
  7188. module.focusSearch();
  7189. }
  7190. }
  7191. $activeLabel.last().next(selector.siblingLabel).addClass(className.active);
  7192. module.remove.activeLabels($activeLabel);
  7193. event.preventDefault();
  7194. }
  7195. else if(caretAtStart && !isSelectedSearch && !hasActiveLabel && pressedKey == keys.backspace) {
  7196. module.verbose('Removing last label on input backspace');
  7197. $activeLabel = $label.last().addClass(className.active);
  7198. module.remove.activeLabels($activeLabel);
  7199. }
  7200. }
  7201. else {
  7202. $activeLabel.removeClass(className.active);
  7203. }
  7204. }
  7205. }
  7206. },
  7207. keydown: function(event) {
  7208. var
  7209. pressedKey = event.which,
  7210. isShortcutKey = module.is.inObject(pressedKey, keys)
  7211. ;
  7212. if(isShortcutKey) {
  7213. var
  7214. $currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
  7215. $activeItem = $menu.children('.' + className.active).eq(0),
  7216. $selectedItem = ($currentlySelected.length > 0)
  7217. ? $currentlySelected
  7218. : $activeItem,
  7219. $visibleItems = ($selectedItem.length > 0)
  7220. ? $selectedItem.siblings(':not(.' + className.filtered +')').addBack()
  7221. : $menu.children(':not(.' + className.filtered +')'),
  7222. $subMenu = $selectedItem.children(selector.menu),
  7223. $parentMenu = $selectedItem.closest(selector.menu),
  7224. inVisibleMenu = ($parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0),
  7225. hasSubMenu = ($subMenu.length> 0),
  7226. hasSelectedItem = ($selectedItem.length > 0),
  7227. selectedIsSelectable = ($selectedItem.not(selector.unselectable).length > 0),
  7228. delimiterPressed = (pressedKey == keys.delimiter && settings.allowAdditions && module.is.multiple()),
  7229. isAdditionWithoutMenu = (settings.allowAdditions && settings.hideAdditions && (pressedKey == keys.enter || delimiterPressed) && selectedIsSelectable),
  7230. $nextItem,
  7231. isSubMenuItem,
  7232. newIndex
  7233. ;
  7234. // allow selection with menu closed
  7235. if(isAdditionWithoutMenu) {
  7236. module.verbose('Selecting item from keyboard shortcut', $selectedItem);
  7237. module.event.item.click.call($selectedItem, event);
  7238. if(module.is.searchSelection()) {
  7239. module.remove.searchTerm();
  7240. }
  7241. if(module.is.multiple()){
  7242. event.preventDefault();
  7243. }
  7244. }
  7245. // visible menu keyboard shortcuts
  7246. if( module.is.visible() ) {
  7247. // enter (select or open sub-menu)
  7248. if(pressedKey == keys.enter || delimiterPressed) {
  7249. if(pressedKey == keys.enter && hasSelectedItem && hasSubMenu && !settings.allowCategorySelection) {
  7250. module.verbose('Pressed enter on unselectable category, opening sub menu');
  7251. pressedKey = keys.rightArrow;
  7252. }
  7253. else if(selectedIsSelectable) {
  7254. module.verbose('Selecting item from keyboard shortcut', $selectedItem);
  7255. module.event.item.click.call($selectedItem, event);
  7256. if(module.is.searchSelection()) {
  7257. module.remove.searchTerm();
  7258. if(module.is.multiple()) {
  7259. $search.focus();
  7260. }
  7261. }
  7262. }
  7263. event.preventDefault();
  7264. }
  7265. // sub-menu actions
  7266. if(hasSelectedItem) {
  7267. if(pressedKey == keys.leftArrow) {
  7268. isSubMenuItem = ($parentMenu[0] !== $menu[0]);
  7269. if(isSubMenuItem) {
  7270. module.verbose('Left key pressed, closing sub-menu');
  7271. module.animate.hide(false, $parentMenu);
  7272. $selectedItem
  7273. .removeClass(className.selected)
  7274. ;
  7275. $parentMenu
  7276. .closest(selector.item)
  7277. .addClass(className.selected)
  7278. ;
  7279. event.preventDefault();
  7280. }
  7281. }
  7282. // right arrow (show sub-menu)
  7283. if(pressedKey == keys.rightArrow) {
  7284. if(hasSubMenu) {
  7285. module.verbose('Right key pressed, opening sub-menu');
  7286. module.animate.show(false, $subMenu);
  7287. $selectedItem
  7288. .removeClass(className.selected)
  7289. ;
  7290. $subMenu
  7291. .find(selector.item).eq(0)
  7292. .addClass(className.selected)
  7293. ;
  7294. event.preventDefault();
  7295. }
  7296. }
  7297. }
  7298. // up arrow (traverse menu up)
  7299. if(pressedKey == keys.upArrow) {
  7300. $nextItem = (hasSelectedItem && inVisibleMenu)
  7301. ? $selectedItem.prevAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
  7302. : $item.eq(0)
  7303. ;
  7304. if($visibleItems.index( $nextItem ) < 0) {
  7305. module.verbose('Up key pressed but reached top of current menu');
  7306. event.preventDefault();
  7307. return;
  7308. }
  7309. else {
  7310. module.verbose('Up key pressed, changing active item');
  7311. $selectedItem
  7312. .removeClass(className.selected)
  7313. ;
  7314. $nextItem
  7315. .addClass(className.selected)
  7316. ;
  7317. module.set.scrollPosition($nextItem);
  7318. if(settings.selectOnKeydown && module.is.single()) {
  7319. module.set.selectedItem($nextItem);
  7320. }
  7321. }
  7322. event.preventDefault();
  7323. }
  7324. // down arrow (traverse menu down)
  7325. if(pressedKey == keys.downArrow) {
  7326. $nextItem = (hasSelectedItem && inVisibleMenu)
  7327. ? $nextItem = $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
  7328. : $item.eq(0)
  7329. ;
  7330. if($nextItem.length === 0) {
  7331. module.verbose('Down key pressed but reached bottom of current menu');
  7332. event.preventDefault();
  7333. return;
  7334. }
  7335. else {
  7336. module.verbose('Down key pressed, changing active item');
  7337. $item
  7338. .removeClass(className.selected)
  7339. ;
  7340. $nextItem
  7341. .addClass(className.selected)
  7342. ;
  7343. module.set.scrollPosition($nextItem);
  7344. if(settings.selectOnKeydown && module.is.single()) {
  7345. module.set.selectedItem($nextItem);
  7346. }
  7347. }
  7348. event.preventDefault();
  7349. }
  7350. // page down (show next page)
  7351. if(pressedKey == keys.pageUp) {
  7352. module.scrollPage('up');
  7353. event.preventDefault();
  7354. }
  7355. if(pressedKey == keys.pageDown) {
  7356. module.scrollPage('down');
  7357. event.preventDefault();
  7358. }
  7359. // escape (close menu)
  7360. if(pressedKey == keys.escape) {
  7361. module.verbose('Escape key pressed, closing dropdown');
  7362. module.hide();
  7363. }
  7364. }
  7365. else {
  7366. // delimiter key
  7367. if(delimiterPressed) {
  7368. event.preventDefault();
  7369. }
  7370. // down arrow (open menu)
  7371. if(pressedKey == keys.downArrow && !module.is.visible()) {
  7372. module.verbose('Down key pressed, showing dropdown');
  7373. module.show();
  7374. event.preventDefault();
  7375. }
  7376. }
  7377. }
  7378. else {
  7379. if( !module.has.search() ) {
  7380. module.set.selectedLetter( String.fromCharCode(pressedKey) );
  7381. }
  7382. }
  7383. }
  7384. },
  7385. trigger: {
  7386. change: function() {
  7387. var
  7388. events = document.createEvent('HTMLEvents'),
  7389. inputElement = $input[0]
  7390. ;
  7391. if(inputElement) {
  7392. module.verbose('Triggering native change event');
  7393. events.initEvent('change', true, false);
  7394. inputElement.dispatchEvent(events);
  7395. }
  7396. }
  7397. },
  7398. determine: {
  7399. selectAction: function(text, value) {
  7400. selectActionActive = true;
  7401. module.verbose('Determining action', settings.action);
  7402. if( $.isFunction( module.action[settings.action] ) ) {
  7403. module.verbose('Triggering preset action', settings.action, text, value);
  7404. module.action[ settings.action ].call(element, text, value, this);
  7405. }
  7406. else if( $.isFunction(settings.action) ) {
  7407. module.verbose('Triggering user action', settings.action, text, value);
  7408. settings.action.call(element, text, value, this);
  7409. }
  7410. else {
  7411. module.error(error.action, settings.action);
  7412. }
  7413. selectActionActive = false;
  7414. },
  7415. eventInModule: function(event, callback) {
  7416. var
  7417. $target = $(event.target),
  7418. inDocument = ($target.closest(document.documentElement).length > 0),
  7419. inModule = ($target.closest($module).length > 0)
  7420. ;
  7421. callback = $.isFunction(callback)
  7422. ? callback
  7423. : function(){}
  7424. ;
  7425. if(inDocument && !inModule) {
  7426. module.verbose('Triggering event', callback);
  7427. callback();
  7428. return true;
  7429. }
  7430. else {
  7431. module.verbose('Event occurred in dropdown, canceling callback');
  7432. return false;
  7433. }
  7434. },
  7435. eventOnElement: function(event, callback) {
  7436. var
  7437. $target = $(event.target),
  7438. $label = $target.closest(selector.siblingLabel),
  7439. inVisibleDOM = document.body.contains(event.target),
  7440. notOnLabel = ($module.find($label).length === 0 || !(module.is.multiple() && settings.useLabels)),
  7441. notInMenu = ($target.closest($menu).length === 0)
  7442. ;
  7443. callback = $.isFunction(callback)
  7444. ? callback
  7445. : function(){}
  7446. ;
  7447. if(inVisibleDOM && notOnLabel && notInMenu) {
  7448. module.verbose('Triggering event', callback);
  7449. callback();
  7450. return true;
  7451. }
  7452. else {
  7453. module.verbose('Event occurred in dropdown menu, canceling callback');
  7454. return false;
  7455. }
  7456. }
  7457. },
  7458. action: {
  7459. nothing: function() {},
  7460. activate: function(text, value, element) {
  7461. value = (value !== undefined)
  7462. ? value
  7463. : text
  7464. ;
  7465. if( module.can.activate( $(element) ) ) {
  7466. module.set.selected(value, $(element));
  7467. if(!module.is.multiple()) {
  7468. module.hideAndClear();
  7469. }
  7470. }
  7471. },
  7472. select: function(text, value, element) {
  7473. value = (value !== undefined)
  7474. ? value
  7475. : text
  7476. ;
  7477. if( module.can.activate( $(element) ) ) {
  7478. module.set.value(value, text, $(element));
  7479. if(!module.is.multiple()) {
  7480. module.hideAndClear();
  7481. }
  7482. }
  7483. },
  7484. combo: function(text, value, element) {
  7485. value = (value !== undefined)
  7486. ? value
  7487. : text
  7488. ;
  7489. module.set.selected(value, $(element));
  7490. module.hideAndClear();
  7491. },
  7492. hide: function(text, value, element) {
  7493. module.set.value(value, text, $(element));
  7494. module.hideAndClear();
  7495. }
  7496. },
  7497. get: {
  7498. id: function() {
  7499. return id;
  7500. },
  7501. defaultText: function() {
  7502. return $module.data(metadata.defaultText);
  7503. },
  7504. defaultValue: function() {
  7505. return $module.data(metadata.defaultValue);
  7506. },
  7507. placeholderText: function() {
  7508. if(settings.placeholder != 'auto' && typeof settings.placeholder == 'string') {
  7509. return settings.placeholder;
  7510. }
  7511. return $module.data(metadata.placeholderText) || '';
  7512. },
  7513. text: function() {
  7514. return $text.text();
  7515. },
  7516. query: function() {
  7517. return $.trim($search.val());
  7518. },
  7519. searchWidth: function(value) {
  7520. value = (value !== undefined)
  7521. ? value
  7522. : $search.val()
  7523. ;
  7524. $sizer.text(value);
  7525. // prevent rounding issues
  7526. return Math.ceil( $sizer.width() + 1);
  7527. },
  7528. selectionCount: function() {
  7529. var
  7530. values = module.get.values(),
  7531. count
  7532. ;
  7533. count = ( module.is.multiple() )
  7534. ? Array.isArray(values)
  7535. ? values.length
  7536. : 0
  7537. : (module.get.value() !== '')
  7538. ? 1
  7539. : 0
  7540. ;
  7541. return count;
  7542. },
  7543. transition: function($subMenu) {
  7544. return (settings.transition == 'auto')
  7545. ? module.is.upward($subMenu)
  7546. ? 'slide up'
  7547. : 'slide down'
  7548. : settings.transition
  7549. ;
  7550. },
  7551. userValues: function() {
  7552. var
  7553. values = module.get.values()
  7554. ;
  7555. if(!values) {
  7556. return false;
  7557. }
  7558. values = Array.isArray(values)
  7559. ? values
  7560. : [values]
  7561. ;
  7562. return $.grep(values, function(value) {
  7563. return (module.get.item(value) === false);
  7564. });
  7565. },
  7566. uniqueArray: function(array) {
  7567. return $.grep(array, function (value, index) {
  7568. return $.inArray(value, array) === index;
  7569. });
  7570. },
  7571. caretPosition: function(returnEndPos) {
  7572. var
  7573. input = $search.get(0),
  7574. range,
  7575. rangeLength
  7576. ;
  7577. if(returnEndPos && 'selectionEnd' in input){
  7578. return input.selectionEnd;
  7579. }
  7580. else if(!returnEndPos && 'selectionStart' in input) {
  7581. return input.selectionStart;
  7582. }
  7583. if (document.selection) {
  7584. input.focus();
  7585. range = document.selection.createRange();
  7586. rangeLength = range.text.length;
  7587. if(returnEndPos) {
  7588. return rangeLength;
  7589. }
  7590. range.moveStart('character', -input.value.length);
  7591. return range.text.length - rangeLength;
  7592. }
  7593. },
  7594. value: function() {
  7595. var
  7596. value = ($input.length > 0)
  7597. ? $input.val()
  7598. : $module.data(metadata.value),
  7599. isEmptyMultiselect = (Array.isArray(value) && value.length === 1 && value[0] === '')
  7600. ;
  7601. // prevents placeholder element from being selected when multiple
  7602. return (value === undefined || isEmptyMultiselect)
  7603. ? ''
  7604. : value
  7605. ;
  7606. },
  7607. values: function() {
  7608. var
  7609. value = module.get.value()
  7610. ;
  7611. if(value === '') {
  7612. return '';
  7613. }
  7614. return ( !module.has.selectInput() && module.is.multiple() )
  7615. ? (typeof value == 'string') // delimited string
  7616. ? module.escape.htmlEntities(value).split(settings.delimiter)
  7617. : ''
  7618. : value
  7619. ;
  7620. },
  7621. remoteValues: function() {
  7622. var
  7623. values = module.get.values(),
  7624. remoteValues = false
  7625. ;
  7626. if(values) {
  7627. if(typeof values == 'string') {
  7628. values = [values];
  7629. }
  7630. $.each(values, function(index, value) {
  7631. var
  7632. name = module.read.remoteData(value)
  7633. ;
  7634. module.verbose('Restoring value from session data', name, value);
  7635. if(name) {
  7636. if(!remoteValues) {
  7637. remoteValues = {};
  7638. }
  7639. remoteValues[value] = name;
  7640. }
  7641. });
  7642. }
  7643. return remoteValues;
  7644. },
  7645. choiceText: function($choice, preserveHTML) {
  7646. preserveHTML = (preserveHTML !== undefined)
  7647. ? preserveHTML
  7648. : settings.preserveHTML
  7649. ;
  7650. if($choice) {
  7651. if($choice.find(selector.menu).length > 0) {
  7652. module.verbose('Retrieving text of element with sub-menu');
  7653. $choice = $choice.clone();
  7654. $choice.find(selector.menu).remove();
  7655. $choice.find(selector.menuIcon).remove();
  7656. }
  7657. return ($choice.data(metadata.text) !== undefined)
  7658. ? $choice.data(metadata.text)
  7659. : (preserveHTML)
  7660. ? $.trim($choice.html())
  7661. : $.trim($choice.text())
  7662. ;
  7663. }
  7664. },
  7665. choiceValue: function($choice, choiceText) {
  7666. choiceText = choiceText || module.get.choiceText($choice);
  7667. if(!$choice) {
  7668. return false;
  7669. }
  7670. return ($choice.data(metadata.value) !== undefined)
  7671. ? String( $choice.data(metadata.value) )
  7672. : (typeof choiceText === 'string')
  7673. ? $.trim(choiceText.toLowerCase())
  7674. : String(choiceText)
  7675. ;
  7676. },
  7677. inputEvent: function() {
  7678. var
  7679. input = $search[0]
  7680. ;
  7681. if(input) {
  7682. return (input.oninput !== undefined)
  7683. ? 'input'
  7684. : (input.onpropertychange !== undefined)
  7685. ? 'propertychange'
  7686. : 'keyup'
  7687. ;
  7688. }
  7689. return false;
  7690. },
  7691. selectValues: function() {
  7692. var
  7693. select = {},
  7694. oldGroup = []
  7695. ;
  7696. select.values = [];
  7697. $module
  7698. .find('option')
  7699. .each(function() {
  7700. var
  7701. $option = $(this),
  7702. name = $option.html(),
  7703. disabled = $option.attr('disabled'),
  7704. value = ( $option.attr('value') !== undefined )
  7705. ? $option.attr('value')
  7706. : name,
  7707. group = $option.parent('optgroup')
  7708. ;
  7709. if(settings.placeholder === 'auto' && value === '') {
  7710. select.placeholder = name;
  7711. }
  7712. else {
  7713. if(group.length !== oldGroup.length || group[0] !== oldGroup[0]) {
  7714. select.values.push({
  7715. type: 'header',
  7716. divider: settings.headerDivider,
  7717. name: group.attr('label') || ''
  7718. });
  7719. oldGroup = group;
  7720. }
  7721. select.values.push({
  7722. name : name,
  7723. value : value,
  7724. disabled : disabled
  7725. });
  7726. }
  7727. })
  7728. ;
  7729. if(settings.placeholder && settings.placeholder !== 'auto') {
  7730. module.debug('Setting placeholder value to', settings.placeholder);
  7731. select.placeholder = settings.placeholder;
  7732. }
  7733. if(settings.sortSelect) {
  7734. if(settings.sortSelect === true) {
  7735. select.values.sort(function(a, b) {
  7736. return a.name.localeCompare(b.name);
  7737. });
  7738. } else if(settings.sortSelect === 'natural') {
  7739. select.values.sort(function(a, b) {
  7740. return (a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
  7741. });
  7742. } else if($.isFunction(settings.sortSelect)) {
  7743. select.values.sort(settings.sortSelect);
  7744. }
  7745. module.debug('Retrieved and sorted values from select', select);
  7746. }
  7747. else {
  7748. module.debug('Retrieved values from select', select);
  7749. }
  7750. return select;
  7751. },
  7752. activeItem: function() {
  7753. return $item.filter('.' + className.active);
  7754. },
  7755. selectedItem: function() {
  7756. var
  7757. $selectedItem = $item.not(selector.unselectable).filter('.' + className.selected)
  7758. ;
  7759. return ($selectedItem.length > 0)
  7760. ? $selectedItem
  7761. : $item.eq(0)
  7762. ;
  7763. },
  7764. itemWithAdditions: function(value) {
  7765. var
  7766. $items = module.get.item(value),
  7767. $userItems = module.create.userChoice(value),
  7768. hasUserItems = ($userItems && $userItems.length > 0)
  7769. ;
  7770. if(hasUserItems) {
  7771. $items = ($items.length > 0)
  7772. ? $items.add($userItems)
  7773. : $userItems
  7774. ;
  7775. }
  7776. return $items;
  7777. },
  7778. item: function(value, strict) {
  7779. var
  7780. $selectedItem = false,
  7781. shouldSearch,
  7782. isMultiple
  7783. ;
  7784. value = (value !== undefined)
  7785. ? value
  7786. : ( module.get.values() !== undefined)
  7787. ? module.get.values()
  7788. : module.get.text()
  7789. ;
  7790. isMultiple = (module.is.multiple() && Array.isArray(value));
  7791. shouldSearch = (isMultiple)
  7792. ? (value.length > 0)
  7793. : (value !== undefined && value !== null)
  7794. ;
  7795. strict = (value === '' || value === false || value === true)
  7796. ? true
  7797. : strict || false
  7798. ;
  7799. if(shouldSearch) {
  7800. $item
  7801. .each(function() {
  7802. var
  7803. $choice = $(this),
  7804. optionText = module.get.choiceText($choice),
  7805. optionValue = module.get.choiceValue($choice, optionText)
  7806. ;
  7807. // safe early exit
  7808. if(optionValue === null || optionValue === undefined) {
  7809. return;
  7810. }
  7811. if(isMultiple) {
  7812. if($.inArray( String(optionValue), value) !== -1) {
  7813. $selectedItem = ($selectedItem)
  7814. ? $selectedItem.add($choice)
  7815. : $choice
  7816. ;
  7817. }
  7818. }
  7819. else if(strict) {
  7820. module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
  7821. if( optionValue === value) {
  7822. $selectedItem = $choice;
  7823. return true;
  7824. }
  7825. }
  7826. else {
  7827. if( String(optionValue) == String(value)) {
  7828. module.verbose('Found select item by value', optionValue, value);
  7829. $selectedItem = $choice;
  7830. return true;
  7831. }
  7832. }
  7833. })
  7834. ;
  7835. }
  7836. return $selectedItem;
  7837. }
  7838. },
  7839. check: {
  7840. maxSelections: function(selectionCount) {
  7841. if(settings.maxSelections) {
  7842. selectionCount = (selectionCount !== undefined)
  7843. ? selectionCount
  7844. : module.get.selectionCount()
  7845. ;
  7846. if(selectionCount >= settings.maxSelections) {
  7847. module.debug('Maximum selection count reached');
  7848. if(settings.useLabels) {
  7849. $item.addClass(className.filtered);
  7850. module.add.message(message.maxSelections);
  7851. }
  7852. return true;
  7853. }
  7854. else {
  7855. module.verbose('No longer at maximum selection count');
  7856. module.remove.message();
  7857. module.remove.filteredItem();
  7858. if(module.is.searchSelection()) {
  7859. module.filterItems();
  7860. }
  7861. return false;
  7862. }
  7863. }
  7864. return true;
  7865. }
  7866. },
  7867. restore: {
  7868. defaults: function() {
  7869. module.clear();
  7870. module.restore.defaultText();
  7871. module.restore.defaultValue();
  7872. },
  7873. defaultText: function() {
  7874. var
  7875. defaultText = module.get.defaultText(),
  7876. placeholderText = module.get.placeholderText
  7877. ;
  7878. if(defaultText === placeholderText) {
  7879. module.debug('Restoring default placeholder text', defaultText);
  7880. module.set.placeholderText(defaultText);
  7881. }
  7882. else {
  7883. module.debug('Restoring default text', defaultText);
  7884. module.set.text(defaultText);
  7885. }
  7886. },
  7887. placeholderText: function() {
  7888. module.set.placeholderText();
  7889. },
  7890. defaultValue: function() {
  7891. var
  7892. defaultValue = module.get.defaultValue()
  7893. ;
  7894. if(defaultValue !== undefined) {
  7895. module.debug('Restoring default value', defaultValue);
  7896. if(defaultValue !== '') {
  7897. module.set.value(defaultValue);
  7898. module.set.selected();
  7899. }
  7900. else {
  7901. module.remove.activeItem();
  7902. module.remove.selectedItem();
  7903. }
  7904. }
  7905. },
  7906. labels: function() {
  7907. if(settings.allowAdditions) {
  7908. if(!settings.useLabels) {
  7909. module.error(error.labels);
  7910. settings.useLabels = true;
  7911. }
  7912. module.debug('Restoring selected values');
  7913. module.create.userLabels();
  7914. }
  7915. module.check.maxSelections();
  7916. },
  7917. selected: function() {
  7918. module.restore.values();
  7919. if(module.is.multiple()) {
  7920. module.debug('Restoring previously selected values and labels');
  7921. module.restore.labels();
  7922. }
  7923. else {
  7924. module.debug('Restoring previously selected values');
  7925. }
  7926. },
  7927. values: function() {
  7928. // prevents callbacks from occurring on initial load
  7929. module.set.initialLoad();
  7930. if(settings.apiSettings && settings.saveRemoteData && module.get.remoteValues()) {
  7931. module.restore.remoteValues();
  7932. }
  7933. else {
  7934. module.set.selected();
  7935. }
  7936. var value = module.get.value();
  7937. if(value && value !== '' && !(Array.isArray(value) && value.length === 0)) {
  7938. $input.removeClass(className.noselection);
  7939. } else {
  7940. $input.addClass(className.noselection);
  7941. }
  7942. module.remove.initialLoad();
  7943. },
  7944. remoteValues: function() {
  7945. var
  7946. values = module.get.remoteValues()
  7947. ;
  7948. module.debug('Recreating selected from session data', values);
  7949. if(values) {
  7950. if( module.is.single() ) {
  7951. $.each(values, function(value, name) {
  7952. module.set.text(name);
  7953. });
  7954. }
  7955. else {
  7956. $.each(values, function(value, name) {
  7957. module.add.label(value, name);
  7958. });
  7959. }
  7960. }
  7961. }
  7962. },
  7963. read: {
  7964. remoteData: function(value) {
  7965. var
  7966. name
  7967. ;
  7968. if(window.Storage === undefined) {
  7969. module.error(error.noStorage);
  7970. return;
  7971. }
  7972. name = sessionStorage.getItem(value);
  7973. return (name !== undefined)
  7974. ? name
  7975. : false
  7976. ;
  7977. }
  7978. },
  7979. save: {
  7980. defaults: function() {
  7981. module.save.defaultText();
  7982. module.save.placeholderText();
  7983. module.save.defaultValue();
  7984. },
  7985. defaultValue: function() {
  7986. var
  7987. value = module.get.value()
  7988. ;
  7989. module.verbose('Saving default value as', value);
  7990. $module.data(metadata.defaultValue, value);
  7991. },
  7992. defaultText: function() {
  7993. var
  7994. text = module.get.text()
  7995. ;
  7996. module.verbose('Saving default text as', text);
  7997. $module.data(metadata.defaultText, text);
  7998. },
  7999. placeholderText: function() {
  8000. var
  8001. text
  8002. ;
  8003. if(settings.placeholder !== false && $text.hasClass(className.placeholder)) {
  8004. text = module.get.text();
  8005. module.verbose('Saving placeholder text as', text);
  8006. $module.data(metadata.placeholderText, text);
  8007. }
  8008. },
  8009. remoteData: function(name, value) {
  8010. if(window.Storage === undefined) {
  8011. module.error(error.noStorage);
  8012. return;
  8013. }
  8014. module.verbose('Saving remote data to session storage', value, name);
  8015. sessionStorage.setItem(value, name);
  8016. }
  8017. },
  8018. clear: function() {
  8019. if(module.is.multiple() && settings.useLabels) {
  8020. module.remove.labels();
  8021. }
  8022. else {
  8023. module.remove.activeItem();
  8024. module.remove.selectedItem();
  8025. module.remove.filteredItem();
  8026. }
  8027. module.set.placeholderText();
  8028. module.clearValue();
  8029. },
  8030. clearValue: function() {
  8031. module.set.value('');
  8032. },
  8033. scrollPage: function(direction, $selectedItem) {
  8034. var
  8035. $currentItem = $selectedItem || module.get.selectedItem(),
  8036. $menu = $currentItem.closest(selector.menu),
  8037. menuHeight = $menu.outerHeight(),
  8038. currentScroll = $menu.scrollTop(),
  8039. itemHeight = $item.eq(0).outerHeight(),
  8040. itemsPerPage = Math.floor(menuHeight / itemHeight),
  8041. maxScroll = $menu.prop('scrollHeight'),
  8042. newScroll = (direction == 'up')
  8043. ? currentScroll - (itemHeight * itemsPerPage)
  8044. : currentScroll + (itemHeight * itemsPerPage),
  8045. $selectableItem = $item.not(selector.unselectable),
  8046. isWithinRange,
  8047. $nextSelectedItem,
  8048. elementIndex
  8049. ;
  8050. elementIndex = (direction == 'up')
  8051. ? $selectableItem.index($currentItem) - itemsPerPage
  8052. : $selectableItem.index($currentItem) + itemsPerPage
  8053. ;
  8054. isWithinRange = (direction == 'up')
  8055. ? (elementIndex >= 0)
  8056. : (elementIndex < $selectableItem.length)
  8057. ;
  8058. $nextSelectedItem = (isWithinRange)
  8059. ? $selectableItem.eq(elementIndex)
  8060. : (direction == 'up')
  8061. ? $selectableItem.first()
  8062. : $selectableItem.last()
  8063. ;
  8064. if($nextSelectedItem.length > 0) {
  8065. module.debug('Scrolling page', direction, $nextSelectedItem);
  8066. $currentItem
  8067. .removeClass(className.selected)
  8068. ;
  8069. $nextSelectedItem
  8070. .addClass(className.selected)
  8071. ;
  8072. if(settings.selectOnKeydown && module.is.single()) {
  8073. module.set.selectedItem($nextSelectedItem);
  8074. }
  8075. $menu
  8076. .scrollTop(newScroll)
  8077. ;
  8078. }
  8079. },
  8080. set: {
  8081. filtered: function() {
  8082. var
  8083. isMultiple = module.is.multiple(),
  8084. isSearch = module.is.searchSelection(),
  8085. isSearchMultiple = (isMultiple && isSearch),
  8086. searchValue = (isSearch)
  8087. ? module.get.query()
  8088. : '',
  8089. hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0),
  8090. searchWidth = module.get.searchWidth(),
  8091. valueIsSet = searchValue !== ''
  8092. ;
  8093. if(isMultiple && hasSearchValue) {
  8094. module.verbose('Adjusting input width', searchWidth, settings.glyphWidth);
  8095. $search.css('width', searchWidth);
  8096. }
  8097. if(hasSearchValue || (isSearchMultiple && valueIsSet)) {
  8098. module.verbose('Hiding placeholder text');
  8099. $text.addClass(className.filtered);
  8100. }
  8101. else if(!isMultiple || (isSearchMultiple && !valueIsSet)) {
  8102. module.verbose('Showing placeholder text');
  8103. $text.removeClass(className.filtered);
  8104. }
  8105. },
  8106. empty: function() {
  8107. $module.addClass(className.empty);
  8108. },
  8109. loading: function() {
  8110. $module.addClass(className.loading);
  8111. },
  8112. placeholderText: function(text) {
  8113. text = text || module.get.placeholderText();
  8114. module.debug('Setting placeholder text', text);
  8115. module.set.text(text);
  8116. $text.addClass(className.placeholder);
  8117. },
  8118. tabbable: function() {
  8119. if( module.is.searchSelection() ) {
  8120. module.debug('Added tabindex to searchable dropdown');
  8121. $search
  8122. .val('')
  8123. .attr('tabindex', 0)
  8124. ;
  8125. $menu
  8126. .attr('tabindex', -1)
  8127. ;
  8128. }
  8129. else {
  8130. module.debug('Added tabindex to dropdown');
  8131. if( $module.attr('tabindex') === undefined) {
  8132. $module
  8133. .attr('tabindex', 0)
  8134. ;
  8135. $menu
  8136. .attr('tabindex', -1)
  8137. ;
  8138. }
  8139. }
  8140. },
  8141. initialLoad: function() {
  8142. module.verbose('Setting initial load');
  8143. initialLoad = true;
  8144. },
  8145. activeItem: function($item) {
  8146. if( settings.allowAdditions && $item.filter(selector.addition).length > 0 ) {
  8147. $item.addClass(className.filtered);
  8148. }
  8149. else {
  8150. $item.addClass(className.active);
  8151. }
  8152. },
  8153. partialSearch: function(text) {
  8154. var
  8155. length = module.get.query().length
  8156. ;
  8157. $search.val( text.substr(0, length));
  8158. },
  8159. scrollPosition: function($item, forceScroll) {
  8160. var
  8161. edgeTolerance = 5,
  8162. $menu,
  8163. hasActive,
  8164. offset,
  8165. itemHeight,
  8166. itemOffset,
  8167. menuOffset,
  8168. menuScroll,
  8169. menuHeight,
  8170. abovePage,
  8171. belowPage
  8172. ;
  8173. $item = $item || module.get.selectedItem();
  8174. $menu = $item.closest(selector.menu);
  8175. hasActive = ($item && $item.length > 0);
  8176. forceScroll = (forceScroll !== undefined)
  8177. ? forceScroll
  8178. : false
  8179. ;
  8180. if(module.get.activeItem().length === 0){
  8181. forceScroll = false;
  8182. }
  8183. if($item && $menu.length > 0 && hasActive) {
  8184. itemOffset = $item.position().top;
  8185. $menu.addClass(className.loading);
  8186. menuScroll = $menu.scrollTop();
  8187. menuOffset = $menu.offset().top;
  8188. itemOffset = $item.offset().top;
  8189. offset = menuScroll - menuOffset + itemOffset;
  8190. if(!forceScroll) {
  8191. menuHeight = $menu.height();
  8192. belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
  8193. abovePage = ((offset - edgeTolerance) < menuScroll);
  8194. }
  8195. module.debug('Scrolling to active item', offset);
  8196. if(forceScroll || abovePage || belowPage) {
  8197. $menu.scrollTop(offset);
  8198. }
  8199. $menu.removeClass(className.loading);
  8200. }
  8201. },
  8202. text: function(text) {
  8203. if(settings.action === 'combo') {
  8204. module.debug('Changing combo button text', text, $combo);
  8205. if(settings.preserveHTML) {
  8206. $combo.html(text);
  8207. }
  8208. else {
  8209. $combo.text(text);
  8210. }
  8211. }
  8212. else if(settings.action === 'activate') {
  8213. if(text !== module.get.placeholderText()) {
  8214. $text.removeClass(className.placeholder);
  8215. }
  8216. module.debug('Changing text', text, $text);
  8217. $text
  8218. .removeClass(className.filtered)
  8219. ;
  8220. if(settings.preserveHTML) {
  8221. $text.html(text);
  8222. }
  8223. else {
  8224. $text.text(text);
  8225. }
  8226. }
  8227. },
  8228. selectedItem: function($item) {
  8229. var
  8230. value = module.get.choiceValue($item),
  8231. searchText = module.get.choiceText($item, false),
  8232. text = module.get.choiceText($item, true)
  8233. ;
  8234. module.debug('Setting user selection to item', $item);
  8235. module.remove.activeItem();
  8236. module.set.partialSearch(searchText);
  8237. module.set.activeItem($item);
  8238. module.set.selected(value, $item);
  8239. module.set.text(text);
  8240. },
  8241. selectedLetter: function(letter) {
  8242. var
  8243. $selectedItem = $item.filter('.' + className.selected),
  8244. alreadySelectedLetter = $selectedItem.length > 0 && module.has.firstLetter($selectedItem, letter),
  8245. $nextValue = false,
  8246. $nextItem
  8247. ;
  8248. // check next of same letter
  8249. if(alreadySelectedLetter) {
  8250. $nextItem = $selectedItem.nextAll($item).eq(0);
  8251. if( module.has.firstLetter($nextItem, letter) ) {
  8252. $nextValue = $nextItem;
  8253. }
  8254. }
  8255. // check all values
  8256. if(!$nextValue) {
  8257. $item
  8258. .each(function(){
  8259. if(module.has.firstLetter($(this), letter)) {
  8260. $nextValue = $(this);
  8261. return false;
  8262. }
  8263. })
  8264. ;
  8265. }
  8266. // set next value
  8267. if($nextValue) {
  8268. module.verbose('Scrolling to next value with letter', letter);
  8269. module.set.scrollPosition($nextValue);
  8270. $selectedItem.removeClass(className.selected);
  8271. $nextValue.addClass(className.selected);
  8272. if(settings.selectOnKeydown && module.is.single()) {
  8273. module.set.selectedItem($nextValue);
  8274. }
  8275. }
  8276. },
  8277. direction: function($menu) {
  8278. if(settings.direction == 'auto') {
  8279. // reset position, remove upward if it's base menu
  8280. if (!$menu) {
  8281. module.remove.upward();
  8282. } else if (module.is.upward($menu)) {
  8283. //we need make sure when make assertion openDownward for $menu, $menu does not have upward class
  8284. module.remove.upward($menu);
  8285. }
  8286. if(module.can.openDownward($menu)) {
  8287. module.remove.upward($menu);
  8288. }
  8289. else {
  8290. module.set.upward($menu);
  8291. }
  8292. if(!module.is.leftward($menu) && !module.can.openRightward($menu)) {
  8293. module.set.leftward($menu);
  8294. }
  8295. }
  8296. else if(settings.direction == 'upward') {
  8297. module.set.upward($menu);
  8298. }
  8299. },
  8300. upward: function($currentMenu) {
  8301. var $element = $currentMenu || $module;
  8302. $element.addClass(className.upward);
  8303. },
  8304. leftward: function($currentMenu) {
  8305. var $element = $currentMenu || $menu;
  8306. $element.addClass(className.leftward);
  8307. },
  8308. value: function(value, text, $selected) {
  8309. if(value !== undefined && value !== '' && !(Array.isArray(value) && value.length === 0)) {
  8310. $input.removeClass(className.noselection);
  8311. } else {
  8312. $input.addClass(className.noselection);
  8313. }
  8314. var
  8315. escapedValue = module.escape.value(value),
  8316. hasInput = ($input.length > 0),
  8317. currentValue = module.get.values(),
  8318. stringValue = (value !== undefined)
  8319. ? String(value)
  8320. : value,
  8321. newValue
  8322. ;
  8323. if(hasInput) {
  8324. if(!settings.allowReselection && stringValue == currentValue) {
  8325. module.verbose('Skipping value update already same value', value, currentValue);
  8326. if(!module.is.initialLoad()) {
  8327. return;
  8328. }
  8329. }
  8330. if( module.is.single() && module.has.selectInput() && module.can.extendSelect() ) {
  8331. module.debug('Adding user option', value);
  8332. module.add.optionValue(value);
  8333. }
  8334. module.debug('Updating input value', escapedValue, currentValue);
  8335. internalChange = true;
  8336. $input
  8337. .val(escapedValue)
  8338. ;
  8339. if(settings.fireOnInit === false && module.is.initialLoad()) {
  8340. module.debug('Input native change event ignored on initial load');
  8341. }
  8342. else {
  8343. module.trigger.change();
  8344. }
  8345. internalChange = false;
  8346. }
  8347. else {
  8348. module.verbose('Storing value in metadata', escapedValue, $input);
  8349. if(escapedValue !== currentValue) {
  8350. $module.data(metadata.value, stringValue);
  8351. }
  8352. }
  8353. if(settings.fireOnInit === false && module.is.initialLoad()) {
  8354. module.verbose('No callback on initial load', settings.onChange);
  8355. }
  8356. else {
  8357. settings.onChange.call(element, value, text, $selected);
  8358. }
  8359. },
  8360. active: function() {
  8361. $module
  8362. .addClass(className.active)
  8363. ;
  8364. },
  8365. multiple: function() {
  8366. $module.addClass(className.multiple);
  8367. },
  8368. visible: function() {
  8369. $module.addClass(className.visible);
  8370. },
  8371. exactly: function(value, $selectedItem) {
  8372. module.debug('Setting selected to exact values');
  8373. module.clear();
  8374. module.set.selected(value, $selectedItem);
  8375. },
  8376. selected: function(value, $selectedItem) {
  8377. var
  8378. isMultiple = module.is.multiple()
  8379. ;
  8380. $selectedItem = (settings.allowAdditions)
  8381. ? $selectedItem || module.get.itemWithAdditions(value)
  8382. : $selectedItem || module.get.item(value)
  8383. ;
  8384. if(!$selectedItem) {
  8385. return;
  8386. }
  8387. module.debug('Setting selected menu item to', $selectedItem);
  8388. if(module.is.multiple()) {
  8389. module.remove.searchWidth();
  8390. }
  8391. if(module.is.single()) {
  8392. module.remove.activeItem();
  8393. module.remove.selectedItem();
  8394. }
  8395. else if(settings.useLabels) {
  8396. module.remove.selectedItem();
  8397. }
  8398. // select each item
  8399. $selectedItem
  8400. .each(function() {
  8401. var
  8402. $selected = $(this),
  8403. selectedText = module.get.choiceText($selected),
  8404. selectedValue = module.get.choiceValue($selected, selectedText),
  8405. isFiltered = $selected.hasClass(className.filtered),
  8406. isActive = $selected.hasClass(className.active),
  8407. isUserValue = $selected.hasClass(className.addition),
  8408. shouldAnimate = (isMultiple && $selectedItem.length == 1)
  8409. ;
  8410. if(isMultiple) {
  8411. if(!isActive || isUserValue) {
  8412. if(settings.apiSettings && settings.saveRemoteData) {
  8413. module.save.remoteData(selectedText, selectedValue);
  8414. }
  8415. if(settings.useLabels) {
  8416. module.add.label(selectedValue, selectedText, shouldAnimate);
  8417. module.add.value(selectedValue, selectedText, $selected);
  8418. module.set.activeItem($selected);
  8419. module.filterActive();
  8420. module.select.nextAvailable($selectedItem);
  8421. }
  8422. else {
  8423. module.add.value(selectedValue, selectedText, $selected);
  8424. module.set.text(module.add.variables(message.count));
  8425. module.set.activeItem($selected);
  8426. }
  8427. }
  8428. else if(!isFiltered && (settings.useLabels || selectActionActive)) {
  8429. module.debug('Selected active value, removing label');
  8430. module.remove.selected(selectedValue);
  8431. }
  8432. }
  8433. else {
  8434. if(settings.apiSettings && settings.saveRemoteData) {
  8435. module.save.remoteData(selectedText, selectedValue);
  8436. }
  8437. module.set.text(selectedText);
  8438. module.set.value(selectedValue, selectedText, $selected);
  8439. $selected
  8440. .addClass(className.active)
  8441. .addClass(className.selected)
  8442. ;
  8443. }
  8444. })
  8445. ;
  8446. },
  8447. },
  8448. add: {
  8449. label: function(value, text, shouldAnimate) {
  8450. var
  8451. $next = module.is.searchSelection()
  8452. ? $search
  8453. : $text,
  8454. escapedValue = module.escape.value(value),
  8455. $label
  8456. ;
  8457. if(settings.ignoreCase) {
  8458. escapedValue = escapedValue.toLowerCase();
  8459. }
  8460. $label = $('<a />')
  8461. .addClass(className.label)
  8462. .attr('data-' + metadata.value, escapedValue)
  8463. .html(templates.label(escapedValue, text, settings.preserveHTML, settings.className))
  8464. ;
  8465. $label = settings.onLabelCreate.call($label, escapedValue, text);
  8466. if(module.has.label(value)) {
  8467. module.debug('User selection already exists, skipping', escapedValue);
  8468. return;
  8469. }
  8470. if(settings.label.variation) {
  8471. $label.addClass(settings.label.variation);
  8472. }
  8473. if(shouldAnimate === true) {
  8474. module.debug('Animating in label', $label);
  8475. $label
  8476. .addClass(className.hidden)
  8477. .insertBefore($next)
  8478. .transition({
  8479. animation : settings.label.transition,
  8480. debug : settings.debug,
  8481. verbose : settings.verbose,
  8482. duration : settings.label.duration
  8483. })
  8484. ;
  8485. }
  8486. else {
  8487. module.debug('Adding selection label', $label);
  8488. $label
  8489. .insertBefore($next)
  8490. ;
  8491. }
  8492. },
  8493. message: function(message) {
  8494. var
  8495. $message = $menu.children(selector.message),
  8496. html = settings.templates.message(module.add.variables(message))
  8497. ;
  8498. if($message.length > 0) {
  8499. $message
  8500. .html(html)
  8501. ;
  8502. }
  8503. else {
  8504. $message = $('<div/>')
  8505. .html(html)
  8506. .addClass(className.message)
  8507. .appendTo($menu)
  8508. ;
  8509. }
  8510. },
  8511. optionValue: function(value) {
  8512. var
  8513. escapedValue = module.escape.value(value),
  8514. $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
  8515. hasOption = ($option.length > 0)
  8516. ;
  8517. if(hasOption) {
  8518. return;
  8519. }
  8520. // temporarily disconnect observer
  8521. module.disconnect.selectObserver();
  8522. if( module.is.single() ) {
  8523. module.verbose('Removing previous user addition');
  8524. $input.find('option.' + className.addition).remove();
  8525. }
  8526. $('<option/>')
  8527. .prop('value', escapedValue)
  8528. .addClass(className.addition)
  8529. .html(value)
  8530. .appendTo($input)
  8531. ;
  8532. module.verbose('Adding user addition as an <option>', value);
  8533. module.observe.select();
  8534. },
  8535. userSuggestion: function(value) {
  8536. var
  8537. $addition = $menu.children(selector.addition),
  8538. $existingItem = module.get.item(value),
  8539. alreadyHasValue = $existingItem && $existingItem.not(selector.addition).length,
  8540. hasUserSuggestion = $addition.length > 0,
  8541. html
  8542. ;
  8543. if(settings.useLabels && module.has.maxSelections()) {
  8544. return;
  8545. }
  8546. if(value === '' || alreadyHasValue) {
  8547. $addition.remove();
  8548. return;
  8549. }
  8550. if(hasUserSuggestion) {
  8551. $addition
  8552. .data(metadata.value, value)
  8553. .data(metadata.text, value)
  8554. .attr('data-' + metadata.value, value)
  8555. .attr('data-' + metadata.text, value)
  8556. .removeClass(className.filtered)
  8557. ;
  8558. if(!settings.hideAdditions) {
  8559. html = settings.templates.addition( module.add.variables(message.addResult, value) );
  8560. $addition
  8561. .html(html)
  8562. ;
  8563. }
  8564. module.verbose('Replacing user suggestion with new value', $addition);
  8565. }
  8566. else {
  8567. $addition = module.create.userChoice(value);
  8568. $addition
  8569. .prependTo($menu)
  8570. ;
  8571. module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
  8572. }
  8573. if(!settings.hideAdditions || module.is.allFiltered()) {
  8574. $addition
  8575. .addClass(className.selected)
  8576. .siblings()
  8577. .removeClass(className.selected)
  8578. ;
  8579. }
  8580. module.refreshItems();
  8581. },
  8582. variables: function(message, term) {
  8583. var
  8584. hasCount = (message.search('{count}') !== -1),
  8585. hasMaxCount = (message.search('{maxCount}') !== -1),
  8586. hasTerm = (message.search('{term}') !== -1),
  8587. count,
  8588. query
  8589. ;
  8590. module.verbose('Adding templated variables to message', message);
  8591. if(hasCount) {
  8592. count = module.get.selectionCount();
  8593. message = message.replace('{count}', count);
  8594. }
  8595. if(hasMaxCount) {
  8596. count = module.get.selectionCount();
  8597. message = message.replace('{maxCount}', settings.maxSelections);
  8598. }
  8599. if(hasTerm) {
  8600. query = term || module.get.query();
  8601. message = message.replace('{term}', query);
  8602. }
  8603. return message;
  8604. },
  8605. value: function(addedValue, addedText, $selectedItem) {
  8606. var
  8607. currentValue = module.get.values(),
  8608. newValue
  8609. ;
  8610. if(module.has.value(addedValue)) {
  8611. module.debug('Value already selected');
  8612. return;
  8613. }
  8614. if(addedValue === '') {
  8615. module.debug('Cannot select blank values from multiselect');
  8616. return;
  8617. }
  8618. // extend current array
  8619. if(Array.isArray(currentValue)) {
  8620. newValue = currentValue.concat([addedValue]);
  8621. newValue = module.get.uniqueArray(newValue);
  8622. }
  8623. else {
  8624. newValue = [addedValue];
  8625. }
  8626. // add values
  8627. if( module.has.selectInput() ) {
  8628. if(module.can.extendSelect()) {
  8629. module.debug('Adding value to select', addedValue, newValue, $input);
  8630. module.add.optionValue(addedValue);
  8631. }
  8632. }
  8633. else {
  8634. newValue = newValue.join(settings.delimiter);
  8635. module.debug('Setting hidden input to delimited value', newValue, $input);
  8636. }
  8637. if(settings.fireOnInit === false && module.is.initialLoad()) {
  8638. module.verbose('Skipping onadd callback on initial load', settings.onAdd);
  8639. }
  8640. else {
  8641. settings.onAdd.call(element, addedValue, addedText, $selectedItem);
  8642. }
  8643. module.set.value(newValue, addedValue, addedText, $selectedItem);
  8644. module.check.maxSelections();
  8645. },
  8646. },
  8647. remove: {
  8648. active: function() {
  8649. $module.removeClass(className.active);
  8650. },
  8651. activeLabel: function() {
  8652. $module.find(selector.label).removeClass(className.active);
  8653. },
  8654. empty: function() {
  8655. $module.removeClass(className.empty);
  8656. },
  8657. loading: function() {
  8658. $module.removeClass(className.loading);
  8659. },
  8660. initialLoad: function() {
  8661. initialLoad = false;
  8662. },
  8663. upward: function($currentMenu) {
  8664. var $element = $currentMenu || $module;
  8665. $element.removeClass(className.upward);
  8666. },
  8667. leftward: function($currentMenu) {
  8668. var $element = $currentMenu || $menu;
  8669. $element.removeClass(className.leftward);
  8670. },
  8671. visible: function() {
  8672. $module.removeClass(className.visible);
  8673. },
  8674. activeItem: function() {
  8675. $item.removeClass(className.active);
  8676. },
  8677. filteredItem: function() {
  8678. if(settings.useLabels && module.has.maxSelections() ) {
  8679. return;
  8680. }
  8681. if(settings.useLabels && module.is.multiple()) {
  8682. $item.not('.' + className.active).removeClass(className.filtered);
  8683. }
  8684. else {
  8685. $item.removeClass(className.filtered);
  8686. }
  8687. if(settings.hideDividers) {
  8688. $divider.removeClass(className.hidden);
  8689. }
  8690. module.remove.empty();
  8691. },
  8692. optionValue: function(value) {
  8693. var
  8694. escapedValue = module.escape.value(value),
  8695. $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
  8696. hasOption = ($option.length > 0)
  8697. ;
  8698. if(!hasOption || !$option.hasClass(className.addition)) {
  8699. return;
  8700. }
  8701. // temporarily disconnect observer
  8702. if(selectObserver) {
  8703. selectObserver.disconnect();
  8704. module.verbose('Temporarily disconnecting mutation observer');
  8705. }
  8706. $option.remove();
  8707. module.verbose('Removing user addition as an <option>', escapedValue);
  8708. if(selectObserver) {
  8709. selectObserver.observe($input[0], {
  8710. childList : true,
  8711. subtree : true
  8712. });
  8713. }
  8714. },
  8715. message: function() {
  8716. $menu.children(selector.message).remove();
  8717. },
  8718. searchWidth: function() {
  8719. $search.css('width', '');
  8720. },
  8721. searchTerm: function() {
  8722. module.verbose('Cleared search term');
  8723. $search.val('');
  8724. module.set.filtered();
  8725. },
  8726. userAddition: function() {
  8727. $item.filter(selector.addition).remove();
  8728. },
  8729. selected: function(value, $selectedItem) {
  8730. $selectedItem = (settings.allowAdditions)
  8731. ? $selectedItem || module.get.itemWithAdditions(value)
  8732. : $selectedItem || module.get.item(value)
  8733. ;
  8734. if(!$selectedItem) {
  8735. return false;
  8736. }
  8737. $selectedItem
  8738. .each(function() {
  8739. var
  8740. $selected = $(this),
  8741. selectedText = module.get.choiceText($selected),
  8742. selectedValue = module.get.choiceValue($selected, selectedText)
  8743. ;
  8744. if(module.is.multiple()) {
  8745. if(settings.useLabels) {
  8746. module.remove.value(selectedValue, selectedText, $selected);
  8747. module.remove.label(selectedValue);
  8748. }
  8749. else {
  8750. module.remove.value(selectedValue, selectedText, $selected);
  8751. if(module.get.selectionCount() === 0) {
  8752. module.set.placeholderText();
  8753. }
  8754. else {
  8755. module.set.text(module.add.variables(message.count));
  8756. }
  8757. }
  8758. }
  8759. else {
  8760. module.remove.value(selectedValue, selectedText, $selected);
  8761. }
  8762. $selected
  8763. .removeClass(className.filtered)
  8764. .removeClass(className.active)
  8765. ;
  8766. if(settings.useLabels) {
  8767. $selected.removeClass(className.selected);
  8768. }
  8769. })
  8770. ;
  8771. },
  8772. selectedItem: function() {
  8773. $item.removeClass(className.selected);
  8774. },
  8775. value: function(removedValue, removedText, $removedItem) {
  8776. var
  8777. values = module.get.values(),
  8778. newValue
  8779. ;
  8780. if( module.has.selectInput() ) {
  8781. module.verbose('Input is <select> removing selected option', removedValue);
  8782. newValue = module.remove.arrayValue(removedValue, values);
  8783. module.remove.optionValue(removedValue);
  8784. }
  8785. else {
  8786. module.verbose('Removing from delimited values', removedValue);
  8787. newValue = module.remove.arrayValue(removedValue, values);
  8788. newValue = newValue.join(settings.delimiter);
  8789. }
  8790. if(settings.fireOnInit === false && module.is.initialLoad()) {
  8791. module.verbose('No callback on initial load', settings.onRemove);
  8792. }
  8793. else {
  8794. settings.onRemove.call(element, removedValue, removedText, $removedItem);
  8795. }
  8796. module.set.value(newValue, removedText, $removedItem);
  8797. module.check.maxSelections();
  8798. },
  8799. arrayValue: function(removedValue, values) {
  8800. if( !Array.isArray(values) ) {
  8801. values = [values];
  8802. }
  8803. values = $.grep(values, function(value){
  8804. return (removedValue != value);
  8805. });
  8806. module.verbose('Removed value from delimited string', removedValue, values);
  8807. return values;
  8808. },
  8809. label: function(value, shouldAnimate) {
  8810. var
  8811. $labels = $module.find(selector.label),
  8812. $removedLabel = $labels.filter('[data-' + metadata.value + '="' + module.escape.string(value) +'"]')
  8813. ;
  8814. module.verbose('Removing label', $removedLabel);
  8815. $removedLabel.remove();
  8816. },
  8817. activeLabels: function($activeLabels) {
  8818. $activeLabels = $activeLabels || $module.find(selector.label).filter('.' + className.active);
  8819. module.verbose('Removing active label selections', $activeLabels);
  8820. module.remove.labels($activeLabels);
  8821. },
  8822. labels: function($labels) {
  8823. $labels = $labels || $module.find(selector.label);
  8824. module.verbose('Removing labels', $labels);
  8825. $labels
  8826. .each(function(){
  8827. var
  8828. $label = $(this),
  8829. value = $label.data(metadata.value),
  8830. stringValue = (value !== undefined)
  8831. ? String(value)
  8832. : value,
  8833. isUserValue = module.is.userValue(stringValue)
  8834. ;
  8835. if(settings.onLabelRemove.call($label, value) === false) {
  8836. module.debug('Label remove callback cancelled removal');
  8837. return;
  8838. }
  8839. module.remove.message();
  8840. if(isUserValue) {
  8841. module.remove.value(stringValue);
  8842. module.remove.label(stringValue);
  8843. }
  8844. else {
  8845. // selected will also remove label
  8846. module.remove.selected(stringValue);
  8847. }
  8848. })
  8849. ;
  8850. },
  8851. tabbable: function() {
  8852. if( module.is.searchSelection() ) {
  8853. module.debug('Searchable dropdown initialized');
  8854. $search
  8855. .removeAttr('tabindex')
  8856. ;
  8857. $menu
  8858. .removeAttr('tabindex')
  8859. ;
  8860. }
  8861. else {
  8862. module.debug('Simple selection dropdown initialized');
  8863. $module
  8864. .removeAttr('tabindex')
  8865. ;
  8866. $menu
  8867. .removeAttr('tabindex')
  8868. ;
  8869. }
  8870. },
  8871. diacritics: function(text) {
  8872. return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : text;
  8873. }
  8874. },
  8875. has: {
  8876. menuSearch: function() {
  8877. return (module.has.search() && $search.closest($menu).length > 0);
  8878. },
  8879. clearItem: function() {
  8880. return ($clear.length > 0);
  8881. },
  8882. search: function() {
  8883. return ($search.length > 0);
  8884. },
  8885. sizer: function() {
  8886. return ($sizer.length > 0);
  8887. },
  8888. selectInput: function() {
  8889. return ( $input.is('select') );
  8890. },
  8891. minCharacters: function(searchTerm) {
  8892. if(settings.minCharacters && !iconClicked) {
  8893. searchTerm = (searchTerm !== undefined)
  8894. ? String(searchTerm)
  8895. : String(module.get.query())
  8896. ;
  8897. return (searchTerm.length >= settings.minCharacters);
  8898. }
  8899. iconClicked=false;
  8900. return true;
  8901. },
  8902. firstLetter: function($item, letter) {
  8903. var
  8904. text,
  8905. firstLetter
  8906. ;
  8907. if(!$item || $item.length === 0 || typeof letter !== 'string') {
  8908. return false;
  8909. }
  8910. text = module.get.choiceText($item, false);
  8911. letter = letter.toLowerCase();
  8912. firstLetter = String(text).charAt(0).toLowerCase();
  8913. return (letter == firstLetter);
  8914. },
  8915. input: function() {
  8916. return ($input.length > 0);
  8917. },
  8918. items: function() {
  8919. return ($item.length > 0);
  8920. },
  8921. menu: function() {
  8922. return ($menu.length > 0);
  8923. },
  8924. message: function() {
  8925. return ($menu.children(selector.message).length !== 0);
  8926. },
  8927. label: function(value) {
  8928. var
  8929. escapedValue = module.escape.value(value),
  8930. $labels = $module.find(selector.label)
  8931. ;
  8932. if(settings.ignoreCase) {
  8933. escapedValue = escapedValue.toLowerCase();
  8934. }
  8935. return ($labels.filter('[data-' + metadata.value + '="' + module.escape.string(escapedValue) +'"]').length > 0);
  8936. },
  8937. maxSelections: function() {
  8938. return (settings.maxSelections && module.get.selectionCount() >= settings.maxSelections);
  8939. },
  8940. allResultsFiltered: function() {
  8941. var
  8942. $normalResults = $item.not(selector.addition)
  8943. ;
  8944. return ($normalResults.filter(selector.unselectable).length === $normalResults.length);
  8945. },
  8946. userSuggestion: function() {
  8947. return ($menu.children(selector.addition).length > 0);
  8948. },
  8949. query: function() {
  8950. return (module.get.query() !== '');
  8951. },
  8952. value: function(value) {
  8953. return (settings.ignoreCase)
  8954. ? module.has.valueIgnoringCase(value)
  8955. : module.has.valueMatchingCase(value)
  8956. ;
  8957. },
  8958. valueMatchingCase: function(value) {
  8959. var
  8960. values = module.get.values(),
  8961. hasValue = Array.isArray(values)
  8962. ? values && ($.inArray(value, values) !== -1)
  8963. : (values == value)
  8964. ;
  8965. return (hasValue)
  8966. ? true
  8967. : false
  8968. ;
  8969. },
  8970. valueIgnoringCase: function(value) {
  8971. var
  8972. values = module.get.values(),
  8973. hasValue = false
  8974. ;
  8975. if(!Array.isArray(values)) {
  8976. values = [values];
  8977. }
  8978. $.each(values, function(index, existingValue) {
  8979. if(String(value).toLowerCase() == String(existingValue).toLowerCase()) {
  8980. hasValue = true;
  8981. return false;
  8982. }
  8983. });
  8984. return hasValue;
  8985. }
  8986. },
  8987. is: {
  8988. active: function() {
  8989. return $module.hasClass(className.active);
  8990. },
  8991. animatingInward: function() {
  8992. return $menu.transition('is inward');
  8993. },
  8994. animatingOutward: function() {
  8995. return $menu.transition('is outward');
  8996. },
  8997. bubbledLabelClick: function(event) {
  8998. return $(event.target).is('select, input') && $module.closest('label').length > 0;
  8999. },
  9000. bubbledIconClick: function(event) {
  9001. return $(event.target).closest($icon).length > 0;
  9002. },
  9003. alreadySetup: function() {
  9004. return ($module.is('select') && $module.parent(selector.dropdown).data(moduleNamespace) !== undefined && $module.prev().length === 0);
  9005. },
  9006. animating: function($subMenu) {
  9007. return ($subMenu)
  9008. ? $subMenu.transition && $subMenu.transition('is animating')
  9009. : $menu.transition && $menu.transition('is animating')
  9010. ;
  9011. },
  9012. leftward: function($subMenu) {
  9013. var $selectedMenu = $subMenu || $menu;
  9014. return $selectedMenu.hasClass(className.leftward);
  9015. },
  9016. clearable: function() {
  9017. return ($module.hasClass(className.clearable) || settings.clearable);
  9018. },
  9019. disabled: function() {
  9020. return $module.hasClass(className.disabled);
  9021. },
  9022. focused: function() {
  9023. return (document.activeElement === $module[0]);
  9024. },
  9025. focusedOnSearch: function() {
  9026. return (document.activeElement === $search[0]);
  9027. },
  9028. allFiltered: function() {
  9029. return( (module.is.multiple() || module.has.search()) && !(settings.hideAdditions == false && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered() );
  9030. },
  9031. hidden: function($subMenu) {
  9032. return !module.is.visible($subMenu);
  9033. },
  9034. initialLoad: function() {
  9035. return initialLoad;
  9036. },
  9037. inObject: function(needle, object) {
  9038. var
  9039. found = false
  9040. ;
  9041. $.each(object, function(index, property) {
  9042. if(property == needle) {
  9043. found = true;
  9044. return true;
  9045. }
  9046. });
  9047. return found;
  9048. },
  9049. multiple: function() {
  9050. return $module.hasClass(className.multiple);
  9051. },
  9052. remote: function() {
  9053. return settings.apiSettings && module.can.useAPI();
  9054. },
  9055. single: function() {
  9056. return !module.is.multiple();
  9057. },
  9058. selectMutation: function(mutations) {
  9059. var
  9060. selectChanged = false
  9061. ;
  9062. $.each(mutations, function(index, mutation) {
  9063. if($(mutation.target).is('select') || $(mutation.addedNodes).is('select')) {
  9064. selectChanged = true;
  9065. return false;
  9066. }
  9067. });
  9068. return selectChanged;
  9069. },
  9070. search: function() {
  9071. return $module.hasClass(className.search);
  9072. },
  9073. searchSelection: function() {
  9074. return ( module.has.search() && $search.parent(selector.dropdown).length === 1 );
  9075. },
  9076. selection: function() {
  9077. return $module.hasClass(className.selection);
  9078. },
  9079. userValue: function(value) {
  9080. return ($.inArray(value, module.get.userValues()) !== -1);
  9081. },
  9082. upward: function($menu) {
  9083. var $element = $menu || $module;
  9084. return $element.hasClass(className.upward);
  9085. },
  9086. visible: function($subMenu) {
  9087. return ($subMenu)
  9088. ? $subMenu.hasClass(className.visible)
  9089. : $menu.hasClass(className.visible)
  9090. ;
  9091. },
  9092. verticallyScrollableContext: function() {
  9093. var
  9094. overflowY = ($context.get(0) !== window)
  9095. ? $context.css('overflow-y')
  9096. : false
  9097. ;
  9098. return (overflowY == 'auto' || overflowY == 'scroll');
  9099. },
  9100. horizontallyScrollableContext: function() {
  9101. var
  9102. overflowX = ($context.get(0) !== window)
  9103. ? $context.css('overflow-X')
  9104. : false
  9105. ;
  9106. return (overflowX == 'auto' || overflowX == 'scroll');
  9107. }
  9108. },
  9109. can: {
  9110. activate: function($item) {
  9111. if(settings.useLabels) {
  9112. return true;
  9113. }
  9114. if(!module.has.maxSelections()) {
  9115. return true;
  9116. }
  9117. if(module.has.maxSelections() && $item.hasClass(className.active)) {
  9118. return true;
  9119. }
  9120. return false;
  9121. },
  9122. openDownward: function($subMenu) {
  9123. var
  9124. $currentMenu = $subMenu || $menu,
  9125. canOpenDownward = true,
  9126. onScreen = {},
  9127. calculations
  9128. ;
  9129. $currentMenu
  9130. .addClass(className.loading)
  9131. ;
  9132. calculations = {
  9133. context: {
  9134. offset : ($context.get(0) === window)
  9135. ? { top: 0, left: 0}
  9136. : $context.offset(),
  9137. scrollTop : $context.scrollTop(),
  9138. height : $context.outerHeight()
  9139. },
  9140. menu : {
  9141. offset: $currentMenu.offset(),
  9142. height: $currentMenu.outerHeight()
  9143. }
  9144. };
  9145. if(module.is.verticallyScrollableContext()) {
  9146. calculations.menu.offset.top += calculations.context.scrollTop;
  9147. }
  9148. onScreen = {
  9149. above : (calculations.context.scrollTop) <= calculations.menu.offset.top - calculations.context.offset.top - calculations.menu.height,
  9150. below : (calculations.context.scrollTop + calculations.context.height) >= calculations.menu.offset.top - calculations.context.offset.top + calculations.menu.height
  9151. };
  9152. if(onScreen.below) {
  9153. module.verbose('Dropdown can fit in context downward', onScreen);
  9154. canOpenDownward = true;
  9155. }
  9156. else if(!onScreen.below && !onScreen.above) {
  9157. module.verbose('Dropdown cannot fit in either direction, favoring downward', onScreen);
  9158. canOpenDownward = true;
  9159. }
  9160. else {
  9161. module.verbose('Dropdown cannot fit below, opening upward', onScreen);
  9162. canOpenDownward = false;
  9163. }
  9164. $currentMenu.removeClass(className.loading);
  9165. return canOpenDownward;
  9166. },
  9167. openRightward: function($subMenu) {
  9168. var
  9169. $currentMenu = $subMenu || $menu,
  9170. canOpenRightward = true,
  9171. isOffscreenRight = false,
  9172. calculations
  9173. ;
  9174. $currentMenu
  9175. .addClass(className.loading)
  9176. ;
  9177. calculations = {
  9178. context: {
  9179. offset : ($context.get(0) === window)
  9180. ? { top: 0, left: 0}
  9181. : $context.offset(),
  9182. scrollLeft : $context.scrollLeft(),
  9183. width : $context.outerWidth()
  9184. },
  9185. menu: {
  9186. offset : $currentMenu.offset(),
  9187. width : $currentMenu.outerWidth()
  9188. }
  9189. };
  9190. if(module.is.horizontallyScrollableContext()) {
  9191. calculations.menu.offset.left += calculations.context.scrollLeft;
  9192. }
  9193. isOffscreenRight = (calculations.menu.offset.left - calculations.context.offset.left + calculations.menu.width >= calculations.context.scrollLeft + calculations.context.width);
  9194. if(isOffscreenRight) {
  9195. module.verbose('Dropdown cannot fit in context rightward', isOffscreenRight);
  9196. canOpenRightward = false;
  9197. }
  9198. $currentMenu.removeClass(className.loading);
  9199. return canOpenRightward;
  9200. },
  9201. click: function() {
  9202. return (hasTouch || settings.on == 'click');
  9203. },
  9204. extendSelect: function() {
  9205. return settings.allowAdditions || settings.apiSettings;
  9206. },
  9207. show: function() {
  9208. return !module.is.disabled() && (module.has.items() || module.has.message());
  9209. },
  9210. useAPI: function() {
  9211. return $.fn.api !== undefined;
  9212. }
  9213. },
  9214. animate: {
  9215. show: function(callback, $subMenu) {
  9216. var
  9217. $currentMenu = $subMenu || $menu,
  9218. start = ($subMenu)
  9219. ? function() {}
  9220. : function() {
  9221. module.hideSubMenus();
  9222. module.hideOthers();
  9223. module.set.active();
  9224. },
  9225. transition
  9226. ;
  9227. callback = $.isFunction(callback)
  9228. ? callback
  9229. : function(){}
  9230. ;
  9231. module.verbose('Doing menu show animation', $currentMenu);
  9232. module.set.direction($subMenu);
  9233. transition = module.get.transition($subMenu);
  9234. if( module.is.selection() ) {
  9235. module.set.scrollPosition(module.get.selectedItem(), true);
  9236. }
  9237. if( module.is.hidden($currentMenu) || module.is.animating($currentMenu) ) {
  9238. if(transition == 'none') {
  9239. start();
  9240. $currentMenu.transition('show');
  9241. callback.call(element);
  9242. }
  9243. else if($.fn.transition !== undefined && $module.transition('is supported')) {
  9244. $currentMenu
  9245. .transition({
  9246. animation : transition + ' in',
  9247. debug : settings.debug,
  9248. verbose : settings.verbose,
  9249. duration : settings.duration,
  9250. queue : true,
  9251. onStart : start,
  9252. onComplete : function() {
  9253. callback.call(element);
  9254. }
  9255. })
  9256. ;
  9257. }
  9258. else {
  9259. module.error(error.noTransition, transition);
  9260. }
  9261. }
  9262. },
  9263. hide: function(callback, $subMenu) {
  9264. var
  9265. $currentMenu = $subMenu || $menu,
  9266. start = ($subMenu)
  9267. ? function() {}
  9268. : function() {
  9269. if( module.can.click() ) {
  9270. module.unbind.intent();
  9271. }
  9272. module.remove.active();
  9273. },
  9274. transition = module.get.transition($subMenu)
  9275. ;
  9276. callback = $.isFunction(callback)
  9277. ? callback
  9278. : function(){}
  9279. ;
  9280. if( module.is.visible($currentMenu) || module.is.animating($currentMenu) ) {
  9281. module.verbose('Doing menu hide animation', $currentMenu);
  9282. if(transition == 'none') {
  9283. start();
  9284. $currentMenu.transition('hide');
  9285. callback.call(element);
  9286. }
  9287. else if($.fn.transition !== undefined && $module.transition('is supported')) {
  9288. $currentMenu
  9289. .transition({
  9290. animation : transition + ' out',
  9291. duration : settings.duration,
  9292. debug : settings.debug,
  9293. verbose : settings.verbose,
  9294. queue : false,
  9295. onStart : start,
  9296. onComplete : function() {
  9297. callback.call(element);
  9298. }
  9299. })
  9300. ;
  9301. }
  9302. else {
  9303. module.error(error.transition);
  9304. }
  9305. }
  9306. }
  9307. },
  9308. hideAndClear: function() {
  9309. module.remove.searchTerm();
  9310. if( module.has.maxSelections() ) {
  9311. return;
  9312. }
  9313. if(module.has.search()) {
  9314. module.hide(function() {
  9315. module.remove.filteredItem();
  9316. });
  9317. }
  9318. else {
  9319. module.hide();
  9320. }
  9321. },
  9322. delay: {
  9323. show: function() {
  9324. module.verbose('Delaying show event to ensure user intent');
  9325. clearTimeout(module.timer);
  9326. module.timer = setTimeout(module.show, settings.delay.show);
  9327. },
  9328. hide: function() {
  9329. module.verbose('Delaying hide event to ensure user intent');
  9330. clearTimeout(module.timer);
  9331. module.timer = setTimeout(module.hide, settings.delay.hide);
  9332. }
  9333. },
  9334. escape: {
  9335. value: function(value) {
  9336. var
  9337. multipleValues = Array.isArray(value),
  9338. stringValue = (typeof value === 'string'),
  9339. isUnparsable = (!stringValue && !multipleValues),
  9340. hasQuotes = (stringValue && value.search(regExp.quote) !== -1),
  9341. values = []
  9342. ;
  9343. if(isUnparsable || !hasQuotes) {
  9344. return value;
  9345. }
  9346. module.debug('Encoding quote values for use in select', value);
  9347. if(multipleValues) {
  9348. $.each(value, function(index, value){
  9349. values.push(value.replace(regExp.quote, '&quot;'));
  9350. });
  9351. return values;
  9352. }
  9353. return value.replace(regExp.quote, '&quot;');
  9354. },
  9355. string: function(text) {
  9356. text = String(text);
  9357. return text.replace(regExp.escape, '\\$&');
  9358. },
  9359. htmlEntities: function(string) {
  9360. var
  9361. badChars = /[&<>"'`]/g,
  9362. shouldEscape = /[&<>"'`]/,
  9363. escape = {
  9364. "&": "&amp;",
  9365. "<": "&lt;",
  9366. ">": "&gt;",
  9367. '"': "&quot;",
  9368. "'": "&#x27;",
  9369. "`": "&#x60;"
  9370. },
  9371. escapedChar = function(chr) {
  9372. return escape[chr];
  9373. }
  9374. ;
  9375. if(shouldEscape.test(string)) {
  9376. return string.replace(badChars, escapedChar);
  9377. }
  9378. return string;
  9379. }
  9380. },
  9381. setting: function(name, value) {
  9382. module.debug('Changing setting', name, value);
  9383. if( $.isPlainObject(name) ) {
  9384. $.extend(true, settings, name);
  9385. }
  9386. else if(value !== undefined) {
  9387. if($.isPlainObject(settings[name])) {
  9388. $.extend(true, settings[name], value);
  9389. }
  9390. else {
  9391. settings[name] = value;
  9392. }
  9393. }
  9394. else {
  9395. return settings[name];
  9396. }
  9397. },
  9398. internal: function(name, value) {
  9399. if( $.isPlainObject(name) ) {
  9400. $.extend(true, module, name);
  9401. }
  9402. else if(value !== undefined) {
  9403. module[name] = value;
  9404. }
  9405. else {
  9406. return module[name];
  9407. }
  9408. },
  9409. debug: function() {
  9410. if(!settings.silent && settings.debug) {
  9411. if(settings.performance) {
  9412. module.performance.log(arguments);
  9413. }
  9414. else {
  9415. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  9416. module.debug.apply(console, arguments);
  9417. }
  9418. }
  9419. },
  9420. verbose: function() {
  9421. if(!settings.silent && settings.verbose && settings.debug) {
  9422. if(settings.performance) {
  9423. module.performance.log(arguments);
  9424. }
  9425. else {
  9426. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  9427. module.verbose.apply(console, arguments);
  9428. }
  9429. }
  9430. },
  9431. error: function() {
  9432. if(!settings.silent) {
  9433. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  9434. module.error.apply(console, arguments);
  9435. }
  9436. },
  9437. performance: {
  9438. log: function(message) {
  9439. var
  9440. currentTime,
  9441. executionTime,
  9442. previousTime
  9443. ;
  9444. if(settings.performance) {
  9445. currentTime = new Date().getTime();
  9446. previousTime = time || currentTime;
  9447. executionTime = currentTime - previousTime;
  9448. time = currentTime;
  9449. performance.push({
  9450. 'Name' : message[0],
  9451. 'Arguments' : [].slice.call(message, 1) || '',
  9452. 'Element' : element,
  9453. 'Execution Time' : executionTime
  9454. });
  9455. }
  9456. clearTimeout(module.performance.timer);
  9457. module.performance.timer = setTimeout(module.performance.display, 500);
  9458. },
  9459. display: function() {
  9460. var
  9461. title = settings.name + ':',
  9462. totalTime = 0
  9463. ;
  9464. time = false;
  9465. clearTimeout(module.performance.timer);
  9466. $.each(performance, function(index, data) {
  9467. totalTime += data['Execution Time'];
  9468. });
  9469. title += ' ' + totalTime + 'ms';
  9470. if(moduleSelector) {
  9471. title += ' \'' + moduleSelector + '\'';
  9472. }
  9473. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  9474. console.groupCollapsed(title);
  9475. if(console.table) {
  9476. console.table(performance);
  9477. }
  9478. else {
  9479. $.each(performance, function(index, data) {
  9480. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  9481. });
  9482. }
  9483. console.groupEnd();
  9484. }
  9485. performance = [];
  9486. }
  9487. },
  9488. invoke: function(query, passedArguments, context) {
  9489. var
  9490. object = instance,
  9491. maxDepth,
  9492. found,
  9493. response
  9494. ;
  9495. passedArguments = passedArguments || queryArguments;
  9496. context = element || context;
  9497. if(typeof query == 'string' && object !== undefined) {
  9498. query = query.split(/[\. ]/);
  9499. maxDepth = query.length - 1;
  9500. $.each(query, function(depth, value) {
  9501. var camelCaseValue = (depth != maxDepth)
  9502. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  9503. : query
  9504. ;
  9505. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  9506. object = object[camelCaseValue];
  9507. }
  9508. else if( object[camelCaseValue] !== undefined ) {
  9509. found = object[camelCaseValue];
  9510. return false;
  9511. }
  9512. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  9513. object = object[value];
  9514. }
  9515. else if( object[value] !== undefined ) {
  9516. found = object[value];
  9517. return false;
  9518. }
  9519. else {
  9520. module.error(error.method, query);
  9521. return false;
  9522. }
  9523. });
  9524. }
  9525. if ( $.isFunction( found ) ) {
  9526. response = found.apply(context, passedArguments);
  9527. }
  9528. else if(found !== undefined) {
  9529. response = found;
  9530. }
  9531. if(Array.isArray(returnedValue)) {
  9532. returnedValue.push(response);
  9533. }
  9534. else if(returnedValue !== undefined) {
  9535. returnedValue = [returnedValue, response];
  9536. }
  9537. else if(response !== undefined) {
  9538. returnedValue = response;
  9539. }
  9540. return found;
  9541. }
  9542. };
  9543. if(methodInvoked) {
  9544. if(instance === undefined) {
  9545. module.initialize();
  9546. }
  9547. module.invoke(query);
  9548. }
  9549. else {
  9550. if(instance !== undefined) {
  9551. instance.invoke('destroy');
  9552. }
  9553. module.initialize();
  9554. }
  9555. })
  9556. ;
  9557. return (returnedValue !== undefined)
  9558. ? returnedValue
  9559. : $allModules
  9560. ;
  9561. };
  9562. $.fn.dropdown.settings = {
  9563. silent : false,
  9564. debug : false,
  9565. verbose : false,
  9566. performance : true,
  9567. on : 'click', // what event should show menu action on item selection
  9568. action : 'activate', // action on item selection (nothing, activate, select, combo, hide, function(){})
  9569. values : false, // specify values to use for dropdown
  9570. clearable : false, // whether the value of the dropdown can be cleared
  9571. apiSettings : false,
  9572. selectOnKeydown : true, // Whether selection should occur automatically when keyboard shortcuts used
  9573. minCharacters : 0, // Minimum characters required to trigger API call
  9574. filterRemoteData : false, // Whether API results should be filtered after being returned for query term
  9575. saveRemoteData : true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
  9576. throttle : 200, // How long to wait after last user input to search remotely
  9577. context : window, // Context to use when determining if on screen
  9578. direction : 'auto', // Whether dropdown should always open in one direction
  9579. keepOnScreen : true, // Whether dropdown should check whether it is on screen before showing
  9580. match : 'both', // what to match against with search selection (both, text, or label)
  9581. fullTextSearch : false, // search anywhere in value (set to 'exact' to require exact matches)
  9582. ignoreDiacritics : false, // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
  9583. hideDividers : false, // Whether to hide any divider elements (specified in selector.divider) that are sibling to any items when searched (set to true will hide all dividers, set to 'empty' will hide them when they are not followed by a visible item)
  9584. placeholder : 'auto', // whether to convert blank <select> values to placeholder text
  9585. preserveHTML : true, // preserve html when selecting value
  9586. sortSelect : false, // sort selection on init
  9587. forceSelection : true, // force a choice on blur with search selection
  9588. allowAdditions : false, // whether multiple select should allow user added values
  9589. ignoreCase : false, // whether to consider values not matching in case to be the same
  9590. hideAdditions : true, // whether or not to hide special message prompting a user they can enter a value
  9591. maxSelections : false, // When set to a number limits the number of selections to this count
  9592. useLabels : true, // whether multiple select should filter currently active selections from choices
  9593. delimiter : ',', // when multiselect uses normal <input> the values will be delimited with this character
  9594. showOnFocus : true, // show menu on focus
  9595. allowReselection : false, // whether current value should trigger callbacks when reselected
  9596. allowTab : true, // add tabindex to element
  9597. allowCategorySelection : false, // allow elements with sub-menus to be selected
  9598. fireOnInit : false, // Whether callbacks should fire when initializing dropdown values
  9599. transition : 'auto', // auto transition will slide down or up based on direction
  9600. duration : 200, // duration of transition
  9601. glyphWidth : 1.037, // widest glyph width in em (W is 1.037 em) used to calculate multiselect input width
  9602. headerDivider : true, // whether option headers should have an additional divider line underneath when converted from <select> <optgroup>
  9603. // label settings on multi-select
  9604. label: {
  9605. transition : 'scale',
  9606. duration : 200,
  9607. variation : false
  9608. },
  9609. // delay before event
  9610. delay : {
  9611. hide : 300,
  9612. show : 200,
  9613. search : 20,
  9614. touch : 50
  9615. },
  9616. /* Callbacks */
  9617. onChange : function(value, text, $selected){},
  9618. onAdd : function(value, text, $selected){},
  9619. onRemove : function(value, text, $selected){},
  9620. onLabelSelect : function($selectedLabels){},
  9621. onLabelCreate : function(value, text) { return $(this); },
  9622. onLabelRemove : function(value) { return true; },
  9623. onNoResults : function(searchTerm) { return true; },
  9624. onShow : function(){},
  9625. onHide : function(){},
  9626. /* Component */
  9627. name : 'Dropdown',
  9628. namespace : 'dropdown',
  9629. message: {
  9630. addResult : 'Add <b>{term}</b>',
  9631. count : '{count} selected',
  9632. maxSelections : 'Max {maxCount} selections',
  9633. noResults : 'No results found.',
  9634. serverError : 'There was an error contacting the server'
  9635. },
  9636. error : {
  9637. action : 'You called a dropdown action that was not defined',
  9638. alreadySetup : 'Once a select has been initialized behaviors must be called on the created ui dropdown',
  9639. labels : 'Allowing user additions currently requires the use of labels.',
  9640. missingMultiple : '<select> requires multiple property to be set to correctly preserve multiple values',
  9641. method : 'The method you called is not defined.',
  9642. noAPI : 'The API module is required to load resources remotely',
  9643. noStorage : 'Saving remote data requires session storage',
  9644. noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>',
  9645. noNormalize : '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.'
  9646. },
  9647. regExp : {
  9648. escape : /[-[\]{}()*+?.,\\^$|#\s:=@]/g,
  9649. quote : /"/g
  9650. },
  9651. metadata : {
  9652. defaultText : 'defaultText',
  9653. defaultValue : 'defaultValue',
  9654. placeholderText : 'placeholder',
  9655. text : 'text',
  9656. value : 'value'
  9657. },
  9658. // property names for remote query
  9659. fields: {
  9660. remoteValues : 'results', // grouping for api results
  9661. values : 'values', // grouping for all dropdown values
  9662. disabled : 'disabled', // whether value should be disabled
  9663. name : 'name', // displayed dropdown text
  9664. value : 'value', // actual dropdown value
  9665. text : 'text', // displayed text when selected
  9666. type : 'type', // type of dropdown element
  9667. image : 'image', // optional image path
  9668. imageClass : 'imageClass', // optional individual class for image
  9669. icon : 'icon', // optional icon name
  9670. iconClass : 'iconClass', // optional individual class for icon (for example to use flag instead)
  9671. class : 'class', // optional individual class for item/header
  9672. divider : 'divider' // optional divider append for group headers
  9673. },
  9674. keys : {
  9675. backspace : 8,
  9676. delimiter : 188, // comma
  9677. deleteKey : 46,
  9678. enter : 13,
  9679. escape : 27,
  9680. pageUp : 33,
  9681. pageDown : 34,
  9682. leftArrow : 37,
  9683. upArrow : 38,
  9684. rightArrow : 39,
  9685. downArrow : 40
  9686. },
  9687. selector : {
  9688. addition : '.addition',
  9689. divider : '.divider, .header',
  9690. dropdown : '.ui.dropdown',
  9691. hidden : '.hidden',
  9692. icon : '> .dropdown.icon',
  9693. input : '> input[type="hidden"], > select',
  9694. item : '.item',
  9695. label : '> .label',
  9696. remove : '> .label > .delete.icon',
  9697. siblingLabel : '.label',
  9698. menu : '.menu',
  9699. message : '.message',
  9700. menuIcon : '.dropdown.icon',
  9701. search : 'input.search, .menu > .search > input, .menu input.search',
  9702. sizer : '> input.sizer',
  9703. text : '> .text:not(.icon)',
  9704. unselectable : '.disabled, .filtered',
  9705. clearIcon : '> .remove.icon'
  9706. },
  9707. className : {
  9708. active : 'active',
  9709. addition : 'addition',
  9710. animating : 'animating',
  9711. disabled : 'disabled',
  9712. empty : 'empty',
  9713. dropdown : 'ui dropdown',
  9714. filtered : 'filtered',
  9715. hidden : 'hidden transition',
  9716. icon : 'icon',
  9717. image : 'image',
  9718. item : 'item',
  9719. label : 'ui label',
  9720. loading : 'loading',
  9721. menu : 'menu',
  9722. message : 'message',
  9723. multiple : 'multiple',
  9724. placeholder : 'default',
  9725. sizer : 'sizer',
  9726. search : 'search',
  9727. selected : 'selected',
  9728. selection : 'selection',
  9729. upward : 'upward',
  9730. leftward : 'left',
  9731. visible : 'visible',
  9732. clearable : 'clearable',
  9733. noselection : 'noselection',
  9734. delete : 'delete',
  9735. header : 'header',
  9736. divider : 'divider',
  9737. groupIcon : ''
  9738. }
  9739. };
  9740. /* Templates */
  9741. $.fn.dropdown.settings.templates = {
  9742. deQuote: function(string) {
  9743. return String(string).replace(/"/g,"");
  9744. },
  9745. escape: function(string, preserveHTML) {
  9746. if (preserveHTML){
  9747. return string;
  9748. }
  9749. var
  9750. badChars = /[&<>"'`]/g,
  9751. shouldEscape = /[&<>"'`]/,
  9752. escape = {
  9753. "&": "&amp;",
  9754. "<": "&lt;",
  9755. ">": "&gt;",
  9756. '"': "&quot;",
  9757. "'": "&#x27;",
  9758. "`": "&#x60;"
  9759. },
  9760. escapedChar = function(chr) {
  9761. return escape[chr];
  9762. }
  9763. ;
  9764. if(shouldEscape.test(string)) {
  9765. return string.replace(badChars, escapedChar);
  9766. }
  9767. return string;
  9768. },
  9769. // generates dropdown from select values
  9770. dropdown: function(select, fields, preserveHTML, className) {
  9771. var
  9772. placeholder = select.placeholder || false,
  9773. html = '',
  9774. escape = $.fn.dropdown.settings.templates.escape
  9775. ;
  9776. html += '<i class="dropdown icon"></i>';
  9777. if(placeholder) {
  9778. html += '<div class="default text">' + escape(placeholder,preserveHTML) + '</div>';
  9779. }
  9780. else {
  9781. html += '<div class="text"></div>';
  9782. }
  9783. html += '<div class="'+className.menu+'">';
  9784. html += $.fn.dropdown.settings.templates.menu(select, fields, preserveHTML,className);
  9785. html += '</div>';
  9786. return html;
  9787. },
  9788. // generates just menu from select
  9789. menu: function(response, fields, preserveHTML, className) {
  9790. var
  9791. values = response[fields.values] || [],
  9792. html = '',
  9793. escape = $.fn.dropdown.settings.templates.escape,
  9794. deQuote = $.fn.dropdown.settings.templates.deQuote
  9795. ;
  9796. $.each(values, function(index, option) {
  9797. var
  9798. itemType = (option[fields.type])
  9799. ? option[fields.type]
  9800. : 'item'
  9801. ;
  9802. if( itemType === 'item' ) {
  9803. var
  9804. maybeText = (option[fields.text])
  9805. ? ' data-text="' + deQuote(option[fields.text]) + '"'
  9806. : '',
  9807. maybeDisabled = (option[fields.disabled])
  9808. ? className.disabled+' '
  9809. : ''
  9810. ;
  9811. html += '<div class="'+ maybeDisabled + (option[fields.class] ? deQuote(option[fields.class]) : className.item)+'" data-value="' + deQuote(option[fields.value]) + '"' + maybeText + '>';
  9812. if(option[fields.image]) {
  9813. html += '<img class="'+(option[fields.imageClass] ? deQuote(option[fields.imageClass]) : className.image)+'" src="' + deQuote(option[fields.image]) + '">';
  9814. }
  9815. if(option[fields.icon]) {
  9816. html += '<i class="'+deQuote(option[fields.icon])+' '+(option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon)+'"></i>';
  9817. }
  9818. html += escape(option[fields.name],preserveHTML);
  9819. html += '</div>';
  9820. } else if (itemType === 'header') {
  9821. var groupName = escape(option[fields.name],preserveHTML),
  9822. groupIcon = option[fields.icon] ? deQuote(option[fields.icon]) : className.groupIcon
  9823. ;
  9824. if(groupName !== '' || groupIcon !== '') {
  9825. html += '<div class="' + (option[fields.class] ? deQuote(option[fields.class]) : className.header) + '">';
  9826. if (groupIcon !== '') {
  9827. html += '<i class="' + groupIcon + ' ' + (option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon) + '"></i>';
  9828. }
  9829. html += groupName;
  9830. html += '</div>';
  9831. }
  9832. if(option[fields.divider]){
  9833. html += '<div class="'+className.divider+'"></div>';
  9834. }
  9835. }
  9836. });
  9837. return html;
  9838. },
  9839. // generates label for multiselect
  9840. label: function(value, text, preserveHTML, className) {
  9841. var
  9842. escape = $.fn.dropdown.settings.templates.escape;
  9843. return escape(text,preserveHTML) + '<i class="'+className.delete+' icon"></i>';
  9844. },
  9845. // generates messages like "No results"
  9846. message: function(message) {
  9847. return message;
  9848. },
  9849. // generates user addition to selection menu
  9850. addition: function(choice) {
  9851. return choice;
  9852. }
  9853. };
  9854. })( jQuery, window, document );
  9855. /*!
  9856. * # Fomantic-UI - Embed
  9857. * http://github.com/fomantic/Fomantic-UI/
  9858. *
  9859. *
  9860. * Released under the MIT license
  9861. * http://opensource.org/licenses/MIT
  9862. *
  9863. */
  9864. ;(function ($, window, document, undefined) {
  9865. "use strict";
  9866. $.isFunction = $.isFunction || function(obj) {
  9867. return typeof obj === "function" && typeof obj.nodeType !== "number";
  9868. };
  9869. window = (typeof window != 'undefined' && window.Math == Math)
  9870. ? window
  9871. : (typeof self != 'undefined' && self.Math == Math)
  9872. ? self
  9873. : Function('return this')()
  9874. ;
  9875. $.fn.embed = function(parameters) {
  9876. var
  9877. $allModules = $(this),
  9878. moduleSelector = $allModules.selector || '',
  9879. time = new Date().getTime(),
  9880. performance = [],
  9881. query = arguments[0],
  9882. methodInvoked = (typeof query == 'string'),
  9883. queryArguments = [].slice.call(arguments, 1),
  9884. returnedValue
  9885. ;
  9886. $allModules
  9887. .each(function() {
  9888. var
  9889. settings = ( $.isPlainObject(parameters) )
  9890. ? $.extend(true, {}, $.fn.embed.settings, parameters)
  9891. : $.extend({}, $.fn.embed.settings),
  9892. selector = settings.selector,
  9893. className = settings.className,
  9894. sources = settings.sources,
  9895. error = settings.error,
  9896. metadata = settings.metadata,
  9897. namespace = settings.namespace,
  9898. templates = settings.templates,
  9899. eventNamespace = '.' + namespace,
  9900. moduleNamespace = 'module-' + namespace,
  9901. $module = $(this),
  9902. $placeholder = $module.find(selector.placeholder),
  9903. $icon = $module.find(selector.icon),
  9904. $embed = $module.find(selector.embed),
  9905. element = this,
  9906. instance = $module.data(moduleNamespace),
  9907. module
  9908. ;
  9909. module = {
  9910. initialize: function() {
  9911. module.debug('Initializing embed');
  9912. module.determine.autoplay();
  9913. module.create();
  9914. module.bind.events();
  9915. module.instantiate();
  9916. },
  9917. instantiate: function() {
  9918. module.verbose('Storing instance of module', module);
  9919. instance = module;
  9920. $module
  9921. .data(moduleNamespace, module)
  9922. ;
  9923. },
  9924. destroy: function() {
  9925. module.verbose('Destroying previous instance of embed');
  9926. module.reset();
  9927. $module
  9928. .removeData(moduleNamespace)
  9929. .off(eventNamespace)
  9930. ;
  9931. },
  9932. refresh: function() {
  9933. module.verbose('Refreshing selector cache');
  9934. $placeholder = $module.find(selector.placeholder);
  9935. $icon = $module.find(selector.icon);
  9936. $embed = $module.find(selector.embed);
  9937. },
  9938. bind: {
  9939. events: function() {
  9940. if( module.has.placeholder() ) {
  9941. module.debug('Adding placeholder events');
  9942. $module
  9943. .on('click' + eventNamespace, selector.placeholder, module.createAndShow)
  9944. .on('click' + eventNamespace, selector.icon, module.createAndShow)
  9945. ;
  9946. }
  9947. }
  9948. },
  9949. create: function() {
  9950. var
  9951. placeholder = module.get.placeholder()
  9952. ;
  9953. if(placeholder) {
  9954. module.createPlaceholder();
  9955. }
  9956. else {
  9957. module.createAndShow();
  9958. }
  9959. },
  9960. createPlaceholder: function(placeholder) {
  9961. var
  9962. icon = module.get.icon(),
  9963. url = module.get.url(),
  9964. embed = module.generate.embed(url)
  9965. ;
  9966. placeholder = placeholder || module.get.placeholder();
  9967. $module.html( templates.placeholder(placeholder, icon) );
  9968. module.debug('Creating placeholder for embed', placeholder, icon);
  9969. },
  9970. createEmbed: function(url) {
  9971. module.refresh();
  9972. url = url || module.get.url();
  9973. $embed = $('<div/>')
  9974. .addClass(className.embed)
  9975. .html( module.generate.embed(url) )
  9976. .appendTo($module)
  9977. ;
  9978. settings.onCreate.call(element, url);
  9979. module.debug('Creating embed object', $embed);
  9980. },
  9981. changeEmbed: function(url) {
  9982. $embed
  9983. .html( module.generate.embed(url) )
  9984. ;
  9985. },
  9986. createAndShow: function() {
  9987. module.createEmbed();
  9988. module.show();
  9989. },
  9990. // sets new embed
  9991. change: function(source, id, url) {
  9992. module.debug('Changing video to ', source, id, url);
  9993. $module
  9994. .data(metadata.source, source)
  9995. .data(metadata.id, id)
  9996. ;
  9997. if(url) {
  9998. $module.data(metadata.url, url);
  9999. }
  10000. else {
  10001. $module.removeData(metadata.url);
  10002. }
  10003. if(module.has.embed()) {
  10004. module.changeEmbed();
  10005. }
  10006. else {
  10007. module.create();
  10008. }
  10009. },
  10010. // clears embed
  10011. reset: function() {
  10012. module.debug('Clearing embed and showing placeholder');
  10013. module.remove.data();
  10014. module.remove.active();
  10015. module.remove.embed();
  10016. module.showPlaceholder();
  10017. settings.onReset.call(element);
  10018. },
  10019. // shows current embed
  10020. show: function() {
  10021. module.debug('Showing embed');
  10022. module.set.active();
  10023. settings.onDisplay.call(element);
  10024. },
  10025. hide: function() {
  10026. module.debug('Hiding embed');
  10027. module.showPlaceholder();
  10028. },
  10029. showPlaceholder: function() {
  10030. module.debug('Showing placeholder image');
  10031. module.remove.active();
  10032. settings.onPlaceholderDisplay.call(element);
  10033. },
  10034. get: {
  10035. id: function() {
  10036. return settings.id || $module.data(metadata.id);
  10037. },
  10038. placeholder: function() {
  10039. return settings.placeholder || $module.data(metadata.placeholder);
  10040. },
  10041. icon: function() {
  10042. return (settings.icon)
  10043. ? settings.icon
  10044. : ($module.data(metadata.icon) !== undefined)
  10045. ? $module.data(metadata.icon)
  10046. : module.determine.icon()
  10047. ;
  10048. },
  10049. source: function(url) {
  10050. return (settings.source)
  10051. ? settings.source
  10052. : ($module.data(metadata.source) !== undefined)
  10053. ? $module.data(metadata.source)
  10054. : module.determine.source()
  10055. ;
  10056. },
  10057. type: function() {
  10058. var source = module.get.source();
  10059. return (sources[source] !== undefined)
  10060. ? sources[source].type
  10061. : false
  10062. ;
  10063. },
  10064. url: function() {
  10065. return (settings.url)
  10066. ? settings.url
  10067. : ($module.data(metadata.url) !== undefined)
  10068. ? $module.data(metadata.url)
  10069. : module.determine.url()
  10070. ;
  10071. }
  10072. },
  10073. determine: {
  10074. autoplay: function() {
  10075. if(module.should.autoplay()) {
  10076. settings.autoplay = true;
  10077. }
  10078. },
  10079. source: function(url) {
  10080. var
  10081. matchedSource = false
  10082. ;
  10083. url = url || module.get.url();
  10084. if(url) {
  10085. $.each(sources, function(name, source) {
  10086. if(url.search(source.domain) !== -1) {
  10087. matchedSource = name;
  10088. return false;
  10089. }
  10090. });
  10091. }
  10092. return matchedSource;
  10093. },
  10094. icon: function() {
  10095. var
  10096. source = module.get.source()
  10097. ;
  10098. return (sources[source] !== undefined)
  10099. ? sources[source].icon
  10100. : false
  10101. ;
  10102. },
  10103. url: function() {
  10104. var
  10105. id = settings.id || $module.data(metadata.id),
  10106. source = settings.source || $module.data(metadata.source),
  10107. url
  10108. ;
  10109. url = (sources[source] !== undefined)
  10110. ? sources[source].url.replace('{id}', id)
  10111. : false
  10112. ;
  10113. if(url) {
  10114. $module.data(metadata.url, url);
  10115. }
  10116. return url;
  10117. }
  10118. },
  10119. set: {
  10120. active: function() {
  10121. $module.addClass(className.active);
  10122. }
  10123. },
  10124. remove: {
  10125. data: function() {
  10126. $module
  10127. .removeData(metadata.id)
  10128. .removeData(metadata.icon)
  10129. .removeData(metadata.placeholder)
  10130. .removeData(metadata.source)
  10131. .removeData(metadata.url)
  10132. ;
  10133. },
  10134. active: function() {
  10135. $module.removeClass(className.active);
  10136. },
  10137. embed: function() {
  10138. $embed.empty();
  10139. }
  10140. },
  10141. encode: {
  10142. parameters: function(parameters) {
  10143. var
  10144. urlString = [],
  10145. index
  10146. ;
  10147. for (index in parameters) {
  10148. urlString.push( encodeURIComponent(index) + '=' + encodeURIComponent( parameters[index] ) );
  10149. }
  10150. return urlString.join('&amp;');
  10151. }
  10152. },
  10153. generate: {
  10154. embed: function(url) {
  10155. module.debug('Generating embed html');
  10156. var
  10157. source = module.get.source(),
  10158. html,
  10159. parameters
  10160. ;
  10161. url = module.get.url(url);
  10162. if(url) {
  10163. parameters = module.generate.parameters(source);
  10164. html = templates.iframe(url, parameters);
  10165. }
  10166. else {
  10167. module.error(error.noURL, $module);
  10168. }
  10169. return html;
  10170. },
  10171. parameters: function(source, extraParameters) {
  10172. var
  10173. parameters = (sources[source] && sources[source].parameters !== undefined)
  10174. ? sources[source].parameters(settings)
  10175. : {}
  10176. ;
  10177. extraParameters = extraParameters || settings.parameters;
  10178. if(extraParameters) {
  10179. parameters = $.extend({}, parameters, extraParameters);
  10180. }
  10181. parameters = settings.onEmbed(parameters);
  10182. return module.encode.parameters(parameters);
  10183. }
  10184. },
  10185. has: {
  10186. embed: function() {
  10187. return ($embed.length > 0);
  10188. },
  10189. placeholder: function() {
  10190. return settings.placeholder || $module.data(metadata.placeholder);
  10191. }
  10192. },
  10193. should: {
  10194. autoplay: function() {
  10195. return (settings.autoplay === 'auto')
  10196. ? (settings.placeholder || $module.data(metadata.placeholder) !== undefined)
  10197. : settings.autoplay
  10198. ;
  10199. }
  10200. },
  10201. is: {
  10202. video: function() {
  10203. return module.get.type() == 'video';
  10204. }
  10205. },
  10206. setting: function(name, value) {
  10207. module.debug('Changing setting', name, value);
  10208. if( $.isPlainObject(name) ) {
  10209. $.extend(true, settings, name);
  10210. }
  10211. else if(value !== undefined) {
  10212. if($.isPlainObject(settings[name])) {
  10213. $.extend(true, settings[name], value);
  10214. }
  10215. else {
  10216. settings[name] = value;
  10217. }
  10218. }
  10219. else {
  10220. return settings[name];
  10221. }
  10222. },
  10223. internal: function(name, value) {
  10224. if( $.isPlainObject(name) ) {
  10225. $.extend(true, module, name);
  10226. }
  10227. else if(value !== undefined) {
  10228. module[name] = value;
  10229. }
  10230. else {
  10231. return module[name];
  10232. }
  10233. },
  10234. debug: function() {
  10235. if(!settings.silent && settings.debug) {
  10236. if(settings.performance) {
  10237. module.performance.log(arguments);
  10238. }
  10239. else {
  10240. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  10241. module.debug.apply(console, arguments);
  10242. }
  10243. }
  10244. },
  10245. verbose: function() {
  10246. if(!settings.silent && settings.verbose && settings.debug) {
  10247. if(settings.performance) {
  10248. module.performance.log(arguments);
  10249. }
  10250. else {
  10251. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  10252. module.verbose.apply(console, arguments);
  10253. }
  10254. }
  10255. },
  10256. error: function() {
  10257. if(!settings.silent) {
  10258. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  10259. module.error.apply(console, arguments);
  10260. }
  10261. },
  10262. performance: {
  10263. log: function(message) {
  10264. var
  10265. currentTime,
  10266. executionTime,
  10267. previousTime
  10268. ;
  10269. if(settings.performance) {
  10270. currentTime = new Date().getTime();
  10271. previousTime = time || currentTime;
  10272. executionTime = currentTime - previousTime;
  10273. time = currentTime;
  10274. performance.push({
  10275. 'Name' : message[0],
  10276. 'Arguments' : [].slice.call(message, 1) || '',
  10277. 'Element' : element,
  10278. 'Execution Time' : executionTime
  10279. });
  10280. }
  10281. clearTimeout(module.performance.timer);
  10282. module.performance.timer = setTimeout(module.performance.display, 500);
  10283. },
  10284. display: function() {
  10285. var
  10286. title = settings.name + ':',
  10287. totalTime = 0
  10288. ;
  10289. time = false;
  10290. clearTimeout(module.performance.timer);
  10291. $.each(performance, function(index, data) {
  10292. totalTime += data['Execution Time'];
  10293. });
  10294. title += ' ' + totalTime + 'ms';
  10295. if(moduleSelector) {
  10296. title += ' \'' + moduleSelector + '\'';
  10297. }
  10298. if($allModules.length > 1) {
  10299. title += ' ' + '(' + $allModules.length + ')';
  10300. }
  10301. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  10302. console.groupCollapsed(title);
  10303. if(console.table) {
  10304. console.table(performance);
  10305. }
  10306. else {
  10307. $.each(performance, function(index, data) {
  10308. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  10309. });
  10310. }
  10311. console.groupEnd();
  10312. }
  10313. performance = [];
  10314. }
  10315. },
  10316. invoke: function(query, passedArguments, context) {
  10317. var
  10318. object = instance,
  10319. maxDepth,
  10320. found,
  10321. response
  10322. ;
  10323. passedArguments = passedArguments || queryArguments;
  10324. context = element || context;
  10325. if(typeof query == 'string' && object !== undefined) {
  10326. query = query.split(/[\. ]/);
  10327. maxDepth = query.length - 1;
  10328. $.each(query, function(depth, value) {
  10329. var camelCaseValue = (depth != maxDepth)
  10330. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  10331. : query
  10332. ;
  10333. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  10334. object = object[camelCaseValue];
  10335. }
  10336. else if( object[camelCaseValue] !== undefined ) {
  10337. found = object[camelCaseValue];
  10338. return false;
  10339. }
  10340. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  10341. object = object[value];
  10342. }
  10343. else if( object[value] !== undefined ) {
  10344. found = object[value];
  10345. return false;
  10346. }
  10347. else {
  10348. module.error(error.method, query);
  10349. return false;
  10350. }
  10351. });
  10352. }
  10353. if ( $.isFunction( found ) ) {
  10354. response = found.apply(context, passedArguments);
  10355. }
  10356. else if(found !== undefined) {
  10357. response = found;
  10358. }
  10359. if(Array.isArray(returnedValue)) {
  10360. returnedValue.push(response);
  10361. }
  10362. else if(returnedValue !== undefined) {
  10363. returnedValue = [returnedValue, response];
  10364. }
  10365. else if(response !== undefined) {
  10366. returnedValue = response;
  10367. }
  10368. return found;
  10369. }
  10370. };
  10371. if(methodInvoked) {
  10372. if(instance === undefined) {
  10373. module.initialize();
  10374. }
  10375. module.invoke(query);
  10376. }
  10377. else {
  10378. if(instance !== undefined) {
  10379. instance.invoke('destroy');
  10380. }
  10381. module.initialize();
  10382. }
  10383. })
  10384. ;
  10385. return (returnedValue !== undefined)
  10386. ? returnedValue
  10387. : this
  10388. ;
  10389. };
  10390. $.fn.embed.settings = {
  10391. name : 'Embed',
  10392. namespace : 'embed',
  10393. silent : false,
  10394. debug : false,
  10395. verbose : false,
  10396. performance : true,
  10397. icon : false,
  10398. source : false,
  10399. url : false,
  10400. id : false,
  10401. // standard video settings
  10402. autoplay : 'auto',
  10403. color : '#444444',
  10404. hd : true,
  10405. brandedUI : false,
  10406. // additional parameters to include with the embed
  10407. parameters: false,
  10408. onDisplay : function() {},
  10409. onPlaceholderDisplay : function() {},
  10410. onReset : function() {},
  10411. onCreate : function(url) {},
  10412. onEmbed : function(parameters) {
  10413. return parameters;
  10414. },
  10415. metadata : {
  10416. id : 'id',
  10417. icon : 'icon',
  10418. placeholder : 'placeholder',
  10419. source : 'source',
  10420. url : 'url'
  10421. },
  10422. error : {
  10423. noURL : 'No URL specified',
  10424. method : 'The method you called is not defined'
  10425. },
  10426. className : {
  10427. active : 'active',
  10428. embed : 'embed'
  10429. },
  10430. selector : {
  10431. embed : '.embed',
  10432. placeholder : '.placeholder',
  10433. icon : '.icon'
  10434. },
  10435. sources: {
  10436. youtube: {
  10437. name : 'youtube',
  10438. type : 'video',
  10439. icon : 'video play',
  10440. domain : 'youtube.com',
  10441. url : '//www.youtube.com/embed/{id}',
  10442. parameters: function(settings) {
  10443. return {
  10444. autohide : !settings.brandedUI,
  10445. autoplay : settings.autoplay,
  10446. color : settings.color || undefined,
  10447. hq : settings.hd,
  10448. jsapi : settings.api,
  10449. modestbranding : !settings.brandedUI
  10450. };
  10451. }
  10452. },
  10453. vimeo: {
  10454. name : 'vimeo',
  10455. type : 'video',
  10456. icon : 'video play',
  10457. domain : 'vimeo.com',
  10458. url : '//player.vimeo.com/video/{id}',
  10459. parameters: function(settings) {
  10460. return {
  10461. api : settings.api,
  10462. autoplay : settings.autoplay,
  10463. byline : settings.brandedUI,
  10464. color : settings.color || undefined,
  10465. portrait : settings.brandedUI,
  10466. title : settings.brandedUI
  10467. };
  10468. }
  10469. }
  10470. },
  10471. templates: {
  10472. iframe : function(url, parameters) {
  10473. var src = url;
  10474. if (parameters) {
  10475. src += '?' + parameters;
  10476. }
  10477. return ''
  10478. + '<iframe src="' + src + '"'
  10479. + ' width="100%" height="100%"'
  10480. + ' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'
  10481. ;
  10482. },
  10483. placeholder : function(image, icon) {
  10484. var
  10485. html = ''
  10486. ;
  10487. if(icon) {
  10488. html += '<i class="' + icon + ' icon"></i>';
  10489. }
  10490. if(image) {
  10491. html += '<img class="placeholder" src="' + image + '">';
  10492. }
  10493. return html;
  10494. }
  10495. },
  10496. // NOT YET IMPLEMENTED
  10497. api : false,
  10498. onPause : function() {},
  10499. onPlay : function() {},
  10500. onStop : function() {}
  10501. };
  10502. })( jQuery, window, document );
  10503. /*!
  10504. * # Fomantic-UI - Modal
  10505. * http://github.com/fomantic/Fomantic-UI/
  10506. *
  10507. *
  10508. * Released under the MIT license
  10509. * http://opensource.org/licenses/MIT
  10510. *
  10511. */
  10512. ;(function ($, window, document, undefined) {
  10513. 'use strict';
  10514. $.isFunction = $.isFunction || function(obj) {
  10515. return typeof obj === "function" && typeof obj.nodeType !== "number";
  10516. };
  10517. window = (typeof window != 'undefined' && window.Math == Math)
  10518. ? window
  10519. : (typeof self != 'undefined' && self.Math == Math)
  10520. ? self
  10521. : Function('return this')()
  10522. ;
  10523. $.fn.modal = function(parameters) {
  10524. var
  10525. $allModules = $(this),
  10526. $window = $(window),
  10527. $document = $(document),
  10528. $body = $('body'),
  10529. moduleSelector = $allModules.selector || '',
  10530. time = new Date().getTime(),
  10531. performance = [],
  10532. query = arguments[0],
  10533. methodInvoked = (typeof query == 'string'),
  10534. queryArguments = [].slice.call(arguments, 1),
  10535. requestAnimationFrame = window.requestAnimationFrame
  10536. || window.mozRequestAnimationFrame
  10537. || window.webkitRequestAnimationFrame
  10538. || window.msRequestAnimationFrame
  10539. || function(callback) { setTimeout(callback, 0); },
  10540. returnedValue
  10541. ;
  10542. $allModules
  10543. .each(function() {
  10544. var
  10545. settings = ( $.isPlainObject(parameters) )
  10546. ? $.extend(true, {}, $.fn.modal.settings, parameters)
  10547. : $.extend({}, $.fn.modal.settings),
  10548. selector = settings.selector,
  10549. className = settings.className,
  10550. namespace = settings.namespace,
  10551. error = settings.error,
  10552. eventNamespace = '.' + namespace,
  10553. moduleNamespace = 'module-' + namespace,
  10554. $module = $(this),
  10555. $context = $(settings.context),
  10556. $close = $module.find(selector.close),
  10557. $allModals,
  10558. $otherModals,
  10559. $focusedElement,
  10560. $dimmable,
  10561. $dimmer,
  10562. element = this,
  10563. instance = $module.data(moduleNamespace),
  10564. ignoreRepeatedEvents = false,
  10565. initialMouseDownInModal,
  10566. initialMouseDownInScrollbar,
  10567. initialBodyMargin = '',
  10568. elementEventNamespace,
  10569. id,
  10570. observer,
  10571. module
  10572. ;
  10573. module = {
  10574. initialize: function() {
  10575. module.verbose('Initializing dimmer', $context);
  10576. module.create.id();
  10577. module.create.dimmer();
  10578. if ( settings.allowMultiple ) {
  10579. module.create.innerDimmer();
  10580. }
  10581. if (!settings.centered){
  10582. $module.addClass('top aligned');
  10583. }
  10584. module.refreshModals();
  10585. module.bind.events();
  10586. if(settings.observeChanges) {
  10587. module.observeChanges();
  10588. }
  10589. module.instantiate();
  10590. },
  10591. instantiate: function() {
  10592. module.verbose('Storing instance of modal');
  10593. instance = module;
  10594. $module
  10595. .data(moduleNamespace, instance)
  10596. ;
  10597. },
  10598. create: {
  10599. dimmer: function() {
  10600. var
  10601. defaultSettings = {
  10602. debug : settings.debug,
  10603. dimmerName : 'modals'
  10604. },
  10605. dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
  10606. ;
  10607. if($.fn.dimmer === undefined) {
  10608. module.error(error.dimmer);
  10609. return;
  10610. }
  10611. module.debug('Creating dimmer');
  10612. $dimmable = $context.dimmer(dimmerSettings);
  10613. if(settings.detachable) {
  10614. module.verbose('Modal is detachable, moving content into dimmer');
  10615. $dimmable.dimmer('add content', $module);
  10616. }
  10617. else {
  10618. module.set.undetached();
  10619. }
  10620. $dimmer = $dimmable.dimmer('get dimmer');
  10621. },
  10622. id: function() {
  10623. id = (Math.random().toString(16) + '000000000').substr(2, 8);
  10624. elementEventNamespace = '.' + id;
  10625. module.verbose('Creating unique id for element', id);
  10626. },
  10627. innerDimmer: function() {
  10628. if ( $module.find(selector.dimmer).length == 0 ) {
  10629. $module.prepend('<div class="ui inverted dimmer"></div>');
  10630. }
  10631. }
  10632. },
  10633. destroy: function() {
  10634. if (observer) {
  10635. observer.disconnect();
  10636. }
  10637. module.verbose('Destroying previous modal');
  10638. $module
  10639. .removeData(moduleNamespace)
  10640. .off(eventNamespace)
  10641. ;
  10642. $window.off(elementEventNamespace);
  10643. $dimmer.off(elementEventNamespace);
  10644. $close.off(eventNamespace);
  10645. $context.dimmer('destroy');
  10646. },
  10647. observeChanges: function() {
  10648. if('MutationObserver' in window) {
  10649. observer = new MutationObserver(function(mutations) {
  10650. module.debug('DOM tree modified, refreshing');
  10651. module.refresh();
  10652. });
  10653. observer.observe(element, {
  10654. childList : true,
  10655. subtree : true
  10656. });
  10657. module.debug('Setting up mutation observer', observer);
  10658. }
  10659. },
  10660. refresh: function() {
  10661. module.remove.scrolling();
  10662. module.cacheSizes();
  10663. if(!module.can.useFlex()) {
  10664. module.set.modalOffset();
  10665. }
  10666. module.set.screenHeight();
  10667. module.set.type();
  10668. },
  10669. refreshModals: function() {
  10670. $otherModals = $module.siblings(selector.modal);
  10671. $allModals = $otherModals.add($module);
  10672. },
  10673. attachEvents: function(selector, event) {
  10674. var
  10675. $toggle = $(selector)
  10676. ;
  10677. event = $.isFunction(module[event])
  10678. ? module[event]
  10679. : module.toggle
  10680. ;
  10681. if($toggle.length > 0) {
  10682. module.debug('Attaching modal events to element', selector, event);
  10683. $toggle
  10684. .off(eventNamespace)
  10685. .on('click' + eventNamespace, event)
  10686. ;
  10687. }
  10688. else {
  10689. module.error(error.notFound, selector);
  10690. }
  10691. },
  10692. bind: {
  10693. events: function() {
  10694. module.verbose('Attaching events');
  10695. $module
  10696. .on('click' + eventNamespace, selector.close, module.event.close)
  10697. .on('click' + eventNamespace, selector.approve, module.event.approve)
  10698. .on('click' + eventNamespace, selector.deny, module.event.deny)
  10699. ;
  10700. $window
  10701. .on('resize' + elementEventNamespace, module.event.resize)
  10702. ;
  10703. },
  10704. scrollLock: function() {
  10705. // touch events default to passive, due to changes in chrome to optimize mobile perf
  10706. $dimmable.get(0).addEventListener('touchmove', module.event.preventScroll, { passive: false });
  10707. }
  10708. },
  10709. unbind: {
  10710. scrollLock: function() {
  10711. $dimmable.get(0).removeEventListener('touchmove', module.event.preventScroll, { passive: false });
  10712. }
  10713. },
  10714. get: {
  10715. id: function() {
  10716. return (Math.random().toString(16) + '000000000').substr(2, 8);
  10717. }
  10718. },
  10719. event: {
  10720. approve: function() {
  10721. if(ignoreRepeatedEvents || settings.onApprove.call(element, $(this)) === false) {
  10722. module.verbose('Approve callback returned false cancelling hide');
  10723. return;
  10724. }
  10725. ignoreRepeatedEvents = true;
  10726. module.hide(function() {
  10727. ignoreRepeatedEvents = false;
  10728. });
  10729. },
  10730. preventScroll: function(event) {
  10731. if(event.target.className.indexOf('dimmer') !== -1) {
  10732. event.preventDefault();
  10733. }
  10734. },
  10735. deny: function() {
  10736. if(ignoreRepeatedEvents || settings.onDeny.call(element, $(this)) === false) {
  10737. module.verbose('Deny callback returned false cancelling hide');
  10738. return;
  10739. }
  10740. ignoreRepeatedEvents = true;
  10741. module.hide(function() {
  10742. ignoreRepeatedEvents = false;
  10743. });
  10744. },
  10745. close: function() {
  10746. module.hide();
  10747. },
  10748. mousedown: function(event) {
  10749. var
  10750. $target = $(event.target)
  10751. ;
  10752. initialMouseDownInModal = ($target.closest(selector.modal).length > 0);
  10753. if(initialMouseDownInModal) {
  10754. module.verbose('Mouse down event registered inside the modal');
  10755. }
  10756. initialMouseDownInScrollbar = module.is.scrolling() && $(window).outerWidth() - settings.scrollbarWidth <= event.clientX;
  10757. if(initialMouseDownInScrollbar) {
  10758. module.verbose('Mouse down event registered inside the scrollbar');
  10759. }
  10760. },
  10761. mouseup: function(event) {
  10762. if(!settings.closable) {
  10763. module.verbose('Dimmer clicked but closable setting is disabled');
  10764. return;
  10765. }
  10766. if(initialMouseDownInModal) {
  10767. module.debug('Dimmer clicked but mouse down was initially registered inside the modal');
  10768. return;
  10769. }
  10770. if(initialMouseDownInScrollbar){
  10771. module.debug('Dimmer clicked but mouse down was initially registered inside the scrollbar');
  10772. return;
  10773. }
  10774. var
  10775. $target = $(event.target),
  10776. isInModal = ($target.closest(selector.modal).length > 0),
  10777. isInDOM = $.contains(document.documentElement, event.target)
  10778. ;
  10779. if(!isInModal && isInDOM && module.is.active() && $module.hasClass(className.front) ) {
  10780. module.debug('Dimmer clicked, hiding all modals');
  10781. if(settings.allowMultiple) {
  10782. if(!module.hideAll()) {
  10783. return;
  10784. }
  10785. }
  10786. else if(!module.hide()){
  10787. return;
  10788. }
  10789. module.remove.clickaway();
  10790. }
  10791. },
  10792. debounce: function(method, delay) {
  10793. clearTimeout(module.timer);
  10794. module.timer = setTimeout(method, delay);
  10795. },
  10796. keyboard: function(event) {
  10797. var
  10798. keyCode = event.which,
  10799. escapeKey = 27
  10800. ;
  10801. if(keyCode == escapeKey) {
  10802. if(settings.closable) {
  10803. module.debug('Escape key pressed hiding modal');
  10804. if ( $module.hasClass(className.front) ) {
  10805. module.hide();
  10806. }
  10807. }
  10808. else {
  10809. module.debug('Escape key pressed, but closable is set to false');
  10810. }
  10811. event.preventDefault();
  10812. }
  10813. },
  10814. resize: function() {
  10815. if( $dimmable.dimmer('is active') && ( module.is.animating() || module.is.active() ) ) {
  10816. requestAnimationFrame(module.refresh);
  10817. }
  10818. }
  10819. },
  10820. toggle: function() {
  10821. if( module.is.active() || module.is.animating() ) {
  10822. module.hide();
  10823. }
  10824. else {
  10825. module.show();
  10826. }
  10827. },
  10828. show: function(callback) {
  10829. callback = $.isFunction(callback)
  10830. ? callback
  10831. : function(){}
  10832. ;
  10833. module.refreshModals();
  10834. module.set.dimmerSettings();
  10835. module.set.dimmerStyles();
  10836. module.showModal(callback);
  10837. },
  10838. hide: function(callback) {
  10839. callback = $.isFunction(callback)
  10840. ? callback
  10841. : function(){}
  10842. ;
  10843. module.refreshModals();
  10844. return module.hideModal(callback);
  10845. },
  10846. showModal: function(callback) {
  10847. callback = $.isFunction(callback)
  10848. ? callback
  10849. : function(){}
  10850. ;
  10851. if( module.is.animating() || !module.is.active() ) {
  10852. module.showDimmer();
  10853. module.cacheSizes();
  10854. if(module.can.useFlex()) {
  10855. module.remove.legacy();
  10856. }
  10857. else {
  10858. module.set.legacy();
  10859. module.set.modalOffset();
  10860. module.debug('Using non-flex legacy modal positioning.');
  10861. }
  10862. module.set.screenHeight();
  10863. module.set.type();
  10864. module.set.clickaway();
  10865. if( !settings.allowMultiple && module.others.active() ) {
  10866. module.hideOthers(module.showModal);
  10867. }
  10868. else {
  10869. ignoreRepeatedEvents = false;
  10870. if( settings.allowMultiple ) {
  10871. if ( module.others.active() ) {
  10872. $otherModals.filter('.' + className.active).find(selector.dimmer).addClass('active');
  10873. }
  10874. if ( settings.detachable ) {
  10875. $module.detach().appendTo($dimmer);
  10876. }
  10877. }
  10878. settings.onShow.call(element);
  10879. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  10880. module.debug('Showing modal with css animations');
  10881. $module
  10882. .transition({
  10883. debug : settings.debug,
  10884. animation : settings.transition + ' in',
  10885. queue : settings.queue,
  10886. duration : settings.duration,
  10887. useFailSafe : true,
  10888. onComplete : function() {
  10889. settings.onVisible.apply(element);
  10890. if(settings.keyboardShortcuts) {
  10891. module.add.keyboardShortcuts();
  10892. }
  10893. module.save.focus();
  10894. module.set.active();
  10895. if(settings.autofocus) {
  10896. module.set.autofocus();
  10897. }
  10898. callback();
  10899. }
  10900. })
  10901. ;
  10902. }
  10903. else {
  10904. module.error(error.noTransition);
  10905. }
  10906. }
  10907. }
  10908. else {
  10909. module.debug('Modal is already visible');
  10910. }
  10911. },
  10912. hideModal: function(callback, keepDimmed, hideOthersToo) {
  10913. var
  10914. $previousModal = $otherModals.filter('.' + className.active).last()
  10915. ;
  10916. callback = $.isFunction(callback)
  10917. ? callback
  10918. : function(){}
  10919. ;
  10920. module.debug('Hiding modal');
  10921. if(settings.onHide.call(element, $(this)) === false) {
  10922. module.verbose('Hide callback returned false cancelling hide');
  10923. ignoreRepeatedEvents = false;
  10924. return false;
  10925. }
  10926. if( module.is.animating() || module.is.active() ) {
  10927. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  10928. module.remove.active();
  10929. $module
  10930. .transition({
  10931. debug : settings.debug,
  10932. animation : settings.transition + ' out',
  10933. queue : settings.queue,
  10934. duration : settings.duration,
  10935. useFailSafe : true,
  10936. onStart : function() {
  10937. if(!module.others.active() && !module.others.animating() && !keepDimmed) {
  10938. module.hideDimmer();
  10939. }
  10940. if( settings.keyboardShortcuts && !module.others.active() ) {
  10941. module.remove.keyboardShortcuts();
  10942. }
  10943. },
  10944. onComplete : function() {
  10945. module.unbind.scrollLock();
  10946. if ( settings.allowMultiple ) {
  10947. $previousModal.addClass(className.front);
  10948. $module.removeClass(className.front);
  10949. if ( hideOthersToo ) {
  10950. $allModals.find(selector.dimmer).removeClass('active');
  10951. }
  10952. else {
  10953. $previousModal.find(selector.dimmer).removeClass('active');
  10954. }
  10955. }
  10956. settings.onHidden.call(element);
  10957. module.remove.dimmerStyles();
  10958. module.restore.focus();
  10959. callback();
  10960. }
  10961. })
  10962. ;
  10963. }
  10964. else {
  10965. module.error(error.noTransition);
  10966. }
  10967. }
  10968. },
  10969. showDimmer: function() {
  10970. if($dimmable.dimmer('is animating') || !$dimmable.dimmer('is active') ) {
  10971. module.save.bodyMargin();
  10972. module.debug('Showing dimmer');
  10973. $dimmable.dimmer('show');
  10974. }
  10975. else {
  10976. module.debug('Dimmer already visible');
  10977. }
  10978. },
  10979. hideDimmer: function() {
  10980. if( $dimmable.dimmer('is animating') || ($dimmable.dimmer('is active')) ) {
  10981. module.unbind.scrollLock();
  10982. $dimmable.dimmer('hide', function() {
  10983. module.restore.bodyMargin();
  10984. module.remove.clickaway();
  10985. module.remove.screenHeight();
  10986. });
  10987. }
  10988. else {
  10989. module.debug('Dimmer is not visible cannot hide');
  10990. return;
  10991. }
  10992. },
  10993. hideAll: function(callback) {
  10994. var
  10995. $visibleModals = $allModals.filter('.' + className.active + ', .' + className.animating)
  10996. ;
  10997. callback = $.isFunction(callback)
  10998. ? callback
  10999. : function(){}
  11000. ;
  11001. if( $visibleModals.length > 0 ) {
  11002. module.debug('Hiding all visible modals');
  11003. var hideOk = true;
  11004. //check in reverse order trying to hide most top displayed modal first
  11005. $($visibleModals.get().reverse()).each(function(index,element){
  11006. if(hideOk){
  11007. hideOk = $(element).modal('hide modal', callback, false, true);
  11008. }
  11009. });
  11010. if(hideOk) {
  11011. module.hideDimmer();
  11012. }
  11013. return hideOk;
  11014. }
  11015. },
  11016. hideOthers: function(callback) {
  11017. var
  11018. $visibleModals = $otherModals.filter('.' + className.active + ', .' + className.animating)
  11019. ;
  11020. callback = $.isFunction(callback)
  11021. ? callback
  11022. : function(){}
  11023. ;
  11024. if( $visibleModals.length > 0 ) {
  11025. module.debug('Hiding other modals', $otherModals);
  11026. $visibleModals
  11027. .modal('hide modal', callback, true)
  11028. ;
  11029. }
  11030. },
  11031. others: {
  11032. active: function() {
  11033. return ($otherModals.filter('.' + className.active).length > 0);
  11034. },
  11035. animating: function() {
  11036. return ($otherModals.filter('.' + className.animating).length > 0);
  11037. }
  11038. },
  11039. add: {
  11040. keyboardShortcuts: function() {
  11041. module.verbose('Adding keyboard shortcuts');
  11042. $document
  11043. .on('keyup' + eventNamespace, module.event.keyboard)
  11044. ;
  11045. }
  11046. },
  11047. save: {
  11048. focus: function() {
  11049. var
  11050. $activeElement = $(document.activeElement),
  11051. inCurrentModal = $activeElement.closest($module).length > 0
  11052. ;
  11053. if(!inCurrentModal) {
  11054. $focusedElement = $(document.activeElement).blur();
  11055. }
  11056. },
  11057. bodyMargin: function() {
  11058. initialBodyMargin = $body.css('margin-right');
  11059. var bodyMarginRightPixel = parseInt(initialBodyMargin.replace(/[^\d.]/g, '')),
  11060. bodyScrollbarWidth = window.innerWidth - document.documentElement.clientWidth,
  11061. diffPos = bodyMarginRightPixel + bodyScrollbarWidth;
  11062. $body.css('margin-right', diffPos + 'px');
  11063. $body.find(selector.bodyFixed).css('padding-right', diffPos + 'px');
  11064. }
  11065. },
  11066. restore: {
  11067. focus: function() {
  11068. if($focusedElement && $focusedElement.length > 0 && settings.restoreFocus) {
  11069. $focusedElement.focus();
  11070. }
  11071. },
  11072. bodyMargin: function() {
  11073. $body.css('margin-right', initialBodyMargin);
  11074. $body.find(selector.bodyFixed).css('padding-right', initialBodyMargin);
  11075. }
  11076. },
  11077. remove: {
  11078. active: function() {
  11079. $module.removeClass(className.active);
  11080. },
  11081. legacy: function() {
  11082. $module.removeClass(className.legacy);
  11083. },
  11084. clickaway: function() {
  11085. $dimmer
  11086. .off('mousedown' + elementEventNamespace)
  11087. ;
  11088. $dimmer
  11089. .off('mouseup' + elementEventNamespace)
  11090. ;
  11091. },
  11092. dimmerStyles: function() {
  11093. $dimmer.removeClass(className.inverted);
  11094. $dimmable.removeClass(className.blurring);
  11095. },
  11096. bodyStyle: function() {
  11097. if($body.attr('style') === '') {
  11098. module.verbose('Removing style attribute');
  11099. $body.removeAttr('style');
  11100. }
  11101. },
  11102. screenHeight: function() {
  11103. module.debug('Removing page height');
  11104. $body
  11105. .css('height', '')
  11106. ;
  11107. },
  11108. keyboardShortcuts: function() {
  11109. module.verbose('Removing keyboard shortcuts');
  11110. $document
  11111. .off('keyup' + eventNamespace)
  11112. ;
  11113. },
  11114. scrolling: function() {
  11115. $dimmable.removeClass(className.scrolling);
  11116. $module.removeClass(className.scrolling);
  11117. }
  11118. },
  11119. cacheSizes: function() {
  11120. $module.addClass(className.loading);
  11121. var
  11122. scrollHeight = $module.prop('scrollHeight'),
  11123. modalWidth = $module.outerWidth(),
  11124. modalHeight = $module.outerHeight()
  11125. ;
  11126. if(module.cache === undefined || modalHeight !== 0) {
  11127. module.cache = {
  11128. pageHeight : $(document).outerHeight(),
  11129. width : modalWidth,
  11130. height : modalHeight + settings.offset,
  11131. scrollHeight : scrollHeight + settings.offset,
  11132. contextHeight : (settings.context == 'body')
  11133. ? $(window).height()
  11134. : $dimmable.height(),
  11135. };
  11136. module.cache.topOffset = -(module.cache.height / 2);
  11137. }
  11138. $module.removeClass(className.loading);
  11139. module.debug('Caching modal and container sizes', module.cache);
  11140. },
  11141. can: {
  11142. useFlex: function() {
  11143. return (settings.useFlex == 'auto')
  11144. ? settings.detachable && !module.is.ie()
  11145. : settings.useFlex
  11146. ;
  11147. },
  11148. fit: function() {
  11149. var
  11150. contextHeight = module.cache.contextHeight,
  11151. verticalCenter = module.cache.contextHeight / 2,
  11152. topOffset = module.cache.topOffset,
  11153. scrollHeight = module.cache.scrollHeight,
  11154. height = module.cache.height,
  11155. paddingHeight = settings.padding,
  11156. startPosition = (verticalCenter + topOffset)
  11157. ;
  11158. return (scrollHeight > height)
  11159. ? (startPosition + scrollHeight + paddingHeight < contextHeight)
  11160. : (height + (paddingHeight * 2) < contextHeight)
  11161. ;
  11162. }
  11163. },
  11164. is: {
  11165. active: function() {
  11166. return $module.hasClass(className.active);
  11167. },
  11168. ie: function() {
  11169. var
  11170. isIE11 = (!(window.ActiveXObject) && 'ActiveXObject' in window),
  11171. isIE = ('ActiveXObject' in window)
  11172. ;
  11173. return (isIE11 || isIE);
  11174. },
  11175. animating: function() {
  11176. return $module.transition('is supported')
  11177. ? $module.transition('is animating')
  11178. : $module.is(':visible')
  11179. ;
  11180. },
  11181. scrolling: function() {
  11182. return $dimmable.hasClass(className.scrolling);
  11183. },
  11184. modernBrowser: function() {
  11185. // appName for IE11 reports 'Netscape' can no longer use
  11186. return !(window.ActiveXObject || 'ActiveXObject' in window);
  11187. }
  11188. },
  11189. set: {
  11190. autofocus: function() {
  11191. var
  11192. $inputs = $module.find('[tabindex], :input').filter(':visible').filter(function() {
  11193. return $(this).closest('.disabled').length === 0;
  11194. }),
  11195. $autofocus = $inputs.filter('[autofocus]'),
  11196. $input = ($autofocus.length > 0)
  11197. ? $autofocus.first()
  11198. : $inputs.first()
  11199. ;
  11200. if($input.length > 0) {
  11201. $input.focus();
  11202. }
  11203. },
  11204. clickaway: function() {
  11205. $dimmer
  11206. .on('mousedown' + elementEventNamespace, module.event.mousedown)
  11207. ;
  11208. $dimmer
  11209. .on('mouseup' + elementEventNamespace, module.event.mouseup)
  11210. ;
  11211. },
  11212. dimmerSettings: function() {
  11213. if($.fn.dimmer === undefined) {
  11214. module.error(error.dimmer);
  11215. return;
  11216. }
  11217. var
  11218. defaultSettings = {
  11219. debug : settings.debug,
  11220. dimmerName : 'modals',
  11221. closable : 'auto',
  11222. useFlex : module.can.useFlex(),
  11223. duration : {
  11224. show : settings.duration,
  11225. hide : settings.duration
  11226. }
  11227. },
  11228. dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
  11229. ;
  11230. if(settings.inverted) {
  11231. dimmerSettings.variation = (dimmerSettings.variation !== undefined)
  11232. ? dimmerSettings.variation + ' inverted'
  11233. : 'inverted'
  11234. ;
  11235. }
  11236. $context.dimmer('setting', dimmerSettings);
  11237. },
  11238. dimmerStyles: function() {
  11239. if(settings.inverted) {
  11240. $dimmer.addClass(className.inverted);
  11241. }
  11242. else {
  11243. $dimmer.removeClass(className.inverted);
  11244. }
  11245. if(settings.blurring) {
  11246. $dimmable.addClass(className.blurring);
  11247. }
  11248. else {
  11249. $dimmable.removeClass(className.blurring);
  11250. }
  11251. },
  11252. modalOffset: function() {
  11253. var
  11254. width = module.cache.width,
  11255. height = module.cache.height
  11256. ;
  11257. $module
  11258. .css({
  11259. marginTop: (!$module.hasClass('aligned') && module.can.fit())
  11260. ? -(height / 2)
  11261. : 0,
  11262. marginLeft: -(width / 2)
  11263. })
  11264. ;
  11265. module.verbose('Setting modal offset for legacy mode');
  11266. },
  11267. screenHeight: function() {
  11268. if( module.can.fit() ) {
  11269. $body.css('height', '');
  11270. }
  11271. else if(!$module.hasClass('bottom')) {
  11272. module.debug('Modal is taller than page content, resizing page height');
  11273. $body
  11274. .css('height', module.cache.height + (settings.padding * 2) )
  11275. ;
  11276. }
  11277. },
  11278. active: function() {
  11279. $module.addClass(className.active + ' ' + className.front);
  11280. $otherModals.filter('.' + className.active).removeClass(className.front);
  11281. },
  11282. scrolling: function() {
  11283. $dimmable.addClass(className.scrolling);
  11284. $module.addClass(className.scrolling);
  11285. module.unbind.scrollLock();
  11286. },
  11287. legacy: function() {
  11288. $module.addClass(className.legacy);
  11289. },
  11290. type: function() {
  11291. if(module.can.fit()) {
  11292. module.verbose('Modal fits on screen');
  11293. if(!module.others.active() && !module.others.animating()) {
  11294. module.remove.scrolling();
  11295. module.bind.scrollLock();
  11296. }
  11297. }
  11298. else if (!$module.hasClass('bottom')){
  11299. module.verbose('Modal cannot fit on screen setting to scrolling');
  11300. module.set.scrolling();
  11301. } else {
  11302. module.verbose('Bottom aligned modal not fitting on screen is unsupported for scrolling');
  11303. }
  11304. },
  11305. undetached: function() {
  11306. $dimmable.addClass(className.undetached);
  11307. }
  11308. },
  11309. setting: function(name, value) {
  11310. module.debug('Changing setting', name, value);
  11311. if( $.isPlainObject(name) ) {
  11312. $.extend(true, settings, name);
  11313. }
  11314. else if(value !== undefined) {
  11315. if($.isPlainObject(settings[name])) {
  11316. $.extend(true, settings[name], value);
  11317. }
  11318. else {
  11319. settings[name] = value;
  11320. }
  11321. }
  11322. else {
  11323. return settings[name];
  11324. }
  11325. },
  11326. internal: function(name, value) {
  11327. if( $.isPlainObject(name) ) {
  11328. $.extend(true, module, name);
  11329. }
  11330. else if(value !== undefined) {
  11331. module[name] = value;
  11332. }
  11333. else {
  11334. return module[name];
  11335. }
  11336. },
  11337. debug: function() {
  11338. if(!settings.silent && settings.debug) {
  11339. if(settings.performance) {
  11340. module.performance.log(arguments);
  11341. }
  11342. else {
  11343. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  11344. module.debug.apply(console, arguments);
  11345. }
  11346. }
  11347. },
  11348. verbose: function() {
  11349. if(!settings.silent && settings.verbose && settings.debug) {
  11350. if(settings.performance) {
  11351. module.performance.log(arguments);
  11352. }
  11353. else {
  11354. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  11355. module.verbose.apply(console, arguments);
  11356. }
  11357. }
  11358. },
  11359. error: function() {
  11360. if(!settings.silent) {
  11361. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  11362. module.error.apply(console, arguments);
  11363. }
  11364. },
  11365. performance: {
  11366. log: function(message) {
  11367. var
  11368. currentTime,
  11369. executionTime,
  11370. previousTime
  11371. ;
  11372. if(settings.performance) {
  11373. currentTime = new Date().getTime();
  11374. previousTime = time || currentTime;
  11375. executionTime = currentTime - previousTime;
  11376. time = currentTime;
  11377. performance.push({
  11378. 'Name' : message[0],
  11379. 'Arguments' : [].slice.call(message, 1) || '',
  11380. 'Element' : element,
  11381. 'Execution Time' : executionTime
  11382. });
  11383. }
  11384. clearTimeout(module.performance.timer);
  11385. module.performance.timer = setTimeout(module.performance.display, 500);
  11386. },
  11387. display: function() {
  11388. var
  11389. title = settings.name + ':',
  11390. totalTime = 0
  11391. ;
  11392. time = false;
  11393. clearTimeout(module.performance.timer);
  11394. $.each(performance, function(index, data) {
  11395. totalTime += data['Execution Time'];
  11396. });
  11397. title += ' ' + totalTime + 'ms';
  11398. if(moduleSelector) {
  11399. title += ' \'' + moduleSelector + '\'';
  11400. }
  11401. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  11402. console.groupCollapsed(title);
  11403. if(console.table) {
  11404. console.table(performance);
  11405. }
  11406. else {
  11407. $.each(performance, function(index, data) {
  11408. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  11409. });
  11410. }
  11411. console.groupEnd();
  11412. }
  11413. performance = [];
  11414. }
  11415. },
  11416. invoke: function(query, passedArguments, context) {
  11417. var
  11418. object = instance,
  11419. maxDepth,
  11420. found,
  11421. response
  11422. ;
  11423. passedArguments = passedArguments || queryArguments;
  11424. context = element || context;
  11425. if(typeof query == 'string' && object !== undefined) {
  11426. query = query.split(/[\. ]/);
  11427. maxDepth = query.length - 1;
  11428. $.each(query, function(depth, value) {
  11429. var camelCaseValue = (depth != maxDepth)
  11430. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  11431. : query
  11432. ;
  11433. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  11434. object = object[camelCaseValue];
  11435. }
  11436. else if( object[camelCaseValue] !== undefined ) {
  11437. found = object[camelCaseValue];
  11438. return false;
  11439. }
  11440. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  11441. object = object[value];
  11442. }
  11443. else if( object[value] !== undefined ) {
  11444. found = object[value];
  11445. return false;
  11446. }
  11447. else {
  11448. return false;
  11449. }
  11450. });
  11451. }
  11452. if ( $.isFunction( found ) ) {
  11453. response = found.apply(context, passedArguments);
  11454. }
  11455. else if(found !== undefined) {
  11456. response = found;
  11457. }
  11458. if(Array.isArray(returnedValue)) {
  11459. returnedValue.push(response);
  11460. }
  11461. else if(returnedValue !== undefined) {
  11462. returnedValue = [returnedValue, response];
  11463. }
  11464. else if(response !== undefined) {
  11465. returnedValue = response;
  11466. }
  11467. return found;
  11468. }
  11469. };
  11470. if(methodInvoked) {
  11471. if(instance === undefined) {
  11472. module.initialize();
  11473. }
  11474. module.invoke(query);
  11475. }
  11476. else {
  11477. if(instance !== undefined) {
  11478. instance.invoke('destroy');
  11479. }
  11480. module.initialize();
  11481. }
  11482. })
  11483. ;
  11484. return (returnedValue !== undefined)
  11485. ? returnedValue
  11486. : this
  11487. ;
  11488. };
  11489. $.fn.modal.settings = {
  11490. name : 'Modal',
  11491. namespace : 'modal',
  11492. useFlex : 'auto',
  11493. offset : 0,
  11494. silent : false,
  11495. debug : false,
  11496. verbose : false,
  11497. performance : true,
  11498. observeChanges : false,
  11499. allowMultiple : false,
  11500. detachable : true,
  11501. closable : true,
  11502. autofocus : true,
  11503. restoreFocus : true,
  11504. inverted : false,
  11505. blurring : false,
  11506. centered : true,
  11507. dimmerSettings : {
  11508. closable : false,
  11509. useCSS : true
  11510. },
  11511. // whether to use keyboard shortcuts
  11512. keyboardShortcuts: true,
  11513. context : 'body',
  11514. queue : false,
  11515. duration : 500,
  11516. transition : 'scale',
  11517. // padding with edge of page
  11518. padding : 50,
  11519. scrollbarWidth: 10,
  11520. // called before show animation
  11521. onShow : function(){},
  11522. // called after show animation
  11523. onVisible : function(){},
  11524. // called before hide animation
  11525. onHide : function(){ return true; },
  11526. // called after hide animation
  11527. onHidden : function(){},
  11528. // called after approve selector match
  11529. onApprove : function(){ return true; },
  11530. // called after deny selector match
  11531. onDeny : function(){ return true; },
  11532. selector : {
  11533. close : '> .close',
  11534. approve : '.actions .positive, .actions .approve, .actions .ok',
  11535. deny : '.actions .negative, .actions .deny, .actions .cancel',
  11536. modal : '.ui.modal',
  11537. dimmer : '> .ui.dimmer',
  11538. bodyFixed: '> .ui.fixed.menu, > .ui.right.toast-container, > .ui.right.sidebar'
  11539. },
  11540. error : {
  11541. dimmer : 'UI Dimmer, a required component is not included in this page',
  11542. method : 'The method you called is not defined.',
  11543. notFound : 'The element you specified could not be found'
  11544. },
  11545. className : {
  11546. active : 'active',
  11547. animating : 'animating',
  11548. blurring : 'blurring',
  11549. inverted : 'inverted',
  11550. legacy : 'legacy',
  11551. loading : 'loading',
  11552. scrolling : 'scrolling',
  11553. undetached : 'undetached',
  11554. front : 'front'
  11555. }
  11556. };
  11557. })( jQuery, window, document );
  11558. /*!
  11559. * # Fomantic-UI - Nag
  11560. * http://github.com/fomantic/Fomantic-UI/
  11561. *
  11562. *
  11563. * Released under the MIT license
  11564. * http://opensource.org/licenses/MIT
  11565. *
  11566. */
  11567. ;(function ($, window, document, undefined) {
  11568. 'use strict';
  11569. $.isFunction = $.isFunction || function(obj) {
  11570. return typeof obj === "function" && typeof obj.nodeType !== "number";
  11571. };
  11572. window = (typeof window != 'undefined' && window.Math == Math)
  11573. ? window
  11574. : (typeof self != 'undefined' && self.Math == Math)
  11575. ? self
  11576. : Function('return this')()
  11577. ;
  11578. $.fn.nag = function(parameters) {
  11579. var
  11580. $allModules = $(this),
  11581. moduleSelector = $allModules.selector || '',
  11582. time = new Date().getTime(),
  11583. performance = [],
  11584. query = arguments[0],
  11585. methodInvoked = (typeof query == 'string'),
  11586. queryArguments = [].slice.call(arguments, 1),
  11587. returnedValue
  11588. ;
  11589. $allModules
  11590. .each(function() {
  11591. var
  11592. settings = ( $.isPlainObject(parameters) )
  11593. ? $.extend(true, {}, $.fn.nag.settings, parameters)
  11594. : $.extend({}, $.fn.nag.settings),
  11595. selector = settings.selector,
  11596. error = settings.error,
  11597. namespace = settings.namespace,
  11598. eventNamespace = '.' + namespace,
  11599. moduleNamespace = namespace + '-module',
  11600. $module = $(this),
  11601. $context = (settings.context)
  11602. ? $(settings.context)
  11603. : $('body'),
  11604. element = this,
  11605. instance = $module.data(moduleNamespace),
  11606. module
  11607. ;
  11608. module = {
  11609. initialize: function() {
  11610. module.verbose('Initializing element');
  11611. $module
  11612. .on('click' + eventNamespace, selector.close, module.dismiss)
  11613. .data(moduleNamespace, module)
  11614. ;
  11615. if(settings.detachable && $module.parent()[0] !== $context[0]) {
  11616. $module
  11617. .detach()
  11618. .prependTo($context)
  11619. ;
  11620. }
  11621. if(settings.displayTime > 0) {
  11622. setTimeout(module.hide, settings.displayTime);
  11623. }
  11624. module.show();
  11625. },
  11626. destroy: function() {
  11627. module.verbose('Destroying instance');
  11628. $module
  11629. .removeData(moduleNamespace)
  11630. .off(eventNamespace)
  11631. ;
  11632. },
  11633. show: function() {
  11634. if( module.should.show() && !$module.is(':visible') ) {
  11635. module.debug('Showing nag', settings.animation.show);
  11636. if(settings.animation.show == 'fade') {
  11637. $module
  11638. .fadeIn(settings.duration, settings.easing)
  11639. ;
  11640. }
  11641. else {
  11642. $module
  11643. .slideDown(settings.duration, settings.easing)
  11644. ;
  11645. }
  11646. }
  11647. },
  11648. hide: function() {
  11649. module.debug('Showing nag', settings.animation.hide);
  11650. if(settings.animation.show == 'fade') {
  11651. $module
  11652. .fadeIn(settings.duration, settings.easing)
  11653. ;
  11654. }
  11655. else {
  11656. $module
  11657. .slideUp(settings.duration, settings.easing)
  11658. ;
  11659. }
  11660. },
  11661. onHide: function() {
  11662. module.debug('Removing nag', settings.animation.hide);
  11663. $module.remove();
  11664. if (settings.onHide) {
  11665. settings.onHide();
  11666. }
  11667. },
  11668. dismiss: function(event) {
  11669. if(settings.storageMethod) {
  11670. module.storage.set(settings.key, settings.value);
  11671. }
  11672. module.hide();
  11673. event.stopImmediatePropagation();
  11674. event.preventDefault();
  11675. },
  11676. should: {
  11677. show: function() {
  11678. if(settings.persist) {
  11679. module.debug('Persistent nag is set, can show nag');
  11680. return true;
  11681. }
  11682. if( module.storage.get(settings.key) != settings.value.toString() ) {
  11683. module.debug('Stored value is not set, can show nag', module.storage.get(settings.key));
  11684. return true;
  11685. }
  11686. module.debug('Stored value is set, cannot show nag', module.storage.get(settings.key));
  11687. return false;
  11688. }
  11689. },
  11690. get: {
  11691. storageOptions: function() {
  11692. var
  11693. options = {}
  11694. ;
  11695. if(settings.expires) {
  11696. options.expires = settings.expires;
  11697. }
  11698. if(settings.domain) {
  11699. options.domain = settings.domain;
  11700. }
  11701. if(settings.path) {
  11702. options.path = settings.path;
  11703. }
  11704. return options;
  11705. }
  11706. },
  11707. clear: function() {
  11708. module.storage.remove(settings.key);
  11709. },
  11710. storage: {
  11711. set: function(key, value) {
  11712. var
  11713. options = module.get.storageOptions()
  11714. ;
  11715. if(settings.storageMethod == 'localstorage' && window.localStorage !== undefined) {
  11716. window.localStorage.setItem(key, value);
  11717. module.debug('Value stored using local storage', key, value);
  11718. }
  11719. else if(settings.storageMethod == 'sessionstorage' && window.sessionStorage !== undefined) {
  11720. window.sessionStorage.setItem(key, value);
  11721. module.debug('Value stored using session storage', key, value);
  11722. }
  11723. else if($.cookie !== undefined) {
  11724. $.cookie(key, value, options);
  11725. module.debug('Value stored using cookie', key, value, options);
  11726. }
  11727. else {
  11728. module.error(error.noCookieStorage);
  11729. return;
  11730. }
  11731. },
  11732. get: function(key, value) {
  11733. var
  11734. storedValue
  11735. ;
  11736. if(settings.storageMethod == 'localstorage' && window.localStorage !== undefined) {
  11737. storedValue = window.localStorage.getItem(key);
  11738. }
  11739. else if(settings.storageMethod == 'sessionstorage' && window.sessionStorage !== undefined) {
  11740. storedValue = window.sessionStorage.getItem(key);
  11741. }
  11742. // get by cookie
  11743. else if($.cookie !== undefined) {
  11744. storedValue = $.cookie(key);
  11745. }
  11746. else {
  11747. module.error(error.noCookieStorage);
  11748. }
  11749. if(storedValue == 'undefined' || storedValue == 'null' || storedValue === undefined || storedValue === null) {
  11750. storedValue = undefined;
  11751. }
  11752. return storedValue;
  11753. },
  11754. remove: function(key) {
  11755. var
  11756. options = module.get.storageOptions()
  11757. ;
  11758. if(settings.storageMethod == 'localstorage' && window.localStorage !== undefined) {
  11759. window.localStorage.removeItem(key);
  11760. }
  11761. else if(settings.storageMethod == 'sessionstorage' && window.sessionStorage !== undefined) {
  11762. window.sessionStorage.removeItem(key);
  11763. }
  11764. // store by cookie
  11765. else if($.cookie !== undefined) {
  11766. $.removeCookie(key, options);
  11767. }
  11768. else {
  11769. module.error(error.noStorage);
  11770. }
  11771. }
  11772. },
  11773. setting: function(name, value) {
  11774. module.debug('Changing setting', name, value);
  11775. if( $.isPlainObject(name) ) {
  11776. $.extend(true, settings, name);
  11777. }
  11778. else if(value !== undefined) {
  11779. if($.isPlainObject(settings[name])) {
  11780. $.extend(true, settings[name], value);
  11781. }
  11782. else {
  11783. settings[name] = value;
  11784. }
  11785. }
  11786. else {
  11787. return settings[name];
  11788. }
  11789. },
  11790. internal: function(name, value) {
  11791. if( $.isPlainObject(name) ) {
  11792. $.extend(true, module, name);
  11793. }
  11794. else if(value !== undefined) {
  11795. module[name] = value;
  11796. }
  11797. else {
  11798. return module[name];
  11799. }
  11800. },
  11801. debug: function() {
  11802. if(!settings.silent && settings.debug) {
  11803. if(settings.performance) {
  11804. module.performance.log(arguments);
  11805. }
  11806. else {
  11807. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  11808. module.debug.apply(console, arguments);
  11809. }
  11810. }
  11811. },
  11812. verbose: function() {
  11813. if(!settings.silent && settings.verbose && settings.debug) {
  11814. if(settings.performance) {
  11815. module.performance.log(arguments);
  11816. }
  11817. else {
  11818. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  11819. module.verbose.apply(console, arguments);
  11820. }
  11821. }
  11822. },
  11823. error: function() {
  11824. if(!settings.silent) {
  11825. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  11826. module.error.apply(console, arguments);
  11827. }
  11828. },
  11829. performance: {
  11830. log: function(message) {
  11831. var
  11832. currentTime,
  11833. executionTime,
  11834. previousTime
  11835. ;
  11836. if(settings.performance) {
  11837. currentTime = new Date().getTime();
  11838. previousTime = time || currentTime;
  11839. executionTime = currentTime - previousTime;
  11840. time = currentTime;
  11841. performance.push({
  11842. 'Name' : message[0],
  11843. 'Arguments' : [].slice.call(message, 1) || '',
  11844. 'Element' : element,
  11845. 'Execution Time' : executionTime
  11846. });
  11847. }
  11848. clearTimeout(module.performance.timer);
  11849. module.performance.timer = setTimeout(module.performance.display, 500);
  11850. },
  11851. display: function() {
  11852. var
  11853. title = settings.name + ':',
  11854. totalTime = 0
  11855. ;
  11856. time = false;
  11857. clearTimeout(module.performance.timer);
  11858. $.each(performance, function(index, data) {
  11859. totalTime += data['Execution Time'];
  11860. });
  11861. title += ' ' + totalTime + 'ms';
  11862. if(moduleSelector) {
  11863. title += ' \'' + moduleSelector + '\'';
  11864. }
  11865. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  11866. console.groupCollapsed(title);
  11867. if(console.table) {
  11868. console.table(performance);
  11869. }
  11870. else {
  11871. $.each(performance, function(index, data) {
  11872. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  11873. });
  11874. }
  11875. console.groupEnd();
  11876. }
  11877. performance = [];
  11878. }
  11879. },
  11880. invoke: function(query, passedArguments, context) {
  11881. var
  11882. object = instance,
  11883. maxDepth,
  11884. found,
  11885. response
  11886. ;
  11887. passedArguments = passedArguments || queryArguments;
  11888. context = element || context;
  11889. if(typeof query == 'string' && object !== undefined) {
  11890. query = query.split(/[\. ]/);
  11891. maxDepth = query.length - 1;
  11892. $.each(query, function(depth, value) {
  11893. var camelCaseValue = (depth != maxDepth)
  11894. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  11895. : query
  11896. ;
  11897. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  11898. object = object[camelCaseValue];
  11899. }
  11900. else if( object[camelCaseValue] !== undefined ) {
  11901. found = object[camelCaseValue];
  11902. return false;
  11903. }
  11904. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  11905. object = object[value];
  11906. }
  11907. else if( object[value] !== undefined ) {
  11908. found = object[value];
  11909. return false;
  11910. }
  11911. else {
  11912. module.error(error.method, query);
  11913. return false;
  11914. }
  11915. });
  11916. }
  11917. if ( $.isFunction( found ) ) {
  11918. response = found.apply(context, passedArguments);
  11919. }
  11920. else if(found !== undefined) {
  11921. response = found;
  11922. }
  11923. if(Array.isArray(returnedValue)) {
  11924. returnedValue.push(response);
  11925. }
  11926. else if(returnedValue !== undefined) {
  11927. returnedValue = [returnedValue, response];
  11928. }
  11929. else if(response !== undefined) {
  11930. returnedValue = response;
  11931. }
  11932. return found;
  11933. }
  11934. };
  11935. if(methodInvoked) {
  11936. if(instance === undefined) {
  11937. module.initialize();
  11938. }
  11939. module.invoke(query);
  11940. }
  11941. else {
  11942. if(instance !== undefined) {
  11943. instance.invoke('destroy');
  11944. }
  11945. module.initialize();
  11946. }
  11947. })
  11948. ;
  11949. return (returnedValue !== undefined)
  11950. ? returnedValue
  11951. : this
  11952. ;
  11953. };
  11954. $.fn.nag.settings = {
  11955. name : 'Nag',
  11956. silent : false,
  11957. debug : false,
  11958. verbose : false,
  11959. performance : true,
  11960. namespace : 'Nag',
  11961. // allows cookie to be overridden
  11962. persist : false,
  11963. // set to zero to require manually dismissal, otherwise hides on its own
  11964. displayTime : 0,
  11965. animation : {
  11966. show : 'slide',
  11967. hide : 'slide'
  11968. },
  11969. context : false,
  11970. detachable : false,
  11971. expires : 30,
  11972. domain : false,
  11973. path : '/',
  11974. // type of storage to use
  11975. storageMethod : 'cookie',
  11976. // value to store in dismissed localstorage/cookie
  11977. key : 'nag',
  11978. value : 'dismiss',
  11979. error: {
  11980. noCookieStorage : '$.cookie is not included. A storage solution is required.',
  11981. noStorage : 'Neither $.cookie or store is defined. A storage solution is required for storing state',
  11982. method : 'The method you called is not defined.'
  11983. },
  11984. className : {
  11985. bottom : 'bottom',
  11986. fixed : 'fixed'
  11987. },
  11988. selector : {
  11989. close : '.close.icon'
  11990. },
  11991. speed : 500,
  11992. easing : 'easeOutQuad',
  11993. onHide: function() {}
  11994. };
  11995. // Adds easing
  11996. $.extend( $.easing, {
  11997. easeOutQuad: function (x, t, b, c, d) {
  11998. return -c *(t/=d)*(t-2) + b;
  11999. }
  12000. });
  12001. })( jQuery, window, document );
  12002. /*!
  12003. * # Fomantic-UI - Popup
  12004. * http://github.com/fomantic/Fomantic-UI/
  12005. *
  12006. *
  12007. * Released under the MIT license
  12008. * http://opensource.org/licenses/MIT
  12009. *
  12010. */
  12011. ;(function ($, window, document, undefined) {
  12012. 'use strict';
  12013. $.isFunction = $.isFunction || function(obj) {
  12014. return typeof obj === "function" && typeof obj.nodeType !== "number";
  12015. };
  12016. window = (typeof window != 'undefined' && window.Math == Math)
  12017. ? window
  12018. : (typeof self != 'undefined' && self.Math == Math)
  12019. ? self
  12020. : Function('return this')()
  12021. ;
  12022. $.fn.popup = function(parameters) {
  12023. var
  12024. $allModules = $(this),
  12025. $document = $(document),
  12026. $window = $(window),
  12027. $body = $('body'),
  12028. moduleSelector = $allModules.selector || '',
  12029. clickEvent = ('ontouchstart' in document.documentElement)
  12030. ? 'touchstart'
  12031. : 'click',
  12032. time = new Date().getTime(),
  12033. performance = [],
  12034. query = arguments[0],
  12035. methodInvoked = (typeof query == 'string'),
  12036. queryArguments = [].slice.call(arguments, 1),
  12037. returnedValue
  12038. ;
  12039. $allModules
  12040. .each(function() {
  12041. var
  12042. settings = ( $.isPlainObject(parameters) )
  12043. ? $.extend(true, {}, $.fn.popup.settings, parameters)
  12044. : $.extend({}, $.fn.popup.settings),
  12045. selector = settings.selector,
  12046. className = settings.className,
  12047. error = settings.error,
  12048. metadata = settings.metadata,
  12049. namespace = settings.namespace,
  12050. eventNamespace = '.' + settings.namespace,
  12051. moduleNamespace = 'module-' + namespace,
  12052. $module = $(this),
  12053. $context = $(settings.context),
  12054. $scrollContext = $(settings.scrollContext),
  12055. $boundary = $(settings.boundary),
  12056. $target = (settings.target)
  12057. ? $(settings.target)
  12058. : $module,
  12059. $popup,
  12060. $offsetParent,
  12061. searchDepth = 0,
  12062. triedPositions = false,
  12063. openedWithTouch = false,
  12064. element = this,
  12065. instance = $module.data(moduleNamespace),
  12066. documentObserver,
  12067. elementNamespace,
  12068. id,
  12069. module
  12070. ;
  12071. module = {
  12072. // binds events
  12073. initialize: function() {
  12074. module.debug('Initializing', $module);
  12075. module.createID();
  12076. module.bind.events();
  12077. if(!module.exists() && settings.preserve) {
  12078. module.create();
  12079. }
  12080. if(settings.observeChanges) {
  12081. module.observeChanges();
  12082. }
  12083. module.instantiate();
  12084. },
  12085. instantiate: function() {
  12086. module.verbose('Storing instance', module);
  12087. instance = module;
  12088. $module
  12089. .data(moduleNamespace, instance)
  12090. ;
  12091. },
  12092. observeChanges: function() {
  12093. if('MutationObserver' in window) {
  12094. documentObserver = new MutationObserver(module.event.documentChanged);
  12095. documentObserver.observe(document, {
  12096. childList : true,
  12097. subtree : true
  12098. });
  12099. module.debug('Setting up mutation observer', documentObserver);
  12100. }
  12101. },
  12102. refresh: function() {
  12103. if(settings.popup) {
  12104. $popup = $(settings.popup).eq(0);
  12105. }
  12106. else {
  12107. if(settings.inline) {
  12108. $popup = $target.nextAll(selector.popup).eq(0);
  12109. settings.popup = $popup;
  12110. }
  12111. }
  12112. if(settings.popup) {
  12113. $popup.addClass(className.loading);
  12114. $offsetParent = module.get.offsetParent();
  12115. $popup.removeClass(className.loading);
  12116. if(settings.movePopup && module.has.popup() && module.get.offsetParent($popup)[0] !== $offsetParent[0]) {
  12117. module.debug('Moving popup to the same offset parent as target');
  12118. $popup
  12119. .detach()
  12120. .appendTo($offsetParent)
  12121. ;
  12122. }
  12123. }
  12124. else {
  12125. $offsetParent = (settings.inline)
  12126. ? module.get.offsetParent($target)
  12127. : module.has.popup()
  12128. ? module.get.offsetParent($popup)
  12129. : $body
  12130. ;
  12131. }
  12132. if( $offsetParent.is('html') && $offsetParent[0] !== $body[0] ) {
  12133. module.debug('Setting page as offset parent');
  12134. $offsetParent = $body;
  12135. }
  12136. if( module.get.variation() ) {
  12137. module.set.variation();
  12138. }
  12139. },
  12140. reposition: function() {
  12141. module.refresh();
  12142. module.set.position();
  12143. },
  12144. destroy: function() {
  12145. module.debug('Destroying previous module');
  12146. if(documentObserver) {
  12147. documentObserver.disconnect();
  12148. }
  12149. // remove element only if was created dynamically
  12150. if($popup && !settings.preserve) {
  12151. module.removePopup();
  12152. }
  12153. // clear all timeouts
  12154. clearTimeout(module.hideTimer);
  12155. clearTimeout(module.showTimer);
  12156. // remove events
  12157. module.unbind.close();
  12158. module.unbind.events();
  12159. $module
  12160. .removeData(moduleNamespace)
  12161. ;
  12162. },
  12163. event: {
  12164. start: function(event) {
  12165. var
  12166. delay = ($.isPlainObject(settings.delay))
  12167. ? settings.delay.show
  12168. : settings.delay
  12169. ;
  12170. clearTimeout(module.hideTimer);
  12171. if(!openedWithTouch || (openedWithTouch && settings.addTouchEvents) ) {
  12172. module.showTimer = setTimeout(module.show, delay);
  12173. }
  12174. },
  12175. end: function() {
  12176. var
  12177. delay = ($.isPlainObject(settings.delay))
  12178. ? settings.delay.hide
  12179. : settings.delay
  12180. ;
  12181. clearTimeout(module.showTimer);
  12182. module.hideTimer = setTimeout(module.hide, delay);
  12183. },
  12184. touchstart: function(event) {
  12185. openedWithTouch = true;
  12186. if(settings.addTouchEvents) {
  12187. module.show();
  12188. }
  12189. },
  12190. resize: function() {
  12191. if( module.is.visible() ) {
  12192. module.set.position();
  12193. }
  12194. },
  12195. documentChanged: function(mutations) {
  12196. [].forEach.call(mutations, function(mutation) {
  12197. if(mutation.removedNodes) {
  12198. [].forEach.call(mutation.removedNodes, function(node) {
  12199. if(node == element || $(node).find(element).length > 0) {
  12200. module.debug('Element removed from DOM, tearing down events');
  12201. module.destroy();
  12202. }
  12203. });
  12204. }
  12205. });
  12206. },
  12207. hideGracefully: function(event) {
  12208. var
  12209. $target = $(event.target),
  12210. isInDOM = $.contains(document.documentElement, event.target),
  12211. inPopup = ($target.closest(selector.popup).length > 0)
  12212. ;
  12213. // don't close on clicks inside popup
  12214. if(event && !inPopup && isInDOM) {
  12215. module.debug('Click occurred outside popup hiding popup');
  12216. module.hide();
  12217. }
  12218. else {
  12219. module.debug('Click was inside popup, keeping popup open');
  12220. }
  12221. }
  12222. },
  12223. // generates popup html from metadata
  12224. create: function() {
  12225. var
  12226. html = module.get.html(),
  12227. title = module.get.title(),
  12228. content = module.get.content()
  12229. ;
  12230. if(html || content || title) {
  12231. module.debug('Creating pop-up html');
  12232. if(!html) {
  12233. html = settings.templates.popup({
  12234. title : title,
  12235. content : content
  12236. });
  12237. }
  12238. $popup = $('<div/>')
  12239. .addClass(className.popup)
  12240. .data(metadata.activator, $module)
  12241. .html(html)
  12242. ;
  12243. if(settings.inline) {
  12244. module.verbose('Inserting popup element inline', $popup);
  12245. $popup
  12246. .insertAfter($module)
  12247. ;
  12248. }
  12249. else {
  12250. module.verbose('Appending popup element to body', $popup);
  12251. $popup
  12252. .appendTo( $context )
  12253. ;
  12254. }
  12255. module.refresh();
  12256. module.set.variation();
  12257. if(settings.hoverable) {
  12258. module.bind.popup();
  12259. }
  12260. settings.onCreate.call($popup, element);
  12261. }
  12262. else if($target.next(selector.popup).length !== 0) {
  12263. module.verbose('Pre-existing popup found');
  12264. settings.inline = true;
  12265. settings.popup = $target.next(selector.popup).data(metadata.activator, $module);
  12266. module.refresh();
  12267. if(settings.hoverable) {
  12268. module.bind.popup();
  12269. }
  12270. }
  12271. else if(settings.popup) {
  12272. $(settings.popup).data(metadata.activator, $module);
  12273. module.verbose('Used popup specified in settings');
  12274. module.refresh();
  12275. if(settings.hoverable) {
  12276. module.bind.popup();
  12277. }
  12278. }
  12279. else {
  12280. module.debug('No content specified skipping display', element);
  12281. }
  12282. },
  12283. createID: function() {
  12284. id = (Math.random().toString(16) + '000000000').substr(2, 8);
  12285. elementNamespace = '.' + id;
  12286. module.verbose('Creating unique id for element', id);
  12287. },
  12288. // determines popup state
  12289. toggle: function() {
  12290. module.debug('Toggling pop-up');
  12291. if( module.is.hidden() ) {
  12292. module.debug('Popup is hidden, showing pop-up');
  12293. module.unbind.close();
  12294. module.show();
  12295. }
  12296. else {
  12297. module.debug('Popup is visible, hiding pop-up');
  12298. module.hide();
  12299. }
  12300. },
  12301. show: function(callback) {
  12302. callback = callback || function(){};
  12303. module.debug('Showing pop-up', settings.transition);
  12304. if(module.is.hidden() && !( module.is.active() && module.is.dropdown()) ) {
  12305. if( !module.exists() ) {
  12306. module.create();
  12307. }
  12308. if(settings.onShow.call($popup, element) === false) {
  12309. module.debug('onShow callback returned false, cancelling popup animation');
  12310. return;
  12311. }
  12312. else if(!settings.preserve && !settings.popup) {
  12313. module.refresh();
  12314. }
  12315. if( $popup && module.set.position() ) {
  12316. module.save.conditions();
  12317. if(settings.exclusive) {
  12318. module.hideAll();
  12319. }
  12320. module.animate.show(callback);
  12321. }
  12322. }
  12323. },
  12324. hide: function(callback) {
  12325. callback = callback || function(){};
  12326. if( module.is.visible() || module.is.animating() ) {
  12327. if(settings.onHide.call($popup, element) === false) {
  12328. module.debug('onHide callback returned false, cancelling popup animation');
  12329. return;
  12330. }
  12331. module.remove.visible();
  12332. module.unbind.close();
  12333. module.restore.conditions();
  12334. module.animate.hide(callback);
  12335. }
  12336. },
  12337. hideAll: function() {
  12338. $(selector.popup)
  12339. .filter('.' + className.popupVisible)
  12340. .each(function() {
  12341. $(this)
  12342. .data(metadata.activator)
  12343. .popup('hide')
  12344. ;
  12345. })
  12346. ;
  12347. },
  12348. exists: function() {
  12349. if(!$popup) {
  12350. return false;
  12351. }
  12352. if(settings.inline || settings.popup) {
  12353. return ( module.has.popup() );
  12354. }
  12355. else {
  12356. return ( $popup.closest($context).length >= 1 )
  12357. ? true
  12358. : false
  12359. ;
  12360. }
  12361. },
  12362. removePopup: function() {
  12363. if( module.has.popup() && !settings.popup) {
  12364. module.debug('Removing popup', $popup);
  12365. $popup.remove();
  12366. $popup = undefined;
  12367. settings.onRemove.call($popup, element);
  12368. }
  12369. },
  12370. save: {
  12371. conditions: function() {
  12372. module.cache = {
  12373. title: $module.attr('title')
  12374. };
  12375. if (module.cache.title) {
  12376. $module.removeAttr('title');
  12377. }
  12378. module.verbose('Saving original attributes', module.cache.title);
  12379. }
  12380. },
  12381. restore: {
  12382. conditions: function() {
  12383. if(module.cache && module.cache.title) {
  12384. $module.attr('title', module.cache.title);
  12385. module.verbose('Restoring original attributes', module.cache.title);
  12386. }
  12387. return true;
  12388. }
  12389. },
  12390. supports: {
  12391. svg: function() {
  12392. return (typeof SVGGraphicsElement !== 'undefined');
  12393. }
  12394. },
  12395. animate: {
  12396. show: function(callback) {
  12397. callback = $.isFunction(callback) ? callback : function(){};
  12398. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  12399. module.set.visible();
  12400. $popup
  12401. .transition({
  12402. animation : settings.transition + ' in',
  12403. queue : false,
  12404. debug : settings.debug,
  12405. verbose : settings.verbose,
  12406. duration : settings.duration,
  12407. onComplete : function() {
  12408. module.bind.close();
  12409. callback.call($popup, element);
  12410. settings.onVisible.call($popup, element);
  12411. }
  12412. })
  12413. ;
  12414. }
  12415. else {
  12416. module.error(error.noTransition);
  12417. }
  12418. },
  12419. hide: function(callback) {
  12420. callback = $.isFunction(callback) ? callback : function(){};
  12421. module.debug('Hiding pop-up');
  12422. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  12423. $popup
  12424. .transition({
  12425. animation : settings.transition + ' out',
  12426. queue : false,
  12427. duration : settings.duration,
  12428. debug : settings.debug,
  12429. verbose : settings.verbose,
  12430. onComplete : function() {
  12431. module.reset();
  12432. callback.call($popup, element);
  12433. settings.onHidden.call($popup, element);
  12434. }
  12435. })
  12436. ;
  12437. }
  12438. else {
  12439. module.error(error.noTransition);
  12440. }
  12441. }
  12442. },
  12443. change: {
  12444. content: function(html) {
  12445. $popup.html(html);
  12446. }
  12447. },
  12448. get: {
  12449. html: function() {
  12450. $module.removeData(metadata.html);
  12451. return $module.data(metadata.html) || settings.html;
  12452. },
  12453. title: function() {
  12454. $module.removeData(metadata.title);
  12455. return $module.data(metadata.title) || settings.title;
  12456. },
  12457. content: function() {
  12458. $module.removeData(metadata.content);
  12459. return $module.data(metadata.content) || settings.content || $module.attr('title');
  12460. },
  12461. variation: function() {
  12462. $module.removeData(metadata.variation);
  12463. return $module.data(metadata.variation) || settings.variation;
  12464. },
  12465. popup: function() {
  12466. return $popup;
  12467. },
  12468. popupOffset: function() {
  12469. return $popup.offset();
  12470. },
  12471. calculations: function() {
  12472. var
  12473. $popupOffsetParent = module.get.offsetParent($popup),
  12474. targetElement = $target[0],
  12475. isWindow = ($boundary[0] == window),
  12476. targetPosition = (settings.inline || (settings.popup && settings.movePopup))
  12477. ? $target.position()
  12478. : $target.offset(),
  12479. screenPosition = (isWindow)
  12480. ? { top: 0, left: 0 }
  12481. : $boundary.offset(),
  12482. calculations = {},
  12483. scroll = (isWindow)
  12484. ? { top: $window.scrollTop(), left: $window.scrollLeft() }
  12485. : { top: 0, left: 0},
  12486. screen
  12487. ;
  12488. calculations = {
  12489. // element which is launching popup
  12490. target : {
  12491. element : $target[0],
  12492. width : $target.outerWidth(),
  12493. height : $target.outerHeight(),
  12494. top : targetPosition.top,
  12495. left : targetPosition.left,
  12496. margin : {}
  12497. },
  12498. // popup itself
  12499. popup : {
  12500. width : $popup.outerWidth(),
  12501. height : $popup.outerHeight()
  12502. },
  12503. // offset container (or 3d context)
  12504. parent : {
  12505. width : $offsetParent.outerWidth(),
  12506. height : $offsetParent.outerHeight()
  12507. },
  12508. // screen boundaries
  12509. screen : {
  12510. top : screenPosition.top,
  12511. left : screenPosition.left,
  12512. scroll: {
  12513. top : scroll.top,
  12514. left : scroll.left
  12515. },
  12516. width : $boundary.width(),
  12517. height : $boundary.height()
  12518. }
  12519. };
  12520. // if popup offset context is not same as target, then adjust calculations
  12521. if($popupOffsetParent.get(0) !== $offsetParent.get(0)) {
  12522. var
  12523. popupOffset = $popupOffsetParent.offset()
  12524. ;
  12525. calculations.target.top -= popupOffset.top;
  12526. calculations.target.left -= popupOffset.left;
  12527. calculations.parent.width = $popupOffsetParent.outerWidth();
  12528. calculations.parent.height = $popupOffsetParent.outerHeight();
  12529. }
  12530. // add in container calcs if fluid
  12531. if( settings.setFluidWidth && module.is.fluid() ) {
  12532. calculations.container = {
  12533. width: $popup.parent().outerWidth()
  12534. };
  12535. calculations.popup.width = calculations.container.width;
  12536. }
  12537. // add in margins if inline
  12538. calculations.target.margin.top = (settings.inline)
  12539. ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10)
  12540. : 0
  12541. ;
  12542. calculations.target.margin.left = (settings.inline)
  12543. ? module.is.rtl()
  12544. ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10)
  12545. : parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left'), 10)
  12546. : 0
  12547. ;
  12548. // calculate screen boundaries
  12549. screen = calculations.screen;
  12550. calculations.boundary = {
  12551. top : screen.top + screen.scroll.top,
  12552. bottom : screen.top + screen.scroll.top + screen.height,
  12553. left : screen.left + screen.scroll.left,
  12554. right : screen.left + screen.scroll.left + screen.width
  12555. };
  12556. return calculations;
  12557. },
  12558. id: function() {
  12559. return id;
  12560. },
  12561. startEvent: function() {
  12562. if(settings.on == 'hover') {
  12563. return 'mouseenter';
  12564. }
  12565. else if(settings.on == 'focus') {
  12566. return 'focus';
  12567. }
  12568. return false;
  12569. },
  12570. scrollEvent: function() {
  12571. return 'scroll';
  12572. },
  12573. endEvent: function() {
  12574. if(settings.on == 'hover') {
  12575. return 'mouseleave';
  12576. }
  12577. else if(settings.on == 'focus') {
  12578. return 'blur';
  12579. }
  12580. return false;
  12581. },
  12582. distanceFromBoundary: function(offset, calculations) {
  12583. var
  12584. distanceFromBoundary = {},
  12585. popup,
  12586. boundary
  12587. ;
  12588. calculations = calculations || module.get.calculations();
  12589. // shorthand
  12590. popup = calculations.popup;
  12591. boundary = calculations.boundary;
  12592. if(offset) {
  12593. distanceFromBoundary = {
  12594. top : (offset.top - boundary.top),
  12595. left : (offset.left - boundary.left),
  12596. right : (boundary.right - (offset.left + popup.width) ),
  12597. bottom : (boundary.bottom - (offset.top + popup.height) )
  12598. };
  12599. module.verbose('Distance from boundaries determined', offset, distanceFromBoundary);
  12600. }
  12601. return distanceFromBoundary;
  12602. },
  12603. offsetParent: function($element) {
  12604. var
  12605. element = ($element !== undefined)
  12606. ? $element[0]
  12607. : $target[0],
  12608. parentNode = element.parentNode,
  12609. $node = $(parentNode)
  12610. ;
  12611. if(parentNode) {
  12612. var
  12613. is2D = ($node.css('transform') === 'none'),
  12614. isStatic = ($node.css('position') === 'static'),
  12615. isBody = $node.is('body')
  12616. ;
  12617. while(parentNode && !isBody && isStatic && is2D) {
  12618. parentNode = parentNode.parentNode;
  12619. $node = $(parentNode);
  12620. is2D = ($node.css('transform') === 'none');
  12621. isStatic = ($node.css('position') === 'static');
  12622. isBody = $node.is('body');
  12623. }
  12624. }
  12625. return ($node && $node.length > 0)
  12626. ? $node
  12627. : $()
  12628. ;
  12629. },
  12630. positions: function() {
  12631. return {
  12632. 'top left' : false,
  12633. 'top center' : false,
  12634. 'top right' : false,
  12635. 'bottom left' : false,
  12636. 'bottom center' : false,
  12637. 'bottom right' : false,
  12638. 'left center' : false,
  12639. 'right center' : false
  12640. };
  12641. },
  12642. nextPosition: function(position) {
  12643. var
  12644. positions = position.split(' '),
  12645. verticalPosition = positions[0],
  12646. horizontalPosition = positions[1],
  12647. opposite = {
  12648. top : 'bottom',
  12649. bottom : 'top',
  12650. left : 'right',
  12651. right : 'left'
  12652. },
  12653. adjacent = {
  12654. left : 'center',
  12655. center : 'right',
  12656. right : 'left'
  12657. },
  12658. backup = {
  12659. 'top left' : 'top center',
  12660. 'top center' : 'top right',
  12661. 'top right' : 'right center',
  12662. 'right center' : 'bottom right',
  12663. 'bottom right' : 'bottom center',
  12664. 'bottom center' : 'bottom left',
  12665. 'bottom left' : 'left center',
  12666. 'left center' : 'top left'
  12667. },
  12668. adjacentsAvailable = (verticalPosition == 'top' || verticalPosition == 'bottom'),
  12669. oppositeTried = false,
  12670. adjacentTried = false,
  12671. nextPosition = false
  12672. ;
  12673. if(!triedPositions) {
  12674. module.verbose('All available positions available');
  12675. triedPositions = module.get.positions();
  12676. }
  12677. module.debug('Recording last position tried', position);
  12678. triedPositions[position] = true;
  12679. if(settings.prefer === 'opposite') {
  12680. nextPosition = [opposite[verticalPosition], horizontalPosition];
  12681. nextPosition = nextPosition.join(' ');
  12682. oppositeTried = (triedPositions[nextPosition] === true);
  12683. module.debug('Trying opposite strategy', nextPosition);
  12684. }
  12685. if((settings.prefer === 'adjacent') && adjacentsAvailable ) {
  12686. nextPosition = [verticalPosition, adjacent[horizontalPosition]];
  12687. nextPosition = nextPosition.join(' ');
  12688. adjacentTried = (triedPositions[nextPosition] === true);
  12689. module.debug('Trying adjacent strategy', nextPosition);
  12690. }
  12691. if(adjacentTried || oppositeTried) {
  12692. module.debug('Using backup position', nextPosition);
  12693. nextPosition = backup[position];
  12694. }
  12695. return nextPosition;
  12696. }
  12697. },
  12698. set: {
  12699. position: function(position, calculations) {
  12700. // exit conditions
  12701. if($target.length === 0 || $popup.length === 0) {
  12702. module.error(error.notFound);
  12703. return;
  12704. }
  12705. var
  12706. offset,
  12707. distanceAway,
  12708. target,
  12709. popup,
  12710. parent,
  12711. positioning,
  12712. popupOffset,
  12713. distanceFromBoundary
  12714. ;
  12715. calculations = calculations || module.get.calculations();
  12716. position = position || $module.data(metadata.position) || settings.position;
  12717. offset = $module.data(metadata.offset) || settings.offset;
  12718. distanceAway = settings.distanceAway;
  12719. // shorthand
  12720. target = calculations.target;
  12721. popup = calculations.popup;
  12722. parent = calculations.parent;
  12723. if(module.should.centerArrow(calculations)) {
  12724. module.verbose('Adjusting offset to center arrow on small target element');
  12725. if(position == 'top left' || position == 'bottom left') {
  12726. offset += (target.width / 2);
  12727. offset -= settings.arrowPixelsFromEdge;
  12728. }
  12729. if(position == 'top right' || position == 'bottom right') {
  12730. offset -= (target.width / 2);
  12731. offset += settings.arrowPixelsFromEdge;
  12732. }
  12733. }
  12734. if(target.width === 0 && target.height === 0 && !module.is.svg(target.element)) {
  12735. module.debug('Popup target is hidden, no action taken');
  12736. return false;
  12737. }
  12738. if(settings.inline) {
  12739. module.debug('Adding margin to calculation', target.margin);
  12740. if(position == 'left center' || position == 'right center') {
  12741. offset += target.margin.top;
  12742. distanceAway += -target.margin.left;
  12743. }
  12744. else if (position == 'top left' || position == 'top center' || position == 'top right') {
  12745. offset += target.margin.left;
  12746. distanceAway -= target.margin.top;
  12747. }
  12748. else {
  12749. offset += target.margin.left;
  12750. distanceAway += target.margin.top;
  12751. }
  12752. }
  12753. module.debug('Determining popup position from calculations', position, calculations);
  12754. if (module.is.rtl()) {
  12755. position = position.replace(/left|right/g, function (match) {
  12756. return (match == 'left')
  12757. ? 'right'
  12758. : 'left'
  12759. ;
  12760. });
  12761. module.debug('RTL: Popup position updated', position);
  12762. }
  12763. // if last attempt use specified last resort position
  12764. if(searchDepth == settings.maxSearchDepth && typeof settings.lastResort === 'string') {
  12765. position = settings.lastResort;
  12766. }
  12767. switch (position) {
  12768. case 'top left':
  12769. positioning = {
  12770. top : 'auto',
  12771. bottom : parent.height - target.top + distanceAway,
  12772. left : target.left + offset,
  12773. right : 'auto'
  12774. };
  12775. break;
  12776. case 'top center':
  12777. positioning = {
  12778. bottom : parent.height - target.top + distanceAway,
  12779. left : target.left + (target.width / 2) - (popup.width / 2) + offset,
  12780. top : 'auto',
  12781. right : 'auto'
  12782. };
  12783. break;
  12784. case 'top right':
  12785. positioning = {
  12786. bottom : parent.height - target.top + distanceAway,
  12787. right : parent.width - target.left - target.width - offset,
  12788. top : 'auto',
  12789. left : 'auto'
  12790. };
  12791. break;
  12792. case 'left center':
  12793. positioning = {
  12794. top : target.top + (target.height / 2) - (popup.height / 2) + offset,
  12795. right : parent.width - target.left + distanceAway,
  12796. left : 'auto',
  12797. bottom : 'auto'
  12798. };
  12799. break;
  12800. case 'right center':
  12801. positioning = {
  12802. top : target.top + (target.height / 2) - (popup.height / 2) + offset,
  12803. left : target.left + target.width + distanceAway,
  12804. bottom : 'auto',
  12805. right : 'auto'
  12806. };
  12807. break;
  12808. case 'bottom left':
  12809. positioning = {
  12810. top : target.top + target.height + distanceAway,
  12811. left : target.left + offset,
  12812. bottom : 'auto',
  12813. right : 'auto'
  12814. };
  12815. break;
  12816. case 'bottom center':
  12817. positioning = {
  12818. top : target.top + target.height + distanceAway,
  12819. left : target.left + (target.width / 2) - (popup.width / 2) + offset,
  12820. bottom : 'auto',
  12821. right : 'auto'
  12822. };
  12823. break;
  12824. case 'bottom right':
  12825. positioning = {
  12826. top : target.top + target.height + distanceAway,
  12827. right : parent.width - target.left - target.width - offset,
  12828. left : 'auto',
  12829. bottom : 'auto'
  12830. };
  12831. break;
  12832. }
  12833. if(positioning === undefined) {
  12834. module.error(error.invalidPosition, position);
  12835. }
  12836. module.debug('Calculated popup positioning values', positioning);
  12837. // tentatively place on stage
  12838. $popup
  12839. .css(positioning)
  12840. .removeClass(className.position)
  12841. .addClass(position)
  12842. .addClass(className.loading)
  12843. ;
  12844. popupOffset = module.get.popupOffset();
  12845. // see if any boundaries are surpassed with this tentative position
  12846. distanceFromBoundary = module.get.distanceFromBoundary(popupOffset, calculations);
  12847. if(!settings.forcePosition && module.is.offstage(distanceFromBoundary, position) ) {
  12848. module.debug('Position is outside viewport', position);
  12849. if(searchDepth < settings.maxSearchDepth) {
  12850. searchDepth++;
  12851. position = module.get.nextPosition(position);
  12852. module.debug('Trying new position', position);
  12853. return ($popup)
  12854. ? module.set.position(position, calculations)
  12855. : false
  12856. ;
  12857. }
  12858. else {
  12859. if(settings.lastResort) {
  12860. module.debug('No position found, showing with last position');
  12861. }
  12862. else {
  12863. module.debug('Popup could not find a position to display', $popup);
  12864. module.error(error.cannotPlace, element);
  12865. module.remove.attempts();
  12866. module.remove.loading();
  12867. module.reset();
  12868. settings.onUnplaceable.call($popup, element);
  12869. return false;
  12870. }
  12871. }
  12872. }
  12873. module.debug('Position is on stage', position);
  12874. module.remove.attempts();
  12875. module.remove.loading();
  12876. if( settings.setFluidWidth && module.is.fluid() ) {
  12877. module.set.fluidWidth(calculations);
  12878. }
  12879. return true;
  12880. },
  12881. fluidWidth: function(calculations) {
  12882. calculations = calculations || module.get.calculations();
  12883. module.debug('Automatically setting element width to parent width', calculations.parent.width);
  12884. $popup.css('width', calculations.container.width);
  12885. },
  12886. variation: function(variation) {
  12887. variation = variation || module.get.variation();
  12888. if(variation && module.has.popup() ) {
  12889. module.verbose('Adding variation to popup', variation);
  12890. $popup.addClass(variation);
  12891. }
  12892. },
  12893. visible: function() {
  12894. $module.addClass(className.visible);
  12895. }
  12896. },
  12897. remove: {
  12898. loading: function() {
  12899. $popup.removeClass(className.loading);
  12900. },
  12901. variation: function(variation) {
  12902. variation = variation || module.get.variation();
  12903. if(variation) {
  12904. module.verbose('Removing variation', variation);
  12905. $popup.removeClass(variation);
  12906. }
  12907. },
  12908. visible: function() {
  12909. $module.removeClass(className.visible);
  12910. },
  12911. attempts: function() {
  12912. module.verbose('Resetting all searched positions');
  12913. searchDepth = 0;
  12914. triedPositions = false;
  12915. }
  12916. },
  12917. bind: {
  12918. events: function() {
  12919. module.debug('Binding popup events to module');
  12920. if(settings.on == 'click') {
  12921. $module
  12922. .on(clickEvent + eventNamespace, module.toggle)
  12923. ;
  12924. }
  12925. if(settings.on == 'hover') {
  12926. $module
  12927. .on('touchstart' + eventNamespace, module.event.touchstart)
  12928. ;
  12929. }
  12930. if( module.get.startEvent() ) {
  12931. $module
  12932. .on(module.get.startEvent() + eventNamespace, module.event.start)
  12933. .on(module.get.endEvent() + eventNamespace, module.event.end)
  12934. ;
  12935. }
  12936. if(settings.target) {
  12937. module.debug('Target set to element', $target);
  12938. }
  12939. $window.on('resize' + elementNamespace, module.event.resize);
  12940. },
  12941. popup: function() {
  12942. module.verbose('Allowing hover events on popup to prevent closing');
  12943. if( $popup && module.has.popup() ) {
  12944. $popup
  12945. .on('mouseenter' + eventNamespace, module.event.start)
  12946. .on('mouseleave' + eventNamespace, module.event.end)
  12947. ;
  12948. }
  12949. },
  12950. close: function() {
  12951. if(settings.hideOnScroll === true || (settings.hideOnScroll == 'auto' && settings.on != 'click')) {
  12952. module.bind.closeOnScroll();
  12953. }
  12954. if(module.is.closable()) {
  12955. module.bind.clickaway();
  12956. }
  12957. else if(settings.on == 'hover' && openedWithTouch) {
  12958. module.bind.touchClose();
  12959. }
  12960. },
  12961. closeOnScroll: function() {
  12962. module.verbose('Binding scroll close event to document');
  12963. $scrollContext
  12964. .one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully)
  12965. ;
  12966. },
  12967. touchClose: function() {
  12968. module.verbose('Binding popup touchclose event to document');
  12969. $document
  12970. .on('touchstart' + elementNamespace, function(event) {
  12971. module.verbose('Touched away from popup');
  12972. module.event.hideGracefully.call(element, event);
  12973. })
  12974. ;
  12975. },
  12976. clickaway: function() {
  12977. module.verbose('Binding popup close event to document');
  12978. $document
  12979. .on(clickEvent + elementNamespace, function(event) {
  12980. module.verbose('Clicked away from popup');
  12981. module.event.hideGracefully.call(element, event);
  12982. })
  12983. ;
  12984. }
  12985. },
  12986. unbind: {
  12987. events: function() {
  12988. $window
  12989. .off(elementNamespace)
  12990. ;
  12991. $module
  12992. .off(eventNamespace)
  12993. ;
  12994. },
  12995. close: function() {
  12996. $document
  12997. .off(elementNamespace)
  12998. ;
  12999. $scrollContext
  13000. .off(elementNamespace)
  13001. ;
  13002. },
  13003. },
  13004. has: {
  13005. popup: function() {
  13006. return ($popup && $popup.length > 0);
  13007. }
  13008. },
  13009. should: {
  13010. centerArrow: function(calculations) {
  13011. return !module.is.basic() && calculations.target.width <= (settings.arrowPixelsFromEdge * 2);
  13012. },
  13013. },
  13014. is: {
  13015. closable: function() {
  13016. if(settings.closable == 'auto') {
  13017. if(settings.on == 'hover') {
  13018. return false;
  13019. }
  13020. return true;
  13021. }
  13022. return settings.closable;
  13023. },
  13024. offstage: function(distanceFromBoundary, position) {
  13025. var
  13026. offstage = []
  13027. ;
  13028. // return boundaries that have been surpassed
  13029. $.each(distanceFromBoundary, function(direction, distance) {
  13030. if(distance < -settings.jitter) {
  13031. module.debug('Position exceeds allowable distance from edge', direction, distance, position);
  13032. offstage.push(direction);
  13033. }
  13034. });
  13035. if(offstage.length > 0) {
  13036. return true;
  13037. }
  13038. else {
  13039. return false;
  13040. }
  13041. },
  13042. svg: function(element) {
  13043. return module.supports.svg() && (element instanceof SVGGraphicsElement);
  13044. },
  13045. basic: function() {
  13046. return $module.hasClass(className.basic);
  13047. },
  13048. active: function() {
  13049. return $module.hasClass(className.active);
  13050. },
  13051. animating: function() {
  13052. return ($popup !== undefined && $popup.hasClass(className.animating) );
  13053. },
  13054. fluid: function() {
  13055. return ($popup !== undefined && $popup.hasClass(className.fluid));
  13056. },
  13057. visible: function() {
  13058. return ($popup !== undefined && $popup.hasClass(className.popupVisible));
  13059. },
  13060. dropdown: function() {
  13061. return $module.hasClass(className.dropdown);
  13062. },
  13063. hidden: function() {
  13064. return !module.is.visible();
  13065. },
  13066. rtl: function () {
  13067. return $module.css('direction') == 'rtl';
  13068. }
  13069. },
  13070. reset: function() {
  13071. module.remove.visible();
  13072. if(settings.preserve) {
  13073. if($.fn.transition !== undefined) {
  13074. $popup
  13075. .transition('remove transition')
  13076. ;
  13077. }
  13078. }
  13079. else {
  13080. module.removePopup();
  13081. }
  13082. },
  13083. setting: function(name, value) {
  13084. if( $.isPlainObject(name) ) {
  13085. $.extend(true, settings, name);
  13086. }
  13087. else if(value !== undefined) {
  13088. settings[name] = value;
  13089. }
  13090. else {
  13091. return settings[name];
  13092. }
  13093. },
  13094. internal: function(name, value) {
  13095. if( $.isPlainObject(name) ) {
  13096. $.extend(true, module, name);
  13097. }
  13098. else if(value !== undefined) {
  13099. module[name] = value;
  13100. }
  13101. else {
  13102. return module[name];
  13103. }
  13104. },
  13105. debug: function() {
  13106. if(!settings.silent && settings.debug) {
  13107. if(settings.performance) {
  13108. module.performance.log(arguments);
  13109. }
  13110. else {
  13111. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  13112. module.debug.apply(console, arguments);
  13113. }
  13114. }
  13115. },
  13116. verbose: function() {
  13117. if(!settings.silent && settings.verbose && settings.debug) {
  13118. if(settings.performance) {
  13119. module.performance.log(arguments);
  13120. }
  13121. else {
  13122. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  13123. module.verbose.apply(console, arguments);
  13124. }
  13125. }
  13126. },
  13127. error: function() {
  13128. if(!settings.silent) {
  13129. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  13130. module.error.apply(console, arguments);
  13131. }
  13132. },
  13133. performance: {
  13134. log: function(message) {
  13135. var
  13136. currentTime,
  13137. executionTime,
  13138. previousTime
  13139. ;
  13140. if(settings.performance) {
  13141. currentTime = new Date().getTime();
  13142. previousTime = time || currentTime;
  13143. executionTime = currentTime - previousTime;
  13144. time = currentTime;
  13145. performance.push({
  13146. 'Name' : message[0],
  13147. 'Arguments' : [].slice.call(message, 1) || '',
  13148. 'Element' : element,
  13149. 'Execution Time' : executionTime
  13150. });
  13151. }
  13152. clearTimeout(module.performance.timer);
  13153. module.performance.timer = setTimeout(module.performance.display, 500);
  13154. },
  13155. display: function() {
  13156. var
  13157. title = settings.name + ':',
  13158. totalTime = 0
  13159. ;
  13160. time = false;
  13161. clearTimeout(module.performance.timer);
  13162. $.each(performance, function(index, data) {
  13163. totalTime += data['Execution Time'];
  13164. });
  13165. title += ' ' + totalTime + 'ms';
  13166. if(moduleSelector) {
  13167. title += ' \'' + moduleSelector + '\'';
  13168. }
  13169. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  13170. console.groupCollapsed(title);
  13171. if(console.table) {
  13172. console.table(performance);
  13173. }
  13174. else {
  13175. $.each(performance, function(index, data) {
  13176. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  13177. });
  13178. }
  13179. console.groupEnd();
  13180. }
  13181. performance = [];
  13182. }
  13183. },
  13184. invoke: function(query, passedArguments, context) {
  13185. var
  13186. object = instance,
  13187. maxDepth,
  13188. found,
  13189. response
  13190. ;
  13191. passedArguments = passedArguments || queryArguments;
  13192. context = element || context;
  13193. if(typeof query == 'string' && object !== undefined) {
  13194. query = query.split(/[\. ]/);
  13195. maxDepth = query.length - 1;
  13196. $.each(query, function(depth, value) {
  13197. var camelCaseValue = (depth != maxDepth)
  13198. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  13199. : query
  13200. ;
  13201. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  13202. object = object[camelCaseValue];
  13203. }
  13204. else if( object[camelCaseValue] !== undefined ) {
  13205. found = object[camelCaseValue];
  13206. return false;
  13207. }
  13208. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  13209. object = object[value];
  13210. }
  13211. else if( object[value] !== undefined ) {
  13212. found = object[value];
  13213. return false;
  13214. }
  13215. else {
  13216. return false;
  13217. }
  13218. });
  13219. }
  13220. if ( $.isFunction( found ) ) {
  13221. response = found.apply(context, passedArguments);
  13222. }
  13223. else if(found !== undefined) {
  13224. response = found;
  13225. }
  13226. if(Array.isArray(returnedValue)) {
  13227. returnedValue.push(response);
  13228. }
  13229. else if(returnedValue !== undefined) {
  13230. returnedValue = [returnedValue, response];
  13231. }
  13232. else if(response !== undefined) {
  13233. returnedValue = response;
  13234. }
  13235. return found;
  13236. }
  13237. };
  13238. if(methodInvoked) {
  13239. if(instance === undefined) {
  13240. module.initialize();
  13241. }
  13242. module.invoke(query);
  13243. }
  13244. else {
  13245. if(instance !== undefined) {
  13246. instance.invoke('destroy');
  13247. }
  13248. module.initialize();
  13249. }
  13250. })
  13251. ;
  13252. return (returnedValue !== undefined)
  13253. ? returnedValue
  13254. : this
  13255. ;
  13256. };
  13257. $.fn.popup.settings = {
  13258. name : 'Popup',
  13259. // module settings
  13260. silent : false,
  13261. debug : false,
  13262. verbose : false,
  13263. performance : true,
  13264. namespace : 'popup',
  13265. // whether it should use dom mutation observers
  13266. observeChanges : true,
  13267. // callback only when element added to dom
  13268. onCreate : function(){},
  13269. // callback before element removed from dom
  13270. onRemove : function(){},
  13271. // callback before show animation
  13272. onShow : function(){},
  13273. // callback after show animation
  13274. onVisible : function(){},
  13275. // callback before hide animation
  13276. onHide : function(){},
  13277. // callback when popup cannot be positioned in visible screen
  13278. onUnplaceable : function(){},
  13279. // callback after hide animation
  13280. onHidden : function(){},
  13281. // when to show popup
  13282. on : 'hover',
  13283. // element to use to determine if popup is out of boundary
  13284. boundary : window,
  13285. // whether to add touchstart events when using hover
  13286. addTouchEvents : true,
  13287. // default position relative to element
  13288. position : 'top left',
  13289. // if given position should be used regardless if popup fits
  13290. forcePosition : false,
  13291. // name of variation to use
  13292. variation : '',
  13293. // whether popup should be moved to context
  13294. movePopup : true,
  13295. // element which popup should be relative to
  13296. target : false,
  13297. // jq selector or element that should be used as popup
  13298. popup : false,
  13299. // popup should remain inline next to activator
  13300. inline : false,
  13301. // popup should be removed from page on hide
  13302. preserve : false,
  13303. // popup should not close when being hovered on
  13304. hoverable : false,
  13305. // explicitly set content
  13306. content : false,
  13307. // explicitly set html
  13308. html : false,
  13309. // explicitly set title
  13310. title : false,
  13311. // whether automatically close on clickaway when on click
  13312. closable : true,
  13313. // automatically hide on scroll
  13314. hideOnScroll : 'auto',
  13315. // hide other popups on show
  13316. exclusive : false,
  13317. // context to attach popups
  13318. context : 'body',
  13319. // context for binding scroll events
  13320. scrollContext : window,
  13321. // position to prefer when calculating new position
  13322. prefer : 'opposite',
  13323. // specify position to appear even if it doesn't fit
  13324. lastResort : false,
  13325. // number of pixels from edge of popup to pointing arrow center (used from centering)
  13326. arrowPixelsFromEdge: 20,
  13327. // delay used to prevent accidental refiring of animations due to user error
  13328. delay : {
  13329. show : 50,
  13330. hide : 70
  13331. },
  13332. // whether fluid variation should assign width explicitly
  13333. setFluidWidth : true,
  13334. // transition settings
  13335. duration : 200,
  13336. transition : 'scale',
  13337. // distance away from activating element in px
  13338. distanceAway : 0,
  13339. // number of pixels an element is allowed to be "offstage" for a position to be chosen (allows for rounding)
  13340. jitter : 2,
  13341. // offset on aligning axis from calculated position
  13342. offset : 0,
  13343. // maximum times to look for a position before failing (9 positions total)
  13344. maxSearchDepth : 15,
  13345. error: {
  13346. invalidPosition : 'The position you specified is not a valid position',
  13347. cannotPlace : 'Popup does not fit within the boundaries of the viewport',
  13348. method : 'The method you called is not defined.',
  13349. noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>',
  13350. notFound : 'The target or popup you specified does not exist on the page'
  13351. },
  13352. metadata: {
  13353. activator : 'activator',
  13354. content : 'content',
  13355. html : 'html',
  13356. offset : 'offset',
  13357. position : 'position',
  13358. title : 'title',
  13359. variation : 'variation'
  13360. },
  13361. className : {
  13362. active : 'active',
  13363. basic : 'basic',
  13364. animating : 'animating',
  13365. dropdown : 'dropdown',
  13366. fluid : 'fluid',
  13367. loading : 'loading',
  13368. popup : 'ui popup',
  13369. position : 'top left center bottom right',
  13370. visible : 'visible',
  13371. popupVisible : 'visible'
  13372. },
  13373. selector : {
  13374. popup : '.ui.popup'
  13375. },
  13376. templates: {
  13377. escape: function(string) {
  13378. var
  13379. badChars = /[&<>"'`]/g,
  13380. shouldEscape = /[&<>"'`]/,
  13381. escape = {
  13382. "&": "&amp;",
  13383. "<": "&lt;",
  13384. ">": "&gt;",
  13385. '"': "&quot;",
  13386. "'": "&#x27;",
  13387. "`": "&#x60;"
  13388. },
  13389. escapedChar = function(chr) {
  13390. return escape[chr];
  13391. }
  13392. ;
  13393. if(shouldEscape.test(string)) {
  13394. return string.replace(badChars, escapedChar);
  13395. }
  13396. return string;
  13397. },
  13398. popup: function(text) {
  13399. var
  13400. html = '',
  13401. escape = $.fn.popup.settings.templates.escape
  13402. ;
  13403. if(typeof text !== undefined) {
  13404. if(typeof text.title !== undefined && text.title) {
  13405. text.title = escape(text.title);
  13406. html += '<div class="header">' + text.title + '</div>';
  13407. }
  13408. if(typeof text.content !== undefined && text.content) {
  13409. text.content = escape(text.content);
  13410. html += '<div class="content">' + text.content + '</div>';
  13411. }
  13412. }
  13413. return html;
  13414. }
  13415. }
  13416. };
  13417. })( jQuery, window, document );
  13418. /*!
  13419. * # Fomantic-UI - Progress
  13420. * http://github.com/fomantic/Fomantic-UI/
  13421. *
  13422. *
  13423. * Released under the MIT license
  13424. * http://opensource.org/licenses/MIT
  13425. *
  13426. */
  13427. ;(function ($, window, document, undefined) {
  13428. 'use strict';
  13429. $.isFunction = $.isFunction || function(obj) {
  13430. return typeof obj === "function" && typeof obj.nodeType !== "number";
  13431. };
  13432. window = (typeof window != 'undefined' && window.Math == Math)
  13433. ? window
  13434. : (typeof self != 'undefined' && self.Math == Math)
  13435. ? self
  13436. : Function('return this')()
  13437. ;
  13438. $.fn.progress = function(parameters) {
  13439. var
  13440. $allModules = $(this),
  13441. moduleSelector = $allModules.selector || '',
  13442. time = new Date().getTime(),
  13443. performance = [],
  13444. query = arguments[0],
  13445. methodInvoked = (typeof query == 'string'),
  13446. queryArguments = [].slice.call(arguments, 1),
  13447. returnedValue
  13448. ;
  13449. $allModules
  13450. .each(function() {
  13451. var
  13452. settings = ( $.isPlainObject(parameters) )
  13453. ? $.extend(true, {}, $.fn.progress.settings, parameters)
  13454. : $.extend({}, $.fn.progress.settings),
  13455. className = settings.className,
  13456. metadata = settings.metadata,
  13457. namespace = settings.namespace,
  13458. selector = settings.selector,
  13459. error = settings.error,
  13460. eventNamespace = '.' + namespace,
  13461. moduleNamespace = 'module-' + namespace,
  13462. $module = $(this),
  13463. $bars = $(this).find(selector.bar),
  13464. $progresses = $(this).find(selector.progress),
  13465. $label = $(this).find(selector.label),
  13466. element = this,
  13467. instance = $module.data(moduleNamespace),
  13468. animating = false,
  13469. transitionEnd,
  13470. module
  13471. ;
  13472. module = {
  13473. helper: {
  13474. sum: function (nums) {
  13475. return Array.isArray(nums) ? nums.reduce(function (left, right) {
  13476. return left + Number(right);
  13477. }, 0) : 0;
  13478. },
  13479. /**
  13480. * Derive precision for multiple progress with total and values.
  13481. *
  13482. * This helper dervices a precision that is sufficiently large to show minimum value of multiple progress.
  13483. *
  13484. * Example1
  13485. * - total: 1122
  13486. * - values: [325, 111, 74, 612]
  13487. * - min ratio: 74/1122 = 0.0659...
  13488. * - required precision: 100
  13489. *
  13490. * Example2
  13491. * - total: 10541
  13492. * - values: [3235, 1111, 74, 6121]
  13493. * - min ratio: 74/10541 = 0.0070...
  13494. * - required precision: 1000
  13495. *
  13496. * @param min A minimum value within multiple values
  13497. * @param total A total amount of multiple values
  13498. * @returns {number} A precison. Could be 1, 10, 100, ... 1e+10.
  13499. */
  13500. derivePrecision: function(min, total) {
  13501. var precisionPower = 0
  13502. var precision = 1;
  13503. var ratio = min / total;
  13504. while (precisionPower < 10) {
  13505. ratio = ratio * precision;
  13506. if (ratio > 1) {
  13507. break;
  13508. }
  13509. precision = Math.pow(10, precisionPower++);
  13510. }
  13511. return precision;
  13512. },
  13513. forceArray: function (element) {
  13514. return Array.isArray(element)
  13515. ? element
  13516. : !isNaN(element)
  13517. ? [element]
  13518. : typeof element == 'string'
  13519. ? element.split(',')
  13520. : []
  13521. ;
  13522. }
  13523. },
  13524. initialize: function() {
  13525. module.set.duration();
  13526. module.set.transitionEvent();
  13527. module.debug(element);
  13528. module.read.metadata();
  13529. module.read.settings();
  13530. module.instantiate();
  13531. },
  13532. instantiate: function() {
  13533. module.verbose('Storing instance of progress', module);
  13534. instance = module;
  13535. $module
  13536. .data(moduleNamespace, module)
  13537. ;
  13538. },
  13539. destroy: function() {
  13540. module.verbose('Destroying previous progress for', $module);
  13541. clearInterval(instance.interval);
  13542. module.remove.state();
  13543. $module.removeData(moduleNamespace);
  13544. instance = undefined;
  13545. },
  13546. reset: function() {
  13547. module.remove.nextValue();
  13548. module.update.progress(0);
  13549. },
  13550. complete: function() {
  13551. if(module.percent === undefined || module.percent < 100) {
  13552. module.remove.progressPoll();
  13553. module.set.percent(100);
  13554. }
  13555. },
  13556. read: {
  13557. metadata: function() {
  13558. var
  13559. data = {
  13560. percent : module.helper.forceArray($module.data(metadata.percent)),
  13561. total : $module.data(metadata.total),
  13562. value : module.helper.forceArray($module.data(metadata.value))
  13563. }
  13564. ;
  13565. if(data.total) {
  13566. module.debug('Total value set from metadata', data.total);
  13567. module.set.total(data.total);
  13568. }
  13569. if(data.value.length > 0) {
  13570. module.debug('Current value set from metadata', data.value);
  13571. module.set.value(data.value);
  13572. module.set.progress(data.value);
  13573. }
  13574. if(data.percent.length > 0) {
  13575. module.debug('Current percent value set from metadata', data.percent);
  13576. module.set.percent(data.percent);
  13577. }
  13578. },
  13579. settings: function() {
  13580. if(settings.total !== false) {
  13581. module.debug('Current total set in settings', settings.total);
  13582. module.set.total(settings.total);
  13583. }
  13584. if(settings.value !== false) {
  13585. module.debug('Current value set in settings', settings.value);
  13586. module.set.value(settings.value);
  13587. module.set.progress(module.value);
  13588. }
  13589. if(settings.percent !== false) {
  13590. module.debug('Current percent set in settings', settings.percent);
  13591. module.set.percent(settings.percent);
  13592. }
  13593. }
  13594. },
  13595. bind: {
  13596. transitionEnd: function(callback) {
  13597. var
  13598. transitionEnd = module.get.transitionEnd()
  13599. ;
  13600. $bars
  13601. .one(transitionEnd + eventNamespace, function(event) {
  13602. clearTimeout(module.failSafeTimer);
  13603. callback.call(this, event);
  13604. })
  13605. ;
  13606. module.failSafeTimer = setTimeout(function() {
  13607. $bars.triggerHandler(transitionEnd);
  13608. }, settings.duration + settings.failSafeDelay);
  13609. module.verbose('Adding fail safe timer', module.timer);
  13610. }
  13611. },
  13612. increment: function(incrementValue) {
  13613. var
  13614. startValue,
  13615. newValue
  13616. ;
  13617. if( module.has.total() ) {
  13618. startValue = module.get.value();
  13619. incrementValue = incrementValue || 1;
  13620. }
  13621. else {
  13622. startValue = module.get.percent();
  13623. incrementValue = incrementValue || module.get.randomValue();
  13624. }
  13625. newValue = startValue + incrementValue;
  13626. module.debug('Incrementing percentage by', startValue, newValue, incrementValue);
  13627. newValue = module.get.normalizedValue(newValue);
  13628. module.set.progress(newValue);
  13629. },
  13630. decrement: function(decrementValue) {
  13631. var
  13632. total = module.get.total(),
  13633. startValue,
  13634. newValue
  13635. ;
  13636. if(total) {
  13637. startValue = module.get.value();
  13638. decrementValue = decrementValue || 1;
  13639. newValue = startValue - decrementValue;
  13640. module.debug('Decrementing value by', decrementValue, startValue);
  13641. }
  13642. else {
  13643. startValue = module.get.percent();
  13644. decrementValue = decrementValue || module.get.randomValue();
  13645. newValue = startValue - decrementValue;
  13646. module.debug('Decrementing percentage by', decrementValue, startValue);
  13647. }
  13648. newValue = module.get.normalizedValue(newValue);
  13649. module.set.progress(newValue);
  13650. },
  13651. has: {
  13652. progressPoll: function() {
  13653. return module.progressPoll;
  13654. },
  13655. total: function() {
  13656. return (module.get.total() !== false);
  13657. }
  13658. },
  13659. get: {
  13660. text: function(templateText, index) {
  13661. var
  13662. index_ = index || 0,
  13663. value = module.get.value(index_),
  13664. total = module.total || 0,
  13665. percent = (animating)
  13666. ? module.get.displayPercent(index_)
  13667. : module.get.percent(index_),
  13668. left = (module.total > 0)
  13669. ? (total - value)
  13670. : (100 - percent)
  13671. ;
  13672. templateText = templateText || '';
  13673. templateText = templateText
  13674. .replace('{value}', value)
  13675. .replace('{total}', total)
  13676. .replace('{left}', left)
  13677. .replace('{percent}', percent)
  13678. .replace('{bar}', settings.text.bars[index_] || '')
  13679. ;
  13680. module.verbose('Adding variables to progress bar text', templateText);
  13681. return templateText;
  13682. },
  13683. normalizedValue: function(value) {
  13684. if(value < 0) {
  13685. module.debug('Value cannot decrement below 0');
  13686. return 0;
  13687. }
  13688. if(module.has.total()) {
  13689. if(value > module.total) {
  13690. module.debug('Value cannot increment above total', module.total);
  13691. return module.total;
  13692. }
  13693. }
  13694. else if(value > 100 ) {
  13695. module.debug('Value cannot increment above 100 percent');
  13696. return 100;
  13697. }
  13698. return value;
  13699. },
  13700. updateInterval: function() {
  13701. if(settings.updateInterval == 'auto') {
  13702. return settings.duration;
  13703. }
  13704. return settings.updateInterval;
  13705. },
  13706. randomValue: function() {
  13707. module.debug('Generating random increment percentage');
  13708. return Math.floor((Math.random() * settings.random.max) + settings.random.min);
  13709. },
  13710. numericValue: function(value) {
  13711. return (typeof value === 'string')
  13712. ? (value.replace(/[^\d.]/g, '') !== '')
  13713. ? +(value.replace(/[^\d.]/g, ''))
  13714. : false
  13715. : value
  13716. ;
  13717. },
  13718. transitionEnd: function() {
  13719. var
  13720. element = document.createElement('element'),
  13721. transitions = {
  13722. 'transition' :'transitionend',
  13723. 'OTransition' :'oTransitionEnd',
  13724. 'MozTransition' :'transitionend',
  13725. 'WebkitTransition' :'webkitTransitionEnd'
  13726. },
  13727. transition
  13728. ;
  13729. for(transition in transitions){
  13730. if( element.style[transition] !== undefined ){
  13731. return transitions[transition];
  13732. }
  13733. }
  13734. },
  13735. // gets current displayed percentage (if animating values this is the intermediary value)
  13736. displayPercent: function(index) {
  13737. var
  13738. $bar = $($bars[index]),
  13739. barWidth = $bar.width(),
  13740. totalWidth = $module.width(),
  13741. minDisplay = parseInt($bar.css('min-width'), 10),
  13742. displayPercent = (barWidth > minDisplay)
  13743. ? (barWidth / totalWidth * 100)
  13744. : module.percent
  13745. ;
  13746. return (settings.precision > 0)
  13747. ? Math.round(displayPercent * (10 * settings.precision)) / (10 * settings.precision)
  13748. : Math.round(displayPercent)
  13749. ;
  13750. },
  13751. percent: function(index) {
  13752. return module.percent && module.percent[index || 0] || 0;
  13753. },
  13754. value: function(index) {
  13755. return module.nextValue || module.value && module.value[index || 0] || 0;
  13756. },
  13757. total: function() {
  13758. return module.total || false;
  13759. }
  13760. },
  13761. create: {
  13762. progressPoll: function() {
  13763. module.progressPoll = setTimeout(function() {
  13764. module.update.toNextValue();
  13765. module.remove.progressPoll();
  13766. }, module.get.updateInterval());
  13767. },
  13768. },
  13769. is: {
  13770. complete: function() {
  13771. return module.is.success() || module.is.warning() || module.is.error();
  13772. },
  13773. success: function() {
  13774. return $module.hasClass(className.success);
  13775. },
  13776. warning: function() {
  13777. return $module.hasClass(className.warning);
  13778. },
  13779. error: function() {
  13780. return $module.hasClass(className.error);
  13781. },
  13782. active: function() {
  13783. return $module.hasClass(className.active);
  13784. },
  13785. visible: function() {
  13786. return $module.is(':visible');
  13787. }
  13788. },
  13789. remove: {
  13790. progressPoll: function() {
  13791. module.verbose('Removing progress poll timer');
  13792. if(module.progressPoll) {
  13793. clearTimeout(module.progressPoll);
  13794. delete module.progressPoll;
  13795. }
  13796. },
  13797. nextValue: function() {
  13798. module.verbose('Removing progress value stored for next update');
  13799. delete module.nextValue;
  13800. },
  13801. state: function() {
  13802. module.verbose('Removing stored state');
  13803. delete module.total;
  13804. delete module.percent;
  13805. delete module.value;
  13806. },
  13807. active: function() {
  13808. module.verbose('Removing active state');
  13809. $module.removeClass(className.active);
  13810. },
  13811. success: function() {
  13812. module.verbose('Removing success state');
  13813. $module.removeClass(className.success);
  13814. },
  13815. warning: function() {
  13816. module.verbose('Removing warning state');
  13817. $module.removeClass(className.warning);
  13818. },
  13819. error: function() {
  13820. module.verbose('Removing error state');
  13821. $module.removeClass(className.error);
  13822. }
  13823. },
  13824. set: {
  13825. barWidth: function(values) {
  13826. module.debug("set bar width with ", values);
  13827. values = module.helper.forceArray(values);
  13828. var firstNonZeroIndex = -1;
  13829. var lastNonZeroIndex = -1;
  13830. var valuesSum = module.helper.sum(values);
  13831. var barCounts = $bars.length;
  13832. var isMultiple = barCounts > 1;
  13833. var percents = values.map(function(value, index) {
  13834. var allZero = (index === barCounts - 1 && valuesSum === 0);
  13835. var $bar = $($bars[index]);
  13836. if (value === 0 && isMultiple && !allZero) {
  13837. $bar.css('display', 'none');
  13838. } else {
  13839. if (isMultiple && allZero) {
  13840. $bar.css('background', 'transparent');
  13841. }
  13842. if (firstNonZeroIndex == -1) {
  13843. firstNonZeroIndex = index;
  13844. }
  13845. lastNonZeroIndex = index;
  13846. $bar.css({
  13847. display: 'block',
  13848. width: value + '%'
  13849. });
  13850. }
  13851. return parseFloat(value);
  13852. });
  13853. values.forEach(function(_, index) {
  13854. var $bar = $($bars[index]);
  13855. $bar.css({
  13856. borderTopLeftRadius: index == firstNonZeroIndex ? '' : 0,
  13857. borderBottomLeftRadius: index == firstNonZeroIndex ? '' : 0,
  13858. borderTopRightRadius: index == lastNonZeroIndex ? '' : 0,
  13859. borderBottomRightRadius: index == lastNonZeroIndex ? '' : 0
  13860. });
  13861. });
  13862. $module
  13863. .attr('data-percent', percents)
  13864. ;
  13865. },
  13866. duration: function(duration) {
  13867. duration = duration || settings.duration;
  13868. duration = (typeof duration == 'number')
  13869. ? duration + 'ms'
  13870. : duration
  13871. ;
  13872. module.verbose('Setting progress bar transition duration', duration);
  13873. $bars
  13874. .css({
  13875. 'transition-duration': duration
  13876. })
  13877. ;
  13878. },
  13879. percent: function(percents) {
  13880. percents = module.helper.forceArray(percents).map(function(percent) {
  13881. return (typeof percent == 'string')
  13882. ? +(percent.replace('%', ''))
  13883. : percent
  13884. ;
  13885. });
  13886. var hasTotal = module.has.total();
  13887. var totalPecent = module.helper.sum(percents);
  13888. var isMultpleValues = percents.length > 1 && hasTotal;
  13889. var sumTotal = module.helper.sum(module.helper.forceArray(module.value));
  13890. if (isMultpleValues && sumTotal > module.total) {
  13891. // Sum values instead of pecents to avoid precision issues when summing floats
  13892. module.error(error.sumExceedsTotal, sumTotal, module.total);
  13893. } else if (!isMultpleValues && totalPecent > 100) {
  13894. // Sum before rouding since sum of rounded may have error though sum of actual is fine
  13895. module.error(error.tooHigh, totalPecent);
  13896. } else if (totalPecent < 0) {
  13897. module.error(error.tooLow, totalPecent);
  13898. } else {
  13899. var autoPrecision = settings.precision > 0
  13900. ? settings.precision
  13901. : isMultpleValues
  13902. ? module.helper.derivePrecision(Math.min.apply(null, module.value), module.total)
  13903. : undefined;
  13904. // round display percentage
  13905. var roundedPercents = percents.map(function (percent) {
  13906. return (autoPrecision > 0)
  13907. ? Math.round(percent * (10 * autoPrecision)) / (10 * autoPrecision)
  13908. : Math.round(percent)
  13909. ;
  13910. });
  13911. module.percent = roundedPercents;
  13912. if (!hasTotal) {
  13913. module.value = roundedPercents.map(function (percent) {
  13914. return (autoPrecision > 0)
  13915. ? Math.round((percent / 100) * module.total * (10 * autoPrecision)) / (10 * autoPrecision)
  13916. : Math.round((percent / 100) * module.total * 10) / 10
  13917. ;
  13918. });
  13919. if (settings.limitValues) {
  13920. module.value = module.value.map(function (value) {
  13921. return (value > 100)
  13922. ? 100
  13923. : (module.value < 0)
  13924. ? 0
  13925. : module.value;
  13926. });
  13927. }
  13928. }
  13929. module.set.barWidth(percents);
  13930. module.set.labelInterval();
  13931. module.set.labels();
  13932. }
  13933. settings.onChange.call(element, percents, module.value, module.total);
  13934. },
  13935. labelInterval: function() {
  13936. var
  13937. animationCallback = function() {
  13938. module.verbose('Bar finished animating, removing continuous label updates');
  13939. clearInterval(module.interval);
  13940. animating = false;
  13941. module.set.labels();
  13942. }
  13943. ;
  13944. clearInterval(module.interval);
  13945. module.bind.transitionEnd(animationCallback);
  13946. animating = true;
  13947. module.interval = setInterval(function() {
  13948. var
  13949. isInDOM = $.contains(document.documentElement, element)
  13950. ;
  13951. if(!isInDOM) {
  13952. clearInterval(module.interval);
  13953. animating = false;
  13954. }
  13955. module.set.labels();
  13956. }, settings.framerate);
  13957. },
  13958. labels: function() {
  13959. module.verbose('Setting both bar progress and outer label text');
  13960. module.set.barLabel();
  13961. module.set.state();
  13962. },
  13963. label: function(text) {
  13964. text = text || '';
  13965. if(text) {
  13966. text = module.get.text(text);
  13967. module.verbose('Setting label to text', text);
  13968. $label.text(text);
  13969. }
  13970. },
  13971. state: function(percent) {
  13972. percent = (percent !== undefined)
  13973. ? percent
  13974. : module.helper.sum(module.percent)
  13975. ;
  13976. if(percent === 100) {
  13977. if(settings.autoSuccess && $bars.length === 1 && !(module.is.warning() || module.is.error() || module.is.success())) {
  13978. module.set.success();
  13979. module.debug('Automatically triggering success at 100%');
  13980. }
  13981. else {
  13982. module.verbose('Reached 100% removing active state');
  13983. module.remove.active();
  13984. module.remove.progressPoll();
  13985. }
  13986. }
  13987. else if(percent > 0) {
  13988. module.verbose('Adjusting active progress bar label', percent);
  13989. module.set.active();
  13990. }
  13991. else {
  13992. module.remove.active();
  13993. module.set.label(settings.text.active);
  13994. }
  13995. },
  13996. barLabel: function(text) {
  13997. $progresses.map(function(index, element){
  13998. var $progress = $(element);
  13999. if (text !== undefined) {
  14000. $progress.text( module.get.text(text, index) );
  14001. }
  14002. else if (settings.label == 'ratio' && module.total) {
  14003. module.verbose('Adding ratio to bar label');
  14004. $progress.text( module.get.text(settings.text.ratio, index) );
  14005. }
  14006. else if (settings.label == 'percent') {
  14007. module.verbose('Adding percentage to bar label');
  14008. $progress.text( module.get.text(settings.text.percent, index) );
  14009. }
  14010. });
  14011. },
  14012. active: function(text) {
  14013. text = text || settings.text.active;
  14014. module.debug('Setting active state');
  14015. if(settings.showActivity && !module.is.active() ) {
  14016. $module.addClass(className.active);
  14017. }
  14018. module.remove.warning();
  14019. module.remove.error();
  14020. module.remove.success();
  14021. text = settings.onLabelUpdate('active', text, module.value, module.total);
  14022. if(text) {
  14023. module.set.label(text);
  14024. }
  14025. module.bind.transitionEnd(function() {
  14026. settings.onActive.call(element, module.value, module.total);
  14027. });
  14028. },
  14029. success : function(text) {
  14030. text = text || settings.text.success || settings.text.active;
  14031. module.debug('Setting success state');
  14032. $module.addClass(className.success);
  14033. module.remove.active();
  14034. module.remove.warning();
  14035. module.remove.error();
  14036. module.complete();
  14037. if(settings.text.success) {
  14038. text = settings.onLabelUpdate('success', text, module.value, module.total);
  14039. module.set.label(text);
  14040. }
  14041. else {
  14042. text = settings.onLabelUpdate('active', text, module.value, module.total);
  14043. module.set.label(text);
  14044. }
  14045. module.bind.transitionEnd(function() {
  14046. settings.onSuccess.call(element, module.total);
  14047. });
  14048. },
  14049. warning : function(text) {
  14050. text = text || settings.text.warning;
  14051. module.debug('Setting warning state');
  14052. $module.addClass(className.warning);
  14053. module.remove.active();
  14054. module.remove.success();
  14055. module.remove.error();
  14056. module.complete();
  14057. text = settings.onLabelUpdate('warning', text, module.value, module.total);
  14058. if(text) {
  14059. module.set.label(text);
  14060. }
  14061. module.bind.transitionEnd(function() {
  14062. settings.onWarning.call(element, module.value, module.total);
  14063. });
  14064. },
  14065. error : function(text) {
  14066. text = text || settings.text.error;
  14067. module.debug('Setting error state');
  14068. $module.addClass(className.error);
  14069. module.remove.active();
  14070. module.remove.success();
  14071. module.remove.warning();
  14072. module.complete();
  14073. text = settings.onLabelUpdate('error', text, module.value, module.total);
  14074. if(text) {
  14075. module.set.label(text);
  14076. }
  14077. module.bind.transitionEnd(function() {
  14078. settings.onError.call(element, module.value, module.total);
  14079. });
  14080. },
  14081. transitionEvent: function() {
  14082. transitionEnd = module.get.transitionEnd();
  14083. },
  14084. total: function(totalValue) {
  14085. module.total = totalValue;
  14086. },
  14087. value: function(value) {
  14088. module.value = module.helper.forceArray(value);
  14089. },
  14090. progress: function(value) {
  14091. if(!module.has.progressPoll()) {
  14092. module.debug('First update in progress update interval, immediately updating', value);
  14093. module.update.progress(value);
  14094. module.create.progressPoll();
  14095. }
  14096. else {
  14097. module.debug('Updated within interval, setting next update to use new value', value);
  14098. module.set.nextValue(value);
  14099. }
  14100. },
  14101. nextValue: function(value) {
  14102. module.nextValue = value;
  14103. }
  14104. },
  14105. update: {
  14106. toNextValue: function() {
  14107. var
  14108. nextValue = module.nextValue
  14109. ;
  14110. if(nextValue) {
  14111. module.debug('Update interval complete using last updated value', nextValue);
  14112. module.update.progress(nextValue);
  14113. module.remove.nextValue();
  14114. }
  14115. },
  14116. progress: function(values) {
  14117. var hasTotal = module.has.total();
  14118. if (hasTotal) {
  14119. module.set.value(values);
  14120. }
  14121. var percentCompletes = module.helper.forceArray(values).map(function(value) {
  14122. var
  14123. percentComplete
  14124. ;
  14125. value = module.get.numericValue(value);
  14126. if (value === false) {
  14127. module.error(error.nonNumeric, value);
  14128. }
  14129. value = module.get.normalizedValue(value);
  14130. if (hasTotal) {
  14131. percentComplete = (value / module.total) * 100;
  14132. module.debug('Calculating percent complete from total', percentComplete);
  14133. }
  14134. else {
  14135. percentComplete = value;
  14136. module.debug('Setting value to exact percentage value', percentComplete);
  14137. }
  14138. return percentComplete;
  14139. });
  14140. module.set.percent( percentCompletes );
  14141. }
  14142. },
  14143. setting: function(name, value) {
  14144. module.debug('Changing setting', name, value);
  14145. if( $.isPlainObject(name) ) {
  14146. $.extend(true, settings, name);
  14147. }
  14148. else if(value !== undefined) {
  14149. if($.isPlainObject(settings[name])) {
  14150. $.extend(true, settings[name], value);
  14151. }
  14152. else {
  14153. settings[name] = value;
  14154. }
  14155. }
  14156. else {
  14157. return settings[name];
  14158. }
  14159. },
  14160. internal: function(name, value) {
  14161. if( $.isPlainObject(name) ) {
  14162. $.extend(true, module, name);
  14163. }
  14164. else if(value !== undefined) {
  14165. module[name] = value;
  14166. }
  14167. else {
  14168. return module[name];
  14169. }
  14170. },
  14171. debug: function() {
  14172. if(!settings.silent && settings.debug) {
  14173. if(settings.performance) {
  14174. module.performance.log(arguments);
  14175. }
  14176. else {
  14177. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  14178. module.debug.apply(console, arguments);
  14179. }
  14180. }
  14181. },
  14182. verbose: function() {
  14183. if(!settings.silent && settings.verbose && settings.debug) {
  14184. if(settings.performance) {
  14185. module.performance.log(arguments);
  14186. }
  14187. else {
  14188. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  14189. module.verbose.apply(console, arguments);
  14190. }
  14191. }
  14192. },
  14193. error: function() {
  14194. if(!settings.silent) {
  14195. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  14196. module.error.apply(console, arguments);
  14197. }
  14198. },
  14199. performance: {
  14200. log: function(message) {
  14201. var
  14202. currentTime,
  14203. executionTime,
  14204. previousTime
  14205. ;
  14206. if(settings.performance) {
  14207. currentTime = new Date().getTime();
  14208. previousTime = time || currentTime;
  14209. executionTime = currentTime - previousTime;
  14210. time = currentTime;
  14211. performance.push({
  14212. 'Name' : message[0],
  14213. 'Arguments' : [].slice.call(message, 1) || '',
  14214. 'Element' : element,
  14215. 'Execution Time' : executionTime
  14216. });
  14217. }
  14218. clearTimeout(module.performance.timer);
  14219. module.performance.timer = setTimeout(module.performance.display, 500);
  14220. },
  14221. display: function() {
  14222. var
  14223. title = settings.name + ':',
  14224. totalTime = 0
  14225. ;
  14226. time = false;
  14227. clearTimeout(module.performance.timer);
  14228. $.each(performance, function(index, data) {
  14229. totalTime += data['Execution Time'];
  14230. });
  14231. title += ' ' + totalTime + 'ms';
  14232. if(moduleSelector) {
  14233. title += ' \'' + moduleSelector + '\'';
  14234. }
  14235. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  14236. console.groupCollapsed(title);
  14237. if(console.table) {
  14238. console.table(performance);
  14239. }
  14240. else {
  14241. $.each(performance, function(index, data) {
  14242. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  14243. });
  14244. }
  14245. console.groupEnd();
  14246. }
  14247. performance = [];
  14248. }
  14249. },
  14250. invoke: function(query, passedArguments, context) {
  14251. var
  14252. object = instance,
  14253. maxDepth,
  14254. found,
  14255. response
  14256. ;
  14257. passedArguments = passedArguments || queryArguments;
  14258. context = element || context;
  14259. if(typeof query == 'string' && object !== undefined) {
  14260. query = query.split(/[\. ]/);
  14261. maxDepth = query.length - 1;
  14262. $.each(query, function(depth, value) {
  14263. var camelCaseValue = (depth != maxDepth)
  14264. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  14265. : query
  14266. ;
  14267. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  14268. object = object[camelCaseValue];
  14269. }
  14270. else if( object[camelCaseValue] !== undefined ) {
  14271. found = object[camelCaseValue];
  14272. return false;
  14273. }
  14274. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  14275. object = object[value];
  14276. }
  14277. else if( object[value] !== undefined ) {
  14278. found = object[value];
  14279. return false;
  14280. }
  14281. else {
  14282. module.error(error.method, query);
  14283. return false;
  14284. }
  14285. });
  14286. }
  14287. if ( $.isFunction( found ) ) {
  14288. response = found.apply(context, passedArguments);
  14289. }
  14290. else if(found !== undefined) {
  14291. response = found;
  14292. }
  14293. if(Array.isArray(returnedValue)) {
  14294. returnedValue.push(response);
  14295. }
  14296. else if(returnedValue !== undefined) {
  14297. returnedValue = [returnedValue, response];
  14298. }
  14299. else if(response !== undefined) {
  14300. returnedValue = response;
  14301. }
  14302. return found;
  14303. }
  14304. };
  14305. if(methodInvoked) {
  14306. if(instance === undefined) {
  14307. module.initialize();
  14308. }
  14309. module.invoke(query);
  14310. }
  14311. else {
  14312. if(instance !== undefined) {
  14313. instance.invoke('destroy');
  14314. }
  14315. module.initialize();
  14316. }
  14317. })
  14318. ;
  14319. return (returnedValue !== undefined)
  14320. ? returnedValue
  14321. : this
  14322. ;
  14323. };
  14324. $.fn.progress.settings = {
  14325. name : 'Progress',
  14326. namespace : 'progress',
  14327. silent : false,
  14328. debug : false,
  14329. verbose : false,
  14330. performance : true,
  14331. random : {
  14332. min : 2,
  14333. max : 5
  14334. },
  14335. duration : 300,
  14336. updateInterval : 'auto',
  14337. autoSuccess : true,
  14338. showActivity : true,
  14339. limitValues : true,
  14340. label : 'percent',
  14341. precision : 0,
  14342. framerate : (1000 / 30), /// 30 fps
  14343. percent : false,
  14344. total : false,
  14345. value : false,
  14346. // delay in ms for fail safe animation callback
  14347. failSafeDelay : 100,
  14348. onLabelUpdate : function(state, text, value, total){
  14349. return text;
  14350. },
  14351. onChange : function(percent, value, total){},
  14352. onSuccess : function(total){},
  14353. onActive : function(value, total){},
  14354. onError : function(value, total){},
  14355. onWarning : function(value, total){},
  14356. error : {
  14357. method : 'The method you called is not defined.',
  14358. nonNumeric : 'Progress value is non numeric',
  14359. tooHigh : 'Value specified is above 100%',
  14360. tooLow : 'Value specified is below 0%',
  14361. sumExceedsTotal : 'Sum of multple values exceed total',
  14362. },
  14363. regExp: {
  14364. variable: /\{\$*[A-z0-9]+\}/g
  14365. },
  14366. metadata: {
  14367. percent : 'percent',
  14368. total : 'total',
  14369. value : 'value'
  14370. },
  14371. selector : {
  14372. bar : '> .bar',
  14373. label : '> .label',
  14374. progress : '.bar > .progress'
  14375. },
  14376. text : {
  14377. active : false,
  14378. error : false,
  14379. success : false,
  14380. warning : false,
  14381. percent : '{percent}%',
  14382. ratio : '{value} of {total}',
  14383. bars : ['']
  14384. },
  14385. className : {
  14386. active : 'active',
  14387. error : 'error',
  14388. success : 'success',
  14389. warning : 'warning'
  14390. }
  14391. };
  14392. })( jQuery, window, document );
  14393. /*!
  14394. * # Fomantic-UI - Slider
  14395. * http://github.com/fomantic/Fomantic-UI/
  14396. *
  14397. *
  14398. * Released under the MIT license
  14399. * http://opensource.org/licenses/MIT
  14400. *
  14401. */
  14402. ;(function ( $, window, document, undefined ) {
  14403. "use strict";
  14404. window = (typeof window != 'undefined' && window.Math == Math)
  14405. ? window
  14406. : (typeof self != 'undefined' && self.Math == Math)
  14407. ? self
  14408. : Function('return this')()
  14409. ;
  14410. $.fn.slider = function(parameters) {
  14411. var
  14412. $allModules = $(this),
  14413. $window = $(window),
  14414. moduleSelector = $allModules.selector || '',
  14415. time = new Date().getTime(),
  14416. performance = [],
  14417. query = arguments[0],
  14418. methodInvoked = (typeof query == 'string'),
  14419. queryArguments = [].slice.call(arguments, 1),
  14420. alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
  14421. SINGLE_STEP = 1,
  14422. BIG_STEP = 2,
  14423. NO_STEP = 0,
  14424. SINGLE_BACKSTEP = -1,
  14425. BIG_BACKSTEP = -2,
  14426. // Used to manage document bound events.
  14427. // Use this so that we can distinguish between which document events are bound to which range.
  14428. currentRange = 0,
  14429. returnedValue
  14430. ;
  14431. $allModules
  14432. .each(function() {
  14433. var
  14434. settings = ( $.isPlainObject(parameters) )
  14435. ? $.extend(true, {}, $.fn.slider.settings, parameters)
  14436. : $.extend({}, $.fn.slider.settings),
  14437. className = settings.className,
  14438. metadata = settings.metadata,
  14439. namespace = settings.namespace,
  14440. error = settings.error,
  14441. keys = settings.keys,
  14442. interpretLabel = settings.interpretLabel,
  14443. isHover = false,
  14444. eventNamespace = '.' + namespace,
  14445. moduleNamespace = 'module-' + namespace,
  14446. $module = $(this),
  14447. $currThumb,
  14448. $thumb,
  14449. $secondThumb,
  14450. $track,
  14451. $trackFill,
  14452. $labels,
  14453. element = this,
  14454. instance = $module.data(moduleNamespace),
  14455. documentEventID,
  14456. value,
  14457. position,
  14458. secondPos,
  14459. offset,
  14460. precision,
  14461. isTouch,
  14462. gapRatio = 1,
  14463. module
  14464. ;
  14465. module = {
  14466. initialize: function() {
  14467. module.debug('Initializing slider', settings);
  14468. currentRange += 1;
  14469. documentEventID = currentRange;
  14470. isTouch = module.setup.testOutTouch();
  14471. module.setup.layout();
  14472. module.setup.labels();
  14473. if(!module.is.disabled()) {
  14474. module.bind.events();
  14475. }
  14476. module.read.metadata();
  14477. module.read.settings();
  14478. module.instantiate();
  14479. },
  14480. instantiate: function() {
  14481. module.verbose('Storing instance of slider', module);
  14482. instance = module;
  14483. $module
  14484. .data(moduleNamespace, module)
  14485. ;
  14486. },
  14487. destroy: function() {
  14488. module.verbose('Destroying previous slider for', $module);
  14489. clearInterval(instance.interval);
  14490. module.unbind.events();
  14491. module.unbind.slidingEvents();
  14492. $module.removeData(moduleNamespace);
  14493. instance = undefined;
  14494. },
  14495. setup: {
  14496. layout: function() {
  14497. if( $module.attr('tabindex') === undefined) {
  14498. $module.attr('tabindex', 0);
  14499. }
  14500. if($module.find('.inner').length == 0) {
  14501. $module.append("<div class='inner'>"
  14502. + "<div class='track'></div>"
  14503. + "<div class='track-fill'></div>"
  14504. + "<div class='thumb'></div>"
  14505. + "</div>");
  14506. }
  14507. precision = module.get.precision();
  14508. $thumb = $module.find('.thumb:not(.second)');
  14509. $currThumb = $thumb;
  14510. if(module.is.range()) {
  14511. if($module.find('.thumb.second').length == 0) {
  14512. $module.find('.inner').append("<div class='thumb second'></div>");
  14513. }
  14514. $secondThumb = $module.find('.thumb.second');
  14515. }
  14516. $track = $module.find('.track');
  14517. $trackFill = $module.find('.track-fill');
  14518. offset = $thumb.width() / 2;
  14519. },
  14520. labels: function() {
  14521. if(module.is.labeled()) {
  14522. $labels = $module.find('.labels:not(.auto)');
  14523. if($labels.length != 0) {
  14524. module.setup.customLabel();
  14525. } else {
  14526. module.setup.autoLabel();
  14527. }
  14528. if (settings.showLabelTicks) {
  14529. $module.addClass(className.ticked)
  14530. }
  14531. }
  14532. },
  14533. testOutTouch: function() {
  14534. try {
  14535. document.createEvent('TouchEvent');
  14536. return true;
  14537. } catch (e) {
  14538. return false;
  14539. }
  14540. },
  14541. customLabel: function() {
  14542. var
  14543. $children = $labels.find('.label'),
  14544. numChildren = $children.length,
  14545. min = module.get.min(),
  14546. max = module.get.max(),
  14547. ratio
  14548. ;
  14549. $children.each(function(index) {
  14550. var
  14551. $child = $(this),
  14552. attrValue = $child.attr('data-value')
  14553. ;
  14554. if(attrValue) {
  14555. attrValue = attrValue > max ? max : attrValue < min ? min : attrValue;
  14556. ratio = (attrValue - min) / (max - min);
  14557. } else {
  14558. ratio = (index + 1) / (numChildren + 1);
  14559. }
  14560. module.update.labelPosition(ratio, $(this));
  14561. });
  14562. },
  14563. autoLabel: function() {
  14564. if(module.get.step() != 0) {
  14565. $labels = $module.find('.labels');
  14566. if($labels.length != 0) {
  14567. $labels.empty();
  14568. }
  14569. else {
  14570. $labels = $module.append('<ul class="auto labels"></ul>').find('.labels');
  14571. }
  14572. for(var i = 0, len = module.get.numLabels(); i <= len; i++) {
  14573. var
  14574. labelText = module.get.label(i),
  14575. $label = (labelText !== "")
  14576. ? !(i % module.get.gapRatio())
  14577. ? $('<li class="label">' + labelText + '</li>')
  14578. : $('<li class="halftick label"></li>')
  14579. : null,
  14580. ratio = i / len
  14581. ;
  14582. if($label) {
  14583. module.update.labelPosition(ratio, $label);
  14584. $labels.append($label);
  14585. }
  14586. }
  14587. }
  14588. }
  14589. },
  14590. bind: {
  14591. events: function() {
  14592. module.bind.globalKeyboardEvents();
  14593. module.bind.keyboardEvents();
  14594. module.bind.mouseEvents();
  14595. if(module.is.touch()) {
  14596. module.bind.touchEvents();
  14597. }
  14598. if (settings.autoAdjustLabels) {
  14599. module.bind.windowEvents();
  14600. }
  14601. },
  14602. keyboardEvents: function() {
  14603. module.verbose('Binding keyboard events');
  14604. $module.on('keydown' + eventNamespace, module.event.keydown);
  14605. },
  14606. globalKeyboardEvents: function() {
  14607. $(document).on('keydown' + eventNamespace + documentEventID, module.event.activateFocus);
  14608. },
  14609. mouseEvents: function() {
  14610. module.verbose('Binding mouse events');
  14611. $module.find('.track, .thumb, .inner').on('mousedown' + eventNamespace, function(event) {
  14612. event.stopImmediatePropagation();
  14613. event.preventDefault();
  14614. module.event.down(event);
  14615. });
  14616. $module.on('mousedown' + eventNamespace, module.event.down);
  14617. $module.on('mouseenter' + eventNamespace, function(event) {
  14618. isHover = true;
  14619. });
  14620. $module.on('mouseleave' + eventNamespace, function(event) {
  14621. isHover = false;
  14622. });
  14623. },
  14624. touchEvents: function() {
  14625. module.verbose('Binding touch events');
  14626. $module.find('.track, .thumb, .inner').on('touchstart' + eventNamespace, function(event) {
  14627. event.stopImmediatePropagation();
  14628. event.preventDefault();
  14629. module.event.down(event);
  14630. });
  14631. $module.on('touchstart' + eventNamespace, module.event.down);
  14632. },
  14633. slidingEvents: function() {
  14634. // these don't need the identifier because we only ever want one of them to be registered with document
  14635. module.verbose('Binding page wide events while handle is being draged');
  14636. if(module.is.touch()) {
  14637. $(document).on('touchmove' + eventNamespace, module.event.move);
  14638. $(document).on('touchend' + eventNamespace, module.event.up);
  14639. }
  14640. else {
  14641. $(document).on('mousemove' + eventNamespace, module.event.move);
  14642. $(document).on('mouseup' + eventNamespace, module.event.up);
  14643. }
  14644. },
  14645. windowEvents: function() {
  14646. $window.on('resize' + eventNamespace, module.event.resize);
  14647. }
  14648. },
  14649. unbind: {
  14650. events: function() {
  14651. $module.find('.track, .thumb, .inner').off('mousedown' + eventNamespace);
  14652. $module.find('.track, .thumb, .inner').off('touchstart' + eventNamespace);
  14653. $module.off('mousedown' + eventNamespace);
  14654. $module.off('mouseenter' + eventNamespace);
  14655. $module.off('mouseleave' + eventNamespace);
  14656. $module.off('touchstart' + eventNamespace);
  14657. $module.off('keydown' + eventNamespace);
  14658. $module.off('focusout' + eventNamespace);
  14659. $(document).off('keydown' + eventNamespace + documentEventID, module.event.activateFocus);
  14660. $window.off('resize' + eventNamespace);
  14661. },
  14662. slidingEvents: function() {
  14663. if(module.is.touch()) {
  14664. $(document).off('touchmove' + eventNamespace);
  14665. $(document).off('touchend' + eventNamespace);
  14666. } else {
  14667. $(document).off('mousemove' + eventNamespace);
  14668. $(document).off('mouseup' + eventNamespace);
  14669. }
  14670. },
  14671. },
  14672. event: {
  14673. down: function(event, originalEvent) {
  14674. event.preventDefault();
  14675. if(module.is.range()) {
  14676. var
  14677. eventPos = module.determine.eventPos(event, originalEvent),
  14678. newPos = module.determine.pos(eventPos)
  14679. ;
  14680. $currThumb = module.determine.closestThumb(newPos);
  14681. }
  14682. if(!module.is.disabled()) {
  14683. module.bind.slidingEvents();
  14684. }
  14685. },
  14686. move: function(event, originalEvent) {
  14687. event.preventDefault();
  14688. var value = module.determine.valueFromEvent(event, originalEvent);
  14689. if(module.get.step() == 0 || module.is.smooth()) {
  14690. var
  14691. thumbVal = module.thumbVal,
  14692. secondThumbVal = module.secondThumbVal,
  14693. thumbSmoothVal = module.determine.smoothValueFromEvent(event, originalEvent)
  14694. ;
  14695. if(!$currThumb.hasClass('second')) {
  14696. thumbVal = value;
  14697. } else {
  14698. secondThumbVal = value;
  14699. }
  14700. value = Math.abs(thumbVal - (secondThumbVal || 0));
  14701. module.update.position(thumbSmoothVal);
  14702. settings.onMove.call(element, value, thumbVal, secondThumbVal);
  14703. } else {
  14704. module.update.value(value, function(value, thumbVal, secondThumbVal) {
  14705. settings.onMove.call(element, value, thumbVal, secondThumbVal);
  14706. });
  14707. }
  14708. },
  14709. up: function(event, originalEvent) {
  14710. event.preventDefault();
  14711. var value = module.determine.valueFromEvent(event, originalEvent);
  14712. module.set.value(value);
  14713. module.unbind.slidingEvents();
  14714. },
  14715. keydown: function(event, first) {
  14716. if(module.is.focused()) {
  14717. $(document).trigger(event);
  14718. }
  14719. if(first || module.is.focused()) {
  14720. var step = module.determine.keyMovement(event);
  14721. if(step != NO_STEP) {
  14722. event.preventDefault();
  14723. switch(step) {
  14724. case SINGLE_STEP:
  14725. module.takeStep();
  14726. break;
  14727. case BIG_STEP:
  14728. module.takeStep(module.get.multiplier());
  14729. break;
  14730. case SINGLE_BACKSTEP:
  14731. module.backStep();
  14732. break;
  14733. case BIG_BACKSTEP:
  14734. module.backStep(module.get.multiplier());
  14735. break;
  14736. }
  14737. }
  14738. }
  14739. },
  14740. activateFocus: function(event) {
  14741. if(!module.is.focused() && module.is.hover() && module.determine.keyMovement(event) != NO_STEP) {
  14742. event.preventDefault();
  14743. module.event.keydown(event, true);
  14744. $module.focus();
  14745. }
  14746. },
  14747. resize: function(_event) {
  14748. // To avoid a useless performance cost, we only call the label refresh when its necessary
  14749. if (gapRatio != module.get.gapRatio()) {
  14750. module.setup.labels();
  14751. gapRatio = module.get.gapRatio();
  14752. }
  14753. }
  14754. },
  14755. resync: function() {
  14756. module.verbose('Resyncing thumb position based on value');
  14757. if(module.is.range()) {
  14758. module.update.position(module.secondThumbVal, $secondThumb);
  14759. }
  14760. module.update.position(module.thumbVal, $thumb);
  14761. module.setup.labels();
  14762. },
  14763. takeStep: function(multiplier) {
  14764. var
  14765. multiplier = multiplier != undefined ? multiplier : 1,
  14766. step = module.get.step(),
  14767. currValue = module.get.currentThumbValue()
  14768. ;
  14769. module.verbose('Taking a step');
  14770. if(step > 0) {
  14771. module.set.value(currValue + step * multiplier);
  14772. } else if (step == 0){
  14773. var
  14774. precision = module.get.precision(),
  14775. newValue = currValue + (multiplier/precision)
  14776. ;
  14777. module.set.value(Math.round(newValue * precision) / precision);
  14778. }
  14779. },
  14780. backStep: function(multiplier) {
  14781. var
  14782. multiplier = multiplier != undefined ? multiplier : 1,
  14783. step = module.get.step(),
  14784. currValue = module.get.currentThumbValue()
  14785. ;
  14786. module.verbose('Going back a step');
  14787. if(step > 0) {
  14788. module.set.value(currValue - step * multiplier);
  14789. } else if (step == 0) {
  14790. var
  14791. precision = module.get.precision(),
  14792. newValue = currValue - (multiplier/precision)
  14793. ;
  14794. module.set.value(Math.round(newValue * precision) / precision);
  14795. }
  14796. },
  14797. is: {
  14798. range: function() {
  14799. return $module.hasClass(settings.className.range);
  14800. },
  14801. hover: function() {
  14802. return isHover;
  14803. },
  14804. focused: function() {
  14805. return $module.is(':focus');
  14806. },
  14807. disabled: function() {
  14808. return $module.hasClass(settings.className.disabled);
  14809. },
  14810. labeled: function() {
  14811. return $module.hasClass(settings.className.labeled);
  14812. },
  14813. reversed: function() {
  14814. return $module.hasClass(settings.className.reversed);
  14815. },
  14816. vertical: function() {
  14817. return $module.hasClass(settings.className.vertical);
  14818. },
  14819. smooth: function() {
  14820. return settings.smooth || $module.hasClass(settings.className.smooth);
  14821. },
  14822. touch: function() {
  14823. return isTouch;
  14824. }
  14825. },
  14826. get: {
  14827. trackOffset: function() {
  14828. if (module.is.vertical()) {
  14829. return $track.offset().top;
  14830. } else {
  14831. return $track.offset().left;
  14832. }
  14833. },
  14834. trackLength: function() {
  14835. if (module.is.vertical()) {
  14836. return $track.height();
  14837. } else {
  14838. return $track.width();
  14839. }
  14840. },
  14841. trackLeft: function() {
  14842. if (module.is.vertical()) {
  14843. return $track.position().top;
  14844. } else {
  14845. return $track.position().left;
  14846. }
  14847. },
  14848. trackStartPos: function() {
  14849. return module.is.reversed() ? module.get.trackLeft() + module.get.trackLength() : module.get.trackLeft();
  14850. },
  14851. trackEndPos: function() {
  14852. return module.is.reversed() ? module.get.trackLeft() : module.get.trackLeft() + module.get.trackLength();
  14853. },
  14854. trackStartMargin: function () {
  14855. var margin;
  14856. if (module.is.vertical()) {
  14857. margin = module.is.reversed() ? $module.css('padding-bottom') : $module.css('padding-top');
  14858. } else {
  14859. margin = module.is.reversed() ? $module.css('padding-right') : $module.css('padding-left');
  14860. }
  14861. return margin || '0px';
  14862. },
  14863. trackEndMargin: function () {
  14864. var margin;
  14865. if (module.is.vertical()) {
  14866. margin = module.is.reversed() ? $module.css('padding-top') : $module.css('padding-bottom');
  14867. } else {
  14868. margin = module.is.reversed() ? $module.css('padding-left') : $module.css('padding-right');
  14869. }
  14870. return margin || '0px';
  14871. },
  14872. precision: function() {
  14873. var
  14874. decimalPlaces,
  14875. step = module.get.step()
  14876. ;
  14877. if(step != 0) {
  14878. var split = String(step).split('.');
  14879. if(split.length == 2) {
  14880. decimalPlaces = split[1].length;
  14881. } else {
  14882. decimalPlaces = 0;
  14883. }
  14884. } else {
  14885. decimalPlaces = settings.decimalPlaces;
  14886. }
  14887. var precision = Math.pow(10, decimalPlaces);
  14888. module.debug('Precision determined', precision);
  14889. return precision;
  14890. },
  14891. min: function() {
  14892. return settings.min;
  14893. },
  14894. max: function() {
  14895. var step = module.get.step(),
  14896. min = module.get.min(),
  14897. quotient = step === 0 ? 0 : Math.floor((settings.max - min) / step),
  14898. remainder = step === 0 ? 0 : (settings.max - min) % step;
  14899. return remainder === 0 ? settings.max : min + quotient * step;
  14900. },
  14901. step: function() {
  14902. return settings.step;
  14903. },
  14904. numLabels: function() {
  14905. var value = Math.round((module.get.max() - module.get.min()) / module.get.step());
  14906. module.debug('Determined that there should be ' + value + ' labels');
  14907. return value;
  14908. },
  14909. labelType: function() {
  14910. return settings.labelType;
  14911. },
  14912. label: function(value) {
  14913. if(interpretLabel) {
  14914. return interpretLabel(value);
  14915. }
  14916. switch (settings.labelType) {
  14917. case settings.labelTypes.number:
  14918. return Math.round(((value * module.get.step()) + module.get.min()) * precision ) / precision;
  14919. case settings.labelTypes.letter:
  14920. return alphabet[(value) % 26];
  14921. default:
  14922. return value;
  14923. }
  14924. },
  14925. value: function() {
  14926. return value;
  14927. },
  14928. currentThumbValue: function() {
  14929. return $currThumb.hasClass('second') ? module.secondThumbVal : module.thumbVal;
  14930. },
  14931. thumbValue: function(which) {
  14932. switch(which) {
  14933. case 'second':
  14934. if(module.is.range()) {
  14935. return module.secondThumbVal;
  14936. }
  14937. else {
  14938. module.error(error.notrange);
  14939. break;
  14940. }
  14941. case 'first':
  14942. default:
  14943. return module.thumbVal;
  14944. }
  14945. },
  14946. multiplier: function() {
  14947. return settings.pageMultiplier;
  14948. },
  14949. thumbPosition: function(which) {
  14950. switch(which) {
  14951. case 'second':
  14952. if(module.is.range()) {
  14953. return secondPos;
  14954. }
  14955. else {
  14956. module.error(error.notrange);
  14957. break;
  14958. }
  14959. case 'first':
  14960. default:
  14961. return position;
  14962. }
  14963. },
  14964. gapRatio: function() {
  14965. var gapRatio = 1;
  14966. if( settings.autoAdjustLabels ) {
  14967. var
  14968. numLabels = module.get.numLabels(),
  14969. gapCounter = 1
  14970. ;
  14971. // While the distance between two labels is too short,
  14972. // we divide the number of labels at each iteration
  14973. // and apply only if the modulo of the operation is an odd number.
  14974. while ((module.get.trackLength() / numLabels) * gapCounter < settings.labelDistance) {
  14975. if( !(numLabels % gapCounter) ) {
  14976. gapRatio = gapCounter;
  14977. }
  14978. gapCounter += 1;
  14979. }
  14980. return gapRatio;
  14981. } else {
  14982. return 1;
  14983. }
  14984. }
  14985. },
  14986. determine: {
  14987. pos: function(pagePos) {
  14988. return module.is.reversed()
  14989. ?
  14990. module.get.trackStartPos() - pagePos + module.get.trackOffset()
  14991. :
  14992. pagePos - module.get.trackOffset() - module.get.trackStartPos()
  14993. ;
  14994. },
  14995. closestThumb: function(eventPos) {
  14996. var
  14997. thumbPos = parseFloat(module.determine.thumbPos($thumb)),
  14998. thumbDelta = Math.abs(eventPos - thumbPos),
  14999. secondThumbPos = parseFloat(module.determine.thumbPos($secondThumb)),
  15000. secondThumbDelta = Math.abs(eventPos - secondThumbPos)
  15001. ;
  15002. return thumbDelta <= secondThumbDelta ? $thumb : $secondThumb;
  15003. },
  15004. closestThumbPos: function(eventPos) {
  15005. var
  15006. thumbPos = parseFloat(module.determine.thumbPos($thumb)),
  15007. thumbDelta = Math.abs(eventPos - thumbPos),
  15008. secondThumbPos = parseFloat(module.determine.thumbPos($secondThumb)),
  15009. secondThumbDelta = Math.abs(eventPos - secondThumbPos)
  15010. ;
  15011. return thumbDelta <= secondThumbDelta ? thumbPos : secondThumbPos;
  15012. },
  15013. thumbPos: function($element) {
  15014. var pos =
  15015. module.is.vertical()
  15016. ?
  15017. module.is.reversed() ? $element.css('bottom') : $element.css('top')
  15018. :
  15019. module.is.reversed() ? $element.css('right') : $element.css('left')
  15020. ;
  15021. return pos;
  15022. },
  15023. positionFromValue: function(value) {
  15024. var
  15025. min = module.get.min(),
  15026. max = module.get.max(),
  15027. value = value > max ? max : value < min ? min : value,
  15028. trackLength = module.get.trackLength(),
  15029. ratio = (value - min) / (max - min),
  15030. position = Math.round(ratio * trackLength)
  15031. ;
  15032. module.verbose('Determined position: ' + position + ' from value: ' + value);
  15033. return position;
  15034. },
  15035. positionFromRatio: function(ratio) {
  15036. var
  15037. trackLength = module.get.trackLength(),
  15038. step = module.get.step(),
  15039. position = Math.round(ratio * trackLength),
  15040. adjustedPos = (step == 0) ? position : Math.round(position / step) * step
  15041. ;
  15042. return adjustedPos;
  15043. },
  15044. valueFromEvent: function(event, originalEvent) {
  15045. var
  15046. eventPos = module.determine.eventPos(event, originalEvent),
  15047. newPos = module.determine.pos(eventPos),
  15048. value
  15049. ;
  15050. if(eventPos < module.get.trackOffset()) {
  15051. value = module.is.reversed() ? module.get.max() : module.get.min();
  15052. } else if(eventPos > module.get.trackOffset() + module.get.trackLength()) {
  15053. value = module.is.reversed() ? module.get.min() : module.get.max();
  15054. } else {
  15055. value = module.determine.value(newPos);
  15056. }
  15057. return value;
  15058. },
  15059. smoothValueFromEvent: function(event, originalEvent) {
  15060. var
  15061. min = module.get.min(),
  15062. max = module.get.max(),
  15063. trackLength = module.get.trackLength(),
  15064. eventPos = module.determine.eventPos(event, originalEvent),
  15065. newPos = eventPos - module.get.trackOffset(),
  15066. ratio,
  15067. value
  15068. ;
  15069. newPos = newPos < 0 ? 0 : newPos > trackLength ? trackLength : newPos;
  15070. ratio = newPos / trackLength;
  15071. if (module.is.reversed()) {
  15072. ratio = 1 - ratio;
  15073. }
  15074. value = ratio * (max - min) + min;
  15075. return value;
  15076. },
  15077. eventPos: function(event, originalEvent) {
  15078. if(module.is.touch()) {
  15079. var
  15080. touchY = event.changedTouches[0].pageY || event.touches[0].pageY,
  15081. touchX = event.changedTouches[0].pageX || event.touches[0].pageX
  15082. ;
  15083. return module.is.vertical() ? touchY : touchX;
  15084. }
  15085. var
  15086. clickY = event.pageY || originalEvent.pageY,
  15087. clickX = event.pageX || originalEvent.pageX
  15088. ;
  15089. return module.is.vertical() ? clickY : clickX;
  15090. },
  15091. value: function(position) {
  15092. var
  15093. startPos = module.is.reversed() ? module.get.trackEndPos() : module.get.trackStartPos(),
  15094. endPos = module.is.reversed() ? module.get.trackStartPos() : module.get.trackEndPos(),
  15095. ratio = (position - startPos) / (endPos - startPos),
  15096. range = module.get.max() - module.get.min(),
  15097. step = module.get.step(),
  15098. value = (ratio * range),
  15099. difference = (step == 0) ? value : Math.round(value / step) * step
  15100. ;
  15101. module.verbose('Determined value based upon position: ' + position + ' as: ' + value);
  15102. if(value != difference) {
  15103. module.verbose('Rounding value to closest step: ' + difference);
  15104. }
  15105. // Use precision to avoid ugly Javascript floating point rounding issues
  15106. // (like 35 * .01 = 0.35000000000000003)
  15107. difference = Math.round(difference * precision) / precision;
  15108. module.verbose('Cutting off additional decimal places');
  15109. return difference + module.get.min();
  15110. },
  15111. keyMovement: function(event) {
  15112. var
  15113. key = event.which,
  15114. downArrow =
  15115. module.is.vertical()
  15116. ?
  15117. module.is.reversed() ? keys.downArrow : keys.upArrow
  15118. :
  15119. keys.downArrow
  15120. ,
  15121. upArrow =
  15122. module.is.vertical()
  15123. ?
  15124. module.is.reversed() ? keys.upArrow : keys.downArrow
  15125. :
  15126. keys.upArrow
  15127. ,
  15128. leftArrow =
  15129. !module.is.vertical()
  15130. ?
  15131. module.is.reversed() ? keys.rightArrow : keys.leftArrow
  15132. :
  15133. keys.leftArrow
  15134. ,
  15135. rightArrow =
  15136. !module.is.vertical()
  15137. ?
  15138. module.is.reversed() ? keys.leftArrow : keys.rightArrow
  15139. :
  15140. keys.rightArrow
  15141. ;
  15142. if(key == downArrow || key == leftArrow) {
  15143. return SINGLE_BACKSTEP;
  15144. } else if(key == upArrow || key == rightArrow) {
  15145. return SINGLE_STEP;
  15146. } else if (key == keys.pageDown) {
  15147. return BIG_BACKSTEP;
  15148. } else if (key == keys.pageUp) {
  15149. return BIG_STEP;
  15150. } else {
  15151. return NO_STEP;
  15152. }
  15153. }
  15154. },
  15155. handleNewValuePosition: function(val) {
  15156. var
  15157. min = module.get.min(),
  15158. max = module.get.max(),
  15159. newPos
  15160. ;
  15161. if (val <= min) {
  15162. val = min;
  15163. } else if (val >= max) {
  15164. val = max;
  15165. }
  15166. newPos = module.determine.positionFromValue(val);
  15167. return newPos;
  15168. },
  15169. set: {
  15170. value: function(newValue) {
  15171. module.update.value(newValue, function(value, thumbVal, secondThumbVal) {
  15172. settings.onChange.call(element, value, thumbVal, secondThumbVal);
  15173. settings.onMove.call(element, value, thumbVal, secondThumbVal);
  15174. });
  15175. },
  15176. rangeValue: function(first, second) {
  15177. if(module.is.range()) {
  15178. var
  15179. min = module.get.min(),
  15180. max = module.get.max()
  15181. ;
  15182. if (first <= min) {
  15183. first = min;
  15184. } else if(first >= max){
  15185. first = max;
  15186. }
  15187. if (second <= min) {
  15188. second = min;
  15189. } else if(second >= max){
  15190. second = max;
  15191. }
  15192. module.thumbVal = first;
  15193. module.secondThumbVal = second;
  15194. value = Math.abs(module.thumbVal - module.secondThumbVal);
  15195. module.update.position(module.thumbVal, $thumb);
  15196. module.update.position(module.secondThumbVal, $secondThumb);
  15197. settings.onChange.call(element, value, module.thumbVal, module.secondThumbVal);
  15198. settings.onMove.call(element, value, module.thumbVal, module.secondThumbVal);
  15199. } else {
  15200. module.error(error.notrange);
  15201. }
  15202. },
  15203. position: function(position, which) {
  15204. var thumbVal = module.determine.value(position);
  15205. switch (which) {
  15206. case 'second':
  15207. module.secondThumbVal = thumbVal;
  15208. module.update.position(thumbVal, $secondThumb);
  15209. break;
  15210. default:
  15211. module.thumbVal = thumbVal;
  15212. module.update.position(thumbVal, $thumb);
  15213. }
  15214. value = Math.abs(module.thumbVal - (module.secondThumbVal || 0));
  15215. module.set.value(value);
  15216. }
  15217. },
  15218. update: {
  15219. value: function(newValue, callback) {
  15220. var
  15221. min = module.get.min(),
  15222. max = module.get.max()
  15223. ;
  15224. if (newValue <= min) {
  15225. newValue = min;
  15226. } else if(newValue >= max){
  15227. newValue = max;
  15228. }
  15229. if(!module.is.range()) {
  15230. value = newValue;
  15231. module.thumbVal = value;
  15232. } else {
  15233. if(!$currThumb.hasClass('second')) {
  15234. module.thumbVal = newValue;
  15235. } else {
  15236. module.secondThumbVal = newValue;
  15237. }
  15238. value = Math.abs(module.thumbVal - module.secondThumbVal);
  15239. }
  15240. module.update.position(newValue);
  15241. module.debug('Setting slider value to ' + value);
  15242. if(typeof callback === 'function') {
  15243. callback(value, module.thumbVal, module.secondThumbVal);
  15244. }
  15245. },
  15246. position: function(newValue, $element) {
  15247. var
  15248. newPos = module.handleNewValuePosition(newValue),
  15249. $targetThumb = $element != undefined ? $element : $currThumb,
  15250. thumbVal = module.thumbVal || module.get.min(),
  15251. secondThumbVal = module.secondThumbVal || module.get.min()
  15252. ;
  15253. if(module.is.range()) {
  15254. if(!$targetThumb.hasClass('second')) {
  15255. position = newPos;
  15256. thumbVal = newValue;
  15257. } else {
  15258. secondPos = newPos;
  15259. secondThumbVal = newValue;
  15260. }
  15261. } else {
  15262. position = newPos;
  15263. thumbVal = newValue;
  15264. }
  15265. var
  15266. trackPosValue,
  15267. thumbPosValue,
  15268. min = module.get.min(),
  15269. max = module.get.max(),
  15270. thumbPosPercent = 100 * (newValue - min) / (max - min),
  15271. trackStartPosPercent = 100 * (Math.min(thumbVal, secondThumbVal) - min) / (max - min),
  15272. trackEndPosPercent = 100 * (1 - (Math.max(thumbVal, secondThumbVal) - min) / (max - min))
  15273. ;
  15274. if (module.is.vertical()) {
  15275. if (module.is.reversed()) {
  15276. thumbPosValue = {bottom: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', top: 'auto'};
  15277. trackPosValue = {bottom: trackStartPosPercent + '%', top: trackEndPosPercent + '%'};
  15278. }
  15279. else {
  15280. thumbPosValue = {top: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', bottom: 'auto'};
  15281. trackPosValue = {top: trackStartPosPercent + '%', bottom: trackEndPosPercent + '%'};
  15282. }
  15283. } else {
  15284. if (module.is.reversed()) {
  15285. thumbPosValue = {right: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', left: 'auto'};
  15286. trackPosValue = {right: trackStartPosPercent + '%', left: trackEndPosPercent + '%'};
  15287. }
  15288. else {
  15289. thumbPosValue = {left: 'calc(' + thumbPosPercent + '% - ' + offset + 'px)', right: 'auto'};
  15290. trackPosValue = {left: trackStartPosPercent + '%', right: trackEndPosPercent + '%'};
  15291. }
  15292. }
  15293. $targetThumb.css(thumbPosValue);
  15294. $trackFill.css(trackPosValue);
  15295. module.debug('Setting slider position to ' + newPos);
  15296. },
  15297. labelPosition: function (ratio, $label) {
  15298. var
  15299. startMargin = module.get.trackStartMargin(),
  15300. endMargin = module.get.trackEndMargin(),
  15301. posDir =
  15302. module.is.vertical()
  15303. ?
  15304. module.is.reversed() ? 'bottom' : 'top'
  15305. :
  15306. module.is.reversed() ? 'right' : 'left',
  15307. startMarginMod = module.is.reversed() && !module.is.vertical() ? ' - ' : ' + '
  15308. ;
  15309. var position = '(100% - ' + startMargin + ' - ' + endMargin + ') * ' + ratio;
  15310. $label.css(posDir, 'calc(' + position + startMarginMod + startMargin + ')');
  15311. }
  15312. },
  15313. goto: {
  15314. max: function() {
  15315. module.set.value(module.get.max());
  15316. },
  15317. min: function() {
  15318. module.set.value(module.get.min());
  15319. },
  15320. },
  15321. read: {
  15322. metadata: function() {
  15323. var
  15324. data = {
  15325. thumbVal : $module.data(metadata.thumbVal),
  15326. secondThumbVal : $module.data(metadata.secondThumbVal)
  15327. }
  15328. ;
  15329. if(data.thumbVal) {
  15330. if(module.is.range() && data.secondThumbVal) {
  15331. module.debug('Current value set from metadata', data.thumbVal, data.secondThumbVal);
  15332. module.set.rangeValue(data.thumbVal, data.secondThumbVal);
  15333. } else {
  15334. module.debug('Current value set from metadata', data.thumbVal);
  15335. module.set.value(data.thumbVal);
  15336. }
  15337. }
  15338. },
  15339. settings: function() {
  15340. if(settings.start !== false) {
  15341. if(module.is.range()) {
  15342. module.debug('Start position set from settings', settings.start, settings.end);
  15343. module.set.rangeValue(settings.start, settings.end);
  15344. } else {
  15345. module.debug('Start position set from settings', settings.start);
  15346. module.set.value(settings.start);
  15347. }
  15348. }
  15349. }
  15350. },
  15351. setting: function(name, value) {
  15352. module.debug('Changing setting', name, value);
  15353. if( $.isPlainObject(name) ) {
  15354. $.extend(true, settings, name);
  15355. }
  15356. else if(value !== undefined) {
  15357. if($.isPlainObject(settings[name])) {
  15358. $.extend(true, settings[name], value);
  15359. }
  15360. else {
  15361. settings[name] = value;
  15362. }
  15363. }
  15364. else {
  15365. return settings[name];
  15366. }
  15367. },
  15368. internal: function(name, value) {
  15369. if( $.isPlainObject(name) ) {
  15370. $.extend(true, module, name);
  15371. }
  15372. else if(value !== undefined) {
  15373. module[name] = value;
  15374. }
  15375. else {
  15376. return module[name];
  15377. }
  15378. },
  15379. debug: function() {
  15380. if(!settings.silent && settings.debug) {
  15381. if(settings.performance) {
  15382. module.performance.log(arguments);
  15383. }
  15384. else {
  15385. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  15386. module.debug.apply(console, arguments);
  15387. }
  15388. }
  15389. },
  15390. verbose: function() {
  15391. if(!settings.silent && settings.verbose && settings.debug) {
  15392. if(settings.performance) {
  15393. module.performance.log(arguments);
  15394. }
  15395. else {
  15396. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  15397. module.verbose.apply(console, arguments);
  15398. }
  15399. }
  15400. },
  15401. error: function() {
  15402. if(!settings.silent) {
  15403. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  15404. module.error.apply(console, arguments);
  15405. }
  15406. },
  15407. performance: {
  15408. log: function(message) {
  15409. var
  15410. currentTime,
  15411. executionTime,
  15412. previousTime
  15413. ;
  15414. if(settings.performance) {
  15415. currentTime = new Date().getTime();
  15416. previousTime = time || currentTime;
  15417. executionTime = currentTime - previousTime;
  15418. time = currentTime;
  15419. performance.push({
  15420. 'Name' : message[0],
  15421. 'Arguments' : [].slice.call(message, 1) || '',
  15422. 'Element' : element,
  15423. 'Execution Time' : executionTime
  15424. });
  15425. }
  15426. clearTimeout(module.performance.timer);
  15427. module.performance.timer = setTimeout(module.performance.display, 500);
  15428. },
  15429. display: function() {
  15430. var
  15431. title = settings.name + ':',
  15432. totalTime = 0
  15433. ;
  15434. time = false;
  15435. clearTimeout(module.performance.timer);
  15436. $.each(performance, function(index, data) {
  15437. totalTime += data['Execution Time'];
  15438. });
  15439. title += ' ' + totalTime + 'ms';
  15440. if(moduleSelector) {
  15441. title += ' \'' + moduleSelector + '\'';
  15442. }
  15443. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  15444. console.groupCollapsed(title);
  15445. if(console.table) {
  15446. console.table(performance);
  15447. }
  15448. else {
  15449. $.each(performance, function(index, data) {
  15450. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  15451. });
  15452. }
  15453. console.groupEnd();
  15454. }
  15455. performance = [];
  15456. }
  15457. },
  15458. invoke: function(query, passedArguments, context) {
  15459. var
  15460. object = instance,
  15461. maxDepth,
  15462. found,
  15463. response
  15464. ;
  15465. passedArguments = passedArguments || queryArguments;
  15466. context = element || context;
  15467. if(typeof query == 'string' && object !== undefined) {
  15468. query = query.split(/[\. ]/);
  15469. maxDepth = query.length - 1;
  15470. $.each(query, function(depth, value) {
  15471. var camelCaseValue = (depth != maxDepth)
  15472. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  15473. : query
  15474. ;
  15475. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  15476. object = object[camelCaseValue];
  15477. }
  15478. else if( object[camelCaseValue] !== undefined ) {
  15479. found = object[camelCaseValue];
  15480. return false;
  15481. }
  15482. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  15483. object = object[value];
  15484. }
  15485. else if( object[value] !== undefined ) {
  15486. found = object[value];
  15487. return false;
  15488. }
  15489. else {
  15490. module.error(error.method, query);
  15491. return false;
  15492. }
  15493. });
  15494. }
  15495. if ( $.isFunction( found ) ) {
  15496. response = found.apply(context, passedArguments);
  15497. }
  15498. else if(found !== undefined) {
  15499. response = found;
  15500. }
  15501. if($.isArray(returnedValue)) {
  15502. returnedValue.push(response);
  15503. }
  15504. else if(returnedValue !== undefined) {
  15505. returnedValue = [returnedValue, response];
  15506. }
  15507. else if(response !== undefined) {
  15508. returnedValue = response;
  15509. }
  15510. return found;
  15511. }
  15512. };
  15513. if(methodInvoked) {
  15514. if(instance === undefined) {
  15515. module.initialize();
  15516. }
  15517. module.invoke(query);
  15518. }
  15519. else {
  15520. if(instance !== undefined) {
  15521. instance.invoke('destroy');
  15522. }
  15523. module.initialize();
  15524. }
  15525. })
  15526. ;
  15527. return (returnedValue !== undefined)
  15528. ? returnedValue
  15529. : this
  15530. ;
  15531. };
  15532. $.fn.slider.settings = {
  15533. silent : false,
  15534. debug : false,
  15535. verbose : false,
  15536. performance : true,
  15537. name : 'Slider',
  15538. namespace : 'slider',
  15539. error : {
  15540. method : 'The method you called is not defined.',
  15541. notrange : 'This slider is not a range slider'
  15542. },
  15543. metadata: {
  15544. thumbVal : 'thumbVal',
  15545. secondThumbVal : 'secondThumbVal'
  15546. },
  15547. min : 0,
  15548. max : 20,
  15549. step : 1,
  15550. start : 0,
  15551. end : 20,
  15552. labelType : 'number',
  15553. showLabelTicks : false,
  15554. smooth : false,
  15555. autoAdjustLabels : true,
  15556. labelDistance : 100,
  15557. //the decimal place to round to if step is undefined
  15558. decimalPlaces : 2,
  15559. // page up/down multiplier. How many more times the steps to take on page up/down press
  15560. pageMultiplier : 2,
  15561. selector: {
  15562. },
  15563. className : {
  15564. reversed : 'reversed',
  15565. disabled : 'disabled',
  15566. labeled : 'labeled',
  15567. ticked : 'ticked',
  15568. vertical : 'vertical',
  15569. range : 'range',
  15570. smooth : 'smooth'
  15571. },
  15572. keys : {
  15573. pageUp : 33,
  15574. pageDown : 34,
  15575. leftArrow : 37,
  15576. upArrow : 38,
  15577. rightArrow : 39,
  15578. downArrow : 40
  15579. },
  15580. labelTypes : {
  15581. number : 'number',
  15582. letter : 'letter'
  15583. },
  15584. onChange : function(value, thumbVal, secondThumbVal){},
  15585. onMove : function(value, thumbVal, secondThumbVal){},
  15586. };
  15587. })( jQuery, window, document );
  15588. /*!
  15589. * # Fomantic-UI - Rating
  15590. * http://github.com/fomantic/Fomantic-UI/
  15591. *
  15592. *
  15593. * Released under the MIT license
  15594. * http://opensource.org/licenses/MIT
  15595. *
  15596. */
  15597. ;(function ($, window, document, undefined) {
  15598. 'use strict';
  15599. $.isFunction = $.isFunction || function(obj) {
  15600. return typeof obj === "function" && typeof obj.nodeType !== "number";
  15601. };
  15602. window = (typeof window != 'undefined' && window.Math == Math)
  15603. ? window
  15604. : (typeof self != 'undefined' && self.Math == Math)
  15605. ? self
  15606. : Function('return this')()
  15607. ;
  15608. $.fn.rating = function(parameters) {
  15609. var
  15610. $allModules = $(this),
  15611. moduleSelector = $allModules.selector || '',
  15612. time = new Date().getTime(),
  15613. performance = [],
  15614. query = arguments[0],
  15615. methodInvoked = (typeof query == 'string'),
  15616. queryArguments = [].slice.call(arguments, 1),
  15617. returnedValue
  15618. ;
  15619. $allModules
  15620. .each(function() {
  15621. var
  15622. settings = ( $.isPlainObject(parameters) )
  15623. ? $.extend(true, {}, $.fn.rating.settings, parameters)
  15624. : $.extend({}, $.fn.rating.settings),
  15625. namespace = settings.namespace,
  15626. className = settings.className,
  15627. metadata = settings.metadata,
  15628. selector = settings.selector,
  15629. eventNamespace = '.' + namespace,
  15630. moduleNamespace = 'module-' + namespace,
  15631. element = this,
  15632. instance = $(this).data(moduleNamespace),
  15633. $module = $(this),
  15634. $icon = $module.find(selector.icon),
  15635. initialLoad,
  15636. module
  15637. ;
  15638. module = {
  15639. initialize: function() {
  15640. module.verbose('Initializing rating module', settings);
  15641. if($icon.length === 0) {
  15642. module.setup.layout();
  15643. }
  15644. if(settings.interactive && !module.is.disabled()) {
  15645. module.enable();
  15646. }
  15647. else {
  15648. module.disable();
  15649. }
  15650. module.set.initialLoad();
  15651. module.set.rating( module.get.initialRating() );
  15652. module.remove.initialLoad();
  15653. module.instantiate();
  15654. },
  15655. instantiate: function() {
  15656. module.verbose('Instantiating module', settings);
  15657. instance = module;
  15658. $module
  15659. .data(moduleNamespace, module)
  15660. ;
  15661. },
  15662. destroy: function() {
  15663. module.verbose('Destroying previous instance', instance);
  15664. module.remove.events();
  15665. $module
  15666. .removeData(moduleNamespace)
  15667. ;
  15668. },
  15669. refresh: function() {
  15670. $icon = $module.find(selector.icon);
  15671. },
  15672. setup: {
  15673. layout: function() {
  15674. var
  15675. maxRating = module.get.maxRating(),
  15676. icon = module.get.icon(),
  15677. html = $.fn.rating.settings.templates.icon(maxRating, icon)
  15678. ;
  15679. module.debug('Generating icon html dynamically');
  15680. $module
  15681. .html(html)
  15682. ;
  15683. module.refresh();
  15684. }
  15685. },
  15686. event: {
  15687. mouseenter: function() {
  15688. var
  15689. $activeIcon = $(this)
  15690. ;
  15691. $activeIcon
  15692. .nextAll()
  15693. .removeClass(className.selected)
  15694. ;
  15695. $module
  15696. .addClass(className.selected)
  15697. ;
  15698. $activeIcon
  15699. .addClass(className.selected)
  15700. .prevAll()
  15701. .addClass(className.selected)
  15702. ;
  15703. },
  15704. mouseleave: function() {
  15705. $module
  15706. .removeClass(className.selected)
  15707. ;
  15708. $icon
  15709. .removeClass(className.selected)
  15710. ;
  15711. },
  15712. click: function() {
  15713. var
  15714. $activeIcon = $(this),
  15715. currentRating = module.get.rating(),
  15716. rating = $icon.index($activeIcon) + 1,
  15717. canClear = (settings.clearable == 'auto')
  15718. ? ($icon.length === 1)
  15719. : settings.clearable
  15720. ;
  15721. if(canClear && currentRating == rating) {
  15722. module.clearRating();
  15723. }
  15724. else {
  15725. module.set.rating( rating );
  15726. }
  15727. }
  15728. },
  15729. clearRating: function() {
  15730. module.debug('Clearing current rating');
  15731. module.set.rating(0);
  15732. },
  15733. bind: {
  15734. events: function() {
  15735. module.verbose('Binding events');
  15736. $module
  15737. .on('mouseenter' + eventNamespace, selector.icon, module.event.mouseenter)
  15738. .on('mouseleave' + eventNamespace, selector.icon, module.event.mouseleave)
  15739. .on('click' + eventNamespace, selector.icon, module.event.click)
  15740. ;
  15741. }
  15742. },
  15743. remove: {
  15744. events: function() {
  15745. module.verbose('Removing events');
  15746. $module
  15747. .off(eventNamespace)
  15748. ;
  15749. },
  15750. initialLoad: function() {
  15751. initialLoad = false;
  15752. }
  15753. },
  15754. enable: function() {
  15755. module.debug('Setting rating to interactive mode');
  15756. module.bind.events();
  15757. $module
  15758. .removeClass(className.disabled)
  15759. ;
  15760. },
  15761. disable: function() {
  15762. module.debug('Setting rating to read-only mode');
  15763. module.remove.events();
  15764. $module
  15765. .addClass(className.disabled)
  15766. ;
  15767. },
  15768. is: {
  15769. initialLoad: function() {
  15770. return initialLoad;
  15771. },
  15772. disabled: function() {
  15773. return $module.hasClass(className.disabled);
  15774. }
  15775. },
  15776. get: {
  15777. icon: function(){
  15778. var icon = $module.data(metadata.icon);
  15779. if (icon) {
  15780. $module.removeData(metadata.icon);
  15781. }
  15782. return icon || settings.icon;
  15783. },
  15784. initialRating: function() {
  15785. if($module.data(metadata.rating) !== undefined) {
  15786. $module.removeData(metadata.rating);
  15787. return $module.data(metadata.rating);
  15788. }
  15789. return settings.initialRating;
  15790. },
  15791. maxRating: function() {
  15792. if($module.data(metadata.maxRating) !== undefined) {
  15793. $module.removeData(metadata.maxRating);
  15794. return $module.data(metadata.maxRating);
  15795. }
  15796. return settings.maxRating;
  15797. },
  15798. rating: function() {
  15799. var
  15800. currentRating = $icon.filter('.' + className.active).length
  15801. ;
  15802. module.verbose('Current rating retrieved', currentRating);
  15803. return currentRating;
  15804. }
  15805. },
  15806. set: {
  15807. rating: function(rating) {
  15808. var
  15809. ratingIndex = (rating - 1 >= 0)
  15810. ? (rating - 1)
  15811. : 0,
  15812. $activeIcon = $icon.eq(ratingIndex)
  15813. ;
  15814. $module
  15815. .removeClass(className.selected)
  15816. ;
  15817. $icon
  15818. .removeClass(className.selected)
  15819. .removeClass(className.active)
  15820. ;
  15821. if(rating > 0) {
  15822. module.verbose('Setting current rating to', rating);
  15823. $activeIcon
  15824. .prevAll()
  15825. .addBack()
  15826. .addClass(className.active)
  15827. ;
  15828. }
  15829. if(!module.is.initialLoad()) {
  15830. settings.onRate.call(element, rating);
  15831. }
  15832. },
  15833. initialLoad: function() {
  15834. initialLoad = true;
  15835. }
  15836. },
  15837. setting: function(name, value) {
  15838. module.debug('Changing setting', name, value);
  15839. if( $.isPlainObject(name) ) {
  15840. $.extend(true, settings, name);
  15841. }
  15842. else if(value !== undefined) {
  15843. if($.isPlainObject(settings[name])) {
  15844. $.extend(true, settings[name], value);
  15845. }
  15846. else {
  15847. settings[name] = value;
  15848. }
  15849. }
  15850. else {
  15851. return settings[name];
  15852. }
  15853. },
  15854. internal: function(name, value) {
  15855. if( $.isPlainObject(name) ) {
  15856. $.extend(true, module, name);
  15857. }
  15858. else if(value !== undefined) {
  15859. module[name] = value;
  15860. }
  15861. else {
  15862. return module[name];
  15863. }
  15864. },
  15865. debug: function() {
  15866. if(!settings.silent && settings.debug) {
  15867. if(settings.performance) {
  15868. module.performance.log(arguments);
  15869. }
  15870. else {
  15871. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  15872. module.debug.apply(console, arguments);
  15873. }
  15874. }
  15875. },
  15876. verbose: function() {
  15877. if(!settings.silent && settings.verbose && settings.debug) {
  15878. if(settings.performance) {
  15879. module.performance.log(arguments);
  15880. }
  15881. else {
  15882. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  15883. module.verbose.apply(console, arguments);
  15884. }
  15885. }
  15886. },
  15887. error: function() {
  15888. if(!settings.silent) {
  15889. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  15890. module.error.apply(console, arguments);
  15891. }
  15892. },
  15893. performance: {
  15894. log: function(message) {
  15895. var
  15896. currentTime,
  15897. executionTime,
  15898. previousTime
  15899. ;
  15900. if(settings.performance) {
  15901. currentTime = new Date().getTime();
  15902. previousTime = time || currentTime;
  15903. executionTime = currentTime - previousTime;
  15904. time = currentTime;
  15905. performance.push({
  15906. 'Name' : message[0],
  15907. 'Arguments' : [].slice.call(message, 1) || '',
  15908. 'Element' : element,
  15909. 'Execution Time' : executionTime
  15910. });
  15911. }
  15912. clearTimeout(module.performance.timer);
  15913. module.performance.timer = setTimeout(module.performance.display, 500);
  15914. },
  15915. display: function() {
  15916. var
  15917. title = settings.name + ':',
  15918. totalTime = 0
  15919. ;
  15920. time = false;
  15921. clearTimeout(module.performance.timer);
  15922. $.each(performance, function(index, data) {
  15923. totalTime += data['Execution Time'];
  15924. });
  15925. title += ' ' + totalTime + 'ms';
  15926. if(moduleSelector) {
  15927. title += ' \'' + moduleSelector + '\'';
  15928. }
  15929. if($allModules.length > 1) {
  15930. title += ' ' + '(' + $allModules.length + ')';
  15931. }
  15932. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  15933. console.groupCollapsed(title);
  15934. if(console.table) {
  15935. console.table(performance);
  15936. }
  15937. else {
  15938. $.each(performance, function(index, data) {
  15939. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  15940. });
  15941. }
  15942. console.groupEnd();
  15943. }
  15944. performance = [];
  15945. }
  15946. },
  15947. invoke: function(query, passedArguments, context) {
  15948. var
  15949. object = instance,
  15950. maxDepth,
  15951. found,
  15952. response
  15953. ;
  15954. passedArguments = passedArguments || queryArguments;
  15955. context = element || context;
  15956. if(typeof query == 'string' && object !== undefined) {
  15957. query = query.split(/[\. ]/);
  15958. maxDepth = query.length - 1;
  15959. $.each(query, function(depth, value) {
  15960. var camelCaseValue = (depth != maxDepth)
  15961. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  15962. : query
  15963. ;
  15964. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  15965. object = object[camelCaseValue];
  15966. }
  15967. else if( object[camelCaseValue] !== undefined ) {
  15968. found = object[camelCaseValue];
  15969. return false;
  15970. }
  15971. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  15972. object = object[value];
  15973. }
  15974. else if( object[value] !== undefined ) {
  15975. found = object[value];
  15976. return false;
  15977. }
  15978. else {
  15979. return false;
  15980. }
  15981. });
  15982. }
  15983. if ( $.isFunction( found ) ) {
  15984. response = found.apply(context, passedArguments);
  15985. }
  15986. else if(found !== undefined) {
  15987. response = found;
  15988. }
  15989. if(Array.isArray(returnedValue)) {
  15990. returnedValue.push(response);
  15991. }
  15992. else if(returnedValue !== undefined) {
  15993. returnedValue = [returnedValue, response];
  15994. }
  15995. else if(response !== undefined) {
  15996. returnedValue = response;
  15997. }
  15998. return found;
  15999. }
  16000. };
  16001. if(methodInvoked) {
  16002. if(instance === undefined) {
  16003. module.initialize();
  16004. }
  16005. module.invoke(query);
  16006. }
  16007. else {
  16008. if(instance !== undefined) {
  16009. instance.invoke('destroy');
  16010. }
  16011. module.initialize();
  16012. }
  16013. })
  16014. ;
  16015. return (returnedValue !== undefined)
  16016. ? returnedValue
  16017. : this
  16018. ;
  16019. };
  16020. $.fn.rating.settings = {
  16021. name : 'Rating',
  16022. namespace : 'rating',
  16023. icon : 'star',
  16024. silent : false,
  16025. debug : false,
  16026. verbose : false,
  16027. performance : true,
  16028. initialRating : 0,
  16029. interactive : true,
  16030. maxRating : 4,
  16031. clearable : 'auto',
  16032. fireOnInit : false,
  16033. onRate : function(rating){},
  16034. error : {
  16035. method : 'The method you called is not defined',
  16036. noMaximum : 'No maximum rating specified. Cannot generate HTML automatically'
  16037. },
  16038. metadata: {
  16039. rating : 'rating',
  16040. maxRating : 'maxRating',
  16041. icon : 'icon'
  16042. },
  16043. className : {
  16044. active : 'active',
  16045. disabled : 'disabled',
  16046. selected : 'selected',
  16047. loading : 'loading'
  16048. },
  16049. selector : {
  16050. icon : '.icon'
  16051. },
  16052. templates: {
  16053. icon: function(maxRating, iconClass) {
  16054. var
  16055. icon = 1,
  16056. html = ''
  16057. ;
  16058. while(icon <= maxRating) {
  16059. html += '<i class="'+iconClass+' icon"></i>';
  16060. icon++;
  16061. }
  16062. return html;
  16063. }
  16064. }
  16065. };
  16066. })( jQuery, window, document );
  16067. /*!
  16068. * # Fomantic-UI - Search
  16069. * http://github.com/fomantic/Fomantic-UI/
  16070. *
  16071. *
  16072. * Released under the MIT license
  16073. * http://opensource.org/licenses/MIT
  16074. *
  16075. */
  16076. ;(function ($, window, document, undefined) {
  16077. 'use strict';
  16078. $.isFunction = $.isFunction || function(obj) {
  16079. return typeof obj === "function" && typeof obj.nodeType !== "number";
  16080. };
  16081. window = (typeof window != 'undefined' && window.Math == Math)
  16082. ? window
  16083. : (typeof self != 'undefined' && self.Math == Math)
  16084. ? self
  16085. : Function('return this')()
  16086. ;
  16087. $.fn.search = function(parameters) {
  16088. var
  16089. $allModules = $(this),
  16090. moduleSelector = $allModules.selector || '',
  16091. time = new Date().getTime(),
  16092. performance = [],
  16093. query = arguments[0],
  16094. methodInvoked = (typeof query == 'string'),
  16095. queryArguments = [].slice.call(arguments, 1),
  16096. returnedValue
  16097. ;
  16098. $(this)
  16099. .each(function() {
  16100. var
  16101. settings = ( $.isPlainObject(parameters) )
  16102. ? $.extend(true, {}, $.fn.search.settings, parameters)
  16103. : $.extend({}, $.fn.search.settings),
  16104. className = settings.className,
  16105. metadata = settings.metadata,
  16106. regExp = settings.regExp,
  16107. fields = settings.fields,
  16108. selector = settings.selector,
  16109. error = settings.error,
  16110. namespace = settings.namespace,
  16111. eventNamespace = '.' + namespace,
  16112. moduleNamespace = namespace + '-module',
  16113. $module = $(this),
  16114. $prompt = $module.find(selector.prompt),
  16115. $searchButton = $module.find(selector.searchButton),
  16116. $results = $module.find(selector.results),
  16117. $result = $module.find(selector.result),
  16118. $category = $module.find(selector.category),
  16119. element = this,
  16120. instance = $module.data(moduleNamespace),
  16121. disabledBubbled = false,
  16122. resultsDismissed = false,
  16123. module
  16124. ;
  16125. module = {
  16126. initialize: function() {
  16127. module.verbose('Initializing module');
  16128. module.get.settings();
  16129. module.determine.searchFields();
  16130. module.bind.events();
  16131. module.set.type();
  16132. module.create.results();
  16133. module.instantiate();
  16134. },
  16135. instantiate: function() {
  16136. module.verbose('Storing instance of module', module);
  16137. instance = module;
  16138. $module
  16139. .data(moduleNamespace, module)
  16140. ;
  16141. },
  16142. destroy: function() {
  16143. module.verbose('Destroying instance');
  16144. $module
  16145. .off(eventNamespace)
  16146. .removeData(moduleNamespace)
  16147. ;
  16148. },
  16149. refresh: function() {
  16150. module.debug('Refreshing selector cache');
  16151. $prompt = $module.find(selector.prompt);
  16152. $searchButton = $module.find(selector.searchButton);
  16153. $category = $module.find(selector.category);
  16154. $results = $module.find(selector.results);
  16155. $result = $module.find(selector.result);
  16156. },
  16157. refreshResults: function() {
  16158. $results = $module.find(selector.results);
  16159. $result = $module.find(selector.result);
  16160. },
  16161. bind: {
  16162. events: function() {
  16163. module.verbose('Binding events to search');
  16164. if(settings.automatic) {
  16165. $module
  16166. .on(module.get.inputEvent() + eventNamespace, selector.prompt, module.event.input)
  16167. ;
  16168. $prompt
  16169. .attr('autocomplete', 'off')
  16170. ;
  16171. }
  16172. $module
  16173. // prompt
  16174. .on('focus' + eventNamespace, selector.prompt, module.event.focus)
  16175. .on('blur' + eventNamespace, selector.prompt, module.event.blur)
  16176. .on('keydown' + eventNamespace, selector.prompt, module.handleKeyboard)
  16177. // search button
  16178. .on('click' + eventNamespace, selector.searchButton, module.query)
  16179. // results
  16180. .on('mousedown' + eventNamespace, selector.results, module.event.result.mousedown)
  16181. .on('mouseup' + eventNamespace, selector.results, module.event.result.mouseup)
  16182. .on('click' + eventNamespace, selector.result, module.event.result.click)
  16183. ;
  16184. }
  16185. },
  16186. determine: {
  16187. searchFields: function() {
  16188. // this makes sure $.extend does not add specified search fields to default fields
  16189. // this is the only setting which should not extend defaults
  16190. if(parameters && parameters.searchFields !== undefined) {
  16191. settings.searchFields = parameters.searchFields;
  16192. }
  16193. }
  16194. },
  16195. event: {
  16196. input: function() {
  16197. if(settings.searchDelay) {
  16198. clearTimeout(module.timer);
  16199. module.timer = setTimeout(function() {
  16200. if(module.is.focused()) {
  16201. module.query();
  16202. }
  16203. }, settings.searchDelay);
  16204. }
  16205. else {
  16206. module.query();
  16207. }
  16208. },
  16209. focus: function() {
  16210. module.set.focus();
  16211. if(settings.searchOnFocus && module.has.minimumCharacters() ) {
  16212. module.query(function() {
  16213. if(module.can.show() ) {
  16214. module.showResults();
  16215. }
  16216. });
  16217. }
  16218. },
  16219. blur: function(event) {
  16220. var
  16221. pageLostFocus = (document.activeElement === this),
  16222. callback = function() {
  16223. module.cancel.query();
  16224. module.remove.focus();
  16225. module.timer = setTimeout(module.hideResults, settings.hideDelay);
  16226. }
  16227. ;
  16228. if(pageLostFocus) {
  16229. return;
  16230. }
  16231. resultsDismissed = false;
  16232. if(module.resultsClicked) {
  16233. module.debug('Determining if user action caused search to close');
  16234. $module
  16235. .one('click.close' + eventNamespace, selector.results, function(event) {
  16236. if(module.is.inMessage(event) || disabledBubbled) {
  16237. $prompt.focus();
  16238. return;
  16239. }
  16240. disabledBubbled = false;
  16241. if( !module.is.animating() && !module.is.hidden()) {
  16242. callback();
  16243. }
  16244. })
  16245. ;
  16246. }
  16247. else {
  16248. module.debug('Input blurred without user action, closing results');
  16249. callback();
  16250. }
  16251. },
  16252. result: {
  16253. mousedown: function() {
  16254. module.resultsClicked = true;
  16255. },
  16256. mouseup: function() {
  16257. module.resultsClicked = false;
  16258. },
  16259. click: function(event) {
  16260. module.debug('Search result selected');
  16261. var
  16262. $result = $(this),
  16263. $title = $result.find(selector.title).eq(0),
  16264. $link = $result.is('a[href]')
  16265. ? $result
  16266. : $result.find('a[href]').eq(0),
  16267. href = $link.attr('href') || false,
  16268. target = $link.attr('target') || false,
  16269. // title is used for result lookup
  16270. value = ($title.length > 0)
  16271. ? $title.text()
  16272. : false,
  16273. results = module.get.results(),
  16274. result = $result.data(metadata.result) || module.get.result(value, results)
  16275. ;
  16276. if(value) {
  16277. module.set.value(value);
  16278. }
  16279. if( $.isFunction(settings.onSelect) ) {
  16280. if(settings.onSelect.call(element, result, results) === false) {
  16281. module.debug('Custom onSelect callback cancelled default select action');
  16282. disabledBubbled = true;
  16283. return;
  16284. }
  16285. }
  16286. module.hideResults();
  16287. if(href) {
  16288. module.verbose('Opening search link found in result', $link);
  16289. if(target == '_blank' || event.ctrlKey) {
  16290. window.open(href);
  16291. }
  16292. else {
  16293. window.location.href = (href);
  16294. }
  16295. }
  16296. }
  16297. }
  16298. },
  16299. handleKeyboard: function(event) {
  16300. var
  16301. // force selector refresh
  16302. $result = $module.find(selector.result),
  16303. $category = $module.find(selector.category),
  16304. $activeResult = $result.filter('.' + className.active),
  16305. currentIndex = $result.index( $activeResult ),
  16306. resultSize = $result.length,
  16307. hasActiveResult = $activeResult.length > 0,
  16308. keyCode = event.which,
  16309. keys = {
  16310. backspace : 8,
  16311. enter : 13,
  16312. escape : 27,
  16313. upArrow : 38,
  16314. downArrow : 40
  16315. },
  16316. newIndex
  16317. ;
  16318. // search shortcuts
  16319. if(keyCode == keys.escape) {
  16320. module.verbose('Escape key pressed, blurring search field');
  16321. module.hideResults();
  16322. resultsDismissed = true;
  16323. }
  16324. if( module.is.visible() ) {
  16325. if(keyCode == keys.enter) {
  16326. module.verbose('Enter key pressed, selecting active result');
  16327. if( $result.filter('.' + className.active).length > 0 ) {
  16328. module.event.result.click.call($result.filter('.' + className.active), event);
  16329. event.preventDefault();
  16330. return false;
  16331. }
  16332. }
  16333. else if(keyCode == keys.upArrow && hasActiveResult) {
  16334. module.verbose('Up key pressed, changing active result');
  16335. newIndex = (currentIndex - 1 < 0)
  16336. ? currentIndex
  16337. : currentIndex - 1
  16338. ;
  16339. $category
  16340. .removeClass(className.active)
  16341. ;
  16342. $result
  16343. .removeClass(className.active)
  16344. .eq(newIndex)
  16345. .addClass(className.active)
  16346. .closest($category)
  16347. .addClass(className.active)
  16348. ;
  16349. event.preventDefault();
  16350. }
  16351. else if(keyCode == keys.downArrow) {
  16352. module.verbose('Down key pressed, changing active result');
  16353. newIndex = (currentIndex + 1 >= resultSize)
  16354. ? currentIndex
  16355. : currentIndex + 1
  16356. ;
  16357. $category
  16358. .removeClass(className.active)
  16359. ;
  16360. $result
  16361. .removeClass(className.active)
  16362. .eq(newIndex)
  16363. .addClass(className.active)
  16364. .closest($category)
  16365. .addClass(className.active)
  16366. ;
  16367. event.preventDefault();
  16368. }
  16369. }
  16370. else {
  16371. // query shortcuts
  16372. if(keyCode == keys.enter) {
  16373. module.verbose('Enter key pressed, executing query');
  16374. module.query();
  16375. module.set.buttonPressed();
  16376. $prompt.one('keyup', module.remove.buttonFocus);
  16377. }
  16378. }
  16379. },
  16380. setup: {
  16381. api: function(searchTerm, callback) {
  16382. var
  16383. apiSettings = {
  16384. debug : settings.debug,
  16385. on : false,
  16386. cache : settings.cache,
  16387. action : 'search',
  16388. urlData : {
  16389. query : searchTerm
  16390. },
  16391. onSuccess : function(response) {
  16392. module.parse.response.call(element, response, searchTerm);
  16393. callback();
  16394. },
  16395. onFailure : function() {
  16396. module.displayMessage(error.serverError);
  16397. callback();
  16398. },
  16399. onAbort : function(response) {
  16400. },
  16401. onError : module.error
  16402. }
  16403. ;
  16404. $.extend(true, apiSettings, settings.apiSettings);
  16405. module.verbose('Setting up API request', apiSettings);
  16406. $module.api(apiSettings);
  16407. }
  16408. },
  16409. can: {
  16410. useAPI: function() {
  16411. return $.fn.api !== undefined;
  16412. },
  16413. show: function() {
  16414. return module.is.focused() && !module.is.visible() && !module.is.empty();
  16415. },
  16416. transition: function() {
  16417. return settings.transition && $.fn.transition !== undefined && $module.transition('is supported');
  16418. }
  16419. },
  16420. is: {
  16421. animating: function() {
  16422. return $results.hasClass(className.animating);
  16423. },
  16424. hidden: function() {
  16425. return $results.hasClass(className.hidden);
  16426. },
  16427. inMessage: function(event) {
  16428. if(!event.target) {
  16429. return;
  16430. }
  16431. var
  16432. $target = $(event.target),
  16433. isInDOM = $.contains(document.documentElement, event.target)
  16434. ;
  16435. return (isInDOM && $target.closest(selector.message).length > 0);
  16436. },
  16437. empty: function() {
  16438. return ($results.html() === '');
  16439. },
  16440. visible: function() {
  16441. return ($results.filter(':visible').length > 0);
  16442. },
  16443. focused: function() {
  16444. return ($prompt.filter(':focus').length > 0);
  16445. }
  16446. },
  16447. get: {
  16448. settings: function() {
  16449. if($.isPlainObject(parameters) && parameters.searchFullText) {
  16450. settings.fullTextSearch = parameters.searchFullText;
  16451. module.error(settings.error.oldSearchSyntax, element);
  16452. }
  16453. if (settings.ignoreDiacritics && !String.prototype.normalize) {
  16454. settings.ignoreDiacritics = false;
  16455. module.error(error.noNormalize, element);
  16456. }
  16457. },
  16458. inputEvent: function() {
  16459. var
  16460. prompt = $prompt[0],
  16461. inputEvent = (prompt !== undefined && prompt.oninput !== undefined)
  16462. ? 'input'
  16463. : (prompt !== undefined && prompt.onpropertychange !== undefined)
  16464. ? 'propertychange'
  16465. : 'keyup'
  16466. ;
  16467. return inputEvent;
  16468. },
  16469. value: function() {
  16470. return $prompt.val();
  16471. },
  16472. results: function() {
  16473. var
  16474. results = $module.data(metadata.results)
  16475. ;
  16476. return results;
  16477. },
  16478. result: function(value, results) {
  16479. var
  16480. result = false
  16481. ;
  16482. value = (value !== undefined)
  16483. ? value
  16484. : module.get.value()
  16485. ;
  16486. results = (results !== undefined)
  16487. ? results
  16488. : module.get.results()
  16489. ;
  16490. if(settings.type === 'category') {
  16491. module.debug('Finding result that matches', value);
  16492. $.each(results, function(index, category) {
  16493. if(Array.isArray(category.results)) {
  16494. result = module.search.object(value, category.results)[0];
  16495. // don't continue searching if a result is found
  16496. if(result) {
  16497. return false;
  16498. }
  16499. }
  16500. });
  16501. }
  16502. else {
  16503. module.debug('Finding result in results object', value);
  16504. result = module.search.object(value, results)[0];
  16505. }
  16506. return result || false;
  16507. },
  16508. },
  16509. select: {
  16510. firstResult: function() {
  16511. module.verbose('Selecting first result');
  16512. $result.first().addClass(className.active);
  16513. }
  16514. },
  16515. set: {
  16516. focus: function() {
  16517. $module.addClass(className.focus);
  16518. },
  16519. loading: function() {
  16520. $module.addClass(className.loading);
  16521. },
  16522. value: function(value) {
  16523. module.verbose('Setting search input value', value);
  16524. $prompt
  16525. .val(value)
  16526. ;
  16527. },
  16528. type: function(type) {
  16529. type = type || settings.type;
  16530. if(settings.type == 'category') {
  16531. $module.addClass(settings.type);
  16532. }
  16533. },
  16534. buttonPressed: function() {
  16535. $searchButton.addClass(className.pressed);
  16536. }
  16537. },
  16538. remove: {
  16539. loading: function() {
  16540. $module.removeClass(className.loading);
  16541. },
  16542. focus: function() {
  16543. $module.removeClass(className.focus);
  16544. },
  16545. buttonPressed: function() {
  16546. $searchButton.removeClass(className.pressed);
  16547. },
  16548. diacritics: function(text) {
  16549. return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : text;
  16550. }
  16551. },
  16552. query: function(callback) {
  16553. callback = $.isFunction(callback)
  16554. ? callback
  16555. : function(){}
  16556. ;
  16557. var
  16558. searchTerm = module.get.value(),
  16559. cache = module.read.cache(searchTerm)
  16560. ;
  16561. callback = callback || function() {};
  16562. if( module.has.minimumCharacters() ) {
  16563. if(cache) {
  16564. module.debug('Reading result from cache', searchTerm);
  16565. module.save.results(cache.results);
  16566. module.addResults(cache.html);
  16567. module.inject.id(cache.results);
  16568. callback();
  16569. }
  16570. else {
  16571. module.debug('Querying for', searchTerm);
  16572. if($.isPlainObject(settings.source) || Array.isArray(settings.source)) {
  16573. module.search.local(searchTerm);
  16574. callback();
  16575. }
  16576. else if( module.can.useAPI() ) {
  16577. module.search.remote(searchTerm, callback);
  16578. }
  16579. else {
  16580. module.error(error.source);
  16581. callback();
  16582. }
  16583. }
  16584. settings.onSearchQuery.call(element, searchTerm);
  16585. }
  16586. else {
  16587. module.hideResults();
  16588. }
  16589. },
  16590. search: {
  16591. local: function(searchTerm) {
  16592. var
  16593. results = module.search.object(searchTerm, settings.source),
  16594. searchHTML
  16595. ;
  16596. module.set.loading();
  16597. module.save.results(results);
  16598. module.debug('Returned full local search results', results);
  16599. if(settings.maxResults > 0) {
  16600. module.debug('Using specified max results', results);
  16601. results = results.slice(0, settings.maxResults);
  16602. }
  16603. if(settings.type == 'category') {
  16604. results = module.create.categoryResults(results);
  16605. }
  16606. searchHTML = module.generateResults({
  16607. results: results
  16608. });
  16609. module.remove.loading();
  16610. module.addResults(searchHTML);
  16611. module.inject.id(results);
  16612. module.write.cache(searchTerm, {
  16613. html : searchHTML,
  16614. results : results
  16615. });
  16616. },
  16617. remote: function(searchTerm, callback) {
  16618. callback = $.isFunction(callback)
  16619. ? callback
  16620. : function(){}
  16621. ;
  16622. if($module.api('is loading')) {
  16623. $module.api('abort');
  16624. }
  16625. module.setup.api(searchTerm, callback);
  16626. $module
  16627. .api('query')
  16628. ;
  16629. },
  16630. object: function(searchTerm, source, searchFields) {
  16631. searchTerm = module.remove.diacritics(String(searchTerm));
  16632. var
  16633. results = [],
  16634. exactResults = [],
  16635. fuzzyResults = [],
  16636. searchExp = searchTerm.replace(regExp.escape, '\\$&'),
  16637. matchRegExp = new RegExp(regExp.beginsWith + searchExp, 'i'),
  16638. // avoid duplicates when pushing results
  16639. addResult = function(array, result) {
  16640. var
  16641. notResult = ($.inArray(result, results) == -1),
  16642. notFuzzyResult = ($.inArray(result, fuzzyResults) == -1),
  16643. notExactResults = ($.inArray(result, exactResults) == -1)
  16644. ;
  16645. if(notResult && notFuzzyResult && notExactResults) {
  16646. array.push(result);
  16647. }
  16648. }
  16649. ;
  16650. source = source || settings.source;
  16651. searchFields = (searchFields !== undefined)
  16652. ? searchFields
  16653. : settings.searchFields
  16654. ;
  16655. // search fields should be array to loop correctly
  16656. if(!Array.isArray(searchFields)) {
  16657. searchFields = [searchFields];
  16658. }
  16659. // exit conditions if no source
  16660. if(source === undefined || source === false) {
  16661. module.error(error.source);
  16662. return [];
  16663. }
  16664. // iterate through search fields looking for matches
  16665. $.each(searchFields, function(index, field) {
  16666. $.each(source, function(label, content) {
  16667. var
  16668. fieldExists = (typeof content[field] == 'string') || (typeof content[field] == 'number')
  16669. ;
  16670. if(fieldExists) {
  16671. var text;
  16672. if (typeof content[field] === 'string'){
  16673. text = module.remove.diacritics(content[field]);
  16674. } else {
  16675. text = content[field].toString();
  16676. }
  16677. if( text.search(matchRegExp) !== -1) {
  16678. // content starts with value (first in results)
  16679. addResult(results, content);
  16680. }
  16681. else if(settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text) ) {
  16682. // content fuzzy matches (last in results)
  16683. addResult(exactResults, content);
  16684. }
  16685. else if(settings.fullTextSearch == true && module.fuzzySearch(searchTerm, text) ) {
  16686. // content fuzzy matches (last in results)
  16687. addResult(fuzzyResults, content);
  16688. }
  16689. }
  16690. });
  16691. });
  16692. $.merge(exactResults, fuzzyResults);
  16693. $.merge(results, exactResults);
  16694. return results;
  16695. }
  16696. },
  16697. exactSearch: function (query, term) {
  16698. query = query.toLowerCase();
  16699. term = term.toLowerCase();
  16700. return term.indexOf(query) > -1;
  16701. },
  16702. fuzzySearch: function(query, term) {
  16703. var
  16704. termLength = term.length,
  16705. queryLength = query.length
  16706. ;
  16707. if(typeof query !== 'string') {
  16708. return false;
  16709. }
  16710. query = query.toLowerCase();
  16711. term = term.toLowerCase();
  16712. if(queryLength > termLength) {
  16713. return false;
  16714. }
  16715. if(queryLength === termLength) {
  16716. return (query === term);
  16717. }
  16718. search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
  16719. var
  16720. queryCharacter = query.charCodeAt(characterIndex)
  16721. ;
  16722. while(nextCharacterIndex < termLength) {
  16723. if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
  16724. continue search;
  16725. }
  16726. }
  16727. return false;
  16728. }
  16729. return true;
  16730. },
  16731. parse: {
  16732. response: function(response, searchTerm) {
  16733. if(Array.isArray(response)){
  16734. var o={};
  16735. o[fields.results]=response;
  16736. response = o;
  16737. }
  16738. var
  16739. searchHTML = module.generateResults(response)
  16740. ;
  16741. module.verbose('Parsing server response', response);
  16742. if(response !== undefined) {
  16743. if(searchTerm !== undefined && response[fields.results] !== undefined) {
  16744. module.addResults(searchHTML);
  16745. module.inject.id(response[fields.results]);
  16746. module.write.cache(searchTerm, {
  16747. html : searchHTML,
  16748. results : response[fields.results]
  16749. });
  16750. module.save.results(response[fields.results]);
  16751. }
  16752. }
  16753. }
  16754. },
  16755. cancel: {
  16756. query: function() {
  16757. if( module.can.useAPI() ) {
  16758. $module.api('abort');
  16759. }
  16760. }
  16761. },
  16762. has: {
  16763. minimumCharacters: function() {
  16764. var
  16765. searchTerm = module.get.value(),
  16766. numCharacters = searchTerm.length
  16767. ;
  16768. return (numCharacters >= settings.minCharacters);
  16769. },
  16770. results: function() {
  16771. if($results.length === 0) {
  16772. return false;
  16773. }
  16774. var
  16775. html = $results.html()
  16776. ;
  16777. return html != '';
  16778. }
  16779. },
  16780. clear: {
  16781. cache: function(value) {
  16782. var
  16783. cache = $module.data(metadata.cache)
  16784. ;
  16785. if(!value) {
  16786. module.debug('Clearing cache', value);
  16787. $module.removeData(metadata.cache);
  16788. }
  16789. else if(value && cache && cache[value]) {
  16790. module.debug('Removing value from cache', value);
  16791. delete cache[value];
  16792. $module.data(metadata.cache, cache);
  16793. }
  16794. }
  16795. },
  16796. read: {
  16797. cache: function(name) {
  16798. var
  16799. cache = $module.data(metadata.cache)
  16800. ;
  16801. if(settings.cache) {
  16802. module.verbose('Checking cache for generated html for query', name);
  16803. return (typeof cache == 'object') && (cache[name] !== undefined)
  16804. ? cache[name]
  16805. : false
  16806. ;
  16807. }
  16808. return false;
  16809. }
  16810. },
  16811. create: {
  16812. categoryResults: function(results) {
  16813. var
  16814. categoryResults = {}
  16815. ;
  16816. $.each(results, function(index, result) {
  16817. if(!result.category) {
  16818. return;
  16819. }
  16820. if(categoryResults[result.category] === undefined) {
  16821. module.verbose('Creating new category of results', result.category);
  16822. categoryResults[result.category] = {
  16823. name : result.category,
  16824. results : [result]
  16825. };
  16826. }
  16827. else {
  16828. categoryResults[result.category].results.push(result);
  16829. }
  16830. });
  16831. return categoryResults;
  16832. },
  16833. id: function(resultIndex, categoryIndex) {
  16834. var
  16835. resultID = (resultIndex + 1), // not zero indexed
  16836. letterID,
  16837. id
  16838. ;
  16839. if(categoryIndex !== undefined) {
  16840. // start char code for "A"
  16841. letterID = String.fromCharCode(97 + categoryIndex);
  16842. id = letterID + resultID;
  16843. module.verbose('Creating category result id', id);
  16844. }
  16845. else {
  16846. id = resultID;
  16847. module.verbose('Creating result id', id);
  16848. }
  16849. return id;
  16850. },
  16851. results: function() {
  16852. if($results.length === 0) {
  16853. $results = $('<div />')
  16854. .addClass(className.results)
  16855. .appendTo($module)
  16856. ;
  16857. }
  16858. }
  16859. },
  16860. inject: {
  16861. result: function(result, resultIndex, categoryIndex) {
  16862. module.verbose('Injecting result into results');
  16863. var
  16864. $selectedResult = (categoryIndex !== undefined)
  16865. ? $results
  16866. .children().eq(categoryIndex)
  16867. .children(selector.results)
  16868. .first()
  16869. .children(selector.result)
  16870. .eq(resultIndex)
  16871. : $results
  16872. .children(selector.result).eq(resultIndex)
  16873. ;
  16874. module.verbose('Injecting results metadata', $selectedResult);
  16875. $selectedResult
  16876. .data(metadata.result, result)
  16877. ;
  16878. },
  16879. id: function(results) {
  16880. module.debug('Injecting unique ids into results');
  16881. var
  16882. // since results may be object, we must use counters
  16883. categoryIndex = 0,
  16884. resultIndex = 0
  16885. ;
  16886. if(settings.type === 'category') {
  16887. // iterate through each category result
  16888. $.each(results, function(index, category) {
  16889. if(category.results.length > 0){
  16890. resultIndex = 0;
  16891. $.each(category.results, function(index, result) {
  16892. if(result.id === undefined) {
  16893. result.id = module.create.id(resultIndex, categoryIndex);
  16894. }
  16895. module.inject.result(result, resultIndex, categoryIndex);
  16896. resultIndex++;
  16897. });
  16898. categoryIndex++;
  16899. }
  16900. });
  16901. }
  16902. else {
  16903. // top level
  16904. $.each(results, function(index, result) {
  16905. if(result.id === undefined) {
  16906. result.id = module.create.id(resultIndex);
  16907. }
  16908. module.inject.result(result, resultIndex);
  16909. resultIndex++;
  16910. });
  16911. }
  16912. return results;
  16913. }
  16914. },
  16915. save: {
  16916. results: function(results) {
  16917. module.verbose('Saving current search results to metadata', results);
  16918. $module.data(metadata.results, results);
  16919. }
  16920. },
  16921. write: {
  16922. cache: function(name, value) {
  16923. var
  16924. cache = ($module.data(metadata.cache) !== undefined)
  16925. ? $module.data(metadata.cache)
  16926. : {}
  16927. ;
  16928. if(settings.cache) {
  16929. module.verbose('Writing generated html to cache', name, value);
  16930. cache[name] = value;
  16931. $module
  16932. .data(metadata.cache, cache)
  16933. ;
  16934. }
  16935. }
  16936. },
  16937. addResults: function(html) {
  16938. if( $.isFunction(settings.onResultsAdd) ) {
  16939. if( settings.onResultsAdd.call($results, html) === false ) {
  16940. module.debug('onResultsAdd callback cancelled default action');
  16941. return false;
  16942. }
  16943. }
  16944. if(html) {
  16945. $results
  16946. .html(html)
  16947. ;
  16948. module.refreshResults();
  16949. if(settings.selectFirstResult) {
  16950. module.select.firstResult();
  16951. }
  16952. module.showResults();
  16953. }
  16954. else {
  16955. module.hideResults(function() {
  16956. $results.empty();
  16957. });
  16958. }
  16959. },
  16960. showResults: function(callback) {
  16961. callback = $.isFunction(callback)
  16962. ? callback
  16963. : function(){}
  16964. ;
  16965. if(resultsDismissed) {
  16966. return;
  16967. }
  16968. if(!module.is.visible() && module.has.results()) {
  16969. if( module.can.transition() ) {
  16970. module.debug('Showing results with css animations');
  16971. $results
  16972. .transition({
  16973. animation : settings.transition + ' in',
  16974. debug : settings.debug,
  16975. verbose : settings.verbose,
  16976. duration : settings.duration,
  16977. onComplete : function() {
  16978. callback();
  16979. },
  16980. queue : true
  16981. })
  16982. ;
  16983. }
  16984. else {
  16985. module.debug('Showing results with javascript');
  16986. $results
  16987. .stop()
  16988. .fadeIn(settings.duration, settings.easing)
  16989. ;
  16990. }
  16991. settings.onResultsOpen.call($results);
  16992. }
  16993. },
  16994. hideResults: function(callback) {
  16995. callback = $.isFunction(callback)
  16996. ? callback
  16997. : function(){}
  16998. ;
  16999. if( module.is.visible() ) {
  17000. if( module.can.transition() ) {
  17001. module.debug('Hiding results with css animations');
  17002. $results
  17003. .transition({
  17004. animation : settings.transition + ' out',
  17005. debug : settings.debug,
  17006. verbose : settings.verbose,
  17007. duration : settings.duration,
  17008. onComplete : function() {
  17009. callback();
  17010. },
  17011. queue : true
  17012. })
  17013. ;
  17014. }
  17015. else {
  17016. module.debug('Hiding results with javascript');
  17017. $results
  17018. .stop()
  17019. .fadeOut(settings.duration, settings.easing)
  17020. ;
  17021. }
  17022. settings.onResultsClose.call($results);
  17023. }
  17024. },
  17025. generateResults: function(response) {
  17026. module.debug('Generating html from response', response);
  17027. var
  17028. template = settings.templates[settings.type],
  17029. isProperObject = ($.isPlainObject(response[fields.results]) && !$.isEmptyObject(response[fields.results])),
  17030. isProperArray = (Array.isArray(response[fields.results]) && response[fields.results].length > 0),
  17031. html = ''
  17032. ;
  17033. if(isProperObject || isProperArray ) {
  17034. if(settings.maxResults > 0) {
  17035. if(isProperObject) {
  17036. if(settings.type == 'standard') {
  17037. module.error(error.maxResults);
  17038. }
  17039. }
  17040. else {
  17041. response[fields.results] = response[fields.results].slice(0, settings.maxResults);
  17042. }
  17043. }
  17044. if($.isFunction(template)) {
  17045. html = template(response, fields, settings.preserveHTML);
  17046. }
  17047. else {
  17048. module.error(error.noTemplate, false);
  17049. }
  17050. }
  17051. else if(settings.showNoResults) {
  17052. html = module.displayMessage(error.noResults, 'empty', error.noResultsHeader);
  17053. }
  17054. settings.onResults.call(element, response);
  17055. return html;
  17056. },
  17057. displayMessage: function(text, type, header) {
  17058. type = type || 'standard';
  17059. module.debug('Displaying message', text, type, header);
  17060. module.addResults( settings.templates.message(text, type, header) );
  17061. return settings.templates.message(text, type, header);
  17062. },
  17063. setting: function(name, value) {
  17064. if( $.isPlainObject(name) ) {
  17065. $.extend(true, settings, name);
  17066. }
  17067. else if(value !== undefined) {
  17068. settings[name] = value;
  17069. }
  17070. else {
  17071. return settings[name];
  17072. }
  17073. },
  17074. internal: function(name, value) {
  17075. if( $.isPlainObject(name) ) {
  17076. $.extend(true, module, name);
  17077. }
  17078. else if(value !== undefined) {
  17079. module[name] = value;
  17080. }
  17081. else {
  17082. return module[name];
  17083. }
  17084. },
  17085. debug: function() {
  17086. if(!settings.silent && settings.debug) {
  17087. if(settings.performance) {
  17088. module.performance.log(arguments);
  17089. }
  17090. else {
  17091. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  17092. module.debug.apply(console, arguments);
  17093. }
  17094. }
  17095. },
  17096. verbose: function() {
  17097. if(!settings.silent && settings.verbose && settings.debug) {
  17098. if(settings.performance) {
  17099. module.performance.log(arguments);
  17100. }
  17101. else {
  17102. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  17103. module.verbose.apply(console, arguments);
  17104. }
  17105. }
  17106. },
  17107. error: function() {
  17108. if(!settings.silent) {
  17109. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  17110. module.error.apply(console, arguments);
  17111. }
  17112. },
  17113. performance: {
  17114. log: function(message) {
  17115. var
  17116. currentTime,
  17117. executionTime,
  17118. previousTime
  17119. ;
  17120. if(settings.performance) {
  17121. currentTime = new Date().getTime();
  17122. previousTime = time || currentTime;
  17123. executionTime = currentTime - previousTime;
  17124. time = currentTime;
  17125. performance.push({
  17126. 'Name' : message[0],
  17127. 'Arguments' : [].slice.call(message, 1) || '',
  17128. 'Element' : element,
  17129. 'Execution Time' : executionTime
  17130. });
  17131. }
  17132. clearTimeout(module.performance.timer);
  17133. module.performance.timer = setTimeout(module.performance.display, 500);
  17134. },
  17135. display: function() {
  17136. var
  17137. title = settings.name + ':',
  17138. totalTime = 0
  17139. ;
  17140. time = false;
  17141. clearTimeout(module.performance.timer);
  17142. $.each(performance, function(index, data) {
  17143. totalTime += data['Execution Time'];
  17144. });
  17145. title += ' ' + totalTime + 'ms';
  17146. if(moduleSelector) {
  17147. title += ' \'' + moduleSelector + '\'';
  17148. }
  17149. if($allModules.length > 1) {
  17150. title += ' ' + '(' + $allModules.length + ')';
  17151. }
  17152. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  17153. console.groupCollapsed(title);
  17154. if(console.table) {
  17155. console.table(performance);
  17156. }
  17157. else {
  17158. $.each(performance, function(index, data) {
  17159. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  17160. });
  17161. }
  17162. console.groupEnd();
  17163. }
  17164. performance = [];
  17165. }
  17166. },
  17167. invoke: function(query, passedArguments, context) {
  17168. var
  17169. object = instance,
  17170. maxDepth,
  17171. found,
  17172. response
  17173. ;
  17174. passedArguments = passedArguments || queryArguments;
  17175. context = element || context;
  17176. if(typeof query == 'string' && object !== undefined) {
  17177. query = query.split(/[\. ]/);
  17178. maxDepth = query.length - 1;
  17179. $.each(query, function(depth, value) {
  17180. var camelCaseValue = (depth != maxDepth)
  17181. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  17182. : query
  17183. ;
  17184. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  17185. object = object[camelCaseValue];
  17186. }
  17187. else if( object[camelCaseValue] !== undefined ) {
  17188. found = object[camelCaseValue];
  17189. return false;
  17190. }
  17191. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  17192. object = object[value];
  17193. }
  17194. else if( object[value] !== undefined ) {
  17195. found = object[value];
  17196. return false;
  17197. }
  17198. else {
  17199. return false;
  17200. }
  17201. });
  17202. }
  17203. if( $.isFunction( found ) ) {
  17204. response = found.apply(context, passedArguments);
  17205. }
  17206. else if(found !== undefined) {
  17207. response = found;
  17208. }
  17209. if(Array.isArray(returnedValue)) {
  17210. returnedValue.push(response);
  17211. }
  17212. else if(returnedValue !== undefined) {
  17213. returnedValue = [returnedValue, response];
  17214. }
  17215. else if(response !== undefined) {
  17216. returnedValue = response;
  17217. }
  17218. return found;
  17219. }
  17220. };
  17221. if(methodInvoked) {
  17222. if(instance === undefined) {
  17223. module.initialize();
  17224. }
  17225. module.invoke(query);
  17226. }
  17227. else {
  17228. if(instance !== undefined) {
  17229. instance.invoke('destroy');
  17230. }
  17231. module.initialize();
  17232. }
  17233. })
  17234. ;
  17235. return (returnedValue !== undefined)
  17236. ? returnedValue
  17237. : this
  17238. ;
  17239. };
  17240. $.fn.search.settings = {
  17241. name : 'Search',
  17242. namespace : 'search',
  17243. silent : false,
  17244. debug : false,
  17245. verbose : false,
  17246. performance : true,
  17247. // template to use (specified in settings.templates)
  17248. type : 'standard',
  17249. // minimum characters required to search
  17250. minCharacters : 1,
  17251. // whether to select first result after searching automatically
  17252. selectFirstResult : false,
  17253. // API config
  17254. apiSettings : false,
  17255. // object to search
  17256. source : false,
  17257. // Whether search should query current term on focus
  17258. searchOnFocus : true,
  17259. // fields to search
  17260. searchFields : [
  17261. 'id',
  17262. 'title',
  17263. 'description'
  17264. ],
  17265. // field to display in standard results template
  17266. displayField : '',
  17267. // search anywhere in value (set to 'exact' to require exact matches
  17268. fullTextSearch : 'exact',
  17269. // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
  17270. ignoreDiacritics : false,
  17271. // whether to add events to prompt automatically
  17272. automatic : true,
  17273. // delay before hiding menu after blur
  17274. hideDelay : 0,
  17275. // delay before searching
  17276. searchDelay : 200,
  17277. // maximum results returned from search
  17278. maxResults : 7,
  17279. // whether to store lookups in local cache
  17280. cache : true,
  17281. // whether no results errors should be shown
  17282. showNoResults : true,
  17283. // preserve possible html of resultset values
  17284. preserveHTML : true,
  17285. // transition settings
  17286. transition : 'scale',
  17287. duration : 200,
  17288. easing : 'easeOutExpo',
  17289. // callbacks
  17290. onSelect : false,
  17291. onResultsAdd : false,
  17292. onSearchQuery : function(query){},
  17293. onResults : function(response){},
  17294. onResultsOpen : function(){},
  17295. onResultsClose : function(){},
  17296. className: {
  17297. animating : 'animating',
  17298. active : 'active',
  17299. empty : 'empty',
  17300. focus : 'focus',
  17301. hidden : 'hidden',
  17302. loading : 'loading',
  17303. results : 'results',
  17304. pressed : 'down'
  17305. },
  17306. error : {
  17307. source : 'Cannot search. No source used, and Semantic API module was not included',
  17308. noResultsHeader : 'No Results',
  17309. noResults : 'Your search returned no results',
  17310. logging : 'Error in debug logging, exiting.',
  17311. noEndpoint : 'No search endpoint was specified',
  17312. noTemplate : 'A valid template name was not specified.',
  17313. oldSearchSyntax : 'searchFullText setting has been renamed fullTextSearch for consistency, please adjust your settings.',
  17314. serverError : 'There was an issue querying the server.',
  17315. maxResults : 'Results must be an array to use maxResults setting',
  17316. method : 'The method you called is not defined.',
  17317. noNormalize : '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.'
  17318. },
  17319. metadata: {
  17320. cache : 'cache',
  17321. results : 'results',
  17322. result : 'result'
  17323. },
  17324. regExp: {
  17325. escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
  17326. beginsWith : '(?:\s|^)'
  17327. },
  17328. // maps api response attributes to internal representation
  17329. fields: {
  17330. categories : 'results', // array of categories (category view)
  17331. categoryName : 'name', // name of category (category view)
  17332. categoryResults : 'results', // array of results (category view)
  17333. description : 'description', // result description
  17334. image : 'image', // result image
  17335. price : 'price', // result price
  17336. results : 'results', // array of results (standard)
  17337. title : 'title', // result title
  17338. url : 'url', // result url
  17339. action : 'action', // "view more" object name
  17340. actionText : 'text', // "view more" text
  17341. actionURL : 'url' // "view more" url
  17342. },
  17343. selector : {
  17344. prompt : '.prompt',
  17345. searchButton : '.search.button',
  17346. results : '.results',
  17347. message : '.results > .message',
  17348. category : '.category',
  17349. result : '.result',
  17350. title : '.title, .name'
  17351. },
  17352. templates: {
  17353. escape: function(string, preserveHTML) {
  17354. if (preserveHTML){
  17355. return string;
  17356. }
  17357. var
  17358. badChars = /[&<>"'`]/g,
  17359. shouldEscape = /[&<>"'`]/,
  17360. escape = {
  17361. "&": "&amp;",
  17362. "<": "&lt;",
  17363. ">": "&gt;",
  17364. '"': "&quot;",
  17365. "'": "&#x27;",
  17366. "`": "&#x60;"
  17367. },
  17368. escapedChar = function(chr) {
  17369. return escape[chr];
  17370. }
  17371. ;
  17372. if(shouldEscape.test(string)) {
  17373. return string.replace(badChars, escapedChar);
  17374. }
  17375. return string;
  17376. },
  17377. message: function(message, type, header) {
  17378. var
  17379. html = ''
  17380. ;
  17381. if(message !== undefined && type !== undefined) {
  17382. html += ''
  17383. + '<div class="message ' + type + '">'
  17384. ;
  17385. if(header) {
  17386. html += ''
  17387. + '<div class="header">' + header + '</div>'
  17388. ;
  17389. }
  17390. html += ' <div class="description">' + message + '</div>';
  17391. html += '</div>';
  17392. }
  17393. return html;
  17394. },
  17395. category: function(response, fields, preserveHTML) {
  17396. var
  17397. html = '',
  17398. escape = $.fn.search.settings.templates.escape
  17399. ;
  17400. if(response[fields.categoryResults] !== undefined) {
  17401. // each category
  17402. $.each(response[fields.categoryResults], function(index, category) {
  17403. if(category[fields.results] !== undefined && category.results.length > 0) {
  17404. html += '<div class="category">';
  17405. if(category[fields.categoryName] !== undefined) {
  17406. html += '<div class="name">' + escape(category[fields.categoryName], preserveHTML) + '</div>';
  17407. }
  17408. // each item inside category
  17409. html += '<div class="results">';
  17410. $.each(category.results, function(index, result) {
  17411. if(result[fields.url]) {
  17412. html += '<a class="result" href="' + result[fields.url].replace(/"/g,"") + '">';
  17413. }
  17414. else {
  17415. html += '<a class="result">';
  17416. }
  17417. if(result[fields.image] !== undefined) {
  17418. html += ''
  17419. + '<div class="image">'
  17420. + ' <img src="' + result[fields.image].replace(/"/g,"") + '">'
  17421. + '</div>'
  17422. ;
  17423. }
  17424. html += '<div class="content">';
  17425. if(result[fields.price] !== undefined) {
  17426. html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
  17427. }
  17428. if(result[fields.title] !== undefined) {
  17429. html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
  17430. }
  17431. if(result[fields.description] !== undefined) {
  17432. html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
  17433. }
  17434. html += ''
  17435. + '</div>'
  17436. ;
  17437. html += '</a>';
  17438. });
  17439. html += '</div>';
  17440. html += ''
  17441. + '</div>'
  17442. ;
  17443. }
  17444. });
  17445. if(response[fields.action]) {
  17446. if(fields.actionURL === false) {
  17447. html += ''
  17448. + '<div class="action">'
  17449. + escape(response[fields.action][fields.actionText], preserveHTML)
  17450. + '</div>';
  17451. } else {
  17452. html += ''
  17453. + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g,"") + '" class="action">'
  17454. + escape(response[fields.action][fields.actionText], preserveHTML)
  17455. + '</a>';
  17456. }
  17457. }
  17458. return html;
  17459. }
  17460. return false;
  17461. },
  17462. standard: function(response, fields, preserveHTML) {
  17463. var
  17464. html = '',
  17465. escape = $.fn.search.settings.templates.escape
  17466. ;
  17467. if(response[fields.results] !== undefined) {
  17468. // each result
  17469. $.each(response[fields.results], function(index, result) {
  17470. if(result[fields.url]) {
  17471. html += '<a class="result" href="' + result[fields.url].replace(/"/g,"") + '">';
  17472. }
  17473. else {
  17474. html += '<a class="result">';
  17475. }
  17476. if(result[fields.image] !== undefined) {
  17477. html += ''
  17478. + '<div class="image">'
  17479. + ' <img src="' + result[fields.image].replace(/"/g,"") + '">'
  17480. + '</div>'
  17481. ;
  17482. }
  17483. html += '<div class="content">';
  17484. if(result[fields.price] !== undefined) {
  17485. html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
  17486. }
  17487. if(result[fields.title] !== undefined) {
  17488. html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
  17489. }
  17490. if(result[fields.description] !== undefined) {
  17491. html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
  17492. }
  17493. html += ''
  17494. + '</div>'
  17495. ;
  17496. html += '</a>';
  17497. });
  17498. if(response[fields.action]) {
  17499. if(fields.actionURL === false) {
  17500. html += ''
  17501. + '<div class="action">'
  17502. + escape(response[fields.action][fields.actionText], preserveHTML)
  17503. + '</div>';
  17504. } else {
  17505. html += ''
  17506. + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g,"") + '" class="action">'
  17507. + escape(response[fields.action][fields.actionText], preserveHTML)
  17508. + '</a>';
  17509. }
  17510. }
  17511. return html;
  17512. }
  17513. return false;
  17514. }
  17515. }
  17516. };
  17517. })( jQuery, window, document );
  17518. /*!
  17519. * # Fomantic-UI - Shape
  17520. * http://github.com/fomantic/Fomantic-UI/
  17521. *
  17522. *
  17523. * Released under the MIT license
  17524. * http://opensource.org/licenses/MIT
  17525. *
  17526. */
  17527. ;(function ($, window, document, undefined) {
  17528. 'use strict';
  17529. $.isFunction = $.isFunction || function(obj) {
  17530. return typeof obj === "function" && typeof obj.nodeType !== "number";
  17531. };
  17532. window = (typeof window != 'undefined' && window.Math == Math)
  17533. ? window
  17534. : (typeof self != 'undefined' && self.Math == Math)
  17535. ? self
  17536. : Function('return this')()
  17537. ;
  17538. $.fn.shape = function(parameters) {
  17539. var
  17540. $allModules = $(this),
  17541. time = new Date().getTime(),
  17542. performance = [],
  17543. query = arguments[0],
  17544. methodInvoked = (typeof query == 'string'),
  17545. queryArguments = [].slice.call(arguments, 1),
  17546. requestAnimationFrame = window.requestAnimationFrame
  17547. || window.mozRequestAnimationFrame
  17548. || window.webkitRequestAnimationFrame
  17549. || window.msRequestAnimationFrame
  17550. || function(callback) { setTimeout(callback, 0); },
  17551. returnedValue
  17552. ;
  17553. $allModules
  17554. .each(function() {
  17555. var
  17556. moduleSelector = $allModules.selector || '',
  17557. settings = ( $.isPlainObject(parameters) )
  17558. ? $.extend(true, {}, $.fn.shape.settings, parameters)
  17559. : $.extend({}, $.fn.shape.settings),
  17560. // internal aliases
  17561. namespace = settings.namespace,
  17562. selector = settings.selector,
  17563. error = settings.error,
  17564. className = settings.className,
  17565. // define namespaces for modules
  17566. eventNamespace = '.' + namespace,
  17567. moduleNamespace = 'module-' + namespace,
  17568. // selector cache
  17569. $module = $(this),
  17570. $sides = $module.find('>' + selector.sides),
  17571. $side = $sides.find('>' + selector.side),
  17572. // private variables
  17573. nextIndex = false,
  17574. $activeSide,
  17575. $nextSide,
  17576. // standard module
  17577. element = this,
  17578. instance = $module.data(moduleNamespace),
  17579. module
  17580. ;
  17581. module = {
  17582. initialize: function() {
  17583. module.verbose('Initializing module for', element);
  17584. module.set.defaultSide();
  17585. module.instantiate();
  17586. },
  17587. instantiate: function() {
  17588. module.verbose('Storing instance of module', module);
  17589. instance = module;
  17590. $module
  17591. .data(moduleNamespace, instance)
  17592. ;
  17593. },
  17594. destroy: function() {
  17595. module.verbose('Destroying previous module for', element);
  17596. $module
  17597. .removeData(moduleNamespace)
  17598. .off(eventNamespace)
  17599. ;
  17600. },
  17601. refresh: function() {
  17602. module.verbose('Refreshing selector cache for', element);
  17603. $module = $(element);
  17604. $sides = $(this).find(selector.sides);
  17605. $side = $(this).find(selector.side);
  17606. },
  17607. repaint: function() {
  17608. module.verbose('Forcing repaint event');
  17609. var
  17610. shape = $sides[0] || document.createElement('div'),
  17611. fakeAssignment = shape.offsetWidth
  17612. ;
  17613. },
  17614. animate: function(propertyObject, callback) {
  17615. module.verbose('Animating box with properties', propertyObject);
  17616. callback = callback || function(event) {
  17617. module.verbose('Executing animation callback');
  17618. if(event !== undefined) {
  17619. event.stopPropagation();
  17620. }
  17621. module.reset();
  17622. module.set.active();
  17623. };
  17624. settings.beforeChange.call($nextSide[0]);
  17625. if(module.get.transitionEvent()) {
  17626. module.verbose('Starting CSS animation');
  17627. $module
  17628. .addClass(className.animating)
  17629. ;
  17630. $sides
  17631. .css(propertyObject)
  17632. .one(module.get.transitionEvent(), callback)
  17633. ;
  17634. module.set.duration(settings.duration);
  17635. requestAnimationFrame(function() {
  17636. $module
  17637. .addClass(className.animating)
  17638. ;
  17639. $activeSide
  17640. .addClass(className.hidden)
  17641. ;
  17642. });
  17643. }
  17644. else {
  17645. callback();
  17646. }
  17647. },
  17648. queue: function(method) {
  17649. module.debug('Queueing animation of', method);
  17650. $sides
  17651. .one(module.get.transitionEvent(), function() {
  17652. module.debug('Executing queued animation');
  17653. setTimeout(function(){
  17654. $module.shape(method);
  17655. }, 0);
  17656. })
  17657. ;
  17658. },
  17659. reset: function() {
  17660. module.verbose('Animating states reset');
  17661. $module
  17662. .removeClass(className.animating)
  17663. .attr('style', '')
  17664. .removeAttr('style')
  17665. ;
  17666. // removeAttr style does not consistently work in safari
  17667. $sides
  17668. .attr('style', '')
  17669. .removeAttr('style')
  17670. ;
  17671. $side
  17672. .attr('style', '')
  17673. .removeAttr('style')
  17674. .removeClass(className.hidden)
  17675. ;
  17676. $nextSide
  17677. .removeClass(className.animating)
  17678. .attr('style', '')
  17679. .removeAttr('style')
  17680. ;
  17681. },
  17682. is: {
  17683. complete: function() {
  17684. return ($side.filter('.' + className.active)[0] == $nextSide[0]);
  17685. },
  17686. animating: function() {
  17687. return $module.hasClass(className.animating);
  17688. },
  17689. hidden: function() {
  17690. return $module.closest(':hidden').length > 0;
  17691. }
  17692. },
  17693. set: {
  17694. defaultSide: function() {
  17695. $activeSide = $side.filter('.' + settings.className.active);
  17696. $nextSide = ( $activeSide.next(selector.side).length > 0 )
  17697. ? $activeSide.next(selector.side)
  17698. : $side.first()
  17699. ;
  17700. nextIndex = false;
  17701. module.verbose('Active side set to', $activeSide);
  17702. module.verbose('Next side set to', $nextSide);
  17703. },
  17704. duration: function(duration) {
  17705. duration = duration || settings.duration;
  17706. duration = (typeof duration == 'number')
  17707. ? duration + 'ms'
  17708. : duration
  17709. ;
  17710. module.verbose('Setting animation duration', duration);
  17711. if(settings.duration || settings.duration === 0) {
  17712. $sides.add($side)
  17713. .css({
  17714. '-webkit-transition-duration': duration,
  17715. '-moz-transition-duration': duration,
  17716. '-ms-transition-duration': duration,
  17717. '-o-transition-duration': duration,
  17718. 'transition-duration': duration
  17719. })
  17720. ;
  17721. }
  17722. },
  17723. currentStageSize: function() {
  17724. var
  17725. $activeSide = $side.filter('.' + settings.className.active),
  17726. width = $activeSide.outerWidth(true),
  17727. height = $activeSide.outerHeight(true)
  17728. ;
  17729. $module
  17730. .css({
  17731. width: width,
  17732. height: height
  17733. })
  17734. ;
  17735. },
  17736. stageSize: function() {
  17737. var
  17738. $clone = $module.clone().addClass(className.loading),
  17739. $side = $clone.find('>' + selector.sides + '>' + selector.side),
  17740. $activeSide = $side.filter('.' + settings.className.active),
  17741. $nextSide = (nextIndex)
  17742. ? $side.eq(nextIndex)
  17743. : ( $activeSide.next(selector.side).length > 0 )
  17744. ? $activeSide.next(selector.side)
  17745. : $side.first(),
  17746. newWidth = (settings.width === 'next')
  17747. ? $nextSide.outerWidth(true)
  17748. : (settings.width === 'initial')
  17749. ? $module.width()
  17750. : settings.width,
  17751. newHeight = (settings.height === 'next')
  17752. ? $nextSide.outerHeight(true)
  17753. : (settings.height === 'initial')
  17754. ? $module.height()
  17755. : settings.height
  17756. ;
  17757. $activeSide.removeClass(className.active);
  17758. $nextSide.addClass(className.active);
  17759. $clone.insertAfter($module);
  17760. $clone.remove();
  17761. if(settings.width !== 'auto') {
  17762. $module.css('width', newWidth + settings.jitter);
  17763. module.verbose('Specifying width during animation', newWidth);
  17764. }
  17765. if(settings.height !== 'auto') {
  17766. $module.css('height', newHeight + settings.jitter);
  17767. module.verbose('Specifying height during animation', newHeight);
  17768. }
  17769. },
  17770. nextSide: function(selector) {
  17771. nextIndex = selector;
  17772. $nextSide = $side.filter(selector);
  17773. nextIndex = $side.index($nextSide);
  17774. if($nextSide.length === 0) {
  17775. module.set.defaultSide();
  17776. module.error(error.side);
  17777. }
  17778. module.verbose('Next side manually set to', $nextSide);
  17779. },
  17780. active: function() {
  17781. module.verbose('Setting new side to active', $nextSide);
  17782. $side
  17783. .removeClass(className.active)
  17784. ;
  17785. $nextSide
  17786. .addClass(className.active)
  17787. ;
  17788. settings.onChange.call($nextSide[0]);
  17789. module.set.defaultSide();
  17790. }
  17791. },
  17792. flip: {
  17793. to: function(type,stage){
  17794. if(module.is.hidden()) {
  17795. module.debug('Module not visible', $nextSide);
  17796. return;
  17797. }
  17798. if(module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
  17799. module.debug('Side already visible', $nextSide);
  17800. return;
  17801. }
  17802. var
  17803. transform = module.get.transform[type]()
  17804. ;
  17805. if( !module.is.animating()) {
  17806. module.debug('Flipping '+type, $nextSide);
  17807. module.set.stageSize();
  17808. module.stage[stage]();
  17809. module.animate(transform);
  17810. }
  17811. else {
  17812. module.queue('flip '+type);
  17813. }
  17814. },
  17815. up: function() {
  17816. module.flip.to('up','above');
  17817. },
  17818. down: function() {
  17819. module.flip.to('down','below');
  17820. },
  17821. left: function() {
  17822. module.flip.to('left','left');
  17823. },
  17824. right: function() {
  17825. module.flip.to('right','right');
  17826. },
  17827. over: function() {
  17828. module.flip.to('over','behind');
  17829. },
  17830. back: function() {
  17831. module.flip.to('back','behind');
  17832. }
  17833. },
  17834. get: {
  17835. transform: {
  17836. up: function() {
  17837. var
  17838. translateZ = $activeSide.outerHeight(true) / 2,
  17839. translateY = $nextSide.outerHeight(true) - translateZ
  17840. ;
  17841. return {
  17842. transform: 'translateY(' + translateY + 'px) translateZ(-'+ translateZ + 'px) rotateX(-90deg)'
  17843. };
  17844. },
  17845. down: function() {
  17846. var
  17847. translate = {
  17848. z: $activeSide.outerHeight(true) / 2
  17849. }
  17850. ;
  17851. return {
  17852. transform: 'translateY(-' + translate.z + 'px) translateZ(-'+ translate.z + 'px) rotateX(90deg)'
  17853. };
  17854. },
  17855. left: function() {
  17856. var
  17857. translateZ = $activeSide.outerWidth(true) / 2,
  17858. translateX = $nextSide.outerWidth(true) - translateZ
  17859. ;
  17860. return {
  17861. transform: 'translateX(' + translateX + 'px) translateZ(-' + translateZ + 'px) rotateY(90deg)'
  17862. };
  17863. },
  17864. right: function() {
  17865. var
  17866. translate = {
  17867. z : $activeSide.outerWidth(true) / 2
  17868. }
  17869. ;
  17870. return {
  17871. transform: 'translateX(-' + translate.z + 'px) translateZ(-' + translate.z + 'px) rotateY(-90deg)'
  17872. };
  17873. },
  17874. over: function() {
  17875. var
  17876. translate = {
  17877. x : -(($activeSide.outerWidth(true) - $nextSide.outerWidth(true)) / 2)
  17878. }
  17879. ;
  17880. return {
  17881. transform: 'translateX(' + translate.x + 'px) rotateY(180deg)'
  17882. };
  17883. },
  17884. back: function() {
  17885. var
  17886. translate = {
  17887. x : -(($activeSide.outerWidth(true) - $nextSide.outerWidth(true)) / 2)
  17888. }
  17889. ;
  17890. return {
  17891. transform: 'translateX(' + translate.x + 'px) rotateY(-180deg)'
  17892. };
  17893. }
  17894. },
  17895. transitionEvent: function() {
  17896. var
  17897. element = document.createElement('element'),
  17898. transitions = {
  17899. 'transition' :'transitionend',
  17900. 'OTransition' :'oTransitionEnd',
  17901. 'MozTransition' :'transitionend',
  17902. 'WebkitTransition' :'webkitTransitionEnd'
  17903. },
  17904. transition
  17905. ;
  17906. for(transition in transitions){
  17907. if( element.style[transition] !== undefined ){
  17908. return transitions[transition];
  17909. }
  17910. }
  17911. },
  17912. nextSide: function() {
  17913. return ( $activeSide.next(selector.side).length > 0 )
  17914. ? $activeSide.next(selector.side)
  17915. : $side.first()
  17916. ;
  17917. }
  17918. },
  17919. stage: {
  17920. above: function() {
  17921. var
  17922. box = {
  17923. origin : (($activeSide.outerHeight(true) - $nextSide.outerHeight(true)) / 2),
  17924. depth : {
  17925. active : ($nextSide.outerHeight(true) / 2),
  17926. next : ($activeSide.outerHeight(true) / 2)
  17927. }
  17928. }
  17929. ;
  17930. module.verbose('Setting the initial animation position as above', $nextSide, box);
  17931. $activeSide
  17932. .css({
  17933. 'transform' : 'rotateX(0deg)'
  17934. })
  17935. ;
  17936. $nextSide
  17937. .addClass(className.animating)
  17938. .css({
  17939. 'top' : box.origin + 'px',
  17940. 'transform' : 'rotateX(90deg) translateZ(' + box.depth.next + 'px) translateY(-' + box.depth.active + 'px)'
  17941. })
  17942. ;
  17943. },
  17944. below: function() {
  17945. var
  17946. box = {
  17947. origin : (($activeSide.outerHeight(true) - $nextSide.outerHeight(true)) / 2),
  17948. depth : {
  17949. active : ($nextSide.outerHeight(true) / 2),
  17950. next : ($activeSide.outerHeight(true) / 2)
  17951. }
  17952. }
  17953. ;
  17954. module.verbose('Setting the initial animation position as below', $nextSide, box);
  17955. $activeSide
  17956. .css({
  17957. 'transform' : 'rotateX(0deg)'
  17958. })
  17959. ;
  17960. $nextSide
  17961. .addClass(className.animating)
  17962. .css({
  17963. 'top' : box.origin + 'px',
  17964. 'transform' : 'rotateX(-90deg) translateZ(' + box.depth.next + 'px) translateY(' + box.depth.active + 'px)'
  17965. })
  17966. ;
  17967. },
  17968. left: function() {
  17969. var
  17970. height = {
  17971. active : $activeSide.outerWidth(true),
  17972. next : $nextSide.outerWidth(true)
  17973. },
  17974. box = {
  17975. origin : ( ( height.active - height.next ) / 2),
  17976. depth : {
  17977. active : (height.next / 2),
  17978. next : (height.active / 2)
  17979. }
  17980. }
  17981. ;
  17982. module.verbose('Setting the initial animation position as left', $nextSide, box);
  17983. $activeSide
  17984. .css({
  17985. 'transform' : 'rotateY(0deg)'
  17986. })
  17987. ;
  17988. $nextSide
  17989. .addClass(className.animating)
  17990. .css({
  17991. 'left' : box.origin + 'px',
  17992. 'transform' : 'rotateY(-90deg) translateZ(' + box.depth.next + 'px) translateX(-' + box.depth.active + 'px)'
  17993. })
  17994. ;
  17995. },
  17996. right: function() {
  17997. var
  17998. height = {
  17999. active : $activeSide.outerWidth(true),
  18000. next : $nextSide.outerWidth(true)
  18001. },
  18002. box = {
  18003. origin : ( ( height.active - height.next ) / 2),
  18004. depth : {
  18005. active : (height.next / 2),
  18006. next : (height.active / 2)
  18007. }
  18008. }
  18009. ;
  18010. module.verbose('Setting the initial animation position as right', $nextSide, box);
  18011. $activeSide
  18012. .css({
  18013. 'transform' : 'rotateY(0deg)'
  18014. })
  18015. ;
  18016. $nextSide
  18017. .addClass(className.animating)
  18018. .css({
  18019. 'left' : box.origin + 'px',
  18020. 'transform' : 'rotateY(90deg) translateZ(' + box.depth.next + 'px) translateX(' + box.depth.active + 'px)'
  18021. })
  18022. ;
  18023. },
  18024. behind: function() {
  18025. var
  18026. height = {
  18027. active : $activeSide.outerWidth(true),
  18028. next : $nextSide.outerWidth(true)
  18029. },
  18030. box = {
  18031. origin : ( ( height.active - height.next ) / 2),
  18032. depth : {
  18033. active : (height.next / 2),
  18034. next : (height.active / 2)
  18035. }
  18036. }
  18037. ;
  18038. module.verbose('Setting the initial animation position as behind', $nextSide, box);
  18039. $activeSide
  18040. .css({
  18041. 'transform' : 'rotateY(0deg)'
  18042. })
  18043. ;
  18044. $nextSide
  18045. .addClass(className.animating)
  18046. .css({
  18047. 'left' : box.origin + 'px',
  18048. 'transform' : 'rotateY(-180deg)'
  18049. })
  18050. ;
  18051. }
  18052. },
  18053. setting: function(name, value) {
  18054. module.debug('Changing setting', name, value);
  18055. if( $.isPlainObject(name) ) {
  18056. $.extend(true, settings, name);
  18057. }
  18058. else if(value !== undefined) {
  18059. if($.isPlainObject(settings[name])) {
  18060. $.extend(true, settings[name], value);
  18061. }
  18062. else {
  18063. settings[name] = value;
  18064. }
  18065. }
  18066. else {
  18067. return settings[name];
  18068. }
  18069. },
  18070. internal: function(name, value) {
  18071. if( $.isPlainObject(name) ) {
  18072. $.extend(true, module, name);
  18073. }
  18074. else if(value !== undefined) {
  18075. module[name] = value;
  18076. }
  18077. else {
  18078. return module[name];
  18079. }
  18080. },
  18081. debug: function() {
  18082. if(!settings.silent && settings.debug) {
  18083. if(settings.performance) {
  18084. module.performance.log(arguments);
  18085. }
  18086. else {
  18087. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  18088. module.debug.apply(console, arguments);
  18089. }
  18090. }
  18091. },
  18092. verbose: function() {
  18093. if(!settings.silent && settings.verbose && settings.debug) {
  18094. if(settings.performance) {
  18095. module.performance.log(arguments);
  18096. }
  18097. else {
  18098. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  18099. module.verbose.apply(console, arguments);
  18100. }
  18101. }
  18102. },
  18103. error: function() {
  18104. if(!settings.silent) {
  18105. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  18106. module.error.apply(console, arguments);
  18107. }
  18108. },
  18109. performance: {
  18110. log: function(message) {
  18111. var
  18112. currentTime,
  18113. executionTime,
  18114. previousTime
  18115. ;
  18116. if(settings.performance) {
  18117. currentTime = new Date().getTime();
  18118. previousTime = time || currentTime;
  18119. executionTime = currentTime - previousTime;
  18120. time = currentTime;
  18121. performance.push({
  18122. 'Name' : message[0],
  18123. 'Arguments' : [].slice.call(message, 1) || '',
  18124. 'Element' : element,
  18125. 'Execution Time' : executionTime
  18126. });
  18127. }
  18128. clearTimeout(module.performance.timer);
  18129. module.performance.timer = setTimeout(module.performance.display, 500);
  18130. },
  18131. display: function() {
  18132. var
  18133. title = settings.name + ':',
  18134. totalTime = 0
  18135. ;
  18136. time = false;
  18137. clearTimeout(module.performance.timer);
  18138. $.each(performance, function(index, data) {
  18139. totalTime += data['Execution Time'];
  18140. });
  18141. title += ' ' + totalTime + 'ms';
  18142. if(moduleSelector) {
  18143. title += ' \'' + moduleSelector + '\'';
  18144. }
  18145. if($allModules.length > 1) {
  18146. title += ' ' + '(' + $allModules.length + ')';
  18147. }
  18148. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  18149. console.groupCollapsed(title);
  18150. if(console.table) {
  18151. console.table(performance);
  18152. }
  18153. else {
  18154. $.each(performance, function(index, data) {
  18155. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  18156. });
  18157. }
  18158. console.groupEnd();
  18159. }
  18160. performance = [];
  18161. }
  18162. },
  18163. invoke: function(query, passedArguments, context) {
  18164. var
  18165. object = instance,
  18166. maxDepth,
  18167. found,
  18168. response
  18169. ;
  18170. passedArguments = passedArguments || queryArguments;
  18171. context = element || context;
  18172. if(typeof query == 'string' && object !== undefined) {
  18173. query = query.split(/[\. ]/);
  18174. maxDepth = query.length - 1;
  18175. $.each(query, function(depth, value) {
  18176. var camelCaseValue = (depth != maxDepth)
  18177. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  18178. : query
  18179. ;
  18180. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  18181. object = object[camelCaseValue];
  18182. }
  18183. else if( object[camelCaseValue] !== undefined ) {
  18184. found = object[camelCaseValue];
  18185. return false;
  18186. }
  18187. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  18188. object = object[value];
  18189. }
  18190. else if( object[value] !== undefined ) {
  18191. found = object[value];
  18192. return false;
  18193. }
  18194. else {
  18195. return false;
  18196. }
  18197. });
  18198. }
  18199. if ( $.isFunction( found ) ) {
  18200. response = found.apply(context, passedArguments);
  18201. }
  18202. else if(found !== undefined) {
  18203. response = found;
  18204. }
  18205. if(Array.isArray(returnedValue)) {
  18206. returnedValue.push(response);
  18207. }
  18208. else if(returnedValue !== undefined) {
  18209. returnedValue = [returnedValue, response];
  18210. }
  18211. else if(response !== undefined) {
  18212. returnedValue = response;
  18213. }
  18214. return found;
  18215. }
  18216. };
  18217. if(methodInvoked) {
  18218. if(instance === undefined) {
  18219. module.initialize();
  18220. }
  18221. var $inputs = $module.find('input');
  18222. if( $inputs.length > 0) {
  18223. $inputs.blur();
  18224. setTimeout(function(){
  18225. module.invoke(query);
  18226. }, 150);
  18227. } else {
  18228. module.invoke(query);
  18229. }
  18230. }
  18231. else {
  18232. if(instance !== undefined) {
  18233. instance.invoke('destroy');
  18234. }
  18235. module.initialize();
  18236. }
  18237. })
  18238. ;
  18239. return (returnedValue !== undefined)
  18240. ? returnedValue
  18241. : this
  18242. ;
  18243. };
  18244. $.fn.shape.settings = {
  18245. // module info
  18246. name : 'Shape',
  18247. // hide all debug content
  18248. silent : false,
  18249. // debug content outputted to console
  18250. debug : false,
  18251. // verbose debug output
  18252. verbose : false,
  18253. // fudge factor in pixels when swapping from 2d to 3d (can be useful to correct rounding errors)
  18254. jitter : 0,
  18255. // performance data output
  18256. performance: true,
  18257. // event namespace
  18258. namespace : 'shape',
  18259. // width during animation, can be set to 'auto', initial', 'next' or pixel amount
  18260. width: 'initial',
  18261. // height during animation, can be set to 'auto', 'initial', 'next' or pixel amount
  18262. height: 'initial',
  18263. // callback occurs on side change
  18264. beforeChange : function() {},
  18265. onChange : function() {},
  18266. // allow animation to same side
  18267. allowRepeats: false,
  18268. // animation duration
  18269. duration : false,
  18270. // possible errors
  18271. error: {
  18272. side : 'You tried to switch to a side that does not exist.',
  18273. method : 'The method you called is not defined'
  18274. },
  18275. // classnames used
  18276. className : {
  18277. animating : 'animating',
  18278. hidden : 'hidden',
  18279. loading : 'loading',
  18280. active : 'active'
  18281. },
  18282. // selectors used
  18283. selector : {
  18284. sides : '.sides',
  18285. side : '.side'
  18286. }
  18287. };
  18288. })( jQuery, window, document );
  18289. /*!
  18290. * # Fomantic-UI - Sidebar
  18291. * http://github.com/fomantic/Fomantic-UI/
  18292. *
  18293. *
  18294. * Released under the MIT license
  18295. * http://opensource.org/licenses/MIT
  18296. *
  18297. */
  18298. ;(function ($, window, document, undefined) {
  18299. 'use strict';
  18300. $.isFunction = $.isFunction || function(obj) {
  18301. return typeof obj === "function" && typeof obj.nodeType !== "number";
  18302. };
  18303. window = (typeof window != 'undefined' && window.Math == Math)
  18304. ? window
  18305. : (typeof self != 'undefined' && self.Math == Math)
  18306. ? self
  18307. : Function('return this')()
  18308. ;
  18309. $.fn.sidebar = function(parameters) {
  18310. var
  18311. $allModules = $(this),
  18312. $window = $(window),
  18313. $document = $(document),
  18314. $html = $('html'),
  18315. $head = $('head'),
  18316. moduleSelector = $allModules.selector || '',
  18317. time = new Date().getTime(),
  18318. performance = [],
  18319. query = arguments[0],
  18320. methodInvoked = (typeof query == 'string'),
  18321. queryArguments = [].slice.call(arguments, 1),
  18322. requestAnimationFrame = window.requestAnimationFrame
  18323. || window.mozRequestAnimationFrame
  18324. || window.webkitRequestAnimationFrame
  18325. || window.msRequestAnimationFrame
  18326. || function(callback) { setTimeout(callback, 0); },
  18327. returnedValue
  18328. ;
  18329. $allModules
  18330. .each(function() {
  18331. var
  18332. settings = ( $.isPlainObject(parameters) )
  18333. ? $.extend(true, {}, $.fn.sidebar.settings, parameters)
  18334. : $.extend({}, $.fn.sidebar.settings),
  18335. selector = settings.selector,
  18336. className = settings.className,
  18337. namespace = settings.namespace,
  18338. regExp = settings.regExp,
  18339. error = settings.error,
  18340. eventNamespace = '.' + namespace,
  18341. moduleNamespace = 'module-' + namespace,
  18342. $module = $(this),
  18343. $context = $(settings.context),
  18344. $sidebars = $module.children(selector.sidebar),
  18345. $fixed = $context.children(selector.fixed),
  18346. $pusher = $context.children(selector.pusher),
  18347. $style,
  18348. element = this,
  18349. instance = $module.data(moduleNamespace),
  18350. elementNamespace,
  18351. id,
  18352. currentScroll,
  18353. transitionEvent,
  18354. module
  18355. ;
  18356. module = {
  18357. initialize: function() {
  18358. module.debug('Initializing sidebar', parameters);
  18359. module.create.id();
  18360. transitionEvent = module.get.transitionEvent();
  18361. // avoids locking rendering if initialized in onReady
  18362. if(settings.delaySetup) {
  18363. requestAnimationFrame(module.setup.layout);
  18364. }
  18365. else {
  18366. module.setup.layout();
  18367. }
  18368. requestAnimationFrame(function() {
  18369. module.setup.cache();
  18370. });
  18371. module.instantiate();
  18372. },
  18373. instantiate: function() {
  18374. module.verbose('Storing instance of module', module);
  18375. instance = module;
  18376. $module
  18377. .data(moduleNamespace, module)
  18378. ;
  18379. },
  18380. create: {
  18381. id: function() {
  18382. id = (Math.random().toString(16) + '000000000').substr(2,8);
  18383. elementNamespace = '.' + id;
  18384. module.verbose('Creating unique id for element', id);
  18385. }
  18386. },
  18387. destroy: function() {
  18388. module.verbose('Destroying previous module for', $module);
  18389. $module
  18390. .off(eventNamespace)
  18391. .removeData(moduleNamespace)
  18392. ;
  18393. if(module.is.ios()) {
  18394. module.remove.ios();
  18395. }
  18396. // bound by uuid
  18397. $context.off(elementNamespace);
  18398. $window.off(elementNamespace);
  18399. $document.off(elementNamespace);
  18400. },
  18401. event: {
  18402. clickaway: function(event) {
  18403. if(settings.closable){
  18404. var
  18405. clickedInPusher = ($pusher.find(event.target).length > 0 || $pusher.is(event.target)),
  18406. clickedContext = ($context.is(event.target))
  18407. ;
  18408. if(clickedInPusher) {
  18409. module.verbose('User clicked on dimmed page');
  18410. module.hide();
  18411. }
  18412. if(clickedContext) {
  18413. module.verbose('User clicked on dimmable context (scaled out page)');
  18414. module.hide();
  18415. }
  18416. }
  18417. },
  18418. touch: function(event) {
  18419. //event.stopPropagation();
  18420. },
  18421. containScroll: function(event) {
  18422. if(element.scrollTop <= 0) {
  18423. element.scrollTop = 1;
  18424. }
  18425. if((element.scrollTop + element.offsetHeight) >= element.scrollHeight) {
  18426. element.scrollTop = element.scrollHeight - element.offsetHeight - 1;
  18427. }
  18428. },
  18429. scroll: function(event) {
  18430. if( $(event.target).closest(selector.sidebar).length === 0 ) {
  18431. event.preventDefault();
  18432. }
  18433. }
  18434. },
  18435. bind: {
  18436. clickaway: function() {
  18437. module.verbose('Adding clickaway events to context', $context);
  18438. $context
  18439. .on('click' + elementNamespace, module.event.clickaway)
  18440. .on('touchend' + elementNamespace, module.event.clickaway)
  18441. ;
  18442. },
  18443. scrollLock: function() {
  18444. if(settings.scrollLock) {
  18445. module.debug('Disabling page scroll');
  18446. $window
  18447. .on('DOMMouseScroll' + elementNamespace, module.event.scroll)
  18448. ;
  18449. }
  18450. module.verbose('Adding events to contain sidebar scroll');
  18451. $document
  18452. .on('touchmove' + elementNamespace, module.event.touch)
  18453. ;
  18454. $module
  18455. .on('scroll' + eventNamespace, module.event.containScroll)
  18456. ;
  18457. }
  18458. },
  18459. unbind: {
  18460. clickaway: function() {
  18461. module.verbose('Removing clickaway events from context', $context);
  18462. $context.off(elementNamespace);
  18463. },
  18464. scrollLock: function() {
  18465. module.verbose('Removing scroll lock from page');
  18466. $document.off(elementNamespace);
  18467. $window.off(elementNamespace);
  18468. $module.off('scroll' + eventNamespace);
  18469. }
  18470. },
  18471. add: {
  18472. inlineCSS: function() {
  18473. var
  18474. width = module.cache.width || $module.outerWidth(),
  18475. height = module.cache.height || $module.outerHeight(),
  18476. isRTL = module.is.rtl(),
  18477. direction = module.get.direction(),
  18478. distance = {
  18479. left : width,
  18480. right : -width,
  18481. top : height,
  18482. bottom : -height
  18483. },
  18484. style
  18485. ;
  18486. if(isRTL){
  18487. module.verbose('RTL detected, flipping widths');
  18488. distance.left = -width;
  18489. distance.right = width;
  18490. }
  18491. style = '<style>';
  18492. if(direction === 'left' || direction === 'right') {
  18493. module.debug('Adding CSS rules for animation distance', width);
  18494. style += ''
  18495. + ' .ui.visible.' + direction + '.sidebar ~ .fixed,'
  18496. + ' .ui.visible.' + direction + '.sidebar ~ .pusher {'
  18497. + ' -webkit-transform: translate3d('+ distance[direction] + 'px, 0, 0);'
  18498. + ' transform: translate3d('+ distance[direction] + 'px, 0, 0);'
  18499. + ' }'
  18500. ;
  18501. }
  18502. else if(direction === 'top' || direction == 'bottom') {
  18503. style += ''
  18504. + ' .ui.visible.' + direction + '.sidebar ~ .fixed,'
  18505. + ' .ui.visible.' + direction + '.sidebar ~ .pusher {'
  18506. + ' -webkit-transform: translate3d(0, ' + distance[direction] + 'px, 0);'
  18507. + ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
  18508. + ' }'
  18509. ;
  18510. }
  18511. /* IE is only browser not to create context with transforms */
  18512. /* https://www.w3.org/Bugs/Public/show_bug.cgi?id=16328 */
  18513. if( module.is.ie() ) {
  18514. if(direction === 'left' || direction === 'right') {
  18515. module.debug('Adding CSS rules for animation distance', width);
  18516. style += ''
  18517. + ' body.pushable > .ui.visible.' + direction + '.sidebar ~ .pusher:after {'
  18518. + ' -webkit-transform: translate3d('+ distance[direction] + 'px, 0, 0);'
  18519. + ' transform: translate3d('+ distance[direction] + 'px, 0, 0);'
  18520. + ' }'
  18521. ;
  18522. }
  18523. else if(direction === 'top' || direction == 'bottom') {
  18524. style += ''
  18525. + ' body.pushable > .ui.visible.' + direction + '.sidebar ~ .pusher:after {'
  18526. + ' -webkit-transform: translate3d(0, ' + distance[direction] + 'px, 0);'
  18527. + ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
  18528. + ' }'
  18529. ;
  18530. }
  18531. /* opposite sides visible forces content overlay */
  18532. style += ''
  18533. + ' body.pushable > .ui.visible.left.sidebar ~ .ui.visible.right.sidebar ~ .pusher:after,'
  18534. + ' body.pushable > .ui.visible.right.sidebar ~ .ui.visible.left.sidebar ~ .pusher:after {'
  18535. + ' -webkit-transform: translate3d(0, 0, 0);'
  18536. + ' transform: translate3d(0, 0, 0);'
  18537. + ' }'
  18538. ;
  18539. }
  18540. style += '</style>';
  18541. $style = $(style)
  18542. .appendTo($head)
  18543. ;
  18544. module.debug('Adding sizing css to head', $style);
  18545. }
  18546. },
  18547. refresh: function() {
  18548. module.verbose('Refreshing selector cache');
  18549. $context = $(settings.context);
  18550. $sidebars = $context.children(selector.sidebar);
  18551. $pusher = $context.children(selector.pusher);
  18552. $fixed = $context.children(selector.fixed);
  18553. module.clear.cache();
  18554. },
  18555. refreshSidebars: function() {
  18556. module.verbose('Refreshing other sidebars');
  18557. $sidebars = $context.children(selector.sidebar);
  18558. },
  18559. repaint: function() {
  18560. module.verbose('Forcing repaint event');
  18561. element.style.display = 'none';
  18562. var ignored = element.offsetHeight;
  18563. element.scrollTop = element.scrollTop;
  18564. element.style.display = '';
  18565. },
  18566. setup: {
  18567. cache: function() {
  18568. module.cache = {
  18569. width : $module.outerWidth(),
  18570. height : $module.outerHeight(),
  18571. rtl : ($module.css('direction') == 'rtl')
  18572. };
  18573. },
  18574. layout: function() {
  18575. if( $context.children(selector.pusher).length === 0 ) {
  18576. module.debug('Adding wrapper element for sidebar');
  18577. module.error(error.pusher);
  18578. $pusher = $('<div class="pusher" />');
  18579. $context
  18580. .children()
  18581. .not(selector.omitted)
  18582. .not($sidebars)
  18583. .wrapAll($pusher)
  18584. ;
  18585. module.refresh();
  18586. }
  18587. if($module.nextAll(selector.pusher).length === 0 || $module.nextAll(selector.pusher)[0] !== $pusher[0]) {
  18588. module.debug('Moved sidebar to correct parent element');
  18589. module.error(error.movedSidebar, element);
  18590. $module.detach().prependTo($context);
  18591. module.refresh();
  18592. }
  18593. module.clear.cache();
  18594. module.set.pushable();
  18595. module.set.direction();
  18596. }
  18597. },
  18598. attachEvents: function(selector, event) {
  18599. var
  18600. $toggle = $(selector)
  18601. ;
  18602. event = $.isFunction(module[event])
  18603. ? module[event]
  18604. : module.toggle
  18605. ;
  18606. if($toggle.length > 0) {
  18607. module.debug('Attaching sidebar events to element', selector, event);
  18608. $toggle
  18609. .on('click' + eventNamespace, event)
  18610. ;
  18611. }
  18612. else {
  18613. module.error(error.notFound, selector);
  18614. }
  18615. },
  18616. show: function(callback) {
  18617. callback = $.isFunction(callback)
  18618. ? callback
  18619. : function(){}
  18620. ;
  18621. if(module.is.hidden()) {
  18622. module.refreshSidebars();
  18623. if(settings.overlay) {
  18624. module.error(error.overlay);
  18625. settings.transition = 'overlay';
  18626. }
  18627. module.refresh();
  18628. if(module.othersActive()) {
  18629. module.debug('Other sidebars currently visible');
  18630. if(settings.exclusive) {
  18631. // if not overlay queue animation after hide
  18632. if(settings.transition != 'overlay') {
  18633. module.hideOthers(module.show);
  18634. return;
  18635. }
  18636. else {
  18637. module.hideOthers();
  18638. }
  18639. }
  18640. else {
  18641. settings.transition = 'overlay';
  18642. }
  18643. }
  18644. module.pushPage(function() {
  18645. callback.call(element);
  18646. settings.onShow.call(element);
  18647. });
  18648. settings.onChange.call(element);
  18649. settings.onVisible.call(element);
  18650. }
  18651. else {
  18652. module.debug('Sidebar is already visible');
  18653. }
  18654. },
  18655. hide: function(callback) {
  18656. callback = $.isFunction(callback)
  18657. ? callback
  18658. : function(){}
  18659. ;
  18660. if(module.is.visible() || module.is.animating()) {
  18661. module.debug('Hiding sidebar', callback);
  18662. module.refreshSidebars();
  18663. module.pullPage(function() {
  18664. callback.call(element);
  18665. settings.onHidden.call(element);
  18666. });
  18667. settings.onChange.call(element);
  18668. settings.onHide.call(element);
  18669. }
  18670. },
  18671. othersAnimating: function() {
  18672. return ($sidebars.not($module).filter('.' + className.animating).length > 0);
  18673. },
  18674. othersVisible: function() {
  18675. return ($sidebars.not($module).filter('.' + className.visible).length > 0);
  18676. },
  18677. othersActive: function() {
  18678. return(module.othersVisible() || module.othersAnimating());
  18679. },
  18680. hideOthers: function(callback) {
  18681. var
  18682. $otherSidebars = $sidebars.not($module).filter('.' + className.visible),
  18683. sidebarCount = $otherSidebars.length,
  18684. callbackCount = 0
  18685. ;
  18686. callback = callback || function(){};
  18687. $otherSidebars
  18688. .sidebar('hide', function() {
  18689. callbackCount++;
  18690. if(callbackCount == sidebarCount) {
  18691. callback();
  18692. }
  18693. })
  18694. ;
  18695. },
  18696. toggle: function() {
  18697. module.verbose('Determining toggled direction');
  18698. if(module.is.hidden()) {
  18699. module.show();
  18700. }
  18701. else {
  18702. module.hide();
  18703. }
  18704. },
  18705. pushPage: function(callback) {
  18706. var
  18707. transition = module.get.transition(),
  18708. $transition = (transition === 'overlay' || module.othersActive())
  18709. ? $module
  18710. : $pusher,
  18711. animate,
  18712. dim,
  18713. transitionEnd
  18714. ;
  18715. callback = $.isFunction(callback)
  18716. ? callback
  18717. : function(){}
  18718. ;
  18719. if(settings.transition == 'scale down') {
  18720. module.scrollToTop();
  18721. }
  18722. module.set.transition(transition);
  18723. module.repaint();
  18724. animate = function() {
  18725. module.bind.clickaway();
  18726. module.add.inlineCSS();
  18727. module.set.animating();
  18728. module.set.visible();
  18729. };
  18730. dim = function() {
  18731. module.set.dimmed();
  18732. };
  18733. transitionEnd = function(event) {
  18734. if( event.target == $transition[0] ) {
  18735. $transition.off(transitionEvent + elementNamespace, transitionEnd);
  18736. module.remove.animating();
  18737. module.bind.scrollLock();
  18738. callback.call(element);
  18739. }
  18740. };
  18741. $transition.off(transitionEvent + elementNamespace);
  18742. $transition.on(transitionEvent + elementNamespace, transitionEnd);
  18743. requestAnimationFrame(animate);
  18744. if(settings.dimPage && !module.othersVisible()) {
  18745. requestAnimationFrame(dim);
  18746. }
  18747. },
  18748. pullPage: function(callback) {
  18749. var
  18750. transition = module.get.transition(),
  18751. $transition = (transition == 'overlay' || module.othersActive())
  18752. ? $module
  18753. : $pusher,
  18754. animate,
  18755. transitionEnd
  18756. ;
  18757. callback = $.isFunction(callback)
  18758. ? callback
  18759. : function(){}
  18760. ;
  18761. module.verbose('Removing context push state', module.get.direction());
  18762. module.unbind.clickaway();
  18763. module.unbind.scrollLock();
  18764. animate = function() {
  18765. module.set.transition(transition);
  18766. module.set.animating();
  18767. module.remove.visible();
  18768. if(settings.dimPage && !module.othersVisible()) {
  18769. $pusher.removeClass(className.dimmed);
  18770. }
  18771. };
  18772. transitionEnd = function(event) {
  18773. if( event.target == $transition[0] ) {
  18774. $transition.off(transitionEvent + elementNamespace, transitionEnd);
  18775. module.remove.animating();
  18776. module.remove.transition();
  18777. module.remove.inlineCSS();
  18778. if(transition == 'scale down' || (settings.returnScroll && module.is.mobile()) ) {
  18779. module.scrollBack();
  18780. }
  18781. callback.call(element);
  18782. }
  18783. };
  18784. $transition.off(transitionEvent + elementNamespace);
  18785. $transition.on(transitionEvent + elementNamespace, transitionEnd);
  18786. requestAnimationFrame(animate);
  18787. },
  18788. scrollToTop: function() {
  18789. module.verbose('Scrolling to top of page to avoid animation issues');
  18790. currentScroll = $(window).scrollTop();
  18791. $module.scrollTop(0);
  18792. window.scrollTo(0, 0);
  18793. },
  18794. scrollBack: function() {
  18795. module.verbose('Scrolling back to original page position');
  18796. window.scrollTo(0, currentScroll);
  18797. },
  18798. clear: {
  18799. cache: function() {
  18800. module.verbose('Clearing cached dimensions');
  18801. module.cache = {};
  18802. }
  18803. },
  18804. set: {
  18805. // ios only (scroll on html not document). This prevent auto-resize canvas/scroll in ios
  18806. // (This is no longer necessary in latest iOS)
  18807. ios: function() {
  18808. $html.addClass(className.ios);
  18809. },
  18810. // container
  18811. pushed: function() {
  18812. $context.addClass(className.pushed);
  18813. },
  18814. pushable: function() {
  18815. $context.addClass(className.pushable);
  18816. },
  18817. // pusher
  18818. dimmed: function() {
  18819. $pusher.addClass(className.dimmed);
  18820. },
  18821. // sidebar
  18822. active: function() {
  18823. $module.addClass(className.active);
  18824. },
  18825. animating: function() {
  18826. $module.addClass(className.animating);
  18827. },
  18828. transition: function(transition) {
  18829. transition = transition || module.get.transition();
  18830. $module.addClass(transition);
  18831. },
  18832. direction: function(direction) {
  18833. direction = direction || module.get.direction();
  18834. $module.addClass(className[direction]);
  18835. },
  18836. visible: function() {
  18837. $module.addClass(className.visible);
  18838. },
  18839. overlay: function() {
  18840. $module.addClass(className.overlay);
  18841. }
  18842. },
  18843. remove: {
  18844. inlineCSS: function() {
  18845. module.debug('Removing inline css styles', $style);
  18846. if($style && $style.length > 0) {
  18847. $style.remove();
  18848. }
  18849. },
  18850. // ios scroll on html not document
  18851. ios: function() {
  18852. $html.removeClass(className.ios);
  18853. },
  18854. // context
  18855. pushed: function() {
  18856. $context.removeClass(className.pushed);
  18857. },
  18858. pushable: function() {
  18859. $context.removeClass(className.pushable);
  18860. },
  18861. // sidebar
  18862. active: function() {
  18863. $module.removeClass(className.active);
  18864. },
  18865. animating: function() {
  18866. $module.removeClass(className.animating);
  18867. },
  18868. transition: function(transition) {
  18869. transition = transition || module.get.transition();
  18870. $module.removeClass(transition);
  18871. },
  18872. direction: function(direction) {
  18873. direction = direction || module.get.direction();
  18874. $module.removeClass(className[direction]);
  18875. },
  18876. visible: function() {
  18877. $module.removeClass(className.visible);
  18878. },
  18879. overlay: function() {
  18880. $module.removeClass(className.overlay);
  18881. }
  18882. },
  18883. get: {
  18884. direction: function() {
  18885. if($module.hasClass(className.top)) {
  18886. return className.top;
  18887. }
  18888. else if($module.hasClass(className.right)) {
  18889. return className.right;
  18890. }
  18891. else if($module.hasClass(className.bottom)) {
  18892. return className.bottom;
  18893. }
  18894. return className.left;
  18895. },
  18896. transition: function() {
  18897. var
  18898. direction = module.get.direction(),
  18899. transition
  18900. ;
  18901. transition = ( module.is.mobile() )
  18902. ? (settings.mobileTransition == 'auto')
  18903. ? settings.defaultTransition.mobile[direction]
  18904. : settings.mobileTransition
  18905. : (settings.transition == 'auto')
  18906. ? settings.defaultTransition.computer[direction]
  18907. : settings.transition
  18908. ;
  18909. module.verbose('Determined transition', transition);
  18910. return transition;
  18911. },
  18912. transitionEvent: function() {
  18913. var
  18914. element = document.createElement('element'),
  18915. transitions = {
  18916. 'transition' :'transitionend',
  18917. 'OTransition' :'oTransitionEnd',
  18918. 'MozTransition' :'transitionend',
  18919. 'WebkitTransition' :'webkitTransitionEnd'
  18920. },
  18921. transition
  18922. ;
  18923. for(transition in transitions){
  18924. if( element.style[transition] !== undefined ){
  18925. return transitions[transition];
  18926. }
  18927. }
  18928. }
  18929. },
  18930. is: {
  18931. ie: function() {
  18932. var
  18933. isIE11 = (!(window.ActiveXObject) && 'ActiveXObject' in window),
  18934. isIE = ('ActiveXObject' in window)
  18935. ;
  18936. return (isIE11 || isIE);
  18937. },
  18938. ios: function() {
  18939. var
  18940. userAgent = navigator.userAgent,
  18941. isIOS = userAgent.match(regExp.ios),
  18942. isMobileChrome = userAgent.match(regExp.mobileChrome)
  18943. ;
  18944. if(isIOS && !isMobileChrome) {
  18945. module.verbose('Browser was found to be iOS', userAgent);
  18946. return true;
  18947. }
  18948. else {
  18949. return false;
  18950. }
  18951. },
  18952. mobile: function() {
  18953. var
  18954. userAgent = navigator.userAgent,
  18955. isMobile = userAgent.match(regExp.mobile)
  18956. ;
  18957. if(isMobile) {
  18958. module.verbose('Browser was found to be mobile', userAgent);
  18959. return true;
  18960. }
  18961. else {
  18962. module.verbose('Browser is not mobile, using regular transition', userAgent);
  18963. return false;
  18964. }
  18965. },
  18966. hidden: function() {
  18967. return !module.is.visible();
  18968. },
  18969. visible: function() {
  18970. return $module.hasClass(className.visible);
  18971. },
  18972. // alias
  18973. open: function() {
  18974. return module.is.visible();
  18975. },
  18976. closed: function() {
  18977. return module.is.hidden();
  18978. },
  18979. vertical: function() {
  18980. return $module.hasClass(className.top);
  18981. },
  18982. animating: function() {
  18983. return $context.hasClass(className.animating);
  18984. },
  18985. rtl: function () {
  18986. if(module.cache.rtl === undefined) {
  18987. module.cache.rtl = ($module.css('direction') == 'rtl');
  18988. }
  18989. return module.cache.rtl;
  18990. }
  18991. },
  18992. setting: function(name, value) {
  18993. module.debug('Changing setting', name, value);
  18994. if( $.isPlainObject(name) ) {
  18995. $.extend(true, settings, name);
  18996. }
  18997. else if(value !== undefined) {
  18998. if($.isPlainObject(settings[name])) {
  18999. $.extend(true, settings[name], value);
  19000. }
  19001. else {
  19002. settings[name] = value;
  19003. }
  19004. }
  19005. else {
  19006. return settings[name];
  19007. }
  19008. },
  19009. internal: function(name, value) {
  19010. if( $.isPlainObject(name) ) {
  19011. $.extend(true, module, name);
  19012. }
  19013. else if(value !== undefined) {
  19014. module[name] = value;
  19015. }
  19016. else {
  19017. return module[name];
  19018. }
  19019. },
  19020. debug: function() {
  19021. if(!settings.silent && settings.debug) {
  19022. if(settings.performance) {
  19023. module.performance.log(arguments);
  19024. }
  19025. else {
  19026. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  19027. module.debug.apply(console, arguments);
  19028. }
  19029. }
  19030. },
  19031. verbose: function() {
  19032. if(!settings.silent && settings.verbose && settings.debug) {
  19033. if(settings.performance) {
  19034. module.performance.log(arguments);
  19035. }
  19036. else {
  19037. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  19038. module.verbose.apply(console, arguments);
  19039. }
  19040. }
  19041. },
  19042. error: function() {
  19043. if(!settings.silent) {
  19044. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  19045. module.error.apply(console, arguments);
  19046. }
  19047. },
  19048. performance: {
  19049. log: function(message) {
  19050. var
  19051. currentTime,
  19052. executionTime,
  19053. previousTime
  19054. ;
  19055. if(settings.performance) {
  19056. currentTime = new Date().getTime();
  19057. previousTime = time || currentTime;
  19058. executionTime = currentTime - previousTime;
  19059. time = currentTime;
  19060. performance.push({
  19061. 'Name' : message[0],
  19062. 'Arguments' : [].slice.call(message, 1) || '',
  19063. 'Element' : element,
  19064. 'Execution Time' : executionTime
  19065. });
  19066. }
  19067. clearTimeout(module.performance.timer);
  19068. module.performance.timer = setTimeout(module.performance.display, 500);
  19069. },
  19070. display: function() {
  19071. var
  19072. title = settings.name + ':',
  19073. totalTime = 0
  19074. ;
  19075. time = false;
  19076. clearTimeout(module.performance.timer);
  19077. $.each(performance, function(index, data) {
  19078. totalTime += data['Execution Time'];
  19079. });
  19080. title += ' ' + totalTime + 'ms';
  19081. if(moduleSelector) {
  19082. title += ' \'' + moduleSelector + '\'';
  19083. }
  19084. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  19085. console.groupCollapsed(title);
  19086. if(console.table) {
  19087. console.table(performance);
  19088. }
  19089. else {
  19090. $.each(performance, function(index, data) {
  19091. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  19092. });
  19093. }
  19094. console.groupEnd();
  19095. }
  19096. performance = [];
  19097. }
  19098. },
  19099. invoke: function(query, passedArguments, context) {
  19100. var
  19101. object = instance,
  19102. maxDepth,
  19103. found,
  19104. response
  19105. ;
  19106. passedArguments = passedArguments || queryArguments;
  19107. context = element || context;
  19108. if(typeof query == 'string' && object !== undefined) {
  19109. query = query.split(/[\. ]/);
  19110. maxDepth = query.length - 1;
  19111. $.each(query, function(depth, value) {
  19112. var camelCaseValue = (depth != maxDepth)
  19113. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  19114. : query
  19115. ;
  19116. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  19117. object = object[camelCaseValue];
  19118. }
  19119. else if( object[camelCaseValue] !== undefined ) {
  19120. found = object[camelCaseValue];
  19121. return false;
  19122. }
  19123. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  19124. object = object[value];
  19125. }
  19126. else if( object[value] !== undefined ) {
  19127. found = object[value];
  19128. return false;
  19129. }
  19130. else {
  19131. module.error(error.method, query);
  19132. return false;
  19133. }
  19134. });
  19135. }
  19136. if ( $.isFunction( found ) ) {
  19137. response = found.apply(context, passedArguments);
  19138. }
  19139. else if(found !== undefined) {
  19140. response = found;
  19141. }
  19142. if(Array.isArray(returnedValue)) {
  19143. returnedValue.push(response);
  19144. }
  19145. else if(returnedValue !== undefined) {
  19146. returnedValue = [returnedValue, response];
  19147. }
  19148. else if(response !== undefined) {
  19149. returnedValue = response;
  19150. }
  19151. return found;
  19152. }
  19153. }
  19154. ;
  19155. if(methodInvoked) {
  19156. if(instance === undefined) {
  19157. module.initialize();
  19158. }
  19159. module.invoke(query);
  19160. }
  19161. else {
  19162. if(instance !== undefined) {
  19163. module.invoke('destroy');
  19164. }
  19165. module.initialize();
  19166. }
  19167. });
  19168. return (returnedValue !== undefined)
  19169. ? returnedValue
  19170. : this
  19171. ;
  19172. };
  19173. $.fn.sidebar.settings = {
  19174. name : 'Sidebar',
  19175. namespace : 'sidebar',
  19176. silent : false,
  19177. debug : false,
  19178. verbose : false,
  19179. performance : true,
  19180. transition : 'auto',
  19181. mobileTransition : 'auto',
  19182. defaultTransition : {
  19183. computer: {
  19184. left : 'uncover',
  19185. right : 'uncover',
  19186. top : 'overlay',
  19187. bottom : 'overlay'
  19188. },
  19189. mobile: {
  19190. left : 'uncover',
  19191. right : 'uncover',
  19192. top : 'overlay',
  19193. bottom : 'overlay'
  19194. }
  19195. },
  19196. context : 'body',
  19197. exclusive : false,
  19198. closable : true,
  19199. dimPage : true,
  19200. scrollLock : false,
  19201. returnScroll : false,
  19202. delaySetup : false,
  19203. duration : 500,
  19204. onChange : function(){},
  19205. onShow : function(){},
  19206. onHide : function(){},
  19207. onHidden : function(){},
  19208. onVisible : function(){},
  19209. className : {
  19210. active : 'active',
  19211. animating : 'animating',
  19212. dimmed : 'dimmed',
  19213. ios : 'ios',
  19214. pushable : 'pushable',
  19215. pushed : 'pushed',
  19216. right : 'right',
  19217. top : 'top',
  19218. left : 'left',
  19219. bottom : 'bottom',
  19220. visible : 'visible'
  19221. },
  19222. selector: {
  19223. fixed : '.fixed',
  19224. omitted : 'script, link, style, .ui.modal, .ui.dimmer, .ui.nag, .ui.fixed',
  19225. pusher : '.pusher',
  19226. sidebar : '.ui.sidebar'
  19227. },
  19228. regExp: {
  19229. ios : /(iPad|iPhone|iPod)/g,
  19230. mobileChrome : /(CriOS)/g,
  19231. mobile : /Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/g
  19232. },
  19233. error : {
  19234. method : 'The method you called is not defined.',
  19235. pusher : 'Had to add pusher element. For optimal performance make sure body content is inside a pusher element',
  19236. movedSidebar : 'Had to move sidebar. For optimal performance make sure sidebar and pusher are direct children of your body tag',
  19237. overlay : 'The overlay setting is no longer supported, use animation: overlay',
  19238. notFound : 'There were no elements that matched the specified selector'
  19239. }
  19240. };
  19241. })( jQuery, window, document );
  19242. /*!
  19243. * # Fomantic-UI - Sticky
  19244. * http://github.com/fomantic/Fomantic-UI/
  19245. *
  19246. *
  19247. * Released under the MIT license
  19248. * http://opensource.org/licenses/MIT
  19249. *
  19250. */
  19251. ;(function ($, window, document, undefined) {
  19252. 'use strict';
  19253. $.isFunction = $.isFunction || function(obj) {
  19254. return typeof obj === "function" && typeof obj.nodeType !== "number";
  19255. };
  19256. window = (typeof window != 'undefined' && window.Math == Math)
  19257. ? window
  19258. : (typeof self != 'undefined' && self.Math == Math)
  19259. ? self
  19260. : Function('return this')()
  19261. ;
  19262. $.fn.sticky = function(parameters) {
  19263. var
  19264. $allModules = $(this),
  19265. moduleSelector = $allModules.selector || '',
  19266. time = new Date().getTime(),
  19267. performance = [],
  19268. query = arguments[0],
  19269. methodInvoked = (typeof query == 'string'),
  19270. queryArguments = [].slice.call(arguments, 1),
  19271. returnedValue
  19272. ;
  19273. $allModules
  19274. .each(function() {
  19275. var
  19276. settings = ( $.isPlainObject(parameters) )
  19277. ? $.extend(true, {}, $.fn.sticky.settings, parameters)
  19278. : $.extend({}, $.fn.sticky.settings),
  19279. className = settings.className,
  19280. namespace = settings.namespace,
  19281. error = settings.error,
  19282. eventNamespace = '.' + namespace,
  19283. moduleNamespace = 'module-' + namespace,
  19284. $module = $(this),
  19285. $window = $(window),
  19286. $scroll = $(settings.scrollContext),
  19287. $container,
  19288. $context,
  19289. instance = $module.data(moduleNamespace),
  19290. requestAnimationFrame = window.requestAnimationFrame
  19291. || window.mozRequestAnimationFrame
  19292. || window.webkitRequestAnimationFrame
  19293. || window.msRequestAnimationFrame
  19294. || function(callback) { setTimeout(callback, 0); },
  19295. element = this,
  19296. documentObserver,
  19297. observer,
  19298. module
  19299. ;
  19300. module = {
  19301. initialize: function() {
  19302. module.determineContainer();
  19303. module.determineContext();
  19304. module.verbose('Initializing sticky', settings, $container);
  19305. module.save.positions();
  19306. module.checkErrors();
  19307. module.bind.events();
  19308. if(settings.observeChanges) {
  19309. module.observeChanges();
  19310. }
  19311. module.instantiate();
  19312. },
  19313. instantiate: function() {
  19314. module.verbose('Storing instance of module', module);
  19315. instance = module;
  19316. $module
  19317. .data(moduleNamespace, module)
  19318. ;
  19319. },
  19320. destroy: function() {
  19321. module.verbose('Destroying previous instance');
  19322. module.reset();
  19323. if(documentObserver) {
  19324. documentObserver.disconnect();
  19325. }
  19326. if(observer) {
  19327. observer.disconnect();
  19328. }
  19329. $window
  19330. .off('load' + eventNamespace, module.event.load)
  19331. .off('resize' + eventNamespace, module.event.resize)
  19332. ;
  19333. $scroll
  19334. .off('scrollchange' + eventNamespace, module.event.scrollchange)
  19335. ;
  19336. $module.removeData(moduleNamespace);
  19337. },
  19338. observeChanges: function() {
  19339. if('MutationObserver' in window) {
  19340. documentObserver = new MutationObserver(module.event.documentChanged);
  19341. observer = new MutationObserver(module.event.changed);
  19342. documentObserver.observe(document, {
  19343. childList : true,
  19344. subtree : true
  19345. });
  19346. observer.observe(element, {
  19347. childList : true,
  19348. subtree : true
  19349. });
  19350. observer.observe($context[0], {
  19351. childList : true,
  19352. subtree : true
  19353. });
  19354. module.debug('Setting up mutation observer', observer);
  19355. }
  19356. },
  19357. determineContainer: function() {
  19358. if(settings.container) {
  19359. $container = $(settings.container);
  19360. }
  19361. else {
  19362. $container = $module.offsetParent();
  19363. }
  19364. },
  19365. determineContext: function() {
  19366. if(settings.context) {
  19367. $context = $(settings.context);
  19368. }
  19369. else {
  19370. $context = $container;
  19371. }
  19372. if($context.length === 0) {
  19373. module.error(error.invalidContext, settings.context, $module);
  19374. return;
  19375. }
  19376. },
  19377. checkErrors: function() {
  19378. if( module.is.hidden() ) {
  19379. module.error(error.visible, $module);
  19380. }
  19381. if(module.cache.element.height > module.cache.context.height) {
  19382. module.reset();
  19383. module.error(error.elementSize, $module);
  19384. return;
  19385. }
  19386. },
  19387. bind: {
  19388. events: function() {
  19389. $window
  19390. .on('load' + eventNamespace, module.event.load)
  19391. .on('resize' + eventNamespace, module.event.resize)
  19392. ;
  19393. // pub/sub pattern
  19394. $scroll
  19395. .off('scroll' + eventNamespace)
  19396. .on('scroll' + eventNamespace, module.event.scroll)
  19397. .on('scrollchange' + eventNamespace, module.event.scrollchange)
  19398. ;
  19399. }
  19400. },
  19401. event: {
  19402. changed: function(mutations) {
  19403. clearTimeout(module.timer);
  19404. module.timer = setTimeout(function() {
  19405. module.verbose('DOM tree modified, updating sticky menu', mutations);
  19406. module.refresh();
  19407. }, 100);
  19408. },
  19409. documentChanged: function(mutations) {
  19410. [].forEach.call(mutations, function(mutation) {
  19411. if(mutation.removedNodes) {
  19412. [].forEach.call(mutation.removedNodes, function(node) {
  19413. if(node == element || $(node).find(element).length > 0) {
  19414. module.debug('Element removed from DOM, tearing down events');
  19415. module.destroy();
  19416. }
  19417. });
  19418. }
  19419. });
  19420. },
  19421. load: function() {
  19422. module.verbose('Page contents finished loading');
  19423. requestAnimationFrame(module.refresh);
  19424. },
  19425. resize: function() {
  19426. module.verbose('Window resized');
  19427. requestAnimationFrame(module.refresh);
  19428. },
  19429. scroll: function() {
  19430. requestAnimationFrame(function() {
  19431. $scroll.triggerHandler('scrollchange' + eventNamespace, $scroll.scrollTop() );
  19432. });
  19433. },
  19434. scrollchange: function(event, scrollPosition) {
  19435. module.stick(scrollPosition);
  19436. settings.onScroll.call(element);
  19437. }
  19438. },
  19439. refresh: function(hardRefresh) {
  19440. module.reset();
  19441. if(!settings.context) {
  19442. module.determineContext();
  19443. }
  19444. if(hardRefresh) {
  19445. module.determineContainer();
  19446. }
  19447. module.save.positions();
  19448. module.stick();
  19449. settings.onReposition.call(element);
  19450. },
  19451. supports: {
  19452. sticky: function() {
  19453. var
  19454. $element = $('<div/>')
  19455. ;
  19456. $element.addClass(className.supported);
  19457. return($element.css('position').match('sticky'));
  19458. }
  19459. },
  19460. save: {
  19461. lastScroll: function(scroll) {
  19462. module.lastScroll = scroll;
  19463. },
  19464. elementScroll: function(scroll) {
  19465. module.elementScroll = scroll;
  19466. },
  19467. positions: function() {
  19468. var
  19469. scrollContext = {
  19470. height : $scroll.height()
  19471. },
  19472. element = {
  19473. margin: {
  19474. top : parseInt($module.css('margin-top'), 10),
  19475. bottom : parseInt($module.css('margin-bottom'), 10),
  19476. },
  19477. offset : $module.offset(),
  19478. width : $module.outerWidth(),
  19479. height : $module.outerHeight()
  19480. },
  19481. context = {
  19482. offset : $context.offset(),
  19483. height : $context.outerHeight()
  19484. }
  19485. ;
  19486. if( !module.is.standardScroll() ) {
  19487. module.debug('Non-standard scroll. Removing scroll offset from element offset');
  19488. scrollContext.top = $scroll.scrollTop();
  19489. scrollContext.left = $scroll.scrollLeft();
  19490. element.offset.top += scrollContext.top;
  19491. context.offset.top += scrollContext.top;
  19492. element.offset.left += scrollContext.left;
  19493. context.offset.left += scrollContext.left;
  19494. }
  19495. module.cache = {
  19496. fits : ( (element.height + settings.offset) <= scrollContext.height),
  19497. sameHeight : (element.height == context.height),
  19498. scrollContext : {
  19499. height : scrollContext.height
  19500. },
  19501. element: {
  19502. margin : element.margin,
  19503. top : element.offset.top - element.margin.top,
  19504. left : element.offset.left,
  19505. width : element.width,
  19506. height : element.height,
  19507. bottom : element.offset.top + element.height
  19508. },
  19509. context: {
  19510. top : context.offset.top,
  19511. height : context.height,
  19512. bottom : context.offset.top + context.height
  19513. }
  19514. };
  19515. module.set.containerSize();
  19516. module.stick();
  19517. module.debug('Caching element positions', module.cache);
  19518. }
  19519. },
  19520. get: {
  19521. direction: function(scroll) {
  19522. var
  19523. direction = 'down'
  19524. ;
  19525. scroll = scroll || $scroll.scrollTop();
  19526. if(module.lastScroll !== undefined) {
  19527. if(module.lastScroll < scroll) {
  19528. direction = 'down';
  19529. }
  19530. else if(module.lastScroll > scroll) {
  19531. direction = 'up';
  19532. }
  19533. }
  19534. return direction;
  19535. },
  19536. scrollChange: function(scroll) {
  19537. scroll = scroll || $scroll.scrollTop();
  19538. return (module.lastScroll)
  19539. ? (scroll - module.lastScroll)
  19540. : 0
  19541. ;
  19542. },
  19543. currentElementScroll: function() {
  19544. if(module.elementScroll) {
  19545. return module.elementScroll;
  19546. }
  19547. return ( module.is.top() )
  19548. ? Math.abs(parseInt($module.css('top'), 10)) || 0
  19549. : Math.abs(parseInt($module.css('bottom'), 10)) || 0
  19550. ;
  19551. },
  19552. elementScroll: function(scroll) {
  19553. scroll = scroll || $scroll.scrollTop();
  19554. var
  19555. element = module.cache.element,
  19556. scrollContext = module.cache.scrollContext,
  19557. delta = module.get.scrollChange(scroll),
  19558. maxScroll = (element.height - scrollContext.height + settings.offset),
  19559. elementScroll = module.get.currentElementScroll(),
  19560. possibleScroll = (elementScroll + delta)
  19561. ;
  19562. if(module.cache.fits || possibleScroll < 0) {
  19563. elementScroll = 0;
  19564. }
  19565. else if(possibleScroll > maxScroll ) {
  19566. elementScroll = maxScroll;
  19567. }
  19568. else {
  19569. elementScroll = possibleScroll;
  19570. }
  19571. return elementScroll;
  19572. }
  19573. },
  19574. remove: {
  19575. lastScroll: function() {
  19576. delete module.lastScroll;
  19577. },
  19578. elementScroll: function(scroll) {
  19579. delete module.elementScroll;
  19580. },
  19581. minimumSize: function() {
  19582. $container
  19583. .css('min-height', '')
  19584. ;
  19585. },
  19586. offset: function() {
  19587. $module.css('margin-top', '');
  19588. }
  19589. },
  19590. set: {
  19591. offset: function() {
  19592. module.verbose('Setting offset on element', settings.offset);
  19593. $module
  19594. .css('margin-top', settings.offset)
  19595. ;
  19596. },
  19597. containerSize: function() {
  19598. var
  19599. tagName = $container.get(0).tagName
  19600. ;
  19601. if(tagName === 'HTML' || tagName == 'body') {
  19602. // this can trigger for too many reasons
  19603. //module.error(error.container, tagName, $module);
  19604. module.determineContainer();
  19605. }
  19606. else {
  19607. if( Math.abs($container.outerHeight() - module.cache.context.height) > settings.jitter) {
  19608. module.debug('Context has padding, specifying exact height for container', module.cache.context.height);
  19609. $container.css({
  19610. height: module.cache.context.height
  19611. });
  19612. }
  19613. }
  19614. },
  19615. minimumSize: function() {
  19616. var
  19617. element = module.cache.element
  19618. ;
  19619. $container
  19620. .css('min-height', element.height)
  19621. ;
  19622. },
  19623. scroll: function(scroll) {
  19624. module.debug('Setting scroll on element', scroll);
  19625. if(module.elementScroll == scroll) {
  19626. return;
  19627. }
  19628. if( module.is.top() ) {
  19629. $module
  19630. .css('bottom', '')
  19631. .css('top', -scroll)
  19632. ;
  19633. }
  19634. if( module.is.bottom() ) {
  19635. $module
  19636. .css('top', '')
  19637. .css('bottom', scroll)
  19638. ;
  19639. }
  19640. },
  19641. size: function() {
  19642. if(module.cache.element.height !== 0 && module.cache.element.width !== 0) {
  19643. element.style.setProperty('width', module.cache.element.width + 'px', 'important');
  19644. element.style.setProperty('height', module.cache.element.height + 'px', 'important');
  19645. }
  19646. }
  19647. },
  19648. is: {
  19649. standardScroll: function() {
  19650. return ($scroll[0] == window);
  19651. },
  19652. top: function() {
  19653. return $module.hasClass(className.top);
  19654. },
  19655. bottom: function() {
  19656. return $module.hasClass(className.bottom);
  19657. },
  19658. initialPosition: function() {
  19659. return (!module.is.fixed() && !module.is.bound());
  19660. },
  19661. hidden: function() {
  19662. return (!$module.is(':visible'));
  19663. },
  19664. bound: function() {
  19665. return $module.hasClass(className.bound);
  19666. },
  19667. fixed: function() {
  19668. return $module.hasClass(className.fixed);
  19669. }
  19670. },
  19671. stick: function(scroll) {
  19672. var
  19673. cachedPosition = scroll || $scroll.scrollTop(),
  19674. cache = module.cache,
  19675. fits = cache.fits,
  19676. sameHeight = cache.sameHeight,
  19677. element = cache.element,
  19678. scrollContext = cache.scrollContext,
  19679. context = cache.context,
  19680. offset = (module.is.bottom() && settings.pushing)
  19681. ? settings.bottomOffset
  19682. : settings.offset,
  19683. scroll = {
  19684. top : cachedPosition + offset,
  19685. bottom : cachedPosition + offset + scrollContext.height
  19686. },
  19687. elementScroll = (fits)
  19688. ? 0
  19689. : module.get.elementScroll(scroll.top),
  19690. // shorthand
  19691. doesntFit = !fits,
  19692. elementVisible = (element.height !== 0)
  19693. ;
  19694. if(elementVisible && !sameHeight) {
  19695. if( module.is.initialPosition() ) {
  19696. if(scroll.top >= context.bottom) {
  19697. module.debug('Initial element position is bottom of container');
  19698. module.bindBottom();
  19699. }
  19700. else if(scroll.top > element.top) {
  19701. if( (element.height + scroll.top - elementScroll) >= context.bottom ) {
  19702. module.debug('Initial element position is bottom of container');
  19703. module.bindBottom();
  19704. }
  19705. else {
  19706. module.debug('Initial element position is fixed');
  19707. module.fixTop();
  19708. }
  19709. }
  19710. }
  19711. else if( module.is.fixed() ) {
  19712. // currently fixed top
  19713. if( module.is.top() ) {
  19714. if( scroll.top <= element.top ) {
  19715. module.debug('Fixed element reached top of container');
  19716. module.setInitialPosition();
  19717. }
  19718. else if( (element.height + scroll.top - elementScroll) >= context.bottom ) {
  19719. module.debug('Fixed element reached bottom of container');
  19720. module.bindBottom();
  19721. }
  19722. // scroll element if larger than screen
  19723. else if(doesntFit) {
  19724. module.set.scroll(elementScroll);
  19725. module.save.lastScroll(scroll.top);
  19726. module.save.elementScroll(elementScroll);
  19727. }
  19728. }
  19729. // currently fixed bottom
  19730. else if(module.is.bottom() ) {
  19731. // top edge
  19732. if( (scroll.bottom - element.height) <= element.top) {
  19733. module.debug('Bottom fixed rail has reached top of container');
  19734. module.setInitialPosition();
  19735. }
  19736. // bottom edge
  19737. else if(scroll.bottom >= context.bottom) {
  19738. module.debug('Bottom fixed rail has reached bottom of container');
  19739. module.bindBottom();
  19740. }
  19741. // scroll element if larger than screen
  19742. else if(doesntFit) {
  19743. module.set.scroll(elementScroll);
  19744. module.save.lastScroll(scroll.top);
  19745. module.save.elementScroll(elementScroll);
  19746. }
  19747. }
  19748. }
  19749. else if( module.is.bottom() ) {
  19750. if( scroll.top <= element.top ) {
  19751. module.debug('Jumped from bottom fixed to top fixed, most likely used home/end button');
  19752. module.setInitialPosition();
  19753. }
  19754. else {
  19755. if(settings.pushing) {
  19756. if(module.is.bound() && scroll.bottom <= context.bottom ) {
  19757. module.debug('Fixing bottom attached element to bottom of browser.');
  19758. module.fixBottom();
  19759. }
  19760. }
  19761. else {
  19762. if(module.is.bound() && (scroll.top <= context.bottom - element.height) ) {
  19763. module.debug('Fixing bottom attached element to top of browser.');
  19764. module.fixTop();
  19765. }
  19766. }
  19767. }
  19768. }
  19769. }
  19770. },
  19771. bindTop: function() {
  19772. module.debug('Binding element to top of parent container');
  19773. module.remove.offset();
  19774. $module
  19775. .css({
  19776. left : '',
  19777. top : '',
  19778. marginBottom : ''
  19779. })
  19780. .removeClass(className.fixed)
  19781. .removeClass(className.bottom)
  19782. .addClass(className.bound)
  19783. .addClass(className.top)
  19784. ;
  19785. settings.onTop.call(element);
  19786. settings.onUnstick.call(element);
  19787. },
  19788. bindBottom: function() {
  19789. module.debug('Binding element to bottom of parent container');
  19790. module.remove.offset();
  19791. $module
  19792. .css({
  19793. left : '',
  19794. top : ''
  19795. })
  19796. .removeClass(className.fixed)
  19797. .removeClass(className.top)
  19798. .addClass(className.bound)
  19799. .addClass(className.bottom)
  19800. ;
  19801. settings.onBottom.call(element);
  19802. settings.onUnstick.call(element);
  19803. },
  19804. setInitialPosition: function() {
  19805. module.debug('Returning to initial position');
  19806. module.unfix();
  19807. module.unbind();
  19808. },
  19809. fixTop: function() {
  19810. module.debug('Fixing element to top of page');
  19811. if(settings.setSize) {
  19812. module.set.size();
  19813. }
  19814. module.set.minimumSize();
  19815. module.set.offset();
  19816. $module
  19817. .css({
  19818. left : module.cache.element.left,
  19819. bottom : '',
  19820. marginBottom : ''
  19821. })
  19822. .removeClass(className.bound)
  19823. .removeClass(className.bottom)
  19824. .addClass(className.fixed)
  19825. .addClass(className.top)
  19826. ;
  19827. settings.onStick.call(element);
  19828. },
  19829. fixBottom: function() {
  19830. module.debug('Sticking element to bottom of page');
  19831. if(settings.setSize) {
  19832. module.set.size();
  19833. }
  19834. module.set.minimumSize();
  19835. module.set.offset();
  19836. $module
  19837. .css({
  19838. left : module.cache.element.left,
  19839. bottom : '',
  19840. marginBottom : ''
  19841. })
  19842. .removeClass(className.bound)
  19843. .removeClass(className.top)
  19844. .addClass(className.fixed)
  19845. .addClass(className.bottom)
  19846. ;
  19847. settings.onStick.call(element);
  19848. },
  19849. unbind: function() {
  19850. if( module.is.bound() ) {
  19851. module.debug('Removing container bound position on element');
  19852. module.remove.offset();
  19853. $module
  19854. .removeClass(className.bound)
  19855. .removeClass(className.top)
  19856. .removeClass(className.bottom)
  19857. ;
  19858. }
  19859. },
  19860. unfix: function() {
  19861. if( module.is.fixed() ) {
  19862. module.debug('Removing fixed position on element');
  19863. module.remove.minimumSize();
  19864. module.remove.offset();
  19865. $module
  19866. .removeClass(className.fixed)
  19867. .removeClass(className.top)
  19868. .removeClass(className.bottom)
  19869. ;
  19870. settings.onUnstick.call(element);
  19871. }
  19872. },
  19873. reset: function() {
  19874. module.debug('Resetting elements position');
  19875. module.unbind();
  19876. module.unfix();
  19877. module.resetCSS();
  19878. module.remove.offset();
  19879. module.remove.lastScroll();
  19880. },
  19881. resetCSS: function() {
  19882. $module
  19883. .css({
  19884. width : '',
  19885. height : ''
  19886. })
  19887. ;
  19888. $container
  19889. .css({
  19890. height: ''
  19891. })
  19892. ;
  19893. },
  19894. setting: function(name, value) {
  19895. if( $.isPlainObject(name) ) {
  19896. $.extend(true, settings, name);
  19897. }
  19898. else if(value !== undefined) {
  19899. settings[name] = value;
  19900. }
  19901. else {
  19902. return settings[name];
  19903. }
  19904. },
  19905. internal: function(name, value) {
  19906. if( $.isPlainObject(name) ) {
  19907. $.extend(true, module, name);
  19908. }
  19909. else if(value !== undefined) {
  19910. module[name] = value;
  19911. }
  19912. else {
  19913. return module[name];
  19914. }
  19915. },
  19916. debug: function() {
  19917. if(!settings.silent && settings.debug) {
  19918. if(settings.performance) {
  19919. module.performance.log(arguments);
  19920. }
  19921. else {
  19922. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  19923. module.debug.apply(console, arguments);
  19924. }
  19925. }
  19926. },
  19927. verbose: function() {
  19928. if(!settings.silent && settings.verbose && settings.debug) {
  19929. if(settings.performance) {
  19930. module.performance.log(arguments);
  19931. }
  19932. else {
  19933. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  19934. module.verbose.apply(console, arguments);
  19935. }
  19936. }
  19937. },
  19938. error: function() {
  19939. if(!settings.silent) {
  19940. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  19941. module.error.apply(console, arguments);
  19942. }
  19943. },
  19944. performance: {
  19945. log: function(message) {
  19946. var
  19947. currentTime,
  19948. executionTime,
  19949. previousTime
  19950. ;
  19951. if(settings.performance) {
  19952. currentTime = new Date().getTime();
  19953. previousTime = time || currentTime;
  19954. executionTime = currentTime - previousTime;
  19955. time = currentTime;
  19956. performance.push({
  19957. 'Name' : message[0],
  19958. 'Arguments' : [].slice.call(message, 1) || '',
  19959. 'Element' : element,
  19960. 'Execution Time' : executionTime
  19961. });
  19962. }
  19963. clearTimeout(module.performance.timer);
  19964. module.performance.timer = setTimeout(module.performance.display, 0);
  19965. },
  19966. display: function() {
  19967. var
  19968. title = settings.name + ':',
  19969. totalTime = 0
  19970. ;
  19971. time = false;
  19972. clearTimeout(module.performance.timer);
  19973. $.each(performance, function(index, data) {
  19974. totalTime += data['Execution Time'];
  19975. });
  19976. title += ' ' + totalTime + 'ms';
  19977. if(moduleSelector) {
  19978. title += ' \'' + moduleSelector + '\'';
  19979. }
  19980. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  19981. console.groupCollapsed(title);
  19982. if(console.table) {
  19983. console.table(performance);
  19984. }
  19985. else {
  19986. $.each(performance, function(index, data) {
  19987. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  19988. });
  19989. }
  19990. console.groupEnd();
  19991. }
  19992. performance = [];
  19993. }
  19994. },
  19995. invoke: function(query, passedArguments, context) {
  19996. var
  19997. object = instance,
  19998. maxDepth,
  19999. found,
  20000. response
  20001. ;
  20002. passedArguments = passedArguments || queryArguments;
  20003. context = element || context;
  20004. if(typeof query == 'string' && object !== undefined) {
  20005. query = query.split(/[\. ]/);
  20006. maxDepth = query.length - 1;
  20007. $.each(query, function(depth, value) {
  20008. var camelCaseValue = (depth != maxDepth)
  20009. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  20010. : query
  20011. ;
  20012. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  20013. object = object[camelCaseValue];
  20014. }
  20015. else if( object[camelCaseValue] !== undefined ) {
  20016. found = object[camelCaseValue];
  20017. return false;
  20018. }
  20019. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  20020. object = object[value];
  20021. }
  20022. else if( object[value] !== undefined ) {
  20023. found = object[value];
  20024. return false;
  20025. }
  20026. else {
  20027. return false;
  20028. }
  20029. });
  20030. }
  20031. if ( $.isFunction( found ) ) {
  20032. response = found.apply(context, passedArguments);
  20033. }
  20034. else if(found !== undefined) {
  20035. response = found;
  20036. }
  20037. if(Array.isArray(returnedValue)) {
  20038. returnedValue.push(response);
  20039. }
  20040. else if(returnedValue !== undefined) {
  20041. returnedValue = [returnedValue, response];
  20042. }
  20043. else if(response !== undefined) {
  20044. returnedValue = response;
  20045. }
  20046. return found;
  20047. }
  20048. };
  20049. if(methodInvoked) {
  20050. if(instance === undefined) {
  20051. module.initialize();
  20052. }
  20053. module.invoke(query);
  20054. }
  20055. else {
  20056. if(instance !== undefined) {
  20057. instance.invoke('destroy');
  20058. }
  20059. module.initialize();
  20060. }
  20061. })
  20062. ;
  20063. return (returnedValue !== undefined)
  20064. ? returnedValue
  20065. : this
  20066. ;
  20067. };
  20068. $.fn.sticky.settings = {
  20069. name : 'Sticky',
  20070. namespace : 'sticky',
  20071. silent : false,
  20072. debug : false,
  20073. verbose : true,
  20074. performance : true,
  20075. // whether to stick in the opposite direction on scroll up
  20076. pushing : false,
  20077. context : false,
  20078. container : false,
  20079. // Context to watch scroll events
  20080. scrollContext : window,
  20081. // Offset to adjust scroll
  20082. offset : 0,
  20083. // Offset to adjust scroll when attached to bottom of screen
  20084. bottomOffset : 0,
  20085. // will only set container height if difference between context and container is larger than this number
  20086. jitter : 5,
  20087. // set width of sticky element when it is fixed to page (used to make sure 100% width is maintained if no fixed size set)
  20088. setSize : true,
  20089. // Whether to automatically observe changes with Mutation Observers
  20090. observeChanges : false,
  20091. // Called when position is recalculated
  20092. onReposition : function(){},
  20093. // Called on each scroll
  20094. onScroll : function(){},
  20095. // Called when element is stuck to viewport
  20096. onStick : function(){},
  20097. // Called when element is unstuck from viewport
  20098. onUnstick : function(){},
  20099. // Called when element reaches top of context
  20100. onTop : function(){},
  20101. // Called when element reaches bottom of context
  20102. onBottom : function(){},
  20103. error : {
  20104. container : 'Sticky element must be inside a relative container',
  20105. visible : 'Element is hidden, you must call refresh after element becomes visible. Use silent setting to surpress this warning in production.',
  20106. method : 'The method you called is not defined.',
  20107. invalidContext : 'Context specified does not exist',
  20108. elementSize : 'Sticky element is larger than its container, cannot create sticky.'
  20109. },
  20110. className : {
  20111. bound : 'bound',
  20112. fixed : 'fixed',
  20113. supported : 'native',
  20114. top : 'top',
  20115. bottom : 'bottom'
  20116. }
  20117. };
  20118. })( jQuery, window, document );
  20119. /*!
  20120. * # Fomantic-UI - Tab
  20121. * http://github.com/fomantic/Fomantic-UI/
  20122. *
  20123. *
  20124. * Released under the MIT license
  20125. * http://opensource.org/licenses/MIT
  20126. *
  20127. */
  20128. ;(function ($, window, document, undefined) {
  20129. 'use strict';
  20130. $.isWindow = $.isWindow || function(obj) {
  20131. return obj != null && obj === obj.window;
  20132. };
  20133. $.isFunction = $.isFunction || function(obj) {
  20134. return typeof obj === "function" && typeof obj.nodeType !== "number";
  20135. };
  20136. window = (typeof window != 'undefined' && window.Math == Math)
  20137. ? window
  20138. : (typeof self != 'undefined' && self.Math == Math)
  20139. ? self
  20140. : Function('return this')()
  20141. ;
  20142. $.fn.tab = function(parameters) {
  20143. var
  20144. // use window context if none specified
  20145. $allModules = $.isFunction(this)
  20146. ? $(window)
  20147. : $(this),
  20148. moduleSelector = $allModules.selector || '',
  20149. time = new Date().getTime(),
  20150. performance = [],
  20151. query = arguments[0],
  20152. methodInvoked = (typeof query == 'string'),
  20153. queryArguments = [].slice.call(arguments, 1),
  20154. initializedHistory = false,
  20155. returnedValue
  20156. ;
  20157. $allModules
  20158. .each(function() {
  20159. var
  20160. settings = ( $.isPlainObject(parameters) )
  20161. ? $.extend(true, {}, $.fn.tab.settings, parameters)
  20162. : $.extend({}, $.fn.tab.settings),
  20163. className = settings.className,
  20164. metadata = settings.metadata,
  20165. selector = settings.selector,
  20166. error = settings.error,
  20167. regExp = settings.regExp,
  20168. eventNamespace = '.' + settings.namespace,
  20169. moduleNamespace = 'module-' + settings.namespace,
  20170. $module = $(this),
  20171. $context,
  20172. $tabs,
  20173. cache = {},
  20174. firstLoad = true,
  20175. recursionDepth = 0,
  20176. element = this,
  20177. instance = $module.data(moduleNamespace),
  20178. activeTabPath,
  20179. parameterArray,
  20180. module,
  20181. historyEvent
  20182. ;
  20183. module = {
  20184. initialize: function() {
  20185. module.debug('Initializing tab menu item', $module);
  20186. module.fix.callbacks();
  20187. module.determineTabs();
  20188. module.debug('Determining tabs', settings.context, $tabs);
  20189. // set up automatic routing
  20190. if(settings.auto) {
  20191. module.set.auto();
  20192. }
  20193. module.bind.events();
  20194. if(settings.history && !initializedHistory) {
  20195. module.initializeHistory();
  20196. initializedHistory = true;
  20197. }
  20198. if(module.determine.activeTab() == null) {
  20199. module.debug('No active tab detected, setting first tab active', module.get.initialPath());
  20200. module.changeTab(module.get.initialPath());
  20201. };
  20202. module.instantiate();
  20203. },
  20204. instantiate: function () {
  20205. module.verbose('Storing instance of module', module);
  20206. instance = module;
  20207. $module
  20208. .data(moduleNamespace, module)
  20209. ;
  20210. },
  20211. destroy: function() {
  20212. module.debug('Destroying tabs', $module);
  20213. $module
  20214. .removeData(moduleNamespace)
  20215. .off(eventNamespace)
  20216. ;
  20217. },
  20218. bind: {
  20219. events: function() {
  20220. // if using $.tab don't add events
  20221. if( !$.isWindow( element ) ) {
  20222. module.debug('Attaching tab activation events to element', $module);
  20223. $module
  20224. .on('click' + eventNamespace, module.event.click)
  20225. ;
  20226. }
  20227. }
  20228. },
  20229. determineTabs: function() {
  20230. var
  20231. $reference
  20232. ;
  20233. // determine tab context
  20234. if(settings.context === 'parent') {
  20235. if($module.closest(selector.ui).length > 0) {
  20236. $reference = $module.closest(selector.ui);
  20237. module.verbose('Using closest UI element as parent', $reference);
  20238. }
  20239. else {
  20240. $reference = $module;
  20241. }
  20242. $context = $reference.parent();
  20243. module.verbose('Determined parent element for creating context', $context);
  20244. }
  20245. else if(settings.context) {
  20246. $context = $(settings.context);
  20247. module.verbose('Using selector for tab context', settings.context, $context);
  20248. }
  20249. else {
  20250. $context = $('body');
  20251. }
  20252. // find tabs
  20253. if(settings.childrenOnly) {
  20254. $tabs = $context.children(selector.tabs);
  20255. module.debug('Searching tab context children for tabs', $context, $tabs);
  20256. }
  20257. else {
  20258. $tabs = $context.find(selector.tabs);
  20259. module.debug('Searching tab context for tabs', $context, $tabs);
  20260. }
  20261. },
  20262. fix: {
  20263. callbacks: function() {
  20264. if( $.isPlainObject(parameters) && (parameters.onTabLoad || parameters.onTabInit) ) {
  20265. if(parameters.onTabLoad) {
  20266. parameters.onLoad = parameters.onTabLoad;
  20267. delete parameters.onTabLoad;
  20268. module.error(error.legacyLoad, parameters.onLoad);
  20269. }
  20270. if(parameters.onTabInit) {
  20271. parameters.onFirstLoad = parameters.onTabInit;
  20272. delete parameters.onTabInit;
  20273. module.error(error.legacyInit, parameters.onFirstLoad);
  20274. }
  20275. settings = $.extend(true, {}, $.fn.tab.settings, parameters);
  20276. }
  20277. }
  20278. },
  20279. initializeHistory: function() {
  20280. module.debug('Initializing page state');
  20281. if( $.address === undefined ) {
  20282. module.error(error.state);
  20283. return false;
  20284. }
  20285. else {
  20286. if(settings.historyType == 'state') {
  20287. module.debug('Using HTML5 to manage state');
  20288. if(settings.path !== false) {
  20289. $.address
  20290. .history(true)
  20291. .state(settings.path)
  20292. ;
  20293. }
  20294. else {
  20295. module.error(error.path);
  20296. return false;
  20297. }
  20298. }
  20299. $.address
  20300. .bind('change', module.event.history.change)
  20301. ;
  20302. }
  20303. },
  20304. event: {
  20305. click: function(event) {
  20306. var
  20307. tabPath = $(this).data(metadata.tab)
  20308. ;
  20309. if(tabPath !== undefined) {
  20310. if(settings.history) {
  20311. module.verbose('Updating page state', event);
  20312. $.address.value(tabPath);
  20313. }
  20314. else {
  20315. module.verbose('Changing tab', event);
  20316. module.changeTab(tabPath);
  20317. }
  20318. event.preventDefault();
  20319. }
  20320. else {
  20321. module.debug('No tab specified');
  20322. }
  20323. },
  20324. history: {
  20325. change: function(event) {
  20326. var
  20327. tabPath = event.pathNames.join('/') || module.get.initialPath(),
  20328. pageTitle = settings.templates.determineTitle(tabPath) || false
  20329. ;
  20330. module.performance.display();
  20331. module.debug('History change event', tabPath, event);
  20332. historyEvent = event;
  20333. if(tabPath !== undefined) {
  20334. module.changeTab(tabPath);
  20335. }
  20336. if(pageTitle) {
  20337. $.address.title(pageTitle);
  20338. }
  20339. }
  20340. }
  20341. },
  20342. refresh: function() {
  20343. if(activeTabPath) {
  20344. module.debug('Refreshing tab', activeTabPath);
  20345. module.changeTab(activeTabPath);
  20346. }
  20347. },
  20348. cache: {
  20349. read: function(cacheKey) {
  20350. return (cacheKey !== undefined)
  20351. ? cache[cacheKey]
  20352. : false
  20353. ;
  20354. },
  20355. add: function(cacheKey, content) {
  20356. cacheKey = cacheKey || activeTabPath;
  20357. module.debug('Adding cached content for', cacheKey);
  20358. cache[cacheKey] = content;
  20359. },
  20360. remove: function(cacheKey) {
  20361. cacheKey = cacheKey || activeTabPath;
  20362. module.debug('Removing cached content for', cacheKey);
  20363. delete cache[cacheKey];
  20364. }
  20365. },
  20366. escape: {
  20367. string: function(text) {
  20368. text = String(text);
  20369. return text.replace(regExp.escape, '\\$&');
  20370. }
  20371. },
  20372. set: {
  20373. auto: function() {
  20374. var
  20375. url = (typeof settings.path == 'string')
  20376. ? settings.path.replace(/\/$/, '') + '/{$tab}'
  20377. : '/{$tab}'
  20378. ;
  20379. module.verbose('Setting up automatic tab retrieval from server', url);
  20380. if($.isPlainObject(settings.apiSettings)) {
  20381. settings.apiSettings.url = url;
  20382. }
  20383. else {
  20384. settings.apiSettings = {
  20385. url: url
  20386. };
  20387. }
  20388. },
  20389. loading: function(tabPath) {
  20390. var
  20391. $tab = module.get.tabElement(tabPath),
  20392. isLoading = $tab.hasClass(className.loading)
  20393. ;
  20394. if(!isLoading) {
  20395. module.verbose('Setting loading state for', $tab);
  20396. $tab
  20397. .addClass(className.loading)
  20398. .siblings($tabs)
  20399. .removeClass(className.active + ' ' + className.loading)
  20400. ;
  20401. if($tab.length > 0) {
  20402. settings.onRequest.call($tab[0], tabPath);
  20403. }
  20404. }
  20405. },
  20406. state: function(state) {
  20407. $.address.value(state);
  20408. }
  20409. },
  20410. changeTab: function(tabPath) {
  20411. var
  20412. pushStateAvailable = (window.history && window.history.pushState),
  20413. shouldIgnoreLoad = (pushStateAvailable && settings.ignoreFirstLoad && firstLoad),
  20414. remoteContent = (settings.auto || $.isPlainObject(settings.apiSettings) ),
  20415. // only add default path if not remote content
  20416. pathArray = (remoteContent && !shouldIgnoreLoad)
  20417. ? module.utilities.pathToArray(tabPath)
  20418. : module.get.defaultPathArray(tabPath)
  20419. ;
  20420. tabPath = module.utilities.arrayToPath(pathArray);
  20421. $.each(pathArray, function(index, tab) {
  20422. var
  20423. currentPathArray = pathArray.slice(0, index + 1),
  20424. currentPath = module.utilities.arrayToPath(currentPathArray),
  20425. isTab = module.is.tab(currentPath),
  20426. isLastIndex = (index + 1 == pathArray.length),
  20427. $tab = module.get.tabElement(currentPath),
  20428. $anchor,
  20429. nextPathArray,
  20430. nextPath,
  20431. isLastTab
  20432. ;
  20433. module.verbose('Looking for tab', tab);
  20434. if(isTab) {
  20435. module.verbose('Tab was found', tab);
  20436. // scope up
  20437. activeTabPath = currentPath;
  20438. parameterArray = module.utilities.filterArray(pathArray, currentPathArray);
  20439. if(isLastIndex) {
  20440. isLastTab = true;
  20441. }
  20442. else {
  20443. nextPathArray = pathArray.slice(0, index + 2);
  20444. nextPath = module.utilities.arrayToPath(nextPathArray);
  20445. isLastTab = ( !module.is.tab(nextPath) );
  20446. if(isLastTab) {
  20447. module.verbose('Tab parameters found', nextPathArray);
  20448. }
  20449. }
  20450. if(isLastTab && remoteContent) {
  20451. if(!shouldIgnoreLoad) {
  20452. module.activate.navigation(currentPath);
  20453. module.fetch.content(currentPath, tabPath);
  20454. }
  20455. else {
  20456. module.debug('Ignoring remote content on first tab load', currentPath);
  20457. firstLoad = false;
  20458. module.cache.add(tabPath, $tab.html());
  20459. module.activate.all(currentPath);
  20460. settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  20461. settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  20462. }
  20463. return false;
  20464. }
  20465. else {
  20466. module.debug('Opened local tab', currentPath);
  20467. module.activate.all(currentPath);
  20468. if( !module.cache.read(currentPath) ) {
  20469. module.cache.add(currentPath, true);
  20470. module.debug('First time tab loaded calling tab init');
  20471. settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  20472. }
  20473. settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  20474. }
  20475. }
  20476. else if(tabPath.search('/') == -1 && tabPath !== '') {
  20477. // look for in page anchor
  20478. tabPath = module.escape.string(tabPath);
  20479. $anchor = $('#' + tabPath + ', a[name="' + tabPath + '"]');
  20480. currentPath = $anchor.closest('[data-tab]').data(metadata.tab);
  20481. $tab = module.get.tabElement(currentPath);
  20482. // if anchor exists use parent tab
  20483. if($anchor && $anchor.length > 0 && currentPath) {
  20484. module.debug('Anchor link used, opening parent tab', $tab, $anchor);
  20485. if( !$tab.hasClass(className.active) ) {
  20486. setTimeout(function() {
  20487. module.scrollTo($anchor);
  20488. }, 0);
  20489. }
  20490. module.activate.all(currentPath);
  20491. if( !module.cache.read(currentPath) ) {
  20492. module.cache.add(currentPath, true);
  20493. module.debug('First time tab loaded calling tab init');
  20494. settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  20495. }
  20496. settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  20497. return false;
  20498. }
  20499. }
  20500. else {
  20501. module.error(error.missingTab, $module, $context, currentPath);
  20502. return false;
  20503. }
  20504. });
  20505. },
  20506. scrollTo: function($element) {
  20507. var
  20508. scrollOffset = ($element && $element.length > 0)
  20509. ? $element.offset().top
  20510. : false
  20511. ;
  20512. if(scrollOffset !== false) {
  20513. module.debug('Forcing scroll to an in-page link in a hidden tab', scrollOffset, $element);
  20514. $(document).scrollTop(scrollOffset);
  20515. }
  20516. },
  20517. update: {
  20518. content: function(tabPath, html, evaluateScripts) {
  20519. var
  20520. $tab = module.get.tabElement(tabPath),
  20521. tab = $tab[0]
  20522. ;
  20523. evaluateScripts = (evaluateScripts !== undefined)
  20524. ? evaluateScripts
  20525. : settings.evaluateScripts
  20526. ;
  20527. if(typeof settings.cacheType == 'string' && settings.cacheType.toLowerCase() == 'dom' && typeof html !== 'string') {
  20528. $tab
  20529. .empty()
  20530. .append($(html).clone(true))
  20531. ;
  20532. }
  20533. else {
  20534. if(evaluateScripts) {
  20535. module.debug('Updating HTML and evaluating inline scripts', tabPath, html);
  20536. $tab.html(html);
  20537. }
  20538. else {
  20539. module.debug('Updating HTML', tabPath, html);
  20540. tab.innerHTML = html;
  20541. }
  20542. }
  20543. }
  20544. },
  20545. fetch: {
  20546. content: function(tabPath, fullTabPath) {
  20547. var
  20548. $tab = module.get.tabElement(tabPath),
  20549. apiSettings = {
  20550. dataType : 'html',
  20551. encodeParameters : false,
  20552. on : 'now',
  20553. cache : settings.alwaysRefresh,
  20554. headers : {
  20555. 'X-Remote': true
  20556. },
  20557. onSuccess : function(response) {
  20558. if(settings.cacheType == 'response') {
  20559. module.cache.add(fullTabPath, response);
  20560. }
  20561. module.update.content(tabPath, response);
  20562. if(tabPath == activeTabPath) {
  20563. module.debug('Content loaded', tabPath);
  20564. module.activate.tab(tabPath);
  20565. }
  20566. else {
  20567. module.debug('Content loaded in background', tabPath);
  20568. }
  20569. settings.onFirstLoad.call($tab[0], tabPath, parameterArray, historyEvent);
  20570. settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);
  20571. if(settings.loadOnce) {
  20572. module.cache.add(fullTabPath, true);
  20573. }
  20574. else if(typeof settings.cacheType == 'string' && settings.cacheType.toLowerCase() == 'dom' && $tab.children().length > 0) {
  20575. setTimeout(function() {
  20576. var
  20577. $clone = $tab.children().clone(true)
  20578. ;
  20579. $clone = $clone.not('script');
  20580. module.cache.add(fullTabPath, $clone);
  20581. }, 0);
  20582. }
  20583. else {
  20584. module.cache.add(fullTabPath, $tab.html());
  20585. }
  20586. },
  20587. urlData: {
  20588. tab: fullTabPath
  20589. }
  20590. },
  20591. request = $tab.api('get request') || false,
  20592. existingRequest = ( request && request.state() === 'pending' ),
  20593. requestSettings,
  20594. cachedContent
  20595. ;
  20596. fullTabPath = fullTabPath || tabPath;
  20597. cachedContent = module.cache.read(fullTabPath);
  20598. if(settings.cache && cachedContent) {
  20599. module.activate.tab(tabPath);
  20600. module.debug('Adding cached content', fullTabPath);
  20601. if(!settings.loadOnce) {
  20602. if(settings.evaluateScripts == 'once') {
  20603. module.update.content(tabPath, cachedContent, false);
  20604. }
  20605. else {
  20606. module.update.content(tabPath, cachedContent);
  20607. }
  20608. }
  20609. settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);
  20610. }
  20611. else if(existingRequest) {
  20612. module.set.loading(tabPath);
  20613. module.debug('Content is already loading', fullTabPath);
  20614. }
  20615. else if($.api !== undefined) {
  20616. requestSettings = $.extend(true, {}, settings.apiSettings, apiSettings);
  20617. module.debug('Retrieving remote content', fullTabPath, requestSettings);
  20618. module.set.loading(tabPath);
  20619. $tab.api(requestSettings);
  20620. }
  20621. else {
  20622. module.error(error.api);
  20623. }
  20624. }
  20625. },
  20626. activate: {
  20627. all: function(tabPath) {
  20628. module.activate.tab(tabPath);
  20629. module.activate.navigation(tabPath);
  20630. },
  20631. tab: function(tabPath) {
  20632. var
  20633. $tab = module.get.tabElement(tabPath),
  20634. $deactiveTabs = (settings.deactivate == 'siblings')
  20635. ? $tab.siblings($tabs)
  20636. : $tabs.not($tab),
  20637. isActive = $tab.hasClass(className.active)
  20638. ;
  20639. module.verbose('Showing tab content for', $tab);
  20640. if(!isActive) {
  20641. $tab
  20642. .addClass(className.active)
  20643. ;
  20644. $deactiveTabs
  20645. .removeClass(className.active + ' ' + className.loading)
  20646. ;
  20647. if($tab.length > 0) {
  20648. settings.onVisible.call($tab[0], tabPath);
  20649. }
  20650. }
  20651. },
  20652. navigation: function(tabPath) {
  20653. var
  20654. $navigation = module.get.navElement(tabPath),
  20655. $deactiveNavigation = (settings.deactivate == 'siblings')
  20656. ? $navigation.siblings($allModules)
  20657. : $allModules.not($navigation),
  20658. isActive = $navigation.hasClass(className.active)
  20659. ;
  20660. module.verbose('Activating tab navigation for', $navigation, tabPath);
  20661. if(!isActive) {
  20662. $navigation
  20663. .addClass(className.active)
  20664. ;
  20665. $deactiveNavigation
  20666. .removeClass(className.active + ' ' + className.loading)
  20667. ;
  20668. }
  20669. }
  20670. },
  20671. deactivate: {
  20672. all: function() {
  20673. module.deactivate.navigation();
  20674. module.deactivate.tabs();
  20675. },
  20676. navigation: function() {
  20677. $allModules
  20678. .removeClass(className.active)
  20679. ;
  20680. },
  20681. tabs: function() {
  20682. $tabs
  20683. .removeClass(className.active + ' ' + className.loading)
  20684. ;
  20685. }
  20686. },
  20687. is: {
  20688. tab: function(tabName) {
  20689. return (tabName !== undefined)
  20690. ? ( module.get.tabElement(tabName).length > 0 )
  20691. : false
  20692. ;
  20693. }
  20694. },
  20695. get: {
  20696. initialPath: function() {
  20697. return $allModules.eq(0).data(metadata.tab) || $tabs.eq(0).data(metadata.tab);
  20698. },
  20699. path: function() {
  20700. return $.address.value();
  20701. },
  20702. // adds default tabs to tab path
  20703. defaultPathArray: function(tabPath) {
  20704. return module.utilities.pathToArray( module.get.defaultPath(tabPath) );
  20705. },
  20706. defaultPath: function(tabPath) {
  20707. var
  20708. $defaultNav = $allModules.filter('[data-' + metadata.tab + '^="' + module.escape.string(tabPath) + '/"]').eq(0),
  20709. defaultTab = $defaultNav.data(metadata.tab) || false
  20710. ;
  20711. if( defaultTab ) {
  20712. module.debug('Found default tab', defaultTab);
  20713. if(recursionDepth < settings.maxDepth) {
  20714. recursionDepth++;
  20715. return module.get.defaultPath(defaultTab);
  20716. }
  20717. module.error(error.recursion);
  20718. }
  20719. else {
  20720. module.debug('No default tabs found for', tabPath, $tabs);
  20721. }
  20722. recursionDepth = 0;
  20723. return tabPath;
  20724. },
  20725. navElement: function(tabPath) {
  20726. tabPath = tabPath || activeTabPath;
  20727. return $allModules.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]');
  20728. },
  20729. tabElement: function(tabPath) {
  20730. var
  20731. $fullPathTab,
  20732. $simplePathTab,
  20733. tabPathArray,
  20734. lastTab
  20735. ;
  20736. tabPath = tabPath || activeTabPath;
  20737. tabPathArray = module.utilities.pathToArray(tabPath);
  20738. lastTab = module.utilities.last(tabPathArray);
  20739. $fullPathTab = $tabs.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]');
  20740. $simplePathTab = $tabs.filter('[data-' + metadata.tab + '="' + module.escape.string(lastTab) + '"]');
  20741. return ($fullPathTab.length > 0)
  20742. ? $fullPathTab
  20743. : $simplePathTab
  20744. ;
  20745. },
  20746. tab: function() {
  20747. return activeTabPath;
  20748. }
  20749. },
  20750. determine: {
  20751. activeTab: function() {
  20752. var activeTab = null;
  20753. $tabs.each(function(_index, tab) {
  20754. var $tab = $(tab);
  20755. if( $tab.hasClass(className.active) ) {
  20756. var
  20757. tabPath = $(this).data(metadata.tab),
  20758. $anchor = $allModules.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]')
  20759. ;
  20760. if( $anchor.hasClass(className.active) ) {
  20761. activeTab = tabPath;
  20762. }
  20763. }
  20764. });
  20765. return activeTab;
  20766. }
  20767. },
  20768. utilities: {
  20769. filterArray: function(keepArray, removeArray) {
  20770. return $.grep(keepArray, function(keepValue) {
  20771. return ( $.inArray(keepValue, removeArray) == -1);
  20772. });
  20773. },
  20774. last: function(array) {
  20775. return Array.isArray(array)
  20776. ? array[ array.length - 1]
  20777. : false
  20778. ;
  20779. },
  20780. pathToArray: function(pathName) {
  20781. if(pathName === undefined) {
  20782. pathName = activeTabPath;
  20783. }
  20784. return typeof pathName == 'string'
  20785. ? pathName.split('/')
  20786. : [pathName]
  20787. ;
  20788. },
  20789. arrayToPath: function(pathArray) {
  20790. return Array.isArray(pathArray)
  20791. ? pathArray.join('/')
  20792. : false
  20793. ;
  20794. }
  20795. },
  20796. setting: function(name, value) {
  20797. module.debug('Changing setting', name, value);
  20798. if( $.isPlainObject(name) ) {
  20799. $.extend(true, settings, name);
  20800. }
  20801. else if(value !== undefined) {
  20802. if($.isPlainObject(settings[name])) {
  20803. $.extend(true, settings[name], value);
  20804. }
  20805. else {
  20806. settings[name] = value;
  20807. }
  20808. }
  20809. else {
  20810. return settings[name];
  20811. }
  20812. },
  20813. internal: function(name, value) {
  20814. if( $.isPlainObject(name) ) {
  20815. $.extend(true, module, name);
  20816. }
  20817. else if(value !== undefined) {
  20818. module[name] = value;
  20819. }
  20820. else {
  20821. return module[name];
  20822. }
  20823. },
  20824. debug: function() {
  20825. if(!settings.silent && settings.debug) {
  20826. if(settings.performance) {
  20827. module.performance.log(arguments);
  20828. }
  20829. else {
  20830. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  20831. module.debug.apply(console, arguments);
  20832. }
  20833. }
  20834. },
  20835. verbose: function() {
  20836. if(!settings.silent && settings.verbose && settings.debug) {
  20837. if(settings.performance) {
  20838. module.performance.log(arguments);
  20839. }
  20840. else {
  20841. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  20842. module.verbose.apply(console, arguments);
  20843. }
  20844. }
  20845. },
  20846. error: function() {
  20847. if(!settings.silent) {
  20848. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  20849. module.error.apply(console, arguments);
  20850. }
  20851. },
  20852. performance: {
  20853. log: function(message) {
  20854. var
  20855. currentTime,
  20856. executionTime,
  20857. previousTime
  20858. ;
  20859. if(settings.performance) {
  20860. currentTime = new Date().getTime();
  20861. previousTime = time || currentTime;
  20862. executionTime = currentTime - previousTime;
  20863. time = currentTime;
  20864. performance.push({
  20865. 'Name' : message[0],
  20866. 'Arguments' : [].slice.call(message, 1) || '',
  20867. 'Element' : element,
  20868. 'Execution Time' : executionTime
  20869. });
  20870. }
  20871. clearTimeout(module.performance.timer);
  20872. module.performance.timer = setTimeout(module.performance.display, 500);
  20873. },
  20874. display: function() {
  20875. var
  20876. title = settings.name + ':',
  20877. totalTime = 0
  20878. ;
  20879. time = false;
  20880. clearTimeout(module.performance.timer);
  20881. $.each(performance, function(index, data) {
  20882. totalTime += data['Execution Time'];
  20883. });
  20884. title += ' ' + totalTime + 'ms';
  20885. if(moduleSelector) {
  20886. title += ' \'' + moduleSelector + '\'';
  20887. }
  20888. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  20889. console.groupCollapsed(title);
  20890. if(console.table) {
  20891. console.table(performance);
  20892. }
  20893. else {
  20894. $.each(performance, function(index, data) {
  20895. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  20896. });
  20897. }
  20898. console.groupEnd();
  20899. }
  20900. performance = [];
  20901. }
  20902. },
  20903. invoke: function(query, passedArguments, context) {
  20904. var
  20905. object = instance,
  20906. maxDepth,
  20907. found,
  20908. response
  20909. ;
  20910. passedArguments = passedArguments || queryArguments;
  20911. context = element || context;
  20912. if(typeof query == 'string' && object !== undefined) {
  20913. query = query.split(/[\. ]/);
  20914. maxDepth = query.length - 1;
  20915. $.each(query, function(depth, value) {
  20916. var camelCaseValue = (depth != maxDepth)
  20917. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  20918. : query
  20919. ;
  20920. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  20921. object = object[camelCaseValue];
  20922. }
  20923. else if( object[camelCaseValue] !== undefined ) {
  20924. found = object[camelCaseValue];
  20925. return false;
  20926. }
  20927. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  20928. object = object[value];
  20929. }
  20930. else if( object[value] !== undefined ) {
  20931. found = object[value];
  20932. return false;
  20933. }
  20934. else {
  20935. module.error(error.method, query);
  20936. return false;
  20937. }
  20938. });
  20939. }
  20940. if ( $.isFunction( found ) ) {
  20941. response = found.apply(context, passedArguments);
  20942. }
  20943. else if(found !== undefined) {
  20944. response = found;
  20945. }
  20946. if(Array.isArray(returnedValue)) {
  20947. returnedValue.push(response);
  20948. }
  20949. else if(returnedValue !== undefined) {
  20950. returnedValue = [returnedValue, response];
  20951. }
  20952. else if(response !== undefined) {
  20953. returnedValue = response;
  20954. }
  20955. return found;
  20956. }
  20957. };
  20958. if(methodInvoked) {
  20959. if(instance === undefined) {
  20960. module.initialize();
  20961. }
  20962. module.invoke(query);
  20963. }
  20964. else {
  20965. if(instance !== undefined) {
  20966. instance.invoke('destroy');
  20967. }
  20968. module.initialize();
  20969. }
  20970. })
  20971. ;
  20972. return (returnedValue !== undefined)
  20973. ? returnedValue
  20974. : this
  20975. ;
  20976. };
  20977. // shortcut for tabbed content with no defined navigation
  20978. $.tab = function() {
  20979. $(window).tab.apply(this, arguments);
  20980. };
  20981. $.fn.tab.settings = {
  20982. name : 'Tab',
  20983. namespace : 'tab',
  20984. silent : false,
  20985. debug : false,
  20986. verbose : false,
  20987. performance : true,
  20988. auto : false, // uses pjax style endpoints fetching content from same url with remote-content headers
  20989. history : false, // use browser history
  20990. historyType : 'hash', // #/ or html5 state
  20991. path : false, // base path of url
  20992. context : false, // specify a context that tabs must appear inside
  20993. childrenOnly : false, // use only tabs that are children of context
  20994. maxDepth : 25, // max depth a tab can be nested
  20995. deactivate : 'siblings', // whether tabs should deactivate sibling menu elements or all elements initialized together
  20996. alwaysRefresh : false, // load tab content new every tab click
  20997. cache : true, // cache the content requests to pull locally
  20998. loadOnce : false, // Whether tab data should only be loaded once when using remote content
  20999. cacheType : 'response', // Whether to cache exact response, or to html cache contents after scripts execute
  21000. ignoreFirstLoad : false, // don't load remote content on first load
  21001. apiSettings : false, // settings for api call
  21002. evaluateScripts : 'once', // whether inline scripts should be parsed (true/false/once). Once will not re-evaluate on cached content
  21003. onFirstLoad : function(tabPath, parameterArray, historyEvent) {}, // called first time loaded
  21004. onLoad : function(tabPath, parameterArray, historyEvent) {}, // called on every load
  21005. onVisible : function(tabPath, parameterArray, historyEvent) {}, // called every time tab visible
  21006. onRequest : function(tabPath, parameterArray, historyEvent) {}, // called ever time a tab beings loading remote content
  21007. templates : {
  21008. determineTitle: function(tabArray) {} // returns page title for path
  21009. },
  21010. error: {
  21011. api : 'You attempted to load content without API module',
  21012. method : 'The method you called is not defined',
  21013. missingTab : 'Activated tab cannot be found. Tabs are case-sensitive.',
  21014. noContent : 'The tab you specified is missing a content url.',
  21015. path : 'History enabled, but no path was specified',
  21016. recursion : 'Max recursive depth reached',
  21017. legacyInit : 'onTabInit has been renamed to onFirstLoad in 2.0, please adjust your code.',
  21018. legacyLoad : 'onTabLoad has been renamed to onLoad in 2.0. Please adjust your code',
  21019. state : 'History requires Asual\'s Address library <https://github.com/asual/jquery-address>'
  21020. },
  21021. regExp : {
  21022. escape : /[-[\]{}()*+?.,\\^$|#\s:=@]/g
  21023. },
  21024. metadata : {
  21025. tab : 'tab',
  21026. loaded : 'loaded',
  21027. promise: 'promise'
  21028. },
  21029. className : {
  21030. loading : 'loading',
  21031. active : 'active'
  21032. },
  21033. selector : {
  21034. tabs : '.ui.tab',
  21035. ui : '.ui'
  21036. }
  21037. };
  21038. })( jQuery, window, document );
  21039. /*!
  21040. * # Fomantic-UI - Toast
  21041. * http://github.com/fomantic/Fomantic-UI/
  21042. *
  21043. *
  21044. * Released under the MIT license
  21045. * http://opensource.org/licenses/MIT
  21046. *
  21047. */
  21048. ;(function ($, window, document, undefined) {
  21049. 'use strict';
  21050. $.isFunction = $.isFunction || function(obj) {
  21051. return typeof obj === "function" && typeof obj.nodeType !== "number";
  21052. };
  21053. window = (typeof window != 'undefined' && window.Math == Math)
  21054. ? window
  21055. : (typeof self != 'undefined' && self.Math == Math)
  21056. ? self
  21057. : Function('return this')()
  21058. ;
  21059. $.fn.toast = function(parameters) {
  21060. var
  21061. $allModules = $(this),
  21062. moduleSelector = $allModules.selector || '',
  21063. time = new Date().getTime(),
  21064. performance = [],
  21065. query = arguments[0],
  21066. methodInvoked = (typeof query == 'string'),
  21067. queryArguments = [].slice.call(arguments, 1),
  21068. returnedValue
  21069. ;
  21070. $allModules
  21071. .each(function() {
  21072. var
  21073. settings = ( $.isPlainObject(parameters) )
  21074. ? $.extend(true, {}, $.fn.toast.settings, parameters)
  21075. : $.extend({}, $.fn.toast.settings),
  21076. className = settings.className,
  21077. selector = settings.selector,
  21078. error = settings.error,
  21079. namespace = settings.namespace,
  21080. eventNamespace = '.' + namespace,
  21081. moduleNamespace = namespace + '-module',
  21082. $module = $(this),
  21083. $toastBox = $('<div/>',{'class':settings.className.box}),
  21084. $toast = $('<div/>'),
  21085. $progress = $('<div/>',{'class':settings.className.progress+' '+settings.class}),
  21086. $progressBar = $('<div/>',{'class':'bar'}),
  21087. $close = $('<i/>',{'class':'close icon'}),
  21088. $context = (settings.context)
  21089. ? $(settings.context)
  21090. : $('body'),
  21091. element = this,
  21092. instance = $module.data(moduleNamespace),
  21093. module
  21094. ;
  21095. module = {
  21096. initialize: function() {
  21097. module.verbose('Initializing element');
  21098. if(typeof settings.showProgress !== 'string' || ['top','bottom'].indexOf(settings.showProgress) === -1 ) {
  21099. settings.showProgress = false;
  21100. }
  21101. if (!module.has.container()) {
  21102. module.create.container();
  21103. }
  21104. module.create.toast();
  21105. module.bind.events();
  21106. if(settings.displayTime > 0) {
  21107. module.closeTimer = setTimeout(module.close, settings.displayTime+(!!settings.showProgress ? 300 : 0));
  21108. }
  21109. module.show();
  21110. },
  21111. destroy: function() {
  21112. module.debug('Removing toast', $toast);
  21113. $toast.remove();
  21114. $toast = undefined;
  21115. settings.onRemove.call($toast, element);
  21116. },
  21117. show: function(callback) {
  21118. callback = callback || function(){};
  21119. module.debug('Showing toast');
  21120. if(settings.onShow.call($toast, element) === false) {
  21121. module.debug('onShow callback returned false, cancelling toast animation');
  21122. return;
  21123. }
  21124. module.animate.show(callback);
  21125. },
  21126. close: function(callback) {
  21127. if(module.closeTimer) {
  21128. clearTimeout(module.closeTimer);
  21129. }
  21130. callback = callback || function(){};
  21131. module.remove.visible();
  21132. module.unbind.events();
  21133. module.animate.close(callback);
  21134. },
  21135. create: {
  21136. container: function() {
  21137. module.verbose('Creating container');
  21138. $context.append('<div class="ui ' + settings.position + ' ' + className.container + '"></div>');
  21139. },
  21140. toast: function() {
  21141. var $content = $('<div/>').addClass(className.content);
  21142. module.verbose('Creating toast');
  21143. if(settings.closeIcon) {
  21144. $toast.append($close);
  21145. $toast.css('cursor','default');
  21146. }
  21147. var iconClass = typeof settings.showIcon === 'string' ? settings.showIcon : settings.showIcon && settings.icons[settings.class] ? settings.icons[settings.class] : '';
  21148. if (iconClass != '') {
  21149. var $icon = $('<i/>').addClass(iconClass + ' ' + className.icon);
  21150. $toast
  21151. .addClass(className.icon)
  21152. .append($icon)
  21153. ;
  21154. }
  21155. if (settings.title !== '') {
  21156. var
  21157. $title = $('<div/>')
  21158. .addClass(className.title)
  21159. .text(settings.title)
  21160. ;
  21161. $content.append($title);
  21162. }
  21163. $content.append($('<div/>').html(settings.message));
  21164. $toast
  21165. .addClass(settings.class + ' ' + className.toast)
  21166. .append($content)
  21167. ;
  21168. $toast.css('opacity', settings.opacity);
  21169. if(settings.compact || $toast.hasClass('compact')) {
  21170. $toastBox.addClass('compact');
  21171. }
  21172. if($toast.hasClass('toast') && !$toast.hasClass('inverted')){
  21173. $progress.addClass('inverted');
  21174. } else {
  21175. $progress.removeClass('inverted');
  21176. }
  21177. $toast = $toastBox.append($toast);
  21178. if(!!settings.showProgress && settings.displayTime > 0){
  21179. $progress
  21180. .addClass(settings.showProgress)
  21181. .append($progressBar);
  21182. if ($progress.hasClass('top')) {
  21183. $toast.prepend($progress);
  21184. } else {
  21185. $toast.append($progress);
  21186. }
  21187. $progressBar.css('transition','width '+(settings.displayTime/1000)+'s linear');
  21188. $progressBar.width(settings.progressUp?'0%':'100%');
  21189. setTimeout(function() {
  21190. if(typeof $progress !== 'undefined'){
  21191. $progressBar.width(settings.progressUp?'100%':'0%');
  21192. }
  21193. },300);
  21194. }
  21195. if (settings.newestOnTop) {
  21196. $toast.prependTo(module.get.container());
  21197. }
  21198. else {
  21199. $toast.appendTo(module.get.container());
  21200. }
  21201. }
  21202. },
  21203. bind: {
  21204. events: function() {
  21205. module.debug('Binding events to toast');
  21206. (settings.closeIcon ? $close : $toast)
  21207. .on('click' + eventNamespace, module.event.click)
  21208. ;
  21209. }
  21210. },
  21211. unbind: {
  21212. events: function() {
  21213. module.debug('Unbinding events to toast');
  21214. (settings.closeIcon ? $close : $toast)
  21215. .off('click' + eventNamespace)
  21216. ;
  21217. }
  21218. },
  21219. animate: {
  21220. show: function(callback) {
  21221. callback = $.isFunction(callback) ? callback : function(){};
  21222. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  21223. module.set.visible();
  21224. $toast
  21225. .transition({
  21226. animation : settings.transition.showMethod + ' in',
  21227. queue : false,
  21228. debug : settings.debug,
  21229. verbose : settings.verbose,
  21230. duration : settings.transition.showDuration,
  21231. onComplete : function() {
  21232. callback.call($toast, element);
  21233. settings.onVisible.call($toast, element);
  21234. }
  21235. })
  21236. ;
  21237. }
  21238. else {
  21239. module.error(error.noTransition);
  21240. }
  21241. },
  21242. close: function(callback) {
  21243. callback = $.isFunction(callback) ? callback : function(){};
  21244. module.debug('Closing toast');
  21245. if(settings.onHide.call($toast, element) === false) {
  21246. module.debug('onHide callback returned false, cancelling toast animation');
  21247. return;
  21248. }
  21249. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  21250. $toast
  21251. .transition({
  21252. animation : settings.transition.hideMethod + ' out',
  21253. queue : false,
  21254. duration : settings.transition.hideDuration,
  21255. debug : settings.debug,
  21256. verbose : settings.verbose,
  21257. onBeforeHide: function(callback){
  21258. callback = $.isFunction(callback)?callback : function(){};
  21259. if(settings.transition.closeEasing !== ''){
  21260. $toast.css('opacity',0);
  21261. $toast.wrap('<div/>').parent().slideUp(500,settings.transition.closeEasing,function(){
  21262. $toast.parent().remove();
  21263. callback.call($toast);
  21264. });
  21265. } else {
  21266. callback.call($toast);
  21267. }
  21268. },
  21269. onComplete : function() {
  21270. module.destroy();
  21271. callback.call($toast, element);
  21272. settings.onHidden.call($toast, element);
  21273. }
  21274. })
  21275. ;
  21276. }
  21277. else {
  21278. module.error(error.noTransition);
  21279. }
  21280. }
  21281. },
  21282. has: {
  21283. container: function() {
  21284. module.verbose('Determining if there is already a container');
  21285. return ($context.find(module.helpers.toClass(settings.position) + selector.container).length > 0);
  21286. }
  21287. },
  21288. get: {
  21289. container: function() {
  21290. return ($context.find(module.helpers.toClass(settings.position) + selector.container)[0]);
  21291. }
  21292. },
  21293. set: {
  21294. visible: function() {
  21295. $toast.addClass(className.visible);
  21296. }
  21297. },
  21298. remove: {
  21299. visible: function() {
  21300. $toast.removeClass(className.visible);
  21301. }
  21302. },
  21303. event: {
  21304. click: function() {
  21305. settings.onClick.call($toast, element);
  21306. module.close();
  21307. }
  21308. },
  21309. helpers: {
  21310. toClass: function(selector) {
  21311. var
  21312. classes = selector.split(' '),
  21313. result = ''
  21314. ;
  21315. classes.forEach(function (element) {
  21316. result += '.' + element;
  21317. });
  21318. return result;
  21319. }
  21320. },
  21321. setting: function(name, value) {
  21322. module.debug('Changing setting', name, value);
  21323. if( $.isPlainObject(name) ) {
  21324. $.extend(true, settings, name);
  21325. }
  21326. else if(value !== undefined) {
  21327. if($.isPlainObject(settings[name])) {
  21328. $.extend(true, settings[name], value);
  21329. }
  21330. else {
  21331. settings[name] = value;
  21332. }
  21333. }
  21334. else {
  21335. return settings[name];
  21336. }
  21337. },
  21338. internal: function(name, value) {
  21339. if( $.isPlainObject(name) ) {
  21340. $.extend(true, module, name);
  21341. }
  21342. else if(value !== undefined) {
  21343. module[name] = value;
  21344. }
  21345. else {
  21346. return module[name];
  21347. }
  21348. },
  21349. debug: function() {
  21350. if(!settings.silent && settings.debug) {
  21351. if(settings.performance) {
  21352. module.performance.log(arguments);
  21353. }
  21354. else {
  21355. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  21356. module.debug.apply(console, arguments);
  21357. }
  21358. }
  21359. },
  21360. verbose: function() {
  21361. if(!settings.silent && settings.verbose && settings.debug) {
  21362. if(settings.performance) {
  21363. module.performance.log(arguments);
  21364. }
  21365. else {
  21366. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  21367. module.verbose.apply(console, arguments);
  21368. }
  21369. }
  21370. },
  21371. error: function() {
  21372. if(!settings.silent) {
  21373. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  21374. module.error.apply(console, arguments);
  21375. }
  21376. },
  21377. performance: {
  21378. log: function(message) {
  21379. var
  21380. currentTime,
  21381. executionTime,
  21382. previousTime
  21383. ;
  21384. if(settings.performance) {
  21385. currentTime = new Date().getTime();
  21386. previousTime = time || currentTime;
  21387. executionTime = currentTime - previousTime;
  21388. time = currentTime;
  21389. performance.push({
  21390. 'Name' : message[0],
  21391. 'Arguments' : [].slice.call(message, 1) || '',
  21392. 'Element' : element,
  21393. 'Execution Time' : executionTime
  21394. });
  21395. }
  21396. clearTimeout(module.performance.timer);
  21397. module.performance.timer = setTimeout(module.performance.display, 500);
  21398. },
  21399. display: function() {
  21400. var
  21401. title = settings.name + ':',
  21402. totalTime = 0
  21403. ;
  21404. time = false;
  21405. clearTimeout(module.performance.timer);
  21406. $.each(performance, function(index, data) {
  21407. totalTime += data['Execution Time'];
  21408. });
  21409. title += ' ' + totalTime + 'ms';
  21410. if(moduleSelector) {
  21411. title += ' \'' + moduleSelector + '\'';
  21412. }
  21413. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  21414. console.groupCollapsed(title);
  21415. if(console.table) {
  21416. console.table(performance);
  21417. }
  21418. else {
  21419. $.each(performance, function(index, data) {
  21420. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  21421. });
  21422. }
  21423. console.groupEnd();
  21424. }
  21425. performance = [];
  21426. }
  21427. },
  21428. invoke: function(query, passedArguments, context) {
  21429. var
  21430. object = instance,
  21431. maxDepth,
  21432. found,
  21433. response
  21434. ;
  21435. passedArguments = passedArguments || queryArguments;
  21436. context = element || context;
  21437. if(typeof query == 'string' && object !== undefined) {
  21438. query = query.split(/[\. ]/);
  21439. maxDepth = query.length - 1;
  21440. $.each(query, function(depth, value) {
  21441. var camelCaseValue = (depth != maxDepth)
  21442. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  21443. : query
  21444. ;
  21445. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  21446. object = object[camelCaseValue];
  21447. }
  21448. else if( object[camelCaseValue] !== undefined ) {
  21449. found = object[camelCaseValue];
  21450. return false;
  21451. }
  21452. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  21453. object = object[value];
  21454. }
  21455. else if( object[value] !== undefined ) {
  21456. found = object[value];
  21457. return false;
  21458. }
  21459. else {
  21460. module.error(error.method, query);
  21461. return false;
  21462. }
  21463. });
  21464. }
  21465. if ( $.isFunction( found ) ) {
  21466. response = found.apply(context, passedArguments);
  21467. }
  21468. else if(found !== undefined) {
  21469. response = found;
  21470. }
  21471. if(Array.isArray(returnedValue)) {
  21472. returnedValue.push(response);
  21473. }
  21474. else if(returnedValue !== undefined) {
  21475. returnedValue = [returnedValue, response];
  21476. }
  21477. else if(response !== undefined) {
  21478. returnedValue = response;
  21479. }
  21480. return found;
  21481. }
  21482. };
  21483. if(methodInvoked) {
  21484. if(instance === undefined) {
  21485. module.initialize();
  21486. }
  21487. module.invoke(query);
  21488. }
  21489. else {
  21490. if(instance !== undefined) {
  21491. instance.invoke('destroy');
  21492. }
  21493. module.initialize();
  21494. }
  21495. })
  21496. ;
  21497. return (returnedValue !== undefined)
  21498. ? returnedValue
  21499. : this
  21500. ;
  21501. };
  21502. $.fn.toast.settings = {
  21503. name : 'Toast',
  21504. namespace : 'toast',
  21505. silent : false,
  21506. debug : false,
  21507. verbose : false,
  21508. performance : true,
  21509. context : 'body',
  21510. position : 'top right',
  21511. class : 'info',
  21512. title : '',
  21513. message : '',
  21514. displayTime : 3000, // set to zero to require manually dismissal, otherwise hides on its own
  21515. showIcon : true,
  21516. newestOnTop : false,
  21517. showProgress : false,
  21518. progressUp : true, //if false, the bar will start at 100% and decrease to 0%
  21519. opacity : 1,
  21520. compact : true,
  21521. closeIcon : false,
  21522. // transition settings
  21523. transition : {
  21524. showMethod : 'scale',
  21525. showDuration : 500,
  21526. hideMethod : 'scale',
  21527. hideDuration : 500,
  21528. closeEasing : 'easeOutBounce' //Set to empty string to stack the closed toast area immediately (old behaviour)
  21529. },
  21530. error: {
  21531. method : 'The method you called is not defined.',
  21532. noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>'
  21533. },
  21534. className : {
  21535. container : 'toast-container',
  21536. box : 'toast-box',
  21537. progress : 'ui attached active progress',
  21538. toast : 'ui toast',
  21539. icon : 'icon',
  21540. visible : 'visible',
  21541. content : 'content',
  21542. title : 'header'
  21543. },
  21544. icons : {
  21545. info : 'info',
  21546. success : 'checkmark',
  21547. warning : 'warning',
  21548. error : 'times'
  21549. },
  21550. selector : {
  21551. container : '.toast-container',
  21552. box : '.toast-box',
  21553. toast : '.ui.toast'
  21554. },
  21555. // callbacks
  21556. onShow : function(){},
  21557. onVisible : function(){},
  21558. onClick : function(){},
  21559. onHide : function(){},
  21560. onHidden : function(){},
  21561. onRemove : function(){},
  21562. };
  21563. $.extend( $.easing, {
  21564. easeOutBounce: function (x, t, b, c, d) {
  21565. if ((t/=d) < (1/2.75)) {
  21566. return c*(7.5625*t*t) + b;
  21567. } else if (t < (2/2.75)) {
  21568. return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
  21569. } else if (t < (2.5/2.75)) {
  21570. return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
  21571. } else {
  21572. return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
  21573. }
  21574. }
  21575. });
  21576. })( jQuery, window, document );
  21577. /*!
  21578. * # Fomantic-UI - Transition
  21579. * http://github.com/fomantic/Fomantic-UI/
  21580. *
  21581. *
  21582. * Released under the MIT license
  21583. * http://opensource.org/licenses/MIT
  21584. *
  21585. */
  21586. ;(function ($, window, document, undefined) {
  21587. 'use strict';
  21588. $.isFunction = $.isFunction || function(obj) {
  21589. return typeof obj === "function" && typeof obj.nodeType !== "number";
  21590. };
  21591. window = (typeof window != 'undefined' && window.Math == Math)
  21592. ? window
  21593. : (typeof self != 'undefined' && self.Math == Math)
  21594. ? self
  21595. : Function('return this')()
  21596. ;
  21597. $.fn.transition = function() {
  21598. var
  21599. $allModules = $(this),
  21600. moduleSelector = $allModules.selector || '',
  21601. time = new Date().getTime(),
  21602. performance = [],
  21603. moduleArguments = arguments,
  21604. query = moduleArguments[0],
  21605. queryArguments = [].slice.call(arguments, 1),
  21606. methodInvoked = (typeof query === 'string'),
  21607. returnedValue
  21608. ;
  21609. $allModules
  21610. .each(function(index) {
  21611. var
  21612. $module = $(this),
  21613. element = this,
  21614. // set at run time
  21615. settings,
  21616. instance,
  21617. error,
  21618. className,
  21619. metadata,
  21620. animationEnd,
  21621. moduleNamespace,
  21622. eventNamespace,
  21623. module
  21624. ;
  21625. module = {
  21626. initialize: function() {
  21627. // get full settings
  21628. settings = module.get.settings.apply(element, moduleArguments);
  21629. // shorthand
  21630. className = settings.className;
  21631. error = settings.error;
  21632. metadata = settings.metadata;
  21633. // define namespace
  21634. eventNamespace = '.' + settings.namespace;
  21635. moduleNamespace = 'module-' + settings.namespace;
  21636. instance = $module.data(moduleNamespace) || module;
  21637. // get vendor specific events
  21638. animationEnd = module.get.animationEndEvent();
  21639. if(methodInvoked) {
  21640. methodInvoked = module.invoke(query);
  21641. }
  21642. // method not invoked, lets run an animation
  21643. if(methodInvoked === false) {
  21644. module.verbose('Converted arguments into settings object', settings);
  21645. if(settings.interval) {
  21646. module.delay(settings.animate);
  21647. }
  21648. else {
  21649. module.animate();
  21650. }
  21651. module.instantiate();
  21652. }
  21653. },
  21654. instantiate: function() {
  21655. module.verbose('Storing instance of module', module);
  21656. instance = module;
  21657. $module
  21658. .data(moduleNamespace, instance)
  21659. ;
  21660. },
  21661. destroy: function() {
  21662. module.verbose('Destroying previous module for', element);
  21663. $module
  21664. .removeData(moduleNamespace)
  21665. ;
  21666. },
  21667. refresh: function() {
  21668. module.verbose('Refreshing display type on next animation');
  21669. delete module.displayType;
  21670. },
  21671. forceRepaint: function() {
  21672. module.verbose('Forcing element repaint');
  21673. var
  21674. $parentElement = $module.parent(),
  21675. $nextElement = $module.next()
  21676. ;
  21677. if($nextElement.length === 0) {
  21678. $module.detach().appendTo($parentElement);
  21679. }
  21680. else {
  21681. $module.detach().insertBefore($nextElement);
  21682. }
  21683. },
  21684. repaint: function() {
  21685. module.verbose('Repainting element');
  21686. var
  21687. fakeAssignment = element.offsetWidth
  21688. ;
  21689. },
  21690. delay: function(interval) {
  21691. var
  21692. direction = module.get.animationDirection(),
  21693. shouldReverse,
  21694. delay
  21695. ;
  21696. if(!direction) {
  21697. direction = module.can.transition()
  21698. ? module.get.direction()
  21699. : 'static'
  21700. ;
  21701. }
  21702. interval = (interval !== undefined)
  21703. ? interval
  21704. : settings.interval
  21705. ;
  21706. shouldReverse = (settings.reverse == 'auto' && direction == className.outward);
  21707. delay = (shouldReverse || settings.reverse == true)
  21708. ? ($allModules.length - index) * settings.interval
  21709. : index * settings.interval
  21710. ;
  21711. module.debug('Delaying animation by', delay);
  21712. setTimeout(module.animate, delay);
  21713. },
  21714. animate: function(overrideSettings) {
  21715. settings = overrideSettings || settings;
  21716. if(!module.is.supported()) {
  21717. module.error(error.support);
  21718. return false;
  21719. }
  21720. module.debug('Preparing animation', settings.animation);
  21721. if(module.is.animating()) {
  21722. if(settings.queue) {
  21723. if(!settings.allowRepeats && module.has.direction() && module.is.occurring() && module.queuing !== true) {
  21724. module.debug('Animation is currently occurring, preventing queueing same animation', settings.animation);
  21725. }
  21726. else {
  21727. module.queue(settings.animation);
  21728. }
  21729. return false;
  21730. }
  21731. else if(!settings.allowRepeats && module.is.occurring()) {
  21732. module.debug('Animation is already occurring, will not execute repeated animation', settings.animation);
  21733. return false;
  21734. }
  21735. else {
  21736. module.debug('New animation started, completing previous early', settings.animation);
  21737. instance.complete();
  21738. }
  21739. }
  21740. if( module.can.animate() ) {
  21741. module.set.animating(settings.animation);
  21742. }
  21743. else {
  21744. module.error(error.noAnimation, settings.animation, element);
  21745. }
  21746. },
  21747. reset: function() {
  21748. module.debug('Resetting animation to beginning conditions');
  21749. module.remove.animationCallbacks();
  21750. module.restore.conditions();
  21751. module.remove.animating();
  21752. },
  21753. queue: function(animation) {
  21754. module.debug('Queueing animation of', animation);
  21755. module.queuing = true;
  21756. $module
  21757. .one(animationEnd + '.queue' + eventNamespace, function() {
  21758. module.queuing = false;
  21759. module.repaint();
  21760. module.animate.apply(this, settings);
  21761. })
  21762. ;
  21763. },
  21764. complete: function (event) {
  21765. if(event && event.target === element) {
  21766. event.stopPropagation();
  21767. }
  21768. module.debug('Animation complete', settings.animation);
  21769. module.remove.completeCallback();
  21770. module.remove.failSafe();
  21771. if(!module.is.looping()) {
  21772. if( module.is.outward() ) {
  21773. module.verbose('Animation is outward, hiding element');
  21774. module.restore.conditions();
  21775. module.hide();
  21776. }
  21777. else if( module.is.inward() ) {
  21778. module.verbose('Animation is outward, showing element');
  21779. module.restore.conditions();
  21780. module.show();
  21781. }
  21782. else {
  21783. module.verbose('Static animation completed');
  21784. module.restore.conditions();
  21785. settings.onComplete.call(element);
  21786. }
  21787. }
  21788. },
  21789. force: {
  21790. visible: function() {
  21791. var
  21792. style = $module.attr('style'),
  21793. userStyle = module.get.userStyle(style),
  21794. displayType = module.get.displayType(),
  21795. overrideStyle = userStyle + 'display: ' + displayType + ' !important;',
  21796. inlineDisplay = $module[0].style.display,
  21797. mustStayHidden = !displayType || (inlineDisplay === 'none' && settings.skipInlineHidden) || $module[0].tagName.match(/(script|link|style)/i)
  21798. ;
  21799. if (mustStayHidden){
  21800. module.remove.transition();
  21801. return false;
  21802. }
  21803. module.verbose('Overriding default display to show element', displayType);
  21804. $module
  21805. .attr('style', overrideStyle)
  21806. ;
  21807. return true;
  21808. },
  21809. hidden: function() {
  21810. var
  21811. style = $module.attr('style'),
  21812. currentDisplay = $module.css('display'),
  21813. emptyStyle = (style === undefined || style === '')
  21814. ;
  21815. if(currentDisplay !== 'none' && !module.is.hidden()) {
  21816. module.verbose('Overriding default display to hide element');
  21817. $module
  21818. .css('display', 'none')
  21819. ;
  21820. }
  21821. else if(emptyStyle) {
  21822. $module
  21823. .removeAttr('style')
  21824. ;
  21825. }
  21826. }
  21827. },
  21828. has: {
  21829. direction: function(animation) {
  21830. var
  21831. hasDirection = false
  21832. ;
  21833. animation = animation || settings.animation;
  21834. if(typeof animation === 'string') {
  21835. animation = animation.split(' ');
  21836. $.each(animation, function(index, word){
  21837. if(word === className.inward || word === className.outward) {
  21838. hasDirection = true;
  21839. }
  21840. });
  21841. }
  21842. return hasDirection;
  21843. },
  21844. inlineDisplay: function() {
  21845. var
  21846. style = $module.attr('style') || ''
  21847. ;
  21848. return Array.isArray(style.match(/display.*?;/, ''));
  21849. }
  21850. },
  21851. set: {
  21852. animating: function(animation) {
  21853. // remove previous callbacks
  21854. module.remove.completeCallback();
  21855. // determine exact animation
  21856. animation = animation || settings.animation;
  21857. var animationClass = module.get.animationClass(animation);
  21858. // save animation class in cache to restore class names
  21859. module.save.animation(animationClass);
  21860. if(module.force.visible()) {
  21861. module.remove.hidden();
  21862. module.remove.direction();
  21863. module.start.animation(animationClass);
  21864. }
  21865. },
  21866. duration: function(animationName, duration) {
  21867. duration = duration || settings.duration;
  21868. duration = (typeof duration == 'number')
  21869. ? duration + 'ms'
  21870. : duration
  21871. ;
  21872. if(duration || duration === 0) {
  21873. module.verbose('Setting animation duration', duration);
  21874. $module
  21875. .css({
  21876. 'animation-duration': duration
  21877. })
  21878. ;
  21879. }
  21880. },
  21881. direction: function(direction) {
  21882. direction = direction || module.get.direction();
  21883. if(direction == className.inward) {
  21884. module.set.inward();
  21885. }
  21886. else {
  21887. module.set.outward();
  21888. }
  21889. },
  21890. looping: function() {
  21891. module.debug('Transition set to loop');
  21892. $module
  21893. .addClass(className.looping)
  21894. ;
  21895. },
  21896. hidden: function() {
  21897. $module
  21898. .addClass(className.transition)
  21899. .addClass(className.hidden)
  21900. ;
  21901. },
  21902. inward: function() {
  21903. module.debug('Setting direction to inward');
  21904. $module
  21905. .removeClass(className.outward)
  21906. .addClass(className.inward)
  21907. ;
  21908. },
  21909. outward: function() {
  21910. module.debug('Setting direction to outward');
  21911. $module
  21912. .removeClass(className.inward)
  21913. .addClass(className.outward)
  21914. ;
  21915. },
  21916. visible: function() {
  21917. $module
  21918. .addClass(className.transition)
  21919. .addClass(className.visible)
  21920. ;
  21921. }
  21922. },
  21923. start: {
  21924. animation: function(animationClass) {
  21925. animationClass = animationClass || module.get.animationClass();
  21926. module.debug('Starting tween', animationClass);
  21927. $module
  21928. .addClass(animationClass)
  21929. .one(animationEnd + '.complete' + eventNamespace, module.complete)
  21930. ;
  21931. if(settings.useFailSafe) {
  21932. module.add.failSafe();
  21933. }
  21934. module.set.duration(settings.duration);
  21935. settings.onStart.call(element);
  21936. }
  21937. },
  21938. save: {
  21939. animation: function(animation) {
  21940. if(!module.cache) {
  21941. module.cache = {};
  21942. }
  21943. module.cache.animation = animation;
  21944. },
  21945. displayType: function(displayType) {
  21946. if(displayType !== 'none') {
  21947. $module.data(metadata.displayType, displayType);
  21948. }
  21949. },
  21950. transitionExists: function(animation, exists) {
  21951. $.fn.transition.exists[animation] = exists;
  21952. module.verbose('Saving existence of transition', animation, exists);
  21953. }
  21954. },
  21955. restore: {
  21956. conditions: function() {
  21957. var
  21958. animation = module.get.currentAnimation()
  21959. ;
  21960. if(animation) {
  21961. $module
  21962. .removeClass(animation)
  21963. ;
  21964. module.verbose('Removing animation class', module.cache);
  21965. }
  21966. module.remove.duration();
  21967. }
  21968. },
  21969. add: {
  21970. failSafe: function() {
  21971. var
  21972. duration = module.get.duration()
  21973. ;
  21974. module.timer = setTimeout(function() {
  21975. $module.triggerHandler(animationEnd);
  21976. }, duration + settings.failSafeDelay);
  21977. module.verbose('Adding fail safe timer', module.timer);
  21978. }
  21979. },
  21980. remove: {
  21981. animating: function() {
  21982. $module.removeClass(className.animating);
  21983. },
  21984. animationCallbacks: function() {
  21985. module.remove.queueCallback();
  21986. module.remove.completeCallback();
  21987. },
  21988. queueCallback: function() {
  21989. $module.off('.queue' + eventNamespace);
  21990. },
  21991. completeCallback: function() {
  21992. $module.off('.complete' + eventNamespace);
  21993. },
  21994. display: function() {
  21995. $module.css('display', '');
  21996. },
  21997. direction: function() {
  21998. $module
  21999. .removeClass(className.inward)
  22000. .removeClass(className.outward)
  22001. ;
  22002. },
  22003. duration: function() {
  22004. $module
  22005. .css('animation-duration', '')
  22006. ;
  22007. },
  22008. failSafe: function() {
  22009. module.verbose('Removing fail safe timer', module.timer);
  22010. if(module.timer) {
  22011. clearTimeout(module.timer);
  22012. }
  22013. },
  22014. hidden: function() {
  22015. $module.removeClass(className.hidden);
  22016. },
  22017. visible: function() {
  22018. $module.removeClass(className.visible);
  22019. },
  22020. looping: function() {
  22021. module.debug('Transitions are no longer looping');
  22022. if( module.is.looping() ) {
  22023. module.reset();
  22024. $module
  22025. .removeClass(className.looping)
  22026. ;
  22027. }
  22028. },
  22029. transition: function() {
  22030. $module
  22031. .removeClass(className.transition)
  22032. .removeClass(className.visible)
  22033. .removeClass(className.hidden)
  22034. ;
  22035. }
  22036. },
  22037. get: {
  22038. settings: function(animation, duration, onComplete) {
  22039. // single settings object
  22040. if(typeof animation == 'object') {
  22041. return $.extend(true, {}, $.fn.transition.settings, animation);
  22042. }
  22043. // all arguments provided
  22044. else if(typeof onComplete == 'function') {
  22045. return $.extend({}, $.fn.transition.settings, {
  22046. animation : animation,
  22047. onComplete : onComplete,
  22048. duration : duration
  22049. });
  22050. }
  22051. // only duration provided
  22052. else if(typeof duration == 'string' || typeof duration == 'number') {
  22053. return $.extend({}, $.fn.transition.settings, {
  22054. animation : animation,
  22055. duration : duration
  22056. });
  22057. }
  22058. // duration is actually settings object
  22059. else if(typeof duration == 'object') {
  22060. return $.extend({}, $.fn.transition.settings, duration, {
  22061. animation : animation
  22062. });
  22063. }
  22064. // duration is actually callback
  22065. else if(typeof duration == 'function') {
  22066. return $.extend({}, $.fn.transition.settings, {
  22067. animation : animation,
  22068. onComplete : duration
  22069. });
  22070. }
  22071. // only animation provided
  22072. else {
  22073. return $.extend({}, $.fn.transition.settings, {
  22074. animation : animation
  22075. });
  22076. }
  22077. },
  22078. animationClass: function(animation) {
  22079. var
  22080. animationClass = animation || settings.animation,
  22081. directionClass = (module.can.transition() && !module.has.direction())
  22082. ? module.get.direction() + ' '
  22083. : ''
  22084. ;
  22085. return className.animating + ' '
  22086. + className.transition + ' '
  22087. + directionClass
  22088. + animationClass
  22089. ;
  22090. },
  22091. currentAnimation: function() {
  22092. return (module.cache && module.cache.animation !== undefined)
  22093. ? module.cache.animation
  22094. : false
  22095. ;
  22096. },
  22097. currentDirection: function() {
  22098. return module.is.inward()
  22099. ? className.inward
  22100. : className.outward
  22101. ;
  22102. },
  22103. direction: function() {
  22104. return module.is.hidden() || !module.is.visible()
  22105. ? className.inward
  22106. : className.outward
  22107. ;
  22108. },
  22109. animationDirection: function(animation) {
  22110. var
  22111. direction
  22112. ;
  22113. animation = animation || settings.animation;
  22114. if(typeof animation === 'string') {
  22115. animation = animation.split(' ');
  22116. // search animation name for out/in class
  22117. $.each(animation, function(index, word){
  22118. if(word === className.inward) {
  22119. direction = className.inward;
  22120. }
  22121. else if(word === className.outward) {
  22122. direction = className.outward;
  22123. }
  22124. });
  22125. }
  22126. // return found direction
  22127. if(direction) {
  22128. return direction;
  22129. }
  22130. return false;
  22131. },
  22132. duration: function(duration) {
  22133. duration = duration || settings.duration;
  22134. if(duration === false) {
  22135. duration = $module.css('animation-duration') || 0;
  22136. }
  22137. return (typeof duration === 'string')
  22138. ? (duration.indexOf('ms') > -1)
  22139. ? parseFloat(duration)
  22140. : parseFloat(duration) * 1000
  22141. : duration
  22142. ;
  22143. },
  22144. displayType: function(shouldDetermine) {
  22145. shouldDetermine = (shouldDetermine !== undefined)
  22146. ? shouldDetermine
  22147. : true
  22148. ;
  22149. if(settings.displayType) {
  22150. return settings.displayType;
  22151. }
  22152. if(shouldDetermine && $module.data(metadata.displayType) === undefined) {
  22153. var currentDisplay = $module.css('display');
  22154. if(currentDisplay === '' || currentDisplay === 'none'){
  22155. // create fake element to determine display state
  22156. module.can.transition(true);
  22157. } else {
  22158. module.save.displayType(currentDisplay);
  22159. }
  22160. }
  22161. return $module.data(metadata.displayType);
  22162. },
  22163. userStyle: function(style) {
  22164. style = style || $module.attr('style') || '';
  22165. return style.replace(/display.*?;/, '');
  22166. },
  22167. transitionExists: function(animation) {
  22168. return $.fn.transition.exists[animation];
  22169. },
  22170. animationStartEvent: function() {
  22171. var
  22172. element = document.createElement('div'),
  22173. animations = {
  22174. 'animation' :'animationstart',
  22175. 'OAnimation' :'oAnimationStart',
  22176. 'MozAnimation' :'mozAnimationStart',
  22177. 'WebkitAnimation' :'webkitAnimationStart'
  22178. },
  22179. animation
  22180. ;
  22181. for(animation in animations){
  22182. if( element.style[animation] !== undefined ){
  22183. return animations[animation];
  22184. }
  22185. }
  22186. return false;
  22187. },
  22188. animationEndEvent: function() {
  22189. var
  22190. element = document.createElement('div'),
  22191. animations = {
  22192. 'animation' :'animationend',
  22193. 'OAnimation' :'oAnimationEnd',
  22194. 'MozAnimation' :'mozAnimationEnd',
  22195. 'WebkitAnimation' :'webkitAnimationEnd'
  22196. },
  22197. animation
  22198. ;
  22199. for(animation in animations){
  22200. if( element.style[animation] !== undefined ){
  22201. return animations[animation];
  22202. }
  22203. }
  22204. return false;
  22205. }
  22206. },
  22207. can: {
  22208. transition: function(forced) {
  22209. var
  22210. animation = settings.animation,
  22211. transitionExists = module.get.transitionExists(animation),
  22212. displayType = module.get.displayType(false),
  22213. elementClass,
  22214. tagName,
  22215. $clone,
  22216. currentAnimation,
  22217. inAnimation,
  22218. directionExists
  22219. ;
  22220. if( transitionExists === undefined || forced) {
  22221. module.verbose('Determining whether animation exists');
  22222. elementClass = $module.attr('class');
  22223. tagName = $module.prop('tagName');
  22224. $clone = $('<' + tagName + ' />').addClass( elementClass ).insertAfter($module);
  22225. currentAnimation = $clone
  22226. .addClass(animation)
  22227. .removeClass(className.inward)
  22228. .removeClass(className.outward)
  22229. .addClass(className.animating)
  22230. .addClass(className.transition)
  22231. .css('animationName')
  22232. ;
  22233. inAnimation = $clone
  22234. .addClass(className.inward)
  22235. .css('animationName')
  22236. ;
  22237. if(!displayType) {
  22238. displayType = $clone
  22239. .attr('class', elementClass)
  22240. .removeAttr('style')
  22241. .removeClass(className.hidden)
  22242. .removeClass(className.visible)
  22243. .show()
  22244. .css('display')
  22245. ;
  22246. module.verbose('Determining final display state', displayType);
  22247. module.save.displayType(displayType);
  22248. }
  22249. $clone.remove();
  22250. if(currentAnimation != inAnimation) {
  22251. module.debug('Direction exists for animation', animation);
  22252. directionExists = true;
  22253. }
  22254. else if(currentAnimation == 'none' || !currentAnimation) {
  22255. module.debug('No animation defined in css', animation);
  22256. return;
  22257. }
  22258. else {
  22259. module.debug('Static animation found', animation, displayType);
  22260. directionExists = false;
  22261. }
  22262. module.save.transitionExists(animation, directionExists);
  22263. }
  22264. return (transitionExists !== undefined)
  22265. ? transitionExists
  22266. : directionExists
  22267. ;
  22268. },
  22269. animate: function() {
  22270. // can transition does not return a value if animation does not exist
  22271. return (module.can.transition() !== undefined);
  22272. }
  22273. },
  22274. is: {
  22275. animating: function() {
  22276. return $module.hasClass(className.animating);
  22277. },
  22278. inward: function() {
  22279. return $module.hasClass(className.inward);
  22280. },
  22281. outward: function() {
  22282. return $module.hasClass(className.outward);
  22283. },
  22284. looping: function() {
  22285. return $module.hasClass(className.looping);
  22286. },
  22287. occurring: function(animation) {
  22288. animation = animation || settings.animation;
  22289. animation = '.' + animation.replace(' ', '.');
  22290. return ( $module.filter(animation).length > 0 );
  22291. },
  22292. visible: function() {
  22293. return $module.is(':visible');
  22294. },
  22295. hidden: function() {
  22296. return $module.css('visibility') === 'hidden';
  22297. },
  22298. supported: function() {
  22299. return(animationEnd !== false);
  22300. }
  22301. },
  22302. hide: function() {
  22303. module.verbose('Hiding element');
  22304. if( module.is.animating() ) {
  22305. module.reset();
  22306. }
  22307. element.blur(); // IE will trigger focus change if element is not blurred before hiding
  22308. module.remove.display();
  22309. module.remove.visible();
  22310. if($.isFunction(settings.onBeforeHide)){
  22311. settings.onBeforeHide.call(element,function(){
  22312. module.hideNow();
  22313. });
  22314. } else {
  22315. module.hideNow();
  22316. }
  22317. },
  22318. hideNow: function() {
  22319. module.set.hidden();
  22320. module.force.hidden();
  22321. settings.onHide.call(element);
  22322. settings.onComplete.call(element);
  22323. // module.repaint();
  22324. },
  22325. show: function(display) {
  22326. module.verbose('Showing element', display);
  22327. if(module.force.visible()) {
  22328. module.remove.hidden();
  22329. module.set.visible();
  22330. settings.onShow.call(element);
  22331. settings.onComplete.call(element);
  22332. // module.repaint();
  22333. }
  22334. },
  22335. toggle: function() {
  22336. if( module.is.visible() ) {
  22337. module.hide();
  22338. }
  22339. else {
  22340. module.show();
  22341. }
  22342. },
  22343. stop: function() {
  22344. module.debug('Stopping current animation');
  22345. $module.triggerHandler(animationEnd);
  22346. },
  22347. stopAll: function() {
  22348. module.debug('Stopping all animation');
  22349. module.remove.queueCallback();
  22350. $module.triggerHandler(animationEnd);
  22351. },
  22352. clear: {
  22353. queue: function() {
  22354. module.debug('Clearing animation queue');
  22355. module.remove.queueCallback();
  22356. }
  22357. },
  22358. enable: function() {
  22359. module.verbose('Starting animation');
  22360. $module.removeClass(className.disabled);
  22361. },
  22362. disable: function() {
  22363. module.debug('Stopping animation');
  22364. $module.addClass(className.disabled);
  22365. },
  22366. setting: function(name, value) {
  22367. module.debug('Changing setting', name, value);
  22368. if( $.isPlainObject(name) ) {
  22369. $.extend(true, settings, name);
  22370. }
  22371. else if(value !== undefined) {
  22372. if($.isPlainObject(settings[name])) {
  22373. $.extend(true, settings[name], value);
  22374. }
  22375. else {
  22376. settings[name] = value;
  22377. }
  22378. }
  22379. else {
  22380. return settings[name];
  22381. }
  22382. },
  22383. internal: function(name, value) {
  22384. if( $.isPlainObject(name) ) {
  22385. $.extend(true, module, name);
  22386. }
  22387. else if(value !== undefined) {
  22388. module[name] = value;
  22389. }
  22390. else {
  22391. return module[name];
  22392. }
  22393. },
  22394. debug: function() {
  22395. if(!settings.silent && settings.debug) {
  22396. if(settings.performance) {
  22397. module.performance.log(arguments);
  22398. }
  22399. else {
  22400. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  22401. module.debug.apply(console, arguments);
  22402. }
  22403. }
  22404. },
  22405. verbose: function() {
  22406. if(!settings.silent && settings.verbose && settings.debug) {
  22407. if(settings.performance) {
  22408. module.performance.log(arguments);
  22409. }
  22410. else {
  22411. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  22412. module.verbose.apply(console, arguments);
  22413. }
  22414. }
  22415. },
  22416. error: function() {
  22417. if(!settings.silent) {
  22418. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  22419. module.error.apply(console, arguments);
  22420. }
  22421. },
  22422. performance: {
  22423. log: function(message) {
  22424. var
  22425. currentTime,
  22426. executionTime,
  22427. previousTime
  22428. ;
  22429. if(settings.performance) {
  22430. currentTime = new Date().getTime();
  22431. previousTime = time || currentTime;
  22432. executionTime = currentTime - previousTime;
  22433. time = currentTime;
  22434. performance.push({
  22435. 'Name' : message[0],
  22436. 'Arguments' : [].slice.call(message, 1) || '',
  22437. 'Element' : element,
  22438. 'Execution Time' : executionTime
  22439. });
  22440. }
  22441. clearTimeout(module.performance.timer);
  22442. module.performance.timer = setTimeout(module.performance.display, 500);
  22443. },
  22444. display: function() {
  22445. var
  22446. title = settings.name + ':',
  22447. totalTime = 0
  22448. ;
  22449. time = false;
  22450. clearTimeout(module.performance.timer);
  22451. $.each(performance, function(index, data) {
  22452. totalTime += data['Execution Time'];
  22453. });
  22454. title += ' ' + totalTime + 'ms';
  22455. if(moduleSelector) {
  22456. title += ' \'' + moduleSelector + '\'';
  22457. }
  22458. if($allModules.length > 1) {
  22459. title += ' ' + '(' + $allModules.length + ')';
  22460. }
  22461. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  22462. console.groupCollapsed(title);
  22463. if(console.table) {
  22464. console.table(performance);
  22465. }
  22466. else {
  22467. $.each(performance, function(index, data) {
  22468. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  22469. });
  22470. }
  22471. console.groupEnd();
  22472. }
  22473. performance = [];
  22474. }
  22475. },
  22476. // modified for transition to return invoke success
  22477. invoke: function(query, passedArguments, context) {
  22478. var
  22479. object = instance,
  22480. maxDepth,
  22481. found,
  22482. response
  22483. ;
  22484. passedArguments = passedArguments || queryArguments;
  22485. context = element || context;
  22486. if(typeof query == 'string' && object !== undefined) {
  22487. query = query.split(/[\. ]/);
  22488. maxDepth = query.length - 1;
  22489. $.each(query, function(depth, value) {
  22490. var camelCaseValue = (depth != maxDepth)
  22491. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  22492. : query
  22493. ;
  22494. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  22495. object = object[camelCaseValue];
  22496. }
  22497. else if( object[camelCaseValue] !== undefined ) {
  22498. found = object[camelCaseValue];
  22499. return false;
  22500. }
  22501. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  22502. object = object[value];
  22503. }
  22504. else if( object[value] !== undefined ) {
  22505. found = object[value];
  22506. return false;
  22507. }
  22508. else {
  22509. return false;
  22510. }
  22511. });
  22512. }
  22513. if ( $.isFunction( found ) ) {
  22514. response = found.apply(context, passedArguments);
  22515. }
  22516. else if(found !== undefined) {
  22517. response = found;
  22518. }
  22519. if(Array.isArray(returnedValue)) {
  22520. returnedValue.push(response);
  22521. }
  22522. else if(returnedValue !== undefined) {
  22523. returnedValue = [returnedValue, response];
  22524. }
  22525. else if(response !== undefined) {
  22526. returnedValue = response;
  22527. }
  22528. return (found !== undefined)
  22529. ? found
  22530. : false
  22531. ;
  22532. }
  22533. };
  22534. module.initialize();
  22535. })
  22536. ;
  22537. return (returnedValue !== undefined)
  22538. ? returnedValue
  22539. : this
  22540. ;
  22541. };
  22542. // Records if CSS transition is available
  22543. $.fn.transition.exists = {};
  22544. $.fn.transition.settings = {
  22545. // module info
  22546. name : 'Transition',
  22547. // hide all output from this component regardless of other settings
  22548. silent : false,
  22549. // debug content outputted to console
  22550. debug : false,
  22551. // verbose debug output
  22552. verbose : false,
  22553. // performance data output
  22554. performance : true,
  22555. // event namespace
  22556. namespace : 'transition',
  22557. // delay between animations in group
  22558. interval : 0,
  22559. // whether group animations should be reversed
  22560. reverse : 'auto',
  22561. // animation callback event
  22562. onStart : function() {},
  22563. onComplete : function() {},
  22564. onShow : function() {},
  22565. onHide : function() {},
  22566. // whether timeout should be used to ensure callback fires in cases animationend does not
  22567. useFailSafe : true,
  22568. // delay in ms for fail safe
  22569. failSafeDelay : 100,
  22570. // whether EXACT animation can occur twice in a row
  22571. allowRepeats : false,
  22572. // Override final display type on visible
  22573. displayType : false,
  22574. // animation duration
  22575. animation : 'fade',
  22576. duration : false,
  22577. // new animations will occur after previous ones
  22578. queue : true,
  22579. // whether initially inline hidden objects should be skipped for transition
  22580. skipInlineHidden: false,
  22581. metadata : {
  22582. displayType: 'display'
  22583. },
  22584. className : {
  22585. animating : 'animating',
  22586. disabled : 'disabled',
  22587. hidden : 'hidden',
  22588. inward : 'in',
  22589. loading : 'loading',
  22590. looping : 'looping',
  22591. outward : 'out',
  22592. transition : 'transition',
  22593. visible : 'visible'
  22594. },
  22595. // possible errors
  22596. error: {
  22597. noAnimation : 'Element is no longer attached to DOM. Unable to animate. Use silent setting to surpress this warning in production.',
  22598. repeated : 'That animation is already occurring, cancelling repeated animation',
  22599. method : 'The method you called is not defined',
  22600. support : 'This browser does not support CSS animations'
  22601. }
  22602. };
  22603. })( jQuery, window, document );
  22604. /*!
  22605. * # Fomantic-UI - API
  22606. * http://github.com/fomantic/Fomantic-UI/
  22607. *
  22608. *
  22609. * Released under the MIT license
  22610. * http://opensource.org/licenses/MIT
  22611. *
  22612. */
  22613. ;(function ($, window, document, undefined) {
  22614. 'use strict';
  22615. $.isWindow = $.isWindow || function(obj) {
  22616. return obj != null && obj === obj.window;
  22617. };
  22618. window = (typeof window != 'undefined' && window.Math == Math)
  22619. ? window
  22620. : (typeof self != 'undefined' && self.Math == Math)
  22621. ? self
  22622. : Function('return this')()
  22623. ;
  22624. $.api = $.fn.api = function(parameters) {
  22625. var
  22626. // use window context if none specified
  22627. $allModules = $.isFunction(this)
  22628. ? $(window)
  22629. : $(this),
  22630. moduleSelector = $allModules.selector || '',
  22631. time = new Date().getTime(),
  22632. performance = [],
  22633. query = arguments[0],
  22634. methodInvoked = (typeof query == 'string'),
  22635. queryArguments = [].slice.call(arguments, 1),
  22636. returnedValue
  22637. ;
  22638. $allModules
  22639. .each(function() {
  22640. var
  22641. settings = ( $.isPlainObject(parameters) )
  22642. ? $.extend(true, {}, $.fn.api.settings, parameters)
  22643. : $.extend({}, $.fn.api.settings),
  22644. // internal aliases
  22645. namespace = settings.namespace,
  22646. metadata = settings.metadata,
  22647. selector = settings.selector,
  22648. error = settings.error,
  22649. className = settings.className,
  22650. // define namespaces for modules
  22651. eventNamespace = '.' + namespace,
  22652. moduleNamespace = 'module-' + namespace,
  22653. // element that creates request
  22654. $module = $(this),
  22655. $form = $module.closest(selector.form),
  22656. // context used for state
  22657. $context = (settings.stateContext)
  22658. ? $(settings.stateContext)
  22659. : $module,
  22660. // request details
  22661. ajaxSettings,
  22662. requestSettings,
  22663. url,
  22664. data,
  22665. requestStartTime,
  22666. // standard module
  22667. element = this,
  22668. context = $context[0],
  22669. instance = $module.data(moduleNamespace),
  22670. module
  22671. ;
  22672. module = {
  22673. initialize: function() {
  22674. if(!methodInvoked) {
  22675. module.bind.events();
  22676. }
  22677. module.instantiate();
  22678. },
  22679. instantiate: function() {
  22680. module.verbose('Storing instance of module', module);
  22681. instance = module;
  22682. $module
  22683. .data(moduleNamespace, instance)
  22684. ;
  22685. },
  22686. destroy: function() {
  22687. module.verbose('Destroying previous module for', element);
  22688. $module
  22689. .removeData(moduleNamespace)
  22690. .off(eventNamespace)
  22691. ;
  22692. },
  22693. bind: {
  22694. events: function() {
  22695. var
  22696. triggerEvent = module.get.event()
  22697. ;
  22698. if( triggerEvent ) {
  22699. module.verbose('Attaching API events to element', triggerEvent);
  22700. $module
  22701. .on(triggerEvent + eventNamespace, module.event.trigger)
  22702. ;
  22703. }
  22704. else if(settings.on == 'now') {
  22705. module.debug('Querying API endpoint immediately');
  22706. module.query();
  22707. }
  22708. }
  22709. },
  22710. decode: {
  22711. json: function(response) {
  22712. if(response !== undefined && typeof response == 'string') {
  22713. try {
  22714. response = JSON.parse(response);
  22715. }
  22716. catch(e) {
  22717. // isnt json string
  22718. }
  22719. }
  22720. return response;
  22721. }
  22722. },
  22723. read: {
  22724. cachedResponse: function(url) {
  22725. var
  22726. response
  22727. ;
  22728. if(window.Storage === undefined) {
  22729. module.error(error.noStorage);
  22730. return;
  22731. }
  22732. response = sessionStorage.getItem(url);
  22733. module.debug('Using cached response', url, response);
  22734. response = module.decode.json(response);
  22735. return response;
  22736. }
  22737. },
  22738. write: {
  22739. cachedResponse: function(url, response) {
  22740. if(response && response === '') {
  22741. module.debug('Response empty, not caching', response);
  22742. return;
  22743. }
  22744. if(window.Storage === undefined) {
  22745. module.error(error.noStorage);
  22746. return;
  22747. }
  22748. if( $.isPlainObject(response) ) {
  22749. response = JSON.stringify(response);
  22750. }
  22751. sessionStorage.setItem(url, response);
  22752. module.verbose('Storing cached response for url', url, response);
  22753. }
  22754. },
  22755. query: function() {
  22756. if(module.is.disabled()) {
  22757. module.debug('Element is disabled API request aborted');
  22758. return;
  22759. }
  22760. if(module.is.loading()) {
  22761. if(settings.interruptRequests) {
  22762. module.debug('Interrupting previous request');
  22763. module.abort();
  22764. }
  22765. else {
  22766. module.debug('Cancelling request, previous request is still pending');
  22767. return;
  22768. }
  22769. }
  22770. // pass element metadata to url (value, text)
  22771. if(settings.defaultData) {
  22772. $.extend(true, settings.urlData, module.get.defaultData());
  22773. }
  22774. // Add form content
  22775. if(settings.serializeForm) {
  22776. settings.data = module.add.formData(settings.data);
  22777. }
  22778. // call beforesend and get any settings changes
  22779. requestSettings = module.get.settings();
  22780. // check if before send cancelled request
  22781. if(requestSettings === false) {
  22782. module.cancelled = true;
  22783. module.error(error.beforeSend);
  22784. return;
  22785. }
  22786. else {
  22787. module.cancelled = false;
  22788. }
  22789. // get url
  22790. url = module.get.templatedURL();
  22791. if(!url && !module.is.mocked()) {
  22792. module.error(error.missingURL);
  22793. return;
  22794. }
  22795. // replace variables
  22796. url = module.add.urlData( url );
  22797. // missing url parameters
  22798. if( !url && !module.is.mocked()) {
  22799. return;
  22800. }
  22801. requestSettings.url = settings.base + url;
  22802. // look for jQuery ajax parameters in settings
  22803. ajaxSettings = $.extend(true, {}, settings, {
  22804. type : settings.method || settings.type,
  22805. data : data,
  22806. url : settings.base + url,
  22807. beforeSend : settings.beforeXHR,
  22808. success : function() {},
  22809. failure : function() {},
  22810. complete : function() {}
  22811. });
  22812. module.debug('Querying URL', ajaxSettings.url);
  22813. module.verbose('Using AJAX settings', ajaxSettings);
  22814. if(settings.cache === 'local' && module.read.cachedResponse(url)) {
  22815. module.debug('Response returned from local cache');
  22816. module.request = module.create.request();
  22817. module.request.resolveWith(context, [ module.read.cachedResponse(url) ]);
  22818. return;
  22819. }
  22820. if( !settings.throttle ) {
  22821. module.debug('Sending request', data, ajaxSettings.method);
  22822. module.send.request();
  22823. }
  22824. else {
  22825. if(!settings.throttleFirstRequest && !module.timer) {
  22826. module.debug('Sending request', data, ajaxSettings.method);
  22827. module.send.request();
  22828. module.timer = setTimeout(function(){}, settings.throttle);
  22829. }
  22830. else {
  22831. module.debug('Throttling request', settings.throttle);
  22832. clearTimeout(module.timer);
  22833. module.timer = setTimeout(function() {
  22834. if(module.timer) {
  22835. delete module.timer;
  22836. }
  22837. module.debug('Sending throttled request', data, ajaxSettings.method);
  22838. module.send.request();
  22839. }, settings.throttle);
  22840. }
  22841. }
  22842. },
  22843. should: {
  22844. removeError: function() {
  22845. return ( settings.hideError === true || (settings.hideError === 'auto' && !module.is.form()) );
  22846. }
  22847. },
  22848. is: {
  22849. disabled: function() {
  22850. return ($module.filter(selector.disabled).length > 0);
  22851. },
  22852. expectingJSON: function() {
  22853. return settings.dataType === 'json' || settings.dataType === 'jsonp';
  22854. },
  22855. form: function() {
  22856. return $module.is('form') || $context.is('form');
  22857. },
  22858. mocked: function() {
  22859. return (settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync);
  22860. },
  22861. input: function() {
  22862. return $module.is('input');
  22863. },
  22864. loading: function() {
  22865. return (module.request)
  22866. ? (module.request.state() == 'pending')
  22867. : false
  22868. ;
  22869. },
  22870. abortedRequest: function(xhr) {
  22871. if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
  22872. module.verbose('XHR request determined to be aborted');
  22873. return true;
  22874. }
  22875. else {
  22876. module.verbose('XHR request was not aborted');
  22877. return false;
  22878. }
  22879. },
  22880. validResponse: function(response) {
  22881. if( (!module.is.expectingJSON()) || !$.isFunction(settings.successTest) ) {
  22882. module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
  22883. return true;
  22884. }
  22885. module.debug('Checking JSON returned success', settings.successTest, response);
  22886. if( settings.successTest(response) ) {
  22887. module.debug('Response passed success test', response);
  22888. return true;
  22889. }
  22890. else {
  22891. module.debug('Response failed success test', response);
  22892. return false;
  22893. }
  22894. }
  22895. },
  22896. was: {
  22897. cancelled: function() {
  22898. return (module.cancelled || false);
  22899. },
  22900. succesful: function() {
  22901. module.verbose('This behavior will be deleted due to typo. Use "was successful" instead.');
  22902. return module.was.successful();
  22903. },
  22904. successful: function() {
  22905. return (module.request && module.request.state() == 'resolved');
  22906. },
  22907. failure: function() {
  22908. return (module.request && module.request.state() == 'rejected');
  22909. },
  22910. complete: function() {
  22911. return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') );
  22912. }
  22913. },
  22914. add: {
  22915. urlData: function(url, urlData) {
  22916. var
  22917. requiredVariables,
  22918. optionalVariables
  22919. ;
  22920. if(url) {
  22921. requiredVariables = url.match(settings.regExp.required);
  22922. optionalVariables = url.match(settings.regExp.optional);
  22923. urlData = urlData || settings.urlData;
  22924. if(requiredVariables) {
  22925. module.debug('Looking for required URL variables', requiredVariables);
  22926. $.each(requiredVariables, function(index, templatedString) {
  22927. var
  22928. // allow legacy {$var} style
  22929. variable = (templatedString.indexOf('$') !== -1)
  22930. ? templatedString.substr(2, templatedString.length - 3)
  22931. : templatedString.substr(1, templatedString.length - 2),
  22932. value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
  22933. ? urlData[variable]
  22934. : ($module.data(variable) !== undefined)
  22935. ? $module.data(variable)
  22936. : ($context.data(variable) !== undefined)
  22937. ? $context.data(variable)
  22938. : urlData[variable]
  22939. ;
  22940. // remove value
  22941. if(value === undefined) {
  22942. module.error(error.requiredParameter, variable, url);
  22943. url = false;
  22944. return false;
  22945. }
  22946. else {
  22947. module.verbose('Found required variable', variable, value);
  22948. value = (settings.encodeParameters)
  22949. ? module.get.urlEncodedValue(value)
  22950. : value
  22951. ;
  22952. url = url.replace(templatedString, value);
  22953. }
  22954. });
  22955. }
  22956. if(optionalVariables) {
  22957. module.debug('Looking for optional URL variables', requiredVariables);
  22958. $.each(optionalVariables, function(index, templatedString) {
  22959. var
  22960. // allow legacy {/$var} style
  22961. variable = (templatedString.indexOf('$') !== -1)
  22962. ? templatedString.substr(3, templatedString.length - 4)
  22963. : templatedString.substr(2, templatedString.length - 3),
  22964. value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
  22965. ? urlData[variable]
  22966. : ($module.data(variable) !== undefined)
  22967. ? $module.data(variable)
  22968. : ($context.data(variable) !== undefined)
  22969. ? $context.data(variable)
  22970. : urlData[variable]
  22971. ;
  22972. // optional replacement
  22973. if(value !== undefined) {
  22974. module.verbose('Optional variable Found', variable, value);
  22975. url = url.replace(templatedString, value);
  22976. }
  22977. else {
  22978. module.verbose('Optional variable not found', variable);
  22979. // remove preceding slash if set
  22980. if(url.indexOf('/' + templatedString) !== -1) {
  22981. url = url.replace('/' + templatedString, '');
  22982. }
  22983. else {
  22984. url = url.replace(templatedString, '');
  22985. }
  22986. }
  22987. });
  22988. }
  22989. }
  22990. return url;
  22991. },
  22992. formData: function(data) {
  22993. var
  22994. canSerialize = ($.fn.serializeObject !== undefined),
  22995. formData = (canSerialize)
  22996. ? $form.serializeObject()
  22997. : $form.serialize(),
  22998. hasOtherData
  22999. ;
  23000. data = data || settings.data;
  23001. hasOtherData = $.isPlainObject(data);
  23002. if(hasOtherData) {
  23003. if(canSerialize) {
  23004. module.debug('Extending existing data with form data', data, formData);
  23005. data = $.extend(true, {}, data, formData);
  23006. }
  23007. else {
  23008. module.error(error.missingSerialize);
  23009. module.debug('Cant extend data. Replacing data with form data', data, formData);
  23010. data = formData;
  23011. }
  23012. }
  23013. else {
  23014. module.debug('Adding form data', formData);
  23015. data = formData;
  23016. }
  23017. return data;
  23018. }
  23019. },
  23020. send: {
  23021. request: function() {
  23022. module.set.loading();
  23023. module.request = module.create.request();
  23024. if( module.is.mocked() ) {
  23025. module.mockedXHR = module.create.mockedXHR();
  23026. }
  23027. else {
  23028. module.xhr = module.create.xhr();
  23029. }
  23030. settings.onRequest.call(context, module.request, module.xhr);
  23031. }
  23032. },
  23033. event: {
  23034. trigger: function(event) {
  23035. module.query();
  23036. if(event.type == 'submit' || event.type == 'click') {
  23037. event.preventDefault();
  23038. }
  23039. },
  23040. xhr: {
  23041. always: function() {
  23042. // nothing special
  23043. },
  23044. done: function(response, textStatus, xhr) {
  23045. var
  23046. context = this,
  23047. elapsedTime = (new Date().getTime() - requestStartTime),
  23048. timeLeft = (settings.loadingDuration - elapsedTime),
  23049. translatedResponse = ( $.isFunction(settings.onResponse) )
  23050. ? module.is.expectingJSON() && !settings.rawResponse
  23051. ? settings.onResponse.call(context, $.extend(true, {}, response))
  23052. : settings.onResponse.call(context, response)
  23053. : false
  23054. ;
  23055. timeLeft = (timeLeft > 0)
  23056. ? timeLeft
  23057. : 0
  23058. ;
  23059. if(translatedResponse) {
  23060. module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
  23061. response = translatedResponse;
  23062. }
  23063. if(timeLeft > 0) {
  23064. module.debug('Response completed early delaying state change by', timeLeft);
  23065. }
  23066. setTimeout(function() {
  23067. if( module.is.validResponse(response) ) {
  23068. module.request.resolveWith(context, [response, xhr]);
  23069. }
  23070. else {
  23071. module.request.rejectWith(context, [xhr, 'invalid']);
  23072. }
  23073. }, timeLeft);
  23074. },
  23075. fail: function(xhr, status, httpMessage) {
  23076. var
  23077. context = this,
  23078. elapsedTime = (new Date().getTime() - requestStartTime),
  23079. timeLeft = (settings.loadingDuration - elapsedTime)
  23080. ;
  23081. timeLeft = (timeLeft > 0)
  23082. ? timeLeft
  23083. : 0
  23084. ;
  23085. if(timeLeft > 0) {
  23086. module.debug('Response completed early delaying state change by', timeLeft);
  23087. }
  23088. setTimeout(function() {
  23089. if( module.is.abortedRequest(xhr) ) {
  23090. module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
  23091. }
  23092. else {
  23093. module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
  23094. }
  23095. }, timeLeft);
  23096. }
  23097. },
  23098. request: {
  23099. done: function(response, xhr) {
  23100. module.debug('Successful API Response', response);
  23101. if(settings.cache === 'local' && url) {
  23102. module.write.cachedResponse(url, response);
  23103. module.debug('Saving server response locally', module.cache);
  23104. }
  23105. settings.onSuccess.call(context, response, $module, xhr);
  23106. },
  23107. complete: function(firstParameter, secondParameter) {
  23108. var
  23109. xhr,
  23110. response
  23111. ;
  23112. // have to guess callback parameters based on request success
  23113. if( module.was.successful() ) {
  23114. response = firstParameter;
  23115. xhr = secondParameter;
  23116. }
  23117. else {
  23118. xhr = firstParameter;
  23119. response = module.get.responseFromXHR(xhr);
  23120. }
  23121. module.remove.loading();
  23122. settings.onComplete.call(context, response, $module, xhr);
  23123. },
  23124. fail: function(xhr, status, httpMessage) {
  23125. var
  23126. // pull response from xhr if available
  23127. response = module.get.responseFromXHR(xhr),
  23128. errorMessage = module.get.errorFromRequest(response, status, httpMessage)
  23129. ;
  23130. if(status == 'aborted') {
  23131. module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
  23132. settings.onAbort.call(context, status, $module, xhr);
  23133. return true;
  23134. }
  23135. else if(status == 'invalid') {
  23136. module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
  23137. }
  23138. else if(status == 'error') {
  23139. if(xhr !== undefined) {
  23140. module.debug('XHR produced a server error', status, httpMessage);
  23141. // make sure we have an error to display to console
  23142. if( (xhr.status < 200 || xhr.status >= 300) && httpMessage !== undefined && httpMessage !== '') {
  23143. module.error(error.statusMessage + httpMessage, ajaxSettings.url);
  23144. }
  23145. settings.onError.call(context, errorMessage, $module, xhr);
  23146. }
  23147. }
  23148. if(settings.errorDuration && status !== 'aborted') {
  23149. module.debug('Adding error state');
  23150. module.set.error();
  23151. if( module.should.removeError() ) {
  23152. setTimeout(module.remove.error, settings.errorDuration);
  23153. }
  23154. }
  23155. module.debug('API Request failed', errorMessage, xhr);
  23156. settings.onFailure.call(context, response, $module, xhr);
  23157. }
  23158. }
  23159. },
  23160. create: {
  23161. request: function() {
  23162. // api request promise
  23163. return $.Deferred()
  23164. .always(module.event.request.complete)
  23165. .done(module.event.request.done)
  23166. .fail(module.event.request.fail)
  23167. ;
  23168. },
  23169. mockedXHR: function () {
  23170. var
  23171. // xhr does not simulate these properties of xhr but must return them
  23172. textStatus = false,
  23173. status = false,
  23174. httpMessage = false,
  23175. responder = settings.mockResponse || settings.response,
  23176. asyncResponder = settings.mockResponseAsync || settings.responseAsync,
  23177. asyncCallback,
  23178. response,
  23179. mockedXHR
  23180. ;
  23181. mockedXHR = $.Deferred()
  23182. .always(module.event.xhr.complete)
  23183. .done(module.event.xhr.done)
  23184. .fail(module.event.xhr.fail)
  23185. ;
  23186. if(responder) {
  23187. if( $.isFunction(responder) ) {
  23188. module.debug('Using specified synchronous callback', responder);
  23189. response = responder.call(context, requestSettings);
  23190. }
  23191. else {
  23192. module.debug('Using settings specified response', responder);
  23193. response = responder;
  23194. }
  23195. // simulating response
  23196. mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
  23197. }
  23198. else if( $.isFunction(asyncResponder) ) {
  23199. asyncCallback = function(response) {
  23200. module.debug('Async callback returned response', response);
  23201. if(response) {
  23202. mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
  23203. }
  23204. else {
  23205. mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
  23206. }
  23207. };
  23208. module.debug('Using specified async response callback', asyncResponder);
  23209. asyncResponder.call(context, requestSettings, asyncCallback);
  23210. }
  23211. return mockedXHR;
  23212. },
  23213. xhr: function() {
  23214. var
  23215. xhr
  23216. ;
  23217. // ajax request promise
  23218. xhr = $.ajax(ajaxSettings)
  23219. .always(module.event.xhr.always)
  23220. .done(module.event.xhr.done)
  23221. .fail(module.event.xhr.fail)
  23222. ;
  23223. module.verbose('Created server request', xhr, ajaxSettings);
  23224. return xhr;
  23225. }
  23226. },
  23227. set: {
  23228. error: function() {
  23229. module.verbose('Adding error state to element', $context);
  23230. $context.addClass(className.error);
  23231. },
  23232. loading: function() {
  23233. module.verbose('Adding loading state to element', $context);
  23234. $context.addClass(className.loading);
  23235. requestStartTime = new Date().getTime();
  23236. }
  23237. },
  23238. remove: {
  23239. error: function() {
  23240. module.verbose('Removing error state from element', $context);
  23241. $context.removeClass(className.error);
  23242. },
  23243. loading: function() {
  23244. module.verbose('Removing loading state from element', $context);
  23245. $context.removeClass(className.loading);
  23246. }
  23247. },
  23248. get: {
  23249. responseFromXHR: function(xhr) {
  23250. return $.isPlainObject(xhr)
  23251. ? (module.is.expectingJSON())
  23252. ? module.decode.json(xhr.responseText)
  23253. : xhr.responseText
  23254. : false
  23255. ;
  23256. },
  23257. errorFromRequest: function(response, status, httpMessage) {
  23258. return ($.isPlainObject(response) && response.error !== undefined)
  23259. ? response.error // use json error message
  23260. : (settings.error[status] !== undefined) // use server error message
  23261. ? settings.error[status]
  23262. : httpMessage
  23263. ;
  23264. },
  23265. request: function() {
  23266. return module.request || false;
  23267. },
  23268. xhr: function() {
  23269. return module.xhr || false;
  23270. },
  23271. settings: function() {
  23272. var
  23273. runSettings
  23274. ;
  23275. runSettings = settings.beforeSend.call(context, settings);
  23276. if(runSettings) {
  23277. if(runSettings.success !== undefined) {
  23278. module.debug('Legacy success callback detected', runSettings);
  23279. module.error(error.legacyParameters, runSettings.success);
  23280. runSettings.onSuccess = runSettings.success;
  23281. }
  23282. if(runSettings.failure !== undefined) {
  23283. module.debug('Legacy failure callback detected', runSettings);
  23284. module.error(error.legacyParameters, runSettings.failure);
  23285. runSettings.onFailure = runSettings.failure;
  23286. }
  23287. if(runSettings.complete !== undefined) {
  23288. module.debug('Legacy complete callback detected', runSettings);
  23289. module.error(error.legacyParameters, runSettings.complete);
  23290. runSettings.onComplete = runSettings.complete;
  23291. }
  23292. }
  23293. if(runSettings === undefined) {
  23294. module.error(error.noReturnedValue);
  23295. }
  23296. if(runSettings === false) {
  23297. return runSettings;
  23298. }
  23299. return (runSettings !== undefined)
  23300. ? $.extend(true, {}, runSettings)
  23301. : $.extend(true, {}, settings)
  23302. ;
  23303. },
  23304. urlEncodedValue: function(value) {
  23305. var
  23306. decodedValue = window.decodeURIComponent(value),
  23307. encodedValue = window.encodeURIComponent(value),
  23308. alreadyEncoded = (decodedValue !== value)
  23309. ;
  23310. if(alreadyEncoded) {
  23311. module.debug('URL value is already encoded, avoiding double encoding', value);
  23312. return value;
  23313. }
  23314. module.verbose('Encoding value using encodeURIComponent', value, encodedValue);
  23315. return encodedValue;
  23316. },
  23317. defaultData: function() {
  23318. var
  23319. data = {}
  23320. ;
  23321. if( !$.isWindow(element) ) {
  23322. if( module.is.input() ) {
  23323. data.value = $module.val();
  23324. }
  23325. else if( module.is.form() ) {
  23326. }
  23327. else {
  23328. data.text = $module.text();
  23329. }
  23330. }
  23331. return data;
  23332. },
  23333. event: function() {
  23334. if( $.isWindow(element) || settings.on == 'now' ) {
  23335. module.debug('API called without element, no events attached');
  23336. return false;
  23337. }
  23338. else if(settings.on == 'auto') {
  23339. if( $module.is('input') ) {
  23340. return (element.oninput !== undefined)
  23341. ? 'input'
  23342. : (element.onpropertychange !== undefined)
  23343. ? 'propertychange'
  23344. : 'keyup'
  23345. ;
  23346. }
  23347. else if( $module.is('form') ) {
  23348. return 'submit';
  23349. }
  23350. else {
  23351. return 'click';
  23352. }
  23353. }
  23354. else {
  23355. return settings.on;
  23356. }
  23357. },
  23358. templatedURL: function(action) {
  23359. action = action || $module.data(metadata.action) || settings.action || false;
  23360. url = $module.data(metadata.url) || settings.url || false;
  23361. if(url) {
  23362. module.debug('Using specified url', url);
  23363. return url;
  23364. }
  23365. if(action) {
  23366. module.debug('Looking up url for action', action, settings.api);
  23367. if(settings.api[action] === undefined && !module.is.mocked()) {
  23368. module.error(error.missingAction, settings.action, settings.api);
  23369. return;
  23370. }
  23371. url = settings.api[action];
  23372. }
  23373. else if( module.is.form() ) {
  23374. url = $module.attr('action') || $context.attr('action') || false;
  23375. module.debug('No url or action specified, defaulting to form action', url);
  23376. }
  23377. return url;
  23378. }
  23379. },
  23380. abort: function() {
  23381. var
  23382. xhr = module.get.xhr()
  23383. ;
  23384. if( xhr && xhr.state() !== 'resolved') {
  23385. module.debug('Cancelling API request');
  23386. xhr.abort();
  23387. }
  23388. },
  23389. // reset state
  23390. reset: function() {
  23391. module.remove.error();
  23392. module.remove.loading();
  23393. },
  23394. setting: function(name, value) {
  23395. module.debug('Changing setting', name, value);
  23396. if( $.isPlainObject(name) ) {
  23397. $.extend(true, settings, name);
  23398. }
  23399. else if(value !== undefined) {
  23400. if($.isPlainObject(settings[name])) {
  23401. $.extend(true, settings[name], value);
  23402. }
  23403. else {
  23404. settings[name] = value;
  23405. }
  23406. }
  23407. else {
  23408. return settings[name];
  23409. }
  23410. },
  23411. internal: function(name, value) {
  23412. if( $.isPlainObject(name) ) {
  23413. $.extend(true, module, name);
  23414. }
  23415. else if(value !== undefined) {
  23416. module[name] = value;
  23417. }
  23418. else {
  23419. return module[name];
  23420. }
  23421. },
  23422. debug: function() {
  23423. if(!settings.silent && settings.debug) {
  23424. if(settings.performance) {
  23425. module.performance.log(arguments);
  23426. }
  23427. else {
  23428. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  23429. module.debug.apply(console, arguments);
  23430. }
  23431. }
  23432. },
  23433. verbose: function() {
  23434. if(!settings.silent && settings.verbose && settings.debug) {
  23435. if(settings.performance) {
  23436. module.performance.log(arguments);
  23437. }
  23438. else {
  23439. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  23440. module.verbose.apply(console, arguments);
  23441. }
  23442. }
  23443. },
  23444. error: function() {
  23445. if(!settings.silent) {
  23446. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  23447. module.error.apply(console, arguments);
  23448. }
  23449. },
  23450. performance: {
  23451. log: function(message) {
  23452. var
  23453. currentTime,
  23454. executionTime,
  23455. previousTime
  23456. ;
  23457. if(settings.performance) {
  23458. currentTime = new Date().getTime();
  23459. previousTime = time || currentTime;
  23460. executionTime = currentTime - previousTime;
  23461. time = currentTime;
  23462. performance.push({
  23463. 'Name' : message[0],
  23464. 'Arguments' : [].slice.call(message, 1) || '',
  23465. //'Element' : element,
  23466. 'Execution Time' : executionTime
  23467. });
  23468. }
  23469. clearTimeout(module.performance.timer);
  23470. module.performance.timer = setTimeout(module.performance.display, 500);
  23471. },
  23472. display: function() {
  23473. var
  23474. title = settings.name + ':',
  23475. totalTime = 0
  23476. ;
  23477. time = false;
  23478. clearTimeout(module.performance.timer);
  23479. $.each(performance, function(index, data) {
  23480. totalTime += data['Execution Time'];
  23481. });
  23482. title += ' ' + totalTime + 'ms';
  23483. if(moduleSelector) {
  23484. title += ' \'' + moduleSelector + '\'';
  23485. }
  23486. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  23487. console.groupCollapsed(title);
  23488. if(console.table) {
  23489. console.table(performance);
  23490. }
  23491. else {
  23492. $.each(performance, function(index, data) {
  23493. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  23494. });
  23495. }
  23496. console.groupEnd();
  23497. }
  23498. performance = [];
  23499. }
  23500. },
  23501. invoke: function(query, passedArguments, context) {
  23502. var
  23503. object = instance,
  23504. maxDepth,
  23505. found,
  23506. response
  23507. ;
  23508. passedArguments = passedArguments || queryArguments;
  23509. context = element || context;
  23510. if(typeof query == 'string' && object !== undefined) {
  23511. query = query.split(/[\. ]/);
  23512. maxDepth = query.length - 1;
  23513. $.each(query, function(depth, value) {
  23514. var camelCaseValue = (depth != maxDepth)
  23515. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  23516. : query
  23517. ;
  23518. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  23519. object = object[camelCaseValue];
  23520. }
  23521. else if( object[camelCaseValue] !== undefined ) {
  23522. found = object[camelCaseValue];
  23523. return false;
  23524. }
  23525. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  23526. object = object[value];
  23527. }
  23528. else if( object[value] !== undefined ) {
  23529. found = object[value];
  23530. return false;
  23531. }
  23532. else {
  23533. module.error(error.method, query);
  23534. return false;
  23535. }
  23536. });
  23537. }
  23538. if ( $.isFunction( found ) ) {
  23539. response = found.apply(context, passedArguments);
  23540. }
  23541. else if(found !== undefined) {
  23542. response = found;
  23543. }
  23544. if(Array.isArray(returnedValue)) {
  23545. returnedValue.push(response);
  23546. }
  23547. else if(returnedValue !== undefined) {
  23548. returnedValue = [returnedValue, response];
  23549. }
  23550. else if(response !== undefined) {
  23551. returnedValue = response;
  23552. }
  23553. return found;
  23554. }
  23555. };
  23556. if(methodInvoked) {
  23557. if(instance === undefined) {
  23558. module.initialize();
  23559. }
  23560. module.invoke(query);
  23561. }
  23562. else {
  23563. if(instance !== undefined) {
  23564. instance.invoke('destroy');
  23565. }
  23566. module.initialize();
  23567. }
  23568. })
  23569. ;
  23570. return (returnedValue !== undefined)
  23571. ? returnedValue
  23572. : this
  23573. ;
  23574. };
  23575. $.api.settings = {
  23576. name : 'API',
  23577. namespace : 'api',
  23578. debug : false,
  23579. verbose : false,
  23580. performance : true,
  23581. // object containing all templates endpoints
  23582. api : {},
  23583. // whether to cache responses
  23584. cache : true,
  23585. // whether new requests should abort previous requests
  23586. interruptRequests : true,
  23587. // event binding
  23588. on : 'auto',
  23589. // context for applying state classes
  23590. stateContext : false,
  23591. // duration for loading state
  23592. loadingDuration : 0,
  23593. // whether to hide errors after a period of time
  23594. hideError : 'auto',
  23595. // duration for error state
  23596. errorDuration : 2000,
  23597. // whether parameters should be encoded with encodeURIComponent
  23598. encodeParameters : true,
  23599. // API action to use
  23600. action : false,
  23601. // templated URL to use
  23602. url : false,
  23603. // base URL to apply to all endpoints
  23604. base : '',
  23605. // data that will
  23606. urlData : {},
  23607. // whether to add default data to url data
  23608. defaultData : true,
  23609. // whether to serialize closest form
  23610. serializeForm : false,
  23611. // how long to wait before request should occur
  23612. throttle : 0,
  23613. // whether to throttle first request or only repeated
  23614. throttleFirstRequest : true,
  23615. // standard ajax settings
  23616. method : 'get',
  23617. data : {},
  23618. dataType : 'json',
  23619. // mock response
  23620. mockResponse : false,
  23621. mockResponseAsync : false,
  23622. // aliases for mock
  23623. response : false,
  23624. responseAsync : false,
  23625. // whether onResponse should work with response value without force converting into an object
  23626. rawResponse : false,
  23627. // callbacks before request
  23628. beforeSend : function(settings) { return settings; },
  23629. beforeXHR : function(xhr) {},
  23630. onRequest : function(promise, xhr) {},
  23631. // after request
  23632. onResponse : false, // function(response) { },
  23633. // response was successful, if JSON passed validation
  23634. onSuccess : function(response, $module) {},
  23635. // request finished without aborting
  23636. onComplete : function(response, $module) {},
  23637. // failed JSON success test
  23638. onFailure : function(response, $module) {},
  23639. // server error
  23640. onError : function(errorMessage, $module) {},
  23641. // request aborted
  23642. onAbort : function(errorMessage, $module) {},
  23643. successTest : false,
  23644. // errors
  23645. error : {
  23646. beforeSend : 'The before send function has aborted the request',
  23647. error : 'There was an error with your request',
  23648. exitConditions : 'API Request Aborted. Exit conditions met',
  23649. JSONParse : 'JSON could not be parsed during error handling',
  23650. legacyParameters : 'You are using legacy API success callback names',
  23651. method : 'The method you called is not defined',
  23652. missingAction : 'API action used but no url was defined',
  23653. missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object',
  23654. missingURL : 'No URL specified for api event',
  23655. noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.',
  23656. noStorage : 'Caching responses locally requires session storage',
  23657. parseError : 'There was an error parsing your request',
  23658. requiredParameter : 'Missing a required URL parameter: ',
  23659. statusMessage : 'Server gave an error: ',
  23660. timeout : 'Your request timed out'
  23661. },
  23662. regExp : {
  23663. required : /\{\$*[A-z0-9]+\}/g,
  23664. optional : /\{\/\$*[A-z0-9]+\}/g,
  23665. },
  23666. className: {
  23667. loading : 'loading',
  23668. error : 'error'
  23669. },
  23670. selector: {
  23671. disabled : '.disabled',
  23672. form : 'form'
  23673. },
  23674. metadata: {
  23675. action : 'action',
  23676. url : 'url'
  23677. }
  23678. };
  23679. })( jQuery, window, document );
  23680. /*!
  23681. * # Fomantic-UI - State
  23682. * http://github.com/fomantic/Fomantic-UI/
  23683. *
  23684. *
  23685. * Released under the MIT license
  23686. * http://opensource.org/licenses/MIT
  23687. *
  23688. */
  23689. ;(function ($, window, document, undefined) {
  23690. "use strict";
  23691. $.isFunction = $.isFunction || function(obj) {
  23692. return typeof obj === "function" && typeof obj.nodeType !== "number";
  23693. };
  23694. window = (typeof window != 'undefined' && window.Math == Math)
  23695. ? window
  23696. : (typeof self != 'undefined' && self.Math == Math)
  23697. ? self
  23698. : Function('return this')()
  23699. ;
  23700. $.fn.state = function(parameters) {
  23701. var
  23702. $allModules = $(this),
  23703. moduleSelector = $allModules.selector || '',
  23704. time = new Date().getTime(),
  23705. performance = [],
  23706. query = arguments[0],
  23707. methodInvoked = (typeof query == 'string'),
  23708. queryArguments = [].slice.call(arguments, 1),
  23709. returnedValue
  23710. ;
  23711. $allModules
  23712. .each(function() {
  23713. var
  23714. settings = ( $.isPlainObject(parameters) )
  23715. ? $.extend(true, {}, $.fn.state.settings, parameters)
  23716. : $.extend({}, $.fn.state.settings),
  23717. error = settings.error,
  23718. metadata = settings.metadata,
  23719. className = settings.className,
  23720. namespace = settings.namespace,
  23721. states = settings.states,
  23722. text = settings.text,
  23723. eventNamespace = '.' + namespace,
  23724. moduleNamespace = namespace + '-module',
  23725. $module = $(this),
  23726. element = this,
  23727. instance = $module.data(moduleNamespace),
  23728. module
  23729. ;
  23730. module = {
  23731. initialize: function() {
  23732. module.verbose('Initializing module');
  23733. // allow module to guess desired state based on element
  23734. if(settings.automatic) {
  23735. module.add.defaults();
  23736. }
  23737. // bind events with delegated events
  23738. if(settings.context && moduleSelector !== '') {
  23739. $(settings.context)
  23740. .on(moduleSelector, 'mouseenter' + eventNamespace, module.change.text)
  23741. .on(moduleSelector, 'mouseleave' + eventNamespace, module.reset.text)
  23742. .on(moduleSelector, 'click' + eventNamespace, module.toggle.state)
  23743. ;
  23744. }
  23745. else {
  23746. $module
  23747. .on('mouseenter' + eventNamespace, module.change.text)
  23748. .on('mouseleave' + eventNamespace, module.reset.text)
  23749. .on('click' + eventNamespace, module.toggle.state)
  23750. ;
  23751. }
  23752. module.instantiate();
  23753. },
  23754. instantiate: function() {
  23755. module.verbose('Storing instance of module', module);
  23756. instance = module;
  23757. $module
  23758. .data(moduleNamespace, module)
  23759. ;
  23760. },
  23761. destroy: function() {
  23762. module.verbose('Destroying previous module', instance);
  23763. $module
  23764. .off(eventNamespace)
  23765. .removeData(moduleNamespace)
  23766. ;
  23767. },
  23768. refresh: function() {
  23769. module.verbose('Refreshing selector cache');
  23770. $module = $(element);
  23771. },
  23772. add: {
  23773. defaults: function() {
  23774. var
  23775. userStates = parameters && $.isPlainObject(parameters.states)
  23776. ? parameters.states
  23777. : {}
  23778. ;
  23779. $.each(settings.defaults, function(type, typeStates) {
  23780. if( module.is[type] !== undefined && module.is[type]() ) {
  23781. module.verbose('Adding default states', type, element);
  23782. $.extend(settings.states, typeStates, userStates);
  23783. }
  23784. });
  23785. }
  23786. },
  23787. is: {
  23788. active: function() {
  23789. return $module.hasClass(className.active);
  23790. },
  23791. loading: function() {
  23792. return $module.hasClass(className.loading);
  23793. },
  23794. inactive: function() {
  23795. return !( $module.hasClass(className.active) );
  23796. },
  23797. state: function(state) {
  23798. if(className[state] === undefined) {
  23799. return false;
  23800. }
  23801. return $module.hasClass( className[state] );
  23802. },
  23803. enabled: function() {
  23804. return !( $module.is(settings.filter.active) );
  23805. },
  23806. disabled: function() {
  23807. return ( $module.is(settings.filter.active) );
  23808. },
  23809. textEnabled: function() {
  23810. return !( $module.is(settings.filter.text) );
  23811. },
  23812. // definitions for automatic type detection
  23813. button: function() {
  23814. return $module.is('.button:not(a, .submit)');
  23815. },
  23816. input: function() {
  23817. return $module.is('input');
  23818. },
  23819. progress: function() {
  23820. return $module.is('.ui.progress');
  23821. }
  23822. },
  23823. allow: function(state) {
  23824. module.debug('Now allowing state', state);
  23825. states[state] = true;
  23826. },
  23827. disallow: function(state) {
  23828. module.debug('No longer allowing', state);
  23829. states[state] = false;
  23830. },
  23831. allows: function(state) {
  23832. return states[state] || false;
  23833. },
  23834. enable: function() {
  23835. $module.removeClass(className.disabled);
  23836. },
  23837. disable: function() {
  23838. $module.addClass(className.disabled);
  23839. },
  23840. setState: function(state) {
  23841. if(module.allows(state)) {
  23842. $module.addClass( className[state] );
  23843. }
  23844. },
  23845. removeState: function(state) {
  23846. if(module.allows(state)) {
  23847. $module.removeClass( className[state] );
  23848. }
  23849. },
  23850. toggle: {
  23851. state: function() {
  23852. var
  23853. apiRequest,
  23854. requestCancelled
  23855. ;
  23856. if( module.allows('active') && module.is.enabled() ) {
  23857. module.refresh();
  23858. if($.fn.api !== undefined) {
  23859. apiRequest = $module.api('get request');
  23860. requestCancelled = $module.api('was cancelled');
  23861. if( requestCancelled ) {
  23862. module.debug('API Request cancelled by beforesend');
  23863. settings.activateTest = function(){ return false; };
  23864. settings.deactivateTest = function(){ return false; };
  23865. }
  23866. else if(apiRequest) {
  23867. module.listenTo(apiRequest);
  23868. return;
  23869. }
  23870. }
  23871. module.change.state();
  23872. }
  23873. }
  23874. },
  23875. listenTo: function(apiRequest) {
  23876. module.debug('API request detected, waiting for state signal', apiRequest);
  23877. if(apiRequest) {
  23878. if(text.loading) {
  23879. module.update.text(text.loading);
  23880. }
  23881. $.when(apiRequest)
  23882. .then(function() {
  23883. if(apiRequest.state() == 'resolved') {
  23884. module.debug('API request succeeded');
  23885. settings.activateTest = function(){ return true; };
  23886. settings.deactivateTest = function(){ return true; };
  23887. }
  23888. else {
  23889. module.debug('API request failed');
  23890. settings.activateTest = function(){ return false; };
  23891. settings.deactivateTest = function(){ return false; };
  23892. }
  23893. module.change.state();
  23894. })
  23895. ;
  23896. }
  23897. },
  23898. // checks whether active/inactive state can be given
  23899. change: {
  23900. state: function() {
  23901. module.debug('Determining state change direction');
  23902. // inactive to active change
  23903. if( module.is.inactive() ) {
  23904. module.activate();
  23905. }
  23906. else {
  23907. module.deactivate();
  23908. }
  23909. if(settings.sync) {
  23910. module.sync();
  23911. }
  23912. settings.onChange.call(element);
  23913. },
  23914. text: function() {
  23915. if( module.is.textEnabled() ) {
  23916. if(module.is.disabled() ) {
  23917. module.verbose('Changing text to disabled text', text.hover);
  23918. module.update.text(text.disabled);
  23919. }
  23920. else if( module.is.active() ) {
  23921. if(text.hover) {
  23922. module.verbose('Changing text to hover text', text.hover);
  23923. module.update.text(text.hover);
  23924. }
  23925. else if(text.deactivate) {
  23926. module.verbose('Changing text to deactivating text', text.deactivate);
  23927. module.update.text(text.deactivate);
  23928. }
  23929. }
  23930. else {
  23931. if(text.hover) {
  23932. module.verbose('Changing text to hover text', text.hover);
  23933. module.update.text(text.hover);
  23934. }
  23935. else if(text.activate){
  23936. module.verbose('Changing text to activating text', text.activate);
  23937. module.update.text(text.activate);
  23938. }
  23939. }
  23940. }
  23941. }
  23942. },
  23943. activate: function() {
  23944. if( settings.activateTest.call(element) ) {
  23945. module.debug('Setting state to active');
  23946. $module
  23947. .addClass(className.active)
  23948. ;
  23949. module.update.text(text.active);
  23950. settings.onActivate.call(element);
  23951. }
  23952. },
  23953. deactivate: function() {
  23954. if( settings.deactivateTest.call(element) ) {
  23955. module.debug('Setting state to inactive');
  23956. $module
  23957. .removeClass(className.active)
  23958. ;
  23959. module.update.text(text.inactive);
  23960. settings.onDeactivate.call(element);
  23961. }
  23962. },
  23963. sync: function() {
  23964. module.verbose('Syncing other buttons to current state');
  23965. if( module.is.active() ) {
  23966. $allModules
  23967. .not($module)
  23968. .state('activate');
  23969. }
  23970. else {
  23971. $allModules
  23972. .not($module)
  23973. .state('deactivate')
  23974. ;
  23975. }
  23976. },
  23977. get: {
  23978. text: function() {
  23979. return (settings.selector.text)
  23980. ? $module.find(settings.selector.text).text()
  23981. : $module.html()
  23982. ;
  23983. },
  23984. textFor: function(state) {
  23985. return text[state] || false;
  23986. }
  23987. },
  23988. flash: {
  23989. text: function(text, duration, callback) {
  23990. var
  23991. previousText = module.get.text()
  23992. ;
  23993. module.debug('Flashing text message', text, duration);
  23994. text = text || settings.text.flash;
  23995. duration = duration || settings.flashDuration;
  23996. callback = callback || function() {};
  23997. module.update.text(text);
  23998. setTimeout(function(){
  23999. module.update.text(previousText);
  24000. callback.call(element);
  24001. }, duration);
  24002. }
  24003. },
  24004. reset: {
  24005. // on mouseout sets text to previous value
  24006. text: function() {
  24007. var
  24008. activeText = text.active || $module.data(metadata.storedText),
  24009. inactiveText = text.inactive || $module.data(metadata.storedText)
  24010. ;
  24011. if( module.is.textEnabled() ) {
  24012. if( module.is.active() && activeText) {
  24013. module.verbose('Resetting active text', activeText);
  24014. module.update.text(activeText);
  24015. }
  24016. else if(inactiveText) {
  24017. module.verbose('Resetting inactive text', activeText);
  24018. module.update.text(inactiveText);
  24019. }
  24020. }
  24021. }
  24022. },
  24023. update: {
  24024. text: function(text) {
  24025. var
  24026. currentText = module.get.text()
  24027. ;
  24028. if(text && text !== currentText) {
  24029. module.debug('Updating text', text);
  24030. if(settings.selector.text) {
  24031. $module
  24032. .data(metadata.storedText, text)
  24033. .find(settings.selector.text)
  24034. .text(text)
  24035. ;
  24036. }
  24037. else {
  24038. $module
  24039. .data(metadata.storedText, text)
  24040. .html(text)
  24041. ;
  24042. }
  24043. }
  24044. else {
  24045. module.debug('Text is already set, ignoring update', text);
  24046. }
  24047. }
  24048. },
  24049. setting: function(name, value) {
  24050. module.debug('Changing setting', name, value);
  24051. if( $.isPlainObject(name) ) {
  24052. $.extend(true, settings, name);
  24053. }
  24054. else if(value !== undefined) {
  24055. if($.isPlainObject(settings[name])) {
  24056. $.extend(true, settings[name], value);
  24057. }
  24058. else {
  24059. settings[name] = value;
  24060. }
  24061. }
  24062. else {
  24063. return settings[name];
  24064. }
  24065. },
  24066. internal: function(name, value) {
  24067. if( $.isPlainObject(name) ) {
  24068. $.extend(true, module, name);
  24069. }
  24070. else if(value !== undefined) {
  24071. module[name] = value;
  24072. }
  24073. else {
  24074. return module[name];
  24075. }
  24076. },
  24077. debug: function() {
  24078. if(!settings.silent && settings.debug) {
  24079. if(settings.performance) {
  24080. module.performance.log(arguments);
  24081. }
  24082. else {
  24083. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  24084. module.debug.apply(console, arguments);
  24085. }
  24086. }
  24087. },
  24088. verbose: function() {
  24089. if(!settings.silent && settings.verbose && settings.debug) {
  24090. if(settings.performance) {
  24091. module.performance.log(arguments);
  24092. }
  24093. else {
  24094. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  24095. module.verbose.apply(console, arguments);
  24096. }
  24097. }
  24098. },
  24099. error: function() {
  24100. if(!settings.silent) {
  24101. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  24102. module.error.apply(console, arguments);
  24103. }
  24104. },
  24105. performance: {
  24106. log: function(message) {
  24107. var
  24108. currentTime,
  24109. executionTime,
  24110. previousTime
  24111. ;
  24112. if(settings.performance) {
  24113. currentTime = new Date().getTime();
  24114. previousTime = time || currentTime;
  24115. executionTime = currentTime - previousTime;
  24116. time = currentTime;
  24117. performance.push({
  24118. 'Name' : message[0],
  24119. 'Arguments' : [].slice.call(message, 1) || '',
  24120. 'Element' : element,
  24121. 'Execution Time' : executionTime
  24122. });
  24123. }
  24124. clearTimeout(module.performance.timer);
  24125. module.performance.timer = setTimeout(module.performance.display, 500);
  24126. },
  24127. display: function() {
  24128. var
  24129. title = settings.name + ':',
  24130. totalTime = 0
  24131. ;
  24132. time = false;
  24133. clearTimeout(module.performance.timer);
  24134. $.each(performance, function(index, data) {
  24135. totalTime += data['Execution Time'];
  24136. });
  24137. title += ' ' + totalTime + 'ms';
  24138. if(moduleSelector) {
  24139. title += ' \'' + moduleSelector + '\'';
  24140. }
  24141. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  24142. console.groupCollapsed(title);
  24143. if(console.table) {
  24144. console.table(performance);
  24145. }
  24146. else {
  24147. $.each(performance, function(index, data) {
  24148. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  24149. });
  24150. }
  24151. console.groupEnd();
  24152. }
  24153. performance = [];
  24154. }
  24155. },
  24156. invoke: function(query, passedArguments, context) {
  24157. var
  24158. object = instance,
  24159. maxDepth,
  24160. found,
  24161. response
  24162. ;
  24163. passedArguments = passedArguments || queryArguments;
  24164. context = element || context;
  24165. if(typeof query == 'string' && object !== undefined) {
  24166. query = query.split(/[\. ]/);
  24167. maxDepth = query.length - 1;
  24168. $.each(query, function(depth, value) {
  24169. var camelCaseValue = (depth != maxDepth)
  24170. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  24171. : query
  24172. ;
  24173. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  24174. object = object[camelCaseValue];
  24175. }
  24176. else if( object[camelCaseValue] !== undefined ) {
  24177. found = object[camelCaseValue];
  24178. return false;
  24179. }
  24180. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  24181. object = object[value];
  24182. }
  24183. else if( object[value] !== undefined ) {
  24184. found = object[value];
  24185. return false;
  24186. }
  24187. else {
  24188. module.error(error.method, query);
  24189. return false;
  24190. }
  24191. });
  24192. }
  24193. if ( $.isFunction( found ) ) {
  24194. response = found.apply(context, passedArguments);
  24195. }
  24196. else if(found !== undefined) {
  24197. response = found;
  24198. }
  24199. if(Array.isArray(returnedValue)) {
  24200. returnedValue.push(response);
  24201. }
  24202. else if(returnedValue !== undefined) {
  24203. returnedValue = [returnedValue, response];
  24204. }
  24205. else if(response !== undefined) {
  24206. returnedValue = response;
  24207. }
  24208. return found;
  24209. }
  24210. };
  24211. if(methodInvoked) {
  24212. if(instance === undefined) {
  24213. module.initialize();
  24214. }
  24215. module.invoke(query);
  24216. }
  24217. else {
  24218. if(instance !== undefined) {
  24219. instance.invoke('destroy');
  24220. }
  24221. module.initialize();
  24222. }
  24223. })
  24224. ;
  24225. return (returnedValue !== undefined)
  24226. ? returnedValue
  24227. : this
  24228. ;
  24229. };
  24230. $.fn.state.settings = {
  24231. // module info
  24232. name : 'State',
  24233. // debug output
  24234. debug : false,
  24235. // verbose debug output
  24236. verbose : false,
  24237. // namespace for events
  24238. namespace : 'state',
  24239. // debug data includes performance
  24240. performance : true,
  24241. // callback occurs on state change
  24242. onActivate : function() {},
  24243. onDeactivate : function() {},
  24244. onChange : function() {},
  24245. // state test functions
  24246. activateTest : function() { return true; },
  24247. deactivateTest : function() { return true; },
  24248. // whether to automatically map default states
  24249. automatic : true,
  24250. // activate / deactivate changes all elements instantiated at same time
  24251. sync : false,
  24252. // default flash text duration, used for temporarily changing text of an element
  24253. flashDuration : 1000,
  24254. // selector filter
  24255. filter : {
  24256. text : '.loading, .disabled',
  24257. active : '.disabled'
  24258. },
  24259. context : false,
  24260. // error
  24261. error: {
  24262. beforeSend : 'The before send function has cancelled state change',
  24263. method : 'The method you called is not defined.'
  24264. },
  24265. // metadata
  24266. metadata: {
  24267. promise : 'promise',
  24268. storedText : 'stored-text'
  24269. },
  24270. // change class on state
  24271. className: {
  24272. active : 'active',
  24273. disabled : 'disabled',
  24274. error : 'error',
  24275. loading : 'loading',
  24276. success : 'success',
  24277. warning : 'warning'
  24278. },
  24279. selector: {
  24280. // selector for text node
  24281. text: false
  24282. },
  24283. defaults : {
  24284. input: {
  24285. disabled : true,
  24286. loading : true,
  24287. active : true
  24288. },
  24289. button: {
  24290. disabled : true,
  24291. loading : true,
  24292. active : true,
  24293. },
  24294. progress: {
  24295. active : true,
  24296. success : true,
  24297. warning : true,
  24298. error : true
  24299. }
  24300. },
  24301. states : {
  24302. active : true,
  24303. disabled : true,
  24304. error : true,
  24305. loading : true,
  24306. success : true,
  24307. warning : true
  24308. },
  24309. text : {
  24310. disabled : false,
  24311. flash : false,
  24312. hover : false,
  24313. active : false,
  24314. inactive : false,
  24315. activate : false,
  24316. deactivate : false
  24317. }
  24318. };
  24319. })( jQuery, window, document );
  24320. /*!
  24321. * # Fomantic-UI - Visibility
  24322. * http://github.com/fomantic/Fomantic-UI/
  24323. *
  24324. *
  24325. * Released under the MIT license
  24326. * http://opensource.org/licenses/MIT
  24327. *
  24328. */
  24329. ;(function ($, window, document, undefined) {
  24330. 'use strict';
  24331. $.isFunction = $.isFunction || function(obj) {
  24332. return typeof obj === "function" && typeof obj.nodeType !== "number";
  24333. };
  24334. window = (typeof window != 'undefined' && window.Math == Math)
  24335. ? window
  24336. : (typeof self != 'undefined' && self.Math == Math)
  24337. ? self
  24338. : Function('return this')()
  24339. ;
  24340. $.fn.visibility = function(parameters) {
  24341. var
  24342. $allModules = $(this),
  24343. moduleSelector = $allModules.selector || '',
  24344. time = new Date().getTime(),
  24345. performance = [],
  24346. query = arguments[0],
  24347. methodInvoked = (typeof query == 'string'),
  24348. queryArguments = [].slice.call(arguments, 1),
  24349. returnedValue,
  24350. moduleCount = $allModules.length,
  24351. loadedCount = 0
  24352. ;
  24353. $allModules
  24354. .each(function() {
  24355. var
  24356. settings = ( $.isPlainObject(parameters) )
  24357. ? $.extend(true, {}, $.fn.visibility.settings, parameters)
  24358. : $.extend({}, $.fn.visibility.settings),
  24359. className = settings.className,
  24360. namespace = settings.namespace,
  24361. error = settings.error,
  24362. metadata = settings.metadata,
  24363. eventNamespace = '.' + namespace,
  24364. moduleNamespace = 'module-' + namespace,
  24365. $window = $(window),
  24366. $module = $(this),
  24367. $context = $(settings.context),
  24368. $placeholder,
  24369. instance = $module.data(moduleNamespace),
  24370. requestAnimationFrame = window.requestAnimationFrame
  24371. || window.mozRequestAnimationFrame
  24372. || window.webkitRequestAnimationFrame
  24373. || window.msRequestAnimationFrame
  24374. || function(callback) { setTimeout(callback, 0); },
  24375. element = this,
  24376. disabled = false,
  24377. contextObserver,
  24378. observer,
  24379. module
  24380. ;
  24381. module = {
  24382. initialize: function() {
  24383. module.debug('Initializing', settings);
  24384. module.setup.cache();
  24385. if( module.should.trackChanges() ) {
  24386. if(settings.type == 'image') {
  24387. module.setup.image();
  24388. }
  24389. if(settings.type == 'fixed') {
  24390. module.setup.fixed();
  24391. }
  24392. if(settings.observeChanges) {
  24393. module.observeChanges();
  24394. }
  24395. module.bind.events();
  24396. }
  24397. module.save.position();
  24398. if( !module.is.visible() ) {
  24399. module.error(error.visible, $module);
  24400. }
  24401. if(settings.initialCheck) {
  24402. module.checkVisibility();
  24403. }
  24404. module.instantiate();
  24405. },
  24406. instantiate: function() {
  24407. module.debug('Storing instance', module);
  24408. $module
  24409. .data(moduleNamespace, module)
  24410. ;
  24411. instance = module;
  24412. },
  24413. destroy: function() {
  24414. module.verbose('Destroying previous module');
  24415. if(observer) {
  24416. observer.disconnect();
  24417. }
  24418. if(contextObserver) {
  24419. contextObserver.disconnect();
  24420. }
  24421. $window
  24422. .off('load' + eventNamespace, module.event.load)
  24423. .off('resize' + eventNamespace, module.event.resize)
  24424. ;
  24425. $context
  24426. .off('scroll' + eventNamespace, module.event.scroll)
  24427. .off('scrollchange' + eventNamespace, module.event.scrollchange)
  24428. ;
  24429. if(settings.type == 'fixed') {
  24430. module.resetFixed();
  24431. module.remove.placeholder();
  24432. }
  24433. $module
  24434. .off(eventNamespace)
  24435. .removeData(moduleNamespace)
  24436. ;
  24437. },
  24438. observeChanges: function() {
  24439. if('MutationObserver' in window) {
  24440. contextObserver = new MutationObserver(module.event.contextChanged);
  24441. observer = new MutationObserver(module.event.changed);
  24442. contextObserver.observe(document, {
  24443. childList : true,
  24444. subtree : true
  24445. });
  24446. observer.observe(element, {
  24447. childList : true,
  24448. subtree : true
  24449. });
  24450. module.debug('Setting up mutation observer', observer);
  24451. }
  24452. },
  24453. bind: {
  24454. events: function() {
  24455. module.verbose('Binding visibility events to scroll and resize');
  24456. if(settings.refreshOnLoad) {
  24457. $window
  24458. .on('load' + eventNamespace, module.event.load)
  24459. ;
  24460. }
  24461. $window
  24462. .on('resize' + eventNamespace, module.event.resize)
  24463. ;
  24464. // pub/sub pattern
  24465. $context
  24466. .off('scroll' + eventNamespace)
  24467. .on('scroll' + eventNamespace, module.event.scroll)
  24468. .on('scrollchange' + eventNamespace, module.event.scrollchange)
  24469. ;
  24470. }
  24471. },
  24472. event: {
  24473. changed: function(mutations) {
  24474. module.verbose('DOM tree modified, updating visibility calculations');
  24475. module.timer = setTimeout(function() {
  24476. module.verbose('DOM tree modified, updating sticky menu');
  24477. module.refresh();
  24478. }, 100);
  24479. },
  24480. contextChanged: function(mutations) {
  24481. [].forEach.call(mutations, function(mutation) {
  24482. if(mutation.removedNodes) {
  24483. [].forEach.call(mutation.removedNodes, function(node) {
  24484. if(node == element || $(node).find(element).length > 0) {
  24485. module.debug('Element removed from DOM, tearing down events');
  24486. module.destroy();
  24487. }
  24488. });
  24489. }
  24490. });
  24491. },
  24492. resize: function() {
  24493. module.debug('Window resized');
  24494. if(settings.refreshOnResize) {
  24495. requestAnimationFrame(module.refresh);
  24496. }
  24497. },
  24498. load: function() {
  24499. module.debug('Page finished loading');
  24500. requestAnimationFrame(module.refresh);
  24501. },
  24502. // publishes scrollchange event on one scroll
  24503. scroll: function() {
  24504. if(settings.throttle) {
  24505. clearTimeout(module.timer);
  24506. module.timer = setTimeout(function() {
  24507. $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]);
  24508. }, settings.throttle);
  24509. }
  24510. else {
  24511. requestAnimationFrame(function() {
  24512. $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]);
  24513. });
  24514. }
  24515. },
  24516. // subscribes to scrollchange
  24517. scrollchange: function(event, scrollPosition) {
  24518. module.checkVisibility(scrollPosition);
  24519. },
  24520. },
  24521. precache: function(images, callback) {
  24522. if (!(images instanceof Array)) {
  24523. images = [images];
  24524. }
  24525. var
  24526. imagesLength = images.length,
  24527. loadedCounter = 0,
  24528. cache = [],
  24529. cacheImage = document.createElement('img'),
  24530. handleLoad = function() {
  24531. loadedCounter++;
  24532. if (loadedCounter >= images.length) {
  24533. if ($.isFunction(callback)) {
  24534. callback();
  24535. }
  24536. }
  24537. }
  24538. ;
  24539. while (imagesLength--) {
  24540. cacheImage = document.createElement('img');
  24541. cacheImage.onload = handleLoad;
  24542. cacheImage.onerror = handleLoad;
  24543. cacheImage.src = images[imagesLength];
  24544. cache.push(cacheImage);
  24545. }
  24546. },
  24547. enableCallbacks: function() {
  24548. module.debug('Allowing callbacks to occur');
  24549. disabled = false;
  24550. },
  24551. disableCallbacks: function() {
  24552. module.debug('Disabling all callbacks temporarily');
  24553. disabled = true;
  24554. },
  24555. should: {
  24556. trackChanges: function() {
  24557. if(methodInvoked) {
  24558. module.debug('One time query, no need to bind events');
  24559. return false;
  24560. }
  24561. module.debug('Callbacks being attached');
  24562. return true;
  24563. }
  24564. },
  24565. setup: {
  24566. cache: function() {
  24567. module.cache = {
  24568. occurred : {},
  24569. screen : {},
  24570. element : {},
  24571. };
  24572. },
  24573. image: function() {
  24574. var
  24575. src = $module.data(metadata.src)
  24576. ;
  24577. if(src) {
  24578. module.verbose('Lazy loading image', src);
  24579. settings.once = true;
  24580. settings.observeChanges = false;
  24581. // show when top visible
  24582. settings.onOnScreen = function() {
  24583. module.debug('Image on screen', element);
  24584. module.precache(src, function() {
  24585. module.set.image(src, function() {
  24586. loadedCount++;
  24587. if(loadedCount == moduleCount) {
  24588. settings.onAllLoaded.call(this);
  24589. }
  24590. settings.onLoad.call(this);
  24591. });
  24592. });
  24593. };
  24594. }
  24595. },
  24596. fixed: function() {
  24597. module.debug('Setting up fixed');
  24598. settings.once = false;
  24599. settings.observeChanges = false;
  24600. settings.initialCheck = true;
  24601. settings.refreshOnLoad = true;
  24602. if(!parameters.transition) {
  24603. settings.transition = false;
  24604. }
  24605. module.create.placeholder();
  24606. module.debug('Added placeholder', $placeholder);
  24607. settings.onTopPassed = function() {
  24608. module.debug('Element passed, adding fixed position', $module);
  24609. module.show.placeholder();
  24610. module.set.fixed();
  24611. if(settings.transition) {
  24612. if($.fn.transition !== undefined) {
  24613. $module.transition(settings.transition, settings.duration);
  24614. }
  24615. }
  24616. };
  24617. settings.onTopPassedReverse = function() {
  24618. module.debug('Element returned to position, removing fixed', $module);
  24619. module.hide.placeholder();
  24620. module.remove.fixed();
  24621. };
  24622. }
  24623. },
  24624. create: {
  24625. placeholder: function() {
  24626. module.verbose('Creating fixed position placeholder');
  24627. $placeholder = $module
  24628. .clone(false)
  24629. .css('display', 'none')
  24630. .addClass(className.placeholder)
  24631. .insertAfter($module)
  24632. ;
  24633. }
  24634. },
  24635. show: {
  24636. placeholder: function() {
  24637. module.verbose('Showing placeholder');
  24638. $placeholder
  24639. .css('display', 'block')
  24640. .css('visibility', 'hidden')
  24641. ;
  24642. }
  24643. },
  24644. hide: {
  24645. placeholder: function() {
  24646. module.verbose('Hiding placeholder');
  24647. $placeholder
  24648. .css('display', 'none')
  24649. .css('visibility', '')
  24650. ;
  24651. }
  24652. },
  24653. set: {
  24654. fixed: function() {
  24655. module.verbose('Setting element to fixed position');
  24656. $module
  24657. .addClass(className.fixed)
  24658. .css({
  24659. position : 'fixed',
  24660. top : settings.offset + 'px',
  24661. left : 'auto',
  24662. zIndex : settings.zIndex
  24663. })
  24664. ;
  24665. settings.onFixed.call(element);
  24666. },
  24667. image: function(src, callback) {
  24668. $module
  24669. .attr('src', src)
  24670. ;
  24671. if(settings.transition) {
  24672. if( $.fn.transition !== undefined) {
  24673. if($module.hasClass(className.visible)) {
  24674. module.debug('Transition already occurred on this image, skipping animation');
  24675. return;
  24676. }
  24677. $module.transition(settings.transition, settings.duration, callback);
  24678. }
  24679. else {
  24680. $module.fadeIn(settings.duration, callback);
  24681. }
  24682. }
  24683. else {
  24684. $module.show();
  24685. }
  24686. }
  24687. },
  24688. is: {
  24689. onScreen: function() {
  24690. var
  24691. calculations = module.get.elementCalculations()
  24692. ;
  24693. return calculations.onScreen;
  24694. },
  24695. offScreen: function() {
  24696. var
  24697. calculations = module.get.elementCalculations()
  24698. ;
  24699. return calculations.offScreen;
  24700. },
  24701. visible: function() {
  24702. if(module.cache && module.cache.element) {
  24703. return !(module.cache.element.width === 0 && module.cache.element.offset.top === 0);
  24704. }
  24705. return false;
  24706. },
  24707. verticallyScrollableContext: function() {
  24708. var
  24709. overflowY = ($context.get(0) !== window)
  24710. ? $context.css('overflow-y')
  24711. : false
  24712. ;
  24713. return (overflowY == 'auto' || overflowY == 'scroll');
  24714. },
  24715. horizontallyScrollableContext: function() {
  24716. var
  24717. overflowX = ($context.get(0) !== window)
  24718. ? $context.css('overflow-x')
  24719. : false
  24720. ;
  24721. return (overflowX == 'auto' || overflowX == 'scroll');
  24722. }
  24723. },
  24724. refresh: function() {
  24725. module.debug('Refreshing constants (width/height)');
  24726. if(settings.type == 'fixed') {
  24727. module.resetFixed();
  24728. }
  24729. module.reset();
  24730. module.save.position();
  24731. if(settings.checkOnRefresh) {
  24732. module.checkVisibility();
  24733. }
  24734. settings.onRefresh.call(element);
  24735. },
  24736. resetFixed: function () {
  24737. module.remove.fixed();
  24738. module.remove.occurred();
  24739. },
  24740. reset: function() {
  24741. module.verbose('Resetting all cached values');
  24742. if( $.isPlainObject(module.cache) ) {
  24743. module.cache.screen = {};
  24744. module.cache.element = {};
  24745. }
  24746. },
  24747. checkVisibility: function(scroll) {
  24748. module.verbose('Checking visibility of element', module.cache.element);
  24749. if( !disabled && module.is.visible() ) {
  24750. // save scroll position
  24751. module.save.scroll(scroll);
  24752. // update calculations derived from scroll
  24753. module.save.calculations();
  24754. // percentage
  24755. module.passed();
  24756. // reverse (must be first)
  24757. module.passingReverse();
  24758. module.topVisibleReverse();
  24759. module.bottomVisibleReverse();
  24760. module.topPassedReverse();
  24761. module.bottomPassedReverse();
  24762. // one time
  24763. module.onScreen();
  24764. module.offScreen();
  24765. module.passing();
  24766. module.topVisible();
  24767. module.bottomVisible();
  24768. module.topPassed();
  24769. module.bottomPassed();
  24770. // on update callback
  24771. if(settings.onUpdate) {
  24772. settings.onUpdate.call(element, module.get.elementCalculations());
  24773. }
  24774. }
  24775. },
  24776. passed: function(amount, newCallback) {
  24777. var
  24778. calculations = module.get.elementCalculations()
  24779. ;
  24780. // assign callback
  24781. if(amount && newCallback) {
  24782. settings.onPassed[amount] = newCallback;
  24783. }
  24784. else if(amount !== undefined) {
  24785. return (module.get.pixelsPassed(amount) > calculations.pixelsPassed);
  24786. }
  24787. else if(calculations.passing) {
  24788. $.each(settings.onPassed, function(amount, callback) {
  24789. if(calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) {
  24790. module.execute(callback, amount);
  24791. }
  24792. else if(!settings.once) {
  24793. module.remove.occurred(callback);
  24794. }
  24795. });
  24796. }
  24797. },
  24798. onScreen: function(newCallback) {
  24799. var
  24800. calculations = module.get.elementCalculations(),
  24801. callback = newCallback || settings.onOnScreen,
  24802. callbackName = 'onScreen'
  24803. ;
  24804. if(newCallback) {
  24805. module.debug('Adding callback for onScreen', newCallback);
  24806. settings.onOnScreen = newCallback;
  24807. }
  24808. if(calculations.onScreen) {
  24809. module.execute(callback, callbackName);
  24810. }
  24811. else if(!settings.once) {
  24812. module.remove.occurred(callbackName);
  24813. }
  24814. if(newCallback !== undefined) {
  24815. return calculations.onOnScreen;
  24816. }
  24817. },
  24818. offScreen: function(newCallback) {
  24819. var
  24820. calculations = module.get.elementCalculations(),
  24821. callback = newCallback || settings.onOffScreen,
  24822. callbackName = 'offScreen'
  24823. ;
  24824. if(newCallback) {
  24825. module.debug('Adding callback for offScreen', newCallback);
  24826. settings.onOffScreen = newCallback;
  24827. }
  24828. if(calculations.offScreen) {
  24829. module.execute(callback, callbackName);
  24830. }
  24831. else if(!settings.once) {
  24832. module.remove.occurred(callbackName);
  24833. }
  24834. if(newCallback !== undefined) {
  24835. return calculations.onOffScreen;
  24836. }
  24837. },
  24838. passing: function(newCallback) {
  24839. var
  24840. calculations = module.get.elementCalculations(),
  24841. callback = newCallback || settings.onPassing,
  24842. callbackName = 'passing'
  24843. ;
  24844. if(newCallback) {
  24845. module.debug('Adding callback for passing', newCallback);
  24846. settings.onPassing = newCallback;
  24847. }
  24848. if(calculations.passing) {
  24849. module.execute(callback, callbackName);
  24850. }
  24851. else if(!settings.once) {
  24852. module.remove.occurred(callbackName);
  24853. }
  24854. if(newCallback !== undefined) {
  24855. return calculations.passing;
  24856. }
  24857. },
  24858. topVisible: function(newCallback) {
  24859. var
  24860. calculations = module.get.elementCalculations(),
  24861. callback = newCallback || settings.onTopVisible,
  24862. callbackName = 'topVisible'
  24863. ;
  24864. if(newCallback) {
  24865. module.debug('Adding callback for top visible', newCallback);
  24866. settings.onTopVisible = newCallback;
  24867. }
  24868. if(calculations.topVisible) {
  24869. module.execute(callback, callbackName);
  24870. }
  24871. else if(!settings.once) {
  24872. module.remove.occurred(callbackName);
  24873. }
  24874. if(newCallback === undefined) {
  24875. return calculations.topVisible;
  24876. }
  24877. },
  24878. bottomVisible: function(newCallback) {
  24879. var
  24880. calculations = module.get.elementCalculations(),
  24881. callback = newCallback || settings.onBottomVisible,
  24882. callbackName = 'bottomVisible'
  24883. ;
  24884. if(newCallback) {
  24885. module.debug('Adding callback for bottom visible', newCallback);
  24886. settings.onBottomVisible = newCallback;
  24887. }
  24888. if(calculations.bottomVisible) {
  24889. module.execute(callback, callbackName);
  24890. }
  24891. else if(!settings.once) {
  24892. module.remove.occurred(callbackName);
  24893. }
  24894. if(newCallback === undefined) {
  24895. return calculations.bottomVisible;
  24896. }
  24897. },
  24898. topPassed: function(newCallback) {
  24899. var
  24900. calculations = module.get.elementCalculations(),
  24901. callback = newCallback || settings.onTopPassed,
  24902. callbackName = 'topPassed'
  24903. ;
  24904. if(newCallback) {
  24905. module.debug('Adding callback for top passed', newCallback);
  24906. settings.onTopPassed = newCallback;
  24907. }
  24908. if(calculations.topPassed) {
  24909. module.execute(callback, callbackName);
  24910. }
  24911. else if(!settings.once) {
  24912. module.remove.occurred(callbackName);
  24913. }
  24914. if(newCallback === undefined) {
  24915. return calculations.topPassed;
  24916. }
  24917. },
  24918. bottomPassed: function(newCallback) {
  24919. var
  24920. calculations = module.get.elementCalculations(),
  24921. callback = newCallback || settings.onBottomPassed,
  24922. callbackName = 'bottomPassed'
  24923. ;
  24924. if(newCallback) {
  24925. module.debug('Adding callback for bottom passed', newCallback);
  24926. settings.onBottomPassed = newCallback;
  24927. }
  24928. if(calculations.bottomPassed) {
  24929. module.execute(callback, callbackName);
  24930. }
  24931. else if(!settings.once) {
  24932. module.remove.occurred(callbackName);
  24933. }
  24934. if(newCallback === undefined) {
  24935. return calculations.bottomPassed;
  24936. }
  24937. },
  24938. passingReverse: function(newCallback) {
  24939. var
  24940. calculations = module.get.elementCalculations(),
  24941. callback = newCallback || settings.onPassingReverse,
  24942. callbackName = 'passingReverse'
  24943. ;
  24944. if(newCallback) {
  24945. module.debug('Adding callback for passing reverse', newCallback);
  24946. settings.onPassingReverse = newCallback;
  24947. }
  24948. if(!calculations.passing) {
  24949. if(module.get.occurred('passing')) {
  24950. module.execute(callback, callbackName);
  24951. }
  24952. }
  24953. else if(!settings.once) {
  24954. module.remove.occurred(callbackName);
  24955. }
  24956. if(newCallback !== undefined) {
  24957. return !calculations.passing;
  24958. }
  24959. },
  24960. topVisibleReverse: function(newCallback) {
  24961. var
  24962. calculations = module.get.elementCalculations(),
  24963. callback = newCallback || settings.onTopVisibleReverse,
  24964. callbackName = 'topVisibleReverse'
  24965. ;
  24966. if(newCallback) {
  24967. module.debug('Adding callback for top visible reverse', newCallback);
  24968. settings.onTopVisibleReverse = newCallback;
  24969. }
  24970. if(!calculations.topVisible) {
  24971. if(module.get.occurred('topVisible')) {
  24972. module.execute(callback, callbackName);
  24973. }
  24974. }
  24975. else if(!settings.once) {
  24976. module.remove.occurred(callbackName);
  24977. }
  24978. if(newCallback === undefined) {
  24979. return !calculations.topVisible;
  24980. }
  24981. },
  24982. bottomVisibleReverse: function(newCallback) {
  24983. var
  24984. calculations = module.get.elementCalculations(),
  24985. callback = newCallback || settings.onBottomVisibleReverse,
  24986. callbackName = 'bottomVisibleReverse'
  24987. ;
  24988. if(newCallback) {
  24989. module.debug('Adding callback for bottom visible reverse', newCallback);
  24990. settings.onBottomVisibleReverse = newCallback;
  24991. }
  24992. if(!calculations.bottomVisible) {
  24993. if(module.get.occurred('bottomVisible')) {
  24994. module.execute(callback, callbackName);
  24995. }
  24996. }
  24997. else if(!settings.once) {
  24998. module.remove.occurred(callbackName);
  24999. }
  25000. if(newCallback === undefined) {
  25001. return !calculations.bottomVisible;
  25002. }
  25003. },
  25004. topPassedReverse: function(newCallback) {
  25005. var
  25006. calculations = module.get.elementCalculations(),
  25007. callback = newCallback || settings.onTopPassedReverse,
  25008. callbackName = 'topPassedReverse'
  25009. ;
  25010. if(newCallback) {
  25011. module.debug('Adding callback for top passed reverse', newCallback);
  25012. settings.onTopPassedReverse = newCallback;
  25013. }
  25014. if(!calculations.topPassed) {
  25015. if(module.get.occurred('topPassed')) {
  25016. module.execute(callback, callbackName);
  25017. }
  25018. }
  25019. else if(!settings.once) {
  25020. module.remove.occurred(callbackName);
  25021. }
  25022. if(newCallback === undefined) {
  25023. return !calculations.onTopPassed;
  25024. }
  25025. },
  25026. bottomPassedReverse: function(newCallback) {
  25027. var
  25028. calculations = module.get.elementCalculations(),
  25029. callback = newCallback || settings.onBottomPassedReverse,
  25030. callbackName = 'bottomPassedReverse'
  25031. ;
  25032. if(newCallback) {
  25033. module.debug('Adding callback for bottom passed reverse', newCallback);
  25034. settings.onBottomPassedReverse = newCallback;
  25035. }
  25036. if(!calculations.bottomPassed) {
  25037. if(module.get.occurred('bottomPassed')) {
  25038. module.execute(callback, callbackName);
  25039. }
  25040. }
  25041. else if(!settings.once) {
  25042. module.remove.occurred(callbackName);
  25043. }
  25044. if(newCallback === undefined) {
  25045. return !calculations.bottomPassed;
  25046. }
  25047. },
  25048. execute: function(callback, callbackName) {
  25049. var
  25050. calculations = module.get.elementCalculations(),
  25051. screen = module.get.screenCalculations()
  25052. ;
  25053. callback = callback || false;
  25054. if(callback) {
  25055. if(settings.continuous) {
  25056. module.debug('Callback being called continuously', callbackName, calculations);
  25057. callback.call(element, calculations, screen);
  25058. }
  25059. else if(!module.get.occurred(callbackName)) {
  25060. module.debug('Conditions met', callbackName, calculations);
  25061. callback.call(element, calculations, screen);
  25062. }
  25063. }
  25064. module.save.occurred(callbackName);
  25065. },
  25066. remove: {
  25067. fixed: function() {
  25068. module.debug('Removing fixed position');
  25069. $module
  25070. .removeClass(className.fixed)
  25071. .css({
  25072. position : '',
  25073. top : '',
  25074. left : '',
  25075. zIndex : ''
  25076. })
  25077. ;
  25078. settings.onUnfixed.call(element);
  25079. },
  25080. placeholder: function() {
  25081. module.debug('Removing placeholder content');
  25082. if($placeholder) {
  25083. $placeholder.remove();
  25084. }
  25085. },
  25086. occurred: function(callback) {
  25087. if(callback) {
  25088. var
  25089. occurred = module.cache.occurred
  25090. ;
  25091. if(occurred[callback] !== undefined && occurred[callback] === true) {
  25092. module.debug('Callback can now be called again', callback);
  25093. module.cache.occurred[callback] = false;
  25094. }
  25095. }
  25096. else {
  25097. module.cache.occurred = {};
  25098. }
  25099. }
  25100. },
  25101. save: {
  25102. calculations: function() {
  25103. module.verbose('Saving all calculations necessary to determine positioning');
  25104. module.save.direction();
  25105. module.save.screenCalculations();
  25106. module.save.elementCalculations();
  25107. },
  25108. occurred: function(callback) {
  25109. if(callback) {
  25110. if(module.cache.occurred[callback] === undefined || (module.cache.occurred[callback] !== true)) {
  25111. module.verbose('Saving callback occurred', callback);
  25112. module.cache.occurred[callback] = true;
  25113. }
  25114. }
  25115. },
  25116. scroll: function(scrollPosition) {
  25117. scrollPosition = scrollPosition + settings.offset || $context.scrollTop() + settings.offset;
  25118. module.cache.scroll = scrollPosition;
  25119. },
  25120. direction: function() {
  25121. var
  25122. scroll = module.get.scroll(),
  25123. lastScroll = module.get.lastScroll(),
  25124. direction
  25125. ;
  25126. if(scroll > lastScroll && lastScroll) {
  25127. direction = 'down';
  25128. }
  25129. else if(scroll < lastScroll && lastScroll) {
  25130. direction = 'up';
  25131. }
  25132. else {
  25133. direction = 'static';
  25134. }
  25135. module.cache.direction = direction;
  25136. return module.cache.direction;
  25137. },
  25138. elementPosition: function() {
  25139. var
  25140. element = module.cache.element,
  25141. screen = module.get.screenSize()
  25142. ;
  25143. module.verbose('Saving element position');
  25144. // (quicker than $.extend)
  25145. element.fits = (element.height < screen.height);
  25146. element.offset = $module.offset();
  25147. element.width = $module.outerWidth();
  25148. element.height = $module.outerHeight();
  25149. // compensate for scroll in context
  25150. if(module.is.verticallyScrollableContext()) {
  25151. element.offset.top += $context.scrollTop() - $context.offset().top;
  25152. }
  25153. if(module.is.horizontallyScrollableContext()) {
  25154. element.offset.left += $context.scrollLeft - $context.offset().left;
  25155. }
  25156. // store
  25157. module.cache.element = element;
  25158. return element;
  25159. },
  25160. elementCalculations: function() {
  25161. var
  25162. screen = module.get.screenCalculations(),
  25163. element = module.get.elementPosition()
  25164. ;
  25165. // offset
  25166. if(settings.includeMargin) {
  25167. element.margin = {};
  25168. element.margin.top = parseInt($module.css('margin-top'), 10);
  25169. element.margin.bottom = parseInt($module.css('margin-bottom'), 10);
  25170. element.top = element.offset.top - element.margin.top;
  25171. element.bottom = element.offset.top + element.height + element.margin.bottom;
  25172. }
  25173. else {
  25174. element.top = element.offset.top;
  25175. element.bottom = element.offset.top + element.height;
  25176. }
  25177. // visibility
  25178. element.topPassed = (screen.top >= element.top);
  25179. element.bottomPassed = (screen.top >= element.bottom);
  25180. element.topVisible = (screen.bottom >= element.top) && !element.topPassed;
  25181. element.bottomVisible = (screen.bottom >= element.bottom) && !element.bottomPassed;
  25182. element.pixelsPassed = 0;
  25183. element.percentagePassed = 0;
  25184. // meta calculations
  25185. element.onScreen = ((element.topVisible || element.passing) && !element.bottomPassed);
  25186. element.passing = (element.topPassed && !element.bottomPassed);
  25187. element.offScreen = (!element.onScreen);
  25188. // passing calculations
  25189. if(element.passing) {
  25190. element.pixelsPassed = (screen.top - element.top);
  25191. element.percentagePassed = (screen.top - element.top) / element.height;
  25192. }
  25193. module.cache.element = element;
  25194. module.verbose('Updated element calculations', element);
  25195. return element;
  25196. },
  25197. screenCalculations: function() {
  25198. var
  25199. scroll = module.get.scroll()
  25200. ;
  25201. module.save.direction();
  25202. module.cache.screen.top = scroll;
  25203. module.cache.screen.bottom = scroll + module.cache.screen.height;
  25204. return module.cache.screen;
  25205. },
  25206. screenSize: function() {
  25207. module.verbose('Saving window position');
  25208. module.cache.screen = {
  25209. height: $context.height()
  25210. };
  25211. },
  25212. position: function() {
  25213. module.save.screenSize();
  25214. module.save.elementPosition();
  25215. }
  25216. },
  25217. get: {
  25218. pixelsPassed: function(amount) {
  25219. var
  25220. element = module.get.elementCalculations()
  25221. ;
  25222. if(amount.search('%') > -1) {
  25223. return ( element.height * (parseInt(amount, 10) / 100) );
  25224. }
  25225. return parseInt(amount, 10);
  25226. },
  25227. occurred: function(callback) {
  25228. return (module.cache.occurred !== undefined)
  25229. ? module.cache.occurred[callback] || false
  25230. : false
  25231. ;
  25232. },
  25233. direction: function() {
  25234. if(module.cache.direction === undefined) {
  25235. module.save.direction();
  25236. }
  25237. return module.cache.direction;
  25238. },
  25239. elementPosition: function() {
  25240. if(module.cache.element === undefined) {
  25241. module.save.elementPosition();
  25242. }
  25243. return module.cache.element;
  25244. },
  25245. elementCalculations: function() {
  25246. if(module.cache.element === undefined) {
  25247. module.save.elementCalculations();
  25248. }
  25249. return module.cache.element;
  25250. },
  25251. screenCalculations: function() {
  25252. if(module.cache.screen === undefined) {
  25253. module.save.screenCalculations();
  25254. }
  25255. return module.cache.screen;
  25256. },
  25257. screenSize: function() {
  25258. if(module.cache.screen === undefined) {
  25259. module.save.screenSize();
  25260. }
  25261. return module.cache.screen;
  25262. },
  25263. scroll: function() {
  25264. if(module.cache.scroll === undefined) {
  25265. module.save.scroll();
  25266. }
  25267. return module.cache.scroll;
  25268. },
  25269. lastScroll: function() {
  25270. if(module.cache.screen === undefined) {
  25271. module.debug('First scroll event, no last scroll could be found');
  25272. return false;
  25273. }
  25274. return module.cache.screen.top;
  25275. }
  25276. },
  25277. setting: function(name, value) {
  25278. if( $.isPlainObject(name) ) {
  25279. $.extend(true, settings, name);
  25280. }
  25281. else if(value !== undefined) {
  25282. settings[name] = value;
  25283. }
  25284. else {
  25285. return settings[name];
  25286. }
  25287. },
  25288. internal: function(name, value) {
  25289. if( $.isPlainObject(name) ) {
  25290. $.extend(true, module, name);
  25291. }
  25292. else if(value !== undefined) {
  25293. module[name] = value;
  25294. }
  25295. else {
  25296. return module[name];
  25297. }
  25298. },
  25299. debug: function() {
  25300. if(!settings.silent && settings.debug) {
  25301. if(settings.performance) {
  25302. module.performance.log(arguments);
  25303. }
  25304. else {
  25305. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  25306. module.debug.apply(console, arguments);
  25307. }
  25308. }
  25309. },
  25310. verbose: function() {
  25311. if(!settings.silent && settings.verbose && settings.debug) {
  25312. if(settings.performance) {
  25313. module.performance.log(arguments);
  25314. }
  25315. else {
  25316. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  25317. module.verbose.apply(console, arguments);
  25318. }
  25319. }
  25320. },
  25321. error: function() {
  25322. if(!settings.silent) {
  25323. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  25324. module.error.apply(console, arguments);
  25325. }
  25326. },
  25327. performance: {
  25328. log: function(message) {
  25329. var
  25330. currentTime,
  25331. executionTime,
  25332. previousTime
  25333. ;
  25334. if(settings.performance) {
  25335. currentTime = new Date().getTime();
  25336. previousTime = time || currentTime;
  25337. executionTime = currentTime - previousTime;
  25338. time = currentTime;
  25339. performance.push({
  25340. 'Name' : message[0],
  25341. 'Arguments' : [].slice.call(message, 1) || '',
  25342. 'Element' : element,
  25343. 'Execution Time' : executionTime
  25344. });
  25345. }
  25346. clearTimeout(module.performance.timer);
  25347. module.performance.timer = setTimeout(module.performance.display, 500);
  25348. },
  25349. display: function() {
  25350. var
  25351. title = settings.name + ':',
  25352. totalTime = 0
  25353. ;
  25354. time = false;
  25355. clearTimeout(module.performance.timer);
  25356. $.each(performance, function(index, data) {
  25357. totalTime += data['Execution Time'];
  25358. });
  25359. title += ' ' + totalTime + 'ms';
  25360. if(moduleSelector) {
  25361. title += ' \'' + moduleSelector + '\'';
  25362. }
  25363. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  25364. console.groupCollapsed(title);
  25365. if(console.table) {
  25366. console.table(performance);
  25367. }
  25368. else {
  25369. $.each(performance, function(index, data) {
  25370. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  25371. });
  25372. }
  25373. console.groupEnd();
  25374. }
  25375. performance = [];
  25376. }
  25377. },
  25378. invoke: function(query, passedArguments, context) {
  25379. var
  25380. object = instance,
  25381. maxDepth,
  25382. found,
  25383. response
  25384. ;
  25385. passedArguments = passedArguments || queryArguments;
  25386. context = element || context;
  25387. if(typeof query == 'string' && object !== undefined) {
  25388. query = query.split(/[\. ]/);
  25389. maxDepth = query.length - 1;
  25390. $.each(query, function(depth, value) {
  25391. var camelCaseValue = (depth != maxDepth)
  25392. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  25393. : query
  25394. ;
  25395. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  25396. object = object[camelCaseValue];
  25397. }
  25398. else if( object[camelCaseValue] !== undefined ) {
  25399. found = object[camelCaseValue];
  25400. return false;
  25401. }
  25402. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  25403. object = object[value];
  25404. }
  25405. else if( object[value] !== undefined ) {
  25406. found = object[value];
  25407. return false;
  25408. }
  25409. else {
  25410. module.error(error.method, query);
  25411. return false;
  25412. }
  25413. });
  25414. }
  25415. if ( $.isFunction( found ) ) {
  25416. response = found.apply(context, passedArguments);
  25417. }
  25418. else if(found !== undefined) {
  25419. response = found;
  25420. }
  25421. if(Array.isArray(returnedValue)) {
  25422. returnedValue.push(response);
  25423. }
  25424. else if(returnedValue !== undefined) {
  25425. returnedValue = [returnedValue, response];
  25426. }
  25427. else if(response !== undefined) {
  25428. returnedValue = response;
  25429. }
  25430. return found;
  25431. }
  25432. };
  25433. if(methodInvoked) {
  25434. if(instance === undefined) {
  25435. module.initialize();
  25436. }
  25437. instance.save.scroll();
  25438. instance.save.calculations();
  25439. module.invoke(query);
  25440. }
  25441. else {
  25442. if(instance !== undefined) {
  25443. instance.invoke('destroy');
  25444. }
  25445. module.initialize();
  25446. }
  25447. })
  25448. ;
  25449. return (returnedValue !== undefined)
  25450. ? returnedValue
  25451. : this
  25452. ;
  25453. };
  25454. $.fn.visibility.settings = {
  25455. name : 'Visibility',
  25456. namespace : 'visibility',
  25457. debug : false,
  25458. verbose : false,
  25459. performance : true,
  25460. // whether to use mutation observers to follow changes
  25461. observeChanges : true,
  25462. // check position immediately on init
  25463. initialCheck : true,
  25464. // whether to refresh calculations after all page images load
  25465. refreshOnLoad : true,
  25466. // whether to refresh calculations after page resize event
  25467. refreshOnResize : true,
  25468. // should call callbacks on refresh event (resize, etc)
  25469. checkOnRefresh : true,
  25470. // callback should only occur one time
  25471. once : true,
  25472. // callback should fire continuously whe evaluates to true
  25473. continuous : false,
  25474. // offset to use with scroll top
  25475. offset : 0,
  25476. // whether to include margin in elements position
  25477. includeMargin : false,
  25478. // scroll context for visibility checks
  25479. context : window,
  25480. // visibility check delay in ms (defaults to animationFrame)
  25481. throttle : false,
  25482. // special visibility type (image, fixed)
  25483. type : false,
  25484. // z-index to use with visibility 'fixed'
  25485. zIndex : '10',
  25486. // image only animation settings
  25487. transition : 'fade in',
  25488. duration : 1000,
  25489. // array of callbacks for percentage
  25490. onPassed : {},
  25491. // standard callbacks
  25492. onOnScreen : false,
  25493. onOffScreen : false,
  25494. onPassing : false,
  25495. onTopVisible : false,
  25496. onBottomVisible : false,
  25497. onTopPassed : false,
  25498. onBottomPassed : false,
  25499. // reverse callbacks
  25500. onPassingReverse : false,
  25501. onTopVisibleReverse : false,
  25502. onBottomVisibleReverse : false,
  25503. onTopPassedReverse : false,
  25504. onBottomPassedReverse : false,
  25505. // special callbacks for image
  25506. onLoad : function() {},
  25507. onAllLoaded : function() {},
  25508. // special callbacks for fixed position
  25509. onFixed : function() {},
  25510. onUnfixed : function() {},
  25511. // utility callbacks
  25512. onUpdate : false, // disabled by default for performance
  25513. onRefresh : function(){},
  25514. metadata : {
  25515. src: 'src'
  25516. },
  25517. className: {
  25518. fixed : 'fixed',
  25519. placeholder : 'constraint',
  25520. visible : 'visible'
  25521. },
  25522. error : {
  25523. method : 'The method you called is not defined.',
  25524. visible : 'Element is hidden, you must call refresh after element becomes visible'
  25525. }
  25526. };
  25527. })( jQuery, window, document );