You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

semantic.js 570KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151
  1. /*
  2. * # Fomantic UI - 2.8.7
  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 - API
  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. 'use strict';
  22. $.isWindow = $.isWindow || function(obj) {
  23. return obj != null && obj === obj.window;
  24. };
  25. window = (typeof window != 'undefined' && window.Math == Math)
  26. ? window
  27. : (typeof self != 'undefined' && self.Math == Math)
  28. ? self
  29. : Function('return this')()
  30. ;
  31. $.api = $.fn.api = function(parameters) {
  32. var
  33. // use window context if none specified
  34. $allModules = $.isFunction(this)
  35. ? $(window)
  36. : $(this),
  37. moduleSelector = $allModules.selector || '',
  38. time = new Date().getTime(),
  39. performance = [],
  40. query = arguments[0],
  41. methodInvoked = (typeof query == 'string'),
  42. queryArguments = [].slice.call(arguments, 1),
  43. returnedValue
  44. ;
  45. $allModules
  46. .each(function() {
  47. var
  48. settings = ( $.isPlainObject(parameters) )
  49. ? $.extend(true, {}, $.fn.api.settings, parameters)
  50. : $.extend({}, $.fn.api.settings),
  51. // internal aliases
  52. namespace = settings.namespace,
  53. metadata = settings.metadata,
  54. selector = settings.selector,
  55. error = settings.error,
  56. className = settings.className,
  57. // define namespaces for modules
  58. eventNamespace = '.' + namespace,
  59. moduleNamespace = 'module-' + namespace,
  60. // element that creates request
  61. $module = $(this),
  62. $form = $module.closest(selector.form),
  63. // context used for state
  64. $context = (settings.stateContext)
  65. ? $(settings.stateContext)
  66. : $module,
  67. // request details
  68. ajaxSettings,
  69. requestSettings,
  70. url,
  71. data,
  72. requestStartTime,
  73. // standard module
  74. element = this,
  75. context = $context[0],
  76. instance = $module.data(moduleNamespace),
  77. module
  78. ;
  79. module = {
  80. initialize: function() {
  81. if(!methodInvoked) {
  82. module.bind.events();
  83. }
  84. module.instantiate();
  85. },
  86. instantiate: function() {
  87. module.verbose('Storing instance of module', module);
  88. instance = module;
  89. $module
  90. .data(moduleNamespace, instance)
  91. ;
  92. },
  93. destroy: function() {
  94. module.verbose('Destroying previous module for', element);
  95. $module
  96. .removeData(moduleNamespace)
  97. .off(eventNamespace)
  98. ;
  99. },
  100. bind: {
  101. events: function() {
  102. var
  103. triggerEvent = module.get.event()
  104. ;
  105. if( triggerEvent ) {
  106. module.verbose('Attaching API events to element', triggerEvent);
  107. $module
  108. .on(triggerEvent + eventNamespace, module.event.trigger)
  109. ;
  110. }
  111. else if(settings.on == 'now') {
  112. module.debug('Querying API endpoint immediately');
  113. module.query();
  114. }
  115. }
  116. },
  117. decode: {
  118. json: function(response) {
  119. if(response !== undefined && typeof response == 'string') {
  120. try {
  121. response = JSON.parse(response);
  122. }
  123. catch(e) {
  124. // isnt json string
  125. }
  126. }
  127. return response;
  128. }
  129. },
  130. read: {
  131. cachedResponse: function(url) {
  132. var
  133. response
  134. ;
  135. if(window.Storage === undefined) {
  136. module.error(error.noStorage);
  137. return;
  138. }
  139. response = sessionStorage.getItem(url);
  140. module.debug('Using cached response', url, response);
  141. response = module.decode.json(response);
  142. return response;
  143. }
  144. },
  145. write: {
  146. cachedResponse: function(url, response) {
  147. if(response && response === '') {
  148. module.debug('Response empty, not caching', response);
  149. return;
  150. }
  151. if(window.Storage === undefined) {
  152. module.error(error.noStorage);
  153. return;
  154. }
  155. if( $.isPlainObject(response) ) {
  156. response = JSON.stringify(response);
  157. }
  158. sessionStorage.setItem(url, response);
  159. module.verbose('Storing cached response for url', url, response);
  160. }
  161. },
  162. query: function() {
  163. if(module.is.disabled()) {
  164. module.debug('Element is disabled API request aborted');
  165. return;
  166. }
  167. if(module.is.loading()) {
  168. if(settings.interruptRequests) {
  169. module.debug('Interrupting previous request');
  170. module.abort();
  171. }
  172. else {
  173. module.debug('Cancelling request, previous request is still pending');
  174. return;
  175. }
  176. }
  177. // pass element metadata to url (value, text)
  178. if(settings.defaultData) {
  179. $.extend(true, settings.urlData, module.get.defaultData());
  180. }
  181. // Add form content
  182. if(settings.serializeForm) {
  183. settings.data = module.add.formData(settings.data);
  184. }
  185. // call beforesend and get any settings changes
  186. requestSettings = module.get.settings();
  187. // check if before send cancelled request
  188. if(requestSettings === false) {
  189. module.cancelled = true;
  190. module.error(error.beforeSend);
  191. return;
  192. }
  193. else {
  194. module.cancelled = false;
  195. }
  196. // get url
  197. url = module.get.templatedURL();
  198. if(!url && !module.is.mocked()) {
  199. module.error(error.missingURL);
  200. return;
  201. }
  202. // replace variables
  203. url = module.add.urlData( url );
  204. // missing url parameters
  205. if( !url && !module.is.mocked()) {
  206. return;
  207. }
  208. requestSettings.url = settings.base + url;
  209. // look for jQuery ajax parameters in settings
  210. ajaxSettings = $.extend(true, {}, settings, {
  211. type : settings.method || settings.type,
  212. data : data,
  213. url : settings.base + url,
  214. beforeSend : settings.beforeXHR,
  215. success : function() {},
  216. failure : function() {},
  217. complete : function() {}
  218. });
  219. module.debug('Querying URL', ajaxSettings.url);
  220. module.verbose('Using AJAX settings', ajaxSettings);
  221. if(settings.cache === 'local' && module.read.cachedResponse(url)) {
  222. module.debug('Response returned from local cache');
  223. module.request = module.create.request();
  224. module.request.resolveWith(context, [ module.read.cachedResponse(url) ]);
  225. return;
  226. }
  227. if( !settings.throttle ) {
  228. module.debug('Sending request', data, ajaxSettings.method);
  229. module.send.request();
  230. }
  231. else {
  232. if(!settings.throttleFirstRequest && !module.timer) {
  233. module.debug('Sending request', data, ajaxSettings.method);
  234. module.send.request();
  235. module.timer = setTimeout(function(){}, settings.throttle);
  236. }
  237. else {
  238. module.debug('Throttling request', settings.throttle);
  239. clearTimeout(module.timer);
  240. module.timer = setTimeout(function() {
  241. if(module.timer) {
  242. delete module.timer;
  243. }
  244. module.debug('Sending throttled request', data, ajaxSettings.method);
  245. module.send.request();
  246. }, settings.throttle);
  247. }
  248. }
  249. },
  250. should: {
  251. removeError: function() {
  252. return ( settings.hideError === true || (settings.hideError === 'auto' && !module.is.form()) );
  253. }
  254. },
  255. is: {
  256. disabled: function() {
  257. return ($module.filter(selector.disabled).length > 0);
  258. },
  259. expectingJSON: function() {
  260. return settings.dataType === 'json' || settings.dataType === 'jsonp';
  261. },
  262. form: function() {
  263. return $module.is('form') || $context.is('form');
  264. },
  265. mocked: function() {
  266. return (settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync);
  267. },
  268. input: function() {
  269. return $module.is('input');
  270. },
  271. loading: function() {
  272. return (module.request)
  273. ? (module.request.state() == 'pending')
  274. : false
  275. ;
  276. },
  277. abortedRequest: function(xhr) {
  278. if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
  279. module.verbose('XHR request determined to be aborted');
  280. return true;
  281. }
  282. else {
  283. module.verbose('XHR request was not aborted');
  284. return false;
  285. }
  286. },
  287. validResponse: function(response) {
  288. if( (!module.is.expectingJSON()) || !$.isFunction(settings.successTest) ) {
  289. module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
  290. return true;
  291. }
  292. module.debug('Checking JSON returned success', settings.successTest, response);
  293. if( settings.successTest(response) ) {
  294. module.debug('Response passed success test', response);
  295. return true;
  296. }
  297. else {
  298. module.debug('Response failed success test', response);
  299. return false;
  300. }
  301. }
  302. },
  303. was: {
  304. cancelled: function() {
  305. return (module.cancelled || false);
  306. },
  307. succesful: function() {
  308. module.verbose('This behavior will be deleted due to typo. Use "was successful" instead.');
  309. return module.was.successful();
  310. },
  311. successful: function() {
  312. return (module.request && module.request.state() == 'resolved');
  313. },
  314. failure: function() {
  315. return (module.request && module.request.state() == 'rejected');
  316. },
  317. complete: function() {
  318. return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') );
  319. }
  320. },
  321. add: {
  322. urlData: function(url, urlData) {
  323. var
  324. requiredVariables,
  325. optionalVariables
  326. ;
  327. if(url) {
  328. requiredVariables = url.match(settings.regExp.required);
  329. optionalVariables = url.match(settings.regExp.optional);
  330. urlData = urlData || settings.urlData;
  331. if(requiredVariables) {
  332. module.debug('Looking for required URL variables', requiredVariables);
  333. $.each(requiredVariables, function(index, templatedString) {
  334. var
  335. // allow legacy {$var} style
  336. variable = (templatedString.indexOf('$') !== -1)
  337. ? templatedString.substr(2, templatedString.length - 3)
  338. : templatedString.substr(1, templatedString.length - 2),
  339. value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
  340. ? urlData[variable]
  341. : ($module.data(variable) !== undefined)
  342. ? $module.data(variable)
  343. : ($context.data(variable) !== undefined)
  344. ? $context.data(variable)
  345. : urlData[variable]
  346. ;
  347. // remove value
  348. if(value === undefined) {
  349. module.error(error.requiredParameter, variable, url);
  350. url = false;
  351. return false;
  352. }
  353. else {
  354. module.verbose('Found required variable', variable, value);
  355. value = (settings.encodeParameters)
  356. ? module.get.urlEncodedValue(value)
  357. : value
  358. ;
  359. url = url.replace(templatedString, value);
  360. }
  361. });
  362. }
  363. if(optionalVariables) {
  364. module.debug('Looking for optional URL variables', requiredVariables);
  365. $.each(optionalVariables, function(index, templatedString) {
  366. var
  367. // allow legacy {/$var} style
  368. variable = (templatedString.indexOf('$') !== -1)
  369. ? templatedString.substr(3, templatedString.length - 4)
  370. : templatedString.substr(2, templatedString.length - 3),
  371. value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
  372. ? urlData[variable]
  373. : ($module.data(variable) !== undefined)
  374. ? $module.data(variable)
  375. : ($context.data(variable) !== undefined)
  376. ? $context.data(variable)
  377. : urlData[variable]
  378. ;
  379. // optional replacement
  380. if(value !== undefined) {
  381. module.verbose('Optional variable Found', variable, value);
  382. url = url.replace(templatedString, value);
  383. }
  384. else {
  385. module.verbose('Optional variable not found', variable);
  386. // remove preceding slash if set
  387. if(url.indexOf('/' + templatedString) !== -1) {
  388. url = url.replace('/' + templatedString, '');
  389. }
  390. else {
  391. url = url.replace(templatedString, '');
  392. }
  393. }
  394. });
  395. }
  396. }
  397. return url;
  398. },
  399. formData: function(data) {
  400. var
  401. canSerialize = ($.fn.serializeObject !== undefined),
  402. formData = (canSerialize)
  403. ? $form.serializeObject()
  404. : $form.serialize(),
  405. hasOtherData
  406. ;
  407. data = data || settings.data;
  408. hasOtherData = $.isPlainObject(data);
  409. if(hasOtherData) {
  410. if(canSerialize) {
  411. module.debug('Extending existing data with form data', data, formData);
  412. data = $.extend(true, {}, data, formData);
  413. }
  414. else {
  415. module.error(error.missingSerialize);
  416. module.debug('Cant extend data. Replacing data with form data', data, formData);
  417. data = formData;
  418. }
  419. }
  420. else {
  421. module.debug('Adding form data', formData);
  422. data = formData;
  423. }
  424. return data;
  425. }
  426. },
  427. send: {
  428. request: function() {
  429. module.set.loading();
  430. module.request = module.create.request();
  431. if( module.is.mocked() ) {
  432. module.mockedXHR = module.create.mockedXHR();
  433. }
  434. else {
  435. module.xhr = module.create.xhr();
  436. }
  437. settings.onRequest.call(context, module.request, module.xhr);
  438. }
  439. },
  440. event: {
  441. trigger: function(event) {
  442. module.query();
  443. if(event.type == 'submit' || event.type == 'click') {
  444. event.preventDefault();
  445. }
  446. },
  447. xhr: {
  448. always: function() {
  449. // nothing special
  450. },
  451. done: function(response, textStatus, xhr) {
  452. var
  453. context = this,
  454. elapsedTime = (new Date().getTime() - requestStartTime),
  455. timeLeft = (settings.loadingDuration - elapsedTime),
  456. translatedResponse = ( $.isFunction(settings.onResponse) )
  457. ? module.is.expectingJSON() && !settings.rawResponse
  458. ? settings.onResponse.call(context, $.extend(true, {}, response))
  459. : settings.onResponse.call(context, response)
  460. : false
  461. ;
  462. timeLeft = (timeLeft > 0)
  463. ? timeLeft
  464. : 0
  465. ;
  466. if(translatedResponse) {
  467. module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
  468. response = translatedResponse;
  469. }
  470. if(timeLeft > 0) {
  471. module.debug('Response completed early delaying state change by', timeLeft);
  472. }
  473. setTimeout(function() {
  474. if( module.is.validResponse(response) ) {
  475. module.request.resolveWith(context, [response, xhr]);
  476. }
  477. else {
  478. module.request.rejectWith(context, [xhr, 'invalid']);
  479. }
  480. }, timeLeft);
  481. },
  482. fail: function(xhr, status, httpMessage) {
  483. var
  484. context = this,
  485. elapsedTime = (new Date().getTime() - requestStartTime),
  486. timeLeft = (settings.loadingDuration - elapsedTime)
  487. ;
  488. timeLeft = (timeLeft > 0)
  489. ? timeLeft
  490. : 0
  491. ;
  492. if(timeLeft > 0) {
  493. module.debug('Response completed early delaying state change by', timeLeft);
  494. }
  495. setTimeout(function() {
  496. if( module.is.abortedRequest(xhr) ) {
  497. module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
  498. }
  499. else {
  500. module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
  501. }
  502. }, timeLeft);
  503. }
  504. },
  505. request: {
  506. done: function(response, xhr) {
  507. module.debug('Successful API Response', response);
  508. if(settings.cache === 'local' && url) {
  509. module.write.cachedResponse(url, response);
  510. module.debug('Saving server response locally', module.cache);
  511. }
  512. settings.onSuccess.call(context, response, $module, xhr);
  513. },
  514. complete: function(firstParameter, secondParameter) {
  515. var
  516. xhr,
  517. response
  518. ;
  519. // have to guess callback parameters based on request success
  520. if( module.was.successful() ) {
  521. response = firstParameter;
  522. xhr = secondParameter;
  523. }
  524. else {
  525. xhr = firstParameter;
  526. response = module.get.responseFromXHR(xhr);
  527. }
  528. module.remove.loading();
  529. settings.onComplete.call(context, response, $module, xhr);
  530. },
  531. fail: function(xhr, status, httpMessage) {
  532. var
  533. // pull response from xhr if available
  534. response = module.get.responseFromXHR(xhr),
  535. errorMessage = module.get.errorFromRequest(response, status, httpMessage)
  536. ;
  537. if(status == 'aborted') {
  538. module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
  539. settings.onAbort.call(context, status, $module, xhr);
  540. return true;
  541. }
  542. else if(status == 'invalid') {
  543. module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
  544. }
  545. else if(status == 'error') {
  546. if(xhr !== undefined) {
  547. module.debug('XHR produced a server error', status, httpMessage);
  548. // make sure we have an error to display to console
  549. if( (xhr.status < 200 || xhr.status >= 300) && httpMessage !== undefined && httpMessage !== '') {
  550. module.error(error.statusMessage + httpMessage, ajaxSettings.url);
  551. }
  552. settings.onError.call(context, errorMessage, $module, xhr);
  553. }
  554. }
  555. if(settings.errorDuration && status !== 'aborted') {
  556. module.debug('Adding error state');
  557. module.set.error();
  558. if( module.should.removeError() ) {
  559. setTimeout(module.remove.error, settings.errorDuration);
  560. }
  561. }
  562. module.debug('API Request failed', errorMessage, xhr);
  563. settings.onFailure.call(context, response, $module, xhr);
  564. }
  565. }
  566. },
  567. create: {
  568. request: function() {
  569. // api request promise
  570. return $.Deferred()
  571. .always(module.event.request.complete)
  572. .done(module.event.request.done)
  573. .fail(module.event.request.fail)
  574. ;
  575. },
  576. mockedXHR: function () {
  577. var
  578. // xhr does not simulate these properties of xhr but must return them
  579. textStatus = false,
  580. status = false,
  581. httpMessage = false,
  582. responder = settings.mockResponse || settings.response,
  583. asyncResponder = settings.mockResponseAsync || settings.responseAsync,
  584. asyncCallback,
  585. response,
  586. mockedXHR
  587. ;
  588. mockedXHR = $.Deferred()
  589. .always(module.event.xhr.complete)
  590. .done(module.event.xhr.done)
  591. .fail(module.event.xhr.fail)
  592. ;
  593. if(responder) {
  594. if( $.isFunction(responder) ) {
  595. module.debug('Using specified synchronous callback', responder);
  596. response = responder.call(context, requestSettings);
  597. }
  598. else {
  599. module.debug('Using settings specified response', responder);
  600. response = responder;
  601. }
  602. // simulating response
  603. mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
  604. }
  605. else if( $.isFunction(asyncResponder) ) {
  606. asyncCallback = function(response) {
  607. module.debug('Async callback returned response', response);
  608. if(response) {
  609. mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
  610. }
  611. else {
  612. mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
  613. }
  614. };
  615. module.debug('Using specified async response callback', asyncResponder);
  616. asyncResponder.call(context, requestSettings, asyncCallback);
  617. }
  618. return mockedXHR;
  619. },
  620. xhr: function() {
  621. var
  622. xhr
  623. ;
  624. // ajax request promise
  625. xhr = $.ajax(ajaxSettings)
  626. .always(module.event.xhr.always)
  627. .done(module.event.xhr.done)
  628. .fail(module.event.xhr.fail)
  629. ;
  630. module.verbose('Created server request', xhr, ajaxSettings);
  631. return xhr;
  632. }
  633. },
  634. set: {
  635. error: function() {
  636. module.verbose('Adding error state to element', $context);
  637. $context.addClass(className.error);
  638. },
  639. loading: function() {
  640. module.verbose('Adding loading state to element', $context);
  641. $context.addClass(className.loading);
  642. requestStartTime = new Date().getTime();
  643. }
  644. },
  645. remove: {
  646. error: function() {
  647. module.verbose('Removing error state from element', $context);
  648. $context.removeClass(className.error);
  649. },
  650. loading: function() {
  651. module.verbose('Removing loading state from element', $context);
  652. $context.removeClass(className.loading);
  653. }
  654. },
  655. get: {
  656. responseFromXHR: function(xhr) {
  657. return $.isPlainObject(xhr)
  658. ? (module.is.expectingJSON())
  659. ? module.decode.json(xhr.responseText)
  660. : xhr.responseText
  661. : false
  662. ;
  663. },
  664. errorFromRequest: function(response, status, httpMessage) {
  665. return ($.isPlainObject(response) && response.error !== undefined)
  666. ? response.error // use json error message
  667. : (settings.error[status] !== undefined) // use server error message
  668. ? settings.error[status]
  669. : httpMessage
  670. ;
  671. },
  672. request: function() {
  673. return module.request || false;
  674. },
  675. xhr: function() {
  676. return module.xhr || false;
  677. },
  678. settings: function() {
  679. var
  680. runSettings
  681. ;
  682. runSettings = settings.beforeSend.call($module, settings);
  683. if(runSettings) {
  684. if(runSettings.success !== undefined) {
  685. module.debug('Legacy success callback detected', runSettings);
  686. module.error(error.legacyParameters, runSettings.success);
  687. runSettings.onSuccess = runSettings.success;
  688. }
  689. if(runSettings.failure !== undefined) {
  690. module.debug('Legacy failure callback detected', runSettings);
  691. module.error(error.legacyParameters, runSettings.failure);
  692. runSettings.onFailure = runSettings.failure;
  693. }
  694. if(runSettings.complete !== undefined) {
  695. module.debug('Legacy complete callback detected', runSettings);
  696. module.error(error.legacyParameters, runSettings.complete);
  697. runSettings.onComplete = runSettings.complete;
  698. }
  699. }
  700. if(runSettings === undefined) {
  701. module.error(error.noReturnedValue);
  702. }
  703. if(runSettings === false) {
  704. return runSettings;
  705. }
  706. return (runSettings !== undefined)
  707. ? $.extend(true, {}, runSettings)
  708. : $.extend(true, {}, settings)
  709. ;
  710. },
  711. urlEncodedValue: function(value) {
  712. var
  713. decodedValue = window.decodeURIComponent(value),
  714. encodedValue = window.encodeURIComponent(value),
  715. alreadyEncoded = (decodedValue !== value)
  716. ;
  717. if(alreadyEncoded) {
  718. module.debug('URL value is already encoded, avoiding double encoding', value);
  719. return value;
  720. }
  721. module.verbose('Encoding value using encodeURIComponent', value, encodedValue);
  722. return encodedValue;
  723. },
  724. defaultData: function() {
  725. var
  726. data = {}
  727. ;
  728. if( !$.isWindow(element) ) {
  729. if( module.is.input() ) {
  730. data.value = $module.val();
  731. }
  732. else if( module.is.form() ) {
  733. }
  734. else {
  735. data.text = $module.text();
  736. }
  737. }
  738. return data;
  739. },
  740. event: function() {
  741. if( $.isWindow(element) || settings.on == 'now' ) {
  742. module.debug('API called without element, no events attached');
  743. return false;
  744. }
  745. else if(settings.on == 'auto') {
  746. if( $module.is('input') ) {
  747. return (element.oninput !== undefined)
  748. ? 'input'
  749. : (element.onpropertychange !== undefined)
  750. ? 'propertychange'
  751. : 'keyup'
  752. ;
  753. }
  754. else if( $module.is('form') ) {
  755. return 'submit';
  756. }
  757. else {
  758. return 'click';
  759. }
  760. }
  761. else {
  762. return settings.on;
  763. }
  764. },
  765. templatedURL: function(action) {
  766. action = action || $module.data(metadata.action) || settings.action || false;
  767. url = $module.data(metadata.url) || settings.url || false;
  768. if(url) {
  769. module.debug('Using specified url', url);
  770. return url;
  771. }
  772. if(action) {
  773. module.debug('Looking up url for action', action, settings.api);
  774. if(settings.api[action] === undefined && !module.is.mocked()) {
  775. module.error(error.missingAction, settings.action, settings.api);
  776. return;
  777. }
  778. url = settings.api[action];
  779. }
  780. else if( module.is.form() ) {
  781. url = $module.attr('action') || $context.attr('action') || false;
  782. module.debug('No url or action specified, defaulting to form action', url);
  783. }
  784. return url;
  785. }
  786. },
  787. abort: function() {
  788. var
  789. xhr = module.get.xhr()
  790. ;
  791. if( xhr && xhr.state() !== 'resolved') {
  792. module.debug('Cancelling API request');
  793. xhr.abort();
  794. }
  795. },
  796. // reset state
  797. reset: function() {
  798. module.remove.error();
  799. module.remove.loading();
  800. },
  801. setting: function(name, value) {
  802. module.debug('Changing setting', name, value);
  803. if( $.isPlainObject(name) ) {
  804. $.extend(true, settings, name);
  805. }
  806. else if(value !== undefined) {
  807. if($.isPlainObject(settings[name])) {
  808. $.extend(true, settings[name], value);
  809. }
  810. else {
  811. settings[name] = value;
  812. }
  813. }
  814. else {
  815. return settings[name];
  816. }
  817. },
  818. internal: function(name, value) {
  819. if( $.isPlainObject(name) ) {
  820. $.extend(true, module, name);
  821. }
  822. else if(value !== undefined) {
  823. module[name] = value;
  824. }
  825. else {
  826. return module[name];
  827. }
  828. },
  829. debug: function() {
  830. if(!settings.silent && settings.debug) {
  831. if(settings.performance) {
  832. module.performance.log(arguments);
  833. }
  834. else {
  835. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  836. module.debug.apply(console, arguments);
  837. }
  838. }
  839. },
  840. verbose: function() {
  841. if(!settings.silent && settings.verbose && settings.debug) {
  842. if(settings.performance) {
  843. module.performance.log(arguments);
  844. }
  845. else {
  846. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  847. module.verbose.apply(console, arguments);
  848. }
  849. }
  850. },
  851. error: function() {
  852. if(!settings.silent) {
  853. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  854. module.error.apply(console, arguments);
  855. }
  856. },
  857. performance: {
  858. log: function(message) {
  859. var
  860. currentTime,
  861. executionTime,
  862. previousTime
  863. ;
  864. if(settings.performance) {
  865. currentTime = new Date().getTime();
  866. previousTime = time || currentTime;
  867. executionTime = currentTime - previousTime;
  868. time = currentTime;
  869. performance.push({
  870. 'Name' : message[0],
  871. 'Arguments' : [].slice.call(message, 1) || '',
  872. //'Element' : element,
  873. 'Execution Time' : executionTime
  874. });
  875. }
  876. clearTimeout(module.performance.timer);
  877. module.performance.timer = setTimeout(module.performance.display, 500);
  878. },
  879. display: function() {
  880. var
  881. title = settings.name + ':',
  882. totalTime = 0
  883. ;
  884. time = false;
  885. clearTimeout(module.performance.timer);
  886. $.each(performance, function(index, data) {
  887. totalTime += data['Execution Time'];
  888. });
  889. title += ' ' + totalTime + 'ms';
  890. if(moduleSelector) {
  891. title += ' \'' + moduleSelector + '\'';
  892. }
  893. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  894. console.groupCollapsed(title);
  895. if(console.table) {
  896. console.table(performance);
  897. }
  898. else {
  899. $.each(performance, function(index, data) {
  900. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  901. });
  902. }
  903. console.groupEnd();
  904. }
  905. performance = [];
  906. }
  907. },
  908. invoke: function(query, passedArguments, context) {
  909. var
  910. object = instance,
  911. maxDepth,
  912. found,
  913. response
  914. ;
  915. passedArguments = passedArguments || queryArguments;
  916. context = element || context;
  917. if(typeof query == 'string' && object !== undefined) {
  918. query = query.split(/[\. ]/);
  919. maxDepth = query.length - 1;
  920. $.each(query, function(depth, value) {
  921. var camelCaseValue = (depth != maxDepth)
  922. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  923. : query
  924. ;
  925. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  926. object = object[camelCaseValue];
  927. }
  928. else if( object[camelCaseValue] !== undefined ) {
  929. found = object[camelCaseValue];
  930. return false;
  931. }
  932. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  933. object = object[value];
  934. }
  935. else if( object[value] !== undefined ) {
  936. found = object[value];
  937. return false;
  938. }
  939. else {
  940. module.error(error.method, query);
  941. return false;
  942. }
  943. });
  944. }
  945. if ( $.isFunction( found ) ) {
  946. response = found.apply(context, passedArguments);
  947. }
  948. else if(found !== undefined) {
  949. response = found;
  950. }
  951. if(Array.isArray(returnedValue)) {
  952. returnedValue.push(response);
  953. }
  954. else if(returnedValue !== undefined) {
  955. returnedValue = [returnedValue, response];
  956. }
  957. else if(response !== undefined) {
  958. returnedValue = response;
  959. }
  960. return found;
  961. }
  962. };
  963. if(methodInvoked) {
  964. if(instance === undefined) {
  965. module.initialize();
  966. }
  967. module.invoke(query);
  968. }
  969. else {
  970. if(instance !== undefined) {
  971. instance.invoke('destroy');
  972. }
  973. module.initialize();
  974. }
  975. })
  976. ;
  977. return (returnedValue !== undefined)
  978. ? returnedValue
  979. : this
  980. ;
  981. };
  982. $.api.settings = {
  983. name : 'API',
  984. namespace : 'api',
  985. debug : false,
  986. verbose : false,
  987. performance : true,
  988. // object containing all templates endpoints
  989. api : {},
  990. // whether to cache responses
  991. cache : true,
  992. // whether new requests should abort previous requests
  993. interruptRequests : true,
  994. // event binding
  995. on : 'auto',
  996. // context for applying state classes
  997. stateContext : false,
  998. // duration for loading state
  999. loadingDuration : 0,
  1000. // whether to hide errors after a period of time
  1001. hideError : 'auto',
  1002. // duration for error state
  1003. errorDuration : 2000,
  1004. // whether parameters should be encoded with encodeURIComponent
  1005. encodeParameters : true,
  1006. // API action to use
  1007. action : false,
  1008. // templated URL to use
  1009. url : false,
  1010. // base URL to apply to all endpoints
  1011. base : '',
  1012. // data that will
  1013. urlData : {},
  1014. // whether to add default data to url data
  1015. defaultData : true,
  1016. // whether to serialize closest form
  1017. serializeForm : false,
  1018. // how long to wait before request should occur
  1019. throttle : 0,
  1020. // whether to throttle first request or only repeated
  1021. throttleFirstRequest : true,
  1022. // standard ajax settings
  1023. method : 'get',
  1024. data : {},
  1025. dataType : 'json',
  1026. // mock response
  1027. mockResponse : false,
  1028. mockResponseAsync : false,
  1029. // aliases for mock
  1030. response : false,
  1031. responseAsync : false,
  1032. // whether onResponse should work with response value without force converting into an object
  1033. rawResponse : false,
  1034. // callbacks before request
  1035. beforeSend : function(settings) { return settings; },
  1036. beforeXHR : function(xhr) {},
  1037. onRequest : function(promise, xhr) {},
  1038. // after request
  1039. onResponse : false, // function(response) { },
  1040. // response was successful, if JSON passed validation
  1041. onSuccess : function(response, $module) {},
  1042. // request finished without aborting
  1043. onComplete : function(response, $module) {},
  1044. // failed JSON success test
  1045. onFailure : function(response, $module) {},
  1046. // server error
  1047. onError : function(errorMessage, $module) {},
  1048. // request aborted
  1049. onAbort : function(errorMessage, $module) {},
  1050. successTest : false,
  1051. // errors
  1052. error : {
  1053. beforeSend : 'The before send function has aborted the request',
  1054. error : 'There was an error with your request',
  1055. exitConditions : 'API Request Aborted. Exit conditions met',
  1056. JSONParse : 'JSON could not be parsed during error handling',
  1057. legacyParameters : 'You are using legacy API success callback names',
  1058. method : 'The method you called is not defined',
  1059. missingAction : 'API action used but no url was defined',
  1060. missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object',
  1061. missingURL : 'No URL specified for api event',
  1062. noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.',
  1063. noStorage : 'Caching responses locally requires session storage',
  1064. parseError : 'There was an error parsing your request',
  1065. requiredParameter : 'Missing a required URL parameter: ',
  1066. statusMessage : 'Server gave an error: ',
  1067. timeout : 'Your request timed out'
  1068. },
  1069. regExp : {
  1070. required : /\{\$*[A-z0-9]+\}/g,
  1071. optional : /\{\/\$*[A-z0-9]+\}/g,
  1072. },
  1073. className: {
  1074. loading : 'loading',
  1075. error : 'error'
  1076. },
  1077. selector: {
  1078. disabled : '.disabled',
  1079. form : 'form'
  1080. },
  1081. metadata: {
  1082. action : 'action',
  1083. url : 'url'
  1084. }
  1085. };
  1086. })( jQuery, window, document );
  1087. /*!
  1088. * # Fomantic-UI - Checkbox
  1089. * http://github.com/fomantic/Fomantic-UI/
  1090. *
  1091. *
  1092. * Released under the MIT license
  1093. * http://opensource.org/licenses/MIT
  1094. *
  1095. */
  1096. ;(function ($, window, document, undefined) {
  1097. 'use strict';
  1098. $.isFunction = $.isFunction || function(obj) {
  1099. return typeof obj === "function" && typeof obj.nodeType !== "number";
  1100. };
  1101. window = (typeof window != 'undefined' && window.Math == Math)
  1102. ? window
  1103. : (typeof self != 'undefined' && self.Math == Math)
  1104. ? self
  1105. : Function('return this')()
  1106. ;
  1107. $.fn.checkbox = function(parameters) {
  1108. var
  1109. $allModules = $(this),
  1110. moduleSelector = $allModules.selector || '',
  1111. time = new Date().getTime(),
  1112. performance = [],
  1113. query = arguments[0],
  1114. methodInvoked = (typeof query == 'string'),
  1115. queryArguments = [].slice.call(arguments, 1),
  1116. returnedValue
  1117. ;
  1118. $allModules
  1119. .each(function() {
  1120. var
  1121. settings = $.extend(true, {}, $.fn.checkbox.settings, parameters),
  1122. className = settings.className,
  1123. namespace = settings.namespace,
  1124. selector = settings.selector,
  1125. error = settings.error,
  1126. eventNamespace = '.' + namespace,
  1127. moduleNamespace = 'module-' + namespace,
  1128. $module = $(this),
  1129. $label = $(this).children(selector.label),
  1130. $input = $(this).children(selector.input),
  1131. input = $input[0],
  1132. initialLoad = false,
  1133. shortcutPressed = false,
  1134. instance = $module.data(moduleNamespace),
  1135. observer,
  1136. element = this,
  1137. module
  1138. ;
  1139. module = {
  1140. initialize: function() {
  1141. module.verbose('Initializing checkbox', settings);
  1142. module.create.label();
  1143. module.bind.events();
  1144. module.set.tabbable();
  1145. module.hide.input();
  1146. module.observeChanges();
  1147. module.instantiate();
  1148. module.setup();
  1149. },
  1150. instantiate: function() {
  1151. module.verbose('Storing instance of module', module);
  1152. instance = module;
  1153. $module
  1154. .data(moduleNamespace, module)
  1155. ;
  1156. },
  1157. destroy: function() {
  1158. module.verbose('Destroying module');
  1159. module.unbind.events();
  1160. module.show.input();
  1161. $module.removeData(moduleNamespace);
  1162. },
  1163. fix: {
  1164. reference: function() {
  1165. if( $module.is(selector.input) ) {
  1166. module.debug('Behavior called on <input> adjusting invoked element');
  1167. $module = $module.closest(selector.checkbox);
  1168. module.refresh();
  1169. }
  1170. }
  1171. },
  1172. setup: function() {
  1173. module.set.initialLoad();
  1174. if( module.is.indeterminate() ) {
  1175. module.debug('Initial value is indeterminate');
  1176. module.indeterminate();
  1177. }
  1178. else if( module.is.checked() ) {
  1179. module.debug('Initial value is checked');
  1180. module.check();
  1181. }
  1182. else {
  1183. module.debug('Initial value is unchecked');
  1184. module.uncheck();
  1185. }
  1186. module.remove.initialLoad();
  1187. },
  1188. refresh: function() {
  1189. $label = $module.children(selector.label);
  1190. $input = $module.children(selector.input);
  1191. input = $input[0];
  1192. },
  1193. hide: {
  1194. input: function() {
  1195. module.verbose('Modifying <input> z-index to be unselectable');
  1196. $input.addClass(className.hidden);
  1197. }
  1198. },
  1199. show: {
  1200. input: function() {
  1201. module.verbose('Modifying <input> z-index to be selectable');
  1202. $input.removeClass(className.hidden);
  1203. }
  1204. },
  1205. observeChanges: function() {
  1206. if('MutationObserver' in window) {
  1207. observer = new MutationObserver(function(mutations) {
  1208. module.debug('DOM tree modified, updating selector cache');
  1209. module.refresh();
  1210. });
  1211. observer.observe(element, {
  1212. childList : true,
  1213. subtree : true
  1214. });
  1215. module.debug('Setting up mutation observer', observer);
  1216. }
  1217. },
  1218. attachEvents: function(selector, event) {
  1219. var
  1220. $element = $(selector)
  1221. ;
  1222. event = $.isFunction(module[event])
  1223. ? module[event]
  1224. : module.toggle
  1225. ;
  1226. if($element.length > 0) {
  1227. module.debug('Attaching checkbox events to element', selector, event);
  1228. $element
  1229. .on('click' + eventNamespace, event)
  1230. ;
  1231. }
  1232. else {
  1233. module.error(error.notFound);
  1234. }
  1235. },
  1236. preventDefaultOnInputTarget: function() {
  1237. if(typeof event !== 'undefined' && event !== null && $(event.target).is(selector.input)) {
  1238. module.verbose('Preventing default check action after manual check action');
  1239. event.preventDefault();
  1240. }
  1241. },
  1242. event: {
  1243. change: function(event) {
  1244. if( !module.should.ignoreCallbacks() ) {
  1245. settings.onChange.call(input);
  1246. }
  1247. },
  1248. click: function(event) {
  1249. var
  1250. $target = $(event.target)
  1251. ;
  1252. if( $target.is(selector.input) ) {
  1253. module.verbose('Using default check action on initialized checkbox');
  1254. return;
  1255. }
  1256. if( $target.is(selector.link) ) {
  1257. module.debug('Clicking link inside checkbox, skipping toggle');
  1258. return;
  1259. }
  1260. module.toggle();
  1261. $input.focus();
  1262. event.preventDefault();
  1263. },
  1264. keydown: function(event) {
  1265. var
  1266. key = event.which,
  1267. keyCode = {
  1268. enter : 13,
  1269. space : 32,
  1270. escape : 27,
  1271. left : 37,
  1272. up : 38,
  1273. right : 39,
  1274. down : 40
  1275. }
  1276. ;
  1277. var r = module.get.radios(),
  1278. rIndex = r.index($module),
  1279. rLen = r.length,
  1280. checkIndex = false;
  1281. if(key == keyCode.left || key == keyCode.up) {
  1282. checkIndex = (rIndex === 0 ? rLen : rIndex) - 1;
  1283. } else if(key == keyCode.right || key == keyCode.down) {
  1284. checkIndex = rIndex === rLen-1 ? 0 : rIndex+1;
  1285. }
  1286. if (!module.should.ignoreCallbacks() && checkIndex !== false) {
  1287. if(settings.beforeUnchecked.apply(input)===false) {
  1288. module.verbose('Option not allowed to be unchecked, cancelling key navigation');
  1289. return false;
  1290. }
  1291. if (settings.beforeChecked.apply($(r[checkIndex]).children(selector.input)[0])===false) {
  1292. module.verbose('Next option should not allow check, cancelling key navigation');
  1293. return false;
  1294. }
  1295. }
  1296. if(key == keyCode.escape) {
  1297. module.verbose('Escape key pressed blurring field');
  1298. $input.blur();
  1299. shortcutPressed = true;
  1300. }
  1301. else if(!event.ctrlKey && ( key == keyCode.space || (key == keyCode.enter && settings.enableEnterKey)) ) {
  1302. module.verbose('Enter/space key pressed, toggling checkbox');
  1303. module.toggle();
  1304. shortcutPressed = true;
  1305. }
  1306. else {
  1307. shortcutPressed = false;
  1308. }
  1309. },
  1310. keyup: function(event) {
  1311. if(shortcutPressed) {
  1312. event.preventDefault();
  1313. }
  1314. }
  1315. },
  1316. check: function() {
  1317. if( !module.should.allowCheck() ) {
  1318. return;
  1319. }
  1320. module.debug('Checking checkbox', $input);
  1321. module.set.checked();
  1322. if( !module.should.ignoreCallbacks() ) {
  1323. settings.onChecked.call(input);
  1324. module.trigger.change();
  1325. }
  1326. module.preventDefaultOnInputTarget();
  1327. },
  1328. uncheck: function() {
  1329. if( !module.should.allowUncheck() ) {
  1330. return;
  1331. }
  1332. module.debug('Unchecking checkbox');
  1333. module.set.unchecked();
  1334. if( !module.should.ignoreCallbacks() ) {
  1335. settings.onUnchecked.call(input);
  1336. module.trigger.change();
  1337. }
  1338. module.preventDefaultOnInputTarget();
  1339. },
  1340. indeterminate: function() {
  1341. if( module.should.allowIndeterminate() ) {
  1342. module.debug('Checkbox is already indeterminate');
  1343. return;
  1344. }
  1345. module.debug('Making checkbox indeterminate');
  1346. module.set.indeterminate();
  1347. if( !module.should.ignoreCallbacks() ) {
  1348. settings.onIndeterminate.call(input);
  1349. module.trigger.change();
  1350. }
  1351. },
  1352. determinate: function() {
  1353. if( module.should.allowDeterminate() ) {
  1354. module.debug('Checkbox is already determinate');
  1355. return;
  1356. }
  1357. module.debug('Making checkbox determinate');
  1358. module.set.determinate();
  1359. if( !module.should.ignoreCallbacks() ) {
  1360. settings.onDeterminate.call(input);
  1361. module.trigger.change();
  1362. }
  1363. },
  1364. enable: function() {
  1365. if( module.is.enabled() ) {
  1366. module.debug('Checkbox is already enabled');
  1367. return;
  1368. }
  1369. module.debug('Enabling checkbox');
  1370. module.set.enabled();
  1371. if( !module.should.ignoreCallbacks() ) {
  1372. settings.onEnable.call(input);
  1373. // preserve legacy callbacks
  1374. settings.onEnabled.call(input);
  1375. module.trigger.change();
  1376. }
  1377. },
  1378. disable: function() {
  1379. if( module.is.disabled() ) {
  1380. module.debug('Checkbox is already disabled');
  1381. return;
  1382. }
  1383. module.debug('Disabling checkbox');
  1384. module.set.disabled();
  1385. if( !module.should.ignoreCallbacks() ) {
  1386. settings.onDisable.call(input);
  1387. // preserve legacy callbacks
  1388. settings.onDisabled.call(input);
  1389. module.trigger.change();
  1390. }
  1391. },
  1392. get: {
  1393. radios: function() {
  1394. var
  1395. name = module.get.name()
  1396. ;
  1397. return $('input[name="' + name + '"]').closest(selector.checkbox);
  1398. },
  1399. otherRadios: function() {
  1400. return module.get.radios().not($module);
  1401. },
  1402. name: function() {
  1403. return $input.attr('name');
  1404. }
  1405. },
  1406. is: {
  1407. initialLoad: function() {
  1408. return initialLoad;
  1409. },
  1410. radio: function() {
  1411. return ($input.hasClass(className.radio) || $input.attr('type') == 'radio');
  1412. },
  1413. indeterminate: function() {
  1414. return $input.prop('indeterminate') !== undefined && $input.prop('indeterminate');
  1415. },
  1416. checked: function() {
  1417. return $input.prop('checked') !== undefined && $input.prop('checked');
  1418. },
  1419. disabled: function() {
  1420. return $input.prop('disabled') !== undefined && $input.prop('disabled');
  1421. },
  1422. enabled: function() {
  1423. return !module.is.disabled();
  1424. },
  1425. determinate: function() {
  1426. return !module.is.indeterminate();
  1427. },
  1428. unchecked: function() {
  1429. return !module.is.checked();
  1430. }
  1431. },
  1432. should: {
  1433. allowCheck: function() {
  1434. if(module.is.determinate() && module.is.checked() && !module.is.initialLoad() ) {
  1435. module.debug('Should not allow check, checkbox is already checked');
  1436. return false;
  1437. }
  1438. if(!module.should.ignoreCallbacks() && settings.beforeChecked.apply(input) === false) {
  1439. module.debug('Should not allow check, beforeChecked cancelled');
  1440. return false;
  1441. }
  1442. return true;
  1443. },
  1444. allowUncheck: function() {
  1445. if(module.is.determinate() && module.is.unchecked() && !module.is.initialLoad() ) {
  1446. module.debug('Should not allow uncheck, checkbox is already unchecked');
  1447. return false;
  1448. }
  1449. if(!module.should.ignoreCallbacks() && settings.beforeUnchecked.apply(input) === false) {
  1450. module.debug('Should not allow uncheck, beforeUnchecked cancelled');
  1451. return false;
  1452. }
  1453. return true;
  1454. },
  1455. allowIndeterminate: function() {
  1456. if(module.is.indeterminate() && !module.is.initialLoad() ) {
  1457. module.debug('Should not allow indeterminate, checkbox is already indeterminate');
  1458. return false;
  1459. }
  1460. if(!module.should.ignoreCallbacks() && settings.beforeIndeterminate.apply(input) === false) {
  1461. module.debug('Should not allow indeterminate, beforeIndeterminate cancelled');
  1462. return false;
  1463. }
  1464. return true;
  1465. },
  1466. allowDeterminate: function() {
  1467. if(module.is.determinate() && !module.is.initialLoad() ) {
  1468. module.debug('Should not allow determinate, checkbox is already determinate');
  1469. return false;
  1470. }
  1471. if(!module.should.ignoreCallbacks() && settings.beforeDeterminate.apply(input) === false) {
  1472. module.debug('Should not allow determinate, beforeDeterminate cancelled');
  1473. return false;
  1474. }
  1475. return true;
  1476. },
  1477. ignoreCallbacks: function() {
  1478. return (initialLoad && !settings.fireOnInit);
  1479. }
  1480. },
  1481. can: {
  1482. change: function() {
  1483. return !( $module.hasClass(className.disabled) || $module.hasClass(className.readOnly) || $input.prop('disabled') || $input.prop('readonly') );
  1484. },
  1485. uncheck: function() {
  1486. return (typeof settings.uncheckable === 'boolean')
  1487. ? settings.uncheckable
  1488. : !module.is.radio()
  1489. ;
  1490. }
  1491. },
  1492. set: {
  1493. initialLoad: function() {
  1494. initialLoad = true;
  1495. },
  1496. checked: function() {
  1497. module.verbose('Setting class to checked');
  1498. $module
  1499. .removeClass(className.indeterminate)
  1500. .addClass(className.checked)
  1501. ;
  1502. if( module.is.radio() ) {
  1503. module.uncheckOthers();
  1504. }
  1505. if(!module.is.indeterminate() && module.is.checked()) {
  1506. module.debug('Input is already checked, skipping input property change');
  1507. return;
  1508. }
  1509. module.verbose('Setting state to checked', input);
  1510. $input
  1511. .prop('indeterminate', false)
  1512. .prop('checked', true)
  1513. ;
  1514. },
  1515. unchecked: function() {
  1516. module.verbose('Removing checked class');
  1517. $module
  1518. .removeClass(className.indeterminate)
  1519. .removeClass(className.checked)
  1520. ;
  1521. if(!module.is.indeterminate() && module.is.unchecked() ) {
  1522. module.debug('Input is already unchecked');
  1523. return;
  1524. }
  1525. module.debug('Setting state to unchecked');
  1526. $input
  1527. .prop('indeterminate', false)
  1528. .prop('checked', false)
  1529. ;
  1530. },
  1531. indeterminate: function() {
  1532. module.verbose('Setting class to indeterminate');
  1533. $module
  1534. .addClass(className.indeterminate)
  1535. ;
  1536. if( module.is.indeterminate() ) {
  1537. module.debug('Input is already indeterminate, skipping input property change');
  1538. return;
  1539. }
  1540. module.debug('Setting state to indeterminate');
  1541. $input
  1542. .prop('indeterminate', true)
  1543. ;
  1544. },
  1545. determinate: function() {
  1546. module.verbose('Removing indeterminate class');
  1547. $module
  1548. .removeClass(className.indeterminate)
  1549. ;
  1550. if( module.is.determinate() ) {
  1551. module.debug('Input is already determinate, skipping input property change');
  1552. return;
  1553. }
  1554. module.debug('Setting state to determinate');
  1555. $input
  1556. .prop('indeterminate', false)
  1557. ;
  1558. },
  1559. disabled: function() {
  1560. module.verbose('Setting class to disabled');
  1561. $module
  1562. .addClass(className.disabled)
  1563. ;
  1564. if( module.is.disabled() ) {
  1565. module.debug('Input is already disabled, skipping input property change');
  1566. return;
  1567. }
  1568. module.debug('Setting state to disabled');
  1569. $input
  1570. .prop('disabled', 'disabled')
  1571. ;
  1572. },
  1573. enabled: function() {
  1574. module.verbose('Removing disabled class');
  1575. $module.removeClass(className.disabled);
  1576. if( module.is.enabled() ) {
  1577. module.debug('Input is already enabled, skipping input property change');
  1578. return;
  1579. }
  1580. module.debug('Setting state to enabled');
  1581. $input
  1582. .prop('disabled', false)
  1583. ;
  1584. },
  1585. tabbable: function() {
  1586. module.verbose('Adding tabindex to checkbox');
  1587. if( $input.attr('tabindex') === undefined) {
  1588. $input.attr('tabindex', 0);
  1589. }
  1590. }
  1591. },
  1592. remove: {
  1593. initialLoad: function() {
  1594. initialLoad = false;
  1595. }
  1596. },
  1597. trigger: {
  1598. change: function() {
  1599. var
  1600. inputElement = $input[0]
  1601. ;
  1602. if(inputElement) {
  1603. var events = document.createEvent('HTMLEvents');
  1604. module.verbose('Triggering native change event');
  1605. events.initEvent('change', true, false);
  1606. inputElement.dispatchEvent(events);
  1607. }
  1608. }
  1609. },
  1610. create: {
  1611. label: function() {
  1612. if($input.prevAll(selector.label).length > 0) {
  1613. $input.prev(selector.label).detach().insertAfter($input);
  1614. module.debug('Moving existing label', $label);
  1615. }
  1616. else if( !module.has.label() ) {
  1617. $label = $('<label>').insertAfter($input);
  1618. module.debug('Creating label', $label);
  1619. }
  1620. }
  1621. },
  1622. has: {
  1623. label: function() {
  1624. return ($label.length > 0);
  1625. }
  1626. },
  1627. bind: {
  1628. events: function() {
  1629. module.verbose('Attaching checkbox events');
  1630. $module
  1631. .on('click' + eventNamespace, module.event.click)
  1632. .on('change' + eventNamespace, module.event.change)
  1633. .on('keydown' + eventNamespace, selector.input, module.event.keydown)
  1634. .on('keyup' + eventNamespace, selector.input, module.event.keyup)
  1635. ;
  1636. }
  1637. },
  1638. unbind: {
  1639. events: function() {
  1640. module.debug('Removing events');
  1641. $module
  1642. .off(eventNamespace)
  1643. ;
  1644. }
  1645. },
  1646. uncheckOthers: function() {
  1647. var
  1648. $radios = module.get.otherRadios()
  1649. ;
  1650. module.debug('Unchecking other radios', $radios);
  1651. $radios.removeClass(className.checked);
  1652. },
  1653. toggle: function() {
  1654. if( !module.can.change() ) {
  1655. if(!module.is.radio()) {
  1656. module.debug('Checkbox is read-only or disabled, ignoring toggle');
  1657. }
  1658. return;
  1659. }
  1660. if( module.is.indeterminate() || module.is.unchecked() ) {
  1661. module.debug('Currently unchecked');
  1662. module.check();
  1663. }
  1664. else if( module.is.checked() && module.can.uncheck() ) {
  1665. module.debug('Currently checked');
  1666. module.uncheck();
  1667. }
  1668. },
  1669. setting: function(name, value) {
  1670. module.debug('Changing setting', name, value);
  1671. if( $.isPlainObject(name) ) {
  1672. $.extend(true, settings, name);
  1673. }
  1674. else if(value !== undefined) {
  1675. if($.isPlainObject(settings[name])) {
  1676. $.extend(true, settings[name], value);
  1677. }
  1678. else {
  1679. settings[name] = value;
  1680. }
  1681. }
  1682. else {
  1683. return settings[name];
  1684. }
  1685. },
  1686. internal: function(name, value) {
  1687. if( $.isPlainObject(name) ) {
  1688. $.extend(true, module, name);
  1689. }
  1690. else if(value !== undefined) {
  1691. module[name] = value;
  1692. }
  1693. else {
  1694. return module[name];
  1695. }
  1696. },
  1697. debug: function() {
  1698. if(!settings.silent && settings.debug) {
  1699. if(settings.performance) {
  1700. module.performance.log(arguments);
  1701. }
  1702. else {
  1703. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1704. module.debug.apply(console, arguments);
  1705. }
  1706. }
  1707. },
  1708. verbose: function() {
  1709. if(!settings.silent && settings.verbose && settings.debug) {
  1710. if(settings.performance) {
  1711. module.performance.log(arguments);
  1712. }
  1713. else {
  1714. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1715. module.verbose.apply(console, arguments);
  1716. }
  1717. }
  1718. },
  1719. error: function() {
  1720. if(!settings.silent) {
  1721. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  1722. module.error.apply(console, arguments);
  1723. }
  1724. },
  1725. performance: {
  1726. log: function(message) {
  1727. var
  1728. currentTime,
  1729. executionTime,
  1730. previousTime
  1731. ;
  1732. if(settings.performance) {
  1733. currentTime = new Date().getTime();
  1734. previousTime = time || currentTime;
  1735. executionTime = currentTime - previousTime;
  1736. time = currentTime;
  1737. performance.push({
  1738. 'Name' : message[0],
  1739. 'Arguments' : [].slice.call(message, 1) || '',
  1740. 'Element' : element,
  1741. 'Execution Time' : executionTime
  1742. });
  1743. }
  1744. clearTimeout(module.performance.timer);
  1745. module.performance.timer = setTimeout(module.performance.display, 500);
  1746. },
  1747. display: function() {
  1748. var
  1749. title = settings.name + ':',
  1750. totalTime = 0
  1751. ;
  1752. time = false;
  1753. clearTimeout(module.performance.timer);
  1754. $.each(performance, function(index, data) {
  1755. totalTime += data['Execution Time'];
  1756. });
  1757. title += ' ' + totalTime + 'ms';
  1758. if(moduleSelector) {
  1759. title += ' \'' + moduleSelector + '\'';
  1760. }
  1761. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  1762. console.groupCollapsed(title);
  1763. if(console.table) {
  1764. console.table(performance);
  1765. }
  1766. else {
  1767. $.each(performance, function(index, data) {
  1768. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  1769. });
  1770. }
  1771. console.groupEnd();
  1772. }
  1773. performance = [];
  1774. }
  1775. },
  1776. invoke: function(query, passedArguments, context) {
  1777. var
  1778. object = instance,
  1779. maxDepth,
  1780. found,
  1781. response
  1782. ;
  1783. passedArguments = passedArguments || queryArguments;
  1784. context = element || context;
  1785. if(typeof query == 'string' && object !== undefined) {
  1786. query = query.split(/[\. ]/);
  1787. maxDepth = query.length - 1;
  1788. $.each(query, function(depth, value) {
  1789. var camelCaseValue = (depth != maxDepth)
  1790. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  1791. : query
  1792. ;
  1793. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  1794. object = object[camelCaseValue];
  1795. }
  1796. else if( object[camelCaseValue] !== undefined ) {
  1797. found = object[camelCaseValue];
  1798. return false;
  1799. }
  1800. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  1801. object = object[value];
  1802. }
  1803. else if( object[value] !== undefined ) {
  1804. found = object[value];
  1805. return false;
  1806. }
  1807. else {
  1808. module.error(error.method, query);
  1809. return false;
  1810. }
  1811. });
  1812. }
  1813. if ( $.isFunction( found ) ) {
  1814. response = found.apply(context, passedArguments);
  1815. }
  1816. else if(found !== undefined) {
  1817. response = found;
  1818. }
  1819. if(Array.isArray(returnedValue)) {
  1820. returnedValue.push(response);
  1821. }
  1822. else if(returnedValue !== undefined) {
  1823. returnedValue = [returnedValue, response];
  1824. }
  1825. else if(response !== undefined) {
  1826. returnedValue = response;
  1827. }
  1828. return found;
  1829. }
  1830. };
  1831. if(methodInvoked) {
  1832. if(instance === undefined) {
  1833. module.initialize();
  1834. }
  1835. module.invoke(query);
  1836. }
  1837. else {
  1838. if(instance !== undefined) {
  1839. instance.invoke('destroy');
  1840. }
  1841. module.initialize();
  1842. }
  1843. })
  1844. ;
  1845. return (returnedValue !== undefined)
  1846. ? returnedValue
  1847. : this
  1848. ;
  1849. };
  1850. $.fn.checkbox.settings = {
  1851. name : 'Checkbox',
  1852. namespace : 'checkbox',
  1853. silent : false,
  1854. debug : false,
  1855. verbose : true,
  1856. performance : true,
  1857. // delegated event context
  1858. uncheckable : 'auto',
  1859. fireOnInit : false,
  1860. enableEnterKey : true,
  1861. onChange : function(){},
  1862. beforeChecked : function(){},
  1863. beforeUnchecked : function(){},
  1864. beforeDeterminate : function(){},
  1865. beforeIndeterminate : function(){},
  1866. onChecked : function(){},
  1867. onUnchecked : function(){},
  1868. onDeterminate : function() {},
  1869. onIndeterminate : function() {},
  1870. onEnable : function(){},
  1871. onDisable : function(){},
  1872. // preserve misspelled callbacks (will be removed in 3.0)
  1873. onEnabled : function(){},
  1874. onDisabled : function(){},
  1875. className : {
  1876. checked : 'checked',
  1877. indeterminate : 'indeterminate',
  1878. disabled : 'disabled',
  1879. hidden : 'hidden',
  1880. radio : 'radio',
  1881. readOnly : 'read-only'
  1882. },
  1883. error : {
  1884. method : 'The method you called is not defined'
  1885. },
  1886. selector : {
  1887. checkbox : '.ui.checkbox',
  1888. label : 'label, .box',
  1889. input : 'input[type="checkbox"], input[type="radio"]',
  1890. link : 'a[href]'
  1891. }
  1892. };
  1893. })( jQuery, window, document );
  1894. /*!
  1895. * # Fomantic-UI - Dimmer
  1896. * http://github.com/fomantic/Fomantic-UI/
  1897. *
  1898. *
  1899. * Released under the MIT license
  1900. * http://opensource.org/licenses/MIT
  1901. *
  1902. */
  1903. ;(function ($, window, document, undefined) {
  1904. 'use strict';
  1905. $.isFunction = $.isFunction || function(obj) {
  1906. return typeof obj === "function" && typeof obj.nodeType !== "number";
  1907. };
  1908. window = (typeof window != 'undefined' && window.Math == Math)
  1909. ? window
  1910. : (typeof self != 'undefined' && self.Math == Math)
  1911. ? self
  1912. : Function('return this')()
  1913. ;
  1914. $.fn.dimmer = function(parameters) {
  1915. var
  1916. $allModules = $(this),
  1917. time = new Date().getTime(),
  1918. performance = [],
  1919. query = arguments[0],
  1920. methodInvoked = (typeof query == 'string'),
  1921. queryArguments = [].slice.call(arguments, 1),
  1922. returnedValue
  1923. ;
  1924. $allModules
  1925. .each(function() {
  1926. var
  1927. settings = ( $.isPlainObject(parameters) )
  1928. ? $.extend(true, {}, $.fn.dimmer.settings, parameters)
  1929. : $.extend({}, $.fn.dimmer.settings),
  1930. selector = settings.selector,
  1931. namespace = settings.namespace,
  1932. className = settings.className,
  1933. error = settings.error,
  1934. eventNamespace = '.' + namespace,
  1935. moduleNamespace = 'module-' + namespace,
  1936. moduleSelector = $allModules.selector || '',
  1937. clickEvent = ('ontouchstart' in document.documentElement)
  1938. ? 'touchstart'
  1939. : 'click',
  1940. $module = $(this),
  1941. $dimmer,
  1942. $dimmable,
  1943. element = this,
  1944. instance = $module.data(moduleNamespace),
  1945. module
  1946. ;
  1947. module = {
  1948. preinitialize: function() {
  1949. if( module.is.dimmer() ) {
  1950. $dimmable = $module.parent();
  1951. $dimmer = $module;
  1952. }
  1953. else {
  1954. $dimmable = $module;
  1955. if( module.has.dimmer() ) {
  1956. if(settings.dimmerName) {
  1957. $dimmer = $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName);
  1958. }
  1959. else {
  1960. $dimmer = $dimmable.find(selector.dimmer);
  1961. }
  1962. }
  1963. else {
  1964. $dimmer = module.create();
  1965. }
  1966. }
  1967. },
  1968. initialize: function() {
  1969. module.debug('Initializing dimmer', settings);
  1970. module.bind.events();
  1971. module.set.dimmable();
  1972. module.instantiate();
  1973. },
  1974. instantiate: function() {
  1975. module.verbose('Storing instance of module', module);
  1976. instance = module;
  1977. $module
  1978. .data(moduleNamespace, instance)
  1979. ;
  1980. },
  1981. destroy: function() {
  1982. module.verbose('Destroying previous module', $dimmer);
  1983. module.unbind.events();
  1984. module.remove.variation();
  1985. $dimmable
  1986. .off(eventNamespace)
  1987. ;
  1988. },
  1989. bind: {
  1990. events: function() {
  1991. if(settings.on == 'hover') {
  1992. $dimmable
  1993. .on('mouseenter' + eventNamespace, module.show)
  1994. .on('mouseleave' + eventNamespace, module.hide)
  1995. ;
  1996. }
  1997. else if(settings.on == 'click') {
  1998. $dimmable
  1999. .on(clickEvent + eventNamespace, module.toggle)
  2000. ;
  2001. }
  2002. if( module.is.page() ) {
  2003. module.debug('Setting as a page dimmer', $dimmable);
  2004. module.set.pageDimmer();
  2005. }
  2006. if( module.is.closable() ) {
  2007. module.verbose('Adding dimmer close event', $dimmer);
  2008. $dimmable
  2009. .on(clickEvent + eventNamespace, selector.dimmer, module.event.click)
  2010. ;
  2011. }
  2012. }
  2013. },
  2014. unbind: {
  2015. events: function() {
  2016. $module
  2017. .removeData(moduleNamespace)
  2018. ;
  2019. $dimmable
  2020. .off(eventNamespace)
  2021. ;
  2022. }
  2023. },
  2024. event: {
  2025. click: function(event) {
  2026. module.verbose('Determining if event occured on dimmer', event);
  2027. if( $dimmer.find(event.target).length === 0 || $(event.target).is(selector.content) ) {
  2028. module.hide();
  2029. event.stopImmediatePropagation();
  2030. }
  2031. }
  2032. },
  2033. addContent: function(element) {
  2034. var
  2035. $content = $(element)
  2036. ;
  2037. module.debug('Add content to dimmer', $content);
  2038. if($content.parent()[0] !== $dimmer[0]) {
  2039. $content.detach().appendTo($dimmer);
  2040. }
  2041. },
  2042. create: function() {
  2043. var
  2044. $element = $( settings.template.dimmer(settings) )
  2045. ;
  2046. if(settings.dimmerName) {
  2047. module.debug('Creating named dimmer', settings.dimmerName);
  2048. $element.addClass(settings.dimmerName);
  2049. }
  2050. $element
  2051. .appendTo($dimmable)
  2052. ;
  2053. return $element;
  2054. },
  2055. show: function(callback) {
  2056. callback = $.isFunction(callback)
  2057. ? callback
  2058. : function(){}
  2059. ;
  2060. module.debug('Showing dimmer', $dimmer, settings);
  2061. module.set.variation();
  2062. if( (!module.is.dimmed() || module.is.animating()) && module.is.enabled() ) {
  2063. module.animate.show(callback);
  2064. settings.onShow.call(element);
  2065. settings.onChange.call(element);
  2066. }
  2067. else {
  2068. module.debug('Dimmer is already shown or disabled');
  2069. }
  2070. },
  2071. hide: function(callback) {
  2072. callback = $.isFunction(callback)
  2073. ? callback
  2074. : function(){}
  2075. ;
  2076. if( module.is.dimmed() || module.is.animating() ) {
  2077. module.debug('Hiding dimmer', $dimmer);
  2078. module.animate.hide(callback);
  2079. settings.onHide.call(element);
  2080. settings.onChange.call(element);
  2081. }
  2082. else {
  2083. module.debug('Dimmer is not visible');
  2084. }
  2085. },
  2086. toggle: function() {
  2087. module.verbose('Toggling dimmer visibility', $dimmer);
  2088. if( !module.is.dimmed() ) {
  2089. module.show();
  2090. }
  2091. else {
  2092. if ( module.is.closable() ) {
  2093. module.hide();
  2094. }
  2095. }
  2096. },
  2097. animate: {
  2098. show: function(callback) {
  2099. callback = $.isFunction(callback)
  2100. ? callback
  2101. : function(){}
  2102. ;
  2103. if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
  2104. if(settings.useFlex) {
  2105. module.debug('Using flex dimmer');
  2106. module.remove.legacy();
  2107. }
  2108. else {
  2109. module.debug('Using legacy non-flex dimmer');
  2110. module.set.legacy();
  2111. }
  2112. if(settings.opacity !== 'auto') {
  2113. module.set.opacity();
  2114. }
  2115. $dimmer
  2116. .transition({
  2117. displayType : settings.useFlex
  2118. ? 'flex'
  2119. : 'block',
  2120. animation : settings.transition + ' in',
  2121. queue : false,
  2122. duration : module.get.duration(),
  2123. useFailSafe : true,
  2124. onStart : function() {
  2125. module.set.dimmed();
  2126. },
  2127. onComplete : function() {
  2128. module.set.active();
  2129. callback();
  2130. }
  2131. })
  2132. ;
  2133. }
  2134. else {
  2135. module.verbose('Showing dimmer animation with javascript');
  2136. module.set.dimmed();
  2137. if(settings.opacity == 'auto') {
  2138. settings.opacity = 0.8;
  2139. }
  2140. $dimmer
  2141. .stop()
  2142. .css({
  2143. opacity : 0,
  2144. width : '100%',
  2145. height : '100%'
  2146. })
  2147. .fadeTo(module.get.duration(), settings.opacity, function() {
  2148. $dimmer.removeAttr('style');
  2149. module.set.active();
  2150. callback();
  2151. })
  2152. ;
  2153. }
  2154. },
  2155. hide: function(callback) {
  2156. callback = $.isFunction(callback)
  2157. ? callback
  2158. : function(){}
  2159. ;
  2160. if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
  2161. module.verbose('Hiding dimmer with css');
  2162. $dimmer
  2163. .transition({
  2164. displayType : settings.useFlex
  2165. ? 'flex'
  2166. : 'block',
  2167. animation : settings.transition + ' out',
  2168. queue : false,
  2169. duration : module.get.duration(),
  2170. useFailSafe : true,
  2171. onComplete : function() {
  2172. module.remove.dimmed();
  2173. module.remove.variation();
  2174. module.remove.active();
  2175. callback();
  2176. }
  2177. })
  2178. ;
  2179. }
  2180. else {
  2181. module.verbose('Hiding dimmer with javascript');
  2182. $dimmer
  2183. .stop()
  2184. .fadeOut(module.get.duration(), function() {
  2185. module.remove.dimmed();
  2186. module.remove.active();
  2187. $dimmer.removeAttr('style');
  2188. callback();
  2189. })
  2190. ;
  2191. }
  2192. }
  2193. },
  2194. get: {
  2195. dimmer: function() {
  2196. return $dimmer;
  2197. },
  2198. duration: function() {
  2199. if(typeof settings.duration == 'object') {
  2200. if( module.is.active() ) {
  2201. return settings.duration.hide;
  2202. }
  2203. else {
  2204. return settings.duration.show;
  2205. }
  2206. }
  2207. return settings.duration;
  2208. }
  2209. },
  2210. has: {
  2211. dimmer: function() {
  2212. if(settings.dimmerName) {
  2213. return ($module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0);
  2214. }
  2215. else {
  2216. return ( $module.find(selector.dimmer).length > 0 );
  2217. }
  2218. }
  2219. },
  2220. is: {
  2221. active: function() {
  2222. return $dimmer.hasClass(className.active);
  2223. },
  2224. animating: function() {
  2225. return ( $dimmer.is(':animated') || $dimmer.hasClass(className.animating) );
  2226. },
  2227. closable: function() {
  2228. if(settings.closable == 'auto') {
  2229. if(settings.on == 'hover') {
  2230. return false;
  2231. }
  2232. return true;
  2233. }
  2234. return settings.closable;
  2235. },
  2236. dimmer: function() {
  2237. return $module.hasClass(className.dimmer);
  2238. },
  2239. dimmable: function() {
  2240. return $module.hasClass(className.dimmable);
  2241. },
  2242. dimmed: function() {
  2243. return $dimmable.hasClass(className.dimmed);
  2244. },
  2245. disabled: function() {
  2246. return $dimmable.hasClass(className.disabled);
  2247. },
  2248. enabled: function() {
  2249. return !module.is.disabled();
  2250. },
  2251. page: function () {
  2252. return $dimmable.is('body');
  2253. },
  2254. pageDimmer: function() {
  2255. return $dimmer.hasClass(className.pageDimmer);
  2256. }
  2257. },
  2258. can: {
  2259. show: function() {
  2260. return !$dimmer.hasClass(className.disabled);
  2261. }
  2262. },
  2263. set: {
  2264. opacity: function(opacity) {
  2265. var
  2266. color = $dimmer.css('background-color'),
  2267. colorArray = color.split(','),
  2268. isRGB = (colorArray && colorArray.length >= 3)
  2269. ;
  2270. opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity;
  2271. if(isRGB) {
  2272. colorArray[2] = colorArray[2].replace(')','');
  2273. colorArray[3] = opacity + ')';
  2274. color = colorArray.join(',');
  2275. }
  2276. else {
  2277. color = 'rgba(0, 0, 0, ' + opacity + ')';
  2278. }
  2279. module.debug('Setting opacity to', opacity);
  2280. $dimmer.css('background-color', color);
  2281. },
  2282. legacy: function() {
  2283. $dimmer.addClass(className.legacy);
  2284. },
  2285. active: function() {
  2286. $dimmer.addClass(className.active);
  2287. },
  2288. dimmable: function() {
  2289. $dimmable.addClass(className.dimmable);
  2290. },
  2291. dimmed: function() {
  2292. $dimmable.addClass(className.dimmed);
  2293. },
  2294. pageDimmer: function() {
  2295. $dimmer.addClass(className.pageDimmer);
  2296. },
  2297. disabled: function() {
  2298. $dimmer.addClass(className.disabled);
  2299. },
  2300. variation: function(variation) {
  2301. variation = variation || settings.variation;
  2302. if(variation) {
  2303. $dimmer.addClass(variation);
  2304. }
  2305. }
  2306. },
  2307. remove: {
  2308. active: function() {
  2309. $dimmer
  2310. .removeClass(className.active)
  2311. ;
  2312. },
  2313. legacy: function() {
  2314. $dimmer.removeClass(className.legacy);
  2315. },
  2316. dimmed: function() {
  2317. $dimmable.removeClass(className.dimmed);
  2318. },
  2319. disabled: function() {
  2320. $dimmer.removeClass(className.disabled);
  2321. },
  2322. variation: function(variation) {
  2323. variation = variation || settings.variation;
  2324. if(variation) {
  2325. $dimmer.removeClass(variation);
  2326. }
  2327. }
  2328. },
  2329. setting: function(name, value) {
  2330. module.debug('Changing setting', name, value);
  2331. if( $.isPlainObject(name) ) {
  2332. $.extend(true, settings, name);
  2333. }
  2334. else if(value !== undefined) {
  2335. if($.isPlainObject(settings[name])) {
  2336. $.extend(true, settings[name], value);
  2337. }
  2338. else {
  2339. settings[name] = value;
  2340. }
  2341. }
  2342. else {
  2343. return settings[name];
  2344. }
  2345. },
  2346. internal: function(name, value) {
  2347. if( $.isPlainObject(name) ) {
  2348. $.extend(true, module, name);
  2349. }
  2350. else if(value !== undefined) {
  2351. module[name] = value;
  2352. }
  2353. else {
  2354. return module[name];
  2355. }
  2356. },
  2357. debug: function() {
  2358. if(!settings.silent && settings.debug) {
  2359. if(settings.performance) {
  2360. module.performance.log(arguments);
  2361. }
  2362. else {
  2363. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  2364. module.debug.apply(console, arguments);
  2365. }
  2366. }
  2367. },
  2368. verbose: function() {
  2369. if(!settings.silent && settings.verbose && settings.debug) {
  2370. if(settings.performance) {
  2371. module.performance.log(arguments);
  2372. }
  2373. else {
  2374. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  2375. module.verbose.apply(console, arguments);
  2376. }
  2377. }
  2378. },
  2379. error: function() {
  2380. if(!settings.silent) {
  2381. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  2382. module.error.apply(console, arguments);
  2383. }
  2384. },
  2385. performance: {
  2386. log: function(message) {
  2387. var
  2388. currentTime,
  2389. executionTime,
  2390. previousTime
  2391. ;
  2392. if(settings.performance) {
  2393. currentTime = new Date().getTime();
  2394. previousTime = time || currentTime;
  2395. executionTime = currentTime - previousTime;
  2396. time = currentTime;
  2397. performance.push({
  2398. 'Name' : message[0],
  2399. 'Arguments' : [].slice.call(message, 1) || '',
  2400. 'Element' : element,
  2401. 'Execution Time' : executionTime
  2402. });
  2403. }
  2404. clearTimeout(module.performance.timer);
  2405. module.performance.timer = setTimeout(module.performance.display, 500);
  2406. },
  2407. display: function() {
  2408. var
  2409. title = settings.name + ':',
  2410. totalTime = 0
  2411. ;
  2412. time = false;
  2413. clearTimeout(module.performance.timer);
  2414. $.each(performance, function(index, data) {
  2415. totalTime += data['Execution Time'];
  2416. });
  2417. title += ' ' + totalTime + 'ms';
  2418. if(moduleSelector) {
  2419. title += ' \'' + moduleSelector + '\'';
  2420. }
  2421. if($allModules.length > 1) {
  2422. title += ' ' + '(' + $allModules.length + ')';
  2423. }
  2424. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  2425. console.groupCollapsed(title);
  2426. if(console.table) {
  2427. console.table(performance);
  2428. }
  2429. else {
  2430. $.each(performance, function(index, data) {
  2431. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  2432. });
  2433. }
  2434. console.groupEnd();
  2435. }
  2436. performance = [];
  2437. }
  2438. },
  2439. invoke: function(query, passedArguments, context) {
  2440. var
  2441. object = instance,
  2442. maxDepth,
  2443. found,
  2444. response
  2445. ;
  2446. passedArguments = passedArguments || queryArguments;
  2447. context = element || context;
  2448. if(typeof query == 'string' && object !== undefined) {
  2449. query = query.split(/[\. ]/);
  2450. maxDepth = query.length - 1;
  2451. $.each(query, function(depth, value) {
  2452. var camelCaseValue = (depth != maxDepth)
  2453. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  2454. : query
  2455. ;
  2456. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  2457. object = object[camelCaseValue];
  2458. }
  2459. else if( object[camelCaseValue] !== undefined ) {
  2460. found = object[camelCaseValue];
  2461. return false;
  2462. }
  2463. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  2464. object = object[value];
  2465. }
  2466. else if( object[value] !== undefined ) {
  2467. found = object[value];
  2468. return false;
  2469. }
  2470. else {
  2471. module.error(error.method, query);
  2472. return false;
  2473. }
  2474. });
  2475. }
  2476. if ( $.isFunction( found ) ) {
  2477. response = found.apply(context, passedArguments);
  2478. }
  2479. else if(found !== undefined) {
  2480. response = found;
  2481. }
  2482. if(Array.isArray(returnedValue)) {
  2483. returnedValue.push(response);
  2484. }
  2485. else if(returnedValue !== undefined) {
  2486. returnedValue = [returnedValue, response];
  2487. }
  2488. else if(response !== undefined) {
  2489. returnedValue = response;
  2490. }
  2491. return found;
  2492. }
  2493. };
  2494. module.preinitialize();
  2495. if(methodInvoked) {
  2496. if(instance === undefined) {
  2497. module.initialize();
  2498. }
  2499. module.invoke(query);
  2500. }
  2501. else {
  2502. if(instance !== undefined) {
  2503. instance.invoke('destroy');
  2504. }
  2505. module.initialize();
  2506. }
  2507. })
  2508. ;
  2509. return (returnedValue !== undefined)
  2510. ? returnedValue
  2511. : this
  2512. ;
  2513. };
  2514. $.fn.dimmer.settings = {
  2515. name : 'Dimmer',
  2516. namespace : 'dimmer',
  2517. silent : false,
  2518. debug : false,
  2519. verbose : false,
  2520. performance : true,
  2521. // whether should use flex layout
  2522. useFlex : true,
  2523. // name to distinguish between multiple dimmers in context
  2524. dimmerName : false,
  2525. // whether to add a variation type
  2526. variation : false,
  2527. // whether to bind close events
  2528. closable : 'auto',
  2529. // whether to use css animations
  2530. useCSS : true,
  2531. // css animation to use
  2532. transition : 'fade',
  2533. // event to bind to
  2534. on : false,
  2535. // overriding opacity value
  2536. opacity : 'auto',
  2537. // transition durations
  2538. duration : {
  2539. show : 500,
  2540. hide : 500
  2541. },
  2542. // whether the dynamically created dimmer should have a loader
  2543. displayLoader: false,
  2544. loaderText : false,
  2545. loaderVariation : '',
  2546. onChange : function(){},
  2547. onShow : function(){},
  2548. onHide : function(){},
  2549. error : {
  2550. method : 'The method you called is not defined.'
  2551. },
  2552. className : {
  2553. active : 'active',
  2554. animating : 'animating',
  2555. dimmable : 'dimmable',
  2556. dimmed : 'dimmed',
  2557. dimmer : 'dimmer',
  2558. disabled : 'disabled',
  2559. hide : 'hide',
  2560. legacy : 'legacy',
  2561. pageDimmer : 'page',
  2562. show : 'show',
  2563. loader : 'ui loader'
  2564. },
  2565. selector: {
  2566. dimmer : '> .ui.dimmer',
  2567. content : '.ui.dimmer > .content, .ui.dimmer > .content > .center'
  2568. },
  2569. template: {
  2570. dimmer: function(settings) {
  2571. var d = $('<div/>').addClass('ui dimmer'),l;
  2572. if(settings.displayLoader) {
  2573. l = $('<div/>')
  2574. .addClass(settings.className.loader)
  2575. .addClass(settings.loaderVariation);
  2576. if(!!settings.loaderText){
  2577. l.text(settings.loaderText);
  2578. l.addClass('text');
  2579. }
  2580. d.append(l);
  2581. }
  2582. return d;
  2583. }
  2584. }
  2585. };
  2586. })( jQuery, window, document );
  2587. /*!
  2588. * # Fomantic-UI - Dropdown
  2589. * http://github.com/fomantic/Fomantic-UI/
  2590. *
  2591. *
  2592. * Released under the MIT license
  2593. * http://opensource.org/licenses/MIT
  2594. *
  2595. */
  2596. /*
  2597. * Copyright 2019 The Gitea Authors
  2598. * Released under the MIT license
  2599. * http://opensource.org/licenses/MIT
  2600. * This version has been modified by Gitea to improve accessibility.
  2601. */
  2602. ;(function ($, window, document, undefined) {
  2603. 'use strict';
  2604. $.isFunction = $.isFunction || function(obj) {
  2605. return typeof obj === "function" && typeof obj.nodeType !== "number";
  2606. };
  2607. window = (typeof window != 'undefined' && window.Math == Math)
  2608. ? window
  2609. : (typeof self != 'undefined' && self.Math == Math)
  2610. ? self
  2611. : Function('return this')()
  2612. ;
  2613. $.fn.dropdown = function(parameters) {
  2614. var
  2615. $allModules = $(this),
  2616. $document = $(document),
  2617. moduleSelector = $allModules.selector || '',
  2618. hasTouch = ('ontouchstart' in document.documentElement),
  2619. clickEvent = hasTouch
  2620. ? 'touchstart'
  2621. : 'click',
  2622. time = new Date().getTime(),
  2623. performance = [],
  2624. query = arguments[0],
  2625. methodInvoked = (typeof query == 'string'),
  2626. queryArguments = [].slice.call(arguments, 1),
  2627. lastAriaID = 1,
  2628. returnedValue
  2629. ;
  2630. $allModules
  2631. .each(function(elementIndex) {
  2632. var
  2633. settings = ( $.isPlainObject(parameters) )
  2634. ? $.extend(true, {}, $.fn.dropdown.settings, parameters)
  2635. : $.extend({}, $.fn.dropdown.settings),
  2636. className = settings.className,
  2637. message = settings.message,
  2638. fields = settings.fields,
  2639. keys = settings.keys,
  2640. metadata = settings.metadata,
  2641. namespace = settings.namespace,
  2642. regExp = settings.regExp,
  2643. selector = settings.selector,
  2644. error = settings.error,
  2645. templates = settings.templates,
  2646. eventNamespace = '.' + namespace,
  2647. moduleNamespace = 'module-' + namespace,
  2648. $module = $(this),
  2649. $context = $(settings.context),
  2650. $text = $module.find(selector.text),
  2651. $search = $module.find(selector.search),
  2652. $sizer = $module.find(selector.sizer),
  2653. $input = $module.find(selector.input),
  2654. $icon = $module.find(selector.icon),
  2655. $clear = $module.find(selector.clearIcon),
  2656. $combo = ($module.prev().find(selector.text).length > 0)
  2657. ? $module.prev().find(selector.text)
  2658. : $module.prev(),
  2659. $menu = $module.children(selector.menu),
  2660. $item = $menu.find(selector.item),
  2661. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $(),
  2662. activated = false,
  2663. itemActivated = false,
  2664. internalChange = false,
  2665. iconClicked = false,
  2666. element = this,
  2667. instance = $module.data(moduleNamespace),
  2668. selectActionActive,
  2669. initialLoad,
  2670. pageLostFocus,
  2671. willRefocus,
  2672. elementNamespace,
  2673. id,
  2674. selectObserver,
  2675. menuObserver,
  2676. classObserver,
  2677. module
  2678. ;
  2679. module = {
  2680. initialize: function() {
  2681. module.debug('Initializing dropdown', settings);
  2682. if( module.is.alreadySetup() ) {
  2683. module.setup.reference();
  2684. }
  2685. else {
  2686. if (settings.ignoreDiacritics && !String.prototype.normalize) {
  2687. settings.ignoreDiacritics = false;
  2688. module.error(error.noNormalize, element);
  2689. }
  2690. module.setup.layout();
  2691. if(settings.values) {
  2692. module.set.initialLoad();
  2693. module.change.values(settings.values);
  2694. module.remove.initialLoad();
  2695. }
  2696. module.refreshData();
  2697. module.save.defaults();
  2698. module.restore.selected();
  2699. module.create.id();
  2700. module.bind.events();
  2701. module.observeChanges();
  2702. module.instantiate();
  2703. module.aria.setup();
  2704. }
  2705. },
  2706. instantiate: function() {
  2707. module.verbose('Storing instance of dropdown', module);
  2708. instance = module;
  2709. $module
  2710. .data(moduleNamespace, module)
  2711. ;
  2712. },
  2713. destroy: function() {
  2714. module.verbose('Destroying previous dropdown', $module);
  2715. module.remove.tabbable();
  2716. module.remove.active();
  2717. $menu.transition('stop all');
  2718. $menu.removeClass(className.visible).addClass(className.hidden);
  2719. $module
  2720. .off(eventNamespace)
  2721. .removeData(moduleNamespace)
  2722. ;
  2723. $menu
  2724. .off(eventNamespace)
  2725. ;
  2726. $document
  2727. .off(elementNamespace)
  2728. ;
  2729. module.disconnect.menuObserver();
  2730. module.disconnect.selectObserver();
  2731. module.disconnect.classObserver();
  2732. },
  2733. observeChanges: function() {
  2734. if('MutationObserver' in window) {
  2735. selectObserver = new MutationObserver(module.event.select.mutation);
  2736. menuObserver = new MutationObserver(module.event.menu.mutation);
  2737. classObserver = new MutationObserver(module.event.class.mutation);
  2738. module.debug('Setting up mutation observer', selectObserver, menuObserver, classObserver);
  2739. module.observe.select();
  2740. module.observe.menu();
  2741. module.observe.class();
  2742. }
  2743. },
  2744. disconnect: {
  2745. menuObserver: function() {
  2746. if(menuObserver) {
  2747. menuObserver.disconnect();
  2748. }
  2749. },
  2750. selectObserver: function() {
  2751. if(selectObserver) {
  2752. selectObserver.disconnect();
  2753. }
  2754. },
  2755. classObserver: function() {
  2756. if(classObserver) {
  2757. classObserver.disconnect();
  2758. }
  2759. }
  2760. },
  2761. observe: {
  2762. select: function() {
  2763. if(module.has.input() && selectObserver) {
  2764. selectObserver.observe($module[0], {
  2765. childList : true,
  2766. subtree : true
  2767. });
  2768. }
  2769. },
  2770. menu: function() {
  2771. if(module.has.menu() && menuObserver) {
  2772. menuObserver.observe($menu[0], {
  2773. childList : true,
  2774. subtree : true
  2775. });
  2776. }
  2777. },
  2778. class: function() {
  2779. if(module.has.search() && classObserver) {
  2780. classObserver.observe($module[0], {
  2781. attributes : true
  2782. });
  2783. }
  2784. }
  2785. },
  2786. create: {
  2787. id: function() {
  2788. id = (Math.random().toString(16) + '000000000').substr(2, 8);
  2789. elementNamespace = '.' + id;
  2790. module.verbose('Creating unique id for element', id);
  2791. },
  2792. userChoice: function(values) {
  2793. var
  2794. $userChoices,
  2795. $userChoice,
  2796. isUserValue,
  2797. html
  2798. ;
  2799. values = values || module.get.userValues();
  2800. if(!values) {
  2801. return false;
  2802. }
  2803. values = Array.isArray(values)
  2804. ? values
  2805. : [values]
  2806. ;
  2807. $.each(values, function(index, value) {
  2808. if(module.get.item(value) === false) {
  2809. html = settings.templates.addition( module.add.variables(message.addResult, value) );
  2810. $userChoice = $('<div />')
  2811. .html(html)
  2812. .attr('data-' + metadata.value, value)
  2813. .attr('data-' + metadata.text, value)
  2814. .addClass(className.addition)
  2815. .addClass(className.item)
  2816. ;
  2817. if(settings.hideAdditions) {
  2818. $userChoice.addClass(className.hidden);
  2819. }
  2820. $userChoices = ($userChoices === undefined)
  2821. ? $userChoice
  2822. : $userChoices.add($userChoice)
  2823. ;
  2824. module.verbose('Creating user choices for value', value, $userChoice);
  2825. }
  2826. });
  2827. return $userChoices;
  2828. },
  2829. userLabels: function(value) {
  2830. var
  2831. userValues = module.get.userValues()
  2832. ;
  2833. if(userValues) {
  2834. module.debug('Adding user labels', userValues);
  2835. $.each(userValues, function(index, value) {
  2836. module.verbose('Adding custom user value');
  2837. module.add.label(value, value);
  2838. });
  2839. }
  2840. },
  2841. menu: function() {
  2842. $menu = $('<div />')
  2843. .addClass(className.menu)
  2844. .appendTo($module)
  2845. ;
  2846. },
  2847. sizer: function() {
  2848. $sizer = $('<span />')
  2849. .addClass(className.sizer)
  2850. .insertAfter($search)
  2851. ;
  2852. }
  2853. },
  2854. search: function(query) {
  2855. query = (query !== undefined)
  2856. ? query
  2857. : module.get.query()
  2858. ;
  2859. module.verbose('Searching for query', query);
  2860. if(module.has.minCharacters(query)) {
  2861. module.filter(query);
  2862. }
  2863. else {
  2864. module.hide(null,true);
  2865. }
  2866. },
  2867. select: {
  2868. firstUnfiltered: function() {
  2869. module.verbose('Selecting first non-filtered element');
  2870. module.remove.selectedItem();
  2871. $item
  2872. .not(selector.unselectable)
  2873. .not(selector.addition + selector.hidden)
  2874. .eq(0)
  2875. .addClass(className.selected)
  2876. ;
  2877. },
  2878. nextAvailable: function($selected) {
  2879. $selected = $selected.eq(0);
  2880. var
  2881. $nextAvailable = $selected.nextAll(selector.item).not(selector.unselectable).eq(0),
  2882. $prevAvailable = $selected.prevAll(selector.item).not(selector.unselectable).eq(0),
  2883. hasNext = ($nextAvailable.length > 0)
  2884. ;
  2885. if(hasNext) {
  2886. module.verbose('Moving selection to', $nextAvailable);
  2887. $nextAvailable.addClass(className.selected);
  2888. }
  2889. else {
  2890. module.verbose('Moving selection to', $prevAvailable);
  2891. $prevAvailable.addClass(className.selected);
  2892. }
  2893. }
  2894. },
  2895. aria: {
  2896. setup: function() {
  2897. var role = module.aria.guessRole();
  2898. if( role !== 'menu' ) {
  2899. return;
  2900. }
  2901. $module.attr('aria-busy', 'true');
  2902. $module.attr('role', 'menu');
  2903. $module.attr('aria-haspopup', 'menu');
  2904. $module.attr('aria-expanded', 'false');
  2905. $menu.find('.divider').attr('role', 'separator');
  2906. $item.attr('role', 'menuitem');
  2907. $item.each(function (index, item) {
  2908. if( !item.id ) {
  2909. item.id = module.aria.nextID('menuitem');
  2910. }
  2911. });
  2912. $text = $module
  2913. .find('> .text')
  2914. .eq(0)
  2915. ;
  2916. if( $module.data('content') ) {
  2917. $text.attr('aria-hidden');
  2918. $module.attr('aria-label', $module.data('content'));
  2919. }
  2920. else {
  2921. $text.attr('id', module.aria.nextID('menutext'));
  2922. $module.attr('aria-labelledby', $text.attr('id'));
  2923. }
  2924. $module.attr('aria-busy', 'false');
  2925. },
  2926. nextID: function(prefix) {
  2927. var nextID;
  2928. do {
  2929. nextID = prefix + '_' + lastAriaID++;
  2930. } while( document.getElementById(nextID) );
  2931. return nextID;
  2932. },
  2933. setExpanded: function(expanded) {
  2934. if( $module.attr('aria-haspopup') ) {
  2935. $module.attr('aria-expanded', expanded);
  2936. }
  2937. },
  2938. refreshDescendant: function() {
  2939. if( $module.attr('aria-haspopup') !== 'menu' ) {
  2940. return;
  2941. }
  2942. var
  2943. $currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
  2944. $activeItem = $menu.children('.' + className.active).eq(0),
  2945. $selectedItem = ($currentlySelected.length > 0)
  2946. ? $currentlySelected
  2947. : $activeItem
  2948. ;
  2949. if( $selectedItem ) {
  2950. $module.attr('aria-activedescendant', $selectedItem.attr('id'));
  2951. }
  2952. else {
  2953. module.aria.removeDescendant();
  2954. }
  2955. },
  2956. removeDescendant: function() {
  2957. if( $module.attr('aria-haspopup') == 'menu' ) {
  2958. $module.removeAttr('aria-activedescendant');
  2959. }
  2960. },
  2961. guessRole: function() {
  2962. var
  2963. isIcon = $module.hasClass('icon'),
  2964. hasSearch = module.has.search(),
  2965. hasInput = ($input.length > 0),
  2966. isMultiple = module.is.multiple()
  2967. ;
  2968. if ( !isIcon && !hasSearch && !hasInput && !isMultiple ) {
  2969. return 'menu';
  2970. }
  2971. return 'unknown';
  2972. }
  2973. },
  2974. setup: {
  2975. api: function() {
  2976. var
  2977. apiSettings = {
  2978. debug : settings.debug,
  2979. urlData : {
  2980. value : module.get.value(),
  2981. query : module.get.query()
  2982. },
  2983. on : false
  2984. }
  2985. ;
  2986. module.verbose('First request, initializing API');
  2987. $module
  2988. .api(apiSettings)
  2989. ;
  2990. },
  2991. layout: function() {
  2992. if( $module.is('select') ) {
  2993. module.setup.select();
  2994. module.setup.returnedObject();
  2995. }
  2996. if( !module.has.menu() ) {
  2997. module.create.menu();
  2998. }
  2999. if ( module.is.selection() && module.is.clearable() && !module.has.clearItem() ) {
  3000. module.verbose('Adding clear icon');
  3001. $clear = $('<i />')
  3002. .addClass('remove icon')
  3003. .insertBefore($text)
  3004. ;
  3005. }
  3006. if( module.is.search() && !module.has.search() ) {
  3007. module.verbose('Adding search input');
  3008. $search = $('<input />')
  3009. .addClass(className.search)
  3010. .prop('autocomplete', 'off')
  3011. .insertBefore($text)
  3012. ;
  3013. }
  3014. if( module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
  3015. module.create.sizer();
  3016. }
  3017. if(settings.allowTab) {
  3018. module.set.tabbable();
  3019. }
  3020. $item.attr('tabindex', '-1');
  3021. },
  3022. select: function() {
  3023. var
  3024. selectValues = module.get.selectValues()
  3025. ;
  3026. module.debug('Dropdown initialized on a select', selectValues);
  3027. if( $module.is('select') ) {
  3028. $input = $module;
  3029. }
  3030. // see if select is placed correctly already
  3031. if($input.parent(selector.dropdown).length > 0) {
  3032. module.debug('UI dropdown already exists. Creating dropdown menu only');
  3033. $module = $input.closest(selector.dropdown);
  3034. if( !module.has.menu() ) {
  3035. module.create.menu();
  3036. }
  3037. $menu = $module.children(selector.menu);
  3038. module.setup.menu(selectValues);
  3039. }
  3040. else {
  3041. module.debug('Creating entire dropdown from select');
  3042. $module = $('<div />')
  3043. .attr('class', $input.attr('class') )
  3044. .addClass(className.selection)
  3045. .addClass(className.dropdown)
  3046. .html( templates.dropdown(selectValues, fields, settings.preserveHTML, settings.className) )
  3047. .insertBefore($input)
  3048. ;
  3049. if($input.hasClass(className.multiple) && $input.prop('multiple') === false) {
  3050. module.error(error.missingMultiple);
  3051. $input.prop('multiple', true);
  3052. }
  3053. if($input.is('[multiple]')) {
  3054. module.set.multiple();
  3055. }
  3056. if ($input.prop('disabled')) {
  3057. module.debug('Disabling dropdown');
  3058. $module.addClass(className.disabled);
  3059. }
  3060. $input
  3061. .removeAttr('required')
  3062. .removeAttr('class')
  3063. .detach()
  3064. .prependTo($module)
  3065. ;
  3066. }
  3067. module.refresh();
  3068. },
  3069. menu: function(values) {
  3070. $menu.html( templates.menu(values, fields,settings.preserveHTML,settings.className));
  3071. $item = $menu.find(selector.item);
  3072. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
  3073. },
  3074. reference: function() {
  3075. module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
  3076. // replace module reference
  3077. $module = $module.parent(selector.dropdown);
  3078. instance = $module.data(moduleNamespace);
  3079. element = $module.get(0);
  3080. module.refresh();
  3081. module.setup.returnedObject();
  3082. },
  3083. returnedObject: function() {
  3084. var
  3085. $firstModules = $allModules.slice(0, elementIndex),
  3086. $lastModules = $allModules.slice(elementIndex + 1)
  3087. ;
  3088. // adjust all modules to use correct reference
  3089. $allModules = $firstModules.add($module).add($lastModules);
  3090. }
  3091. },
  3092. refresh: function() {
  3093. module.refreshSelectors();
  3094. module.refreshData();
  3095. },
  3096. refreshItems: function() {
  3097. $item = $menu.find(selector.item);
  3098. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
  3099. },
  3100. refreshSelectors: function() {
  3101. module.verbose('Refreshing selector cache');
  3102. $text = $module.find(selector.text);
  3103. $search = $module.find(selector.search);
  3104. $input = $module.find(selector.input);
  3105. $icon = $module.find(selector.icon);
  3106. $combo = ($module.prev().find(selector.text).length > 0)
  3107. ? $module.prev().find(selector.text)
  3108. : $module.prev()
  3109. ;
  3110. $menu = $module.children(selector.menu);
  3111. $item = $menu.find(selector.item);
  3112. $divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
  3113. },
  3114. refreshData: function() {
  3115. module.verbose('Refreshing cached metadata');
  3116. $item
  3117. .removeData(metadata.text)
  3118. .removeData(metadata.value)
  3119. ;
  3120. },
  3121. clearData: function() {
  3122. module.verbose('Clearing metadata');
  3123. $item
  3124. .removeData(metadata.text)
  3125. .removeData(metadata.value)
  3126. ;
  3127. $module
  3128. .removeData(metadata.defaultText)
  3129. .removeData(metadata.defaultValue)
  3130. .removeData(metadata.placeholderText)
  3131. ;
  3132. },
  3133. toggle: function() {
  3134. module.verbose('Toggling menu visibility');
  3135. if( !module.is.active() ) {
  3136. module.show();
  3137. }
  3138. else {
  3139. module.hide();
  3140. }
  3141. },
  3142. show: function(callback, preventFocus) {
  3143. callback = $.isFunction(callback)
  3144. ? callback
  3145. : function(){}
  3146. ;
  3147. if(!module.can.show() && module.is.remote()) {
  3148. module.debug('No API results retrieved, searching before show');
  3149. module.queryRemote(module.get.query(), module.show);
  3150. }
  3151. if( module.can.show() && !module.is.active() ) {
  3152. module.debug('Showing dropdown');
  3153. if(module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered()) ) {
  3154. module.remove.message();
  3155. }
  3156. if(module.is.allFiltered()) {
  3157. return true;
  3158. }
  3159. if(settings.onShow.call(element) !== false) {
  3160. module.aria.setExpanded(true);
  3161. module.aria.refreshDescendant();
  3162. module.animate.show(function() {
  3163. if( module.can.click() ) {
  3164. module.bind.intent();
  3165. }
  3166. if(module.has.search() && !preventFocus) {
  3167. module.focusSearch();
  3168. }
  3169. module.set.visible();
  3170. callback.call(element);
  3171. });
  3172. }
  3173. }
  3174. },
  3175. hide: function(callback, preventBlur) {
  3176. callback = $.isFunction(callback)
  3177. ? callback
  3178. : function(){}
  3179. ;
  3180. if( module.is.active() && !module.is.animatingOutward() ) {
  3181. module.debug('Hiding dropdown');
  3182. if(settings.onHide.call(element) !== false) {
  3183. module.aria.setExpanded(false);
  3184. module.aria.removeDescendant();
  3185. module.animate.hide(function() {
  3186. module.remove.visible();
  3187. // hidding search focus
  3188. if ( module.is.focusedOnSearch() && preventBlur !== true ) {
  3189. $search.blur();
  3190. }
  3191. callback.call(element);
  3192. });
  3193. }
  3194. } else if( module.can.click() ) {
  3195. module.unbind.intent();
  3196. }
  3197. iconClicked = false;
  3198. },
  3199. hideOthers: function() {
  3200. module.verbose('Finding other dropdowns to hide');
  3201. $allModules
  3202. .not($module)
  3203. .has(selector.menu + '.' + className.visible)
  3204. .dropdown('hide')
  3205. ;
  3206. },
  3207. hideMenu: function() {
  3208. module.verbose('Hiding menu instantaneously');
  3209. module.remove.active();
  3210. module.remove.visible();
  3211. $menu.transition('hide');
  3212. },
  3213. hideSubMenus: function() {
  3214. var
  3215. $subMenus = $menu.children(selector.item).find(selector.menu)
  3216. ;
  3217. module.verbose('Hiding sub menus', $subMenus);
  3218. $subMenus.transition('hide');
  3219. },
  3220. bind: {
  3221. events: function() {
  3222. module.bind.keyboardEvents();
  3223. module.bind.inputEvents();
  3224. module.bind.mouseEvents();
  3225. },
  3226. keyboardEvents: function() {
  3227. module.verbose('Binding keyboard events');
  3228. $module
  3229. .on('keydown' + eventNamespace, module.event.keydown)
  3230. ;
  3231. if( module.has.search() ) {
  3232. $module
  3233. .on(module.get.inputEvent() + eventNamespace, selector.search, module.event.input)
  3234. ;
  3235. }
  3236. if( module.is.multiple() ) {
  3237. $document
  3238. .on('keydown' + elementNamespace, module.event.document.keydown)
  3239. ;
  3240. }
  3241. },
  3242. inputEvents: function() {
  3243. module.verbose('Binding input change events');
  3244. $module
  3245. .on('change' + eventNamespace, selector.input, module.event.change)
  3246. ;
  3247. },
  3248. mouseEvents: function() {
  3249. module.verbose('Binding mouse events');
  3250. if(module.is.multiple()) {
  3251. $module
  3252. .on(clickEvent + eventNamespace, selector.label, module.event.label.click)
  3253. .on(clickEvent + eventNamespace, selector.remove, module.event.remove.click)
  3254. ;
  3255. }
  3256. if( module.is.searchSelection() ) {
  3257. $module
  3258. .on('mousedown' + eventNamespace, module.event.mousedown)
  3259. .on('mouseup' + eventNamespace, module.event.mouseup)
  3260. .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
  3261. .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
  3262. .on(clickEvent + eventNamespace, selector.icon, module.event.icon.click)
  3263. .on(clickEvent + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
  3264. .on('focus' + eventNamespace, selector.search, module.event.search.focus)
  3265. .on(clickEvent + eventNamespace, selector.search, module.event.search.focus)
  3266. .on('blur' + eventNamespace, selector.search, module.event.search.blur)
  3267. .on(clickEvent + eventNamespace, selector.text, module.event.text.focus)
  3268. ;
  3269. if(module.is.multiple()) {
  3270. $module
  3271. .on(clickEvent + eventNamespace, module.event.click)
  3272. ;
  3273. }
  3274. }
  3275. else {
  3276. if(settings.on == 'click') {
  3277. $module
  3278. .on(clickEvent + eventNamespace, selector.icon, module.event.icon.click)
  3279. .on(clickEvent + eventNamespace, module.event.test.toggle)
  3280. ;
  3281. }
  3282. else if(settings.on == 'hover') {
  3283. $module
  3284. .on('mouseenter' + eventNamespace, module.delay.show)
  3285. .on('mouseleave' + eventNamespace, module.delay.hide)
  3286. ;
  3287. }
  3288. else {
  3289. $module
  3290. .on(settings.on + eventNamespace, module.toggle)
  3291. ;
  3292. }
  3293. $module
  3294. .on('mousedown' + eventNamespace, module.event.mousedown)
  3295. .on('mouseup' + eventNamespace, module.event.mouseup)
  3296. .on('focus' + eventNamespace, module.event.focus)
  3297. .on(clickEvent + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
  3298. ;
  3299. if(module.has.menuSearch() ) {
  3300. $module
  3301. .on('blur' + eventNamespace, selector.search, module.event.search.blur)
  3302. ;
  3303. }
  3304. else {
  3305. $module
  3306. .on('blur' + eventNamespace, module.event.blur)
  3307. ;
  3308. }
  3309. }
  3310. $menu
  3311. .on((hasTouch ? 'touchstart' : 'mouseenter') + eventNamespace, selector.item, module.event.item.mouseenter)
  3312. .on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
  3313. .on('click' + eventNamespace, selector.item, module.event.item.click)
  3314. ;
  3315. },
  3316. intent: function() {
  3317. module.verbose('Binding hide intent event to document');
  3318. if(hasTouch) {
  3319. $document
  3320. .on('touchstart' + elementNamespace, module.event.test.touch)
  3321. .on('touchmove' + elementNamespace, module.event.test.touch)
  3322. ;
  3323. }
  3324. $document
  3325. .on(clickEvent + elementNamespace, module.event.test.hide)
  3326. ;
  3327. }
  3328. },
  3329. unbind: {
  3330. intent: function() {
  3331. module.verbose('Removing hide intent event from document');
  3332. if(hasTouch) {
  3333. $document
  3334. .off('touchstart' + elementNamespace)
  3335. .off('touchmove' + elementNamespace)
  3336. ;
  3337. }
  3338. $document
  3339. .off(clickEvent + elementNamespace)
  3340. ;
  3341. }
  3342. },
  3343. filter: function(query) {
  3344. var
  3345. searchTerm = (query !== undefined)
  3346. ? query
  3347. : module.get.query(),
  3348. afterFiltered = function() {
  3349. if(module.is.multiple()) {
  3350. module.filterActive();
  3351. }
  3352. if(query || (!query && module.get.activeItem().length == 0)) {
  3353. module.select.firstUnfiltered();
  3354. }
  3355. if( module.has.allResultsFiltered() ) {
  3356. if( settings.onNoResults.call(element, searchTerm) ) {
  3357. if(settings.allowAdditions) {
  3358. if(settings.hideAdditions) {
  3359. module.verbose('User addition with no menu, setting empty style');
  3360. module.set.empty();
  3361. module.hideMenu();
  3362. }
  3363. }
  3364. else {
  3365. module.verbose('All items filtered, showing message', searchTerm);
  3366. module.add.message(message.noResults);
  3367. }
  3368. }
  3369. else {
  3370. module.verbose('All items filtered, hiding dropdown', searchTerm);
  3371. module.hideMenu();
  3372. }
  3373. }
  3374. else {
  3375. module.remove.empty();
  3376. module.remove.message();
  3377. }
  3378. if(settings.allowAdditions) {
  3379. module.add.userSuggestion(module.escape.htmlEntities(query));
  3380. }
  3381. if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() ) {
  3382. module.show();
  3383. }
  3384. }
  3385. ;
  3386. if(settings.useLabels && module.has.maxSelections()) {
  3387. return;
  3388. }
  3389. if(settings.apiSettings) {
  3390. if( module.can.useAPI() ) {
  3391. module.queryRemote(searchTerm, function() {
  3392. if(settings.filterRemoteData) {
  3393. module.filterItems(searchTerm);
  3394. }
  3395. var preSelected = $input.val();
  3396. if(!Array.isArray(preSelected)) {
  3397. preSelected = preSelected && preSelected!=="" ? preSelected.split(settings.delimiter) : [];
  3398. }
  3399. $.each(preSelected,function(index,value){
  3400. $item.filter('[data-value="'+value+'"]')
  3401. .addClass(className.filtered)
  3402. ;
  3403. });
  3404. afterFiltered();
  3405. });
  3406. }
  3407. else {
  3408. module.error(error.noAPI);
  3409. }
  3410. }
  3411. else {
  3412. module.filterItems(searchTerm);
  3413. afterFiltered();
  3414. }
  3415. },
  3416. queryRemote: function(query, callback) {
  3417. var
  3418. apiSettings = {
  3419. errorDuration : false,
  3420. cache : 'local',
  3421. throttle : settings.throttle,
  3422. urlData : {
  3423. query: query
  3424. },
  3425. onError: function() {
  3426. module.add.message(message.serverError);
  3427. callback();
  3428. },
  3429. onFailure: function() {
  3430. module.add.message(message.serverError);
  3431. callback();
  3432. },
  3433. onSuccess : function(response) {
  3434. var
  3435. values = response[fields.remoteValues]
  3436. ;
  3437. if (!Array.isArray(values)){
  3438. values = [];
  3439. }
  3440. module.remove.message();
  3441. var menuConfig = {};
  3442. menuConfig[fields.values] = values;
  3443. module.setup.menu(menuConfig);
  3444. if(values.length===0 && !settings.allowAdditions) {
  3445. module.add.message(message.noResults);
  3446. }
  3447. callback();
  3448. }
  3449. }
  3450. ;
  3451. if( !$module.api('get request') ) {
  3452. module.setup.api();
  3453. }
  3454. apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings);
  3455. $module
  3456. .api('setting', apiSettings)
  3457. .api('query')
  3458. ;
  3459. },
  3460. filterItems: function(query) {
  3461. var
  3462. searchTerm = module.remove.diacritics(query !== undefined
  3463. ? query
  3464. : module.get.query()
  3465. ),
  3466. results = null,
  3467. escapedTerm = module.escape.string(searchTerm),
  3468. regExpFlags = (settings.ignoreSearchCase ? 'i' : '') + 'gm',
  3469. beginsWithRegExp = new RegExp('^' + escapedTerm, regExpFlags)
  3470. ;
  3471. // avoid loop if we're matching nothing
  3472. if( module.has.query() ) {
  3473. results = [];
  3474. module.verbose('Searching for matching values', searchTerm);
  3475. $item
  3476. .each(function(){
  3477. var
  3478. $choice = $(this),
  3479. text,
  3480. value
  3481. ;
  3482. if($choice.hasClass(className.unfilterable)) {
  3483. results.push(this);
  3484. return true;
  3485. }
  3486. if(settings.match === 'both' || settings.match === 'text') {
  3487. text = module.remove.diacritics(String(module.get.choiceText($choice, false)));
  3488. if(text.search(beginsWithRegExp) !== -1) {
  3489. results.push(this);
  3490. return true;
  3491. }
  3492. else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
  3493. results.push(this);
  3494. return true;
  3495. }
  3496. else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
  3497. results.push(this);
  3498. return true;
  3499. }
  3500. }
  3501. if(settings.match === 'both' || settings.match === 'value') {
  3502. value = module.remove.diacritics(String(module.get.choiceValue($choice, text)));
  3503. if(value.search(beginsWithRegExp) !== -1) {
  3504. results.push(this);
  3505. return true;
  3506. }
  3507. else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value)) {
  3508. results.push(this);
  3509. return true;
  3510. }
  3511. else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value)) {
  3512. results.push(this);
  3513. return true;
  3514. }
  3515. }
  3516. })
  3517. ;
  3518. }
  3519. module.debug('Showing only matched items', searchTerm);
  3520. module.remove.filteredItem();
  3521. if(results) {
  3522. $item
  3523. .not(results)
  3524. .addClass(className.filtered)
  3525. ;
  3526. }
  3527. if(!module.has.query()) {
  3528. $divider
  3529. .removeClass(className.hidden);
  3530. } else if(settings.hideDividers === true) {
  3531. $divider
  3532. .addClass(className.hidden);
  3533. } else if(settings.hideDividers === 'empty') {
  3534. $divider
  3535. .removeClass(className.hidden)
  3536. .filter(function() {
  3537. // First find the last divider in this divider group
  3538. // Dividers which are direct siblings are considered a group
  3539. var lastDivider = $(this).nextUntil(selector.item);
  3540. return (lastDivider.length ? lastDivider : $(this))
  3541. // Count all non-filtered items until the next divider (or end of the dropdown)
  3542. .nextUntil(selector.divider)
  3543. .filter(selector.item + ":not(." + className.filtered + ")")
  3544. // Hide divider if no items are found
  3545. .length === 0;
  3546. })
  3547. .addClass(className.hidden);
  3548. }
  3549. },
  3550. fuzzySearch: function(query, term) {
  3551. var
  3552. termLength = term.length,
  3553. queryLength = query.length
  3554. ;
  3555. query = (settings.ignoreSearchCase ? query.toLowerCase() : query);
  3556. term = (settings.ignoreSearchCase ? term.toLowerCase() : term);
  3557. if(queryLength > termLength) {
  3558. return false;
  3559. }
  3560. if(queryLength === termLength) {
  3561. return (query === term);
  3562. }
  3563. search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
  3564. var
  3565. queryCharacter = query.charCodeAt(characterIndex)
  3566. ;
  3567. while(nextCharacterIndex < termLength) {
  3568. if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
  3569. continue search;
  3570. }
  3571. }
  3572. return false;
  3573. }
  3574. return true;
  3575. },
  3576. exactSearch: function (query, term) {
  3577. query = (settings.ignoreSearchCase ? query.toLowerCase() : query);
  3578. term = (settings.ignoreSearchCase ? term.toLowerCase() : term);
  3579. return term.indexOf(query) > -1;
  3580. },
  3581. filterActive: function() {
  3582. if(settings.useLabels) {
  3583. $item.filter('.' + className.active)
  3584. .addClass(className.filtered)
  3585. ;
  3586. }
  3587. },
  3588. focusSearch: function(skipHandler) {
  3589. if( module.has.search() && !module.is.focusedOnSearch() ) {
  3590. if(skipHandler) {
  3591. $module.off('focus' + eventNamespace, selector.search);
  3592. $search.focus();
  3593. $module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
  3594. }
  3595. else {
  3596. $search.focus();
  3597. }
  3598. }
  3599. },
  3600. blurSearch: function() {
  3601. if( module.has.search() ) {
  3602. $search.blur();
  3603. }
  3604. },
  3605. forceSelection: function() {
  3606. var
  3607. $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
  3608. $activeItem = $item.not(className.filtered).filter('.' + className.active).eq(0),
  3609. $selectedItem = ($currentlySelected.length > 0)
  3610. ? $currentlySelected
  3611. : $activeItem,
  3612. hasSelected = ($selectedItem.length > 0)
  3613. ;
  3614. if(settings.allowAdditions || (hasSelected && !module.is.multiple())) {
  3615. module.debug('Forcing partial selection to selected item', $selectedItem);
  3616. module.event.item.click.call($selectedItem, {}, true);
  3617. }
  3618. else {
  3619. module.remove.searchTerm();
  3620. }
  3621. },
  3622. change: {
  3623. values: function(values) {
  3624. if(!settings.allowAdditions) {
  3625. module.clear();
  3626. }
  3627. module.debug('Creating dropdown with specified values', values);
  3628. var menuConfig = {};
  3629. menuConfig[fields.values] = values;
  3630. module.setup.menu(menuConfig);
  3631. $.each(values, function(index, item) {
  3632. if(item.selected == true) {
  3633. module.debug('Setting initial selection to', item[fields.value]);
  3634. module.set.selected(item[fields.value]);
  3635. if(!module.is.multiple()) {
  3636. return false;
  3637. }
  3638. }
  3639. });
  3640. if(module.has.selectInput()) {
  3641. module.disconnect.selectObserver();
  3642. $input.html('');
  3643. $input.append('<option disabled selected value></option>');
  3644. $.each(values, function(index, item) {
  3645. var
  3646. value = settings.templates.deQuote(item[fields.value]),
  3647. name = settings.templates.escape(
  3648. item[fields.name] || '',
  3649. settings.preserveHTML
  3650. )
  3651. ;
  3652. $input.append('<option value="' + value + '">' + name + '</option>');
  3653. });
  3654. module.observe.select();
  3655. }
  3656. }
  3657. },
  3658. event: {
  3659. change: function() {
  3660. if(!internalChange) {
  3661. module.debug('Input changed, updating selection');
  3662. module.set.selected();
  3663. }
  3664. },
  3665. focus: function() {
  3666. if(settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
  3667. module.show();
  3668. }
  3669. },
  3670. blur: function(event) {
  3671. pageLostFocus = (document.activeElement === this);
  3672. if(!activated && !pageLostFocus) {
  3673. module.remove.activeLabel();
  3674. module.hide();
  3675. }
  3676. },
  3677. mousedown: function() {
  3678. if(module.is.searchSelection()) {
  3679. // prevent menu hiding on immediate re-focus
  3680. willRefocus = true;
  3681. }
  3682. else {
  3683. // prevents focus callback from occurring on mousedown
  3684. activated = true;
  3685. }
  3686. },
  3687. mouseup: function() {
  3688. if(module.is.searchSelection()) {
  3689. // prevent menu hiding on immediate re-focus
  3690. willRefocus = false;
  3691. }
  3692. else {
  3693. activated = false;
  3694. }
  3695. },
  3696. click: function(event) {
  3697. var
  3698. $target = $(event.target)
  3699. ;
  3700. // focus search
  3701. if($target.is($module)) {
  3702. if(!module.is.focusedOnSearch()) {
  3703. module.focusSearch();
  3704. }
  3705. else {
  3706. module.show();
  3707. }
  3708. }
  3709. },
  3710. search: {
  3711. focus: function(event) {
  3712. activated = true;
  3713. if(module.is.multiple()) {
  3714. module.remove.activeLabel();
  3715. }
  3716. if(settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin')) {
  3717. module.search();
  3718. }
  3719. },
  3720. blur: function(event) {
  3721. pageLostFocus = (document.activeElement === this);
  3722. if(module.is.searchSelection() && !willRefocus) {
  3723. if(!itemActivated && !pageLostFocus) {
  3724. if(settings.forceSelection) {
  3725. module.forceSelection();
  3726. } else if(!settings.allowAdditions){
  3727. module.remove.searchTerm();
  3728. }
  3729. module.hide();
  3730. }
  3731. }
  3732. willRefocus = false;
  3733. }
  3734. },
  3735. clearIcon: {
  3736. click: function(event) {
  3737. module.clear();
  3738. if(module.is.searchSelection()) {
  3739. module.remove.searchTerm();
  3740. }
  3741. module.hide();
  3742. event.stopPropagation();
  3743. }
  3744. },
  3745. icon: {
  3746. click: function(event) {
  3747. iconClicked=true;
  3748. if(module.has.search()) {
  3749. if(!module.is.active()) {
  3750. if(settings.showOnFocus){
  3751. module.focusSearch();
  3752. } else {
  3753. module.toggle();
  3754. }
  3755. } else {
  3756. module.blurSearch();
  3757. }
  3758. } else {
  3759. module.toggle();
  3760. }
  3761. }
  3762. },
  3763. text: {
  3764. focus: function(event) {
  3765. activated = true;
  3766. module.focusSearch();
  3767. }
  3768. },
  3769. input: function(event) {
  3770. if(module.is.multiple() || module.is.searchSelection()) {
  3771. module.set.filtered();
  3772. }
  3773. clearTimeout(module.timer);
  3774. module.timer = setTimeout(module.search, settings.delay.search);
  3775. },
  3776. label: {
  3777. click: function(event) {
  3778. var
  3779. $label = $(this),
  3780. $labels = $module.find(selector.label),
  3781. $activeLabels = $labels.filter('.' + className.active),
  3782. $nextActive = $label.nextAll('.' + className.active),
  3783. $prevActive = $label.prevAll('.' + className.active),
  3784. $range = ($nextActive.length > 0)
  3785. ? $label.nextUntil($nextActive).add($activeLabels).add($label)
  3786. : $label.prevUntil($prevActive).add($activeLabels).add($label)
  3787. ;
  3788. if(event.shiftKey) {
  3789. $activeLabels.removeClass(className.active);
  3790. $range.addClass(className.active);
  3791. }
  3792. else if(event.ctrlKey) {
  3793. $label.toggleClass(className.active);
  3794. }
  3795. else {
  3796. $activeLabels.removeClass(className.active);
  3797. $label.addClass(className.active);
  3798. }
  3799. settings.onLabelSelect.apply(this, $labels.filter('.' + className.active));
  3800. }
  3801. },
  3802. remove: {
  3803. click: function() {
  3804. var
  3805. $label = $(this).parent()
  3806. ;
  3807. if( $label.hasClass(className.active) ) {
  3808. // remove all selected labels
  3809. module.remove.activeLabels();
  3810. }
  3811. else {
  3812. // remove this label only
  3813. module.remove.activeLabels( $label );
  3814. }
  3815. }
  3816. },
  3817. test: {
  3818. toggle: function(event) {
  3819. var
  3820. toggleBehavior = (module.is.multiple())
  3821. ? module.show
  3822. : module.toggle
  3823. ;
  3824. if(module.is.bubbledLabelClick(event) || module.is.bubbledIconClick(event)) {
  3825. return;
  3826. }
  3827. if( module.determine.eventOnElement(event, toggleBehavior) ) {
  3828. event.preventDefault();
  3829. }
  3830. },
  3831. touch: function(event) {
  3832. module.determine.eventOnElement(event, function() {
  3833. if(event.type == 'touchstart') {
  3834. module.timer = setTimeout(function() {
  3835. module.hide();
  3836. }, settings.delay.touch);
  3837. }
  3838. else if(event.type == 'touchmove') {
  3839. clearTimeout(module.timer);
  3840. }
  3841. });
  3842. event.stopPropagation();
  3843. },
  3844. hide: function(event) {
  3845. if(module.determine.eventInModule(event, module.hide)){
  3846. if(element.id && $(event.target).attr('for') === element.id){
  3847. event.preventDefault();
  3848. }
  3849. }
  3850. }
  3851. },
  3852. class: {
  3853. mutation: function(mutations) {
  3854. mutations.forEach(function(mutation) {
  3855. if(mutation.attributeName === "class") {
  3856. module.check.disabled();
  3857. }
  3858. });
  3859. }
  3860. },
  3861. select: {
  3862. mutation: function(mutations) {
  3863. module.debug('<select> modified, recreating menu');
  3864. if(module.is.selectMutation(mutations)) {
  3865. module.disconnect.selectObserver();
  3866. module.refresh();
  3867. module.setup.select();
  3868. module.set.selected();
  3869. module.observe.select();
  3870. }
  3871. }
  3872. },
  3873. menu: {
  3874. mutation: function(mutations) {
  3875. var
  3876. mutation = mutations[0],
  3877. $addedNode = mutation.addedNodes
  3878. ? $(mutation.addedNodes[0])
  3879. : $(false),
  3880. $removedNode = mutation.removedNodes
  3881. ? $(mutation.removedNodes[0])
  3882. : $(false),
  3883. $changedNodes = $addedNode.add($removedNode),
  3884. isUserAddition = $changedNodes.is(selector.addition) || $changedNodes.closest(selector.addition).length > 0,
  3885. isMessage = $changedNodes.is(selector.message) || $changedNodes.closest(selector.message).length > 0
  3886. ;
  3887. if(isUserAddition || isMessage) {
  3888. module.debug('Updating item selector cache');
  3889. module.refreshItems();
  3890. }
  3891. else {
  3892. module.debug('Menu modified, updating selector cache');
  3893. module.refresh();
  3894. }
  3895. },
  3896. mousedown: function() {
  3897. itemActivated = true;
  3898. },
  3899. mouseup: function() {
  3900. itemActivated = false;
  3901. }
  3902. },
  3903. item: {
  3904. mouseenter: function(event) {
  3905. var
  3906. $target = $(event.target),
  3907. $item = $(this),
  3908. $subMenu = $item.children(selector.menu),
  3909. $otherMenus = $item.siblings(selector.item).children(selector.menu),
  3910. hasSubMenu = ($subMenu.length > 0),
  3911. isBubbledEvent = ($subMenu.find($target).length > 0)
  3912. ;
  3913. if( !isBubbledEvent && hasSubMenu ) {
  3914. clearTimeout(module.itemTimer);
  3915. module.itemTimer = setTimeout(function() {
  3916. module.verbose('Showing sub-menu', $subMenu);
  3917. $.each($otherMenus, function() {
  3918. module.animate.hide(false, $(this));
  3919. });
  3920. module.animate.show(false, $subMenu);
  3921. }, settings.delay.show);
  3922. event.preventDefault();
  3923. }
  3924. },
  3925. mouseleave: function(event) {
  3926. var
  3927. $subMenu = $(this).children(selector.menu)
  3928. ;
  3929. if($subMenu.length > 0) {
  3930. clearTimeout(module.itemTimer);
  3931. module.itemTimer = setTimeout(function() {
  3932. module.verbose('Hiding sub-menu', $subMenu);
  3933. module.animate.hide(false, $subMenu);
  3934. }, settings.delay.hide);
  3935. }
  3936. },
  3937. click: function (event, skipRefocus) {
  3938. var
  3939. $choice = $(this),
  3940. $target = (event)
  3941. ? $(event.target)
  3942. : $(''),
  3943. $subMenu = $choice.find(selector.menu),
  3944. text = module.get.choiceText($choice),
  3945. value = module.get.choiceValue($choice, text),
  3946. hasSubMenu = ($subMenu.length > 0),
  3947. isBubbledEvent = ($subMenu.find($target).length > 0)
  3948. ;
  3949. // prevents IE11 bug where menu receives focus even though `tabindex=-1`
  3950. if (document.activeElement.tagName.toLowerCase() !== 'input') {
  3951. $(document.activeElement).blur();
  3952. }
  3953. if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
  3954. if(module.is.searchSelection()) {
  3955. if(settings.allowAdditions) {
  3956. module.remove.userAddition();
  3957. }
  3958. module.remove.searchTerm();
  3959. if(!module.is.focusedOnSearch() && !(skipRefocus == true)) {
  3960. module.focusSearch(true);
  3961. }
  3962. }
  3963. if(!settings.useLabels) {
  3964. module.remove.filteredItem();
  3965. module.set.scrollPosition($choice);
  3966. }
  3967. module.determine.selectAction.call(this, text, value);
  3968. }
  3969. }
  3970. },
  3971. document: {
  3972. // label selection should occur even when element has no focus
  3973. keydown: function(event) {
  3974. var
  3975. pressedKey = event.which,
  3976. isShortcutKey = module.is.inObject(pressedKey, keys)
  3977. ;
  3978. if(isShortcutKey) {
  3979. var
  3980. $label = $module.find(selector.label),
  3981. $activeLabel = $label.filter('.' + className.active),
  3982. activeValue = $activeLabel.data(metadata.value),
  3983. labelIndex = $label.index($activeLabel),
  3984. labelCount = $label.length,
  3985. hasActiveLabel = ($activeLabel.length > 0),
  3986. hasMultipleActive = ($activeLabel.length > 1),
  3987. isFirstLabel = (labelIndex === 0),
  3988. isLastLabel = (labelIndex + 1 == labelCount),
  3989. isSearch = module.is.searchSelection(),
  3990. isFocusedOnSearch = module.is.focusedOnSearch(),
  3991. isFocused = module.is.focused(),
  3992. caretAtStart = (isFocusedOnSearch && module.get.caretPosition(false) === 0),
  3993. isSelectedSearch = (caretAtStart && module.get.caretPosition(true) !== 0),
  3994. $nextLabel
  3995. ;
  3996. if(isSearch && !hasActiveLabel && !isFocusedOnSearch) {
  3997. return;
  3998. }
  3999. if(pressedKey == keys.leftArrow) {
  4000. // activate previous label
  4001. if((isFocused || caretAtStart) && !hasActiveLabel) {
  4002. module.verbose('Selecting previous label');
  4003. $label.last().addClass(className.active);
  4004. }
  4005. else if(hasActiveLabel) {
  4006. if(!event.shiftKey) {
  4007. module.verbose('Selecting previous label');
  4008. $label.removeClass(className.active);
  4009. }
  4010. else {
  4011. module.verbose('Adding previous label to selection');
  4012. }
  4013. if(isFirstLabel && !hasMultipleActive) {
  4014. $activeLabel.addClass(className.active);
  4015. }
  4016. else {
  4017. $activeLabel.prev(selector.siblingLabel)
  4018. .addClass(className.active)
  4019. .end()
  4020. ;
  4021. }
  4022. event.preventDefault();
  4023. }
  4024. }
  4025. else if(pressedKey == keys.rightArrow) {
  4026. // activate first label
  4027. if(isFocused && !hasActiveLabel) {
  4028. $label.first().addClass(className.active);
  4029. }
  4030. // activate next label
  4031. if(hasActiveLabel) {
  4032. if(!event.shiftKey) {
  4033. module.verbose('Selecting next label');
  4034. $label.removeClass(className.active);
  4035. }
  4036. else {
  4037. module.verbose('Adding next label to selection');
  4038. }
  4039. if(isLastLabel) {
  4040. if(isSearch) {
  4041. if(!isFocusedOnSearch) {
  4042. module.focusSearch();
  4043. }
  4044. else {
  4045. $label.removeClass(className.active);
  4046. }
  4047. }
  4048. else if(hasMultipleActive) {
  4049. $activeLabel.next(selector.siblingLabel).addClass(className.active);
  4050. }
  4051. else {
  4052. $activeLabel.addClass(className.active);
  4053. }
  4054. }
  4055. else {
  4056. $activeLabel.next(selector.siblingLabel).addClass(className.active);
  4057. }
  4058. event.preventDefault();
  4059. }
  4060. }
  4061. else if(pressedKey == keys.deleteKey || pressedKey == keys.backspace) {
  4062. if(hasActiveLabel) {
  4063. module.verbose('Removing active labels');
  4064. if(isLastLabel) {
  4065. if(isSearch && !isFocusedOnSearch) {
  4066. module.focusSearch();
  4067. }
  4068. }
  4069. $activeLabel.last().next(selector.siblingLabel).addClass(className.active);
  4070. module.remove.activeLabels($activeLabel);
  4071. event.preventDefault();
  4072. }
  4073. else if(caretAtStart && !isSelectedSearch && !hasActiveLabel && pressedKey == keys.backspace) {
  4074. module.verbose('Removing last label on input backspace');
  4075. $activeLabel = $label.last().addClass(className.active);
  4076. module.remove.activeLabels($activeLabel);
  4077. }
  4078. }
  4079. else {
  4080. $activeLabel.removeClass(className.active);
  4081. }
  4082. }
  4083. }
  4084. },
  4085. keydown: function(event) {
  4086. var
  4087. pressedKey = event.which,
  4088. isShortcutKey = module.is.inObject(pressedKey, keys)
  4089. ;
  4090. if(isShortcutKey) {
  4091. var
  4092. $currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
  4093. $activeItem = $menu.children('.' + className.active).eq(0),
  4094. $selectedItem = ($currentlySelected.length > 0)
  4095. ? $currentlySelected
  4096. : $activeItem,
  4097. $visibleItems = ($selectedItem.length > 0)
  4098. ? $selectedItem.siblings(':not(.' + className.filtered +')').addBack()
  4099. : $menu.children(':not(.' + className.filtered +')'),
  4100. $subMenu = $selectedItem.children(selector.menu),
  4101. $parentMenu = $selectedItem.closest(selector.menu),
  4102. inVisibleMenu = ($parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0),
  4103. hasSubMenu = ($subMenu.length> 0),
  4104. hasSelectedItem = ($selectedItem.length > 0),
  4105. selectedIsSelectable = ($selectedItem.not(selector.unselectable).length > 0),
  4106. delimiterPressed = (pressedKey == keys.delimiter && settings.allowAdditions && module.is.multiple()),
  4107. isAdditionWithoutMenu = (settings.allowAdditions && settings.hideAdditions && (pressedKey == keys.enter || delimiterPressed) && selectedIsSelectable),
  4108. $nextItem,
  4109. isSubMenuItem,
  4110. newIndex
  4111. ;
  4112. // allow selection with menu closed
  4113. if(isAdditionWithoutMenu) {
  4114. module.verbose('Selecting item from keyboard shortcut', $selectedItem);
  4115. $selectedItem[0].click();
  4116. if(module.is.searchSelection()) {
  4117. module.remove.searchTerm();
  4118. }
  4119. if(module.is.multiple()){
  4120. event.preventDefault();
  4121. }
  4122. }
  4123. // visible menu keyboard shortcuts
  4124. if( module.is.visible() ) {
  4125. // enter (select or open sub-menu)
  4126. if(pressedKey == keys.enter || delimiterPressed) {
  4127. if(pressedKey == keys.enter && hasSelectedItem && hasSubMenu && !settings.allowCategorySelection) {
  4128. module.verbose('Pressed enter on unselectable category, opening sub menu');
  4129. pressedKey = keys.rightArrow;
  4130. }
  4131. else if(selectedIsSelectable) {
  4132. module.verbose('Selecting item from keyboard shortcut', $selectedItem);
  4133. $selectedItem[0].click();
  4134. if(module.is.searchSelection()) {
  4135. module.remove.searchTerm();
  4136. if(module.is.multiple()) {
  4137. $search.focus();
  4138. }
  4139. }
  4140. }
  4141. event.preventDefault();
  4142. }
  4143. // sub-menu actions
  4144. if(hasSelectedItem) {
  4145. if(pressedKey == keys.leftArrow) {
  4146. isSubMenuItem = ($parentMenu[0] !== $menu[0]);
  4147. if(isSubMenuItem) {
  4148. module.verbose('Left key pressed, closing sub-menu');
  4149. module.animate.hide(false, $parentMenu);
  4150. $selectedItem
  4151. .removeClass(className.selected)
  4152. ;
  4153. $parentMenu
  4154. .closest(selector.item)
  4155. .addClass(className.selected)
  4156. ;
  4157. module.aria.refreshDescendant();
  4158. event.preventDefault();
  4159. }
  4160. }
  4161. // right arrow (show sub-menu)
  4162. if(pressedKey == keys.rightArrow) {
  4163. if(hasSubMenu) {
  4164. module.verbose('Right key pressed, opening sub-menu');
  4165. module.animate.show(false, $subMenu);
  4166. $selectedItem
  4167. .removeClass(className.selected)
  4168. ;
  4169. $subMenu
  4170. .find(selector.item).eq(0)
  4171. .addClass(className.selected)
  4172. ;
  4173. module.aria.refreshDescendant();
  4174. event.preventDefault();
  4175. }
  4176. }
  4177. }
  4178. // up arrow (traverse menu up)
  4179. if(pressedKey == keys.upArrow) {
  4180. $nextItem = (hasSelectedItem && inVisibleMenu)
  4181. ? $selectedItem.prevAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
  4182. : $item.eq(0)
  4183. ;
  4184. if($visibleItems.index( $nextItem ) < 0) {
  4185. module.verbose('Up key pressed but reached top of current menu');
  4186. event.preventDefault();
  4187. return;
  4188. }
  4189. else {
  4190. module.verbose('Up key pressed, changing active item');
  4191. $selectedItem
  4192. .removeClass(className.selected)
  4193. ;
  4194. $nextItem
  4195. .addClass(className.selected)
  4196. ;
  4197. module.aria.refreshDescendant();
  4198. module.set.scrollPosition($nextItem);
  4199. if(settings.selectOnKeydown && module.is.single()) {
  4200. module.set.selectedItem($nextItem);
  4201. }
  4202. }
  4203. event.preventDefault();
  4204. }
  4205. // down arrow (traverse menu down)
  4206. if(pressedKey == keys.downArrow) {
  4207. $nextItem = (hasSelectedItem && inVisibleMenu)
  4208. ? $nextItem = $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
  4209. : $item.eq(0)
  4210. ;
  4211. if($nextItem.length === 0) {
  4212. module.verbose('Down key pressed but reached bottom of current menu');
  4213. event.preventDefault();
  4214. return;
  4215. }
  4216. else {
  4217. module.verbose('Down key pressed, changing active item');
  4218. $item
  4219. .removeClass(className.selected)
  4220. ;
  4221. $nextItem
  4222. .addClass(className.selected)
  4223. ;
  4224. module.aria.refreshDescendant();
  4225. module.set.scrollPosition($nextItem);
  4226. if(settings.selectOnKeydown && module.is.single()) {
  4227. module.set.selectedItem($nextItem);
  4228. }
  4229. }
  4230. event.preventDefault();
  4231. }
  4232. // page down (show next page)
  4233. if(pressedKey == keys.pageUp) {
  4234. module.scrollPage('up');
  4235. event.preventDefault();
  4236. }
  4237. if(pressedKey == keys.pageDown) {
  4238. module.scrollPage('down');
  4239. event.preventDefault();
  4240. }
  4241. // escape (close menu)
  4242. if(pressedKey == keys.escape) {
  4243. module.verbose('Escape key pressed, closing dropdown');
  4244. module.hide();
  4245. }
  4246. }
  4247. else {
  4248. // delimiter key
  4249. if(delimiterPressed) {
  4250. event.preventDefault();
  4251. }
  4252. // down arrow (open menu)
  4253. if(pressedKey == keys.downArrow && !module.is.visible()) {
  4254. module.verbose('Down key pressed, showing dropdown');
  4255. module.show();
  4256. event.preventDefault();
  4257. }
  4258. }
  4259. }
  4260. else {
  4261. if( !module.has.search() ) {
  4262. module.set.selectedLetter( String.fromCharCode(pressedKey) );
  4263. }
  4264. }
  4265. }
  4266. },
  4267. trigger: {
  4268. change: function() {
  4269. var
  4270. inputElement = $input[0]
  4271. ;
  4272. if(inputElement) {
  4273. var events = document.createEvent('HTMLEvents');
  4274. module.verbose('Triggering native change event');
  4275. events.initEvent('change', true, false);
  4276. inputElement.dispatchEvent(events);
  4277. }
  4278. }
  4279. },
  4280. determine: {
  4281. selectAction: function(text, value) {
  4282. selectActionActive = true;
  4283. module.verbose('Determining action', settings.action);
  4284. if( $.isFunction( module.action[settings.action] ) ) {
  4285. module.verbose('Triggering preset action', settings.action, text, value);
  4286. module.action[ settings.action ].call(element, text, value, this);
  4287. }
  4288. else if( $.isFunction(settings.action) ) {
  4289. module.verbose('Triggering user action', settings.action, text, value);
  4290. settings.action.call(element, text, value, this);
  4291. }
  4292. else {
  4293. module.error(error.action, settings.action);
  4294. }
  4295. selectActionActive = false;
  4296. },
  4297. eventInModule: function(event, callback) {
  4298. var
  4299. $target = $(event.target),
  4300. inDocument = ($target.closest(document.documentElement).length > 0),
  4301. inModule = ($target.closest($module).length > 0)
  4302. ;
  4303. callback = $.isFunction(callback)
  4304. ? callback
  4305. : function(){}
  4306. ;
  4307. if(inDocument && !inModule) {
  4308. module.verbose('Triggering event', callback);
  4309. callback();
  4310. return true;
  4311. }
  4312. else {
  4313. module.verbose('Event occurred in dropdown, canceling callback');
  4314. return false;
  4315. }
  4316. },
  4317. eventOnElement: function(event, callback) {
  4318. var
  4319. $target = $(event.target),
  4320. $label = $target.closest(selector.siblingLabel),
  4321. inVisibleDOM = document.body.contains(event.target),
  4322. notOnLabel = ($module.find($label).length === 0 || !(module.is.multiple() && settings.useLabels)),
  4323. notInMenu = ($target.closest($menu).length === 0)
  4324. ;
  4325. callback = $.isFunction(callback)
  4326. ? callback
  4327. : function(){}
  4328. ;
  4329. if(inVisibleDOM && notOnLabel && notInMenu) {
  4330. module.verbose('Triggering event', callback);
  4331. callback();
  4332. return true;
  4333. }
  4334. else {
  4335. module.verbose('Event occurred in dropdown menu, canceling callback');
  4336. return false;
  4337. }
  4338. }
  4339. },
  4340. action: {
  4341. nothing: function() {},
  4342. activate: function(text, value, element) {
  4343. value = (value !== undefined)
  4344. ? value
  4345. : text
  4346. ;
  4347. if( module.can.activate( $(element) ) ) {
  4348. module.set.selected(value, $(element));
  4349. if(!module.is.multiple()) {
  4350. module.hideAndClear();
  4351. }
  4352. }
  4353. },
  4354. select: function(text, value, element) {
  4355. value = (value !== undefined)
  4356. ? value
  4357. : text
  4358. ;
  4359. if( module.can.activate( $(element) ) ) {
  4360. module.set.value(value, text, $(element));
  4361. if(!module.is.multiple()) {
  4362. module.hideAndClear();
  4363. }
  4364. }
  4365. },
  4366. combo: function(text, value, element) {
  4367. value = (value !== undefined)
  4368. ? value
  4369. : text
  4370. ;
  4371. module.set.selected(value, $(element));
  4372. module.hideAndClear();
  4373. },
  4374. hide: function(text, value, element) {
  4375. module.set.value(value, text, $(element));
  4376. module.hideAndClear();
  4377. }
  4378. },
  4379. get: {
  4380. id: function() {
  4381. return id;
  4382. },
  4383. defaultText: function() {
  4384. return $module.data(metadata.defaultText);
  4385. },
  4386. defaultValue: function() {
  4387. return $module.data(metadata.defaultValue);
  4388. },
  4389. placeholderText: function() {
  4390. if(settings.placeholder != 'auto' && typeof settings.placeholder == 'string') {
  4391. return settings.placeholder;
  4392. }
  4393. return $module.data(metadata.placeholderText) || '';
  4394. },
  4395. text: function() {
  4396. return settings.preserveHTML ? $text.html() : $text.text();
  4397. },
  4398. query: function() {
  4399. return String($search.val()).trim();
  4400. },
  4401. searchWidth: function(value) {
  4402. value = (value !== undefined)
  4403. ? value
  4404. : $search.val()
  4405. ;
  4406. $sizer.text(value);
  4407. // prevent rounding issues
  4408. return Math.ceil( $sizer.width() + 1);
  4409. },
  4410. selectionCount: function() {
  4411. var
  4412. values = module.get.values(),
  4413. count
  4414. ;
  4415. count = ( module.is.multiple() )
  4416. ? Array.isArray(values)
  4417. ? values.length
  4418. : 0
  4419. : (module.get.value() !== '')
  4420. ? 1
  4421. : 0
  4422. ;
  4423. return count;
  4424. },
  4425. transition: function($subMenu) {
  4426. return (settings.transition == 'auto')
  4427. ? module.is.upward($subMenu)
  4428. ? 'slide up'
  4429. : 'slide down'
  4430. : settings.transition
  4431. ;
  4432. },
  4433. userValues: function() {
  4434. var
  4435. values = module.get.values()
  4436. ;
  4437. if(!values) {
  4438. return false;
  4439. }
  4440. values = Array.isArray(values)
  4441. ? values
  4442. : [values]
  4443. ;
  4444. return $.grep(values, function(value) {
  4445. return (module.get.item(value) === false);
  4446. });
  4447. },
  4448. uniqueArray: function(array) {
  4449. return $.grep(array, function (value, index) {
  4450. return $.inArray(value, array) === index;
  4451. });
  4452. },
  4453. caretPosition: function(returnEndPos) {
  4454. var
  4455. input = $search.get(0),
  4456. range,
  4457. rangeLength
  4458. ;
  4459. if(returnEndPos && 'selectionEnd' in input){
  4460. return input.selectionEnd;
  4461. }
  4462. else if(!returnEndPos && 'selectionStart' in input) {
  4463. return input.selectionStart;
  4464. }
  4465. if (document.selection) {
  4466. input.focus();
  4467. range = document.selection.createRange();
  4468. rangeLength = range.text.length;
  4469. if(returnEndPos) {
  4470. return rangeLength;
  4471. }
  4472. range.moveStart('character', -input.value.length);
  4473. return range.text.length - rangeLength;
  4474. }
  4475. },
  4476. value: function() {
  4477. var
  4478. value = ($input.length > 0)
  4479. ? $input.val()
  4480. : $module.data(metadata.value),
  4481. isEmptyMultiselect = (Array.isArray(value) && value.length === 1 && value[0] === '')
  4482. ;
  4483. // prevents placeholder element from being selected when multiple
  4484. return (value === undefined || isEmptyMultiselect)
  4485. ? ''
  4486. : value
  4487. ;
  4488. },
  4489. values: function() {
  4490. var
  4491. value = module.get.value()
  4492. ;
  4493. if(value === '') {
  4494. return '';
  4495. }
  4496. return ( !module.has.selectInput() && module.is.multiple() )
  4497. ? (typeof value == 'string') // delimited string
  4498. ? module.escape.htmlEntities(value).split(settings.delimiter)
  4499. : ''
  4500. : value
  4501. ;
  4502. },
  4503. remoteValues: function() {
  4504. var
  4505. values = module.get.values(),
  4506. remoteValues = false
  4507. ;
  4508. if(values) {
  4509. if(typeof values == 'string') {
  4510. values = [values];
  4511. }
  4512. $.each(values, function(index, value) {
  4513. var
  4514. name = module.read.remoteData(value)
  4515. ;
  4516. module.verbose('Restoring value from session data', name, value);
  4517. if(name) {
  4518. if(!remoteValues) {
  4519. remoteValues = {};
  4520. }
  4521. remoteValues[value] = name;
  4522. }
  4523. });
  4524. }
  4525. return remoteValues;
  4526. },
  4527. choiceText: function($choice, preserveHTML) {
  4528. preserveHTML = (preserveHTML !== undefined)
  4529. ? preserveHTML
  4530. : settings.preserveHTML
  4531. ;
  4532. if($choice) {
  4533. if($choice.find(selector.menu).length > 0) {
  4534. module.verbose('Retrieving text of element with sub-menu');
  4535. $choice = $choice.clone();
  4536. $choice.find(selector.menu).remove();
  4537. $choice.find(selector.menuIcon).remove();
  4538. }
  4539. return ($choice.data(metadata.text) !== undefined)
  4540. ? $choice.data(metadata.text)
  4541. : (preserveHTML)
  4542. ? $choice.html().trim()
  4543. : $choice.text().trim()
  4544. ;
  4545. }
  4546. },
  4547. choiceValue: function($choice, choiceText) {
  4548. choiceText = choiceText || module.get.choiceText($choice);
  4549. if(!$choice) {
  4550. return false;
  4551. }
  4552. return ($choice.data(metadata.value) !== undefined)
  4553. ? String( $choice.data(metadata.value) )
  4554. : (typeof choiceText === 'string')
  4555. ? String(
  4556. settings.ignoreSearchCase
  4557. ? choiceText.toLowerCase()
  4558. : choiceText
  4559. ).trim()
  4560. : String(choiceText)
  4561. ;
  4562. },
  4563. inputEvent: function() {
  4564. var
  4565. input = $search[0]
  4566. ;
  4567. if(input) {
  4568. return (input.oninput !== undefined)
  4569. ? 'input'
  4570. : (input.onpropertychange !== undefined)
  4571. ? 'propertychange'
  4572. : 'keyup'
  4573. ;
  4574. }
  4575. return false;
  4576. },
  4577. selectValues: function() {
  4578. var
  4579. select = {},
  4580. oldGroup = [],
  4581. values = []
  4582. ;
  4583. $module
  4584. .find('option')
  4585. .each(function() {
  4586. var
  4587. $option = $(this),
  4588. name = $option.html(),
  4589. disabled = $option.attr('disabled'),
  4590. value = ( $option.attr('value') !== undefined )
  4591. ? $option.attr('value')
  4592. : name,
  4593. text = ( $option.data(metadata.text) !== undefined )
  4594. ? $option.data(metadata.text)
  4595. : name,
  4596. group = $option.parent('optgroup')
  4597. ;
  4598. if(settings.placeholder === 'auto' && value === '') {
  4599. select.placeholder = name;
  4600. }
  4601. else {
  4602. if(group.length !== oldGroup.length || group[0] !== oldGroup[0]) {
  4603. values.push({
  4604. type: 'header',
  4605. divider: settings.headerDivider,
  4606. name: group.attr('label') || ''
  4607. });
  4608. oldGroup = group;
  4609. }
  4610. values.push({
  4611. name : name,
  4612. value : value,
  4613. text : text,
  4614. disabled : disabled
  4615. });
  4616. }
  4617. })
  4618. ;
  4619. if(settings.placeholder && settings.placeholder !== 'auto') {
  4620. module.debug('Setting placeholder value to', settings.placeholder);
  4621. select.placeholder = settings.placeholder;
  4622. }
  4623. if(settings.sortSelect) {
  4624. if(settings.sortSelect === true) {
  4625. values.sort(function(a, b) {
  4626. return a.name.localeCompare(b.name);
  4627. });
  4628. } else if(settings.sortSelect === 'natural') {
  4629. values.sort(function(a, b) {
  4630. return (a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
  4631. });
  4632. } else if($.isFunction(settings.sortSelect)) {
  4633. values.sort(settings.sortSelect);
  4634. }
  4635. select[fields.values] = values;
  4636. module.debug('Retrieved and sorted values from select', select);
  4637. }
  4638. else {
  4639. select[fields.values] = values;
  4640. module.debug('Retrieved values from select', select);
  4641. }
  4642. return select;
  4643. },
  4644. activeItem: function() {
  4645. return $item.filter('.' + className.active);
  4646. },
  4647. selectedItem: function() {
  4648. var
  4649. $selectedItem = $item.not(selector.unselectable).filter('.' + className.selected)
  4650. ;
  4651. return ($selectedItem.length > 0)
  4652. ? $selectedItem
  4653. : $item.eq(0)
  4654. ;
  4655. },
  4656. itemWithAdditions: function(value) {
  4657. var
  4658. $items = module.get.item(value),
  4659. $userItems = module.create.userChoice(value),
  4660. hasUserItems = ($userItems && $userItems.length > 0)
  4661. ;
  4662. if(hasUserItems) {
  4663. $items = ($items.length > 0)
  4664. ? $items.add($userItems)
  4665. : $userItems
  4666. ;
  4667. }
  4668. return $items;
  4669. },
  4670. item: function(value, strict) {
  4671. var
  4672. $selectedItem = false,
  4673. shouldSearch,
  4674. isMultiple
  4675. ;
  4676. value = (value !== undefined)
  4677. ? value
  4678. : ( module.get.values() !== undefined)
  4679. ? module.get.values()
  4680. : module.get.text()
  4681. ;
  4682. isMultiple = (module.is.multiple() && Array.isArray(value));
  4683. shouldSearch = (isMultiple)
  4684. ? (value.length > 0)
  4685. : (value !== undefined && value !== null)
  4686. ;
  4687. strict = (value === '' || value === false || value === true)
  4688. ? true
  4689. : strict || false
  4690. ;
  4691. if(shouldSearch) {
  4692. $item
  4693. .each(function() {
  4694. var
  4695. $choice = $(this),
  4696. optionText = module.get.choiceText($choice),
  4697. optionValue = module.get.choiceValue($choice, optionText)
  4698. ;
  4699. // safe early exit
  4700. if(optionValue === null || optionValue === undefined) {
  4701. return;
  4702. }
  4703. if(isMultiple) {
  4704. if($.inArray(module.escape.htmlEntities(String(optionValue)), value.map(function(v){return String(v);})) !== -1) {
  4705. $selectedItem = ($selectedItem)
  4706. ? $selectedItem.add($choice)
  4707. : $choice
  4708. ;
  4709. }
  4710. }
  4711. else if(strict) {
  4712. module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
  4713. if( optionValue === value) {
  4714. $selectedItem = $choice;
  4715. return true;
  4716. }
  4717. }
  4718. else {
  4719. if(settings.ignoreCase) {
  4720. optionValue = optionValue.toLowerCase();
  4721. value = value.toLowerCase();
  4722. }
  4723. if(module.escape.htmlEntities(String(optionValue)) === module.escape.htmlEntities(String(value))) {
  4724. module.verbose('Found select item by value', optionValue, value);
  4725. $selectedItem = $choice;
  4726. return true;
  4727. }
  4728. }
  4729. })
  4730. ;
  4731. }
  4732. return $selectedItem;
  4733. }
  4734. },
  4735. check: {
  4736. maxSelections: function(selectionCount) {
  4737. if(settings.maxSelections) {
  4738. selectionCount = (selectionCount !== undefined)
  4739. ? selectionCount
  4740. : module.get.selectionCount()
  4741. ;
  4742. if(selectionCount >= settings.maxSelections) {
  4743. module.debug('Maximum selection count reached');
  4744. if(settings.useLabels) {
  4745. $item.addClass(className.filtered);
  4746. module.add.message(message.maxSelections);
  4747. }
  4748. return true;
  4749. }
  4750. else {
  4751. module.verbose('No longer at maximum selection count');
  4752. module.remove.message();
  4753. module.remove.filteredItem();
  4754. if(module.is.searchSelection()) {
  4755. module.filterItems();
  4756. }
  4757. return false;
  4758. }
  4759. }
  4760. return true;
  4761. },
  4762. disabled: function(){
  4763. $search.attr('tabindex',module.is.disabled() ? -1 : 0);
  4764. }
  4765. },
  4766. restore: {
  4767. defaults: function(preventChangeTrigger) {
  4768. module.clear(preventChangeTrigger);
  4769. module.restore.defaultText();
  4770. module.restore.defaultValue();
  4771. },
  4772. defaultText: function() {
  4773. var
  4774. defaultText = module.get.defaultText(),
  4775. placeholderText = module.get.placeholderText
  4776. ;
  4777. if(defaultText === placeholderText) {
  4778. module.debug('Restoring default placeholder text', defaultText);
  4779. module.set.placeholderText(defaultText);
  4780. }
  4781. else {
  4782. module.debug('Restoring default text', defaultText);
  4783. module.set.text(defaultText);
  4784. }
  4785. },
  4786. placeholderText: function() {
  4787. module.set.placeholderText();
  4788. },
  4789. defaultValue: function() {
  4790. var
  4791. defaultValue = module.get.defaultValue()
  4792. ;
  4793. if(defaultValue !== undefined) {
  4794. module.debug('Restoring default value', defaultValue);
  4795. if(defaultValue !== '') {
  4796. module.set.value(defaultValue);
  4797. module.set.selected();
  4798. }
  4799. else {
  4800. module.remove.activeItem();
  4801. module.remove.selectedItem();
  4802. }
  4803. }
  4804. },
  4805. labels: function() {
  4806. if(settings.allowAdditions) {
  4807. if(!settings.useLabels) {
  4808. module.error(error.labels);
  4809. settings.useLabels = true;
  4810. }
  4811. module.debug('Restoring selected values');
  4812. module.create.userLabels();
  4813. }
  4814. module.check.maxSelections();
  4815. },
  4816. selected: function() {
  4817. module.restore.values();
  4818. if(module.is.multiple()) {
  4819. module.debug('Restoring previously selected values and labels');
  4820. module.restore.labels();
  4821. }
  4822. else {
  4823. module.debug('Restoring previously selected values');
  4824. }
  4825. },
  4826. values: function() {
  4827. // prevents callbacks from occurring on initial load
  4828. module.set.initialLoad();
  4829. if(settings.apiSettings && settings.saveRemoteData && module.get.remoteValues()) {
  4830. module.restore.remoteValues();
  4831. }
  4832. else {
  4833. module.set.selected();
  4834. }
  4835. var value = module.get.value();
  4836. if(value && value !== '' && !(Array.isArray(value) && value.length === 0)) {
  4837. $input.removeClass(className.noselection);
  4838. } else {
  4839. $input.addClass(className.noselection);
  4840. }
  4841. module.remove.initialLoad();
  4842. },
  4843. remoteValues: function() {
  4844. var
  4845. values = module.get.remoteValues()
  4846. ;
  4847. module.debug('Recreating selected from session data', values);
  4848. if(values) {
  4849. if( module.is.single() ) {
  4850. $.each(values, function(value, name) {
  4851. module.set.text(name);
  4852. });
  4853. }
  4854. else {
  4855. $.each(values, function(value, name) {
  4856. module.add.label(value, name);
  4857. });
  4858. }
  4859. }
  4860. }
  4861. },
  4862. read: {
  4863. remoteData: function(value) {
  4864. var
  4865. name
  4866. ;
  4867. if(window.Storage === undefined) {
  4868. module.error(error.noStorage);
  4869. return;
  4870. }
  4871. name = sessionStorage.getItem(value);
  4872. return (name !== undefined)
  4873. ? name
  4874. : false
  4875. ;
  4876. }
  4877. },
  4878. save: {
  4879. defaults: function() {
  4880. module.save.defaultText();
  4881. module.save.placeholderText();
  4882. module.save.defaultValue();
  4883. },
  4884. defaultValue: function() {
  4885. var
  4886. value = module.get.value()
  4887. ;
  4888. module.verbose('Saving default value as', value);
  4889. $module.data(metadata.defaultValue, value);
  4890. },
  4891. defaultText: function() {
  4892. var
  4893. text = module.get.text()
  4894. ;
  4895. module.verbose('Saving default text as', text);
  4896. $module.data(metadata.defaultText, text);
  4897. },
  4898. placeholderText: function() {
  4899. var
  4900. text
  4901. ;
  4902. if(settings.placeholder !== false && $text.hasClass(className.placeholder)) {
  4903. text = module.get.text();
  4904. module.verbose('Saving placeholder text as', text);
  4905. $module.data(metadata.placeholderText, text);
  4906. }
  4907. },
  4908. remoteData: function(name, value) {
  4909. if(window.Storage === undefined) {
  4910. module.error(error.noStorage);
  4911. return;
  4912. }
  4913. module.verbose('Saving remote data to session storage', value, name);
  4914. sessionStorage.setItem(value, name);
  4915. }
  4916. },
  4917. clear: function(preventChangeTrigger) {
  4918. if(module.is.multiple() && settings.useLabels) {
  4919. module.remove.labels();
  4920. }
  4921. else {
  4922. module.remove.activeItem();
  4923. module.remove.selectedItem();
  4924. module.remove.filteredItem();
  4925. }
  4926. module.set.placeholderText();
  4927. module.clearValue(preventChangeTrigger);
  4928. },
  4929. clearValue: function(preventChangeTrigger) {
  4930. module.set.value('', null, null, preventChangeTrigger);
  4931. },
  4932. scrollPage: function(direction, $selectedItem) {
  4933. var
  4934. $currentItem = $selectedItem || module.get.selectedItem(),
  4935. $menu = $currentItem.closest(selector.menu),
  4936. menuHeight = $menu.outerHeight(),
  4937. currentScroll = $menu.scrollTop(),
  4938. itemHeight = $item.eq(0).outerHeight(),
  4939. itemsPerPage = Math.floor(menuHeight / itemHeight),
  4940. maxScroll = $menu.prop('scrollHeight'),
  4941. newScroll = (direction == 'up')
  4942. ? currentScroll - (itemHeight * itemsPerPage)
  4943. : currentScroll + (itemHeight * itemsPerPage),
  4944. $selectableItem = $item.not(selector.unselectable),
  4945. isWithinRange,
  4946. $nextSelectedItem,
  4947. elementIndex
  4948. ;
  4949. elementIndex = (direction == 'up')
  4950. ? $selectableItem.index($currentItem) - itemsPerPage
  4951. : $selectableItem.index($currentItem) + itemsPerPage
  4952. ;
  4953. isWithinRange = (direction == 'up')
  4954. ? (elementIndex >= 0)
  4955. : (elementIndex < $selectableItem.length)
  4956. ;
  4957. $nextSelectedItem = (isWithinRange)
  4958. ? $selectableItem.eq(elementIndex)
  4959. : (direction == 'up')
  4960. ? $selectableItem.first()
  4961. : $selectableItem.last()
  4962. ;
  4963. if($nextSelectedItem.length > 0) {
  4964. module.debug('Scrolling page', direction, $nextSelectedItem);
  4965. $currentItem
  4966. .removeClass(className.selected)
  4967. ;
  4968. $nextSelectedItem
  4969. .addClass(className.selected)
  4970. ;
  4971. if(settings.selectOnKeydown && module.is.single()) {
  4972. module.set.selectedItem($nextSelectedItem);
  4973. }
  4974. $menu
  4975. .scrollTop(newScroll)
  4976. ;
  4977. }
  4978. },
  4979. set: {
  4980. filtered: function() {
  4981. var
  4982. isMultiple = module.is.multiple(),
  4983. isSearch = module.is.searchSelection(),
  4984. isSearchMultiple = (isMultiple && isSearch),
  4985. searchValue = (isSearch)
  4986. ? module.get.query()
  4987. : '',
  4988. hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0),
  4989. searchWidth = module.get.searchWidth(),
  4990. valueIsSet = searchValue !== ''
  4991. ;
  4992. if(isMultiple && hasSearchValue) {
  4993. module.verbose('Adjusting input width', searchWidth, settings.glyphWidth);
  4994. $search.css('width', searchWidth);
  4995. }
  4996. if(hasSearchValue || (isSearchMultiple && valueIsSet)) {
  4997. module.verbose('Hiding placeholder text');
  4998. $text.addClass(className.filtered);
  4999. }
  5000. else if(!isMultiple || (isSearchMultiple && !valueIsSet)) {
  5001. module.verbose('Showing placeholder text');
  5002. $text.removeClass(className.filtered);
  5003. }
  5004. },
  5005. empty: function() {
  5006. $module.addClass(className.empty);
  5007. },
  5008. loading: function() {
  5009. $module.addClass(className.loading);
  5010. },
  5011. placeholderText: function(text) {
  5012. text = text || module.get.placeholderText();
  5013. module.debug('Setting placeholder text', text);
  5014. module.set.text(text);
  5015. $text.addClass(className.placeholder);
  5016. },
  5017. tabbable: function() {
  5018. if( module.is.searchSelection() ) {
  5019. module.debug('Added tabindex to searchable dropdown');
  5020. $search
  5021. .val('')
  5022. ;
  5023. module.check.disabled();
  5024. $menu
  5025. .attr('tabindex', -1)
  5026. ;
  5027. }
  5028. else {
  5029. module.debug('Added tabindex to dropdown');
  5030. if( $module.attr('tabindex') === undefined) {
  5031. $module
  5032. .attr('tabindex', 0)
  5033. ;
  5034. $menu
  5035. .attr('tabindex', -1)
  5036. ;
  5037. }
  5038. }
  5039. },
  5040. initialLoad: function() {
  5041. module.verbose('Setting initial load');
  5042. initialLoad = true;
  5043. },
  5044. activeItem: function($item) {
  5045. if( settings.allowAdditions && $item.filter(selector.addition).length > 0 ) {
  5046. $item.addClass(className.filtered);
  5047. }
  5048. else {
  5049. $item.addClass(className.active);
  5050. }
  5051. },
  5052. partialSearch: function(text) {
  5053. var
  5054. length = module.get.query().length
  5055. ;
  5056. $search.val( text.substr(0, length));
  5057. },
  5058. scrollPosition: function($item, forceScroll) {
  5059. var
  5060. edgeTolerance = 5,
  5061. $menu,
  5062. hasActive,
  5063. offset,
  5064. itemHeight,
  5065. itemOffset,
  5066. menuOffset,
  5067. menuScroll,
  5068. menuHeight,
  5069. abovePage,
  5070. belowPage
  5071. ;
  5072. $item = $item || module.get.selectedItem();
  5073. $menu = $item.closest(selector.menu);
  5074. hasActive = ($item && $item.length > 0);
  5075. forceScroll = (forceScroll !== undefined)
  5076. ? forceScroll
  5077. : false
  5078. ;
  5079. if(module.get.activeItem().length === 0){
  5080. forceScroll = false;
  5081. }
  5082. if($item && $menu.length > 0 && hasActive) {
  5083. itemOffset = $item.position().top;
  5084. $menu.addClass(className.loading);
  5085. menuScroll = $menu.scrollTop();
  5086. menuOffset = $menu.offset().top;
  5087. itemOffset = $item.offset().top;
  5088. offset = menuScroll - menuOffset + itemOffset;
  5089. if(!forceScroll) {
  5090. menuHeight = $menu.height();
  5091. belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
  5092. abovePage = ((offset - edgeTolerance) < menuScroll);
  5093. }
  5094. module.debug('Scrolling to active item', offset);
  5095. if(forceScroll || abovePage || belowPage) {
  5096. $menu.scrollTop(offset);
  5097. }
  5098. $menu.removeClass(className.loading);
  5099. }
  5100. },
  5101. text: function(text) {
  5102. if(settings.action === 'combo') {
  5103. module.debug('Changing combo button text', text, $combo);
  5104. if(settings.preserveHTML) {
  5105. $combo.html(text);
  5106. }
  5107. else {
  5108. $combo.text(text);
  5109. }
  5110. }
  5111. else if(settings.action === 'activate') {
  5112. if(text !== module.get.placeholderText()) {
  5113. $text.removeClass(className.placeholder);
  5114. }
  5115. module.debug('Changing text', text, $text);
  5116. $text
  5117. .removeClass(className.filtered)
  5118. ;
  5119. if(settings.preserveHTML) {
  5120. $text.html(text);
  5121. }
  5122. else {
  5123. $text.text(text);
  5124. }
  5125. }
  5126. },
  5127. selectedItem: function($item) {
  5128. var
  5129. value = module.get.choiceValue($item),
  5130. searchText = module.get.choiceText($item, false),
  5131. text = module.get.choiceText($item, true)
  5132. ;
  5133. module.debug('Setting user selection to item', $item);
  5134. module.remove.activeItem();
  5135. module.set.partialSearch(searchText);
  5136. module.set.activeItem($item);
  5137. module.set.selected(value, $item);
  5138. module.set.text(text);
  5139. },
  5140. selectedLetter: function(letter) {
  5141. var
  5142. $selectedItem = $item.filter('.' + className.selected),
  5143. alreadySelectedLetter = $selectedItem.length > 0 && module.has.firstLetter($selectedItem, letter),
  5144. $nextValue = false,
  5145. $nextItem
  5146. ;
  5147. // check next of same letter
  5148. if(alreadySelectedLetter) {
  5149. $nextItem = $selectedItem.nextAll($item).eq(0);
  5150. if( module.has.firstLetter($nextItem, letter) ) {
  5151. $nextValue = $nextItem;
  5152. }
  5153. }
  5154. // check all values
  5155. if(!$nextValue) {
  5156. $item
  5157. .each(function(){
  5158. if(module.has.firstLetter($(this), letter)) {
  5159. $nextValue = $(this);
  5160. return false;
  5161. }
  5162. })
  5163. ;
  5164. }
  5165. // set next value
  5166. if($nextValue) {
  5167. module.verbose('Scrolling to next value with letter', letter);
  5168. module.set.scrollPosition($nextValue);
  5169. $selectedItem.removeClass(className.selected);
  5170. $nextValue.addClass(className.selected);
  5171. module.aria.refreshDescendant();
  5172. if(settings.selectOnKeydown && module.is.single()) {
  5173. module.set.selectedItem($nextValue);
  5174. }
  5175. }
  5176. },
  5177. direction: function($menu) {
  5178. if(settings.direction == 'auto') {
  5179. // reset position, remove upward if it's base menu
  5180. if (!$menu) {
  5181. module.remove.upward();
  5182. } else if (module.is.upward($menu)) {
  5183. //we need make sure when make assertion openDownward for $menu, $menu does not have upward class
  5184. module.remove.upward($menu);
  5185. }
  5186. if(module.can.openDownward($menu)) {
  5187. module.remove.upward($menu);
  5188. }
  5189. else {
  5190. module.set.upward($menu);
  5191. }
  5192. if(!module.is.leftward($menu) && !module.can.openRightward($menu)) {
  5193. module.set.leftward($menu);
  5194. }
  5195. }
  5196. else if(settings.direction == 'upward') {
  5197. module.set.upward($menu);
  5198. }
  5199. },
  5200. upward: function($currentMenu) {
  5201. var $element = $currentMenu || $module;
  5202. $element.addClass(className.upward);
  5203. },
  5204. leftward: function($currentMenu) {
  5205. var $element = $currentMenu || $menu;
  5206. $element.addClass(className.leftward);
  5207. },
  5208. value: function(value, text, $selected, preventChangeTrigger) {
  5209. if(value !== undefined && value !== '' && !(Array.isArray(value) && value.length === 0)) {
  5210. $input.removeClass(className.noselection);
  5211. } else {
  5212. $input.addClass(className.noselection);
  5213. }
  5214. var
  5215. escapedValue = module.escape.value(value),
  5216. hasInput = ($input.length > 0),
  5217. currentValue = module.get.values(),
  5218. stringValue = (value !== undefined)
  5219. ? String(value)
  5220. : value,
  5221. newValue
  5222. ;
  5223. if(hasInput) {
  5224. if(!settings.allowReselection && stringValue == currentValue) {
  5225. module.verbose('Skipping value update already same value', value, currentValue);
  5226. if(!module.is.initialLoad()) {
  5227. return;
  5228. }
  5229. }
  5230. if( module.is.single() && module.has.selectInput() && module.can.extendSelect() ) {
  5231. module.debug('Adding user option', value);
  5232. module.add.optionValue(value);
  5233. }
  5234. module.debug('Updating input value', escapedValue, currentValue);
  5235. internalChange = true;
  5236. $input
  5237. .val(escapedValue)
  5238. ;
  5239. if(settings.fireOnInit === false && module.is.initialLoad()) {
  5240. module.debug('Input native change event ignored on initial load');
  5241. }
  5242. else if(preventChangeTrigger !== true) {
  5243. module.trigger.change();
  5244. }
  5245. internalChange = false;
  5246. }
  5247. else {
  5248. module.verbose('Storing value in metadata', escapedValue, $input);
  5249. if(escapedValue !== currentValue) {
  5250. $module.data(metadata.value, stringValue);
  5251. }
  5252. }
  5253. if(settings.fireOnInit === false && module.is.initialLoad()) {
  5254. module.verbose('No callback on initial load', settings.onChange);
  5255. }
  5256. else if(preventChangeTrigger !== true) {
  5257. settings.onChange.call(element, value, text, $selected);
  5258. }
  5259. },
  5260. active: function() {
  5261. $module
  5262. .addClass(className.active)
  5263. ;
  5264. },
  5265. multiple: function() {
  5266. $module.addClass(className.multiple);
  5267. },
  5268. visible: function() {
  5269. $module.addClass(className.visible);
  5270. },
  5271. exactly: function(value, $selectedItem) {
  5272. module.debug('Setting selected to exact values');
  5273. module.clear();
  5274. module.set.selected(value, $selectedItem);
  5275. },
  5276. selected: function(value, $selectedItem) {
  5277. var
  5278. isMultiple = module.is.multiple()
  5279. ;
  5280. $selectedItem = (settings.allowAdditions)
  5281. ? $selectedItem || module.get.itemWithAdditions(value)
  5282. : $selectedItem || module.get.item(value)
  5283. ;
  5284. if(!$selectedItem) {
  5285. return;
  5286. }
  5287. module.debug('Setting selected menu item to', $selectedItem);
  5288. if(module.is.multiple()) {
  5289. module.remove.searchWidth();
  5290. }
  5291. if(module.is.single()) {
  5292. module.remove.activeItem();
  5293. module.remove.selectedItem();
  5294. }
  5295. else if(settings.useLabels) {
  5296. module.remove.selectedItem();
  5297. }
  5298. // select each item
  5299. $selectedItem
  5300. .each(function() {
  5301. var
  5302. $selected = $(this),
  5303. selectedText = module.get.choiceText($selected),
  5304. selectedValue = module.get.choiceValue($selected, selectedText),
  5305. isFiltered = $selected.hasClass(className.filtered),
  5306. isActive = $selected.hasClass(className.active),
  5307. isUserValue = $selected.hasClass(className.addition),
  5308. shouldAnimate = (isMultiple && $selectedItem.length == 1)
  5309. ;
  5310. if(isMultiple) {
  5311. if(!isActive || isUserValue) {
  5312. if(settings.apiSettings && settings.saveRemoteData) {
  5313. module.save.remoteData(selectedText, selectedValue);
  5314. }
  5315. if(settings.useLabels) {
  5316. module.add.label(selectedValue, selectedText, shouldAnimate);
  5317. module.add.value(selectedValue, selectedText, $selected);
  5318. module.set.activeItem($selected);
  5319. module.filterActive();
  5320. module.select.nextAvailable($selectedItem);
  5321. }
  5322. else {
  5323. module.add.value(selectedValue, selectedText, $selected);
  5324. module.set.text(module.add.variables(message.count));
  5325. module.set.activeItem($selected);
  5326. }
  5327. }
  5328. else if(!isFiltered && (settings.useLabels || selectActionActive)) {
  5329. module.debug('Selected active value, removing label');
  5330. module.remove.selected(selectedValue);
  5331. }
  5332. }
  5333. else {
  5334. if(settings.apiSettings && settings.saveRemoteData) {
  5335. module.save.remoteData(selectedText, selectedValue);
  5336. }
  5337. module.set.text(selectedText);
  5338. module.set.value(selectedValue, selectedText, $selected);
  5339. $selected
  5340. .addClass(className.active)
  5341. .addClass(className.selected)
  5342. ;
  5343. }
  5344. })
  5345. ;
  5346. module.remove.searchTerm();
  5347. }
  5348. },
  5349. add: {
  5350. label: function(value, text, shouldAnimate) {
  5351. var
  5352. $next = module.is.searchSelection()
  5353. ? $search
  5354. : $text,
  5355. escapedValue = module.escape.value(value),
  5356. $label
  5357. ;
  5358. if(settings.ignoreCase) {
  5359. escapedValue = escapedValue.toLowerCase();
  5360. }
  5361. $label = $('<a />')
  5362. .addClass(className.label)
  5363. .attr('data-' + metadata.value, escapedValue)
  5364. .html(templates.label(escapedValue, text, settings.preserveHTML, settings.className))
  5365. ;
  5366. $label = settings.onLabelCreate.call($label, escapedValue, text);
  5367. if(module.has.label(value)) {
  5368. module.debug('User selection already exists, skipping', escapedValue);
  5369. return;
  5370. }
  5371. if(settings.label.variation) {
  5372. $label.addClass(settings.label.variation);
  5373. }
  5374. if(shouldAnimate === true) {
  5375. module.debug('Animating in label', $label);
  5376. $label
  5377. .addClass(className.hidden)
  5378. .insertBefore($next)
  5379. .transition({
  5380. animation : settings.label.transition,
  5381. debug : settings.debug,
  5382. verbose : settings.verbose,
  5383. duration : settings.label.duration
  5384. })
  5385. ;
  5386. }
  5387. else {
  5388. module.debug('Adding selection label', $label);
  5389. $label
  5390. .insertBefore($next)
  5391. ;
  5392. }
  5393. },
  5394. message: function(message) {
  5395. var
  5396. $message = $menu.children(selector.message),
  5397. html = settings.templates.message(module.add.variables(message))
  5398. ;
  5399. if($message.length > 0) {
  5400. $message
  5401. .html(html)
  5402. ;
  5403. }
  5404. else {
  5405. $message = $('<div/>')
  5406. .html(html)
  5407. .addClass(className.message)
  5408. .appendTo($menu)
  5409. ;
  5410. }
  5411. },
  5412. optionValue: function(value) {
  5413. var
  5414. escapedValue = module.escape.value(value),
  5415. $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
  5416. hasOption = ($option.length > 0)
  5417. ;
  5418. if(hasOption) {
  5419. return;
  5420. }
  5421. // temporarily disconnect observer
  5422. module.disconnect.selectObserver();
  5423. if( module.is.single() ) {
  5424. module.verbose('Removing previous user addition');
  5425. $input.find('option.' + className.addition).remove();
  5426. }
  5427. $('<option/>')
  5428. .prop('value', escapedValue)
  5429. .addClass(className.addition)
  5430. .html(value)
  5431. .appendTo($input)
  5432. ;
  5433. module.verbose('Adding user addition as an <option>', value);
  5434. module.observe.select();
  5435. },
  5436. userSuggestion: function(value) {
  5437. var
  5438. $addition = $menu.children(selector.addition),
  5439. $existingItem = module.get.item(value),
  5440. alreadyHasValue = $existingItem && $existingItem.not(selector.addition).length,
  5441. hasUserSuggestion = $addition.length > 0,
  5442. html
  5443. ;
  5444. if(settings.useLabels && module.has.maxSelections()) {
  5445. return;
  5446. }
  5447. if(value === '' || alreadyHasValue) {
  5448. $addition.remove();
  5449. return;
  5450. }
  5451. if(hasUserSuggestion) {
  5452. $addition
  5453. .data(metadata.value, value)
  5454. .data(metadata.text, value)
  5455. .attr('data-' + metadata.value, value)
  5456. .attr('data-' + metadata.text, value)
  5457. .removeClass(className.filtered)
  5458. ;
  5459. if(!settings.hideAdditions) {
  5460. html = settings.templates.addition( module.add.variables(message.addResult, value) );
  5461. $addition
  5462. .html(html)
  5463. ;
  5464. }
  5465. module.verbose('Replacing user suggestion with new value', $addition);
  5466. }
  5467. else {
  5468. $addition = module.create.userChoice(value);
  5469. $addition
  5470. .prependTo($menu)
  5471. ;
  5472. module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
  5473. }
  5474. if(!settings.hideAdditions || module.is.allFiltered()) {
  5475. $addition
  5476. .addClass(className.selected)
  5477. .siblings()
  5478. .removeClass(className.selected)
  5479. ;
  5480. }
  5481. module.refreshItems();
  5482. },
  5483. variables: function(message, term) {
  5484. var
  5485. hasCount = (message.search('{count}') !== -1),
  5486. hasMaxCount = (message.search('{maxCount}') !== -1),
  5487. hasTerm = (message.search('{term}') !== -1),
  5488. count,
  5489. query
  5490. ;
  5491. module.verbose('Adding templated variables to message', message);
  5492. if(hasCount) {
  5493. count = module.get.selectionCount();
  5494. message = message.replace('{count}', count);
  5495. }
  5496. if(hasMaxCount) {
  5497. count = module.get.selectionCount();
  5498. message = message.replace('{maxCount}', settings.maxSelections);
  5499. }
  5500. if(hasTerm) {
  5501. query = term || module.get.query();
  5502. message = message.replace('{term}', query);
  5503. }
  5504. return message;
  5505. },
  5506. value: function(addedValue, addedText, $selectedItem) {
  5507. var
  5508. currentValue = module.get.values(),
  5509. newValue
  5510. ;
  5511. if(module.has.value(addedValue)) {
  5512. module.debug('Value already selected');
  5513. return;
  5514. }
  5515. if(addedValue === '') {
  5516. module.debug('Cannot select blank values from multiselect');
  5517. return;
  5518. }
  5519. // extend current array
  5520. if(Array.isArray(currentValue)) {
  5521. newValue = currentValue.concat([addedValue]);
  5522. newValue = module.get.uniqueArray(newValue);
  5523. }
  5524. else {
  5525. newValue = [addedValue];
  5526. }
  5527. // add values
  5528. if( module.has.selectInput() ) {
  5529. if(module.can.extendSelect()) {
  5530. module.debug('Adding value to select', addedValue, newValue, $input);
  5531. module.add.optionValue(addedValue);
  5532. }
  5533. }
  5534. else {
  5535. newValue = newValue.join(settings.delimiter);
  5536. module.debug('Setting hidden input to delimited value', newValue, $input);
  5537. }
  5538. if(settings.fireOnInit === false && module.is.initialLoad()) {
  5539. module.verbose('Skipping onadd callback on initial load', settings.onAdd);
  5540. }
  5541. else {
  5542. settings.onAdd.call(element, addedValue, addedText, $selectedItem);
  5543. }
  5544. module.set.value(newValue, addedText, $selectedItem);
  5545. module.check.maxSelections();
  5546. },
  5547. },
  5548. remove: {
  5549. active: function() {
  5550. $module.removeClass(className.active);
  5551. },
  5552. activeLabel: function() {
  5553. $module.find(selector.label).removeClass(className.active);
  5554. },
  5555. empty: function() {
  5556. $module.removeClass(className.empty);
  5557. },
  5558. loading: function() {
  5559. $module.removeClass(className.loading);
  5560. },
  5561. initialLoad: function() {
  5562. initialLoad = false;
  5563. },
  5564. upward: function($currentMenu) {
  5565. var $element = $currentMenu || $module;
  5566. $element.removeClass(className.upward);
  5567. },
  5568. leftward: function($currentMenu) {
  5569. var $element = $currentMenu || $menu;
  5570. $element.removeClass(className.leftward);
  5571. },
  5572. visible: function() {
  5573. $module.removeClass(className.visible);
  5574. },
  5575. activeItem: function() {
  5576. $item.removeClass(className.active);
  5577. },
  5578. filteredItem: function() {
  5579. if(settings.useLabels && module.has.maxSelections() ) {
  5580. return;
  5581. }
  5582. if(settings.useLabels && module.is.multiple()) {
  5583. $item.not('.' + className.active).removeClass(className.filtered);
  5584. }
  5585. else {
  5586. $item.removeClass(className.filtered);
  5587. }
  5588. if(settings.hideDividers) {
  5589. $divider.removeClass(className.hidden);
  5590. }
  5591. module.remove.empty();
  5592. },
  5593. optionValue: function(value) {
  5594. var
  5595. escapedValue = module.escape.value(value),
  5596. $option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
  5597. hasOption = ($option.length > 0)
  5598. ;
  5599. if(!hasOption || !$option.hasClass(className.addition)) {
  5600. return;
  5601. }
  5602. // temporarily disconnect observer
  5603. if(selectObserver) {
  5604. selectObserver.disconnect();
  5605. module.verbose('Temporarily disconnecting mutation observer');
  5606. }
  5607. $option.remove();
  5608. module.verbose('Removing user addition as an <option>', escapedValue);
  5609. if(selectObserver) {
  5610. selectObserver.observe($input[0], {
  5611. childList : true,
  5612. subtree : true
  5613. });
  5614. }
  5615. },
  5616. message: function() {
  5617. $menu.children(selector.message).remove();
  5618. },
  5619. searchWidth: function() {
  5620. $search.css('width', '');
  5621. },
  5622. searchTerm: function() {
  5623. module.verbose('Cleared search term');
  5624. $search.val('');
  5625. module.set.filtered();
  5626. },
  5627. userAddition: function() {
  5628. $item.filter(selector.addition).remove();
  5629. },
  5630. selected: function(value, $selectedItem) {
  5631. $selectedItem = (settings.allowAdditions)
  5632. ? $selectedItem || module.get.itemWithAdditions(value)
  5633. : $selectedItem || module.get.item(value)
  5634. ;
  5635. if(!$selectedItem) {
  5636. return false;
  5637. }
  5638. $selectedItem
  5639. .each(function() {
  5640. var
  5641. $selected = $(this),
  5642. selectedText = module.get.choiceText($selected),
  5643. selectedValue = module.get.choiceValue($selected, selectedText)
  5644. ;
  5645. if(module.is.multiple()) {
  5646. if(settings.useLabels) {
  5647. module.remove.value(selectedValue, selectedText, $selected);
  5648. module.remove.label(selectedValue);
  5649. }
  5650. else {
  5651. module.remove.value(selectedValue, selectedText, $selected);
  5652. if(module.get.selectionCount() === 0) {
  5653. module.set.placeholderText();
  5654. }
  5655. else {
  5656. module.set.text(module.add.variables(message.count));
  5657. }
  5658. }
  5659. }
  5660. else {
  5661. module.remove.value(selectedValue, selectedText, $selected);
  5662. }
  5663. $selected
  5664. .removeClass(className.filtered)
  5665. .removeClass(className.active)
  5666. ;
  5667. if(settings.useLabels) {
  5668. $selected.removeClass(className.selected);
  5669. }
  5670. })
  5671. ;
  5672. },
  5673. selectedItem: function() {
  5674. $item.removeClass(className.selected);
  5675. },
  5676. value: function(removedValue, removedText, $removedItem) {
  5677. var
  5678. values = module.get.values(),
  5679. newValue
  5680. ;
  5681. removedValue = module.escape.htmlEntities(removedValue);
  5682. if( module.has.selectInput() ) {
  5683. module.verbose('Input is <select> removing selected option', removedValue);
  5684. newValue = module.remove.arrayValue(removedValue, values);
  5685. module.remove.optionValue(removedValue);
  5686. }
  5687. else {
  5688. module.verbose('Removing from delimited values', removedValue);
  5689. newValue = module.remove.arrayValue(removedValue, values);
  5690. newValue = newValue.join(settings.delimiter);
  5691. }
  5692. if(settings.fireOnInit === false && module.is.initialLoad()) {
  5693. module.verbose('No callback on initial load', settings.onRemove);
  5694. }
  5695. else {
  5696. settings.onRemove.call(element, removedValue, removedText, $removedItem);
  5697. }
  5698. module.set.value(newValue, removedText, $removedItem);
  5699. module.check.maxSelections();
  5700. },
  5701. arrayValue: function(removedValue, values) {
  5702. if( !Array.isArray(values) ) {
  5703. values = [values];
  5704. }
  5705. values = $.grep(values, function(value){
  5706. return (removedValue != value);
  5707. });
  5708. module.verbose('Removed value from delimited string', removedValue, values);
  5709. return values;
  5710. },
  5711. label: function(value, shouldAnimate) {
  5712. var
  5713. $labels = $module.find(selector.label),
  5714. $removedLabel = $labels.filter('[data-' + metadata.value + '="' + module.escape.string(settings.ignoreCase ? value.toLowerCase() : value) +'"]')
  5715. ;
  5716. module.verbose('Removing label', $removedLabel);
  5717. $removedLabel.remove();
  5718. },
  5719. activeLabels: function($activeLabels) {
  5720. $activeLabels = $activeLabels || $module.find(selector.label).filter('.' + className.active);
  5721. module.verbose('Removing active label selections', $activeLabels);
  5722. module.remove.labels($activeLabels);
  5723. },
  5724. labels: function($labels) {
  5725. $labels = $labels || $module.find(selector.label);
  5726. module.verbose('Removing labels', $labels);
  5727. $labels
  5728. .each(function(){
  5729. var
  5730. $label = $(this),
  5731. value = $label.data(metadata.value),
  5732. stringValue = (value !== undefined)
  5733. ? String(value)
  5734. : value,
  5735. isUserValue = module.is.userValue(stringValue)
  5736. ;
  5737. if(settings.onLabelRemove.call($label, value) === false) {
  5738. module.debug('Label remove callback cancelled removal');
  5739. return;
  5740. }
  5741. module.remove.message();
  5742. if(isUserValue) {
  5743. module.remove.value(stringValue);
  5744. module.remove.label(stringValue);
  5745. }
  5746. else {
  5747. // selected will also remove label
  5748. module.remove.selected(stringValue);
  5749. }
  5750. })
  5751. ;
  5752. },
  5753. tabbable: function() {
  5754. if( module.is.searchSelection() ) {
  5755. module.debug('Searchable dropdown initialized');
  5756. $search
  5757. .removeAttr('tabindex')
  5758. ;
  5759. $menu
  5760. .removeAttr('tabindex')
  5761. ;
  5762. }
  5763. else {
  5764. module.debug('Simple selection dropdown initialized');
  5765. $module
  5766. .removeAttr('tabindex')
  5767. ;
  5768. $menu
  5769. .removeAttr('tabindex')
  5770. ;
  5771. }
  5772. },
  5773. diacritics: function(text) {
  5774. return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : text;
  5775. }
  5776. },
  5777. has: {
  5778. menuSearch: function() {
  5779. return (module.has.search() && $search.closest($menu).length > 0);
  5780. },
  5781. clearItem: function() {
  5782. return ($clear.length > 0);
  5783. },
  5784. search: function() {
  5785. return ($search.length > 0);
  5786. },
  5787. sizer: function() {
  5788. return ($sizer.length > 0);
  5789. },
  5790. selectInput: function() {
  5791. return ( $input.is('select') );
  5792. },
  5793. minCharacters: function(searchTerm) {
  5794. if(settings.minCharacters && !iconClicked) {
  5795. searchTerm = (searchTerm !== undefined)
  5796. ? String(searchTerm)
  5797. : String(module.get.query())
  5798. ;
  5799. return (searchTerm.length >= settings.minCharacters);
  5800. }
  5801. iconClicked=false;
  5802. return true;
  5803. },
  5804. firstLetter: function($item, letter) {
  5805. var
  5806. text,
  5807. firstLetter
  5808. ;
  5809. if(!$item || $item.length === 0 || typeof letter !== 'string') {
  5810. return false;
  5811. }
  5812. text = module.get.choiceText($item, false);
  5813. letter = letter.toLowerCase();
  5814. firstLetter = String(text).charAt(0).toLowerCase();
  5815. return (letter == firstLetter);
  5816. },
  5817. input: function() {
  5818. return ($input.length > 0);
  5819. },
  5820. items: function() {
  5821. return ($item.length > 0);
  5822. },
  5823. menu: function() {
  5824. return ($menu.length > 0);
  5825. },
  5826. message: function() {
  5827. return ($menu.children(selector.message).length !== 0);
  5828. },
  5829. label: function(value) {
  5830. var
  5831. escapedValue = module.escape.value(value),
  5832. $labels = $module.find(selector.label)
  5833. ;
  5834. if(settings.ignoreCase) {
  5835. escapedValue = escapedValue.toLowerCase();
  5836. }
  5837. return ($labels.filter('[data-' + metadata.value + '="' + module.escape.string(escapedValue) +'"]').length > 0);
  5838. },
  5839. maxSelections: function() {
  5840. return (settings.maxSelections && module.get.selectionCount() >= settings.maxSelections);
  5841. },
  5842. allResultsFiltered: function() {
  5843. var
  5844. $normalResults = $item.not(selector.addition)
  5845. ;
  5846. return ($normalResults.filter(selector.unselectable).length === $normalResults.length);
  5847. },
  5848. userSuggestion: function() {
  5849. return ($menu.children(selector.addition).length > 0);
  5850. },
  5851. query: function() {
  5852. return (module.get.query() !== '');
  5853. },
  5854. value: function(value) {
  5855. return (settings.ignoreCase)
  5856. ? module.has.valueIgnoringCase(value)
  5857. : module.has.valueMatchingCase(value)
  5858. ;
  5859. },
  5860. valueMatchingCase: function(value) {
  5861. var
  5862. values = module.get.values(),
  5863. hasValue = Array.isArray(values)
  5864. ? values && ($.inArray(value, values) !== -1)
  5865. : (values == value)
  5866. ;
  5867. return (hasValue)
  5868. ? true
  5869. : false
  5870. ;
  5871. },
  5872. valueIgnoringCase: function(value) {
  5873. var
  5874. values = module.get.values(),
  5875. hasValue = false
  5876. ;
  5877. if(!Array.isArray(values)) {
  5878. values = [values];
  5879. }
  5880. $.each(values, function(index, existingValue) {
  5881. if(String(value).toLowerCase() == String(existingValue).toLowerCase()) {
  5882. hasValue = true;
  5883. return false;
  5884. }
  5885. });
  5886. return hasValue;
  5887. }
  5888. },
  5889. is: {
  5890. active: function() {
  5891. return $module.hasClass(className.active);
  5892. },
  5893. animatingInward: function() {
  5894. return $menu.transition('is inward');
  5895. },
  5896. animatingOutward: function() {
  5897. return $menu.transition('is outward');
  5898. },
  5899. bubbledLabelClick: function(event) {
  5900. return $(event.target).is('select, input') && $module.closest('label').length > 0;
  5901. },
  5902. bubbledIconClick: function(event) {
  5903. return $(event.target).closest($icon).length > 0;
  5904. },
  5905. alreadySetup: function() {
  5906. return ($module.is('select') && $module.parent(selector.dropdown).data(moduleNamespace) !== undefined && $module.prev().length === 0);
  5907. },
  5908. animating: function($subMenu) {
  5909. return ($subMenu)
  5910. ? $subMenu.transition && $subMenu.transition('is animating')
  5911. : $menu.transition && $menu.transition('is animating')
  5912. ;
  5913. },
  5914. leftward: function($subMenu) {
  5915. var $selectedMenu = $subMenu || $menu;
  5916. return $selectedMenu.hasClass(className.leftward);
  5917. },
  5918. clearable: function() {
  5919. return ($module.hasClass(className.clearable) || settings.clearable);
  5920. },
  5921. disabled: function() {
  5922. return $module.hasClass(className.disabled);
  5923. },
  5924. focused: function() {
  5925. return (document.activeElement === $module[0]);
  5926. },
  5927. focusedOnSearch: function() {
  5928. return (document.activeElement === $search[0]);
  5929. },
  5930. allFiltered: function() {
  5931. return( (module.is.multiple() || module.has.search()) && !(settings.hideAdditions == false && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered() );
  5932. },
  5933. hidden: function($subMenu) {
  5934. return !module.is.visible($subMenu);
  5935. },
  5936. initialLoad: function() {
  5937. return initialLoad;
  5938. },
  5939. inObject: function(needle, object) {
  5940. var
  5941. found = false
  5942. ;
  5943. $.each(object, function(index, property) {
  5944. if(property == needle) {
  5945. found = true;
  5946. return true;
  5947. }
  5948. });
  5949. return found;
  5950. },
  5951. multiple: function() {
  5952. return $module.hasClass(className.multiple);
  5953. },
  5954. remote: function() {
  5955. return settings.apiSettings && module.can.useAPI();
  5956. },
  5957. single: function() {
  5958. return !module.is.multiple();
  5959. },
  5960. selectMutation: function(mutations) {
  5961. var
  5962. selectChanged = false
  5963. ;
  5964. $.each(mutations, function(index, mutation) {
  5965. if($(mutation.target).is('select') || $(mutation.addedNodes).is('select')) {
  5966. selectChanged = true;
  5967. return false;
  5968. }
  5969. });
  5970. return selectChanged;
  5971. },
  5972. search: function() {
  5973. return $module.hasClass(className.search);
  5974. },
  5975. searchSelection: function() {
  5976. return ( module.has.search() && $search.parent(selector.dropdown).length === 1 );
  5977. },
  5978. selection: function() {
  5979. return $module.hasClass(className.selection);
  5980. },
  5981. userValue: function(value) {
  5982. return ($.inArray(value, module.get.userValues()) !== -1);
  5983. },
  5984. upward: function($menu) {
  5985. var $element = $menu || $module;
  5986. return $element.hasClass(className.upward);
  5987. },
  5988. visible: function($subMenu) {
  5989. return ($subMenu)
  5990. ? $subMenu.hasClass(className.visible)
  5991. : $menu.hasClass(className.visible)
  5992. ;
  5993. },
  5994. verticallyScrollableContext: function() {
  5995. var
  5996. overflowY = ($context.get(0) !== window)
  5997. ? $context.css('overflow-y')
  5998. : false
  5999. ;
  6000. return (overflowY == 'auto' || overflowY == 'scroll');
  6001. },
  6002. horizontallyScrollableContext: function() {
  6003. var
  6004. overflowX = ($context.get(0) !== window)
  6005. ? $context.css('overflow-X')
  6006. : false
  6007. ;
  6008. return (overflowX == 'auto' || overflowX == 'scroll');
  6009. }
  6010. },
  6011. can: {
  6012. activate: function($item) {
  6013. if(settings.useLabels) {
  6014. return true;
  6015. }
  6016. if(!module.has.maxSelections()) {
  6017. return true;
  6018. }
  6019. if(module.has.maxSelections() && $item.hasClass(className.active)) {
  6020. return true;
  6021. }
  6022. return false;
  6023. },
  6024. openDownward: function($subMenu) {
  6025. var
  6026. $currentMenu = $subMenu || $menu,
  6027. canOpenDownward = true,
  6028. onScreen = {},
  6029. calculations
  6030. ;
  6031. $currentMenu
  6032. .addClass(className.loading)
  6033. ;
  6034. calculations = {
  6035. context: {
  6036. offset : ($context.get(0) === window)
  6037. ? { top: 0, left: 0}
  6038. : $context.offset(),
  6039. scrollTop : $context.scrollTop(),
  6040. height : $context.outerHeight()
  6041. },
  6042. menu : {
  6043. offset: $currentMenu.offset(),
  6044. height: $currentMenu.outerHeight()
  6045. }
  6046. };
  6047. if(module.is.verticallyScrollableContext()) {
  6048. calculations.menu.offset.top += calculations.context.scrollTop;
  6049. }
  6050. onScreen = {
  6051. above : (calculations.context.scrollTop) <= calculations.menu.offset.top - calculations.context.offset.top - calculations.menu.height,
  6052. below : (calculations.context.scrollTop + calculations.context.height) >= calculations.menu.offset.top - calculations.context.offset.top + calculations.menu.height
  6053. };
  6054. if(onScreen.below) {
  6055. module.verbose('Dropdown can fit in context downward', onScreen);
  6056. canOpenDownward = true;
  6057. }
  6058. else if(!onScreen.below && !onScreen.above) {
  6059. module.verbose('Dropdown cannot fit in either direction, favoring downward', onScreen);
  6060. canOpenDownward = true;
  6061. }
  6062. else {
  6063. module.verbose('Dropdown cannot fit below, opening upward', onScreen);
  6064. canOpenDownward = false;
  6065. }
  6066. $currentMenu.removeClass(className.loading);
  6067. return canOpenDownward;
  6068. },
  6069. openRightward: function($subMenu) {
  6070. var
  6071. $currentMenu = $subMenu || $menu,
  6072. canOpenRightward = true,
  6073. isOffscreenRight = false,
  6074. calculations
  6075. ;
  6076. $currentMenu
  6077. .addClass(className.loading)
  6078. ;
  6079. calculations = {
  6080. context: {
  6081. offset : ($context.get(0) === window)
  6082. ? { top: 0, left: 0}
  6083. : $context.offset(),
  6084. scrollLeft : $context.scrollLeft(),
  6085. width : $context.outerWidth()
  6086. },
  6087. menu: {
  6088. offset : $currentMenu.offset(),
  6089. width : $currentMenu.outerWidth()
  6090. }
  6091. };
  6092. if(module.is.horizontallyScrollableContext()) {
  6093. calculations.menu.offset.left += calculations.context.scrollLeft;
  6094. }
  6095. isOffscreenRight = (calculations.menu.offset.left - calculations.context.offset.left + calculations.menu.width >= calculations.context.scrollLeft + calculations.context.width);
  6096. if(isOffscreenRight) {
  6097. module.verbose('Dropdown cannot fit in context rightward', isOffscreenRight);
  6098. canOpenRightward = false;
  6099. }
  6100. $currentMenu.removeClass(className.loading);
  6101. return canOpenRightward;
  6102. },
  6103. click: function() {
  6104. return (hasTouch || settings.on == 'click');
  6105. },
  6106. extendSelect: function() {
  6107. return settings.allowAdditions || settings.apiSettings;
  6108. },
  6109. show: function() {
  6110. return !module.is.disabled() && (module.has.items() || module.has.message());
  6111. },
  6112. useAPI: function() {
  6113. return $.fn.api !== undefined;
  6114. }
  6115. },
  6116. animate: {
  6117. show: function(callback, $subMenu) {
  6118. var
  6119. $currentMenu = $subMenu || $menu,
  6120. start = ($subMenu)
  6121. ? function() {}
  6122. : function() {
  6123. module.hideSubMenus();
  6124. module.hideOthers();
  6125. module.set.active();
  6126. },
  6127. transition
  6128. ;
  6129. callback = $.isFunction(callback)
  6130. ? callback
  6131. : function(){}
  6132. ;
  6133. module.verbose('Doing menu show animation', $currentMenu);
  6134. module.set.direction($subMenu);
  6135. transition = module.get.transition($subMenu);
  6136. if( module.is.selection() ) {
  6137. module.set.scrollPosition(module.get.selectedItem(), true);
  6138. }
  6139. if( module.is.hidden($currentMenu) || module.is.animating($currentMenu) ) {
  6140. var displayType = $module.hasClass('column') ? 'flex' : false;
  6141. if(transition == 'none') {
  6142. start();
  6143. $currentMenu.transition({
  6144. displayType: displayType
  6145. }).transition('show');
  6146. callback.call(element);
  6147. }
  6148. else if($.fn.transition !== undefined && $module.transition('is supported')) {
  6149. $currentMenu
  6150. .transition({
  6151. animation : transition + ' in',
  6152. debug : settings.debug,
  6153. verbose : settings.verbose,
  6154. duration : settings.duration,
  6155. queue : true,
  6156. onStart : start,
  6157. displayType: displayType,
  6158. onComplete : function() {
  6159. callback.call(element);
  6160. }
  6161. })
  6162. ;
  6163. }
  6164. else {
  6165. module.error(error.noTransition, transition);
  6166. }
  6167. }
  6168. },
  6169. hide: function(callback, $subMenu) {
  6170. var
  6171. $currentMenu = $subMenu || $menu,
  6172. start = ($subMenu)
  6173. ? function() {}
  6174. : function() {
  6175. if( module.can.click() ) {
  6176. module.unbind.intent();
  6177. }
  6178. module.remove.active();
  6179. },
  6180. transition = module.get.transition($subMenu)
  6181. ;
  6182. callback = $.isFunction(callback)
  6183. ? callback
  6184. : function(){}
  6185. ;
  6186. if( module.is.visible($currentMenu) || module.is.animating($currentMenu) ) {
  6187. module.verbose('Doing menu hide animation', $currentMenu);
  6188. if(transition == 'none') {
  6189. start();
  6190. $currentMenu.transition('hide');
  6191. callback.call(element);
  6192. }
  6193. else if($.fn.transition !== undefined && $module.transition('is supported')) {
  6194. $currentMenu
  6195. .transition({
  6196. animation : transition + ' out',
  6197. duration : settings.duration,
  6198. debug : settings.debug,
  6199. verbose : settings.verbose,
  6200. queue : false,
  6201. onStart : start,
  6202. onComplete : function() {
  6203. callback.call(element);
  6204. }
  6205. })
  6206. ;
  6207. }
  6208. else {
  6209. module.error(error.transition);
  6210. }
  6211. }
  6212. }
  6213. },
  6214. hideAndClear: function() {
  6215. module.remove.searchTerm();
  6216. if( module.has.maxSelections() ) {
  6217. return;
  6218. }
  6219. if(module.has.search()) {
  6220. module.hide(function() {
  6221. module.remove.filteredItem();
  6222. });
  6223. }
  6224. else {
  6225. module.hide();
  6226. }
  6227. },
  6228. delay: {
  6229. show: function() {
  6230. module.verbose('Delaying show event to ensure user intent');
  6231. clearTimeout(module.timer);
  6232. module.timer = setTimeout(module.show, settings.delay.show);
  6233. },
  6234. hide: function() {
  6235. module.verbose('Delaying hide event to ensure user intent');
  6236. clearTimeout(module.timer);
  6237. module.timer = setTimeout(module.hide, settings.delay.hide);
  6238. }
  6239. },
  6240. escape: {
  6241. value: function(value) {
  6242. var
  6243. multipleValues = Array.isArray(value),
  6244. stringValue = (typeof value === 'string'),
  6245. isUnparsable = (!stringValue && !multipleValues),
  6246. hasQuotes = (stringValue && value.search(regExp.quote) !== -1),
  6247. values = []
  6248. ;
  6249. if(isUnparsable || !hasQuotes) {
  6250. return value;
  6251. }
  6252. module.debug('Encoding quote values for use in select', value);
  6253. if(multipleValues) {
  6254. $.each(value, function(index, value){
  6255. values.push(value.replace(regExp.quote, '&quot;'));
  6256. });
  6257. return values;
  6258. }
  6259. return value.replace(regExp.quote, '&quot;');
  6260. },
  6261. string: function(text) {
  6262. text = String(text);
  6263. return text.replace(regExp.escape, '\\$&');
  6264. },
  6265. htmlEntities: function(string) {
  6266. var
  6267. badChars = /[<>"'`]/g,
  6268. shouldEscape = /[&<>"'`]/,
  6269. escape = {
  6270. "<": "&lt;",
  6271. ">": "&gt;",
  6272. '"': "&quot;",
  6273. "'": "&#x27;",
  6274. "`": "&#x60;"
  6275. },
  6276. escapedChar = function(chr) {
  6277. return escape[chr];
  6278. }
  6279. ;
  6280. if(shouldEscape.test(string)) {
  6281. string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
  6282. return string.replace(badChars, escapedChar);
  6283. }
  6284. return string;
  6285. }
  6286. },
  6287. setting: function(name, value) {
  6288. module.debug('Changing setting', name, value);
  6289. if( $.isPlainObject(name) ) {
  6290. $.extend(true, settings, name);
  6291. }
  6292. else if(value !== undefined) {
  6293. if($.isPlainObject(settings[name])) {
  6294. $.extend(true, settings[name], value);
  6295. }
  6296. else {
  6297. settings[name] = value;
  6298. }
  6299. }
  6300. else {
  6301. return settings[name];
  6302. }
  6303. },
  6304. internal: function(name, value) {
  6305. if( $.isPlainObject(name) ) {
  6306. $.extend(true, module, name);
  6307. }
  6308. else if(value !== undefined) {
  6309. module[name] = value;
  6310. }
  6311. else {
  6312. return module[name];
  6313. }
  6314. },
  6315. debug: function() {
  6316. if(!settings.silent && settings.debug) {
  6317. if(settings.performance) {
  6318. module.performance.log(arguments);
  6319. }
  6320. else {
  6321. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  6322. module.debug.apply(console, arguments);
  6323. }
  6324. }
  6325. },
  6326. verbose: function() {
  6327. if(!settings.silent && settings.verbose && settings.debug) {
  6328. if(settings.performance) {
  6329. module.performance.log(arguments);
  6330. }
  6331. else {
  6332. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  6333. module.verbose.apply(console, arguments);
  6334. }
  6335. }
  6336. },
  6337. error: function() {
  6338. if(!settings.silent) {
  6339. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  6340. module.error.apply(console, arguments);
  6341. }
  6342. },
  6343. performance: {
  6344. log: function(message) {
  6345. var
  6346. currentTime,
  6347. executionTime,
  6348. previousTime
  6349. ;
  6350. if(settings.performance) {
  6351. currentTime = new Date().getTime();
  6352. previousTime = time || currentTime;
  6353. executionTime = currentTime - previousTime;
  6354. time = currentTime;
  6355. performance.push({
  6356. 'Name' : message[0],
  6357. 'Arguments' : [].slice.call(message, 1) || '',
  6358. 'Element' : element,
  6359. 'Execution Time' : executionTime
  6360. });
  6361. }
  6362. clearTimeout(module.performance.timer);
  6363. module.performance.timer = setTimeout(module.performance.display, 500);
  6364. },
  6365. display: function() {
  6366. var
  6367. title = settings.name + ':',
  6368. totalTime = 0
  6369. ;
  6370. time = false;
  6371. clearTimeout(module.performance.timer);
  6372. $.each(performance, function(index, data) {
  6373. totalTime += data['Execution Time'];
  6374. });
  6375. title += ' ' + totalTime + 'ms';
  6376. if(moduleSelector) {
  6377. title += ' \'' + moduleSelector + '\'';
  6378. }
  6379. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  6380. console.groupCollapsed(title);
  6381. if(console.table) {
  6382. console.table(performance);
  6383. }
  6384. else {
  6385. $.each(performance, function(index, data) {
  6386. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  6387. });
  6388. }
  6389. console.groupEnd();
  6390. }
  6391. performance = [];
  6392. }
  6393. },
  6394. invoke: function(query, passedArguments, context) {
  6395. var
  6396. object = instance,
  6397. maxDepth,
  6398. found,
  6399. response
  6400. ;
  6401. passedArguments = passedArguments || queryArguments;
  6402. context = element || context;
  6403. if(typeof query == 'string' && object !== undefined) {
  6404. query = query.split(/[\. ]/);
  6405. maxDepth = query.length - 1;
  6406. $.each(query, function(depth, value) {
  6407. var camelCaseValue = (depth != maxDepth)
  6408. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  6409. : query
  6410. ;
  6411. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  6412. object = object[camelCaseValue];
  6413. }
  6414. else if( object[camelCaseValue] !== undefined ) {
  6415. found = object[camelCaseValue];
  6416. return false;
  6417. }
  6418. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  6419. object = object[value];
  6420. }
  6421. else if( object[value] !== undefined ) {
  6422. found = object[value];
  6423. return false;
  6424. }
  6425. else {
  6426. module.error(error.method, query);
  6427. return false;
  6428. }
  6429. });
  6430. }
  6431. if ( $.isFunction( found ) ) {
  6432. response = found.apply(context, passedArguments);
  6433. }
  6434. else if(found !== undefined) {
  6435. response = found;
  6436. }
  6437. if(Array.isArray(returnedValue)) {
  6438. returnedValue.push(response);
  6439. }
  6440. else if(returnedValue !== undefined) {
  6441. returnedValue = [returnedValue, response];
  6442. }
  6443. else if(response !== undefined) {
  6444. returnedValue = response;
  6445. }
  6446. return found;
  6447. }
  6448. };
  6449. if(methodInvoked) {
  6450. if(instance === undefined) {
  6451. module.initialize();
  6452. }
  6453. module.invoke(query);
  6454. }
  6455. else {
  6456. if(instance !== undefined) {
  6457. instance.invoke('destroy');
  6458. }
  6459. module.initialize();
  6460. }
  6461. })
  6462. ;
  6463. return (returnedValue !== undefined)
  6464. ? returnedValue
  6465. : $allModules
  6466. ;
  6467. };
  6468. $.fn.dropdown.settings = {
  6469. silent : false,
  6470. debug : false,
  6471. verbose : false,
  6472. performance : true,
  6473. on : 'click', // what event should show menu action on item selection
  6474. action : 'activate', // action on item selection (nothing, activate, select, combo, hide, function(){})
  6475. values : false, // specify values to use for dropdown
  6476. clearable : false, // whether the value of the dropdown can be cleared
  6477. apiSettings : false,
  6478. selectOnKeydown : true, // Whether selection should occur automatically when keyboard shortcuts used
  6479. minCharacters : 0, // Minimum characters required to trigger API call
  6480. filterRemoteData : false, // Whether API results should be filtered after being returned for query term
  6481. saveRemoteData : true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
  6482. throttle : 200, // How long to wait after last user input to search remotely
  6483. context : window, // Context to use when determining if on screen
  6484. direction : 'auto', // Whether dropdown should always open in one direction
  6485. keepOnScreen : true, // Whether dropdown should check whether it is on screen before showing
  6486. match : 'both', // what to match against with search selection (both, text, or label)
  6487. fullTextSearch : false, // search anywhere in value (set to 'exact' to require exact matches)
  6488. 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...)
  6489. 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)
  6490. placeholder : 'auto', // whether to convert blank <select> values to placeholder text
  6491. preserveHTML : true, // preserve html when selecting value
  6492. sortSelect : false, // sort selection on init
  6493. forceSelection : true, // force a choice on blur with search selection
  6494. allowAdditions : false, // whether multiple select should allow user added values
  6495. ignoreCase : false, // whether to consider case sensitivity when creating labels
  6496. ignoreSearchCase : true, // whether to consider case sensitivity when filtering items
  6497. hideAdditions : true, // whether or not to hide special message prompting a user they can enter a value
  6498. maxSelections : false, // When set to a number limits the number of selections to this count
  6499. useLabels : true, // whether multiple select should filter currently active selections from choices
  6500. delimiter : ',', // when multiselect uses normal <input> the values will be delimited with this character
  6501. showOnFocus : true, // show menu on focus
  6502. allowReselection : false, // whether current value should trigger callbacks when reselected
  6503. allowTab : true, // add tabindex to element
  6504. allowCategorySelection : false, // allow elements with sub-menus to be selected
  6505. fireOnInit : false, // Whether callbacks should fire when initializing dropdown values
  6506. transition : 'auto', // auto transition will slide down or up based on direction
  6507. duration : 200, // duration of transition
  6508. glyphWidth : 1.037, // widest glyph width in em (W is 1.037 em) used to calculate multiselect input width
  6509. headerDivider : true, // whether option headers should have an additional divider line underneath when converted from <select> <optgroup>
  6510. // label settings on multi-select
  6511. label: {
  6512. transition : 'scale',
  6513. duration : 200,
  6514. variation : false
  6515. },
  6516. // delay before event
  6517. delay : {
  6518. hide : 300,
  6519. show : 200,
  6520. search : 20,
  6521. touch : 50
  6522. },
  6523. /* Callbacks */
  6524. onChange : function(value, text, $selected){},
  6525. onAdd : function(value, text, $selected){},
  6526. onRemove : function(value, text, $selected){},
  6527. onLabelSelect : function($selectedLabels){},
  6528. onLabelCreate : function(value, text) { return $(this); },
  6529. onLabelRemove : function(value) { return true; },
  6530. onNoResults : function(searchTerm) { return true; },
  6531. onShow : function(){},
  6532. onHide : function(){},
  6533. /* Component */
  6534. name : 'Dropdown',
  6535. namespace : 'dropdown',
  6536. message: {
  6537. addResult : 'Add <b>{term}</b>',
  6538. count : '{count} selected',
  6539. maxSelections : 'Max {maxCount} selections',
  6540. noResults : 'No results found.',
  6541. serverError : 'There was an error contacting the server'
  6542. },
  6543. error : {
  6544. action : 'You called a dropdown action that was not defined',
  6545. alreadySetup : 'Once a select has been initialized behaviors must be called on the created ui dropdown',
  6546. labels : 'Allowing user additions currently requires the use of labels.',
  6547. missingMultiple : '<select> requires multiple property to be set to correctly preserve multiple values',
  6548. method : 'The method you called is not defined.',
  6549. noAPI : 'The API module is required to load resources remotely',
  6550. noStorage : 'Saving remote data requires session storage',
  6551. noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>',
  6552. 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.'
  6553. },
  6554. regExp : {
  6555. escape : /[-[\]{}()*+?.,\\^$|#\s:=@]/g,
  6556. quote : /"/g
  6557. },
  6558. metadata : {
  6559. defaultText : 'defaultText',
  6560. defaultValue : 'defaultValue',
  6561. placeholderText : 'placeholder',
  6562. text : 'text',
  6563. value : 'value'
  6564. },
  6565. // property names for remote query
  6566. fields: {
  6567. remoteValues : 'results', // grouping for api results
  6568. values : 'values', // grouping for all dropdown values
  6569. disabled : 'disabled', // whether value should be disabled
  6570. name : 'name', // displayed dropdown text
  6571. value : 'value', // actual dropdown value
  6572. text : 'text', // displayed text when selected
  6573. type : 'type', // type of dropdown element
  6574. image : 'image', // optional image path
  6575. imageClass : 'imageClass', // optional individual class for image
  6576. icon : 'icon', // optional icon name
  6577. iconClass : 'iconClass', // optional individual class for icon (for example to use flag instead)
  6578. class : 'class', // optional individual class for item/header
  6579. divider : 'divider' // optional divider append for group headers
  6580. },
  6581. keys : {
  6582. backspace : 8,
  6583. delimiter : 188, // comma
  6584. deleteKey : 46,
  6585. enter : 13,
  6586. escape : 27,
  6587. pageUp : 33,
  6588. pageDown : 34,
  6589. leftArrow : 37,
  6590. upArrow : 38,
  6591. rightArrow : 39,
  6592. downArrow : 40
  6593. },
  6594. selector : {
  6595. addition : '.addition',
  6596. divider : '.divider, .header',
  6597. dropdown : '.ui.dropdown',
  6598. hidden : '.hidden',
  6599. icon : '> .dropdown.icon',
  6600. input : '> input[type="hidden"], > select',
  6601. item : '.item',
  6602. label : '> .label',
  6603. remove : '> .label > .delete.icon',
  6604. siblingLabel : '.label',
  6605. menu : '.menu',
  6606. message : '.message',
  6607. menuIcon : '.dropdown.icon',
  6608. search : 'input.search, .menu > .search > input, .menu input.search',
  6609. sizer : '> span.sizer',
  6610. text : '> .text:not(.icon)',
  6611. unselectable : '.disabled, .filtered',
  6612. clearIcon : '> .remove.icon'
  6613. },
  6614. className : {
  6615. active : 'active',
  6616. addition : 'addition',
  6617. animating : 'animating',
  6618. disabled : 'disabled',
  6619. empty : 'empty',
  6620. dropdown : 'ui dropdown',
  6621. filtered : 'filtered',
  6622. hidden : 'hidden transition',
  6623. icon : 'icon',
  6624. image : 'image',
  6625. item : 'item',
  6626. label : 'ui label',
  6627. loading : 'loading',
  6628. menu : 'menu',
  6629. message : 'message',
  6630. multiple : 'multiple',
  6631. placeholder : 'default',
  6632. sizer : 'sizer',
  6633. search : 'search',
  6634. selected : 'selected',
  6635. selection : 'selection',
  6636. upward : 'upward',
  6637. leftward : 'left',
  6638. visible : 'visible',
  6639. clearable : 'clearable',
  6640. noselection : 'noselection',
  6641. delete : 'delete',
  6642. header : 'header',
  6643. divider : 'divider',
  6644. groupIcon : '',
  6645. unfilterable : 'unfilterable'
  6646. }
  6647. };
  6648. /* Templates */
  6649. $.fn.dropdown.settings.templates = {
  6650. deQuote: function(string) {
  6651. return String(string).replace(/"/g,"");
  6652. },
  6653. escape: function(string, preserveHTML) {
  6654. if (preserveHTML){
  6655. return string;
  6656. }
  6657. var
  6658. badChars = /[<>"'`]/g,
  6659. shouldEscape = /[&<>"'`]/,
  6660. escape = {
  6661. "<": "&lt;",
  6662. ">": "&gt;",
  6663. '"': "&quot;",
  6664. "'": "&#x27;",
  6665. "`": "&#x60;"
  6666. },
  6667. escapedChar = function(chr) {
  6668. return escape[chr];
  6669. }
  6670. ;
  6671. if(shouldEscape.test(string)) {
  6672. string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
  6673. return string.replace(badChars, escapedChar);
  6674. }
  6675. return string;
  6676. },
  6677. // generates dropdown from select values
  6678. dropdown: function(select, fields, preserveHTML, className) {
  6679. var
  6680. placeholder = select.placeholder || false,
  6681. html = '',
  6682. escape = $.fn.dropdown.settings.templates.escape
  6683. ;
  6684. html += '<i class="dropdown icon"></i>';
  6685. if(placeholder) {
  6686. html += '<div class="default text">' + escape(placeholder,preserveHTML) + '</div>';
  6687. }
  6688. else {
  6689. html += '<div class="text"></div>';
  6690. }
  6691. html += '<div class="'+className.menu+'">';
  6692. html += $.fn.dropdown.settings.templates.menu(select, fields, preserveHTML,className);
  6693. html += '</div>';
  6694. return html;
  6695. },
  6696. // generates just menu from select
  6697. menu: function(response, fields, preserveHTML, className) {
  6698. var
  6699. values = response[fields.values] || [],
  6700. html = '',
  6701. escape = $.fn.dropdown.settings.templates.escape,
  6702. deQuote = $.fn.dropdown.settings.templates.deQuote
  6703. ;
  6704. $.each(values, function(index, option) {
  6705. var
  6706. itemType = (option[fields.type])
  6707. ? option[fields.type]
  6708. : 'item'
  6709. ;
  6710. if( itemType === 'item' ) {
  6711. var
  6712. maybeText = (option[fields.text])
  6713. ? ' data-text="' + deQuote(option[fields.text]) + '"'
  6714. : '',
  6715. maybeDisabled = (option[fields.disabled])
  6716. ? className.disabled+' '
  6717. : ''
  6718. ;
  6719. html += '<div class="'+ maybeDisabled + (option[fields.class] ? deQuote(option[fields.class]) : className.item)+'" data-value="' + deQuote(option[fields.value]) + '"' + maybeText + '>';
  6720. if(option[fields.image]) {
  6721. html += '<img class="'+(option[fields.imageClass] ? deQuote(option[fields.imageClass]) : className.image)+'" src="' + deQuote(option[fields.image]) + '">';
  6722. }
  6723. if(option[fields.icon]) {
  6724. html += '<i class="'+deQuote(option[fields.icon])+' '+(option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon)+'"></i>';
  6725. }
  6726. html += escape(option[fields.name] || '', preserveHTML);
  6727. html += '</div>';
  6728. } else if (itemType === 'header') {
  6729. var groupName = escape(option[fields.name] || '', preserveHTML),
  6730. groupIcon = option[fields.icon] ? deQuote(option[fields.icon]) : className.groupIcon
  6731. ;
  6732. if(groupName !== '' || groupIcon !== '') {
  6733. html += '<div class="' + (option[fields.class] ? deQuote(option[fields.class]) : className.header) + '">';
  6734. if (groupIcon !== '') {
  6735. html += '<i class="' + groupIcon + ' ' + (option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon) + '"></i>';
  6736. }
  6737. html += groupName;
  6738. html += '</div>';
  6739. }
  6740. if(option[fields.divider]){
  6741. html += '<div class="'+className.divider+'"></div>';
  6742. }
  6743. }
  6744. });
  6745. return html;
  6746. },
  6747. // generates label for multiselect
  6748. label: function(value, text, preserveHTML, className) {
  6749. var
  6750. escape = $.fn.dropdown.settings.templates.escape;
  6751. return escape(text,preserveHTML) + '<i class="'+className.delete+' icon"></i>';
  6752. },
  6753. // generates messages like "No results"
  6754. message: function(message) {
  6755. return message;
  6756. },
  6757. // generates user addition to selection menu
  6758. addition: function(choice) {
  6759. return choice;
  6760. }
  6761. };
  6762. })( jQuery, window, document );
  6763. /*!
  6764. * # Fomantic-UI - Form Validation
  6765. * http://github.com/fomantic/Fomantic-UI/
  6766. *
  6767. *
  6768. * Released under the MIT license
  6769. * http://opensource.org/licenses/MIT
  6770. *
  6771. */
  6772. ;(function ($, window, document, undefined) {
  6773. 'use strict';
  6774. $.isFunction = $.isFunction || function(obj) {
  6775. return typeof obj === "function" && typeof obj.nodeType !== "number";
  6776. };
  6777. window = (typeof window != 'undefined' && window.Math == Math)
  6778. ? window
  6779. : (typeof self != 'undefined' && self.Math == Math)
  6780. ? self
  6781. : Function('return this')()
  6782. ;
  6783. $.fn.form = function(parameters) {
  6784. var
  6785. $allModules = $(this),
  6786. moduleSelector = $allModules.selector || '',
  6787. time = new Date().getTime(),
  6788. performance = [],
  6789. query = arguments[0],
  6790. legacyParameters = arguments[1],
  6791. methodInvoked = (typeof query == 'string'),
  6792. queryArguments = [].slice.call(arguments, 1),
  6793. returnedValue
  6794. ;
  6795. $allModules
  6796. .each(function() {
  6797. var
  6798. $module = $(this),
  6799. element = this,
  6800. formErrors = [],
  6801. keyHeldDown = false,
  6802. // set at run-time
  6803. $field,
  6804. $group,
  6805. $message,
  6806. $prompt,
  6807. $submit,
  6808. $clear,
  6809. $reset,
  6810. settings,
  6811. validation,
  6812. metadata,
  6813. selector,
  6814. className,
  6815. regExp,
  6816. error,
  6817. namespace,
  6818. moduleNamespace,
  6819. eventNamespace,
  6820. submitting = false,
  6821. dirty = false,
  6822. history = ['clean', 'clean'],
  6823. instance,
  6824. module
  6825. ;
  6826. module = {
  6827. initialize: function() {
  6828. // settings grabbed at run time
  6829. module.get.settings();
  6830. if(methodInvoked) {
  6831. if(instance === undefined) {
  6832. module.instantiate();
  6833. }
  6834. module.invoke(query);
  6835. }
  6836. else {
  6837. if(instance !== undefined) {
  6838. instance.invoke('destroy');
  6839. }
  6840. module.verbose('Initializing form validation', $module, settings);
  6841. module.bindEvents();
  6842. module.set.defaults();
  6843. if (settings.autoCheckRequired) {
  6844. module.set.autoCheck();
  6845. }
  6846. module.instantiate();
  6847. }
  6848. },
  6849. instantiate: function() {
  6850. module.verbose('Storing instance of module', module);
  6851. instance = module;
  6852. $module
  6853. .data(moduleNamespace, module)
  6854. ;
  6855. },
  6856. destroy: function() {
  6857. module.verbose('Destroying previous module', instance);
  6858. module.removeEvents();
  6859. $module
  6860. .removeData(moduleNamespace)
  6861. ;
  6862. },
  6863. refresh: function() {
  6864. module.verbose('Refreshing selector cache');
  6865. $field = $module.find(selector.field);
  6866. $group = $module.find(selector.group);
  6867. $message = $module.find(selector.message);
  6868. $prompt = $module.find(selector.prompt);
  6869. $submit = $module.find(selector.submit);
  6870. $clear = $module.find(selector.clear);
  6871. $reset = $module.find(selector.reset);
  6872. },
  6873. submit: function() {
  6874. module.verbose('Submitting form', $module);
  6875. submitting = true;
  6876. $module.submit();
  6877. },
  6878. attachEvents: function(selector, action) {
  6879. action = action || 'submit';
  6880. $(selector).on('click' + eventNamespace, function(event) {
  6881. module[action]();
  6882. event.preventDefault();
  6883. });
  6884. },
  6885. bindEvents: function() {
  6886. module.verbose('Attaching form events');
  6887. $module
  6888. .on('submit' + eventNamespace, module.validate.form)
  6889. .on('blur' + eventNamespace, selector.field, module.event.field.blur)
  6890. .on('click' + eventNamespace, selector.submit, module.submit)
  6891. .on('click' + eventNamespace, selector.reset, module.reset)
  6892. .on('click' + eventNamespace, selector.clear, module.clear)
  6893. ;
  6894. if(settings.keyboardShortcuts) {
  6895. $module.on('keydown' + eventNamespace, selector.field, module.event.field.keydown);
  6896. }
  6897. $field.each(function(index, el) {
  6898. var
  6899. $input = $(el),
  6900. type = $input.prop('type'),
  6901. inputEvent = module.get.changeEvent(type, $input)
  6902. ;
  6903. $input.on(inputEvent + eventNamespace, module.event.field.change);
  6904. });
  6905. // Dirty events
  6906. if (settings.preventLeaving) {
  6907. $(window).on('beforeunload' + eventNamespace, module.event.beforeUnload);
  6908. }
  6909. $field.on('change click keyup keydown blur', function(e) {
  6910. $(this).triggerHandler(e.type + ".dirty");
  6911. });
  6912. $field.on('change.dirty click.dirty keyup.dirty keydown.dirty blur.dirty', module.determine.isDirty);
  6913. $module.on('dirty' + eventNamespace, function(e) {
  6914. settings.onDirty.call();
  6915. });
  6916. $module.on('clean' + eventNamespace, function(e) {
  6917. settings.onClean.call();
  6918. })
  6919. },
  6920. clear: function() {
  6921. $field.each(function (index, el) {
  6922. var
  6923. $field = $(el),
  6924. $element = $field.parent(),
  6925. $fieldGroup = $field.closest($group),
  6926. $prompt = $fieldGroup.find(selector.prompt),
  6927. $calendar = $field.closest(selector.uiCalendar),
  6928. defaultValue = $field.data(metadata.defaultValue) || '',
  6929. isCheckbox = $element.is(selector.uiCheckbox),
  6930. isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  6931. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  6932. isErrored = $fieldGroup.hasClass(className.error)
  6933. ;
  6934. if(isErrored) {
  6935. module.verbose('Resetting error on field', $fieldGroup);
  6936. $fieldGroup.removeClass(className.error);
  6937. $prompt.remove();
  6938. }
  6939. if(isDropdown) {
  6940. module.verbose('Resetting dropdown value', $element, defaultValue);
  6941. $element.dropdown('clear', true);
  6942. }
  6943. else if(isCheckbox) {
  6944. $field.prop('checked', false);
  6945. }
  6946. else if (isCalendar) {
  6947. $calendar.calendar('clear');
  6948. }
  6949. else {
  6950. module.verbose('Resetting field value', $field, defaultValue);
  6951. $field.val('');
  6952. }
  6953. });
  6954. module.remove.states();
  6955. },
  6956. reset: function() {
  6957. $field.each(function (index, el) {
  6958. var
  6959. $field = $(el),
  6960. $element = $field.parent(),
  6961. $fieldGroup = $field.closest($group),
  6962. $calendar = $field.closest(selector.uiCalendar),
  6963. $prompt = $fieldGroup.find(selector.prompt),
  6964. defaultValue = $field.data(metadata.defaultValue),
  6965. isCheckbox = $element.is(selector.uiCheckbox),
  6966. isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  6967. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  6968. isErrored = $fieldGroup.hasClass(className.error)
  6969. ;
  6970. if(defaultValue === undefined) {
  6971. return;
  6972. }
  6973. if(isErrored) {
  6974. module.verbose('Resetting error on field', $fieldGroup);
  6975. $fieldGroup.removeClass(className.error);
  6976. $prompt.remove();
  6977. }
  6978. if(isDropdown) {
  6979. module.verbose('Resetting dropdown value', $element, defaultValue);
  6980. $element.dropdown('restore defaults', true);
  6981. }
  6982. else if(isCheckbox) {
  6983. module.verbose('Resetting checkbox value', $element, defaultValue);
  6984. $field.prop('checked', defaultValue);
  6985. }
  6986. else if (isCalendar) {
  6987. $calendar.calendar('set date', defaultValue);
  6988. }
  6989. else {
  6990. module.verbose('Resetting field value', $field, defaultValue);
  6991. $field.val(defaultValue);
  6992. }
  6993. });
  6994. module.remove.states();
  6995. },
  6996. determine: {
  6997. isValid: function() {
  6998. var
  6999. allValid = true
  7000. ;
  7001. $.each(validation, function(fieldName, field) {
  7002. if( !( module.validate.field(field, fieldName, true) ) ) {
  7003. allValid = false;
  7004. }
  7005. });
  7006. return allValid;
  7007. },
  7008. isDirty: function(e) {
  7009. var formIsDirty = false;
  7010. $field.each(function(index, el) {
  7011. var
  7012. $el = $(el),
  7013. isCheckbox = ($el.filter(selector.checkbox).length > 0),
  7014. isDirty
  7015. ;
  7016. if (isCheckbox) {
  7017. isDirty = module.is.checkboxDirty($el);
  7018. } else {
  7019. isDirty = module.is.fieldDirty($el);
  7020. }
  7021. $el.data(settings.metadata.isDirty, isDirty);
  7022. formIsDirty |= isDirty;
  7023. });
  7024. if (formIsDirty) {
  7025. module.set.dirty();
  7026. } else {
  7027. module.set.clean();
  7028. }
  7029. if (e && e.namespace === 'dirty') {
  7030. e.stopImmediatePropagation();
  7031. e.preventDefault();
  7032. }
  7033. }
  7034. },
  7035. is: {
  7036. bracketedRule: function(rule) {
  7037. return (rule.type && rule.type.match(settings.regExp.bracket));
  7038. },
  7039. shorthandFields: function(fields) {
  7040. var
  7041. fieldKeys = Object.keys(fields),
  7042. firstRule = fields[fieldKeys[0]]
  7043. ;
  7044. return module.is.shorthandRules(firstRule);
  7045. },
  7046. // duck type rule test
  7047. shorthandRules: function(rules) {
  7048. return (typeof rules == 'string' || Array.isArray(rules));
  7049. },
  7050. empty: function($field) {
  7051. if(!$field || $field.length === 0) {
  7052. return true;
  7053. }
  7054. else if($field.is(selector.checkbox)) {
  7055. return !$field.is(':checked');
  7056. }
  7057. else {
  7058. return module.is.blank($field);
  7059. }
  7060. },
  7061. blank: function($field) {
  7062. return String($field.val()).trim() === '';
  7063. },
  7064. valid: function(field, showErrors) {
  7065. var
  7066. allValid = true
  7067. ;
  7068. if(field) {
  7069. module.verbose('Checking if field is valid', field);
  7070. return module.validate.field(validation[field], field, !!showErrors);
  7071. }
  7072. else {
  7073. module.verbose('Checking if form is valid');
  7074. $.each(validation, function(fieldName, field) {
  7075. if( !module.is.valid(fieldName, showErrors) ) {
  7076. allValid = false;
  7077. }
  7078. });
  7079. return allValid;
  7080. }
  7081. },
  7082. dirty: function() {
  7083. return dirty;
  7084. },
  7085. clean: function() {
  7086. return !dirty;
  7087. },
  7088. fieldDirty: function($el) {
  7089. var initialValue = $el.data(metadata.defaultValue);
  7090. // Explicitly check for null/undefined here as value may be `false`, so ($el.data(dataInitialValue) || '') would not work
  7091. if (initialValue == null) { initialValue = ''; }
  7092. else if(Array.isArray(initialValue)) {
  7093. initialValue = initialValue.toString();
  7094. }
  7095. var currentValue = $el.val();
  7096. if (currentValue == null) { currentValue = ''; }
  7097. // multiple select values are returned as arrays which are never equal, so do string conversion first
  7098. else if(Array.isArray(currentValue)) {
  7099. currentValue = currentValue.toString();
  7100. }
  7101. // Boolean values can be encoded as "true/false" or "True/False" depending on underlying frameworks so we need a case insensitive comparison
  7102. var boolRegex = /^(true|false)$/i;
  7103. var isBoolValue = boolRegex.test(initialValue) && boolRegex.test(currentValue);
  7104. if (isBoolValue) {
  7105. var regex = new RegExp("^" + initialValue + "$", "i");
  7106. return !regex.test(currentValue);
  7107. }
  7108. return currentValue !== initialValue;
  7109. },
  7110. checkboxDirty: function($el) {
  7111. var initialValue = $el.data(metadata.defaultValue);
  7112. var currentValue = $el.is(":checked");
  7113. return initialValue !== currentValue;
  7114. },
  7115. justDirty: function() {
  7116. return (history[0] === 'dirty');
  7117. },
  7118. justClean: function() {
  7119. return (history[0] === 'clean');
  7120. }
  7121. },
  7122. removeEvents: function() {
  7123. $module.off(eventNamespace);
  7124. $field.off(eventNamespace);
  7125. $submit.off(eventNamespace);
  7126. $field.off(eventNamespace);
  7127. },
  7128. event: {
  7129. field: {
  7130. keydown: function(event) {
  7131. var
  7132. $field = $(this),
  7133. key = event.which,
  7134. isInput = $field.is(selector.input),
  7135. isCheckbox = $field.is(selector.checkbox),
  7136. isInDropdown = ($field.closest(selector.uiDropdown).length > 0),
  7137. keyCode = {
  7138. enter : 13,
  7139. escape : 27
  7140. }
  7141. ;
  7142. if( key == keyCode.escape) {
  7143. module.verbose('Escape key pressed blurring field');
  7144. $field
  7145. .blur()
  7146. ;
  7147. }
  7148. if(!event.ctrlKey && key == keyCode.enter && isInput && !isInDropdown && !isCheckbox) {
  7149. if(!keyHeldDown) {
  7150. $field.one('keyup' + eventNamespace, module.event.field.keyup);
  7151. module.submit();
  7152. module.debug('Enter pressed on input submitting form');
  7153. }
  7154. keyHeldDown = true;
  7155. }
  7156. },
  7157. keyup: function() {
  7158. keyHeldDown = false;
  7159. },
  7160. blur: function(event) {
  7161. var
  7162. $field = $(this),
  7163. $fieldGroup = $field.closest($group),
  7164. validationRules = module.get.validation($field)
  7165. ;
  7166. if( $fieldGroup.hasClass(className.error) ) {
  7167. module.debug('Revalidating field', $field, validationRules);
  7168. if(validationRules) {
  7169. module.validate.field( validationRules );
  7170. }
  7171. }
  7172. else if(settings.on == 'blur') {
  7173. if(validationRules) {
  7174. module.validate.field( validationRules );
  7175. }
  7176. }
  7177. },
  7178. change: function(event) {
  7179. var
  7180. $field = $(this),
  7181. $fieldGroup = $field.closest($group),
  7182. validationRules = module.get.validation($field)
  7183. ;
  7184. if(validationRules && (settings.on == 'change' || ( $fieldGroup.hasClass(className.error) && settings.revalidate) )) {
  7185. clearTimeout(module.timer);
  7186. module.timer = setTimeout(function() {
  7187. module.debug('Revalidating field', $field, module.get.validation($field));
  7188. module.validate.field( validationRules );
  7189. if(!settings.inline) {
  7190. module.validate.form(false,true);
  7191. }
  7192. }, settings.delay);
  7193. }
  7194. }
  7195. },
  7196. beforeUnload: function(event) {
  7197. if (module.is.dirty() && !submitting) {
  7198. var event = event || window.event;
  7199. // For modern browsers
  7200. if (event) {
  7201. event.returnValue = settings.text.leavingMessage;
  7202. }
  7203. // For olders...
  7204. return settings.text.leavingMessage;
  7205. }
  7206. }
  7207. },
  7208. get: {
  7209. ancillaryValue: function(rule) {
  7210. if(!rule.type || (!rule.value && !module.is.bracketedRule(rule))) {
  7211. return false;
  7212. }
  7213. return (rule.value !== undefined)
  7214. ? rule.value
  7215. : rule.type.match(settings.regExp.bracket)[1] + ''
  7216. ;
  7217. },
  7218. ruleName: function(rule) {
  7219. if( module.is.bracketedRule(rule) ) {
  7220. return rule.type.replace(rule.type.match(settings.regExp.bracket)[0], '');
  7221. }
  7222. return rule.type;
  7223. },
  7224. changeEvent: function(type, $input) {
  7225. if(type == 'checkbox' || type == 'radio' || type == 'hidden' || $input.is('select')) {
  7226. return 'change';
  7227. }
  7228. else {
  7229. return module.get.inputEvent();
  7230. }
  7231. },
  7232. inputEvent: function() {
  7233. return (document.createElement('input').oninput !== undefined)
  7234. ? 'input'
  7235. : (document.createElement('input').onpropertychange !== undefined)
  7236. ? 'propertychange'
  7237. : 'keyup'
  7238. ;
  7239. },
  7240. fieldsFromShorthand: function(fields) {
  7241. var
  7242. fullFields = {}
  7243. ;
  7244. $.each(fields, function(name, rules) {
  7245. if(typeof rules == 'string') {
  7246. rules = [rules];
  7247. }
  7248. fullFields[name] = {
  7249. rules: []
  7250. };
  7251. $.each(rules, function(index, rule) {
  7252. fullFields[name].rules.push({ type: rule });
  7253. });
  7254. });
  7255. return fullFields;
  7256. },
  7257. prompt: function(rule, field) {
  7258. var
  7259. ruleName = module.get.ruleName(rule),
  7260. ancillary = module.get.ancillaryValue(rule),
  7261. $field = module.get.field(field.identifier),
  7262. value = $field.val(),
  7263. prompt = $.isFunction(rule.prompt)
  7264. ? rule.prompt(value)
  7265. : rule.prompt || settings.prompt[ruleName] || settings.text.unspecifiedRule,
  7266. requiresValue = (prompt.search('{value}') !== -1),
  7267. requiresName = (prompt.search('{name}') !== -1),
  7268. $label,
  7269. name
  7270. ;
  7271. if(requiresValue) {
  7272. prompt = prompt.replace(/\{value\}/g, $field.val());
  7273. }
  7274. if(requiresName) {
  7275. $label = $field.closest(selector.group).find('label').eq(0);
  7276. name = ($label.length == 1)
  7277. ? $label.text()
  7278. : $field.prop('placeholder') || settings.text.unspecifiedField
  7279. ;
  7280. prompt = prompt.replace(/\{name\}/g, name);
  7281. }
  7282. prompt = prompt.replace(/\{identifier\}/g, field.identifier);
  7283. prompt = prompt.replace(/\{ruleValue\}/g, ancillary);
  7284. if(!rule.prompt) {
  7285. module.verbose('Using default validation prompt for type', prompt, ruleName);
  7286. }
  7287. return prompt;
  7288. },
  7289. settings: function() {
  7290. if($.isPlainObject(parameters)) {
  7291. var
  7292. keys = Object.keys(parameters),
  7293. isLegacySettings = (keys.length > 0)
  7294. ? (parameters[keys[0]].identifier !== undefined && parameters[keys[0]].rules !== undefined)
  7295. : false
  7296. ;
  7297. if(isLegacySettings) {
  7298. // 1.x (ducktyped)
  7299. settings = $.extend(true, {}, $.fn.form.settings, legacyParameters);
  7300. validation = $.extend({}, $.fn.form.settings.defaults, parameters);
  7301. module.error(settings.error.oldSyntax, element);
  7302. module.verbose('Extending settings from legacy parameters', validation, settings);
  7303. }
  7304. else {
  7305. // 2.x
  7306. if(parameters.fields && module.is.shorthandFields(parameters.fields)) {
  7307. parameters.fields = module.get.fieldsFromShorthand(parameters.fields);
  7308. }
  7309. settings = $.extend(true, {}, $.fn.form.settings, parameters);
  7310. validation = $.extend({}, $.fn.form.settings.defaults, settings.fields);
  7311. module.verbose('Extending settings', validation, settings);
  7312. }
  7313. }
  7314. else {
  7315. settings = $.fn.form.settings;
  7316. validation = $.fn.form.settings.defaults;
  7317. module.verbose('Using default form validation', validation, settings);
  7318. }
  7319. // shorthand
  7320. namespace = settings.namespace;
  7321. metadata = settings.metadata;
  7322. selector = settings.selector;
  7323. className = settings.className;
  7324. regExp = settings.regExp;
  7325. error = settings.error;
  7326. moduleNamespace = 'module-' + namespace;
  7327. eventNamespace = '.' + namespace;
  7328. // grab instance
  7329. instance = $module.data(moduleNamespace);
  7330. // refresh selector cache
  7331. module.refresh();
  7332. },
  7333. field: function(identifier) {
  7334. module.verbose('Finding field with identifier', identifier);
  7335. identifier = module.escape.string(identifier);
  7336. var t;
  7337. if((t=$field.filter('#' + identifier)).length > 0 ) {
  7338. return t;
  7339. }
  7340. if((t=$field.filter('[name="' + identifier +'"]')).length > 0 ) {
  7341. return t;
  7342. }
  7343. if((t=$field.filter('[name="' + identifier +'[]"]')).length > 0 ) {
  7344. return t;
  7345. }
  7346. if((t=$field.filter('[data-' + metadata.validate + '="'+ identifier +'"]')).length > 0 ) {
  7347. return t;
  7348. }
  7349. return $('<input/>');
  7350. },
  7351. fields: function(fields) {
  7352. var
  7353. $fields = $()
  7354. ;
  7355. $.each(fields, function(index, name) {
  7356. $fields = $fields.add( module.get.field(name) );
  7357. });
  7358. return $fields;
  7359. },
  7360. validation: function($field) {
  7361. var
  7362. fieldValidation,
  7363. identifier
  7364. ;
  7365. if(!validation) {
  7366. return false;
  7367. }
  7368. $.each(validation, function(fieldName, field) {
  7369. identifier = field.identifier || fieldName;
  7370. $.each(module.get.field(identifier), function(index, groupField) {
  7371. if(groupField == $field[0]) {
  7372. field.identifier = identifier;
  7373. fieldValidation = field;
  7374. return false;
  7375. }
  7376. });
  7377. });
  7378. return fieldValidation || false;
  7379. },
  7380. value: function (field) {
  7381. var
  7382. fields = [],
  7383. results
  7384. ;
  7385. fields.push(field);
  7386. results = module.get.values.call(element, fields);
  7387. return results[field];
  7388. },
  7389. values: function (fields) {
  7390. var
  7391. $fields = Array.isArray(fields)
  7392. ? module.get.fields(fields)
  7393. : $field,
  7394. values = {}
  7395. ;
  7396. $fields.each(function(index, field) {
  7397. var
  7398. $field = $(field),
  7399. $calendar = $field.closest(selector.uiCalendar),
  7400. name = $field.prop('name'),
  7401. value = $field.val(),
  7402. isCheckbox = $field.is(selector.checkbox),
  7403. isRadio = $field.is(selector.radio),
  7404. isMultiple = (name.indexOf('[]') !== -1),
  7405. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  7406. isChecked = (isCheckbox)
  7407. ? $field.is(':checked')
  7408. : false
  7409. ;
  7410. if(name) {
  7411. if(isMultiple) {
  7412. name = name.replace('[]', '');
  7413. if(!values[name]) {
  7414. values[name] = [];
  7415. }
  7416. if(isCheckbox) {
  7417. if(isChecked) {
  7418. values[name].push(value || true);
  7419. }
  7420. else {
  7421. values[name].push(false);
  7422. }
  7423. }
  7424. else {
  7425. values[name].push(value);
  7426. }
  7427. }
  7428. else {
  7429. if(isRadio) {
  7430. if(values[name] === undefined || values[name] === false) {
  7431. values[name] = (isChecked)
  7432. ? value || true
  7433. : false
  7434. ;
  7435. }
  7436. }
  7437. else if(isCheckbox) {
  7438. if(isChecked) {
  7439. values[name] = value || true;
  7440. }
  7441. else {
  7442. values[name] = false;
  7443. }
  7444. }
  7445. else if(isCalendar) {
  7446. var date = $calendar.calendar('get date');
  7447. if (date !== null) {
  7448. if (settings.dateHandling == 'date') {
  7449. values[name] = date;
  7450. } else if(settings.dateHandling == 'input') {
  7451. values[name] = $calendar.calendar('get input date')
  7452. } else if (settings.dateHandling == 'formatter') {
  7453. var type = $calendar.calendar('setting', 'type');
  7454. switch(type) {
  7455. case 'date':
  7456. values[name] = settings.formatter.date(date);
  7457. break;
  7458. case 'datetime':
  7459. values[name] = settings.formatter.datetime(date);
  7460. break;
  7461. case 'time':
  7462. values[name] = settings.formatter.time(date);
  7463. break;
  7464. case 'month':
  7465. values[name] = settings.formatter.month(date);
  7466. break;
  7467. case 'year':
  7468. values[name] = settings.formatter.year(date);
  7469. break;
  7470. default:
  7471. module.debug('Wrong calendar mode', $calendar, type);
  7472. values[name] = '';
  7473. }
  7474. }
  7475. } else {
  7476. values[name] = '';
  7477. }
  7478. } else {
  7479. values[name] = value;
  7480. }
  7481. }
  7482. }
  7483. });
  7484. return values;
  7485. },
  7486. dirtyFields: function() {
  7487. return $field.filter(function(index, e) {
  7488. return $(e).data(metadata.isDirty);
  7489. });
  7490. }
  7491. },
  7492. has: {
  7493. field: function(identifier) {
  7494. module.verbose('Checking for existence of a field with identifier', identifier);
  7495. identifier = module.escape.string(identifier);
  7496. if(typeof identifier !== 'string') {
  7497. module.error(error.identifier, identifier);
  7498. }
  7499. if($field.filter('#' + identifier).length > 0 ) {
  7500. return true;
  7501. }
  7502. else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
  7503. return true;
  7504. }
  7505. else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
  7506. return true;
  7507. }
  7508. return false;
  7509. }
  7510. },
  7511. can: {
  7512. useElement: function(element){
  7513. if ($.fn[element] !== undefined) {
  7514. return true;
  7515. }
  7516. module.error(error.noElement.replace('{element}',element));
  7517. return false;
  7518. }
  7519. },
  7520. escape: {
  7521. string: function(text) {
  7522. text = String(text);
  7523. return text.replace(regExp.escape, '\\$&');
  7524. }
  7525. },
  7526. add: {
  7527. // alias
  7528. rule: function(name, rules) {
  7529. module.add.field(name, rules);
  7530. },
  7531. field: function(name, rules) {
  7532. // Validation should have at least a standard format
  7533. if(validation[name] === undefined || validation[name].rules === undefined) {
  7534. validation[name] = {
  7535. rules: []
  7536. };
  7537. }
  7538. var
  7539. newValidation = {
  7540. rules: []
  7541. }
  7542. ;
  7543. if(module.is.shorthandRules(rules)) {
  7544. rules = Array.isArray(rules)
  7545. ? rules
  7546. : [rules]
  7547. ;
  7548. $.each(rules, function(_index, rule) {
  7549. newValidation.rules.push({ type: rule });
  7550. });
  7551. }
  7552. else {
  7553. newValidation.rules = rules.rules;
  7554. }
  7555. // For each new rule, check if there's not already one with the same type
  7556. $.each(newValidation.rules, function (_index, rule) {
  7557. if ($.grep(validation[name].rules, function(item){ return item.type == rule.type; }).length == 0) {
  7558. validation[name].rules.push(rule);
  7559. }
  7560. });
  7561. module.debug('Adding rules', newValidation.rules, validation);
  7562. },
  7563. fields: function(fields) {
  7564. var
  7565. newValidation
  7566. ;
  7567. if(fields && module.is.shorthandFields(fields)) {
  7568. newValidation = module.get.fieldsFromShorthand(fields);
  7569. }
  7570. else {
  7571. newValidation = fields;
  7572. }
  7573. validation = $.extend({}, validation, newValidation);
  7574. },
  7575. prompt: function(identifier, errors, internal) {
  7576. var
  7577. $field = module.get.field(identifier),
  7578. $fieldGroup = $field.closest($group),
  7579. $prompt = $fieldGroup.children(selector.prompt),
  7580. promptExists = ($prompt.length !== 0)
  7581. ;
  7582. errors = (typeof errors == 'string')
  7583. ? [errors]
  7584. : errors
  7585. ;
  7586. module.verbose('Adding field error state', identifier);
  7587. if(!internal) {
  7588. $fieldGroup
  7589. .addClass(className.error)
  7590. ;
  7591. }
  7592. if(settings.inline) {
  7593. if(!promptExists) {
  7594. $prompt = settings.templates.prompt(errors, className.label);
  7595. $prompt
  7596. .appendTo($fieldGroup)
  7597. ;
  7598. }
  7599. $prompt
  7600. .html(errors[0])
  7601. ;
  7602. if(!promptExists) {
  7603. if(settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
  7604. module.verbose('Displaying error with css transition', settings.transition);
  7605. $prompt.transition(settings.transition + ' in', settings.duration);
  7606. }
  7607. else {
  7608. module.verbose('Displaying error with fallback javascript animation');
  7609. $prompt
  7610. .fadeIn(settings.duration)
  7611. ;
  7612. }
  7613. }
  7614. else {
  7615. module.verbose('Inline errors are disabled, no inline error added', identifier);
  7616. }
  7617. }
  7618. },
  7619. errors: function(errors) {
  7620. module.debug('Adding form error messages', errors);
  7621. module.set.error();
  7622. $message
  7623. .html( settings.templates.error(errors) )
  7624. ;
  7625. }
  7626. },
  7627. remove: {
  7628. errors: function() {
  7629. module.debug('Removing form error messages');
  7630. $message.empty();
  7631. },
  7632. states: function() {
  7633. $module.removeClass(className.error).removeClass(className.success);
  7634. if(!settings.inline) {
  7635. module.remove.errors();
  7636. }
  7637. module.determine.isDirty();
  7638. },
  7639. rule: function(field, rule) {
  7640. var
  7641. rules = Array.isArray(rule)
  7642. ? rule
  7643. : [rule]
  7644. ;
  7645. if(validation[field] === undefined || !Array.isArray(validation[field].rules)) {
  7646. return;
  7647. }
  7648. if(rule === undefined) {
  7649. module.debug('Removed all rules');
  7650. validation[field].rules = [];
  7651. return;
  7652. }
  7653. $.each(validation[field].rules, function(index, rule) {
  7654. if(rule && rules.indexOf(rule.type) !== -1) {
  7655. module.debug('Removed rule', rule.type);
  7656. validation[field].rules.splice(index, 1);
  7657. }
  7658. });
  7659. },
  7660. field: function(field) {
  7661. var
  7662. fields = Array.isArray(field)
  7663. ? field
  7664. : [field]
  7665. ;
  7666. $.each(fields, function(index, field) {
  7667. module.remove.rule(field);
  7668. });
  7669. },
  7670. // alias
  7671. rules: function(field, rules) {
  7672. if(Array.isArray(field)) {
  7673. $.each(field, function(index, field) {
  7674. module.remove.rule(field, rules);
  7675. });
  7676. }
  7677. else {
  7678. module.remove.rule(field, rules);
  7679. }
  7680. },
  7681. fields: function(fields) {
  7682. module.remove.field(fields);
  7683. },
  7684. prompt: function(identifier) {
  7685. var
  7686. $field = module.get.field(identifier),
  7687. $fieldGroup = $field.closest($group),
  7688. $prompt = $fieldGroup.children(selector.prompt)
  7689. ;
  7690. $fieldGroup
  7691. .removeClass(className.error)
  7692. ;
  7693. if(settings.inline && $prompt.is(':visible')) {
  7694. module.verbose('Removing prompt for field', identifier);
  7695. if(settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
  7696. $prompt.transition(settings.transition + ' out', settings.duration, function() {
  7697. $prompt.remove();
  7698. });
  7699. }
  7700. else {
  7701. $prompt
  7702. .fadeOut(settings.duration, function(){
  7703. $prompt.remove();
  7704. })
  7705. ;
  7706. }
  7707. }
  7708. }
  7709. },
  7710. set: {
  7711. success: function() {
  7712. $module
  7713. .removeClass(className.error)
  7714. .addClass(className.success)
  7715. ;
  7716. },
  7717. defaults: function () {
  7718. $field.each(function (index, el) {
  7719. var
  7720. $el = $(el),
  7721. $parent = $el.parent(),
  7722. isCheckbox = ($el.filter(selector.checkbox).length > 0),
  7723. isDropdown = $parent.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  7724. $calendar = $el.closest(selector.uiCalendar),
  7725. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  7726. value = (isCheckbox)
  7727. ? $el.is(':checked')
  7728. : $el.val()
  7729. ;
  7730. if (isDropdown) {
  7731. $parent.dropdown('save defaults');
  7732. }
  7733. else if (isCalendar) {
  7734. $calendar.calendar('refresh');
  7735. }
  7736. $el.data(metadata.defaultValue, value);
  7737. $el.data(metadata.isDirty, false);
  7738. });
  7739. },
  7740. error: function() {
  7741. $module
  7742. .removeClass(className.success)
  7743. .addClass(className.error)
  7744. ;
  7745. },
  7746. value: function (field, value) {
  7747. var
  7748. fields = {}
  7749. ;
  7750. fields[field] = value;
  7751. return module.set.values.call(element, fields);
  7752. },
  7753. values: function (fields) {
  7754. if($.isEmptyObject(fields)) {
  7755. return;
  7756. }
  7757. $.each(fields, function(key, value) {
  7758. var
  7759. $field = module.get.field(key),
  7760. $element = $field.parent(),
  7761. $calendar = $field.closest(selector.uiCalendar),
  7762. isMultiple = Array.isArray(value),
  7763. isCheckbox = $element.is(selector.uiCheckbox) && module.can.useElement('checkbox'),
  7764. isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
  7765. isRadio = ($field.is(selector.radio) && isCheckbox),
  7766. isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
  7767. fieldExists = ($field.length > 0),
  7768. $multipleField
  7769. ;
  7770. if(fieldExists) {
  7771. if(isMultiple && isCheckbox) {
  7772. module.verbose('Selecting multiple', value, $field);
  7773. $element.checkbox('uncheck');
  7774. $.each(value, function(index, value) {
  7775. $multipleField = $field.filter('[value="' + value + '"]');
  7776. $element = $multipleField.parent();
  7777. if($multipleField.length > 0) {
  7778. $element.checkbox('check');
  7779. }
  7780. });
  7781. }
  7782. else if(isRadio) {
  7783. module.verbose('Selecting radio value', value, $field);
  7784. $field.filter('[value="' + value + '"]')
  7785. .parent(selector.uiCheckbox)
  7786. .checkbox('check')
  7787. ;
  7788. }
  7789. else if(isCheckbox) {
  7790. module.verbose('Setting checkbox value', value, $element);
  7791. if(value === true || value === 1) {
  7792. $element.checkbox('check');
  7793. }
  7794. else {
  7795. $element.checkbox('uncheck');
  7796. }
  7797. }
  7798. else if(isDropdown) {
  7799. module.verbose('Setting dropdown value', value, $element);
  7800. $element.dropdown('set selected', value);
  7801. }
  7802. else if (isCalendar) {
  7803. $calendar.calendar('set date',value);
  7804. }
  7805. else {
  7806. module.verbose('Setting field value', value, $field);
  7807. $field.val(value);
  7808. }
  7809. }
  7810. });
  7811. },
  7812. dirty: function() {
  7813. module.verbose('Setting state dirty');
  7814. dirty = true;
  7815. history[0] = history[1];
  7816. history[1] = 'dirty';
  7817. if (module.is.justClean()) {
  7818. $module.trigger('dirty');
  7819. }
  7820. },
  7821. clean: function() {
  7822. module.verbose('Setting state clean');
  7823. dirty = false;
  7824. history[0] = history[1];
  7825. history[1] = 'clean';
  7826. if (module.is.justDirty()) {
  7827. $module.trigger('clean');
  7828. }
  7829. },
  7830. asClean: function() {
  7831. module.set.defaults();
  7832. module.set.clean();
  7833. },
  7834. asDirty: function() {
  7835. module.set.defaults();
  7836. module.set.dirty();
  7837. },
  7838. autoCheck: function() {
  7839. module.debug('Enabling auto check on required fields');
  7840. $field.each(function (_index, el) {
  7841. var
  7842. $el = $(el),
  7843. $elGroup = $(el).closest($group),
  7844. isCheckbox = ($el.filter(selector.checkbox).length > 0),
  7845. isRequired = $el.prop('required') || $elGroup.hasClass(className.required) || $elGroup.parent().hasClass(className.required),
  7846. isDisabled = $el.is(':disabled') || $elGroup.hasClass(className.disabled) || $elGroup.parent().hasClass(className.disabled),
  7847. validation = module.get.validation($el),
  7848. hasEmptyRule = validation
  7849. ? $.grep(validation.rules, function(rule) { return rule.type == "empty" }) !== 0
  7850. : false,
  7851. identifier = validation.identifier || $el.attr('id') || $el.attr('name') || $el.data(metadata.validate)
  7852. ;
  7853. if (isRequired && !isDisabled && !hasEmptyRule && identifier !== undefined) {
  7854. if (isCheckbox) {
  7855. module.verbose("Adding 'checked' rule on field", identifier);
  7856. module.add.rule(identifier, "checked");
  7857. } else {
  7858. module.verbose("Adding 'empty' rule on field", identifier);
  7859. module.add.rule(identifier, "empty");
  7860. }
  7861. }
  7862. });
  7863. }
  7864. },
  7865. validate: {
  7866. form: function(event, ignoreCallbacks) {
  7867. var values = module.get.values();
  7868. // input keydown event will fire submit repeatedly by browser default
  7869. if(keyHeldDown) {
  7870. return false;
  7871. }
  7872. // reset errors
  7873. formErrors = [];
  7874. if( module.determine.isValid() ) {
  7875. module.debug('Form has no validation errors, submitting');
  7876. module.set.success();
  7877. if(!settings.inline) {
  7878. module.remove.errors();
  7879. }
  7880. if(ignoreCallbacks !== true) {
  7881. return settings.onSuccess.call(element, event, values);
  7882. }
  7883. }
  7884. else {
  7885. module.debug('Form has errors');
  7886. submitting = false;
  7887. module.set.error();
  7888. if(!settings.inline) {
  7889. module.add.errors(formErrors);
  7890. }
  7891. // prevent ajax submit
  7892. if(event && $module.data('moduleApi') !== undefined) {
  7893. event.stopImmediatePropagation();
  7894. }
  7895. if(ignoreCallbacks !== true) {
  7896. return settings.onFailure.call(element, formErrors, values);
  7897. }
  7898. }
  7899. },
  7900. // takes a validation object and returns whether field passes validation
  7901. field: function(field, fieldName, showErrors) {
  7902. showErrors = (showErrors !== undefined)
  7903. ? showErrors
  7904. : true
  7905. ;
  7906. if(typeof field == 'string') {
  7907. module.verbose('Validating field', field);
  7908. fieldName = field;
  7909. field = validation[field];
  7910. }
  7911. var
  7912. identifier = field.identifier || fieldName,
  7913. $field = module.get.field(identifier),
  7914. $dependsField = (field.depends)
  7915. ? module.get.field(field.depends)
  7916. : false,
  7917. fieldValid = true,
  7918. fieldErrors = []
  7919. ;
  7920. if(!field.identifier) {
  7921. module.debug('Using field name as identifier', identifier);
  7922. field.identifier = identifier;
  7923. }
  7924. var isDisabled = !$field.filter(':not(:disabled)').length;
  7925. if(isDisabled) {
  7926. module.debug('Field is disabled. Skipping', identifier);
  7927. }
  7928. else if(field.optional && module.is.blank($field)){
  7929. module.debug('Field is optional and blank. Skipping', identifier);
  7930. }
  7931. else if(field.depends && module.is.empty($dependsField)) {
  7932. module.debug('Field depends on another value that is not present or empty. Skipping', $dependsField);
  7933. }
  7934. else if(field.rules !== undefined) {
  7935. if(showErrors) {
  7936. $field.closest($group).removeClass(className.error);
  7937. }
  7938. $.each(field.rules, function(index, rule) {
  7939. if( module.has.field(identifier)) {
  7940. var invalidFields = module.validate.rule(field, rule,true) || [];
  7941. if (invalidFields.length>0){
  7942. module.debug('Field is invalid', identifier, rule.type);
  7943. fieldErrors.push(module.get.prompt(rule, field));
  7944. fieldValid = false;
  7945. if(showErrors){
  7946. $(invalidFields).closest($group).addClass(className.error);
  7947. }
  7948. }
  7949. }
  7950. });
  7951. }
  7952. if(fieldValid) {
  7953. if(showErrors) {
  7954. module.remove.prompt(identifier, fieldErrors);
  7955. settings.onValid.call($field);
  7956. }
  7957. }
  7958. else {
  7959. if(showErrors) {
  7960. formErrors = formErrors.concat(fieldErrors);
  7961. module.add.prompt(identifier, fieldErrors, true);
  7962. settings.onInvalid.call($field, fieldErrors);
  7963. }
  7964. return false;
  7965. }
  7966. return true;
  7967. },
  7968. // takes validation rule and returns whether field passes rule
  7969. rule: function(field, rule, internal) {
  7970. var
  7971. $field = module.get.field(field.identifier),
  7972. ancillary = module.get.ancillaryValue(rule),
  7973. ruleName = module.get.ruleName(rule),
  7974. ruleFunction = settings.rules[ruleName],
  7975. invalidFields = [],
  7976. isCheckbox = $field.is(selector.checkbox),
  7977. isValid = function(field){
  7978. var value = (isCheckbox ? $(field).filter(':checked').val() : $(field).val());
  7979. // cast to string avoiding encoding special values
  7980. value = (value === undefined || value === '' || value === null)
  7981. ? ''
  7982. : (settings.shouldTrim) ? String(value + '').trim() : String(value + '')
  7983. ;
  7984. return ruleFunction.call(field, value, ancillary, $module);
  7985. }
  7986. ;
  7987. if( !$.isFunction(ruleFunction) ) {
  7988. module.error(error.noRule, ruleName);
  7989. return;
  7990. }
  7991. if(isCheckbox) {
  7992. if (!isValid($field)) {
  7993. invalidFields = $field;
  7994. }
  7995. } else {
  7996. $.each($field, function (index, field) {
  7997. if (!isValid(field)) {
  7998. invalidFields.push(field);
  7999. }
  8000. });
  8001. }
  8002. return internal ? invalidFields : !(invalidFields.length>0);
  8003. }
  8004. },
  8005. setting: function(name, value) {
  8006. if( $.isPlainObject(name) ) {
  8007. $.extend(true, settings, name);
  8008. }
  8009. else if(value !== undefined) {
  8010. settings[name] = value;
  8011. }
  8012. else {
  8013. return settings[name];
  8014. }
  8015. },
  8016. internal: function(name, value) {
  8017. if( $.isPlainObject(name) ) {
  8018. $.extend(true, module, name);
  8019. }
  8020. else if(value !== undefined) {
  8021. module[name] = value;
  8022. }
  8023. else {
  8024. return module[name];
  8025. }
  8026. },
  8027. debug: function() {
  8028. if(!settings.silent && settings.debug) {
  8029. if(settings.performance) {
  8030. module.performance.log(arguments);
  8031. }
  8032. else {
  8033. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  8034. module.debug.apply(console, arguments);
  8035. }
  8036. }
  8037. },
  8038. verbose: function() {
  8039. if(!settings.silent && settings.verbose && settings.debug) {
  8040. if(settings.performance) {
  8041. module.performance.log(arguments);
  8042. }
  8043. else {
  8044. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  8045. module.verbose.apply(console, arguments);
  8046. }
  8047. }
  8048. },
  8049. error: function() {
  8050. if(!settings.silent) {
  8051. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  8052. module.error.apply(console, arguments);
  8053. }
  8054. },
  8055. performance: {
  8056. log: function(message) {
  8057. var
  8058. currentTime,
  8059. executionTime,
  8060. previousTime
  8061. ;
  8062. if(settings.performance) {
  8063. currentTime = new Date().getTime();
  8064. previousTime = time || currentTime;
  8065. executionTime = currentTime - previousTime;
  8066. time = currentTime;
  8067. performance.push({
  8068. 'Name' : message[0],
  8069. 'Arguments' : [].slice.call(message, 1) || '',
  8070. 'Element' : element,
  8071. 'Execution Time' : executionTime
  8072. });
  8073. }
  8074. clearTimeout(module.performance.timer);
  8075. module.performance.timer = setTimeout(module.performance.display, 500);
  8076. },
  8077. display: function() {
  8078. var
  8079. title = settings.name + ':',
  8080. totalTime = 0
  8081. ;
  8082. time = false;
  8083. clearTimeout(module.performance.timer);
  8084. $.each(performance, function(index, data) {
  8085. totalTime += data['Execution Time'];
  8086. });
  8087. title += ' ' + totalTime + 'ms';
  8088. if(moduleSelector) {
  8089. title += ' \'' + moduleSelector + '\'';
  8090. }
  8091. if($allModules.length > 1) {
  8092. title += ' ' + '(' + $allModules.length + ')';
  8093. }
  8094. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  8095. console.groupCollapsed(title);
  8096. if(console.table) {
  8097. console.table(performance);
  8098. }
  8099. else {
  8100. $.each(performance, function(index, data) {
  8101. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  8102. });
  8103. }
  8104. console.groupEnd();
  8105. }
  8106. performance = [];
  8107. }
  8108. },
  8109. invoke: function(query, passedArguments, context) {
  8110. var
  8111. object = instance,
  8112. maxDepth,
  8113. found,
  8114. response
  8115. ;
  8116. passedArguments = passedArguments || queryArguments;
  8117. context = element || context;
  8118. if(typeof query == 'string' && object !== undefined) {
  8119. query = query.split(/[\. ]/);
  8120. maxDepth = query.length - 1;
  8121. $.each(query, function(depth, value) {
  8122. var camelCaseValue = (depth != maxDepth)
  8123. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  8124. : query
  8125. ;
  8126. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  8127. object = object[camelCaseValue];
  8128. }
  8129. else if( object[camelCaseValue] !== undefined ) {
  8130. found = object[camelCaseValue];
  8131. return false;
  8132. }
  8133. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  8134. object = object[value];
  8135. }
  8136. else if( object[value] !== undefined ) {
  8137. found = object[value];
  8138. return false;
  8139. }
  8140. else {
  8141. return false;
  8142. }
  8143. });
  8144. }
  8145. if( $.isFunction( found ) ) {
  8146. response = found.apply(context, passedArguments);
  8147. }
  8148. else if(found !== undefined) {
  8149. response = found;
  8150. }
  8151. if(Array.isArray(returnedValue)) {
  8152. returnedValue.push(response);
  8153. }
  8154. else if(returnedValue !== undefined) {
  8155. returnedValue = [returnedValue, response];
  8156. }
  8157. else if(response !== undefined) {
  8158. returnedValue = response;
  8159. }
  8160. return found;
  8161. }
  8162. };
  8163. module.initialize();
  8164. })
  8165. ;
  8166. return (returnedValue !== undefined)
  8167. ? returnedValue
  8168. : this
  8169. ;
  8170. };
  8171. $.fn.form.settings = {
  8172. name : 'Form',
  8173. namespace : 'form',
  8174. debug : false,
  8175. verbose : false,
  8176. performance : true,
  8177. fields : false,
  8178. keyboardShortcuts : true,
  8179. on : 'submit',
  8180. inline : false,
  8181. delay : 200,
  8182. revalidate : true,
  8183. shouldTrim : true,
  8184. transition : 'scale',
  8185. duration : 200,
  8186. autoCheckRequired : false,
  8187. preventLeaving : false,
  8188. dateHandling : 'date', // 'date', 'input', 'formatter'
  8189. onValid : function() {},
  8190. onInvalid : function() {},
  8191. onSuccess : function() { return true; },
  8192. onFailure : function() { return false; },
  8193. onDirty : function() {},
  8194. onClean : function() {},
  8195. metadata : {
  8196. defaultValue : 'default',
  8197. validate : 'validate',
  8198. isDirty : 'isDirty'
  8199. },
  8200. regExp: {
  8201. htmlID : /^[a-zA-Z][\w:.-]*$/g,
  8202. bracket : /\[(.*)\]/i,
  8203. decimal : /^\d+\.?\d*$/,
  8204. email : /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,
  8205. escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|:,=@]/g,
  8206. flags : /^\/(.*)\/(.*)?/,
  8207. integer : /^\-?\d+$/,
  8208. number : /^\-?\d*(\.\d+)?$/,
  8209. url : /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/i
  8210. },
  8211. text: {
  8212. unspecifiedRule : 'Please enter a valid value',
  8213. unspecifiedField : 'This field',
  8214. leavingMessage : 'There are unsaved changes on this page which will be discarded if you continue.'
  8215. },
  8216. prompt: {
  8217. empty : '{name} must have a value',
  8218. checked : '{name} must be checked',
  8219. email : '{name} must be a valid e-mail',
  8220. url : '{name} must be a valid url',
  8221. regExp : '{name} is not formatted correctly',
  8222. integer : '{name} must be an integer',
  8223. decimal : '{name} must be a decimal number',
  8224. number : '{name} must be set to a number',
  8225. is : '{name} must be "{ruleValue}"',
  8226. isExactly : '{name} must be exactly "{ruleValue}"',
  8227. not : '{name} cannot be set to "{ruleValue}"',
  8228. notExactly : '{name} cannot be set to exactly "{ruleValue}"',
  8229. contain : '{name} must contain "{ruleValue}"',
  8230. containExactly : '{name} must contain exactly "{ruleValue}"',
  8231. doesntContain : '{name} cannot contain "{ruleValue}"',
  8232. doesntContainExactly : '{name} cannot contain exactly "{ruleValue}"',
  8233. minLength : '{name} must be at least {ruleValue} characters',
  8234. length : '{name} must be at least {ruleValue} characters',
  8235. exactLength : '{name} must be exactly {ruleValue} characters',
  8236. maxLength : '{name} cannot be longer than {ruleValue} characters',
  8237. match : '{name} must match {ruleValue} field',
  8238. different : '{name} must have a different value than {ruleValue} field',
  8239. creditCard : '{name} must be a valid credit card number',
  8240. minCount : '{name} must have at least {ruleValue} choices',
  8241. exactCount : '{name} must have exactly {ruleValue} choices',
  8242. maxCount : '{name} must have {ruleValue} or less choices'
  8243. },
  8244. selector : {
  8245. checkbox : 'input[type="checkbox"], input[type="radio"]',
  8246. clear : '.clear',
  8247. field : 'input:not(.search), textarea, select',
  8248. group : '.field',
  8249. input : 'input',
  8250. message : '.error.message',
  8251. prompt : '.prompt.label',
  8252. radio : 'input[type="radio"]',
  8253. reset : '.reset:not([type="reset"])',
  8254. submit : '.submit:not([type="submit"])',
  8255. uiCheckbox : '.ui.checkbox',
  8256. uiDropdown : '.ui.dropdown',
  8257. uiCalendar : '.ui.calendar'
  8258. },
  8259. className : {
  8260. error : 'error',
  8261. label : 'ui basic red pointing prompt label',
  8262. pressed : 'down',
  8263. success : 'success',
  8264. required : 'required',
  8265. disabled : 'disabled'
  8266. },
  8267. error: {
  8268. identifier : 'You must specify a string identifier for each field',
  8269. method : 'The method you called is not defined.',
  8270. noRule : 'There is no rule matching the one you specified',
  8271. oldSyntax : 'Starting in 2.0 forms now only take a single settings object. Validation settings converted to new syntax automatically.',
  8272. noElement : 'This module requires ui {element}'
  8273. },
  8274. templates: {
  8275. // template that produces error message
  8276. error: function(errors) {
  8277. var
  8278. html = '<ul class="list">'
  8279. ;
  8280. $.each(errors, function(index, value) {
  8281. html += '<li>' + value + '</li>';
  8282. });
  8283. html += '</ul>';
  8284. return $(html);
  8285. },
  8286. // template that produces label
  8287. prompt: function(errors, labelClasses) {
  8288. return $('<div/>')
  8289. .addClass(labelClasses)
  8290. .html(errors[0])
  8291. ;
  8292. }
  8293. },
  8294. formatter: {
  8295. date: function(date) {
  8296. return Intl.DateTimeFormat('en-GB').format(date);
  8297. },
  8298. datetime: function(date) {
  8299. return Intl.DateTimeFormat('en-GB', {
  8300. year: "numeric",
  8301. month: "2-digit",
  8302. day: "2-digit",
  8303. hour: '2-digit',
  8304. minute: '2-digit',
  8305. second: '2-digit'
  8306. }).format(date);
  8307. },
  8308. time: function(date) {
  8309. return Intl.DateTimeFormat('en-GB', {
  8310. hour: '2-digit',
  8311. minute: '2-digit',
  8312. second: '2-digit'
  8313. }).format(date);
  8314. },
  8315. month: function(date) {
  8316. return Intl.DateTimeFormat('en-GB', {
  8317. month: '2-digit',
  8318. year: 'numeric'
  8319. }).format(date);
  8320. },
  8321. year: function(date) {
  8322. return Intl.DateTimeFormat('en-GB', {
  8323. year: 'numeric'
  8324. }).format(date);
  8325. }
  8326. },
  8327. rules: {
  8328. // is not empty or blank string
  8329. empty: function(value) {
  8330. return !(value === undefined || '' === value || Array.isArray(value) && value.length === 0);
  8331. },
  8332. // checkbox checked
  8333. checked: function() {
  8334. return ($(this).filter(':checked').length > 0);
  8335. },
  8336. // is most likely an email
  8337. email: function(value){
  8338. return $.fn.form.settings.regExp.email.test(value);
  8339. },
  8340. // value is most likely url
  8341. url: function(value) {
  8342. return $.fn.form.settings.regExp.url.test(value);
  8343. },
  8344. // matches specified regExp
  8345. regExp: function(value, regExp) {
  8346. if(regExp instanceof RegExp) {
  8347. return value.match(regExp);
  8348. }
  8349. var
  8350. regExpParts = regExp.match($.fn.form.settings.regExp.flags),
  8351. flags
  8352. ;
  8353. // regular expression specified as /baz/gi (flags)
  8354. if(regExpParts) {
  8355. regExp = (regExpParts.length >= 2)
  8356. ? regExpParts[1]
  8357. : regExp
  8358. ;
  8359. flags = (regExpParts.length >= 3)
  8360. ? regExpParts[2]
  8361. : ''
  8362. ;
  8363. }
  8364. return value.match( new RegExp(regExp, flags) );
  8365. },
  8366. // is valid integer or matches range
  8367. integer: function(value, range) {
  8368. var
  8369. intRegExp = $.fn.form.settings.regExp.integer,
  8370. min,
  8371. max,
  8372. parts
  8373. ;
  8374. if( !range || ['', '..'].indexOf(range) !== -1) {
  8375. // do nothing
  8376. }
  8377. else if(range.indexOf('..') == -1) {
  8378. if(intRegExp.test(range)) {
  8379. min = max = range - 0;
  8380. }
  8381. }
  8382. else {
  8383. parts = range.split('..', 2);
  8384. if(intRegExp.test(parts[0])) {
  8385. min = parts[0] - 0;
  8386. }
  8387. if(intRegExp.test(parts[1])) {
  8388. max = parts[1] - 0;
  8389. }
  8390. }
  8391. return (
  8392. intRegExp.test(value) &&
  8393. (min === undefined || value >= min) &&
  8394. (max === undefined || value <= max)
  8395. );
  8396. },
  8397. // is valid number (with decimal)
  8398. decimal: function(value) {
  8399. return $.fn.form.settings.regExp.decimal.test(value);
  8400. },
  8401. // is valid number
  8402. number: function(value) {
  8403. return $.fn.form.settings.regExp.number.test(value);
  8404. },
  8405. // is value (case insensitive)
  8406. is: function(value, text) {
  8407. text = (typeof text == 'string')
  8408. ? text.toLowerCase()
  8409. : text
  8410. ;
  8411. value = (typeof value == 'string')
  8412. ? value.toLowerCase()
  8413. : value
  8414. ;
  8415. return (value == text);
  8416. },
  8417. // is value
  8418. isExactly: function(value, text) {
  8419. return (value == text);
  8420. },
  8421. // value is not another value (case insensitive)
  8422. not: function(value, notValue) {
  8423. value = (typeof value == 'string')
  8424. ? value.toLowerCase()
  8425. : value
  8426. ;
  8427. notValue = (typeof notValue == 'string')
  8428. ? notValue.toLowerCase()
  8429. : notValue
  8430. ;
  8431. return (value != notValue);
  8432. },
  8433. // value is not another value (case sensitive)
  8434. notExactly: function(value, notValue) {
  8435. return (value != notValue);
  8436. },
  8437. // value contains text (insensitive)
  8438. contains: function(value, text) {
  8439. // escape regex characters
  8440. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  8441. return (value.search( new RegExp(text, 'i') ) !== -1);
  8442. },
  8443. // value contains text (case sensitive)
  8444. containsExactly: function(value, text) {
  8445. // escape regex characters
  8446. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  8447. return (value.search( new RegExp(text) ) !== -1);
  8448. },
  8449. // value contains text (insensitive)
  8450. doesntContain: function(value, text) {
  8451. // escape regex characters
  8452. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  8453. return (value.search( new RegExp(text, 'i') ) === -1);
  8454. },
  8455. // value contains text (case sensitive)
  8456. doesntContainExactly: function(value, text) {
  8457. // escape regex characters
  8458. text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
  8459. return (value.search( new RegExp(text) ) === -1);
  8460. },
  8461. // is at least string length
  8462. minLength: function(value, requiredLength) {
  8463. return (value !== undefined)
  8464. ? (value.length >= requiredLength)
  8465. : false
  8466. ;
  8467. },
  8468. // see rls notes for 2.0.6 (this is a duplicate of minLength)
  8469. length: function(value, requiredLength) {
  8470. return (value !== undefined)
  8471. ? (value.length >= requiredLength)
  8472. : false
  8473. ;
  8474. },
  8475. // is exactly length
  8476. exactLength: function(value, requiredLength) {
  8477. return (value !== undefined)
  8478. ? (value.length == requiredLength)
  8479. : false
  8480. ;
  8481. },
  8482. // is less than length
  8483. maxLength: function(value, maxLength) {
  8484. return (value !== undefined)
  8485. ? (value.length <= maxLength)
  8486. : false
  8487. ;
  8488. },
  8489. // matches another field
  8490. match: function(value, identifier, $module) {
  8491. var
  8492. matchingValue,
  8493. matchingElement
  8494. ;
  8495. if((matchingElement = $module.find('[data-validate="'+ identifier +'"]')).length > 0 ) {
  8496. matchingValue = matchingElement.val();
  8497. }
  8498. else if((matchingElement = $module.find('#' + identifier)).length > 0) {
  8499. matchingValue = matchingElement.val();
  8500. }
  8501. else if((matchingElement = $module.find('[name="' + identifier +'"]')).length > 0) {
  8502. matchingValue = matchingElement.val();
  8503. }
  8504. else if((matchingElement = $module.find('[name="' + identifier +'[]"]')).length > 0 ) {
  8505. matchingValue = matchingElement;
  8506. }
  8507. return (matchingValue !== undefined)
  8508. ? ( value.toString() == matchingValue.toString() )
  8509. : false
  8510. ;
  8511. },
  8512. // different than another field
  8513. different: function(value, identifier, $module) {
  8514. // use either id or name of field
  8515. var
  8516. matchingValue,
  8517. matchingElement
  8518. ;
  8519. if((matchingElement = $module.find('[data-validate="'+ identifier +'"]')).length > 0 ) {
  8520. matchingValue = matchingElement.val();
  8521. }
  8522. else if((matchingElement = $module.find('#' + identifier)).length > 0) {
  8523. matchingValue = matchingElement.val();
  8524. }
  8525. else if((matchingElement = $module.find('[name="' + identifier +'"]')).length > 0) {
  8526. matchingValue = matchingElement.val();
  8527. }
  8528. else if((matchingElement = $module.find('[name="' + identifier +'[]"]')).length > 0 ) {
  8529. matchingValue = matchingElement;
  8530. }
  8531. return (matchingValue !== undefined)
  8532. ? ( value.toString() !== matchingValue.toString() )
  8533. : false
  8534. ;
  8535. },
  8536. creditCard: function(cardNumber, cardTypes) {
  8537. var
  8538. cards = {
  8539. visa: {
  8540. pattern : /^4/,
  8541. length : [16]
  8542. },
  8543. amex: {
  8544. pattern : /^3[47]/,
  8545. length : [15]
  8546. },
  8547. mastercard: {
  8548. pattern : /^5[1-5]/,
  8549. length : [16]
  8550. },
  8551. discover: {
  8552. 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)/,
  8553. length : [16]
  8554. },
  8555. unionPay: {
  8556. pattern : /^(62|88)/,
  8557. length : [16, 17, 18, 19]
  8558. },
  8559. jcb: {
  8560. pattern : /^35(2[89]|[3-8][0-9])/,
  8561. length : [16]
  8562. },
  8563. maestro: {
  8564. pattern : /^(5018|5020|5038|6304|6759|676[1-3])/,
  8565. length : [12, 13, 14, 15, 16, 17, 18, 19]
  8566. },
  8567. dinersClub: {
  8568. pattern : /^(30[0-5]|^36)/,
  8569. length : [14]
  8570. },
  8571. laser: {
  8572. pattern : /^(6304|670[69]|6771)/,
  8573. length : [16, 17, 18, 19]
  8574. },
  8575. visaElectron: {
  8576. pattern : /^(4026|417500|4508|4844|491(3|7))/,
  8577. length : [16]
  8578. }
  8579. },
  8580. valid = {},
  8581. validCard = false,
  8582. requiredTypes = (typeof cardTypes == 'string')
  8583. ? cardTypes.split(',')
  8584. : false,
  8585. unionPay,
  8586. validation
  8587. ;
  8588. if(typeof cardNumber !== 'string' || cardNumber.length === 0) {
  8589. return;
  8590. }
  8591. // allow dashes in card
  8592. cardNumber = cardNumber.replace(/[\-]/g, '');
  8593. // verify card types
  8594. if(requiredTypes) {
  8595. $.each(requiredTypes, function(index, type){
  8596. // verify each card type
  8597. validation = cards[type];
  8598. if(validation) {
  8599. valid = {
  8600. length : ($.inArray(cardNumber.length, validation.length) !== -1),
  8601. pattern : (cardNumber.search(validation.pattern) !== -1)
  8602. };
  8603. if(valid.length && valid.pattern) {
  8604. validCard = true;
  8605. }
  8606. }
  8607. });
  8608. if(!validCard) {
  8609. return false;
  8610. }
  8611. }
  8612. // skip luhn for UnionPay
  8613. unionPay = {
  8614. number : ($.inArray(cardNumber.length, cards.unionPay.length) !== -1),
  8615. pattern : (cardNumber.search(cards.unionPay.pattern) !== -1)
  8616. };
  8617. if(unionPay.number && unionPay.pattern) {
  8618. return true;
  8619. }
  8620. // verify luhn, adapted from <https://gist.github.com/2134376>
  8621. var
  8622. length = cardNumber.length,
  8623. multiple = 0,
  8624. producedValue = [
  8625. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
  8626. [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
  8627. ],
  8628. sum = 0
  8629. ;
  8630. while (length--) {
  8631. sum += producedValue[multiple][parseInt(cardNumber.charAt(length), 10)];
  8632. multiple ^= 1;
  8633. }
  8634. return (sum % 10 === 0 && sum > 0);
  8635. },
  8636. minCount: function(value, minCount) {
  8637. if(minCount == 0) {
  8638. return true;
  8639. }
  8640. if(minCount == 1) {
  8641. return (value !== '');
  8642. }
  8643. return (value.split(',').length >= minCount);
  8644. },
  8645. exactCount: function(value, exactCount) {
  8646. if(exactCount == 0) {
  8647. return (value === '');
  8648. }
  8649. if(exactCount == 1) {
  8650. return (value !== '' && value.search(',') === -1);
  8651. }
  8652. return (value.split(',').length == exactCount);
  8653. },
  8654. maxCount: function(value, maxCount) {
  8655. if(maxCount == 0) {
  8656. return false;
  8657. }
  8658. if(maxCount == 1) {
  8659. return (value.search(',') === -1);
  8660. }
  8661. return (value.split(',').length <= maxCount);
  8662. }
  8663. }
  8664. };
  8665. })( jQuery, window, document );
  8666. /*!
  8667. * # Fomantic-UI - Modal
  8668. * http://github.com/fomantic/Fomantic-UI/
  8669. *
  8670. *
  8671. * Released under the MIT license
  8672. * http://opensource.org/licenses/MIT
  8673. *
  8674. */
  8675. ;(function ($, window, document, undefined) {
  8676. 'use strict';
  8677. $.isFunction = $.isFunction || function(obj) {
  8678. return typeof obj === "function" && typeof obj.nodeType !== "number";
  8679. };
  8680. window = (typeof window != 'undefined' && window.Math == Math)
  8681. ? window
  8682. : (typeof self != 'undefined' && self.Math == Math)
  8683. ? self
  8684. : Function('return this')()
  8685. ;
  8686. $.fn.modal = function(parameters) {
  8687. var
  8688. $allModules = $(this),
  8689. $window = $(window),
  8690. $document = $(document),
  8691. $body = $('body'),
  8692. moduleSelector = $allModules.selector || '',
  8693. time = new Date().getTime(),
  8694. performance = [],
  8695. query = arguments[0],
  8696. methodInvoked = (typeof query == 'string'),
  8697. queryArguments = [].slice.call(arguments, 1),
  8698. requestAnimationFrame = window.requestAnimationFrame
  8699. || window.mozRequestAnimationFrame
  8700. || window.webkitRequestAnimationFrame
  8701. || window.msRequestAnimationFrame
  8702. || function(callback) { setTimeout(callback, 0); },
  8703. returnedValue
  8704. ;
  8705. $allModules
  8706. .each(function() {
  8707. var
  8708. settings = ( $.isPlainObject(parameters) )
  8709. ? $.extend(true, {}, $.fn.modal.settings, parameters)
  8710. : $.extend({}, $.fn.modal.settings),
  8711. selector = settings.selector,
  8712. className = settings.className,
  8713. namespace = settings.namespace,
  8714. error = settings.error,
  8715. eventNamespace = '.' + namespace,
  8716. moduleNamespace = 'module-' + namespace,
  8717. $module = $(this),
  8718. $context = $(settings.context),
  8719. $close = $module.find(selector.close),
  8720. $allModals,
  8721. $otherModals,
  8722. $focusedElement,
  8723. $dimmable,
  8724. $dimmer,
  8725. element = this,
  8726. instance = $module.data(moduleNamespace),
  8727. ignoreRepeatedEvents = false,
  8728. initialMouseDownInModal,
  8729. initialMouseDownInScrollbar,
  8730. initialBodyMargin = '',
  8731. tempBodyMargin = '',
  8732. elementEventNamespace,
  8733. id,
  8734. observer,
  8735. module
  8736. ;
  8737. module = {
  8738. initialize: function() {
  8739. module.cache = {};
  8740. module.verbose('Initializing dimmer', $context);
  8741. module.create.id();
  8742. module.create.dimmer();
  8743. if ( settings.allowMultiple ) {
  8744. module.create.innerDimmer();
  8745. }
  8746. if (!settings.centered){
  8747. $module.addClass('top aligned');
  8748. }
  8749. module.refreshModals();
  8750. module.bind.events();
  8751. if(settings.observeChanges) {
  8752. module.observeChanges();
  8753. }
  8754. module.instantiate();
  8755. },
  8756. instantiate: function() {
  8757. module.verbose('Storing instance of modal');
  8758. instance = module;
  8759. $module
  8760. .data(moduleNamespace, instance)
  8761. ;
  8762. },
  8763. create: {
  8764. dimmer: function() {
  8765. var
  8766. defaultSettings = {
  8767. debug : settings.debug,
  8768. dimmerName : 'modals'
  8769. },
  8770. dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
  8771. ;
  8772. if($.fn.dimmer === undefined) {
  8773. module.error(error.dimmer);
  8774. return;
  8775. }
  8776. module.debug('Creating dimmer');
  8777. $dimmable = $context.dimmer(dimmerSettings);
  8778. if(settings.detachable) {
  8779. module.verbose('Modal is detachable, moving content into dimmer');
  8780. $dimmable.dimmer('add content', $module);
  8781. }
  8782. else {
  8783. module.set.undetached();
  8784. }
  8785. $dimmer = $dimmable.dimmer('get dimmer');
  8786. },
  8787. id: function() {
  8788. id = (Math.random().toString(16) + '000000000').substr(2, 8);
  8789. elementEventNamespace = '.' + id;
  8790. module.verbose('Creating unique id for element', id);
  8791. },
  8792. innerDimmer: function() {
  8793. if ( $module.find(selector.dimmer).length == 0 ) {
  8794. $module.prepend('<div class="ui inverted dimmer"></div>');
  8795. }
  8796. }
  8797. },
  8798. destroy: function() {
  8799. if (observer) {
  8800. observer.disconnect();
  8801. }
  8802. module.verbose('Destroying previous modal');
  8803. $module
  8804. .removeData(moduleNamespace)
  8805. .off(eventNamespace)
  8806. ;
  8807. $window.off(elementEventNamespace);
  8808. $dimmer.off(elementEventNamespace);
  8809. $close.off(eventNamespace);
  8810. $context.dimmer('destroy');
  8811. },
  8812. observeChanges: function() {
  8813. if('MutationObserver' in window) {
  8814. observer = new MutationObserver(function(mutations) {
  8815. module.debug('DOM tree modified, refreshing');
  8816. module.refresh();
  8817. });
  8818. observer.observe(element, {
  8819. childList : true,
  8820. subtree : true
  8821. });
  8822. module.debug('Setting up mutation observer', observer);
  8823. }
  8824. },
  8825. refresh: function() {
  8826. module.remove.scrolling();
  8827. module.cacheSizes();
  8828. if(!module.can.useFlex()) {
  8829. module.set.modalOffset();
  8830. }
  8831. module.set.screenHeight();
  8832. module.set.type();
  8833. },
  8834. refreshModals: function() {
  8835. $otherModals = $module.siblings(selector.modal);
  8836. $allModals = $otherModals.add($module);
  8837. },
  8838. attachEvents: function(selector, event) {
  8839. var
  8840. $toggle = $(selector)
  8841. ;
  8842. event = $.isFunction(module[event])
  8843. ? module[event]
  8844. : module.toggle
  8845. ;
  8846. if($toggle.length > 0) {
  8847. module.debug('Attaching modal events to element', selector, event);
  8848. $toggle
  8849. .off(eventNamespace)
  8850. .on('click' + eventNamespace, event)
  8851. ;
  8852. }
  8853. else {
  8854. module.error(error.notFound, selector);
  8855. }
  8856. },
  8857. bind: {
  8858. events: function() {
  8859. module.verbose('Attaching events');
  8860. $module
  8861. .on('click' + eventNamespace, selector.close, module.event.close)
  8862. .on('click' + eventNamespace, selector.approve, module.event.approve)
  8863. .on('click' + eventNamespace, selector.deny, module.event.deny)
  8864. ;
  8865. $window
  8866. .on('resize' + elementEventNamespace, module.event.resize)
  8867. ;
  8868. },
  8869. scrollLock: function() {
  8870. // touch events default to passive, due to changes in chrome to optimize mobile perf
  8871. $dimmable.get(0).addEventListener('touchmove', module.event.preventScroll, { passive: false });
  8872. }
  8873. },
  8874. unbind: {
  8875. scrollLock: function() {
  8876. $dimmable.get(0).removeEventListener('touchmove', module.event.preventScroll, { passive: false });
  8877. }
  8878. },
  8879. get: {
  8880. id: function() {
  8881. return (Math.random().toString(16) + '000000000').substr(2, 8);
  8882. }
  8883. },
  8884. event: {
  8885. approve: function() {
  8886. if(ignoreRepeatedEvents || settings.onApprove.call(element, $(this)) === false) {
  8887. module.verbose('Approve callback returned false cancelling hide');
  8888. return;
  8889. }
  8890. ignoreRepeatedEvents = true;
  8891. module.hide(function() {
  8892. ignoreRepeatedEvents = false;
  8893. });
  8894. },
  8895. preventScroll: function(event) {
  8896. if(event.target.className.indexOf('dimmer') !== -1) {
  8897. event.preventDefault();
  8898. }
  8899. },
  8900. deny: function() {
  8901. if(ignoreRepeatedEvents || settings.onDeny.call(element, $(this)) === false) {
  8902. module.verbose('Deny callback returned false cancelling hide');
  8903. return;
  8904. }
  8905. ignoreRepeatedEvents = true;
  8906. module.hide(function() {
  8907. ignoreRepeatedEvents = false;
  8908. });
  8909. },
  8910. close: function() {
  8911. module.hide();
  8912. },
  8913. mousedown: function(event) {
  8914. var
  8915. $target = $(event.target),
  8916. isRtl = module.is.rtl();
  8917. ;
  8918. initialMouseDownInModal = ($target.closest(selector.modal).length > 0);
  8919. if(initialMouseDownInModal) {
  8920. module.verbose('Mouse down event registered inside the modal');
  8921. }
  8922. initialMouseDownInScrollbar = module.is.scrolling() && ((!isRtl && $(window).outerWidth() - settings.scrollbarWidth <= event.clientX) || (isRtl && settings.scrollbarWidth >= event.clientX));
  8923. if(initialMouseDownInScrollbar) {
  8924. module.verbose('Mouse down event registered inside the scrollbar');
  8925. }
  8926. },
  8927. mouseup: function(event) {
  8928. if(!settings.closable) {
  8929. module.verbose('Dimmer clicked but closable setting is disabled');
  8930. return;
  8931. }
  8932. if(initialMouseDownInModal) {
  8933. module.debug('Dimmer clicked but mouse down was initially registered inside the modal');
  8934. return;
  8935. }
  8936. if(initialMouseDownInScrollbar){
  8937. module.debug('Dimmer clicked but mouse down was initially registered inside the scrollbar');
  8938. return;
  8939. }
  8940. var
  8941. $target = $(event.target),
  8942. isInModal = ($target.closest(selector.modal).length > 0),
  8943. isInDOM = $.contains(document.documentElement, event.target)
  8944. ;
  8945. if(!isInModal && isInDOM && module.is.active() && $module.hasClass(className.front) ) {
  8946. module.debug('Dimmer clicked, hiding all modals');
  8947. if(settings.allowMultiple) {
  8948. if(!module.hideAll()) {
  8949. return;
  8950. }
  8951. }
  8952. else if(!module.hide()){
  8953. return;
  8954. }
  8955. module.remove.clickaway();
  8956. }
  8957. },
  8958. debounce: function(method, delay) {
  8959. clearTimeout(module.timer);
  8960. module.timer = setTimeout(method, delay);
  8961. },
  8962. keyboard: function(event) {
  8963. var
  8964. keyCode = event.which,
  8965. escapeKey = 27
  8966. ;
  8967. if(keyCode == escapeKey) {
  8968. if(settings.closable) {
  8969. module.debug('Escape key pressed hiding modal');
  8970. if ( $module.hasClass(className.front) ) {
  8971. module.hide();
  8972. }
  8973. }
  8974. else {
  8975. module.debug('Escape key pressed, but closable is set to false');
  8976. }
  8977. event.preventDefault();
  8978. }
  8979. },
  8980. resize: function() {
  8981. if( $dimmable.dimmer('is active') && ( module.is.animating() || module.is.active() ) ) {
  8982. requestAnimationFrame(module.refresh);
  8983. }
  8984. }
  8985. },
  8986. toggle: function() {
  8987. if( module.is.active() || module.is.animating() ) {
  8988. module.hide();
  8989. }
  8990. else {
  8991. module.show();
  8992. }
  8993. },
  8994. show: function(callback) {
  8995. callback = $.isFunction(callback)
  8996. ? callback
  8997. : function(){}
  8998. ;
  8999. module.refreshModals();
  9000. module.set.dimmerSettings();
  9001. module.set.dimmerStyles();
  9002. module.showModal(callback);
  9003. },
  9004. hide: function(callback) {
  9005. callback = $.isFunction(callback)
  9006. ? callback
  9007. : function(){}
  9008. ;
  9009. module.refreshModals();
  9010. return module.hideModal(callback);
  9011. },
  9012. showModal: function(callback) {
  9013. callback = $.isFunction(callback)
  9014. ? callback
  9015. : function(){}
  9016. ;
  9017. if( module.is.animating() || !module.is.active() ) {
  9018. module.showDimmer();
  9019. module.cacheSizes();
  9020. module.set.bodyMargin();
  9021. if(module.can.useFlex()) {
  9022. module.remove.legacy();
  9023. }
  9024. else {
  9025. module.set.legacy();
  9026. module.set.modalOffset();
  9027. module.debug('Using non-flex legacy modal positioning.');
  9028. }
  9029. module.set.screenHeight();
  9030. module.set.type();
  9031. module.set.clickaway();
  9032. if( !settings.allowMultiple && module.others.active() ) {
  9033. module.hideOthers(module.showModal);
  9034. }
  9035. else {
  9036. ignoreRepeatedEvents = false;
  9037. if( settings.allowMultiple ) {
  9038. if ( module.others.active() ) {
  9039. $otherModals.filter('.' + className.active).find(selector.dimmer).addClass('active');
  9040. }
  9041. if ( settings.detachable ) {
  9042. $module.detach().appendTo($dimmer);
  9043. }
  9044. }
  9045. settings.onShow.call(element);
  9046. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  9047. module.debug('Showing modal with css animations');
  9048. $module
  9049. .transition({
  9050. debug : settings.debug,
  9051. animation : settings.transition + ' in',
  9052. queue : settings.queue,
  9053. duration : settings.duration,
  9054. useFailSafe : true,
  9055. onComplete : function() {
  9056. settings.onVisible.apply(element);
  9057. if(settings.keyboardShortcuts) {
  9058. module.add.keyboardShortcuts();
  9059. }
  9060. module.save.focus();
  9061. module.set.active();
  9062. if(settings.autofocus) {
  9063. module.set.autofocus();
  9064. }
  9065. callback();
  9066. }
  9067. })
  9068. ;
  9069. }
  9070. else {
  9071. module.error(error.noTransition);
  9072. }
  9073. }
  9074. }
  9075. else {
  9076. module.debug('Modal is already visible');
  9077. }
  9078. },
  9079. hideModal: function(callback, keepDimmed, hideOthersToo) {
  9080. var
  9081. $previousModal = $otherModals.filter('.' + className.active).last()
  9082. ;
  9083. callback = $.isFunction(callback)
  9084. ? callback
  9085. : function(){}
  9086. ;
  9087. module.debug('Hiding modal');
  9088. if(settings.onHide.call(element, $(this)) === false) {
  9089. module.verbose('Hide callback returned false cancelling hide');
  9090. ignoreRepeatedEvents = false;
  9091. return false;
  9092. }
  9093. if( module.is.animating() || module.is.active() ) {
  9094. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  9095. module.remove.active();
  9096. $module
  9097. .transition({
  9098. debug : settings.debug,
  9099. animation : settings.transition + ' out',
  9100. queue : settings.queue,
  9101. duration : settings.duration,
  9102. useFailSafe : true,
  9103. onStart : function() {
  9104. if(!module.others.active() && !module.others.animating() && !keepDimmed) {
  9105. module.hideDimmer();
  9106. }
  9107. if( settings.keyboardShortcuts && !module.others.active() ) {
  9108. module.remove.keyboardShortcuts();
  9109. }
  9110. },
  9111. onComplete : function() {
  9112. module.unbind.scrollLock();
  9113. if ( settings.allowMultiple ) {
  9114. $previousModal.addClass(className.front);
  9115. $module.removeClass(className.front);
  9116. if ( hideOthersToo ) {
  9117. $allModals.find(selector.dimmer).removeClass('active');
  9118. }
  9119. else {
  9120. $previousModal.find(selector.dimmer).removeClass('active');
  9121. }
  9122. }
  9123. settings.onHidden.call(element);
  9124. module.remove.dimmerStyles();
  9125. module.restore.focus();
  9126. callback();
  9127. }
  9128. })
  9129. ;
  9130. }
  9131. else {
  9132. module.error(error.noTransition);
  9133. }
  9134. }
  9135. },
  9136. showDimmer: function() {
  9137. if($dimmable.dimmer('is animating') || !$dimmable.dimmer('is active') ) {
  9138. module.save.bodyMargin();
  9139. module.debug('Showing dimmer');
  9140. $dimmable.dimmer('show');
  9141. }
  9142. else {
  9143. module.debug('Dimmer already visible');
  9144. }
  9145. },
  9146. hideDimmer: function() {
  9147. if( $dimmable.dimmer('is animating') || ($dimmable.dimmer('is active')) ) {
  9148. module.unbind.scrollLock();
  9149. $dimmable.dimmer('hide', function() {
  9150. module.restore.bodyMargin();
  9151. module.remove.clickaway();
  9152. module.remove.screenHeight();
  9153. });
  9154. }
  9155. else {
  9156. module.debug('Dimmer is not visible cannot hide');
  9157. return;
  9158. }
  9159. },
  9160. hideAll: function(callback) {
  9161. var
  9162. $visibleModals = $allModals.filter('.' + className.active + ', .' + className.animating)
  9163. ;
  9164. callback = $.isFunction(callback)
  9165. ? callback
  9166. : function(){}
  9167. ;
  9168. if( $visibleModals.length > 0 ) {
  9169. module.debug('Hiding all visible modals');
  9170. var hideOk = true;
  9171. //check in reverse order trying to hide most top displayed modal first
  9172. $($visibleModals.get().reverse()).each(function(index,element){
  9173. if(hideOk){
  9174. hideOk = $(element).modal('hide modal', callback, false, true);
  9175. }
  9176. });
  9177. if(hideOk) {
  9178. module.hideDimmer();
  9179. }
  9180. return hideOk;
  9181. }
  9182. },
  9183. hideOthers: function(callback) {
  9184. var
  9185. $visibleModals = $otherModals.filter('.' + className.active + ', .' + className.animating)
  9186. ;
  9187. callback = $.isFunction(callback)
  9188. ? callback
  9189. : function(){}
  9190. ;
  9191. if( $visibleModals.length > 0 ) {
  9192. module.debug('Hiding other modals', $otherModals);
  9193. $visibleModals
  9194. .modal('hide modal', callback, true)
  9195. ;
  9196. }
  9197. },
  9198. others: {
  9199. active: function() {
  9200. return ($otherModals.filter('.' + className.active).length > 0);
  9201. },
  9202. animating: function() {
  9203. return ($otherModals.filter('.' + className.animating).length > 0);
  9204. }
  9205. },
  9206. add: {
  9207. keyboardShortcuts: function() {
  9208. module.verbose('Adding keyboard shortcuts');
  9209. $document
  9210. .on('keyup' + eventNamespace, module.event.keyboard)
  9211. ;
  9212. }
  9213. },
  9214. save: {
  9215. focus: function() {
  9216. var
  9217. $activeElement = $(document.activeElement),
  9218. inCurrentModal = $activeElement.closest($module).length > 0
  9219. ;
  9220. if(!inCurrentModal) {
  9221. $focusedElement = $(document.activeElement).blur();
  9222. }
  9223. },
  9224. bodyMargin: function() {
  9225. initialBodyMargin = $body.css('margin-'+(module.can.leftBodyScrollbar() ? 'left':'right'));
  9226. var bodyMarginRightPixel = parseInt(initialBodyMargin.replace(/[^\d.]/g, '')),
  9227. bodyScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
  9228. tempBodyMargin = bodyMarginRightPixel + bodyScrollbarWidth;
  9229. }
  9230. },
  9231. restore: {
  9232. focus: function() {
  9233. if($focusedElement && $focusedElement.length > 0 && settings.restoreFocus) {
  9234. $focusedElement.focus();
  9235. }
  9236. },
  9237. bodyMargin: function() {
  9238. var position = module.can.leftBodyScrollbar() ? 'left':'right';
  9239. $body.css('margin-'+position, initialBodyMargin);
  9240. $body.find(selector.bodyFixed.replace('right',position)).css('padding-'+position, initialBodyMargin);
  9241. }
  9242. },
  9243. remove: {
  9244. active: function() {
  9245. $module.removeClass(className.active);
  9246. },
  9247. legacy: function() {
  9248. $module.removeClass(className.legacy);
  9249. },
  9250. clickaway: function() {
  9251. if (!settings.detachable) {
  9252. $module
  9253. .off('mousedown' + elementEventNamespace)
  9254. ;
  9255. }
  9256. $dimmer
  9257. .off('mousedown' + elementEventNamespace)
  9258. ;
  9259. $dimmer
  9260. .off('mouseup' + elementEventNamespace)
  9261. ;
  9262. },
  9263. dimmerStyles: function() {
  9264. $dimmer.removeClass(className.inverted);
  9265. $dimmable.removeClass(className.blurring);
  9266. },
  9267. bodyStyle: function() {
  9268. if($body.attr('style') === '') {
  9269. module.verbose('Removing style attribute');
  9270. $body.removeAttr('style');
  9271. }
  9272. },
  9273. screenHeight: function() {
  9274. module.debug('Removing page height');
  9275. $body
  9276. .css('height', '')
  9277. ;
  9278. },
  9279. keyboardShortcuts: function() {
  9280. module.verbose('Removing keyboard shortcuts');
  9281. $document
  9282. .off('keyup' + eventNamespace)
  9283. ;
  9284. },
  9285. scrolling: function() {
  9286. $dimmable.removeClass(className.scrolling);
  9287. $module.removeClass(className.scrolling);
  9288. }
  9289. },
  9290. cacheSizes: function() {
  9291. $module.addClass(className.loading);
  9292. var
  9293. scrollHeight = $module.prop('scrollHeight'),
  9294. modalWidth = $module.outerWidth(),
  9295. modalHeight = $module.outerHeight()
  9296. ;
  9297. if(module.cache.pageHeight === undefined || modalHeight !== 0) {
  9298. $.extend(module.cache, {
  9299. pageHeight : $(document).outerHeight(),
  9300. width : modalWidth,
  9301. height : modalHeight + settings.offset,
  9302. scrollHeight : scrollHeight + settings.offset,
  9303. contextHeight : (settings.context == 'body')
  9304. ? $(window).height()
  9305. : $dimmable.height(),
  9306. });
  9307. module.cache.topOffset = -(module.cache.height / 2);
  9308. }
  9309. $module.removeClass(className.loading);
  9310. module.debug('Caching modal and container sizes', module.cache);
  9311. },
  9312. can: {
  9313. leftBodyScrollbar: function(){
  9314. if(module.cache.leftBodyScrollbar === undefined) {
  9315. module.cache.leftBodyScrollbar = module.is.rtl() && ((module.is.iframe && !module.is.firefox()) || module.is.safari() || module.is.edge() || module.is.ie());
  9316. }
  9317. return module.cache.leftBodyScrollbar;
  9318. },
  9319. useFlex: function() {
  9320. if (settings.useFlex === 'auto') {
  9321. return settings.detachable && !module.is.ie();
  9322. }
  9323. if(settings.useFlex && module.is.ie()) {
  9324. module.debug('useFlex true is not supported in IE');
  9325. } else if(settings.useFlex && !settings.detachable) {
  9326. module.debug('useFlex true in combination with detachable false is not supported');
  9327. }
  9328. return settings.useFlex;
  9329. },
  9330. fit: function() {
  9331. var
  9332. contextHeight = module.cache.contextHeight,
  9333. verticalCenter = module.cache.contextHeight / 2,
  9334. topOffset = module.cache.topOffset,
  9335. scrollHeight = module.cache.scrollHeight,
  9336. height = module.cache.height,
  9337. paddingHeight = settings.padding,
  9338. startPosition = (verticalCenter + topOffset)
  9339. ;
  9340. return (scrollHeight > height)
  9341. ? (startPosition + scrollHeight + paddingHeight < contextHeight)
  9342. : (height + (paddingHeight * 2) < contextHeight)
  9343. ;
  9344. }
  9345. },
  9346. is: {
  9347. active: function() {
  9348. return $module.hasClass(className.active);
  9349. },
  9350. ie: function() {
  9351. if(module.cache.isIE === undefined) {
  9352. var
  9353. isIE11 = (!(window.ActiveXObject) && 'ActiveXObject' in window),
  9354. isIE = ('ActiveXObject' in window)
  9355. ;
  9356. module.cache.isIE = (isIE11 || isIE);
  9357. }
  9358. return module.cache.isIE;
  9359. },
  9360. animating: function() {
  9361. return $module.transition('is supported')
  9362. ? $module.transition('is animating')
  9363. : $module.is(':visible')
  9364. ;
  9365. },
  9366. scrolling: function() {
  9367. return $dimmable.hasClass(className.scrolling);
  9368. },
  9369. modernBrowser: function() {
  9370. // appName for IE11 reports 'Netscape' can no longer use
  9371. return !(window.ActiveXObject || 'ActiveXObject' in window);
  9372. },
  9373. rtl: function() {
  9374. if(module.cache.isRTL === undefined) {
  9375. module.cache.isRTL = $body.attr('dir') === 'rtl' || $body.css('direction') === 'rtl';
  9376. }
  9377. return module.cache.isRTL;
  9378. },
  9379. safari: function() {
  9380. if(module.cache.isSafari === undefined) {
  9381. module.cache.isSafari = /constructor/i.test(window.HTMLElement) || !!window.ApplePaySession;
  9382. }
  9383. return module.cache.isSafari;
  9384. },
  9385. edge: function(){
  9386. if(module.cache.isEdge === undefined) {
  9387. module.cache.isEdge = !!window.setImmediate && !module.is.ie();
  9388. }
  9389. return module.cache.isEdge;
  9390. },
  9391. firefox: function(){
  9392. if(module.cache.isFirefox === undefined) {
  9393. module.cache.isFirefox = !!window.InstallTrigger;
  9394. }
  9395. return module.cache.isFirefox;
  9396. },
  9397. iframe: function() {
  9398. return !(self === top);
  9399. }
  9400. },
  9401. set: {
  9402. autofocus: function() {
  9403. var
  9404. $inputs = $module.find('[tabindex], :input').filter(':visible').filter(function() {
  9405. return $(this).closest('.disabled').length === 0;
  9406. }),
  9407. $autofocus = $inputs.filter('[autofocus]'),
  9408. $input = ($autofocus.length > 0)
  9409. ? $autofocus.first()
  9410. : $inputs.first()
  9411. ;
  9412. if($input.length > 0) {
  9413. $input.focus();
  9414. }
  9415. },
  9416. bodyMargin: function() {
  9417. var position = module.can.leftBodyScrollbar() ? 'left':'right';
  9418. if(settings.detachable || module.can.fit()) {
  9419. $body.css('margin-'+position, tempBodyMargin + 'px');
  9420. }
  9421. $body.find(selector.bodyFixed.replace('right',position)).css('padding-'+position, tempBodyMargin + 'px');
  9422. },
  9423. clickaway: function() {
  9424. if (!settings.detachable) {
  9425. $module
  9426. .on('mousedown' + elementEventNamespace, module.event.mousedown)
  9427. ;
  9428. }
  9429. $dimmer
  9430. .on('mousedown' + elementEventNamespace, module.event.mousedown)
  9431. ;
  9432. $dimmer
  9433. .on('mouseup' + elementEventNamespace, module.event.mouseup)
  9434. ;
  9435. },
  9436. dimmerSettings: function() {
  9437. if($.fn.dimmer === undefined) {
  9438. module.error(error.dimmer);
  9439. return;
  9440. }
  9441. var
  9442. defaultSettings = {
  9443. debug : settings.debug,
  9444. dimmerName : 'modals',
  9445. closable : 'auto',
  9446. useFlex : module.can.useFlex(),
  9447. duration : {
  9448. show : settings.duration,
  9449. hide : settings.duration
  9450. }
  9451. },
  9452. dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
  9453. ;
  9454. if(settings.inverted) {
  9455. dimmerSettings.variation = (dimmerSettings.variation !== undefined)
  9456. ? dimmerSettings.variation + ' inverted'
  9457. : 'inverted'
  9458. ;
  9459. }
  9460. $context.dimmer('setting', dimmerSettings);
  9461. },
  9462. dimmerStyles: function() {
  9463. if(settings.inverted) {
  9464. $dimmer.addClass(className.inverted);
  9465. }
  9466. else {
  9467. $dimmer.removeClass(className.inverted);
  9468. }
  9469. if(settings.blurring) {
  9470. $dimmable.addClass(className.blurring);
  9471. }
  9472. else {
  9473. $dimmable.removeClass(className.blurring);
  9474. }
  9475. },
  9476. modalOffset: function() {
  9477. if (!settings.detachable) {
  9478. var canFit = module.can.fit();
  9479. $module
  9480. .css({
  9481. top: (!$module.hasClass('aligned') && canFit)
  9482. ? $(document).scrollTop() + (module.cache.contextHeight - module.cache.height) / 2
  9483. : !canFit || $module.hasClass('top')
  9484. ? $(document).scrollTop() + settings.padding
  9485. : $(document).scrollTop() + (module.cache.contextHeight - module.cache.height - settings.padding),
  9486. marginLeft: -(module.cache.width / 2)
  9487. })
  9488. ;
  9489. } else {
  9490. $module
  9491. .css({
  9492. marginTop: (!$module.hasClass('aligned') && module.can.fit())
  9493. ? -(module.cache.height / 2)
  9494. : settings.padding / 2,
  9495. marginLeft: -(module.cache.width / 2)
  9496. })
  9497. ;
  9498. }
  9499. module.verbose('Setting modal offset for legacy mode');
  9500. },
  9501. screenHeight: function() {
  9502. if( module.can.fit() ) {
  9503. $body.css('height', '');
  9504. }
  9505. else if(!$module.hasClass('bottom')) {
  9506. module.debug('Modal is taller than page content, resizing page height');
  9507. $body
  9508. .css('height', module.cache.height + (settings.padding * 2) )
  9509. ;
  9510. }
  9511. },
  9512. active: function() {
  9513. $module.addClass(className.active + ' ' + className.front);
  9514. $otherModals.filter('.' + className.active).removeClass(className.front);
  9515. },
  9516. scrolling: function() {
  9517. $dimmable.addClass(className.scrolling);
  9518. $module.addClass(className.scrolling);
  9519. module.unbind.scrollLock();
  9520. },
  9521. legacy: function() {
  9522. $module.addClass(className.legacy);
  9523. },
  9524. type: function() {
  9525. if(module.can.fit()) {
  9526. module.verbose('Modal fits on screen');
  9527. if(!module.others.active() && !module.others.animating()) {
  9528. module.remove.scrolling();
  9529. module.bind.scrollLock();
  9530. }
  9531. }
  9532. else if (!$module.hasClass('bottom')){
  9533. module.verbose('Modal cannot fit on screen setting to scrolling');
  9534. module.set.scrolling();
  9535. } else {
  9536. module.verbose('Bottom aligned modal not fitting on screen is unsupported for scrolling');
  9537. }
  9538. },
  9539. undetached: function() {
  9540. $dimmable.addClass(className.undetached);
  9541. }
  9542. },
  9543. setting: function(name, value) {
  9544. module.debug('Changing setting', name, value);
  9545. if( $.isPlainObject(name) ) {
  9546. $.extend(true, settings, name);
  9547. }
  9548. else if(value !== undefined) {
  9549. if($.isPlainObject(settings[name])) {
  9550. $.extend(true, settings[name], value);
  9551. }
  9552. else {
  9553. settings[name] = value;
  9554. }
  9555. }
  9556. else {
  9557. return settings[name];
  9558. }
  9559. },
  9560. internal: function(name, value) {
  9561. if( $.isPlainObject(name) ) {
  9562. $.extend(true, module, name);
  9563. }
  9564. else if(value !== undefined) {
  9565. module[name] = value;
  9566. }
  9567. else {
  9568. return module[name];
  9569. }
  9570. },
  9571. debug: function() {
  9572. if(!settings.silent && settings.debug) {
  9573. if(settings.performance) {
  9574. module.performance.log(arguments);
  9575. }
  9576. else {
  9577. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  9578. module.debug.apply(console, arguments);
  9579. }
  9580. }
  9581. },
  9582. verbose: function() {
  9583. if(!settings.silent && settings.verbose && settings.debug) {
  9584. if(settings.performance) {
  9585. module.performance.log(arguments);
  9586. }
  9587. else {
  9588. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  9589. module.verbose.apply(console, arguments);
  9590. }
  9591. }
  9592. },
  9593. error: function() {
  9594. if(!settings.silent) {
  9595. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  9596. module.error.apply(console, arguments);
  9597. }
  9598. },
  9599. performance: {
  9600. log: function(message) {
  9601. var
  9602. currentTime,
  9603. executionTime,
  9604. previousTime
  9605. ;
  9606. if(settings.performance) {
  9607. currentTime = new Date().getTime();
  9608. previousTime = time || currentTime;
  9609. executionTime = currentTime - previousTime;
  9610. time = currentTime;
  9611. performance.push({
  9612. 'Name' : message[0],
  9613. 'Arguments' : [].slice.call(message, 1) || '',
  9614. 'Element' : element,
  9615. 'Execution Time' : executionTime
  9616. });
  9617. }
  9618. clearTimeout(module.performance.timer);
  9619. module.performance.timer = setTimeout(module.performance.display, 500);
  9620. },
  9621. display: function() {
  9622. var
  9623. title = settings.name + ':',
  9624. totalTime = 0
  9625. ;
  9626. time = false;
  9627. clearTimeout(module.performance.timer);
  9628. $.each(performance, function(index, data) {
  9629. totalTime += data['Execution Time'];
  9630. });
  9631. title += ' ' + totalTime + 'ms';
  9632. if(moduleSelector) {
  9633. title += ' \'' + moduleSelector + '\'';
  9634. }
  9635. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  9636. console.groupCollapsed(title);
  9637. if(console.table) {
  9638. console.table(performance);
  9639. }
  9640. else {
  9641. $.each(performance, function(index, data) {
  9642. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  9643. });
  9644. }
  9645. console.groupEnd();
  9646. }
  9647. performance = [];
  9648. }
  9649. },
  9650. invoke: function(query, passedArguments, context) {
  9651. var
  9652. object = instance,
  9653. maxDepth,
  9654. found,
  9655. response
  9656. ;
  9657. passedArguments = passedArguments || queryArguments;
  9658. context = element || context;
  9659. if(typeof query == 'string' && object !== undefined) {
  9660. query = query.split(/[\. ]/);
  9661. maxDepth = query.length - 1;
  9662. $.each(query, function(depth, value) {
  9663. var camelCaseValue = (depth != maxDepth)
  9664. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  9665. : query
  9666. ;
  9667. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  9668. object = object[camelCaseValue];
  9669. }
  9670. else if( object[camelCaseValue] !== undefined ) {
  9671. found = object[camelCaseValue];
  9672. return false;
  9673. }
  9674. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  9675. object = object[value];
  9676. }
  9677. else if( object[value] !== undefined ) {
  9678. found = object[value];
  9679. return false;
  9680. }
  9681. else {
  9682. return false;
  9683. }
  9684. });
  9685. }
  9686. if ( $.isFunction( found ) ) {
  9687. response = found.apply(context, passedArguments);
  9688. }
  9689. else if(found !== undefined) {
  9690. response = found;
  9691. }
  9692. if(Array.isArray(returnedValue)) {
  9693. returnedValue.push(response);
  9694. }
  9695. else if(returnedValue !== undefined) {
  9696. returnedValue = [returnedValue, response];
  9697. }
  9698. else if(response !== undefined) {
  9699. returnedValue = response;
  9700. }
  9701. return found;
  9702. }
  9703. };
  9704. if(methodInvoked) {
  9705. if(instance === undefined) {
  9706. module.initialize();
  9707. }
  9708. module.invoke(query);
  9709. }
  9710. else {
  9711. if(instance !== undefined) {
  9712. instance.invoke('destroy');
  9713. }
  9714. module.initialize();
  9715. }
  9716. })
  9717. ;
  9718. return (returnedValue !== undefined)
  9719. ? returnedValue
  9720. : this
  9721. ;
  9722. };
  9723. $.fn.modal.settings = {
  9724. name : 'Modal',
  9725. namespace : 'modal',
  9726. useFlex : 'auto',
  9727. offset : 0,
  9728. silent : false,
  9729. debug : false,
  9730. verbose : false,
  9731. performance : true,
  9732. observeChanges : false,
  9733. allowMultiple : false,
  9734. detachable : true,
  9735. closable : true,
  9736. autofocus : true,
  9737. restoreFocus : true,
  9738. inverted : false,
  9739. blurring : false,
  9740. centered : true,
  9741. dimmerSettings : {
  9742. closable : false,
  9743. useCSS : true
  9744. },
  9745. // whether to use keyboard shortcuts
  9746. keyboardShortcuts: true,
  9747. context : 'body',
  9748. queue : false,
  9749. duration : 500,
  9750. transition : 'scale',
  9751. // padding with edge of page
  9752. padding : 50,
  9753. scrollbarWidth: 10,
  9754. // called before show animation
  9755. onShow : function(){},
  9756. // called after show animation
  9757. onVisible : function(){},
  9758. // called before hide animation
  9759. onHide : function(){ return true; },
  9760. // called after hide animation
  9761. onHidden : function(){},
  9762. // called after approve selector match
  9763. onApprove : function(){ return true; },
  9764. // called after deny selector match
  9765. onDeny : function(){ return true; },
  9766. selector : {
  9767. close : '> .close',
  9768. approve : '.actions .positive, .actions .approve, .actions .ok',
  9769. deny : '.actions .negative, .actions .deny, .actions .cancel',
  9770. modal : '.ui.modal',
  9771. dimmer : '> .ui.dimmer',
  9772. bodyFixed: '> .ui.fixed.menu, > .ui.right.toast-container, > .ui.right.sidebar'
  9773. },
  9774. error : {
  9775. dimmer : 'UI Dimmer, a required component is not included in this page',
  9776. method : 'The method you called is not defined.',
  9777. notFound : 'The element you specified could not be found'
  9778. },
  9779. className : {
  9780. active : 'active',
  9781. animating : 'animating',
  9782. blurring : 'blurring',
  9783. inverted : 'inverted',
  9784. legacy : 'legacy',
  9785. loading : 'loading',
  9786. scrolling : 'scrolling',
  9787. undetached : 'undetached',
  9788. front : 'front'
  9789. }
  9790. };
  9791. })( jQuery, window, document );
  9792. /*!
  9793. * # Fomantic-UI - Popup
  9794. * http://github.com/fomantic/Fomantic-UI/
  9795. *
  9796. *
  9797. * Released under the MIT license
  9798. * http://opensource.org/licenses/MIT
  9799. *
  9800. */
  9801. ;(function ($, window, document, undefined) {
  9802. 'use strict';
  9803. $.isFunction = $.isFunction || function(obj) {
  9804. return typeof obj === "function" && typeof obj.nodeType !== "number";
  9805. };
  9806. window = (typeof window != 'undefined' && window.Math == Math)
  9807. ? window
  9808. : (typeof self != 'undefined' && self.Math == Math)
  9809. ? self
  9810. : Function('return this')()
  9811. ;
  9812. $.fn.popup = function(parameters) {
  9813. var
  9814. $allModules = $(this),
  9815. $document = $(document),
  9816. $window = $(window),
  9817. $body = $('body'),
  9818. moduleSelector = $allModules.selector || '',
  9819. clickEvent = ('ontouchstart' in document.documentElement)
  9820. ? 'touchstart'
  9821. : 'click',
  9822. time = new Date().getTime(),
  9823. performance = [],
  9824. query = arguments[0],
  9825. methodInvoked = (typeof query == 'string'),
  9826. queryArguments = [].slice.call(arguments, 1),
  9827. returnedValue
  9828. ;
  9829. $allModules
  9830. .each(function() {
  9831. var
  9832. settings = ( $.isPlainObject(parameters) )
  9833. ? $.extend(true, {}, $.fn.popup.settings, parameters)
  9834. : $.extend({}, $.fn.popup.settings),
  9835. selector = settings.selector,
  9836. className = settings.className,
  9837. error = settings.error,
  9838. metadata = settings.metadata,
  9839. namespace = settings.namespace,
  9840. eventNamespace = '.' + settings.namespace,
  9841. moduleNamespace = 'module-' + namespace,
  9842. $module = $(this),
  9843. $context = $(settings.context),
  9844. $scrollContext = $(settings.scrollContext),
  9845. $boundary = $(settings.boundary),
  9846. $target = (settings.target)
  9847. ? $(settings.target)
  9848. : $module,
  9849. $popup,
  9850. $offsetParent,
  9851. searchDepth = 0,
  9852. triedPositions = false,
  9853. openedWithTouch = false,
  9854. element = this,
  9855. instance = $module.data(moduleNamespace),
  9856. documentObserver,
  9857. elementNamespace,
  9858. id,
  9859. module
  9860. ;
  9861. module = {
  9862. // binds events
  9863. initialize: function() {
  9864. module.debug('Initializing', $module);
  9865. module.createID();
  9866. module.bind.events();
  9867. if(!module.exists() && settings.preserve) {
  9868. module.create();
  9869. }
  9870. if(settings.observeChanges) {
  9871. module.observeChanges();
  9872. }
  9873. module.instantiate();
  9874. },
  9875. instantiate: function() {
  9876. module.verbose('Storing instance', module);
  9877. instance = module;
  9878. $module
  9879. .data(moduleNamespace, instance)
  9880. ;
  9881. },
  9882. observeChanges: function() {
  9883. if('MutationObserver' in window) {
  9884. documentObserver = new MutationObserver(module.event.documentChanged);
  9885. documentObserver.observe(document, {
  9886. childList : true,
  9887. subtree : true
  9888. });
  9889. module.debug('Setting up mutation observer', documentObserver);
  9890. }
  9891. },
  9892. refresh: function() {
  9893. if(settings.popup) {
  9894. $popup = $(settings.popup).eq(0);
  9895. }
  9896. else {
  9897. if(settings.inline) {
  9898. $popup = $target.nextAll(selector.popup).eq(0);
  9899. settings.popup = $popup;
  9900. }
  9901. }
  9902. if(settings.popup) {
  9903. $popup.addClass(className.loading);
  9904. $offsetParent = module.get.offsetParent();
  9905. $popup.removeClass(className.loading);
  9906. if(settings.movePopup && module.has.popup() && module.get.offsetParent($popup)[0] !== $offsetParent[0]) {
  9907. module.debug('Moving popup to the same offset parent as target');
  9908. $popup
  9909. .detach()
  9910. .appendTo($offsetParent)
  9911. ;
  9912. }
  9913. }
  9914. else {
  9915. $offsetParent = (settings.inline)
  9916. ? module.get.offsetParent($target)
  9917. : module.has.popup()
  9918. ? module.get.offsetParent($popup)
  9919. : $body
  9920. ;
  9921. }
  9922. if( $offsetParent.is('html') && $offsetParent[0] !== $body[0] ) {
  9923. module.debug('Setting page as offset parent');
  9924. $offsetParent = $body;
  9925. }
  9926. if( module.get.variation() ) {
  9927. module.set.variation();
  9928. }
  9929. },
  9930. reposition: function() {
  9931. module.refresh();
  9932. module.set.position();
  9933. },
  9934. destroy: function() {
  9935. module.debug('Destroying previous module');
  9936. if(documentObserver) {
  9937. documentObserver.disconnect();
  9938. }
  9939. // remove element only if was created dynamically
  9940. if($popup && !settings.preserve) {
  9941. module.removePopup();
  9942. }
  9943. // clear all timeouts
  9944. clearTimeout(module.hideTimer);
  9945. clearTimeout(module.showTimer);
  9946. // remove events
  9947. module.unbind.close();
  9948. module.unbind.events();
  9949. $module
  9950. .removeData(moduleNamespace)
  9951. ;
  9952. },
  9953. event: {
  9954. start: function(event) {
  9955. var
  9956. delay = ($.isPlainObject(settings.delay))
  9957. ? settings.delay.show
  9958. : settings.delay
  9959. ;
  9960. clearTimeout(module.hideTimer);
  9961. if(!openedWithTouch || (openedWithTouch && settings.addTouchEvents) ) {
  9962. module.showTimer = setTimeout(module.show, delay);
  9963. }
  9964. },
  9965. end: function() {
  9966. var
  9967. delay = ($.isPlainObject(settings.delay))
  9968. ? settings.delay.hide
  9969. : settings.delay
  9970. ;
  9971. clearTimeout(module.showTimer);
  9972. module.hideTimer = setTimeout(module.hide, delay);
  9973. },
  9974. touchstart: function(event) {
  9975. openedWithTouch = true;
  9976. if(settings.addTouchEvents) {
  9977. module.show();
  9978. }
  9979. },
  9980. resize: function() {
  9981. if( module.is.visible() ) {
  9982. module.set.position();
  9983. }
  9984. },
  9985. documentChanged: function(mutations) {
  9986. [].forEach.call(mutations, function(mutation) {
  9987. if(mutation.removedNodes) {
  9988. [].forEach.call(mutation.removedNodes, function(node) {
  9989. if(node == element || $(node).find(element).length > 0) {
  9990. module.debug('Element removed from DOM, tearing down events');
  9991. module.destroy();
  9992. }
  9993. });
  9994. }
  9995. });
  9996. },
  9997. hideGracefully: function(event) {
  9998. var
  9999. $target = $(event.target),
  10000. isInDOM = $.contains(document.documentElement, event.target),
  10001. inPopup = ($target.closest(selector.popup).length > 0)
  10002. ;
  10003. // don't close on clicks inside popup
  10004. if(event && !inPopup && isInDOM) {
  10005. module.debug('Click occurred outside popup hiding popup');
  10006. module.hide();
  10007. }
  10008. else {
  10009. module.debug('Click was inside popup, keeping popup open');
  10010. }
  10011. }
  10012. },
  10013. // generates popup html from metadata
  10014. create: function() {
  10015. var
  10016. html = module.get.html(),
  10017. title = module.get.title(),
  10018. content = module.get.content()
  10019. ;
  10020. if(html || content || title) {
  10021. module.debug('Creating pop-up html');
  10022. if(!html) {
  10023. html = settings.templates.popup({
  10024. title : title,
  10025. content : content
  10026. });
  10027. }
  10028. $popup = $('<div/>')
  10029. .addClass(className.popup)
  10030. .data(metadata.activator, $module)
  10031. .html(html)
  10032. ;
  10033. if(settings.inline) {
  10034. module.verbose('Inserting popup element inline', $popup);
  10035. $popup
  10036. .insertAfter($module)
  10037. ;
  10038. }
  10039. else {
  10040. module.verbose('Appending popup element to body', $popup);
  10041. $popup
  10042. .appendTo( $context )
  10043. ;
  10044. }
  10045. module.refresh();
  10046. module.set.variation();
  10047. if(settings.hoverable) {
  10048. module.bind.popup();
  10049. }
  10050. settings.onCreate.call($popup, element);
  10051. }
  10052. else if(settings.popup) {
  10053. $(settings.popup).data(metadata.activator, $module);
  10054. module.verbose('Used popup specified in settings');
  10055. module.refresh();
  10056. if(settings.hoverable) {
  10057. module.bind.popup();
  10058. }
  10059. }
  10060. else if($target.next(selector.popup).length !== 0) {
  10061. module.verbose('Pre-existing popup found');
  10062. settings.inline = true;
  10063. settings.popup = $target.next(selector.popup).data(metadata.activator, $module);
  10064. module.refresh();
  10065. if(settings.hoverable) {
  10066. module.bind.popup();
  10067. }
  10068. }
  10069. else {
  10070. module.debug('No content specified skipping display', element);
  10071. }
  10072. },
  10073. createID: function() {
  10074. id = (Math.random().toString(16) + '000000000').substr(2, 8);
  10075. elementNamespace = '.' + id;
  10076. module.verbose('Creating unique id for element', id);
  10077. },
  10078. // determines popup state
  10079. toggle: function() {
  10080. module.debug('Toggling pop-up');
  10081. if( module.is.hidden() ) {
  10082. module.debug('Popup is hidden, showing pop-up');
  10083. module.unbind.close();
  10084. module.show();
  10085. }
  10086. else {
  10087. module.debug('Popup is visible, hiding pop-up');
  10088. module.hide();
  10089. }
  10090. },
  10091. show: function(callback) {
  10092. callback = callback || function(){};
  10093. module.debug('Showing pop-up', settings.transition);
  10094. if(module.is.hidden() && !( module.is.active() && module.is.dropdown()) ) {
  10095. if( !module.exists() ) {
  10096. module.create();
  10097. }
  10098. if(settings.onShow.call($popup, element) === false) {
  10099. module.debug('onShow callback returned false, cancelling popup animation');
  10100. return;
  10101. }
  10102. else if(!settings.preserve && !settings.popup) {
  10103. module.refresh();
  10104. }
  10105. if( $popup && module.set.position() ) {
  10106. module.save.conditions();
  10107. if(settings.exclusive) {
  10108. module.hideAll();
  10109. }
  10110. module.animate.show(callback);
  10111. }
  10112. }
  10113. },
  10114. hide: function(callback) {
  10115. callback = callback || function(){};
  10116. if( module.is.visible() || module.is.animating() ) {
  10117. if(settings.onHide.call($popup, element) === false) {
  10118. module.debug('onHide callback returned false, cancelling popup animation');
  10119. return;
  10120. }
  10121. module.remove.visible();
  10122. module.unbind.close();
  10123. module.restore.conditions();
  10124. module.animate.hide(callback);
  10125. }
  10126. },
  10127. hideAll: function() {
  10128. $(selector.popup)
  10129. .filter('.' + className.popupVisible)
  10130. .each(function() {
  10131. $(this)
  10132. .data(metadata.activator)
  10133. .popup('hide')
  10134. ;
  10135. })
  10136. ;
  10137. },
  10138. exists: function() {
  10139. if(!$popup) {
  10140. return false;
  10141. }
  10142. if(settings.inline || settings.popup) {
  10143. return ( module.has.popup() );
  10144. }
  10145. else {
  10146. return ( $popup.closest($context).length >= 1 )
  10147. ? true
  10148. : false
  10149. ;
  10150. }
  10151. },
  10152. removePopup: function() {
  10153. if( module.has.popup() && !settings.popup) {
  10154. module.debug('Removing popup', $popup);
  10155. $popup.remove();
  10156. $popup = undefined;
  10157. settings.onRemove.call($popup, element);
  10158. }
  10159. },
  10160. save: {
  10161. conditions: function() {
  10162. module.cache = {
  10163. title: $module.attr('title')
  10164. };
  10165. if (module.cache.title) {
  10166. $module.removeAttr('title');
  10167. }
  10168. module.verbose('Saving original attributes', module.cache.title);
  10169. }
  10170. },
  10171. restore: {
  10172. conditions: function() {
  10173. if(module.cache && module.cache.title) {
  10174. $module.attr('title', module.cache.title);
  10175. module.verbose('Restoring original attributes', module.cache.title);
  10176. }
  10177. return true;
  10178. }
  10179. },
  10180. supports: {
  10181. svg: function() {
  10182. return (typeof SVGGraphicsElement !== 'undefined');
  10183. }
  10184. },
  10185. animate: {
  10186. show: function(callback) {
  10187. callback = $.isFunction(callback) ? callback : function(){};
  10188. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  10189. module.set.visible();
  10190. $popup
  10191. .transition({
  10192. animation : settings.transition + ' in',
  10193. queue : false,
  10194. debug : settings.debug,
  10195. verbose : settings.verbose,
  10196. duration : settings.duration,
  10197. onComplete : function() {
  10198. module.bind.close();
  10199. callback.call($popup, element);
  10200. settings.onVisible.call($popup, element);
  10201. }
  10202. })
  10203. ;
  10204. }
  10205. else {
  10206. module.error(error.noTransition);
  10207. }
  10208. },
  10209. hide: function(callback) {
  10210. callback = $.isFunction(callback) ? callback : function(){};
  10211. module.debug('Hiding pop-up');
  10212. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  10213. $popup
  10214. .transition({
  10215. animation : settings.transition + ' out',
  10216. queue : false,
  10217. duration : settings.duration,
  10218. debug : settings.debug,
  10219. verbose : settings.verbose,
  10220. onComplete : function() {
  10221. module.reset();
  10222. callback.call($popup, element);
  10223. settings.onHidden.call($popup, element);
  10224. }
  10225. })
  10226. ;
  10227. }
  10228. else {
  10229. module.error(error.noTransition);
  10230. }
  10231. }
  10232. },
  10233. change: {
  10234. content: function(html) {
  10235. $popup.html(html);
  10236. }
  10237. },
  10238. get: {
  10239. html: function() {
  10240. $module.removeData(metadata.html);
  10241. return $module.data(metadata.html) || settings.html;
  10242. },
  10243. title: function() {
  10244. $module.removeData(metadata.title);
  10245. return $module.data(metadata.title) || settings.title;
  10246. },
  10247. content: function() {
  10248. $module.removeData(metadata.content);
  10249. return $module.data(metadata.content) || settings.content || $module.attr('title');
  10250. },
  10251. variation: function() {
  10252. $module.removeData(metadata.variation);
  10253. return $module.data(metadata.variation) || settings.variation;
  10254. },
  10255. popup: function() {
  10256. return $popup;
  10257. },
  10258. popupOffset: function() {
  10259. return $popup.offset();
  10260. },
  10261. calculations: function() {
  10262. var
  10263. $popupOffsetParent = module.get.offsetParent($popup),
  10264. targetElement = $target[0],
  10265. isWindow = ($boundary[0] == window),
  10266. targetOffset = $target.offset(),
  10267. parentOffset = settings.inline || (settings.popup && settings.movePopup)
  10268. ? $target.offsetParent().offset()
  10269. : { top: 0, left: 0 },
  10270. screenPosition = (isWindow)
  10271. ? { top: 0, left: 0 }
  10272. : $boundary.offset(),
  10273. calculations = {},
  10274. scroll = (isWindow)
  10275. ? { top: $window.scrollTop(), left: $window.scrollLeft() }
  10276. : { top: 0, left: 0},
  10277. screen
  10278. ;
  10279. calculations = {
  10280. // element which is launching popup
  10281. target : {
  10282. element : $target[0],
  10283. width : $target.outerWidth(),
  10284. height : $target.outerHeight(),
  10285. top : targetOffset.top - parentOffset.top,
  10286. left : targetOffset.left - parentOffset.left,
  10287. margin : {}
  10288. },
  10289. // popup itself
  10290. popup : {
  10291. width : $popup.outerWidth(),
  10292. height : $popup.outerHeight()
  10293. },
  10294. // offset container (or 3d context)
  10295. parent : {
  10296. width : $offsetParent.outerWidth(),
  10297. height : $offsetParent.outerHeight()
  10298. },
  10299. // screen boundaries
  10300. screen : {
  10301. top : screenPosition.top,
  10302. left : screenPosition.left,
  10303. scroll: {
  10304. top : scroll.top,
  10305. left : scroll.left
  10306. },
  10307. width : $boundary.width(),
  10308. height : $boundary.height()
  10309. }
  10310. };
  10311. // if popup offset context is not same as target, then adjust calculations
  10312. if($popupOffsetParent.get(0) !== $offsetParent.get(0)) {
  10313. var
  10314. popupOffset = $popupOffsetParent.offset()
  10315. ;
  10316. calculations.target.top -= popupOffset.top;
  10317. calculations.target.left -= popupOffset.left;
  10318. calculations.parent.width = $popupOffsetParent.outerWidth();
  10319. calculations.parent.height = $popupOffsetParent.outerHeight();
  10320. }
  10321. // add in container calcs if fluid
  10322. if( settings.setFluidWidth && module.is.fluid() ) {
  10323. calculations.container = {
  10324. width: $popup.parent().outerWidth()
  10325. };
  10326. calculations.popup.width = calculations.container.width;
  10327. }
  10328. // add in margins if inline
  10329. calculations.target.margin.top = (settings.inline)
  10330. ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10)
  10331. : 0
  10332. ;
  10333. calculations.target.margin.left = (settings.inline)
  10334. ? module.is.rtl()
  10335. ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10)
  10336. : parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left'), 10)
  10337. : 0
  10338. ;
  10339. // calculate screen boundaries
  10340. screen = calculations.screen;
  10341. calculations.boundary = {
  10342. top : screen.top + screen.scroll.top,
  10343. bottom : screen.top + screen.scroll.top + screen.height,
  10344. left : screen.left + screen.scroll.left,
  10345. right : screen.left + screen.scroll.left + screen.width
  10346. };
  10347. return calculations;
  10348. },
  10349. id: function() {
  10350. return id;
  10351. },
  10352. startEvent: function() {
  10353. if(settings.on == 'hover') {
  10354. return 'mouseenter';
  10355. }
  10356. else if(settings.on == 'focus') {
  10357. return 'focus';
  10358. }
  10359. return false;
  10360. },
  10361. scrollEvent: function() {
  10362. return 'scroll';
  10363. },
  10364. endEvent: function() {
  10365. if(settings.on == 'hover') {
  10366. return 'mouseleave';
  10367. }
  10368. else if(settings.on == 'focus') {
  10369. return 'blur';
  10370. }
  10371. return false;
  10372. },
  10373. distanceFromBoundary: function(offset, calculations) {
  10374. var
  10375. distanceFromBoundary = {},
  10376. popup,
  10377. boundary
  10378. ;
  10379. calculations = calculations || module.get.calculations();
  10380. // shorthand
  10381. popup = calculations.popup;
  10382. boundary = calculations.boundary;
  10383. if(offset) {
  10384. distanceFromBoundary = {
  10385. top : (offset.top - boundary.top),
  10386. left : (offset.left - boundary.left),
  10387. right : (boundary.right - (offset.left + popup.width) ),
  10388. bottom : (boundary.bottom - (offset.top + popup.height) )
  10389. };
  10390. module.verbose('Distance from boundaries determined', offset, distanceFromBoundary);
  10391. }
  10392. return distanceFromBoundary;
  10393. },
  10394. offsetParent: function($element) {
  10395. var
  10396. element = ($element !== undefined)
  10397. ? $element[0]
  10398. : $target[0],
  10399. parentNode = element.parentNode,
  10400. $node = $(parentNode)
  10401. ;
  10402. if(parentNode) {
  10403. var
  10404. is2D = ($node.css('transform') === 'none'),
  10405. isStatic = ($node.css('position') === 'static'),
  10406. isBody = $node.is('body')
  10407. ;
  10408. while(parentNode && !isBody && isStatic && is2D) {
  10409. parentNode = parentNode.parentNode;
  10410. $node = $(parentNode);
  10411. is2D = ($node.css('transform') === 'none');
  10412. isStatic = ($node.css('position') === 'static');
  10413. isBody = $node.is('body');
  10414. }
  10415. }
  10416. return ($node && $node.length > 0)
  10417. ? $node
  10418. : $()
  10419. ;
  10420. },
  10421. positions: function() {
  10422. return {
  10423. 'top left' : false,
  10424. 'top center' : false,
  10425. 'top right' : false,
  10426. 'bottom left' : false,
  10427. 'bottom center' : false,
  10428. 'bottom right' : false,
  10429. 'left center' : false,
  10430. 'right center' : false
  10431. };
  10432. },
  10433. nextPosition: function(position) {
  10434. var
  10435. positions = position.split(' '),
  10436. verticalPosition = positions[0],
  10437. horizontalPosition = positions[1],
  10438. opposite = {
  10439. top : 'bottom',
  10440. bottom : 'top',
  10441. left : 'right',
  10442. right : 'left'
  10443. },
  10444. adjacent = {
  10445. left : 'center',
  10446. center : 'right',
  10447. right : 'left'
  10448. },
  10449. backup = {
  10450. 'top left' : 'top center',
  10451. 'top center' : 'top right',
  10452. 'top right' : 'right center',
  10453. 'right center' : 'bottom right',
  10454. 'bottom right' : 'bottom center',
  10455. 'bottom center' : 'bottom left',
  10456. 'bottom left' : 'left center',
  10457. 'left center' : 'top left'
  10458. },
  10459. adjacentsAvailable = (verticalPosition == 'top' || verticalPosition == 'bottom'),
  10460. oppositeTried = false,
  10461. adjacentTried = false,
  10462. nextPosition = false
  10463. ;
  10464. if(!triedPositions) {
  10465. module.verbose('All available positions available');
  10466. triedPositions = module.get.positions();
  10467. }
  10468. module.debug('Recording last position tried', position);
  10469. triedPositions[position] = true;
  10470. if(settings.prefer === 'opposite') {
  10471. nextPosition = [opposite[verticalPosition], horizontalPosition];
  10472. nextPosition = nextPosition.join(' ');
  10473. oppositeTried = (triedPositions[nextPosition] === true);
  10474. module.debug('Trying opposite strategy', nextPosition);
  10475. }
  10476. if((settings.prefer === 'adjacent') && adjacentsAvailable ) {
  10477. nextPosition = [verticalPosition, adjacent[horizontalPosition]];
  10478. nextPosition = nextPosition.join(' ');
  10479. adjacentTried = (triedPositions[nextPosition] === true);
  10480. module.debug('Trying adjacent strategy', nextPosition);
  10481. }
  10482. if(adjacentTried || oppositeTried) {
  10483. module.debug('Using backup position', nextPosition);
  10484. nextPosition = backup[position];
  10485. }
  10486. return nextPosition;
  10487. }
  10488. },
  10489. set: {
  10490. position: function(position, calculations) {
  10491. // exit conditions
  10492. if($target.length === 0 || $popup.length === 0) {
  10493. module.error(error.notFound);
  10494. return;
  10495. }
  10496. var
  10497. offset,
  10498. distanceAway,
  10499. target,
  10500. popup,
  10501. parent,
  10502. positioning,
  10503. popupOffset,
  10504. distanceFromBoundary
  10505. ;
  10506. calculations = calculations || module.get.calculations();
  10507. position = position || $module.data(metadata.position) || settings.position;
  10508. offset = $module.data(metadata.offset) || settings.offset;
  10509. distanceAway = settings.distanceAway;
  10510. // shorthand
  10511. target = calculations.target;
  10512. popup = calculations.popup;
  10513. parent = calculations.parent;
  10514. if(module.should.centerArrow(calculations)) {
  10515. module.verbose('Adjusting offset to center arrow on small target element');
  10516. if(position == 'top left' || position == 'bottom left') {
  10517. offset += (target.width / 2);
  10518. offset -= settings.arrowPixelsFromEdge;
  10519. }
  10520. if(position == 'top right' || position == 'bottom right') {
  10521. offset -= (target.width / 2);
  10522. offset += settings.arrowPixelsFromEdge;
  10523. }
  10524. }
  10525. if(target.width === 0 && target.height === 0 && !module.is.svg(target.element)) {
  10526. module.debug('Popup target is hidden, no action taken');
  10527. return false;
  10528. }
  10529. if(settings.inline) {
  10530. module.debug('Adding margin to calculation', target.margin);
  10531. if(position == 'left center' || position == 'right center') {
  10532. offset += target.margin.top;
  10533. distanceAway += -target.margin.left;
  10534. }
  10535. else if (position == 'top left' || position == 'top center' || position == 'top right') {
  10536. offset += target.margin.left;
  10537. distanceAway -= target.margin.top;
  10538. }
  10539. else {
  10540. offset += target.margin.left;
  10541. distanceAway += target.margin.top;
  10542. }
  10543. }
  10544. module.debug('Determining popup position from calculations', position, calculations);
  10545. if (module.is.rtl()) {
  10546. position = position.replace(/left|right/g, function (match) {
  10547. return (match == 'left')
  10548. ? 'right'
  10549. : 'left'
  10550. ;
  10551. });
  10552. module.debug('RTL: Popup position updated', position);
  10553. }
  10554. // if last attempt use specified last resort position
  10555. if(searchDepth == settings.maxSearchDepth && typeof settings.lastResort === 'string') {
  10556. position = settings.lastResort;
  10557. }
  10558. switch (position) {
  10559. case 'top left':
  10560. positioning = {
  10561. top : 'auto',
  10562. bottom : parent.height - target.top + distanceAway,
  10563. left : target.left + offset,
  10564. right : 'auto'
  10565. };
  10566. break;
  10567. case 'top center':
  10568. positioning = {
  10569. bottom : parent.height - target.top + distanceAway,
  10570. left : target.left + (target.width / 2) - (popup.width / 2) + offset,
  10571. top : 'auto',
  10572. right : 'auto'
  10573. };
  10574. break;
  10575. case 'top right':
  10576. positioning = {
  10577. bottom : parent.height - target.top + distanceAway,
  10578. right : parent.width - target.left - target.width - offset,
  10579. top : 'auto',
  10580. left : 'auto'
  10581. };
  10582. break;
  10583. case 'left center':
  10584. positioning = {
  10585. top : target.top + (target.height / 2) - (popup.height / 2) + offset,
  10586. right : parent.width - target.left + distanceAway,
  10587. left : 'auto',
  10588. bottom : 'auto'
  10589. };
  10590. break;
  10591. case 'right center':
  10592. positioning = {
  10593. top : target.top + (target.height / 2) - (popup.height / 2) + offset,
  10594. left : target.left + target.width + distanceAway,
  10595. bottom : 'auto',
  10596. right : 'auto'
  10597. };
  10598. break;
  10599. case 'bottom left':
  10600. positioning = {
  10601. top : target.top + target.height + distanceAway,
  10602. left : target.left + offset,
  10603. bottom : 'auto',
  10604. right : 'auto'
  10605. };
  10606. break;
  10607. case 'bottom center':
  10608. positioning = {
  10609. top : target.top + target.height + distanceAway,
  10610. left : target.left + (target.width / 2) - (popup.width / 2) + offset,
  10611. bottom : 'auto',
  10612. right : 'auto'
  10613. };
  10614. break;
  10615. case 'bottom right':
  10616. positioning = {
  10617. top : target.top + target.height + distanceAway,
  10618. right : parent.width - target.left - target.width - offset,
  10619. left : 'auto',
  10620. bottom : 'auto'
  10621. };
  10622. break;
  10623. }
  10624. if(positioning === undefined) {
  10625. module.error(error.invalidPosition, position);
  10626. }
  10627. module.debug('Calculated popup positioning values', positioning);
  10628. // tentatively place on stage
  10629. $popup
  10630. .css(positioning)
  10631. .removeClass(className.position)
  10632. .addClass(position)
  10633. .addClass(className.loading)
  10634. ;
  10635. popupOffset = module.get.popupOffset();
  10636. // see if any boundaries are surpassed with this tentative position
  10637. distanceFromBoundary = module.get.distanceFromBoundary(popupOffset, calculations);
  10638. if(!settings.forcePosition && module.is.offstage(distanceFromBoundary, position) ) {
  10639. module.debug('Position is outside viewport', position);
  10640. if(searchDepth < settings.maxSearchDepth) {
  10641. searchDepth++;
  10642. position = module.get.nextPosition(position);
  10643. module.debug('Trying new position', position);
  10644. return ($popup)
  10645. ? module.set.position(position, calculations)
  10646. : false
  10647. ;
  10648. }
  10649. else {
  10650. if(settings.lastResort) {
  10651. module.debug('No position found, showing with last position');
  10652. }
  10653. else {
  10654. module.debug('Popup could not find a position to display', $popup);
  10655. module.error(error.cannotPlace, element);
  10656. module.remove.attempts();
  10657. module.remove.loading();
  10658. module.reset();
  10659. settings.onUnplaceable.call($popup, element);
  10660. return false;
  10661. }
  10662. }
  10663. }
  10664. module.debug('Position is on stage', position);
  10665. module.remove.attempts();
  10666. module.remove.loading();
  10667. if( settings.setFluidWidth && module.is.fluid() ) {
  10668. module.set.fluidWidth(calculations);
  10669. }
  10670. return true;
  10671. },
  10672. fluidWidth: function(calculations) {
  10673. calculations = calculations || module.get.calculations();
  10674. module.debug('Automatically setting element width to parent width', calculations.parent.width);
  10675. $popup.css('width', calculations.container.width);
  10676. },
  10677. variation: function(variation) {
  10678. variation = variation || module.get.variation();
  10679. if(variation && module.has.popup() ) {
  10680. module.verbose('Adding variation to popup', variation);
  10681. $popup.addClass(variation);
  10682. }
  10683. },
  10684. visible: function() {
  10685. $module.addClass(className.visible);
  10686. }
  10687. },
  10688. remove: {
  10689. loading: function() {
  10690. $popup.removeClass(className.loading);
  10691. },
  10692. variation: function(variation) {
  10693. variation = variation || module.get.variation();
  10694. if(variation) {
  10695. module.verbose('Removing variation', variation);
  10696. $popup.removeClass(variation);
  10697. }
  10698. },
  10699. visible: function() {
  10700. $module.removeClass(className.visible);
  10701. },
  10702. attempts: function() {
  10703. module.verbose('Resetting all searched positions');
  10704. searchDepth = 0;
  10705. triedPositions = false;
  10706. }
  10707. },
  10708. bind: {
  10709. events: function() {
  10710. module.debug('Binding popup events to module');
  10711. if(settings.on == 'click') {
  10712. $module
  10713. .on(clickEvent + eventNamespace, module.toggle)
  10714. ;
  10715. }
  10716. if(settings.on == 'hover') {
  10717. $module
  10718. .on('touchstart' + eventNamespace, module.event.touchstart)
  10719. ;
  10720. }
  10721. if( module.get.startEvent() ) {
  10722. $module
  10723. .on(module.get.startEvent() + eventNamespace, module.event.start)
  10724. .on(module.get.endEvent() + eventNamespace, module.event.end)
  10725. ;
  10726. }
  10727. if(settings.target) {
  10728. module.debug('Target set to element', $target);
  10729. }
  10730. $window.on('resize' + elementNamespace, module.event.resize);
  10731. },
  10732. popup: function() {
  10733. module.verbose('Allowing hover events on popup to prevent closing');
  10734. if( $popup && module.has.popup() ) {
  10735. $popup
  10736. .on('mouseenter' + eventNamespace, module.event.start)
  10737. .on('mouseleave' + eventNamespace, module.event.end)
  10738. ;
  10739. }
  10740. },
  10741. close: function() {
  10742. if(settings.hideOnScroll === true || (settings.hideOnScroll == 'auto' && settings.on != 'click')) {
  10743. module.bind.closeOnScroll();
  10744. }
  10745. if(module.is.closable()) {
  10746. module.bind.clickaway();
  10747. }
  10748. else if(settings.on == 'hover' && openedWithTouch) {
  10749. module.bind.touchClose();
  10750. }
  10751. },
  10752. closeOnScroll: function() {
  10753. module.verbose('Binding scroll close event to document');
  10754. $scrollContext
  10755. .one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully)
  10756. ;
  10757. },
  10758. touchClose: function() {
  10759. module.verbose('Binding popup touchclose event to document');
  10760. $document
  10761. .on('touchstart' + elementNamespace, function(event) {
  10762. module.verbose('Touched away from popup');
  10763. module.event.hideGracefully.call(element, event);
  10764. })
  10765. ;
  10766. },
  10767. clickaway: function() {
  10768. module.verbose('Binding popup close event to document');
  10769. $document
  10770. .on(clickEvent + elementNamespace, function(event) {
  10771. module.verbose('Clicked away from popup');
  10772. module.event.hideGracefully.call(element, event);
  10773. })
  10774. ;
  10775. }
  10776. },
  10777. unbind: {
  10778. events: function() {
  10779. $window
  10780. .off(elementNamespace)
  10781. ;
  10782. $module
  10783. .off(eventNamespace)
  10784. ;
  10785. },
  10786. close: function() {
  10787. $document
  10788. .off(elementNamespace)
  10789. ;
  10790. $scrollContext
  10791. .off(elementNamespace)
  10792. ;
  10793. },
  10794. },
  10795. has: {
  10796. popup: function() {
  10797. return ($popup && $popup.length > 0);
  10798. }
  10799. },
  10800. should: {
  10801. centerArrow: function(calculations) {
  10802. return !module.is.basic() && calculations.target.width <= (settings.arrowPixelsFromEdge * 2);
  10803. },
  10804. },
  10805. is: {
  10806. closable: function() {
  10807. if(settings.closable == 'auto') {
  10808. if(settings.on == 'hover') {
  10809. return false;
  10810. }
  10811. return true;
  10812. }
  10813. return settings.closable;
  10814. },
  10815. offstage: function(distanceFromBoundary, position) {
  10816. var
  10817. offstage = []
  10818. ;
  10819. // return boundaries that have been surpassed
  10820. $.each(distanceFromBoundary, function(direction, distance) {
  10821. if(distance < -settings.jitter) {
  10822. module.debug('Position exceeds allowable distance from edge', direction, distance, position);
  10823. offstage.push(direction);
  10824. }
  10825. });
  10826. if(offstage.length > 0) {
  10827. return true;
  10828. }
  10829. else {
  10830. return false;
  10831. }
  10832. },
  10833. svg: function(element) {
  10834. return module.supports.svg() && (element instanceof SVGGraphicsElement);
  10835. },
  10836. basic: function() {
  10837. return $module.hasClass(className.basic);
  10838. },
  10839. active: function() {
  10840. return $module.hasClass(className.active);
  10841. },
  10842. animating: function() {
  10843. return ($popup !== undefined && $popup.hasClass(className.animating) );
  10844. },
  10845. fluid: function() {
  10846. return ($popup !== undefined && $popup.hasClass(className.fluid));
  10847. },
  10848. visible: function() {
  10849. return ($popup !== undefined && $popup.hasClass(className.popupVisible));
  10850. },
  10851. dropdown: function() {
  10852. return $module.hasClass(className.dropdown);
  10853. },
  10854. hidden: function() {
  10855. return !module.is.visible();
  10856. },
  10857. rtl: function () {
  10858. return $module.attr('dir') === 'rtl' || $module.css('direction') === 'rtl';
  10859. }
  10860. },
  10861. reset: function() {
  10862. module.remove.visible();
  10863. if(settings.preserve) {
  10864. if($.fn.transition !== undefined) {
  10865. $popup
  10866. .transition('remove transition')
  10867. ;
  10868. }
  10869. }
  10870. else {
  10871. module.removePopup();
  10872. }
  10873. },
  10874. setting: function(name, value) {
  10875. if( $.isPlainObject(name) ) {
  10876. $.extend(true, settings, name);
  10877. }
  10878. else if(value !== undefined) {
  10879. settings[name] = value;
  10880. }
  10881. else {
  10882. return settings[name];
  10883. }
  10884. },
  10885. internal: function(name, value) {
  10886. if( $.isPlainObject(name) ) {
  10887. $.extend(true, module, name);
  10888. }
  10889. else if(value !== undefined) {
  10890. module[name] = value;
  10891. }
  10892. else {
  10893. return module[name];
  10894. }
  10895. },
  10896. debug: function() {
  10897. if(!settings.silent && settings.debug) {
  10898. if(settings.performance) {
  10899. module.performance.log(arguments);
  10900. }
  10901. else {
  10902. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  10903. module.debug.apply(console, arguments);
  10904. }
  10905. }
  10906. },
  10907. verbose: function() {
  10908. if(!settings.silent && settings.verbose && settings.debug) {
  10909. if(settings.performance) {
  10910. module.performance.log(arguments);
  10911. }
  10912. else {
  10913. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  10914. module.verbose.apply(console, arguments);
  10915. }
  10916. }
  10917. },
  10918. error: function() {
  10919. if(!settings.silent) {
  10920. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  10921. module.error.apply(console, arguments);
  10922. }
  10923. },
  10924. performance: {
  10925. log: function(message) {
  10926. var
  10927. currentTime,
  10928. executionTime,
  10929. previousTime
  10930. ;
  10931. if(settings.performance) {
  10932. currentTime = new Date().getTime();
  10933. previousTime = time || currentTime;
  10934. executionTime = currentTime - previousTime;
  10935. time = currentTime;
  10936. performance.push({
  10937. 'Name' : message[0],
  10938. 'Arguments' : [].slice.call(message, 1) || '',
  10939. 'Element' : element,
  10940. 'Execution Time' : executionTime
  10941. });
  10942. }
  10943. clearTimeout(module.performance.timer);
  10944. module.performance.timer = setTimeout(module.performance.display, 500);
  10945. },
  10946. display: function() {
  10947. var
  10948. title = settings.name + ':',
  10949. totalTime = 0
  10950. ;
  10951. time = false;
  10952. clearTimeout(module.performance.timer);
  10953. $.each(performance, function(index, data) {
  10954. totalTime += data['Execution Time'];
  10955. });
  10956. title += ' ' + totalTime + 'ms';
  10957. if(moduleSelector) {
  10958. title += ' \'' + moduleSelector + '\'';
  10959. }
  10960. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  10961. console.groupCollapsed(title);
  10962. if(console.table) {
  10963. console.table(performance);
  10964. }
  10965. else {
  10966. $.each(performance, function(index, data) {
  10967. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  10968. });
  10969. }
  10970. console.groupEnd();
  10971. }
  10972. performance = [];
  10973. }
  10974. },
  10975. invoke: function(query, passedArguments, context) {
  10976. var
  10977. object = instance,
  10978. maxDepth,
  10979. found,
  10980. response
  10981. ;
  10982. passedArguments = passedArguments || queryArguments;
  10983. context = element || context;
  10984. if(typeof query == 'string' && object !== undefined) {
  10985. query = query.split(/[\. ]/);
  10986. maxDepth = query.length - 1;
  10987. $.each(query, function(depth, value) {
  10988. var camelCaseValue = (depth != maxDepth)
  10989. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  10990. : query
  10991. ;
  10992. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  10993. object = object[camelCaseValue];
  10994. }
  10995. else if( object[camelCaseValue] !== undefined ) {
  10996. found = object[camelCaseValue];
  10997. return false;
  10998. }
  10999. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  11000. object = object[value];
  11001. }
  11002. else if( object[value] !== undefined ) {
  11003. found = object[value];
  11004. return false;
  11005. }
  11006. else {
  11007. return false;
  11008. }
  11009. });
  11010. }
  11011. if ( $.isFunction( found ) ) {
  11012. response = found.apply(context, passedArguments);
  11013. }
  11014. else if(found !== undefined) {
  11015. response = found;
  11016. }
  11017. if(Array.isArray(returnedValue)) {
  11018. returnedValue.push(response);
  11019. }
  11020. else if(returnedValue !== undefined) {
  11021. returnedValue = [returnedValue, response];
  11022. }
  11023. else if(response !== undefined) {
  11024. returnedValue = response;
  11025. }
  11026. return found;
  11027. }
  11028. };
  11029. if(methodInvoked) {
  11030. if(instance === undefined) {
  11031. module.initialize();
  11032. }
  11033. module.invoke(query);
  11034. }
  11035. else {
  11036. if(instance !== undefined) {
  11037. instance.invoke('destroy');
  11038. }
  11039. module.initialize();
  11040. }
  11041. })
  11042. ;
  11043. return (returnedValue !== undefined)
  11044. ? returnedValue
  11045. : this
  11046. ;
  11047. };
  11048. $.fn.popup.settings = {
  11049. name : 'Popup',
  11050. // module settings
  11051. silent : false,
  11052. debug : false,
  11053. verbose : false,
  11054. performance : true,
  11055. namespace : 'popup',
  11056. // whether it should use dom mutation observers
  11057. observeChanges : true,
  11058. // callback only when element added to dom
  11059. onCreate : function(){},
  11060. // callback before element removed from dom
  11061. onRemove : function(){},
  11062. // callback before show animation
  11063. onShow : function(){},
  11064. // callback after show animation
  11065. onVisible : function(){},
  11066. // callback before hide animation
  11067. onHide : function(){},
  11068. // callback when popup cannot be positioned in visible screen
  11069. onUnplaceable : function(){},
  11070. // callback after hide animation
  11071. onHidden : function(){},
  11072. // when to show popup
  11073. on : 'hover',
  11074. // element to use to determine if popup is out of boundary
  11075. boundary : window,
  11076. // whether to add touchstart events when using hover
  11077. addTouchEvents : true,
  11078. // default position relative to element
  11079. position : 'top left',
  11080. // if given position should be used regardless if popup fits
  11081. forcePosition : false,
  11082. // name of variation to use
  11083. variation : '',
  11084. // whether popup should be moved to context
  11085. movePopup : true,
  11086. // element which popup should be relative to
  11087. target : false,
  11088. // jq selector or element that should be used as popup
  11089. popup : false,
  11090. // popup should remain inline next to activator
  11091. inline : false,
  11092. // popup should be removed from page on hide
  11093. preserve : false,
  11094. // popup should not close when being hovered on
  11095. hoverable : false,
  11096. // explicitly set content
  11097. content : false,
  11098. // explicitly set html
  11099. html : false,
  11100. // explicitly set title
  11101. title : false,
  11102. // whether automatically close on clickaway when on click
  11103. closable : true,
  11104. // automatically hide on scroll
  11105. hideOnScroll : 'auto',
  11106. // hide other popups on show
  11107. exclusive : false,
  11108. // context to attach popups
  11109. context : 'body',
  11110. // context for binding scroll events
  11111. scrollContext : window,
  11112. // position to prefer when calculating new position
  11113. prefer : 'opposite',
  11114. // specify position to appear even if it doesn't fit
  11115. lastResort : false,
  11116. // number of pixels from edge of popup to pointing arrow center (used from centering)
  11117. arrowPixelsFromEdge: 20,
  11118. // delay used to prevent accidental refiring of animations due to user error
  11119. delay : {
  11120. show : 50,
  11121. hide : 70
  11122. },
  11123. // whether fluid variation should assign width explicitly
  11124. setFluidWidth : true,
  11125. // transition settings
  11126. duration : 200,
  11127. transition : 'scale',
  11128. // distance away from activating element in px
  11129. distanceAway : 0,
  11130. // number of pixels an element is allowed to be "offstage" for a position to be chosen (allows for rounding)
  11131. jitter : 2,
  11132. // offset on aligning axis from calculated position
  11133. offset : 0,
  11134. // maximum times to look for a position before failing (9 positions total)
  11135. maxSearchDepth : 15,
  11136. error: {
  11137. invalidPosition : 'The position you specified is not a valid position',
  11138. cannotPlace : 'Popup does not fit within the boundaries of the viewport',
  11139. method : 'The method you called is not defined.',
  11140. noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>',
  11141. notFound : 'The target or popup you specified does not exist on the page'
  11142. },
  11143. metadata: {
  11144. activator : 'activator',
  11145. content : 'content',
  11146. html : 'html',
  11147. offset : 'offset',
  11148. position : 'position',
  11149. title : 'title',
  11150. variation : 'variation'
  11151. },
  11152. className : {
  11153. active : 'active',
  11154. basic : 'basic',
  11155. animating : 'animating',
  11156. dropdown : 'dropdown',
  11157. fluid : 'fluid',
  11158. loading : 'loading',
  11159. popup : 'ui popup',
  11160. position : 'top left center bottom right',
  11161. visible : 'visible',
  11162. popupVisible : 'visible'
  11163. },
  11164. selector : {
  11165. popup : '.ui.popup'
  11166. },
  11167. templates: {
  11168. escape: function(string) {
  11169. var
  11170. badChars = /[<>"'`]/g,
  11171. shouldEscape = /[&<>"'`]/,
  11172. escape = {
  11173. "<": "&lt;",
  11174. ">": "&gt;",
  11175. '"': "&quot;",
  11176. "'": "&#x27;",
  11177. "`": "&#x60;"
  11178. },
  11179. escapedChar = function(chr) {
  11180. return escape[chr];
  11181. }
  11182. ;
  11183. if(shouldEscape.test(string)) {
  11184. string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
  11185. return string.replace(badChars, escapedChar);
  11186. }
  11187. return string;
  11188. },
  11189. popup: function(text) {
  11190. var
  11191. html = '',
  11192. escape = $.fn.popup.settings.templates.escape
  11193. ;
  11194. if(typeof text !== undefined) {
  11195. if(typeof text.title !== undefined && text.title) {
  11196. text.title = escape(text.title);
  11197. html += '<div class="header">' + text.title + '</div>';
  11198. }
  11199. if(typeof text.content !== undefined && text.content) {
  11200. text.content = escape(text.content);
  11201. html += '<div class="content">' + text.content + '</div>';
  11202. }
  11203. }
  11204. return html;
  11205. }
  11206. }
  11207. };
  11208. })( jQuery, window, document );
  11209. /*!
  11210. * # Fomantic-UI - Progress
  11211. * http://github.com/fomantic/Fomantic-UI/
  11212. *
  11213. *
  11214. * Released under the MIT license
  11215. * http://opensource.org/licenses/MIT
  11216. *
  11217. */
  11218. ;(function ($, window, document, undefined) {
  11219. 'use strict';
  11220. $.isFunction = $.isFunction || function(obj) {
  11221. return typeof obj === "function" && typeof obj.nodeType !== "number";
  11222. };
  11223. window = (typeof window != 'undefined' && window.Math == Math)
  11224. ? window
  11225. : (typeof self != 'undefined' && self.Math == Math)
  11226. ? self
  11227. : Function('return this')()
  11228. ;
  11229. $.fn.progress = function(parameters) {
  11230. var
  11231. $allModules = $(this),
  11232. moduleSelector = $allModules.selector || '',
  11233. time = new Date().getTime(),
  11234. performance = [],
  11235. query = arguments[0],
  11236. methodInvoked = (typeof query == 'string'),
  11237. queryArguments = [].slice.call(arguments, 1),
  11238. returnedValue
  11239. ;
  11240. $allModules
  11241. .each(function() {
  11242. var
  11243. settings = ( $.isPlainObject(parameters) )
  11244. ? $.extend(true, {}, $.fn.progress.settings, parameters)
  11245. : $.extend({}, $.fn.progress.settings),
  11246. className = settings.className,
  11247. metadata = settings.metadata,
  11248. namespace = settings.namespace,
  11249. selector = settings.selector,
  11250. error = settings.error,
  11251. eventNamespace = '.' + namespace,
  11252. moduleNamespace = 'module-' + namespace,
  11253. $module = $(this),
  11254. $bars = $(this).find(selector.bar),
  11255. $progresses = $(this).find(selector.progress),
  11256. $label = $(this).find(selector.label),
  11257. element = this,
  11258. instance = $module.data(moduleNamespace),
  11259. animating = false,
  11260. transitionEnd,
  11261. module
  11262. ;
  11263. module = {
  11264. helper: {
  11265. sum: function (nums) {
  11266. return Array.isArray(nums) ? nums.reduce(function (left, right) {
  11267. return left + Number(right);
  11268. }, 0) : 0;
  11269. },
  11270. /**
  11271. * Derive precision for multiple progress with total and values.
  11272. *
  11273. * This helper dervices a precision that is sufficiently large to show minimum value of multiple progress.
  11274. *
  11275. * Example1
  11276. * - total: 1122
  11277. * - values: [325, 111, 74, 612]
  11278. * - min ratio: 74/1122 = 0.0659...
  11279. * - required precision: 100
  11280. *
  11281. * Example2
  11282. * - total: 10541
  11283. * - values: [3235, 1111, 74, 6121]
  11284. * - min ratio: 74/10541 = 0.0070...
  11285. * - required precision: 1000
  11286. *
  11287. * @param min A minimum value within multiple values
  11288. * @param total A total amount of multiple values
  11289. * @returns {number} A precison. Could be 1, 10, 100, ... 1e+10.
  11290. */
  11291. derivePrecision: function(min, total) {
  11292. var precisionPower = 0
  11293. var precision = 1;
  11294. var ratio = min / total;
  11295. while (precisionPower < 10) {
  11296. ratio = ratio * precision;
  11297. if (ratio > 1) {
  11298. break;
  11299. }
  11300. precision = Math.pow(10, precisionPower++);
  11301. }
  11302. return precision;
  11303. },
  11304. forceArray: function (element) {
  11305. return Array.isArray(element)
  11306. ? element
  11307. : !isNaN(element)
  11308. ? [element]
  11309. : typeof element == 'string'
  11310. ? element.split(',')
  11311. : []
  11312. ;
  11313. }
  11314. },
  11315. initialize: function() {
  11316. module.set.duration();
  11317. module.set.transitionEvent();
  11318. module.debug(element);
  11319. module.read.metadata();
  11320. module.read.settings();
  11321. module.instantiate();
  11322. },
  11323. instantiate: function() {
  11324. module.verbose('Storing instance of progress', module);
  11325. instance = module;
  11326. $module
  11327. .data(moduleNamespace, module)
  11328. ;
  11329. },
  11330. destroy: function() {
  11331. module.verbose('Destroying previous progress for', $module);
  11332. clearInterval(instance.interval);
  11333. module.remove.state();
  11334. $module.removeData(moduleNamespace);
  11335. instance = undefined;
  11336. },
  11337. reset: function() {
  11338. module.remove.nextValue();
  11339. module.update.progress(0);
  11340. },
  11341. complete: function(keepState) {
  11342. if(module.percent === undefined || module.percent < 100) {
  11343. module.remove.progressPoll();
  11344. if(keepState !== true){
  11345. module.set.percent(100);
  11346. }
  11347. }
  11348. },
  11349. read: {
  11350. metadata: function() {
  11351. var
  11352. data = {
  11353. percent : module.helper.forceArray($module.data(metadata.percent)),
  11354. total : $module.data(metadata.total),
  11355. value : module.helper.forceArray($module.data(metadata.value))
  11356. }
  11357. ;
  11358. if(data.total !== undefined) {
  11359. module.debug('Total value set from metadata', data.total);
  11360. module.set.total(data.total);
  11361. }
  11362. if(data.value.length > 0) {
  11363. module.debug('Current value set from metadata', data.value);
  11364. module.set.value(data.value);
  11365. module.set.progress(data.value);
  11366. }
  11367. if(data.percent.length > 0) {
  11368. module.debug('Current percent value set from metadata', data.percent);
  11369. module.set.percent(data.percent);
  11370. }
  11371. },
  11372. settings: function() {
  11373. if(settings.total !== false) {
  11374. module.debug('Current total set in settings', settings.total);
  11375. module.set.total(settings.total);
  11376. }
  11377. if(settings.value !== false) {
  11378. module.debug('Current value set in settings', settings.value);
  11379. module.set.value(settings.value);
  11380. module.set.progress(module.value);
  11381. }
  11382. if(settings.percent !== false) {
  11383. module.debug('Current percent set in settings', settings.percent);
  11384. module.set.percent(settings.percent);
  11385. }
  11386. }
  11387. },
  11388. bind: {
  11389. transitionEnd: function(callback) {
  11390. var
  11391. transitionEnd = module.get.transitionEnd()
  11392. ;
  11393. $bars
  11394. .one(transitionEnd + eventNamespace, function(event) {
  11395. clearTimeout(module.failSafeTimer);
  11396. callback.call(this, event);
  11397. })
  11398. ;
  11399. module.failSafeTimer = setTimeout(function() {
  11400. $bars.triggerHandler(transitionEnd);
  11401. }, settings.duration + settings.failSafeDelay);
  11402. module.verbose('Adding fail safe timer', module.timer);
  11403. }
  11404. },
  11405. increment: function(incrementValue) {
  11406. var
  11407. startValue,
  11408. newValue
  11409. ;
  11410. if( module.has.total() ) {
  11411. startValue = module.get.value();
  11412. incrementValue = incrementValue || 1;
  11413. }
  11414. else {
  11415. startValue = module.get.percent();
  11416. incrementValue = incrementValue || module.get.randomValue();
  11417. }
  11418. newValue = startValue + incrementValue;
  11419. module.debug('Incrementing percentage by', startValue, newValue, incrementValue);
  11420. newValue = module.get.normalizedValue(newValue);
  11421. module.set.progress(newValue);
  11422. },
  11423. decrement: function(decrementValue) {
  11424. var
  11425. total = module.get.total(),
  11426. startValue,
  11427. newValue
  11428. ;
  11429. if(total) {
  11430. startValue = module.get.value();
  11431. decrementValue = decrementValue || 1;
  11432. newValue = startValue - decrementValue;
  11433. module.debug('Decrementing value by', decrementValue, startValue);
  11434. }
  11435. else {
  11436. startValue = module.get.percent();
  11437. decrementValue = decrementValue || module.get.randomValue();
  11438. newValue = startValue - decrementValue;
  11439. module.debug('Decrementing percentage by', decrementValue, startValue);
  11440. }
  11441. newValue = module.get.normalizedValue(newValue);
  11442. module.set.progress(newValue);
  11443. },
  11444. has: {
  11445. progressPoll: function() {
  11446. return module.progressPoll;
  11447. },
  11448. total: function() {
  11449. return (module.get.total() !== false);
  11450. }
  11451. },
  11452. get: {
  11453. text: function(templateText, index) {
  11454. var
  11455. index_ = index || 0,
  11456. value = module.get.value(index_),
  11457. total = module.get.total(),
  11458. percent = (animating)
  11459. ? module.get.displayPercent(index_)
  11460. : module.get.percent(index_),
  11461. left = (total !== false)
  11462. ? Math.max(0,total - value)
  11463. : (100 - percent)
  11464. ;
  11465. templateText = templateText || '';
  11466. templateText = templateText
  11467. .replace('{value}', value)
  11468. .replace('{total}', total || 0)
  11469. .replace('{left}', left)
  11470. .replace('{percent}', percent)
  11471. .replace('{bar}', settings.text.bars[index_] || '')
  11472. ;
  11473. module.verbose('Adding variables to progress bar text', templateText);
  11474. return templateText;
  11475. },
  11476. normalizedValue: function(value) {
  11477. if(value < 0) {
  11478. module.debug('Value cannot decrement below 0');
  11479. return 0;
  11480. }
  11481. if(module.has.total()) {
  11482. if(value > module.total) {
  11483. module.debug('Value cannot increment above total', module.total);
  11484. return module.total;
  11485. }
  11486. }
  11487. else if(value > 100 ) {
  11488. module.debug('Value cannot increment above 100 percent');
  11489. return 100;
  11490. }
  11491. return value;
  11492. },
  11493. updateInterval: function() {
  11494. if(settings.updateInterval == 'auto') {
  11495. return settings.duration;
  11496. }
  11497. return settings.updateInterval;
  11498. },
  11499. randomValue: function() {
  11500. module.debug('Generating random increment percentage');
  11501. return Math.floor((Math.random() * settings.random.max) + settings.random.min);
  11502. },
  11503. numericValue: function(value) {
  11504. return (typeof value === 'string')
  11505. ? (value.replace(/[^\d.]/g, '') !== '')
  11506. ? +(value.replace(/[^\d.]/g, ''))
  11507. : false
  11508. : value
  11509. ;
  11510. },
  11511. transitionEnd: function() {
  11512. var
  11513. element = document.createElement('element'),
  11514. transitions = {
  11515. 'transition' :'transitionend',
  11516. 'OTransition' :'oTransitionEnd',
  11517. 'MozTransition' :'transitionend',
  11518. 'WebkitTransition' :'webkitTransitionEnd'
  11519. },
  11520. transition
  11521. ;
  11522. for(transition in transitions){
  11523. if( element.style[transition] !== undefined ){
  11524. return transitions[transition];
  11525. }
  11526. }
  11527. },
  11528. // gets current displayed percentage (if animating values this is the intermediary value)
  11529. displayPercent: function(index) {
  11530. var
  11531. $bar = $($bars[index]),
  11532. barWidth = $bar.width(),
  11533. totalWidth = $module.width(),
  11534. minDisplay = parseInt($bar.css('min-width'), 10),
  11535. displayPercent = (barWidth > minDisplay)
  11536. ? (barWidth / totalWidth * 100)
  11537. : module.percent
  11538. ;
  11539. return (settings.precision > 0)
  11540. ? Math.round(displayPercent * (10 * settings.precision)) / (10 * settings.precision)
  11541. : Math.round(displayPercent)
  11542. ;
  11543. },
  11544. percent: function(index) {
  11545. return module.percent && module.percent[index || 0] || 0;
  11546. },
  11547. value: function(index) {
  11548. return module.nextValue || module.value && module.value[index || 0] || 0;
  11549. },
  11550. total: function() {
  11551. return module.total !== undefined ? module.total : false;
  11552. }
  11553. },
  11554. create: {
  11555. progressPoll: function() {
  11556. module.progressPoll = setTimeout(function() {
  11557. module.update.toNextValue();
  11558. module.remove.progressPoll();
  11559. }, module.get.updateInterval());
  11560. },
  11561. },
  11562. is: {
  11563. complete: function() {
  11564. return module.is.success() || module.is.warning() || module.is.error();
  11565. },
  11566. success: function() {
  11567. return $module.hasClass(className.success);
  11568. },
  11569. warning: function() {
  11570. return $module.hasClass(className.warning);
  11571. },
  11572. error: function() {
  11573. return $module.hasClass(className.error);
  11574. },
  11575. active: function() {
  11576. return $module.hasClass(className.active);
  11577. },
  11578. visible: function() {
  11579. return $module.is(':visible');
  11580. }
  11581. },
  11582. remove: {
  11583. progressPoll: function() {
  11584. module.verbose('Removing progress poll timer');
  11585. if(module.progressPoll) {
  11586. clearTimeout(module.progressPoll);
  11587. delete module.progressPoll;
  11588. }
  11589. },
  11590. nextValue: function() {
  11591. module.verbose('Removing progress value stored for next update');
  11592. delete module.nextValue;
  11593. },
  11594. state: function() {
  11595. module.verbose('Removing stored state');
  11596. delete module.total;
  11597. delete module.percent;
  11598. delete module.value;
  11599. },
  11600. active: function() {
  11601. module.verbose('Removing active state');
  11602. $module.removeClass(className.active);
  11603. },
  11604. success: function() {
  11605. module.verbose('Removing success state');
  11606. $module.removeClass(className.success);
  11607. },
  11608. warning: function() {
  11609. module.verbose('Removing warning state');
  11610. $module.removeClass(className.warning);
  11611. },
  11612. error: function() {
  11613. module.verbose('Removing error state');
  11614. $module.removeClass(className.error);
  11615. }
  11616. },
  11617. set: {
  11618. barWidth: function(values) {
  11619. module.debug("set bar width with ", values);
  11620. values = module.helper.forceArray(values);
  11621. var firstNonZeroIndex = -1;
  11622. var lastNonZeroIndex = -1;
  11623. var valuesSum = module.helper.sum(values);
  11624. var barCounts = $bars.length;
  11625. var isMultiple = barCounts > 1;
  11626. var percents = values.map(function(value, index) {
  11627. var allZero = (index === barCounts - 1 && valuesSum === 0);
  11628. var $bar = $($bars[index]);
  11629. if (value === 0 && isMultiple && !allZero) {
  11630. $bar.css('display', 'none');
  11631. } else {
  11632. if (isMultiple && allZero) {
  11633. $bar.css('background', 'transparent');
  11634. }
  11635. if (firstNonZeroIndex == -1) {
  11636. firstNonZeroIndex = index;
  11637. }
  11638. lastNonZeroIndex = index;
  11639. $bar.css({
  11640. display: 'block',
  11641. width: value + '%'
  11642. });
  11643. }
  11644. return parseFloat(value);
  11645. });
  11646. values.forEach(function(_, index) {
  11647. var $bar = $($bars[index]);
  11648. $bar.css({
  11649. borderTopLeftRadius: index == firstNonZeroIndex ? '' : 0,
  11650. borderBottomLeftRadius: index == firstNonZeroIndex ? '' : 0,
  11651. borderTopRightRadius: index == lastNonZeroIndex ? '' : 0,
  11652. borderBottomRightRadius: index == lastNonZeroIndex ? '' : 0
  11653. });
  11654. });
  11655. $module
  11656. .attr('data-percent', percents)
  11657. ;
  11658. },
  11659. duration: function(duration) {
  11660. duration = duration || settings.duration;
  11661. duration = (typeof duration == 'number')
  11662. ? duration + 'ms'
  11663. : duration
  11664. ;
  11665. module.verbose('Setting progress bar transition duration', duration);
  11666. $bars
  11667. .css({
  11668. 'transition-duration': duration
  11669. })
  11670. ;
  11671. },
  11672. percent: function(percents) {
  11673. percents = module.helper.forceArray(percents).map(function(percent) {
  11674. return (typeof percent == 'string')
  11675. ? +(percent.replace('%', ''))
  11676. : percent
  11677. ;
  11678. });
  11679. var hasTotal = module.has.total();
  11680. var totalPercent = module.helper.sum(percents);
  11681. var isMultipleValues = percents.length > 1 && hasTotal;
  11682. var sumTotal = module.helper.sum(module.helper.forceArray(module.value));
  11683. if (isMultipleValues && sumTotal > module.total) {
  11684. // Sum values instead of pecents to avoid precision issues when summing floats
  11685. module.error(error.sumExceedsTotal, sumTotal, module.total);
  11686. } else if (!isMultipleValues && totalPercent > 100) {
  11687. // Sum before rounding since sum of rounded may have error though sum of actual is fine
  11688. module.error(error.tooHigh, totalPercent);
  11689. } else if (totalPercent < 0) {
  11690. module.error(error.tooLow, totalPercent);
  11691. } else {
  11692. var autoPrecision = settings.precision > 0
  11693. ? settings.precision
  11694. : isMultipleValues
  11695. ? module.helper.derivePrecision(Math.min.apply(null, module.value), module.total)
  11696. : 0;
  11697. // round display percentage
  11698. var roundedPercents = percents.map(function (percent) {
  11699. return (autoPrecision > 0)
  11700. ? Math.round(percent * (10 * autoPrecision)) / (10 * autoPrecision)
  11701. : Math.round(percent)
  11702. ;
  11703. });
  11704. module.percent = roundedPercents;
  11705. if (hasTotal) {
  11706. module.value = roundedPercents.map(function (percent) {
  11707. return (autoPrecision > 0)
  11708. ? Math.round((percent / 100) * module.total * (10 * autoPrecision)) / (10 * autoPrecision)
  11709. : Math.round((percent / 100) * module.total * 10) / 10
  11710. ;
  11711. });
  11712. if (settings.limitValues) {
  11713. module.value = module.value.map(function (value) {
  11714. return Math.max(0, Math.min(100, value));
  11715. });
  11716. }
  11717. }
  11718. module.set.barWidth(percents);
  11719. module.set.labelInterval();
  11720. module.set.labels();
  11721. }
  11722. settings.onChange.call(element, percents, module.value, module.total);
  11723. },
  11724. labelInterval: function() {
  11725. var
  11726. animationCallback = function() {
  11727. module.verbose('Bar finished animating, removing continuous label updates');
  11728. clearInterval(module.interval);
  11729. animating = false;
  11730. module.set.labels();
  11731. }
  11732. ;
  11733. clearInterval(module.interval);
  11734. module.bind.transitionEnd(animationCallback);
  11735. animating = true;
  11736. module.interval = setInterval(function() {
  11737. var
  11738. isInDOM = $.contains(document.documentElement, element)
  11739. ;
  11740. if(!isInDOM) {
  11741. clearInterval(module.interval);
  11742. animating = false;
  11743. }
  11744. module.set.labels();
  11745. }, settings.framerate);
  11746. },
  11747. labels: function() {
  11748. module.verbose('Setting both bar progress and outer label text');
  11749. module.set.barLabel();
  11750. module.set.state();
  11751. },
  11752. label: function(text) {
  11753. text = text || '';
  11754. if(text) {
  11755. text = module.get.text(text);
  11756. module.verbose('Setting label to text', text);
  11757. $label.text(text);
  11758. }
  11759. },
  11760. state: function(percent) {
  11761. percent = (percent !== undefined)
  11762. ? percent
  11763. : module.helper.sum(module.percent)
  11764. ;
  11765. if(percent === 100) {
  11766. if(settings.autoSuccess && $bars.length === 1 && !(module.is.warning() || module.is.error() || module.is.success())) {
  11767. module.set.success();
  11768. module.debug('Automatically triggering success at 100%');
  11769. }
  11770. else {
  11771. module.verbose('Reached 100% removing active state');
  11772. module.remove.active();
  11773. module.remove.progressPoll();
  11774. }
  11775. }
  11776. else if(percent > 0) {
  11777. module.verbose('Adjusting active progress bar label', percent);
  11778. module.set.active();
  11779. }
  11780. else {
  11781. module.remove.active();
  11782. module.set.label(settings.text.active);
  11783. }
  11784. },
  11785. barLabel: function(text) {
  11786. $progresses.map(function(index, element){
  11787. var $progress = $(element);
  11788. if (text !== undefined) {
  11789. $progress.text( module.get.text(text, index) );
  11790. }
  11791. else if (settings.label == 'ratio' && module.has.total()) {
  11792. module.verbose('Adding ratio to bar label');
  11793. $progress.text( module.get.text(settings.text.ratio, index) );
  11794. }
  11795. else if (settings.label == 'percent') {
  11796. module.verbose('Adding percentage to bar label');
  11797. $progress.text( module.get.text(settings.text.percent, index) );
  11798. }
  11799. });
  11800. },
  11801. active: function(text) {
  11802. text = text || settings.text.active;
  11803. module.debug('Setting active state');
  11804. if(settings.showActivity && !module.is.active() ) {
  11805. $module.addClass(className.active);
  11806. }
  11807. module.remove.warning();
  11808. module.remove.error();
  11809. module.remove.success();
  11810. text = settings.onLabelUpdate('active', text, module.value, module.total);
  11811. if(text) {
  11812. module.set.label(text);
  11813. }
  11814. module.bind.transitionEnd(function() {
  11815. settings.onActive.call(element, module.value, module.total);
  11816. });
  11817. },
  11818. success : function(text, keepState) {
  11819. text = text || settings.text.success || settings.text.active;
  11820. module.debug('Setting success state');
  11821. $module.addClass(className.success);
  11822. module.remove.active();
  11823. module.remove.warning();
  11824. module.remove.error();
  11825. module.complete(keepState);
  11826. if(settings.text.success) {
  11827. text = settings.onLabelUpdate('success', text, module.value, module.total);
  11828. module.set.label(text);
  11829. }
  11830. else {
  11831. text = settings.onLabelUpdate('active', text, module.value, module.total);
  11832. module.set.label(text);
  11833. }
  11834. module.bind.transitionEnd(function() {
  11835. settings.onSuccess.call(element, module.total);
  11836. });
  11837. },
  11838. warning : function(text, keepState) {
  11839. text = text || settings.text.warning;
  11840. module.debug('Setting warning state');
  11841. $module.addClass(className.warning);
  11842. module.remove.active();
  11843. module.remove.success();
  11844. module.remove.error();
  11845. module.complete(keepState);
  11846. text = settings.onLabelUpdate('warning', text, module.value, module.total);
  11847. if(text) {
  11848. module.set.label(text);
  11849. }
  11850. module.bind.transitionEnd(function() {
  11851. settings.onWarning.call(element, module.value, module.total);
  11852. });
  11853. },
  11854. error : function(text, keepState) {
  11855. text = text || settings.text.error;
  11856. module.debug('Setting error state');
  11857. $module.addClass(className.error);
  11858. module.remove.active();
  11859. module.remove.success();
  11860. module.remove.warning();
  11861. module.complete(keepState);
  11862. text = settings.onLabelUpdate('error', text, module.value, module.total);
  11863. if(text) {
  11864. module.set.label(text);
  11865. }
  11866. module.bind.transitionEnd(function() {
  11867. settings.onError.call(element, module.value, module.total);
  11868. });
  11869. },
  11870. transitionEvent: function() {
  11871. transitionEnd = module.get.transitionEnd();
  11872. },
  11873. total: function(totalValue) {
  11874. module.total = totalValue;
  11875. },
  11876. value: function(value) {
  11877. module.value = module.helper.forceArray(value);
  11878. },
  11879. progress: function(value) {
  11880. if(!module.has.progressPoll()) {
  11881. module.debug('First update in progress update interval, immediately updating', value);
  11882. module.update.progress(value);
  11883. module.create.progressPoll();
  11884. }
  11885. else {
  11886. module.debug('Updated within interval, setting next update to use new value', value);
  11887. module.set.nextValue(value);
  11888. }
  11889. },
  11890. nextValue: function(value) {
  11891. module.nextValue = value;
  11892. }
  11893. },
  11894. update: {
  11895. toNextValue: function() {
  11896. var
  11897. nextValue = module.nextValue
  11898. ;
  11899. if(nextValue) {
  11900. module.debug('Update interval complete using last updated value', nextValue);
  11901. module.update.progress(nextValue);
  11902. module.remove.nextValue();
  11903. }
  11904. },
  11905. progress: function(values) {
  11906. var hasTotal = module.has.total();
  11907. if (hasTotal) {
  11908. module.set.value(values);
  11909. }
  11910. var percentCompletes = module.helper.forceArray(values).map(function(value) {
  11911. var
  11912. percentComplete
  11913. ;
  11914. value = module.get.numericValue(value);
  11915. if (value === false) {
  11916. module.error(error.nonNumeric, value);
  11917. }
  11918. value = module.get.normalizedValue(value);
  11919. if (hasTotal) {
  11920. percentComplete = module.total > 0 ? (value / module.total) * 100 : 100;
  11921. module.debug('Calculating percent complete from total', percentComplete);
  11922. }
  11923. else {
  11924. percentComplete = value;
  11925. module.debug('Setting value to exact percentage value', percentComplete);
  11926. }
  11927. return percentComplete;
  11928. });
  11929. module.set.percent( percentCompletes );
  11930. }
  11931. },
  11932. setting: function(name, value) {
  11933. module.debug('Changing setting', name, value);
  11934. if( $.isPlainObject(name) ) {
  11935. $.extend(true, settings, name);
  11936. }
  11937. else if(value !== undefined) {
  11938. if($.isPlainObject(settings[name])) {
  11939. $.extend(true, settings[name], value);
  11940. }
  11941. else {
  11942. settings[name] = value;
  11943. }
  11944. }
  11945. else {
  11946. return settings[name];
  11947. }
  11948. },
  11949. internal: function(name, value) {
  11950. if( $.isPlainObject(name) ) {
  11951. $.extend(true, module, name);
  11952. }
  11953. else if(value !== undefined) {
  11954. module[name] = value;
  11955. }
  11956. else {
  11957. return module[name];
  11958. }
  11959. },
  11960. debug: function() {
  11961. if(!settings.silent && settings.debug) {
  11962. if(settings.performance) {
  11963. module.performance.log(arguments);
  11964. }
  11965. else {
  11966. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  11967. module.debug.apply(console, arguments);
  11968. }
  11969. }
  11970. },
  11971. verbose: function() {
  11972. if(!settings.silent && settings.verbose && settings.debug) {
  11973. if(settings.performance) {
  11974. module.performance.log(arguments);
  11975. }
  11976. else {
  11977. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  11978. module.verbose.apply(console, arguments);
  11979. }
  11980. }
  11981. },
  11982. error: function() {
  11983. if(!settings.silent) {
  11984. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  11985. module.error.apply(console, arguments);
  11986. }
  11987. },
  11988. performance: {
  11989. log: function(message) {
  11990. var
  11991. currentTime,
  11992. executionTime,
  11993. previousTime
  11994. ;
  11995. if(settings.performance) {
  11996. currentTime = new Date().getTime();
  11997. previousTime = time || currentTime;
  11998. executionTime = currentTime - previousTime;
  11999. time = currentTime;
  12000. performance.push({
  12001. 'Name' : message[0],
  12002. 'Arguments' : [].slice.call(message, 1) || '',
  12003. 'Element' : element,
  12004. 'Execution Time' : executionTime
  12005. });
  12006. }
  12007. clearTimeout(module.performance.timer);
  12008. module.performance.timer = setTimeout(module.performance.display, 500);
  12009. },
  12010. display: function() {
  12011. var
  12012. title = settings.name + ':',
  12013. totalTime = 0
  12014. ;
  12015. time = false;
  12016. clearTimeout(module.performance.timer);
  12017. $.each(performance, function(index, data) {
  12018. totalTime += data['Execution Time'];
  12019. });
  12020. title += ' ' + totalTime + 'ms';
  12021. if(moduleSelector) {
  12022. title += ' \'' + moduleSelector + '\'';
  12023. }
  12024. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  12025. console.groupCollapsed(title);
  12026. if(console.table) {
  12027. console.table(performance);
  12028. }
  12029. else {
  12030. $.each(performance, function(index, data) {
  12031. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  12032. });
  12033. }
  12034. console.groupEnd();
  12035. }
  12036. performance = [];
  12037. }
  12038. },
  12039. invoke: function(query, passedArguments, context) {
  12040. var
  12041. object = instance,
  12042. maxDepth,
  12043. found,
  12044. response
  12045. ;
  12046. passedArguments = passedArguments || queryArguments;
  12047. context = element || context;
  12048. if(typeof query == 'string' && object !== undefined) {
  12049. query = query.split(/[\. ]/);
  12050. maxDepth = query.length - 1;
  12051. $.each(query, function(depth, value) {
  12052. var camelCaseValue = (depth != maxDepth)
  12053. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  12054. : query
  12055. ;
  12056. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  12057. object = object[camelCaseValue];
  12058. }
  12059. else if( object[camelCaseValue] !== undefined ) {
  12060. found = object[camelCaseValue];
  12061. return false;
  12062. }
  12063. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  12064. object = object[value];
  12065. }
  12066. else if( object[value] !== undefined ) {
  12067. found = object[value];
  12068. return false;
  12069. }
  12070. else {
  12071. module.error(error.method, query);
  12072. return false;
  12073. }
  12074. });
  12075. }
  12076. if ( $.isFunction( found ) ) {
  12077. response = found.apply(context, passedArguments);
  12078. }
  12079. else if(found !== undefined) {
  12080. response = found;
  12081. }
  12082. if(Array.isArray(returnedValue)) {
  12083. returnedValue.push(response);
  12084. }
  12085. else if(returnedValue !== undefined) {
  12086. returnedValue = [returnedValue, response];
  12087. }
  12088. else if(response !== undefined) {
  12089. returnedValue = response;
  12090. }
  12091. return found;
  12092. }
  12093. };
  12094. if(methodInvoked) {
  12095. if(instance === undefined) {
  12096. module.initialize();
  12097. }
  12098. module.invoke(query);
  12099. }
  12100. else {
  12101. if(instance !== undefined) {
  12102. instance.invoke('destroy');
  12103. }
  12104. module.initialize();
  12105. }
  12106. })
  12107. ;
  12108. return (returnedValue !== undefined)
  12109. ? returnedValue
  12110. : this
  12111. ;
  12112. };
  12113. $.fn.progress.settings = {
  12114. name : 'Progress',
  12115. namespace : 'progress',
  12116. silent : false,
  12117. debug : false,
  12118. verbose : false,
  12119. performance : true,
  12120. random : {
  12121. min : 2,
  12122. max : 5
  12123. },
  12124. duration : 300,
  12125. updateInterval : 'auto',
  12126. autoSuccess : true,
  12127. showActivity : true,
  12128. limitValues : true,
  12129. label : 'percent',
  12130. precision : 0,
  12131. framerate : (1000 / 30), /// 30 fps
  12132. percent : false,
  12133. total : false,
  12134. value : false,
  12135. // delay in ms for fail safe animation callback
  12136. failSafeDelay : 100,
  12137. onLabelUpdate : function(state, text, value, total){
  12138. return text;
  12139. },
  12140. onChange : function(percent, value, total){},
  12141. onSuccess : function(total){},
  12142. onActive : function(value, total){},
  12143. onError : function(value, total){},
  12144. onWarning : function(value, total){},
  12145. error : {
  12146. method : 'The method you called is not defined.',
  12147. nonNumeric : 'Progress value is non numeric',
  12148. tooHigh : 'Value specified is above 100%',
  12149. tooLow : 'Value specified is below 0%',
  12150. sumExceedsTotal : 'Sum of multple values exceed total',
  12151. },
  12152. regExp: {
  12153. variable: /\{\$*[A-z0-9]+\}/g
  12154. },
  12155. metadata: {
  12156. percent : 'percent',
  12157. total : 'total',
  12158. value : 'value'
  12159. },
  12160. selector : {
  12161. bar : '> .bar',
  12162. label : '> .label',
  12163. progress : '.bar > .progress'
  12164. },
  12165. text : {
  12166. active : false,
  12167. error : false,
  12168. success : false,
  12169. warning : false,
  12170. percent : '{percent}%',
  12171. ratio : '{value} of {total}',
  12172. bars : ['']
  12173. },
  12174. className : {
  12175. active : 'active',
  12176. error : 'error',
  12177. success : 'success',
  12178. warning : 'warning'
  12179. }
  12180. };
  12181. })( jQuery, window, document );
  12182. /*!
  12183. * # Fomantic-UI - Search
  12184. * http://github.com/fomantic/Fomantic-UI/
  12185. *
  12186. *
  12187. * Released under the MIT license
  12188. * http://opensource.org/licenses/MIT
  12189. *
  12190. */
  12191. ;(function ($, window, document, undefined) {
  12192. 'use strict';
  12193. $.isFunction = $.isFunction || function(obj) {
  12194. return typeof obj === "function" && typeof obj.nodeType !== "number";
  12195. };
  12196. window = (typeof window != 'undefined' && window.Math == Math)
  12197. ? window
  12198. : (typeof self != 'undefined' && self.Math == Math)
  12199. ? self
  12200. : Function('return this')()
  12201. ;
  12202. $.fn.search = function(parameters) {
  12203. var
  12204. $allModules = $(this),
  12205. moduleSelector = $allModules.selector || '',
  12206. time = new Date().getTime(),
  12207. performance = [],
  12208. query = arguments[0],
  12209. methodInvoked = (typeof query == 'string'),
  12210. queryArguments = [].slice.call(arguments, 1),
  12211. returnedValue
  12212. ;
  12213. $(this)
  12214. .each(function() {
  12215. var
  12216. settings = ( $.isPlainObject(parameters) )
  12217. ? $.extend(true, {}, $.fn.search.settings, parameters)
  12218. : $.extend({}, $.fn.search.settings),
  12219. className = settings.className,
  12220. metadata = settings.metadata,
  12221. regExp = settings.regExp,
  12222. fields = settings.fields,
  12223. selector = settings.selector,
  12224. error = settings.error,
  12225. namespace = settings.namespace,
  12226. eventNamespace = '.' + namespace,
  12227. moduleNamespace = namespace + '-module',
  12228. $module = $(this),
  12229. $prompt = $module.find(selector.prompt),
  12230. $searchButton = $module.find(selector.searchButton),
  12231. $results = $module.find(selector.results),
  12232. $result = $module.find(selector.result),
  12233. $category = $module.find(selector.category),
  12234. element = this,
  12235. instance = $module.data(moduleNamespace),
  12236. disabledBubbled = false,
  12237. resultsDismissed = false,
  12238. module
  12239. ;
  12240. module = {
  12241. initialize: function() {
  12242. module.verbose('Initializing module');
  12243. module.get.settings();
  12244. module.determine.searchFields();
  12245. module.bind.events();
  12246. module.set.type();
  12247. module.create.results();
  12248. module.instantiate();
  12249. },
  12250. instantiate: function() {
  12251. module.verbose('Storing instance of module', module);
  12252. instance = module;
  12253. $module
  12254. .data(moduleNamespace, module)
  12255. ;
  12256. },
  12257. destroy: function() {
  12258. module.verbose('Destroying instance');
  12259. $module
  12260. .off(eventNamespace)
  12261. .removeData(moduleNamespace)
  12262. ;
  12263. },
  12264. refresh: function() {
  12265. module.debug('Refreshing selector cache');
  12266. $prompt = $module.find(selector.prompt);
  12267. $searchButton = $module.find(selector.searchButton);
  12268. $category = $module.find(selector.category);
  12269. $results = $module.find(selector.results);
  12270. $result = $module.find(selector.result);
  12271. },
  12272. refreshResults: function() {
  12273. $results = $module.find(selector.results);
  12274. $result = $module.find(selector.result);
  12275. },
  12276. bind: {
  12277. events: function() {
  12278. module.verbose('Binding events to search');
  12279. if(settings.automatic) {
  12280. $module
  12281. .on(module.get.inputEvent() + eventNamespace, selector.prompt, module.event.input)
  12282. ;
  12283. $prompt
  12284. .attr('autocomplete', 'off')
  12285. ;
  12286. }
  12287. $module
  12288. // prompt
  12289. .on('focus' + eventNamespace, selector.prompt, module.event.focus)
  12290. .on('blur' + eventNamespace, selector.prompt, module.event.blur)
  12291. .on('keydown' + eventNamespace, selector.prompt, module.handleKeyboard)
  12292. // search button
  12293. .on('click' + eventNamespace, selector.searchButton, module.query)
  12294. // results
  12295. .on('mousedown' + eventNamespace, selector.results, module.event.result.mousedown)
  12296. .on('mouseup' + eventNamespace, selector.results, module.event.result.mouseup)
  12297. .on('click' + eventNamespace, selector.result, module.event.result.click)
  12298. ;
  12299. }
  12300. },
  12301. determine: {
  12302. searchFields: function() {
  12303. // this makes sure $.extend does not add specified search fields to default fields
  12304. // this is the only setting which should not extend defaults
  12305. if(parameters && parameters.searchFields !== undefined) {
  12306. settings.searchFields = parameters.searchFields;
  12307. }
  12308. }
  12309. },
  12310. event: {
  12311. input: function() {
  12312. if(settings.searchDelay) {
  12313. clearTimeout(module.timer);
  12314. module.timer = setTimeout(function() {
  12315. if(module.is.focused()) {
  12316. module.query();
  12317. }
  12318. }, settings.searchDelay);
  12319. }
  12320. else {
  12321. module.query();
  12322. }
  12323. },
  12324. focus: function() {
  12325. module.set.focus();
  12326. if(settings.searchOnFocus && module.has.minimumCharacters() ) {
  12327. module.query(function() {
  12328. if(module.can.show() ) {
  12329. module.showResults();
  12330. }
  12331. });
  12332. }
  12333. },
  12334. blur: function(event) {
  12335. var
  12336. pageLostFocus = (document.activeElement === this),
  12337. callback = function() {
  12338. module.cancel.query();
  12339. module.remove.focus();
  12340. module.timer = setTimeout(module.hideResults, settings.hideDelay);
  12341. }
  12342. ;
  12343. if(pageLostFocus) {
  12344. return;
  12345. }
  12346. resultsDismissed = false;
  12347. if(module.resultsClicked) {
  12348. module.debug('Determining if user action caused search to close');
  12349. $module
  12350. .one('click.close' + eventNamespace, selector.results, function(event) {
  12351. if(module.is.inMessage(event) || disabledBubbled) {
  12352. $prompt.focus();
  12353. return;
  12354. }
  12355. disabledBubbled = false;
  12356. if( !module.is.animating() && !module.is.hidden()) {
  12357. callback();
  12358. }
  12359. })
  12360. ;
  12361. }
  12362. else {
  12363. module.debug('Input blurred without user action, closing results');
  12364. callback();
  12365. }
  12366. },
  12367. result: {
  12368. mousedown: function() {
  12369. module.resultsClicked = true;
  12370. },
  12371. mouseup: function() {
  12372. module.resultsClicked = false;
  12373. },
  12374. click: function(event) {
  12375. module.debug('Search result selected');
  12376. var
  12377. $result = $(this),
  12378. $title = $result.find(selector.title).eq(0),
  12379. $link = $result.is('a[href]')
  12380. ? $result
  12381. : $result.find('a[href]').eq(0),
  12382. href = $link.attr('href') || false,
  12383. target = $link.attr('target') || false,
  12384. // title is used for result lookup
  12385. value = ($title.length > 0)
  12386. ? $title.text()
  12387. : false,
  12388. results = module.get.results(),
  12389. result = $result.data(metadata.result) || module.get.result(value, results)
  12390. ;
  12391. if(value) {
  12392. module.set.value(value);
  12393. }
  12394. if( $.isFunction(settings.onSelect) ) {
  12395. if(settings.onSelect.call(element, result, results) === false) {
  12396. module.debug('Custom onSelect callback cancelled default select action');
  12397. disabledBubbled = true;
  12398. return;
  12399. }
  12400. }
  12401. module.hideResults();
  12402. if(href) {
  12403. event.preventDefault();
  12404. module.verbose('Opening search link found in result', $link);
  12405. if(target == '_blank' || event.ctrlKey) {
  12406. window.open(href);
  12407. }
  12408. else {
  12409. window.location.href = (href);
  12410. }
  12411. }
  12412. }
  12413. }
  12414. },
  12415. ensureVisible: function ensureVisible($el) {
  12416. var elTop, elBottom, resultsScrollTop, resultsHeight;
  12417. elTop = $el.position().top;
  12418. elBottom = elTop + $el.outerHeight(true);
  12419. resultsScrollTop = $results.scrollTop();
  12420. resultsHeight = $results.height()
  12421. parseInt($results.css('paddingTop'), 0) +
  12422. parseInt($results.css('paddingBottom'), 0);
  12423. if (elTop < 0) {
  12424. $results.scrollTop(resultsScrollTop + elTop);
  12425. }
  12426. else if (resultsHeight < elBottom) {
  12427. $results.scrollTop(resultsScrollTop + (elBottom - resultsHeight));
  12428. }
  12429. },
  12430. handleKeyboard: function(event) {
  12431. var
  12432. // force selector refresh
  12433. $result = $module.find(selector.result),
  12434. $category = $module.find(selector.category),
  12435. $activeResult = $result.filter('.' + className.active),
  12436. currentIndex = $result.index( $activeResult ),
  12437. resultSize = $result.length,
  12438. hasActiveResult = $activeResult.length > 0,
  12439. keyCode = event.which,
  12440. keys = {
  12441. backspace : 8,
  12442. enter : 13,
  12443. escape : 27,
  12444. upArrow : 38,
  12445. downArrow : 40
  12446. },
  12447. newIndex
  12448. ;
  12449. // search shortcuts
  12450. if(keyCode == keys.escape) {
  12451. module.verbose('Escape key pressed, blurring search field');
  12452. module.hideResults();
  12453. resultsDismissed = true;
  12454. }
  12455. if( module.is.visible() ) {
  12456. if(keyCode == keys.enter) {
  12457. module.verbose('Enter key pressed, selecting active result');
  12458. if( $result.filter('.' + className.active).length > 0 ) {
  12459. module.event.result.click.call($result.filter('.' + className.active), event);
  12460. event.preventDefault();
  12461. return false;
  12462. }
  12463. }
  12464. else if(keyCode == keys.upArrow && hasActiveResult) {
  12465. module.verbose('Up key pressed, changing active result');
  12466. newIndex = (currentIndex - 1 < 0)
  12467. ? currentIndex
  12468. : currentIndex - 1
  12469. ;
  12470. $category
  12471. .removeClass(className.active)
  12472. ;
  12473. $result
  12474. .removeClass(className.active)
  12475. .eq(newIndex)
  12476. .addClass(className.active)
  12477. .closest($category)
  12478. .addClass(className.active)
  12479. ;
  12480. module.ensureVisible($result.eq(newIndex));
  12481. event.preventDefault();
  12482. }
  12483. else if(keyCode == keys.downArrow) {
  12484. module.verbose('Down key pressed, changing active result');
  12485. newIndex = (currentIndex + 1 >= resultSize)
  12486. ? currentIndex
  12487. : currentIndex + 1
  12488. ;
  12489. $category
  12490. .removeClass(className.active)
  12491. ;
  12492. $result
  12493. .removeClass(className.active)
  12494. .eq(newIndex)
  12495. .addClass(className.active)
  12496. .closest($category)
  12497. .addClass(className.active)
  12498. ;
  12499. module.ensureVisible($result.eq(newIndex));
  12500. event.preventDefault();
  12501. }
  12502. }
  12503. else {
  12504. // query shortcuts
  12505. if(keyCode == keys.enter) {
  12506. module.verbose('Enter key pressed, executing query');
  12507. module.query();
  12508. module.set.buttonPressed();
  12509. $prompt.one('keyup', module.remove.buttonFocus);
  12510. }
  12511. }
  12512. },
  12513. setup: {
  12514. api: function(searchTerm, callback) {
  12515. var
  12516. apiSettings = {
  12517. debug : settings.debug,
  12518. on : false,
  12519. cache : settings.cache,
  12520. action : 'search',
  12521. urlData : {
  12522. query : searchTerm
  12523. },
  12524. onSuccess : function(response) {
  12525. module.parse.response.call(element, response, searchTerm);
  12526. callback();
  12527. },
  12528. onFailure : function() {
  12529. module.displayMessage(error.serverError);
  12530. callback();
  12531. },
  12532. onAbort : function(response) {
  12533. },
  12534. onError : module.error
  12535. }
  12536. ;
  12537. $.extend(true, apiSettings, settings.apiSettings);
  12538. module.verbose('Setting up API request', apiSettings);
  12539. $module.api(apiSettings);
  12540. }
  12541. },
  12542. can: {
  12543. useAPI: function() {
  12544. return $.fn.api !== undefined;
  12545. },
  12546. show: function() {
  12547. return module.is.focused() && !module.is.visible() && !module.is.empty();
  12548. },
  12549. transition: function() {
  12550. return settings.transition && $.fn.transition !== undefined && $module.transition('is supported');
  12551. }
  12552. },
  12553. is: {
  12554. animating: function() {
  12555. return $results.hasClass(className.animating);
  12556. },
  12557. hidden: function() {
  12558. return $results.hasClass(className.hidden);
  12559. },
  12560. inMessage: function(event) {
  12561. if(!event.target) {
  12562. return;
  12563. }
  12564. var
  12565. $target = $(event.target),
  12566. isInDOM = $.contains(document.documentElement, event.target)
  12567. ;
  12568. return (isInDOM && $target.closest(selector.message).length > 0);
  12569. },
  12570. empty: function() {
  12571. return ($results.html() === '');
  12572. },
  12573. visible: function() {
  12574. return ($results.filter(':visible').length > 0);
  12575. },
  12576. focused: function() {
  12577. return ($prompt.filter(':focus').length > 0);
  12578. }
  12579. },
  12580. get: {
  12581. settings: function() {
  12582. if($.isPlainObject(parameters) && parameters.searchFullText) {
  12583. settings.fullTextSearch = parameters.searchFullText;
  12584. module.error(settings.error.oldSearchSyntax, element);
  12585. }
  12586. if (settings.ignoreDiacritics && !String.prototype.normalize) {
  12587. settings.ignoreDiacritics = false;
  12588. module.error(error.noNormalize, element);
  12589. }
  12590. },
  12591. inputEvent: function() {
  12592. var
  12593. prompt = $prompt[0],
  12594. inputEvent = (prompt !== undefined && prompt.oninput !== undefined)
  12595. ? 'input'
  12596. : (prompt !== undefined && prompt.onpropertychange !== undefined)
  12597. ? 'propertychange'
  12598. : 'keyup'
  12599. ;
  12600. return inputEvent;
  12601. },
  12602. value: function() {
  12603. return $prompt.val();
  12604. },
  12605. results: function() {
  12606. var
  12607. results = $module.data(metadata.results)
  12608. ;
  12609. return results;
  12610. },
  12611. result: function(value, results) {
  12612. var
  12613. result = false
  12614. ;
  12615. value = (value !== undefined)
  12616. ? value
  12617. : module.get.value()
  12618. ;
  12619. results = (results !== undefined)
  12620. ? results
  12621. : module.get.results()
  12622. ;
  12623. if(settings.type === 'category') {
  12624. module.debug('Finding result that matches', value);
  12625. $.each(results, function(index, category) {
  12626. if(Array.isArray(category.results)) {
  12627. result = module.search.object(value, category.results)[0];
  12628. // don't continue searching if a result is found
  12629. if(result) {
  12630. return false;
  12631. }
  12632. }
  12633. });
  12634. }
  12635. else {
  12636. module.debug('Finding result in results object', value);
  12637. result = module.search.object(value, results)[0];
  12638. }
  12639. return result || false;
  12640. },
  12641. },
  12642. select: {
  12643. firstResult: function() {
  12644. module.verbose('Selecting first result');
  12645. $result.first().addClass(className.active);
  12646. }
  12647. },
  12648. set: {
  12649. focus: function() {
  12650. $module.addClass(className.focus);
  12651. },
  12652. loading: function() {
  12653. $module.addClass(className.loading);
  12654. },
  12655. value: function(value) {
  12656. module.verbose('Setting search input value', value);
  12657. $prompt
  12658. .val(value)
  12659. ;
  12660. },
  12661. type: function(type) {
  12662. type = type || settings.type;
  12663. if(settings.type == 'category') {
  12664. $module.addClass(settings.type);
  12665. }
  12666. },
  12667. buttonPressed: function() {
  12668. $searchButton.addClass(className.pressed);
  12669. }
  12670. },
  12671. remove: {
  12672. loading: function() {
  12673. $module.removeClass(className.loading);
  12674. },
  12675. focus: function() {
  12676. $module.removeClass(className.focus);
  12677. },
  12678. buttonPressed: function() {
  12679. $searchButton.removeClass(className.pressed);
  12680. },
  12681. diacritics: function(text) {
  12682. return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : text;
  12683. }
  12684. },
  12685. query: function(callback) {
  12686. callback = $.isFunction(callback)
  12687. ? callback
  12688. : function(){}
  12689. ;
  12690. var
  12691. searchTerm = module.get.value(),
  12692. cache = module.read.cache(searchTerm)
  12693. ;
  12694. callback = callback || function() {};
  12695. if( module.has.minimumCharacters() ) {
  12696. if(cache) {
  12697. module.debug('Reading result from cache', searchTerm);
  12698. module.save.results(cache.results);
  12699. module.addResults(cache.html);
  12700. module.inject.id(cache.results);
  12701. callback();
  12702. }
  12703. else {
  12704. module.debug('Querying for', searchTerm);
  12705. if($.isPlainObject(settings.source) || Array.isArray(settings.source)) {
  12706. module.search.local(searchTerm);
  12707. callback();
  12708. }
  12709. else if( module.can.useAPI() ) {
  12710. module.search.remote(searchTerm, callback);
  12711. }
  12712. else {
  12713. module.error(error.source);
  12714. callback();
  12715. }
  12716. }
  12717. settings.onSearchQuery.call(element, searchTerm);
  12718. }
  12719. else {
  12720. module.hideResults();
  12721. }
  12722. },
  12723. search: {
  12724. local: function(searchTerm) {
  12725. var
  12726. results = module.search.object(searchTerm, settings.source),
  12727. searchHTML
  12728. ;
  12729. module.set.loading();
  12730. module.save.results(results);
  12731. module.debug('Returned full local search results', results);
  12732. if(settings.maxResults > 0) {
  12733. module.debug('Using specified max results', results);
  12734. results = results.slice(0, settings.maxResults);
  12735. }
  12736. if(settings.type == 'category') {
  12737. results = module.create.categoryResults(results);
  12738. }
  12739. searchHTML = module.generateResults({
  12740. results: results
  12741. });
  12742. module.remove.loading();
  12743. module.addResults(searchHTML);
  12744. module.inject.id(results);
  12745. module.write.cache(searchTerm, {
  12746. html : searchHTML,
  12747. results : results
  12748. });
  12749. },
  12750. remote: function(searchTerm, callback) {
  12751. callback = $.isFunction(callback)
  12752. ? callback
  12753. : function(){}
  12754. ;
  12755. if($module.api('is loading')) {
  12756. $module.api('abort');
  12757. }
  12758. module.setup.api(searchTerm, callback);
  12759. $module
  12760. .api('query')
  12761. ;
  12762. },
  12763. object: function(searchTerm, source, searchFields) {
  12764. searchTerm = module.remove.diacritics(String(searchTerm));
  12765. var
  12766. results = [],
  12767. exactResults = [],
  12768. fuzzyResults = [],
  12769. searchExp = searchTerm.replace(regExp.escape, '\\$&'),
  12770. matchRegExp = new RegExp(regExp.beginsWith + searchExp, 'i'),
  12771. // avoid duplicates when pushing results
  12772. addResult = function(array, result) {
  12773. var
  12774. notResult = ($.inArray(result, results) == -1),
  12775. notFuzzyResult = ($.inArray(result, fuzzyResults) == -1),
  12776. notExactResults = ($.inArray(result, exactResults) == -1)
  12777. ;
  12778. if(notResult && notFuzzyResult && notExactResults) {
  12779. array.push(result);
  12780. }
  12781. }
  12782. ;
  12783. source = source || settings.source;
  12784. searchFields = (searchFields !== undefined)
  12785. ? searchFields
  12786. : settings.searchFields
  12787. ;
  12788. // search fields should be array to loop correctly
  12789. if(!Array.isArray(searchFields)) {
  12790. searchFields = [searchFields];
  12791. }
  12792. // exit conditions if no source
  12793. if(source === undefined || source === false) {
  12794. module.error(error.source);
  12795. return [];
  12796. }
  12797. // iterate through search fields looking for matches
  12798. $.each(searchFields, function(index, field) {
  12799. $.each(source, function(label, content) {
  12800. var
  12801. fieldExists = (typeof content[field] == 'string') || (typeof content[field] == 'number')
  12802. ;
  12803. if(fieldExists) {
  12804. var text;
  12805. if (typeof content[field] === 'string'){
  12806. text = module.remove.diacritics(content[field]);
  12807. } else {
  12808. text = content[field].toString();
  12809. }
  12810. if( text.search(matchRegExp) !== -1) {
  12811. // content starts with value (first in results)
  12812. addResult(results, content);
  12813. }
  12814. else if(settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text) ) {
  12815. // content fuzzy matches (last in results)
  12816. addResult(exactResults, content);
  12817. }
  12818. else if(settings.fullTextSearch == true && module.fuzzySearch(searchTerm, text) ) {
  12819. // content fuzzy matches (last in results)
  12820. addResult(fuzzyResults, content);
  12821. }
  12822. }
  12823. });
  12824. });
  12825. $.merge(exactResults, fuzzyResults);
  12826. $.merge(results, exactResults);
  12827. return results;
  12828. }
  12829. },
  12830. exactSearch: function (query, term) {
  12831. query = query.toLowerCase();
  12832. term = term.toLowerCase();
  12833. return term.indexOf(query) > -1;
  12834. },
  12835. fuzzySearch: function(query, term) {
  12836. var
  12837. termLength = term.length,
  12838. queryLength = query.length
  12839. ;
  12840. if(typeof query !== 'string') {
  12841. return false;
  12842. }
  12843. query = query.toLowerCase();
  12844. term = term.toLowerCase();
  12845. if(queryLength > termLength) {
  12846. return false;
  12847. }
  12848. if(queryLength === termLength) {
  12849. return (query === term);
  12850. }
  12851. search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
  12852. var
  12853. queryCharacter = query.charCodeAt(characterIndex)
  12854. ;
  12855. while(nextCharacterIndex < termLength) {
  12856. if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
  12857. continue search;
  12858. }
  12859. }
  12860. return false;
  12861. }
  12862. return true;
  12863. },
  12864. parse: {
  12865. response: function(response, searchTerm) {
  12866. if(Array.isArray(response)){
  12867. var o={};
  12868. o[fields.results]=response;
  12869. response = o;
  12870. }
  12871. var
  12872. searchHTML = module.generateResults(response)
  12873. ;
  12874. module.verbose('Parsing server response', response);
  12875. if(response !== undefined) {
  12876. if(searchTerm !== undefined && response[fields.results] !== undefined) {
  12877. module.addResults(searchHTML);
  12878. module.inject.id(response[fields.results]);
  12879. module.write.cache(searchTerm, {
  12880. html : searchHTML,
  12881. results : response[fields.results]
  12882. });
  12883. module.save.results(response[fields.results]);
  12884. }
  12885. }
  12886. }
  12887. },
  12888. cancel: {
  12889. query: function() {
  12890. if( module.can.useAPI() ) {
  12891. $module.api('abort');
  12892. }
  12893. }
  12894. },
  12895. has: {
  12896. minimumCharacters: function() {
  12897. var
  12898. searchTerm = module.get.value(),
  12899. numCharacters = searchTerm.length
  12900. ;
  12901. return (numCharacters >= settings.minCharacters);
  12902. },
  12903. results: function() {
  12904. if($results.length === 0) {
  12905. return false;
  12906. }
  12907. var
  12908. html = $results.html()
  12909. ;
  12910. return html != '';
  12911. }
  12912. },
  12913. clear: {
  12914. cache: function(value) {
  12915. var
  12916. cache = $module.data(metadata.cache)
  12917. ;
  12918. if(!value) {
  12919. module.debug('Clearing cache', value);
  12920. $module.removeData(metadata.cache);
  12921. }
  12922. else if(value && cache && cache[value]) {
  12923. module.debug('Removing value from cache', value);
  12924. delete cache[value];
  12925. $module.data(metadata.cache, cache);
  12926. }
  12927. }
  12928. },
  12929. read: {
  12930. cache: function(name) {
  12931. var
  12932. cache = $module.data(metadata.cache)
  12933. ;
  12934. if(settings.cache) {
  12935. module.verbose('Checking cache for generated html for query', name);
  12936. return (typeof cache == 'object') && (cache[name] !== undefined)
  12937. ? cache[name]
  12938. : false
  12939. ;
  12940. }
  12941. return false;
  12942. }
  12943. },
  12944. create: {
  12945. categoryResults: function(results) {
  12946. var
  12947. categoryResults = {}
  12948. ;
  12949. $.each(results, function(index, result) {
  12950. if(!result.category) {
  12951. return;
  12952. }
  12953. if(categoryResults[result.category] === undefined) {
  12954. module.verbose('Creating new category of results', result.category);
  12955. categoryResults[result.category] = {
  12956. name : result.category,
  12957. results : [result]
  12958. };
  12959. }
  12960. else {
  12961. categoryResults[result.category].results.push(result);
  12962. }
  12963. });
  12964. return categoryResults;
  12965. },
  12966. id: function(resultIndex, categoryIndex) {
  12967. var
  12968. resultID = (resultIndex + 1), // not zero indexed
  12969. letterID,
  12970. id
  12971. ;
  12972. if(categoryIndex !== undefined) {
  12973. // start char code for "A"
  12974. letterID = String.fromCharCode(97 + categoryIndex);
  12975. id = letterID + resultID;
  12976. module.verbose('Creating category result id', id);
  12977. }
  12978. else {
  12979. id = resultID;
  12980. module.verbose('Creating result id', id);
  12981. }
  12982. return id;
  12983. },
  12984. results: function() {
  12985. if($results.length === 0) {
  12986. $results = $('<div />')
  12987. .addClass(className.results)
  12988. .appendTo($module)
  12989. ;
  12990. }
  12991. }
  12992. },
  12993. inject: {
  12994. result: function(result, resultIndex, categoryIndex) {
  12995. module.verbose('Injecting result into results');
  12996. var
  12997. $selectedResult = (categoryIndex !== undefined)
  12998. ? $results
  12999. .children().eq(categoryIndex)
  13000. .children(selector.results)
  13001. .first()
  13002. .children(selector.result)
  13003. .eq(resultIndex)
  13004. : $results
  13005. .children(selector.result).eq(resultIndex)
  13006. ;
  13007. module.verbose('Injecting results metadata', $selectedResult);
  13008. $selectedResult
  13009. .data(metadata.result, result)
  13010. ;
  13011. },
  13012. id: function(results) {
  13013. module.debug('Injecting unique ids into results');
  13014. var
  13015. // since results may be object, we must use counters
  13016. categoryIndex = 0,
  13017. resultIndex = 0
  13018. ;
  13019. if(settings.type === 'category') {
  13020. // iterate through each category result
  13021. $.each(results, function(index, category) {
  13022. if(category.results.length > 0){
  13023. resultIndex = 0;
  13024. $.each(category.results, function(index, result) {
  13025. if(result.id === undefined) {
  13026. result.id = module.create.id(resultIndex, categoryIndex);
  13027. }
  13028. module.inject.result(result, resultIndex, categoryIndex);
  13029. resultIndex++;
  13030. });
  13031. categoryIndex++;
  13032. }
  13033. });
  13034. }
  13035. else {
  13036. // top level
  13037. $.each(results, function(index, result) {
  13038. if(result.id === undefined) {
  13039. result.id = module.create.id(resultIndex);
  13040. }
  13041. module.inject.result(result, resultIndex);
  13042. resultIndex++;
  13043. });
  13044. }
  13045. return results;
  13046. }
  13047. },
  13048. save: {
  13049. results: function(results) {
  13050. module.verbose('Saving current search results to metadata', results);
  13051. $module.data(metadata.results, results);
  13052. }
  13053. },
  13054. write: {
  13055. cache: function(name, value) {
  13056. var
  13057. cache = ($module.data(metadata.cache) !== undefined)
  13058. ? $module.data(metadata.cache)
  13059. : {}
  13060. ;
  13061. if(settings.cache) {
  13062. module.verbose('Writing generated html to cache', name, value);
  13063. cache[name] = value;
  13064. $module
  13065. .data(metadata.cache, cache)
  13066. ;
  13067. }
  13068. }
  13069. },
  13070. addResults: function(html) {
  13071. if( $.isFunction(settings.onResultsAdd) ) {
  13072. if( settings.onResultsAdd.call($results, html) === false ) {
  13073. module.debug('onResultsAdd callback cancelled default action');
  13074. return false;
  13075. }
  13076. }
  13077. if(html) {
  13078. $results
  13079. .html(html)
  13080. ;
  13081. module.refreshResults();
  13082. if(settings.selectFirstResult) {
  13083. module.select.firstResult();
  13084. }
  13085. module.showResults();
  13086. }
  13087. else {
  13088. module.hideResults(function() {
  13089. $results.empty();
  13090. });
  13091. }
  13092. },
  13093. showResults: function(callback) {
  13094. callback = $.isFunction(callback)
  13095. ? callback
  13096. : function(){}
  13097. ;
  13098. if(resultsDismissed) {
  13099. return;
  13100. }
  13101. if(!module.is.visible() && module.has.results()) {
  13102. if( module.can.transition() ) {
  13103. module.debug('Showing results with css animations');
  13104. $results
  13105. .transition({
  13106. animation : settings.transition + ' in',
  13107. debug : settings.debug,
  13108. verbose : settings.verbose,
  13109. duration : settings.duration,
  13110. onShow : function() {
  13111. var $firstResult = $module.find(selector.result).eq(0);
  13112. if($firstResult.length > 0) {
  13113. module.ensureVisible($firstResult);
  13114. }
  13115. },
  13116. onComplete : function() {
  13117. callback();
  13118. },
  13119. queue : true
  13120. })
  13121. ;
  13122. }
  13123. else {
  13124. module.debug('Showing results with javascript');
  13125. $results
  13126. .stop()
  13127. .fadeIn(settings.duration, settings.easing)
  13128. ;
  13129. }
  13130. settings.onResultsOpen.call($results);
  13131. }
  13132. },
  13133. hideResults: function(callback) {
  13134. callback = $.isFunction(callback)
  13135. ? callback
  13136. : function(){}
  13137. ;
  13138. if( module.is.visible() ) {
  13139. if( module.can.transition() ) {
  13140. module.debug('Hiding results with css animations');
  13141. $results
  13142. .transition({
  13143. animation : settings.transition + ' out',
  13144. debug : settings.debug,
  13145. verbose : settings.verbose,
  13146. duration : settings.duration,
  13147. onComplete : function() {
  13148. callback();
  13149. },
  13150. queue : true
  13151. })
  13152. ;
  13153. }
  13154. else {
  13155. module.debug('Hiding results with javascript');
  13156. $results
  13157. .stop()
  13158. .fadeOut(settings.duration, settings.easing)
  13159. ;
  13160. }
  13161. settings.onResultsClose.call($results);
  13162. }
  13163. },
  13164. generateResults: function(response) {
  13165. module.debug('Generating html from response', response);
  13166. var
  13167. template = settings.templates[settings.type],
  13168. isProperObject = ($.isPlainObject(response[fields.results]) && !$.isEmptyObject(response[fields.results])),
  13169. isProperArray = (Array.isArray(response[fields.results]) && response[fields.results].length > 0),
  13170. html = ''
  13171. ;
  13172. if(isProperObject || isProperArray ) {
  13173. if(settings.maxResults > 0) {
  13174. if(isProperObject) {
  13175. if(settings.type == 'standard') {
  13176. module.error(error.maxResults);
  13177. }
  13178. }
  13179. else {
  13180. response[fields.results] = response[fields.results].slice(0, settings.maxResults);
  13181. }
  13182. }
  13183. if($.isFunction(template)) {
  13184. html = template(response, fields, settings.preserveHTML);
  13185. }
  13186. else {
  13187. module.error(error.noTemplate, false);
  13188. }
  13189. }
  13190. else if(settings.showNoResults) {
  13191. html = module.displayMessage(error.noResults, 'empty', error.noResultsHeader);
  13192. }
  13193. settings.onResults.call(element, response);
  13194. return html;
  13195. },
  13196. displayMessage: function(text, type, header) {
  13197. type = type || 'standard';
  13198. module.debug('Displaying message', text, type, header);
  13199. module.addResults( settings.templates.message(text, type, header) );
  13200. return settings.templates.message(text, type, header);
  13201. },
  13202. setting: function(name, value) {
  13203. if( $.isPlainObject(name) ) {
  13204. $.extend(true, settings, name);
  13205. }
  13206. else if(value !== undefined) {
  13207. settings[name] = value;
  13208. }
  13209. else {
  13210. return settings[name];
  13211. }
  13212. },
  13213. internal: function(name, value) {
  13214. if( $.isPlainObject(name) ) {
  13215. $.extend(true, module, name);
  13216. }
  13217. else if(value !== undefined) {
  13218. module[name] = value;
  13219. }
  13220. else {
  13221. return module[name];
  13222. }
  13223. },
  13224. debug: function() {
  13225. if(!settings.silent && settings.debug) {
  13226. if(settings.performance) {
  13227. module.performance.log(arguments);
  13228. }
  13229. else {
  13230. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  13231. module.debug.apply(console, arguments);
  13232. }
  13233. }
  13234. },
  13235. verbose: function() {
  13236. if(!settings.silent && settings.verbose && settings.debug) {
  13237. if(settings.performance) {
  13238. module.performance.log(arguments);
  13239. }
  13240. else {
  13241. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  13242. module.verbose.apply(console, arguments);
  13243. }
  13244. }
  13245. },
  13246. error: function() {
  13247. if(!settings.silent) {
  13248. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  13249. module.error.apply(console, arguments);
  13250. }
  13251. },
  13252. performance: {
  13253. log: function(message) {
  13254. var
  13255. currentTime,
  13256. executionTime,
  13257. previousTime
  13258. ;
  13259. if(settings.performance) {
  13260. currentTime = new Date().getTime();
  13261. previousTime = time || currentTime;
  13262. executionTime = currentTime - previousTime;
  13263. time = currentTime;
  13264. performance.push({
  13265. 'Name' : message[0],
  13266. 'Arguments' : [].slice.call(message, 1) || '',
  13267. 'Element' : element,
  13268. 'Execution Time' : executionTime
  13269. });
  13270. }
  13271. clearTimeout(module.performance.timer);
  13272. module.performance.timer = setTimeout(module.performance.display, 500);
  13273. },
  13274. display: function() {
  13275. var
  13276. title = settings.name + ':',
  13277. totalTime = 0
  13278. ;
  13279. time = false;
  13280. clearTimeout(module.performance.timer);
  13281. $.each(performance, function(index, data) {
  13282. totalTime += data['Execution Time'];
  13283. });
  13284. title += ' ' + totalTime + 'ms';
  13285. if(moduleSelector) {
  13286. title += ' \'' + moduleSelector + '\'';
  13287. }
  13288. if($allModules.length > 1) {
  13289. title += ' ' + '(' + $allModules.length + ')';
  13290. }
  13291. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  13292. console.groupCollapsed(title);
  13293. if(console.table) {
  13294. console.table(performance);
  13295. }
  13296. else {
  13297. $.each(performance, function(index, data) {
  13298. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  13299. });
  13300. }
  13301. console.groupEnd();
  13302. }
  13303. performance = [];
  13304. }
  13305. },
  13306. invoke: function(query, passedArguments, context) {
  13307. var
  13308. object = instance,
  13309. maxDepth,
  13310. found,
  13311. response
  13312. ;
  13313. passedArguments = passedArguments || queryArguments;
  13314. context = element || context;
  13315. if(typeof query == 'string' && object !== undefined) {
  13316. query = query.split(/[\. ]/);
  13317. maxDepth = query.length - 1;
  13318. $.each(query, function(depth, value) {
  13319. var camelCaseValue = (depth != maxDepth)
  13320. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  13321. : query
  13322. ;
  13323. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  13324. object = object[camelCaseValue];
  13325. }
  13326. else if( object[camelCaseValue] !== undefined ) {
  13327. found = object[camelCaseValue];
  13328. return false;
  13329. }
  13330. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  13331. object = object[value];
  13332. }
  13333. else if( object[value] !== undefined ) {
  13334. found = object[value];
  13335. return false;
  13336. }
  13337. else {
  13338. return false;
  13339. }
  13340. });
  13341. }
  13342. if( $.isFunction( found ) ) {
  13343. response = found.apply(context, passedArguments);
  13344. }
  13345. else if(found !== undefined) {
  13346. response = found;
  13347. }
  13348. if(Array.isArray(returnedValue)) {
  13349. returnedValue.push(response);
  13350. }
  13351. else if(returnedValue !== undefined) {
  13352. returnedValue = [returnedValue, response];
  13353. }
  13354. else if(response !== undefined) {
  13355. returnedValue = response;
  13356. }
  13357. return found;
  13358. }
  13359. };
  13360. if(methodInvoked) {
  13361. if(instance === undefined) {
  13362. module.initialize();
  13363. }
  13364. module.invoke(query);
  13365. }
  13366. else {
  13367. if(instance !== undefined) {
  13368. instance.invoke('destroy');
  13369. }
  13370. module.initialize();
  13371. }
  13372. })
  13373. ;
  13374. return (returnedValue !== undefined)
  13375. ? returnedValue
  13376. : this
  13377. ;
  13378. };
  13379. $.fn.search.settings = {
  13380. name : 'Search',
  13381. namespace : 'search',
  13382. silent : false,
  13383. debug : false,
  13384. verbose : false,
  13385. performance : true,
  13386. // template to use (specified in settings.templates)
  13387. type : 'standard',
  13388. // minimum characters required to search
  13389. minCharacters : 1,
  13390. // whether to select first result after searching automatically
  13391. selectFirstResult : false,
  13392. // API config
  13393. apiSettings : false,
  13394. // object to search
  13395. source : false,
  13396. // Whether search should query current term on focus
  13397. searchOnFocus : true,
  13398. // fields to search
  13399. searchFields : [
  13400. 'id',
  13401. 'title',
  13402. 'description'
  13403. ],
  13404. // field to display in standard results template
  13405. displayField : '',
  13406. // search anywhere in value (set to 'exact' to require exact matches
  13407. fullTextSearch : 'exact',
  13408. // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
  13409. ignoreDiacritics : false,
  13410. // whether to add events to prompt automatically
  13411. automatic : true,
  13412. // delay before hiding menu after blur
  13413. hideDelay : 0,
  13414. // delay before searching
  13415. searchDelay : 200,
  13416. // maximum results returned from search
  13417. maxResults : 7,
  13418. // whether to store lookups in local cache
  13419. cache : true,
  13420. // whether no results errors should be shown
  13421. showNoResults : true,
  13422. // preserve possible html of resultset values
  13423. preserveHTML : true,
  13424. // transition settings
  13425. transition : 'scale',
  13426. duration : 200,
  13427. easing : 'easeOutExpo',
  13428. // callbacks
  13429. onSelect : false,
  13430. onResultsAdd : false,
  13431. onSearchQuery : function(query){},
  13432. onResults : function(response){},
  13433. onResultsOpen : function(){},
  13434. onResultsClose : function(){},
  13435. className: {
  13436. animating : 'animating',
  13437. active : 'active',
  13438. empty : 'empty',
  13439. focus : 'focus',
  13440. hidden : 'hidden',
  13441. loading : 'loading',
  13442. results : 'results',
  13443. pressed : 'down'
  13444. },
  13445. error : {
  13446. source : 'Cannot search. No source used, and Semantic API module was not included',
  13447. noResultsHeader : 'No Results',
  13448. noResults : 'Your search returned no results',
  13449. logging : 'Error in debug logging, exiting.',
  13450. noEndpoint : 'No search endpoint was specified',
  13451. noTemplate : 'A valid template name was not specified.',
  13452. oldSearchSyntax : 'searchFullText setting has been renamed fullTextSearch for consistency, please adjust your settings.',
  13453. serverError : 'There was an issue querying the server.',
  13454. maxResults : 'Results must be an array to use maxResults setting',
  13455. method : 'The method you called is not defined.',
  13456. 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.'
  13457. },
  13458. metadata: {
  13459. cache : 'cache',
  13460. results : 'results',
  13461. result : 'result'
  13462. },
  13463. regExp: {
  13464. escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
  13465. beginsWith : '(?:\s|^)'
  13466. },
  13467. // maps api response attributes to internal representation
  13468. fields: {
  13469. categories : 'results', // array of categories (category view)
  13470. categoryName : 'name', // name of category (category view)
  13471. categoryResults : 'results', // array of results (category view)
  13472. description : 'description', // result description
  13473. image : 'image', // result image
  13474. price : 'price', // result price
  13475. results : 'results', // array of results (standard)
  13476. title : 'title', // result title
  13477. url : 'url', // result url
  13478. action : 'action', // "view more" object name
  13479. actionText : 'text', // "view more" text
  13480. actionURL : 'url' // "view more" url
  13481. },
  13482. selector : {
  13483. prompt : '.prompt',
  13484. searchButton : '.search.button',
  13485. results : '.results',
  13486. message : '.results > .message',
  13487. category : '.category',
  13488. result : '.result',
  13489. title : '.title, .name'
  13490. },
  13491. templates: {
  13492. escape: function(string, preserveHTML) {
  13493. if (preserveHTML){
  13494. return string;
  13495. }
  13496. var
  13497. badChars = /[<>"'`]/g,
  13498. shouldEscape = /[&<>"'`]/,
  13499. escape = {
  13500. "<": "&lt;",
  13501. ">": "&gt;",
  13502. '"': "&quot;",
  13503. "'": "&#x27;",
  13504. "`": "&#x60;"
  13505. },
  13506. escapedChar = function(chr) {
  13507. return escape[chr];
  13508. }
  13509. ;
  13510. if(shouldEscape.test(string)) {
  13511. string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
  13512. return string.replace(badChars, escapedChar);
  13513. }
  13514. return string;
  13515. },
  13516. message: function(message, type, header) {
  13517. var
  13518. html = ''
  13519. ;
  13520. if(message !== undefined && type !== undefined) {
  13521. html += ''
  13522. + '<div class="message ' + type + '">'
  13523. ;
  13524. if(header) {
  13525. html += ''
  13526. + '<div class="header">' + header + '</div>'
  13527. ;
  13528. }
  13529. html += ' <div class="description">' + message + '</div>';
  13530. html += '</div>';
  13531. }
  13532. return html;
  13533. },
  13534. category: function(response, fields, preserveHTML) {
  13535. var
  13536. html = '',
  13537. escape = $.fn.search.settings.templates.escape
  13538. ;
  13539. if(response[fields.categoryResults] !== undefined) {
  13540. // each category
  13541. $.each(response[fields.categoryResults], function(index, category) {
  13542. if(category[fields.results] !== undefined && category.results.length > 0) {
  13543. html += '<div class="category">';
  13544. if(category[fields.categoryName] !== undefined) {
  13545. html += '<div class="name">' + escape(category[fields.categoryName], preserveHTML) + '</div>';
  13546. }
  13547. // each item inside category
  13548. html += '<div class="results">';
  13549. $.each(category.results, function(index, result) {
  13550. if(result[fields.url]) {
  13551. html += '<a class="result" href="' + result[fields.url].replace(/"/g,"") + '">';
  13552. }
  13553. else {
  13554. html += '<a class="result">';
  13555. }
  13556. if(result[fields.image] !== undefined) {
  13557. html += ''
  13558. + '<div class="image">'
  13559. + ' <img src="' + result[fields.image].replace(/"/g,"") + '">'
  13560. + '</div>'
  13561. ;
  13562. }
  13563. html += '<div class="content">';
  13564. if(result[fields.price] !== undefined) {
  13565. html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
  13566. }
  13567. if(result[fields.title] !== undefined) {
  13568. html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
  13569. }
  13570. if(result[fields.description] !== undefined) {
  13571. html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
  13572. }
  13573. html += ''
  13574. + '</div>'
  13575. ;
  13576. html += '</a>';
  13577. });
  13578. html += '</div>';
  13579. html += ''
  13580. + '</div>'
  13581. ;
  13582. }
  13583. });
  13584. if(response[fields.action]) {
  13585. if(fields.actionURL === false) {
  13586. html += ''
  13587. + '<div class="action">'
  13588. + escape(response[fields.action][fields.actionText], preserveHTML)
  13589. + '</div>';
  13590. } else {
  13591. html += ''
  13592. + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g,"") + '" class="action">'
  13593. + escape(response[fields.action][fields.actionText], preserveHTML)
  13594. + '</a>';
  13595. }
  13596. }
  13597. return html;
  13598. }
  13599. return false;
  13600. },
  13601. standard: function(response, fields, preserveHTML) {
  13602. var
  13603. html = '',
  13604. escape = $.fn.search.settings.templates.escape
  13605. ;
  13606. if(response[fields.results] !== undefined) {
  13607. // each result
  13608. $.each(response[fields.results], function(index, result) {
  13609. if(result[fields.url]) {
  13610. html += '<a class="result" href="' + result[fields.url].replace(/"/g,"") + '">';
  13611. }
  13612. else {
  13613. html += '<a class="result">';
  13614. }
  13615. if(result[fields.image] !== undefined) {
  13616. html += ''
  13617. + '<div class="image">'
  13618. + ' <img src="' + result[fields.image].replace(/"/g,"") + '">'
  13619. + '</div>'
  13620. ;
  13621. }
  13622. html += '<div class="content">';
  13623. if(result[fields.price] !== undefined) {
  13624. html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
  13625. }
  13626. if(result[fields.title] !== undefined) {
  13627. html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
  13628. }
  13629. if(result[fields.description] !== undefined) {
  13630. html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
  13631. }
  13632. html += ''
  13633. + '</div>'
  13634. ;
  13635. html += '</a>';
  13636. });
  13637. if(response[fields.action]) {
  13638. if(fields.actionURL === false) {
  13639. html += ''
  13640. + '<div class="action">'
  13641. + escape(response[fields.action][fields.actionText], preserveHTML)
  13642. + '</div>';
  13643. } else {
  13644. html += ''
  13645. + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g,"") + '" class="action">'
  13646. + escape(response[fields.action][fields.actionText], preserveHTML)
  13647. + '</a>';
  13648. }
  13649. }
  13650. return html;
  13651. }
  13652. return false;
  13653. }
  13654. }
  13655. };
  13656. })( jQuery, window, document );
  13657. /*!
  13658. * # Fomantic-UI - Site
  13659. * http://github.com/fomantic/Fomantic-UI/
  13660. *
  13661. *
  13662. * Released under the MIT license
  13663. * http://opensource.org/licenses/MIT
  13664. *
  13665. */
  13666. ;(function ($, window, document, undefined) {
  13667. $.isFunction = $.isFunction || function(obj) {
  13668. return typeof obj === "function" && typeof obj.nodeType !== "number";
  13669. };
  13670. $.site = $.fn.site = function(parameters) {
  13671. var
  13672. time = new Date().getTime(),
  13673. performance = [],
  13674. query = arguments[0],
  13675. methodInvoked = (typeof query == 'string'),
  13676. queryArguments = [].slice.call(arguments, 1),
  13677. settings = ( $.isPlainObject(parameters) )
  13678. ? $.extend(true, {}, $.site.settings, parameters)
  13679. : $.extend({}, $.site.settings),
  13680. namespace = settings.namespace,
  13681. error = settings.error,
  13682. moduleNamespace = 'module-' + namespace,
  13683. $document = $(document),
  13684. $module = $document,
  13685. element = this,
  13686. instance = $module.data(moduleNamespace),
  13687. module,
  13688. returnedValue
  13689. ;
  13690. module = {
  13691. initialize: function() {
  13692. module.instantiate();
  13693. },
  13694. instantiate: function() {
  13695. module.verbose('Storing instance of site', module);
  13696. instance = module;
  13697. $module
  13698. .data(moduleNamespace, module)
  13699. ;
  13700. },
  13701. normalize: function() {
  13702. module.fix.console();
  13703. module.fix.requestAnimationFrame();
  13704. },
  13705. fix: {
  13706. console: function() {
  13707. module.debug('Normalizing window.console');
  13708. if (console === undefined || console.log === undefined) {
  13709. module.verbose('Console not available, normalizing events');
  13710. module.disable.console();
  13711. }
  13712. if (typeof console.group == 'undefined' || typeof console.groupEnd == 'undefined' || typeof console.groupCollapsed == 'undefined') {
  13713. module.verbose('Console group not available, normalizing events');
  13714. window.console.group = function() {};
  13715. window.console.groupEnd = function() {};
  13716. window.console.groupCollapsed = function() {};
  13717. }
  13718. if (typeof console.markTimeline == 'undefined') {
  13719. module.verbose('Mark timeline not available, normalizing events');
  13720. window.console.markTimeline = function() {};
  13721. }
  13722. },
  13723. consoleClear: function() {
  13724. module.debug('Disabling programmatic console clearing');
  13725. window.console.clear = function() {};
  13726. },
  13727. requestAnimationFrame: function() {
  13728. module.debug('Normalizing requestAnimationFrame');
  13729. if(window.requestAnimationFrame === undefined) {
  13730. module.debug('RequestAnimationFrame not available, normalizing event');
  13731. window.requestAnimationFrame = window.requestAnimationFrame
  13732. || window.mozRequestAnimationFrame
  13733. || window.webkitRequestAnimationFrame
  13734. || window.msRequestAnimationFrame
  13735. || function(callback) { setTimeout(callback, 0); }
  13736. ;
  13737. }
  13738. }
  13739. },
  13740. moduleExists: function(name) {
  13741. return ($.fn[name] !== undefined && $.fn[name].settings !== undefined);
  13742. },
  13743. enabled: {
  13744. modules: function(modules) {
  13745. var
  13746. enabledModules = []
  13747. ;
  13748. modules = modules || settings.modules;
  13749. $.each(modules, function(index, name) {
  13750. if(module.moduleExists(name)) {
  13751. enabledModules.push(name);
  13752. }
  13753. });
  13754. return enabledModules;
  13755. }
  13756. },
  13757. disabled: {
  13758. modules: function(modules) {
  13759. var
  13760. disabledModules = []
  13761. ;
  13762. modules = modules || settings.modules;
  13763. $.each(modules, function(index, name) {
  13764. if(!module.moduleExists(name)) {
  13765. disabledModules.push(name);
  13766. }
  13767. });
  13768. return disabledModules;
  13769. }
  13770. },
  13771. change: {
  13772. setting: function(setting, value, modules, modifyExisting) {
  13773. modules = (typeof modules === 'string')
  13774. ? (modules === 'all')
  13775. ? settings.modules
  13776. : [modules]
  13777. : modules || settings.modules
  13778. ;
  13779. modifyExisting = (modifyExisting !== undefined)
  13780. ? modifyExisting
  13781. : true
  13782. ;
  13783. $.each(modules, function(index, name) {
  13784. var
  13785. namespace = (module.moduleExists(name))
  13786. ? $.fn[name].settings.namespace || false
  13787. : true,
  13788. $existingModules
  13789. ;
  13790. if(module.moduleExists(name)) {
  13791. module.verbose('Changing default setting', setting, value, name);
  13792. $.fn[name].settings[setting] = value;
  13793. if(modifyExisting && namespace) {
  13794. $existingModules = $(':data(module-' + namespace + ')');
  13795. if($existingModules.length > 0) {
  13796. module.verbose('Modifying existing settings', $existingModules);
  13797. $existingModules[name]('setting', setting, value);
  13798. }
  13799. }
  13800. }
  13801. });
  13802. },
  13803. settings: function(newSettings, modules, modifyExisting) {
  13804. modules = (typeof modules === 'string')
  13805. ? [modules]
  13806. : modules || settings.modules
  13807. ;
  13808. modifyExisting = (modifyExisting !== undefined)
  13809. ? modifyExisting
  13810. : true
  13811. ;
  13812. $.each(modules, function(index, name) {
  13813. var
  13814. $existingModules
  13815. ;
  13816. if(module.moduleExists(name)) {
  13817. module.verbose('Changing default setting', newSettings, name);
  13818. $.extend(true, $.fn[name].settings, newSettings);
  13819. if(modifyExisting && namespace) {
  13820. $existingModules = $(':data(module-' + namespace + ')');
  13821. if($existingModules.length > 0) {
  13822. module.verbose('Modifying existing settings', $existingModules);
  13823. $existingModules[name]('setting', newSettings);
  13824. }
  13825. }
  13826. }
  13827. });
  13828. }
  13829. },
  13830. enable: {
  13831. console: function() {
  13832. module.console(true);
  13833. },
  13834. debug: function(modules, modifyExisting) {
  13835. modules = modules || settings.modules;
  13836. module.debug('Enabling debug for modules', modules);
  13837. module.change.setting('debug', true, modules, modifyExisting);
  13838. },
  13839. verbose: function(modules, modifyExisting) {
  13840. modules = modules || settings.modules;
  13841. module.debug('Enabling verbose debug for modules', modules);
  13842. module.change.setting('verbose', true, modules, modifyExisting);
  13843. }
  13844. },
  13845. disable: {
  13846. console: function() {
  13847. module.console(false);
  13848. },
  13849. debug: function(modules, modifyExisting) {
  13850. modules = modules || settings.modules;
  13851. module.debug('Disabling debug for modules', modules);
  13852. module.change.setting('debug', false, modules, modifyExisting);
  13853. },
  13854. verbose: function(modules, modifyExisting) {
  13855. modules = modules || settings.modules;
  13856. module.debug('Disabling verbose debug for modules', modules);
  13857. module.change.setting('verbose', false, modules, modifyExisting);
  13858. }
  13859. },
  13860. console: function(enable) {
  13861. if(enable) {
  13862. if(instance.cache.console === undefined) {
  13863. module.error(error.console);
  13864. return;
  13865. }
  13866. module.debug('Restoring console function');
  13867. window.console = instance.cache.console;
  13868. }
  13869. else {
  13870. module.debug('Disabling console function');
  13871. instance.cache.console = window.console;
  13872. window.console = {
  13873. clear : function(){},
  13874. error : function(){},
  13875. group : function(){},
  13876. groupCollapsed : function(){},
  13877. groupEnd : function(){},
  13878. info : function(){},
  13879. log : function(){},
  13880. markTimeline : function(){},
  13881. warn : function(){}
  13882. };
  13883. }
  13884. },
  13885. destroy: function() {
  13886. module.verbose('Destroying previous site for', $module);
  13887. $module
  13888. .removeData(moduleNamespace)
  13889. ;
  13890. },
  13891. cache: {},
  13892. setting: function(name, value) {
  13893. if( $.isPlainObject(name) ) {
  13894. $.extend(true, settings, name);
  13895. }
  13896. else if(value !== undefined) {
  13897. settings[name] = value;
  13898. }
  13899. else {
  13900. return settings[name];
  13901. }
  13902. },
  13903. internal: function(name, value) {
  13904. if( $.isPlainObject(name) ) {
  13905. $.extend(true, module, name);
  13906. }
  13907. else if(value !== undefined) {
  13908. module[name] = value;
  13909. }
  13910. else {
  13911. return module[name];
  13912. }
  13913. },
  13914. debug: function() {
  13915. if(settings.debug) {
  13916. if(settings.performance) {
  13917. module.performance.log(arguments);
  13918. }
  13919. else {
  13920. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  13921. module.debug.apply(console, arguments);
  13922. }
  13923. }
  13924. },
  13925. verbose: function() {
  13926. if(settings.verbose && settings.debug) {
  13927. if(settings.performance) {
  13928. module.performance.log(arguments);
  13929. }
  13930. else {
  13931. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  13932. module.verbose.apply(console, arguments);
  13933. }
  13934. }
  13935. },
  13936. error: function() {
  13937. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  13938. module.error.apply(console, arguments);
  13939. },
  13940. performance: {
  13941. log: function(message) {
  13942. var
  13943. currentTime,
  13944. executionTime,
  13945. previousTime
  13946. ;
  13947. if(settings.performance) {
  13948. currentTime = new Date().getTime();
  13949. previousTime = time || currentTime;
  13950. executionTime = currentTime - previousTime;
  13951. time = currentTime;
  13952. performance.push({
  13953. 'Element' : element,
  13954. 'Name' : message[0],
  13955. 'Arguments' : [].slice.call(message, 1) || '',
  13956. 'Execution Time' : executionTime
  13957. });
  13958. }
  13959. clearTimeout(module.performance.timer);
  13960. module.performance.timer = setTimeout(module.performance.display, 500);
  13961. },
  13962. display: function() {
  13963. var
  13964. title = settings.name + ':',
  13965. totalTime = 0
  13966. ;
  13967. time = false;
  13968. clearTimeout(module.performance.timer);
  13969. $.each(performance, function(index, data) {
  13970. totalTime += data['Execution Time'];
  13971. });
  13972. title += ' ' + totalTime + 'ms';
  13973. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  13974. console.groupCollapsed(title);
  13975. if(console.table) {
  13976. console.table(performance);
  13977. }
  13978. else {
  13979. $.each(performance, function(index, data) {
  13980. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  13981. });
  13982. }
  13983. console.groupEnd();
  13984. }
  13985. performance = [];
  13986. }
  13987. },
  13988. invoke: function(query, passedArguments, context) {
  13989. var
  13990. object = instance,
  13991. maxDepth,
  13992. found,
  13993. response
  13994. ;
  13995. passedArguments = passedArguments || queryArguments;
  13996. context = element || context;
  13997. if(typeof query == 'string' && object !== undefined) {
  13998. query = query.split(/[\. ]/);
  13999. maxDepth = query.length - 1;
  14000. $.each(query, function(depth, value) {
  14001. var camelCaseValue = (depth != maxDepth)
  14002. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  14003. : query
  14004. ;
  14005. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  14006. object = object[camelCaseValue];
  14007. }
  14008. else if( object[camelCaseValue] !== undefined ) {
  14009. found = object[camelCaseValue];
  14010. return false;
  14011. }
  14012. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  14013. object = object[value];
  14014. }
  14015. else if( object[value] !== undefined ) {
  14016. found = object[value];
  14017. return false;
  14018. }
  14019. else {
  14020. module.error(error.method, query);
  14021. return false;
  14022. }
  14023. });
  14024. }
  14025. if ( $.isFunction( found ) ) {
  14026. response = found.apply(context, passedArguments);
  14027. }
  14028. else if(found !== undefined) {
  14029. response = found;
  14030. }
  14031. if(Array.isArray(returnedValue)) {
  14032. returnedValue.push(response);
  14033. }
  14034. else if(returnedValue !== undefined) {
  14035. returnedValue = [returnedValue, response];
  14036. }
  14037. else if(response !== undefined) {
  14038. returnedValue = response;
  14039. }
  14040. return found;
  14041. }
  14042. };
  14043. if(methodInvoked) {
  14044. if(instance === undefined) {
  14045. module.initialize();
  14046. }
  14047. module.invoke(query);
  14048. }
  14049. else {
  14050. if(instance !== undefined) {
  14051. module.destroy();
  14052. }
  14053. module.initialize();
  14054. }
  14055. return (returnedValue !== undefined)
  14056. ? returnedValue
  14057. : this
  14058. ;
  14059. };
  14060. $.site.settings = {
  14061. name : 'Site',
  14062. namespace : 'site',
  14063. error : {
  14064. console : 'Console cannot be restored, most likely it was overwritten outside of module',
  14065. method : 'The method you called is not defined.'
  14066. },
  14067. debug : false,
  14068. verbose : false,
  14069. performance : true,
  14070. modules: [
  14071. 'accordion',
  14072. 'api',
  14073. 'calendar',
  14074. 'checkbox',
  14075. 'dimmer',
  14076. 'dropdown',
  14077. 'embed',
  14078. 'form',
  14079. 'modal',
  14080. 'nag',
  14081. 'popup',
  14082. 'slider',
  14083. 'rating',
  14084. 'shape',
  14085. 'sidebar',
  14086. 'state',
  14087. 'sticky',
  14088. 'tab',
  14089. 'toast',
  14090. 'transition',
  14091. 'visibility',
  14092. 'visit'
  14093. ],
  14094. siteNamespace : 'site',
  14095. namespaceStub : {
  14096. cache : {},
  14097. config : {},
  14098. sections : {},
  14099. section : {},
  14100. utilities : {}
  14101. }
  14102. };
  14103. // allows for selection of elements with data attributes
  14104. $.extend($.expr[ ":" ], {
  14105. data: ($.expr.createPseudo)
  14106. ? $.expr.createPseudo(function(dataName) {
  14107. return function(elem) {
  14108. return !!$.data(elem, dataName);
  14109. };
  14110. })
  14111. : function(elem, i, match) {
  14112. // support: jQuery < 1.8
  14113. return !!$.data(elem, match[ 3 ]);
  14114. }
  14115. });
  14116. })( jQuery, window, document );
  14117. /*!
  14118. * # Fomantic-UI - Tab
  14119. * http://github.com/fomantic/Fomantic-UI/
  14120. *
  14121. *
  14122. * Released under the MIT license
  14123. * http://opensource.org/licenses/MIT
  14124. *
  14125. */
  14126. ;(function ($, window, document, undefined) {
  14127. 'use strict';
  14128. $.isWindow = $.isWindow || function(obj) {
  14129. return obj != null && obj === obj.window;
  14130. };
  14131. $.isFunction = $.isFunction || function(obj) {
  14132. return typeof obj === "function" && typeof obj.nodeType !== "number";
  14133. };
  14134. window = (typeof window != 'undefined' && window.Math == Math)
  14135. ? window
  14136. : (typeof self != 'undefined' && self.Math == Math)
  14137. ? self
  14138. : Function('return this')()
  14139. ;
  14140. $.fn.tab = function(parameters) {
  14141. var
  14142. // use window context if none specified
  14143. $allModules = $.isFunction(this)
  14144. ? $(window)
  14145. : $(this),
  14146. moduleSelector = $allModules.selector || '',
  14147. time = new Date().getTime(),
  14148. performance = [],
  14149. query = arguments[0],
  14150. methodInvoked = (typeof query == 'string'),
  14151. queryArguments = [].slice.call(arguments, 1),
  14152. initializedHistory = false,
  14153. returnedValue
  14154. ;
  14155. $allModules
  14156. .each(function() {
  14157. var
  14158. settings = ( $.isPlainObject(parameters) )
  14159. ? $.extend(true, {}, $.fn.tab.settings, parameters)
  14160. : $.extend({}, $.fn.tab.settings),
  14161. className = settings.className,
  14162. metadata = settings.metadata,
  14163. selector = settings.selector,
  14164. error = settings.error,
  14165. regExp = settings.regExp,
  14166. eventNamespace = '.' + settings.namespace,
  14167. moduleNamespace = 'module-' + settings.namespace,
  14168. $module = $(this),
  14169. $context,
  14170. $tabs,
  14171. cache = {},
  14172. firstLoad = true,
  14173. recursionDepth = 0,
  14174. element = this,
  14175. instance = $module.data(moduleNamespace),
  14176. activeTabPath,
  14177. parameterArray,
  14178. module,
  14179. historyEvent
  14180. ;
  14181. module = {
  14182. initialize: function() {
  14183. module.debug('Initializing tab menu item', $module);
  14184. module.fix.callbacks();
  14185. module.determineTabs();
  14186. module.debug('Determining tabs', settings.context, $tabs);
  14187. // set up automatic routing
  14188. if(settings.auto) {
  14189. module.set.auto();
  14190. }
  14191. module.bind.events();
  14192. if(settings.history && !initializedHistory) {
  14193. module.initializeHistory();
  14194. initializedHistory = true;
  14195. }
  14196. if(settings.autoTabActivation && instance === undefined && module.determine.activeTab() == null) {
  14197. module.debug('No active tab detected, setting first tab active', module.get.initialPath());
  14198. module.changeTab(settings.autoTabActivation === true ? module.get.initialPath() : settings.autoTabActivation);
  14199. };
  14200. module.instantiate();
  14201. },
  14202. instantiate: function () {
  14203. module.verbose('Storing instance of module', module);
  14204. instance = module;
  14205. $module
  14206. .data(moduleNamespace, module)
  14207. ;
  14208. },
  14209. destroy: function() {
  14210. module.debug('Destroying tabs', $module);
  14211. $module
  14212. .removeData(moduleNamespace)
  14213. .off(eventNamespace)
  14214. ;
  14215. },
  14216. bind: {
  14217. events: function() {
  14218. // if using $.tab don't add events
  14219. if( !$.isWindow( element ) ) {
  14220. module.debug('Attaching tab activation events to element', $module);
  14221. $module
  14222. .on('click' + eventNamespace, module.event.click)
  14223. ;
  14224. }
  14225. }
  14226. },
  14227. determineTabs: function() {
  14228. var
  14229. $reference
  14230. ;
  14231. // determine tab context
  14232. if(settings.context === 'parent') {
  14233. if($module.closest(selector.ui).length > 0) {
  14234. $reference = $module.closest(selector.ui);
  14235. module.verbose('Using closest UI element as parent', $reference);
  14236. }
  14237. else {
  14238. $reference = $module;
  14239. }
  14240. $context = $reference.parent();
  14241. module.verbose('Determined parent element for creating context', $context);
  14242. }
  14243. else if(settings.context) {
  14244. $context = $(settings.context);
  14245. module.verbose('Using selector for tab context', settings.context, $context);
  14246. }
  14247. else {
  14248. $context = $('body');
  14249. }
  14250. // find tabs
  14251. if(settings.childrenOnly) {
  14252. $tabs = $context.children(selector.tabs);
  14253. module.debug('Searching tab context children for tabs', $context, $tabs);
  14254. }
  14255. else {
  14256. $tabs = $context.find(selector.tabs);
  14257. module.debug('Searching tab context for tabs', $context, $tabs);
  14258. }
  14259. },
  14260. fix: {
  14261. callbacks: function() {
  14262. if( $.isPlainObject(parameters) && (parameters.onTabLoad || parameters.onTabInit) ) {
  14263. if(parameters.onTabLoad) {
  14264. parameters.onLoad = parameters.onTabLoad;
  14265. delete parameters.onTabLoad;
  14266. module.error(error.legacyLoad, parameters.onLoad);
  14267. }
  14268. if(parameters.onTabInit) {
  14269. parameters.onFirstLoad = parameters.onTabInit;
  14270. delete parameters.onTabInit;
  14271. module.error(error.legacyInit, parameters.onFirstLoad);
  14272. }
  14273. settings = $.extend(true, {}, $.fn.tab.settings, parameters);
  14274. }
  14275. }
  14276. },
  14277. initializeHistory: function() {
  14278. module.debug('Initializing page state');
  14279. if( $.address === undefined ) {
  14280. module.error(error.state);
  14281. return false;
  14282. }
  14283. else {
  14284. if(settings.historyType == 'state') {
  14285. module.debug('Using HTML5 to manage state');
  14286. if(settings.path !== false) {
  14287. $.address
  14288. .history(true)
  14289. .state(settings.path)
  14290. ;
  14291. }
  14292. else {
  14293. module.error(error.path);
  14294. return false;
  14295. }
  14296. }
  14297. $.address
  14298. .bind('change', module.event.history.change)
  14299. ;
  14300. }
  14301. },
  14302. event: {
  14303. click: function(event) {
  14304. var
  14305. tabPath = $(this).data(metadata.tab)
  14306. ;
  14307. if(tabPath !== undefined) {
  14308. if(settings.history) {
  14309. module.verbose('Updating page state', event);
  14310. $.address.value(tabPath);
  14311. }
  14312. else {
  14313. module.verbose('Changing tab', event);
  14314. module.changeTab(tabPath);
  14315. }
  14316. event.preventDefault();
  14317. }
  14318. else {
  14319. module.debug('No tab specified');
  14320. }
  14321. },
  14322. history: {
  14323. change: function(event) {
  14324. var
  14325. tabPath = event.pathNames.join('/') || module.get.initialPath(),
  14326. pageTitle = settings.templates.determineTitle(tabPath) || false
  14327. ;
  14328. module.performance.display();
  14329. module.debug('History change event', tabPath, event);
  14330. historyEvent = event;
  14331. if(tabPath !== undefined) {
  14332. module.changeTab(tabPath);
  14333. }
  14334. if(pageTitle) {
  14335. $.address.title(pageTitle);
  14336. }
  14337. }
  14338. }
  14339. },
  14340. refresh: function() {
  14341. if(activeTabPath) {
  14342. module.debug('Refreshing tab', activeTabPath);
  14343. module.changeTab(activeTabPath);
  14344. }
  14345. },
  14346. cache: {
  14347. read: function(cacheKey) {
  14348. return (cacheKey !== undefined)
  14349. ? cache[cacheKey]
  14350. : false
  14351. ;
  14352. },
  14353. add: function(cacheKey, content) {
  14354. cacheKey = cacheKey || activeTabPath;
  14355. module.debug('Adding cached content for', cacheKey);
  14356. cache[cacheKey] = content;
  14357. },
  14358. remove: function(cacheKey) {
  14359. cacheKey = cacheKey || activeTabPath;
  14360. module.debug('Removing cached content for', cacheKey);
  14361. delete cache[cacheKey];
  14362. }
  14363. },
  14364. escape: {
  14365. string: function(text) {
  14366. text = String(text);
  14367. return text.replace(regExp.escape, '\\$&');
  14368. }
  14369. },
  14370. set: {
  14371. auto: function() {
  14372. var
  14373. url = (typeof settings.path == 'string')
  14374. ? settings.path.replace(/\/$/, '') + '/{$tab}'
  14375. : '/{$tab}'
  14376. ;
  14377. module.verbose('Setting up automatic tab retrieval from server', url);
  14378. if($.isPlainObject(settings.apiSettings)) {
  14379. settings.apiSettings.url = url;
  14380. }
  14381. else {
  14382. settings.apiSettings = {
  14383. url: url
  14384. };
  14385. }
  14386. },
  14387. loading: function(tabPath) {
  14388. var
  14389. $tab = module.get.tabElement(tabPath),
  14390. isLoading = $tab.hasClass(className.loading)
  14391. ;
  14392. if(!isLoading) {
  14393. module.verbose('Setting loading state for', $tab);
  14394. $tab
  14395. .addClass(className.loading)
  14396. .siblings($tabs)
  14397. .removeClass(className.active + ' ' + className.loading)
  14398. ;
  14399. if($tab.length > 0) {
  14400. settings.onRequest.call($tab[0], tabPath);
  14401. }
  14402. }
  14403. },
  14404. state: function(state) {
  14405. $.address.value(state);
  14406. }
  14407. },
  14408. changeTab: function(tabPath) {
  14409. var
  14410. pushStateAvailable = (window.history && window.history.pushState),
  14411. shouldIgnoreLoad = (pushStateAvailable && settings.ignoreFirstLoad && firstLoad),
  14412. remoteContent = (settings.auto || $.isPlainObject(settings.apiSettings) ),
  14413. // only add default path if not remote content
  14414. pathArray = (remoteContent && !shouldIgnoreLoad)
  14415. ? module.utilities.pathToArray(tabPath)
  14416. : module.get.defaultPathArray(tabPath)
  14417. ;
  14418. tabPath = module.utilities.arrayToPath(pathArray);
  14419. $.each(pathArray, function(index, tab) {
  14420. var
  14421. currentPathArray = pathArray.slice(0, index + 1),
  14422. currentPath = module.utilities.arrayToPath(currentPathArray),
  14423. isTab = module.is.tab(currentPath),
  14424. isLastIndex = (index + 1 == pathArray.length),
  14425. $tab = module.get.tabElement(currentPath),
  14426. $anchor,
  14427. nextPathArray,
  14428. nextPath,
  14429. isLastTab
  14430. ;
  14431. module.verbose('Looking for tab', tab);
  14432. if(isTab) {
  14433. module.verbose('Tab was found', tab);
  14434. // scope up
  14435. activeTabPath = currentPath;
  14436. parameterArray = module.utilities.filterArray(pathArray, currentPathArray);
  14437. if(isLastIndex) {
  14438. isLastTab = true;
  14439. }
  14440. else {
  14441. nextPathArray = pathArray.slice(0, index + 2);
  14442. nextPath = module.utilities.arrayToPath(nextPathArray);
  14443. isLastTab = ( !module.is.tab(nextPath) );
  14444. if(isLastTab) {
  14445. module.verbose('Tab parameters found', nextPathArray);
  14446. }
  14447. }
  14448. if(isLastTab && remoteContent) {
  14449. if(!shouldIgnoreLoad) {
  14450. module.activate.navigation(currentPath);
  14451. module.fetch.content(currentPath, tabPath);
  14452. }
  14453. else {
  14454. module.debug('Ignoring remote content on first tab load', currentPath);
  14455. firstLoad = false;
  14456. module.cache.add(tabPath, $tab.html());
  14457. module.activate.all(currentPath);
  14458. settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  14459. settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  14460. }
  14461. return false;
  14462. }
  14463. else {
  14464. module.debug('Opened local tab', currentPath);
  14465. module.activate.all(currentPath);
  14466. if( !module.cache.read(currentPath) ) {
  14467. module.cache.add(currentPath, true);
  14468. module.debug('First time tab loaded calling tab init');
  14469. settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  14470. }
  14471. settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  14472. }
  14473. }
  14474. else if(tabPath.search('/') == -1 && tabPath !== '') {
  14475. // look for in page anchor
  14476. tabPath = module.escape.string(tabPath);
  14477. $anchor = $('#' + tabPath + ', a[name="' + tabPath + '"]');
  14478. currentPath = $anchor.closest('[data-tab]').data(metadata.tab);
  14479. $tab = module.get.tabElement(currentPath);
  14480. // if anchor exists use parent tab
  14481. if($anchor && $anchor.length > 0 && currentPath) {
  14482. module.debug('Anchor link used, opening parent tab', $tab, $anchor);
  14483. if( !$tab.hasClass(className.active) ) {
  14484. setTimeout(function() {
  14485. module.scrollTo($anchor);
  14486. }, 0);
  14487. }
  14488. module.activate.all(currentPath);
  14489. if( !module.cache.read(currentPath) ) {
  14490. module.cache.add(currentPath, true);
  14491. module.debug('First time tab loaded calling tab init');
  14492. settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  14493. }
  14494. settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);
  14495. return false;
  14496. }
  14497. }
  14498. else {
  14499. module.error(error.missingTab, $module, $context, currentPath);
  14500. return false;
  14501. }
  14502. });
  14503. },
  14504. scrollTo: function($element) {
  14505. var
  14506. scrollOffset = ($element && $element.length > 0)
  14507. ? $element.offset().top
  14508. : false
  14509. ;
  14510. if(scrollOffset !== false) {
  14511. module.debug('Forcing scroll to an in-page link in a hidden tab', scrollOffset, $element);
  14512. $(document).scrollTop(scrollOffset);
  14513. }
  14514. },
  14515. update: {
  14516. content: function(tabPath, html, evaluateScripts) {
  14517. var
  14518. $tab = module.get.tabElement(tabPath),
  14519. tab = $tab[0]
  14520. ;
  14521. evaluateScripts = (evaluateScripts !== undefined)
  14522. ? evaluateScripts
  14523. : settings.evaluateScripts
  14524. ;
  14525. if(typeof settings.cacheType == 'string' && settings.cacheType.toLowerCase() == 'dom' && typeof html !== 'string') {
  14526. $tab
  14527. .empty()
  14528. .append($(html).clone(true))
  14529. ;
  14530. }
  14531. else {
  14532. if(evaluateScripts) {
  14533. module.debug('Updating HTML and evaluating inline scripts', tabPath, html);
  14534. $tab.html(html);
  14535. }
  14536. else {
  14537. module.debug('Updating HTML', tabPath, html);
  14538. tab.innerHTML = html;
  14539. }
  14540. }
  14541. }
  14542. },
  14543. fetch: {
  14544. content: function(tabPath, fullTabPath) {
  14545. var
  14546. $tab = module.get.tabElement(tabPath),
  14547. apiSettings = {
  14548. dataType : 'html',
  14549. encodeParameters : false,
  14550. on : 'now',
  14551. cache : settings.alwaysRefresh,
  14552. headers : {
  14553. 'X-Remote': true
  14554. },
  14555. onSuccess : function(response) {
  14556. if(settings.cacheType == 'response') {
  14557. module.cache.add(fullTabPath, response);
  14558. }
  14559. module.update.content(tabPath, response);
  14560. if(tabPath == activeTabPath) {
  14561. module.debug('Content loaded', tabPath);
  14562. module.activate.tab(tabPath);
  14563. }
  14564. else {
  14565. module.debug('Content loaded in background', tabPath);
  14566. }
  14567. settings.onFirstLoad.call($tab[0], tabPath, parameterArray, historyEvent);
  14568. settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);
  14569. if(settings.loadOnce) {
  14570. module.cache.add(fullTabPath, true);
  14571. }
  14572. else if(typeof settings.cacheType == 'string' && settings.cacheType.toLowerCase() == 'dom' && $tab.children().length > 0) {
  14573. setTimeout(function() {
  14574. var
  14575. $clone = $tab.children().clone(true)
  14576. ;
  14577. $clone = $clone.not('script');
  14578. module.cache.add(fullTabPath, $clone);
  14579. }, 0);
  14580. }
  14581. else {
  14582. module.cache.add(fullTabPath, $tab.html());
  14583. }
  14584. },
  14585. urlData: {
  14586. tab: fullTabPath
  14587. }
  14588. },
  14589. request = $tab.api('get request') || false,
  14590. existingRequest = ( request && request.state() === 'pending' ),
  14591. requestSettings,
  14592. cachedContent
  14593. ;
  14594. fullTabPath = fullTabPath || tabPath;
  14595. cachedContent = module.cache.read(fullTabPath);
  14596. if(settings.cache && cachedContent) {
  14597. module.activate.tab(tabPath);
  14598. module.debug('Adding cached content', fullTabPath);
  14599. if(!settings.loadOnce) {
  14600. if(settings.evaluateScripts == 'once') {
  14601. module.update.content(tabPath, cachedContent, false);
  14602. }
  14603. else {
  14604. module.update.content(tabPath, cachedContent);
  14605. }
  14606. }
  14607. settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);
  14608. }
  14609. else if(existingRequest) {
  14610. module.set.loading(tabPath);
  14611. module.debug('Content is already loading', fullTabPath);
  14612. }
  14613. else if($.api !== undefined) {
  14614. requestSettings = $.extend(true, {}, settings.apiSettings, apiSettings);
  14615. module.debug('Retrieving remote content', fullTabPath, requestSettings);
  14616. module.set.loading(tabPath);
  14617. $tab.api(requestSettings);
  14618. }
  14619. else {
  14620. module.error(error.api);
  14621. }
  14622. }
  14623. },
  14624. activate: {
  14625. all: function(tabPath) {
  14626. module.activate.tab(tabPath);
  14627. module.activate.navigation(tabPath);
  14628. },
  14629. tab: function(tabPath) {
  14630. var
  14631. $tab = module.get.tabElement(tabPath),
  14632. $deactiveTabs = (settings.deactivate == 'siblings')
  14633. ? $tab.siblings($tabs)
  14634. : $tabs.not($tab),
  14635. isActive = $tab.hasClass(className.active)
  14636. ;
  14637. module.verbose('Showing tab content for', $tab);
  14638. if(!isActive) {
  14639. $tab
  14640. .addClass(className.active)
  14641. ;
  14642. $deactiveTabs
  14643. .removeClass(className.active + ' ' + className.loading)
  14644. ;
  14645. if($tab.length > 0) {
  14646. settings.onVisible.call($tab[0], tabPath);
  14647. }
  14648. }
  14649. },
  14650. navigation: function(tabPath) {
  14651. var
  14652. $navigation = module.get.navElement(tabPath),
  14653. $deactiveNavigation = (settings.deactivate == 'siblings')
  14654. ? $navigation.siblings($allModules)
  14655. : $allModules.not($navigation),
  14656. isActive = $navigation.hasClass(className.active)
  14657. ;
  14658. module.verbose('Activating tab navigation for', $navigation, tabPath);
  14659. if(!isActive) {
  14660. $navigation
  14661. .addClass(className.active)
  14662. ;
  14663. $deactiveNavigation
  14664. .removeClass(className.active + ' ' + className.loading)
  14665. ;
  14666. }
  14667. }
  14668. },
  14669. deactivate: {
  14670. all: function() {
  14671. module.deactivate.navigation();
  14672. module.deactivate.tabs();
  14673. },
  14674. navigation: function() {
  14675. $allModules
  14676. .removeClass(className.active)
  14677. ;
  14678. },
  14679. tabs: function() {
  14680. $tabs
  14681. .removeClass(className.active + ' ' + className.loading)
  14682. ;
  14683. }
  14684. },
  14685. is: {
  14686. tab: function(tabName) {
  14687. return (tabName !== undefined)
  14688. ? ( module.get.tabElement(tabName).length > 0 )
  14689. : false
  14690. ;
  14691. }
  14692. },
  14693. get: {
  14694. initialPath: function() {
  14695. return $allModules.eq(0).data(metadata.tab) || $tabs.eq(0).data(metadata.tab);
  14696. },
  14697. path: function() {
  14698. return $.address.value();
  14699. },
  14700. // adds default tabs to tab path
  14701. defaultPathArray: function(tabPath) {
  14702. return module.utilities.pathToArray( module.get.defaultPath(tabPath) );
  14703. },
  14704. defaultPath: function(tabPath) {
  14705. var
  14706. $defaultNav = $allModules.filter('[data-' + metadata.tab + '^="' + module.escape.string(tabPath) + '/"]').eq(0),
  14707. defaultTab = $defaultNav.data(metadata.tab) || false
  14708. ;
  14709. if( defaultTab ) {
  14710. module.debug('Found default tab', defaultTab);
  14711. if(recursionDepth < settings.maxDepth) {
  14712. recursionDepth++;
  14713. return module.get.defaultPath(defaultTab);
  14714. }
  14715. module.error(error.recursion);
  14716. }
  14717. else {
  14718. module.debug('No default tabs found for', tabPath, $tabs);
  14719. }
  14720. recursionDepth = 0;
  14721. return tabPath;
  14722. },
  14723. navElement: function(tabPath) {
  14724. tabPath = tabPath || activeTabPath;
  14725. return $allModules.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]');
  14726. },
  14727. tabElement: function(tabPath) {
  14728. var
  14729. $fullPathTab,
  14730. $simplePathTab,
  14731. tabPathArray,
  14732. lastTab
  14733. ;
  14734. tabPath = tabPath || activeTabPath;
  14735. tabPathArray = module.utilities.pathToArray(tabPath);
  14736. lastTab = module.utilities.last(tabPathArray);
  14737. $fullPathTab = $tabs.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]');
  14738. $simplePathTab = $tabs.filter('[data-' + metadata.tab + '="' + module.escape.string(lastTab) + '"]');
  14739. return ($fullPathTab.length > 0)
  14740. ? $fullPathTab
  14741. : $simplePathTab
  14742. ;
  14743. },
  14744. tab: function() {
  14745. return activeTabPath;
  14746. }
  14747. },
  14748. determine: {
  14749. activeTab: function() {
  14750. var activeTab = null;
  14751. $tabs.each(function(_index, tab) {
  14752. var $tab = $(tab);
  14753. if( $tab.hasClass(className.active) ) {
  14754. var
  14755. tabPath = $(this).data(metadata.tab),
  14756. $anchor = $allModules.filter('[data-' + metadata.tab + '="' + module.escape.string(tabPath) + '"]')
  14757. ;
  14758. if( $anchor.hasClass(className.active) ) {
  14759. activeTab = tabPath;
  14760. }
  14761. }
  14762. });
  14763. return activeTab;
  14764. }
  14765. },
  14766. utilities: {
  14767. filterArray: function(keepArray, removeArray) {
  14768. return $.grep(keepArray, function(keepValue) {
  14769. return ( $.inArray(keepValue, removeArray) == -1);
  14770. });
  14771. },
  14772. last: function(array) {
  14773. return Array.isArray(array)
  14774. ? array[ array.length - 1]
  14775. : false
  14776. ;
  14777. },
  14778. pathToArray: function(pathName) {
  14779. if(pathName === undefined) {
  14780. pathName = activeTabPath;
  14781. }
  14782. return typeof pathName == 'string'
  14783. ? pathName.split('/')
  14784. : [pathName]
  14785. ;
  14786. },
  14787. arrayToPath: function(pathArray) {
  14788. return Array.isArray(pathArray)
  14789. ? pathArray.join('/')
  14790. : false
  14791. ;
  14792. }
  14793. },
  14794. setting: function(name, value) {
  14795. module.debug('Changing setting', name, value);
  14796. if( $.isPlainObject(name) ) {
  14797. $.extend(true, settings, name);
  14798. }
  14799. else if(value !== undefined) {
  14800. if($.isPlainObject(settings[name])) {
  14801. $.extend(true, settings[name], value);
  14802. }
  14803. else {
  14804. settings[name] = value;
  14805. }
  14806. }
  14807. else {
  14808. return settings[name];
  14809. }
  14810. },
  14811. internal: function(name, value) {
  14812. if( $.isPlainObject(name) ) {
  14813. $.extend(true, module, name);
  14814. }
  14815. else if(value !== undefined) {
  14816. module[name] = value;
  14817. }
  14818. else {
  14819. return module[name];
  14820. }
  14821. },
  14822. debug: function() {
  14823. if(!settings.silent && settings.debug) {
  14824. if(settings.performance) {
  14825. module.performance.log(arguments);
  14826. }
  14827. else {
  14828. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  14829. module.debug.apply(console, arguments);
  14830. }
  14831. }
  14832. },
  14833. verbose: function() {
  14834. if(!settings.silent && settings.verbose && settings.debug) {
  14835. if(settings.performance) {
  14836. module.performance.log(arguments);
  14837. }
  14838. else {
  14839. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  14840. module.verbose.apply(console, arguments);
  14841. }
  14842. }
  14843. },
  14844. error: function() {
  14845. if(!settings.silent) {
  14846. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  14847. module.error.apply(console, arguments);
  14848. }
  14849. },
  14850. performance: {
  14851. log: function(message) {
  14852. var
  14853. currentTime,
  14854. executionTime,
  14855. previousTime
  14856. ;
  14857. if(settings.performance) {
  14858. currentTime = new Date().getTime();
  14859. previousTime = time || currentTime;
  14860. executionTime = currentTime - previousTime;
  14861. time = currentTime;
  14862. performance.push({
  14863. 'Name' : message[0],
  14864. 'Arguments' : [].slice.call(message, 1) || '',
  14865. 'Element' : element,
  14866. 'Execution Time' : executionTime
  14867. });
  14868. }
  14869. clearTimeout(module.performance.timer);
  14870. module.performance.timer = setTimeout(module.performance.display, 500);
  14871. },
  14872. display: function() {
  14873. var
  14874. title = settings.name + ':',
  14875. totalTime = 0
  14876. ;
  14877. time = false;
  14878. clearTimeout(module.performance.timer);
  14879. $.each(performance, function(index, data) {
  14880. totalTime += data['Execution Time'];
  14881. });
  14882. title += ' ' + totalTime + 'ms';
  14883. if(moduleSelector) {
  14884. title += ' \'' + moduleSelector + '\'';
  14885. }
  14886. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  14887. console.groupCollapsed(title);
  14888. if(console.table) {
  14889. console.table(performance);
  14890. }
  14891. else {
  14892. $.each(performance, function(index, data) {
  14893. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  14894. });
  14895. }
  14896. console.groupEnd();
  14897. }
  14898. performance = [];
  14899. }
  14900. },
  14901. invoke: function(query, passedArguments, context) {
  14902. var
  14903. object = instance,
  14904. maxDepth,
  14905. found,
  14906. response
  14907. ;
  14908. passedArguments = passedArguments || queryArguments;
  14909. context = element || context;
  14910. if(typeof query == 'string' && object !== undefined) {
  14911. query = query.split(/[\. ]/);
  14912. maxDepth = query.length - 1;
  14913. $.each(query, function(depth, value) {
  14914. var camelCaseValue = (depth != maxDepth)
  14915. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  14916. : query
  14917. ;
  14918. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  14919. object = object[camelCaseValue];
  14920. }
  14921. else if( object[camelCaseValue] !== undefined ) {
  14922. found = object[camelCaseValue];
  14923. return false;
  14924. }
  14925. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  14926. object = object[value];
  14927. }
  14928. else if( object[value] !== undefined ) {
  14929. found = object[value];
  14930. return false;
  14931. }
  14932. else {
  14933. module.error(error.method, query);
  14934. return false;
  14935. }
  14936. });
  14937. }
  14938. if ( $.isFunction( found ) ) {
  14939. response = found.apply(context, passedArguments);
  14940. }
  14941. else if(found !== undefined) {
  14942. response = found;
  14943. }
  14944. if(Array.isArray(returnedValue)) {
  14945. returnedValue.push(response);
  14946. }
  14947. else if(returnedValue !== undefined) {
  14948. returnedValue = [returnedValue, response];
  14949. }
  14950. else if(response !== undefined) {
  14951. returnedValue = response;
  14952. }
  14953. return found;
  14954. }
  14955. };
  14956. if(methodInvoked) {
  14957. if(instance === undefined) {
  14958. module.initialize();
  14959. }
  14960. module.invoke(query);
  14961. }
  14962. else {
  14963. if(instance !== undefined) {
  14964. instance.invoke('destroy');
  14965. }
  14966. module.initialize();
  14967. }
  14968. })
  14969. ;
  14970. return (returnedValue !== undefined)
  14971. ? returnedValue
  14972. : this
  14973. ;
  14974. };
  14975. // shortcut for tabbed content with no defined navigation
  14976. $.tab = function() {
  14977. $(window).tab.apply(this, arguments);
  14978. };
  14979. $.fn.tab.settings = {
  14980. name : 'Tab',
  14981. namespace : 'tab',
  14982. silent : false,
  14983. debug : false,
  14984. verbose : false,
  14985. performance : true,
  14986. auto : false, // uses pjax style endpoints fetching content from same url with remote-content headers
  14987. history : false, // use browser history
  14988. historyType : 'hash', // #/ or html5 state
  14989. path : false, // base path of url
  14990. context : false, // specify a context that tabs must appear inside
  14991. childrenOnly : false, // use only tabs that are children of context
  14992. maxDepth : 25, // max depth a tab can be nested
  14993. deactivate : 'siblings', // whether tabs should deactivate sibling menu elements or all elements initialized together
  14994. alwaysRefresh : false, // load tab content new every tab click
  14995. cache : true, // cache the content requests to pull locally
  14996. loadOnce : false, // Whether tab data should only be loaded once when using remote content
  14997. cacheType : 'response', // Whether to cache exact response, or to html cache contents after scripts execute
  14998. ignoreFirstLoad : false, // don't load remote content on first load
  14999. apiSettings : false, // settings for api call
  15000. evaluateScripts : 'once', // whether inline scripts should be parsed (true/false/once). Once will not re-evaluate on cached content
  15001. autoTabActivation: true, // whether a non existing active tab will auto activate the first available tab
  15002. onFirstLoad : function(tabPath, parameterArray, historyEvent) {}, // called first time loaded
  15003. onLoad : function(tabPath, parameterArray, historyEvent) {}, // called on every load
  15004. onVisible : function(tabPath, parameterArray, historyEvent) {}, // called every time tab visible
  15005. onRequest : function(tabPath, parameterArray, historyEvent) {}, // called ever time a tab beings loading remote content
  15006. templates : {
  15007. determineTitle: function(tabArray) {} // returns page title for path
  15008. },
  15009. error: {
  15010. api : 'You attempted to load content without API module',
  15011. method : 'The method you called is not defined',
  15012. missingTab : 'Activated tab cannot be found. Tabs are case-sensitive.',
  15013. noContent : 'The tab you specified is missing a content url.',
  15014. path : 'History enabled, but no path was specified',
  15015. recursion : 'Max recursive depth reached',
  15016. legacyInit : 'onTabInit has been renamed to onFirstLoad in 2.0, please adjust your code.',
  15017. legacyLoad : 'onTabLoad has been renamed to onLoad in 2.0. Please adjust your code',
  15018. state : 'History requires Asual\'s Address library <https://github.com/asual/jquery-address>'
  15019. },
  15020. regExp : {
  15021. escape : /[-[\]{}()*+?.,\\^$|#\s:=@]/g
  15022. },
  15023. metadata : {
  15024. tab : 'tab',
  15025. loaded : 'loaded',
  15026. promise: 'promise'
  15027. },
  15028. className : {
  15029. loading : 'loading',
  15030. active : 'active'
  15031. },
  15032. selector : {
  15033. tabs : '.ui.tab',
  15034. ui : '.ui'
  15035. }
  15036. };
  15037. })( jQuery, window, document );
  15038. /*!
  15039. * # Fomantic-UI - Transition
  15040. * http://github.com/fomantic/Fomantic-UI/
  15041. *
  15042. *
  15043. * Released under the MIT license
  15044. * http://opensource.org/licenses/MIT
  15045. *
  15046. */
  15047. ;(function ($, window, document, undefined) {
  15048. 'use strict';
  15049. $.isFunction = $.isFunction || function(obj) {
  15050. return typeof obj === "function" && typeof obj.nodeType !== "number";
  15051. };
  15052. window = (typeof window != 'undefined' && window.Math == Math)
  15053. ? window
  15054. : (typeof self != 'undefined' && self.Math == Math)
  15055. ? self
  15056. : Function('return this')()
  15057. ;
  15058. $.fn.transition = function() {
  15059. var
  15060. $allModules = $(this),
  15061. moduleSelector = $allModules.selector || '',
  15062. time = new Date().getTime(),
  15063. performance = [],
  15064. moduleArguments = arguments,
  15065. query = moduleArguments[0],
  15066. queryArguments = [].slice.call(arguments, 1),
  15067. methodInvoked = (typeof query === 'string'),
  15068. returnedValue
  15069. ;
  15070. $allModules
  15071. .each(function(index) {
  15072. var
  15073. $module = $(this),
  15074. element = this,
  15075. // set at run time
  15076. settings,
  15077. instance,
  15078. error,
  15079. className,
  15080. metadata,
  15081. animationEnd,
  15082. moduleNamespace,
  15083. eventNamespace,
  15084. module
  15085. ;
  15086. module = {
  15087. initialize: function() {
  15088. // get full settings
  15089. settings = module.get.settings.apply(element, moduleArguments);
  15090. // shorthand
  15091. className = settings.className;
  15092. error = settings.error;
  15093. metadata = settings.metadata;
  15094. // define namespace
  15095. eventNamespace = '.' + settings.namespace;
  15096. moduleNamespace = 'module-' + settings.namespace;
  15097. instance = $module.data(moduleNamespace) || module;
  15098. // get vendor specific events
  15099. animationEnd = module.get.animationEndEvent();
  15100. if(methodInvoked) {
  15101. methodInvoked = module.invoke(query);
  15102. }
  15103. // method not invoked, lets run an animation
  15104. if(methodInvoked === false) {
  15105. module.verbose('Converted arguments into settings object', settings);
  15106. if(settings.interval) {
  15107. module.delay(settings.animate);
  15108. }
  15109. else {
  15110. module.animate();
  15111. }
  15112. module.instantiate();
  15113. }
  15114. },
  15115. instantiate: function() {
  15116. module.verbose('Storing instance of module', module);
  15117. instance = module;
  15118. $module
  15119. .data(moduleNamespace, instance)
  15120. ;
  15121. },
  15122. destroy: function() {
  15123. module.verbose('Destroying previous module for', element);
  15124. $module
  15125. .removeData(moduleNamespace)
  15126. ;
  15127. },
  15128. refresh: function() {
  15129. module.verbose('Refreshing display type on next animation');
  15130. delete module.displayType;
  15131. },
  15132. forceRepaint: function() {
  15133. module.verbose('Forcing element repaint');
  15134. var
  15135. $parentElement = $module.parent(),
  15136. $nextElement = $module.next()
  15137. ;
  15138. if($nextElement.length === 0) {
  15139. $module.detach().appendTo($parentElement);
  15140. }
  15141. else {
  15142. $module.detach().insertBefore($nextElement);
  15143. }
  15144. },
  15145. repaint: function() {
  15146. module.verbose('Repainting element');
  15147. var
  15148. fakeAssignment = element.offsetWidth
  15149. ;
  15150. },
  15151. delay: function(interval) {
  15152. var
  15153. direction = module.get.animationDirection(),
  15154. shouldReverse,
  15155. delay
  15156. ;
  15157. if(!direction) {
  15158. direction = module.can.transition()
  15159. ? module.get.direction()
  15160. : 'static'
  15161. ;
  15162. }
  15163. interval = (interval !== undefined)
  15164. ? interval
  15165. : settings.interval
  15166. ;
  15167. shouldReverse = (settings.reverse == 'auto' && direction == className.outward);
  15168. delay = (shouldReverse || settings.reverse == true)
  15169. ? ($allModules.length - index) * settings.interval
  15170. : index * settings.interval
  15171. ;
  15172. module.debug('Delaying animation by', delay);
  15173. setTimeout(module.animate, delay);
  15174. },
  15175. animate: function(overrideSettings) {
  15176. settings = overrideSettings || settings;
  15177. if(!module.is.supported()) {
  15178. module.error(error.support);
  15179. return false;
  15180. }
  15181. module.debug('Preparing animation', settings.animation);
  15182. if(module.is.animating()) {
  15183. if(settings.queue) {
  15184. if(!settings.allowRepeats && module.has.direction() && module.is.occurring() && module.queuing !== true) {
  15185. module.debug('Animation is currently occurring, preventing queueing same animation', settings.animation);
  15186. }
  15187. else {
  15188. module.queue(settings.animation);
  15189. }
  15190. return false;
  15191. }
  15192. else if(!settings.allowRepeats && module.is.occurring()) {
  15193. module.debug('Animation is already occurring, will not execute repeated animation', settings.animation);
  15194. return false;
  15195. }
  15196. else {
  15197. module.debug('New animation started, completing previous early', settings.animation);
  15198. instance.complete();
  15199. }
  15200. }
  15201. if( module.can.animate() ) {
  15202. module.set.animating(settings.animation);
  15203. }
  15204. else {
  15205. module.error(error.noAnimation, settings.animation, element);
  15206. }
  15207. },
  15208. reset: function() {
  15209. module.debug('Resetting animation to beginning conditions');
  15210. module.remove.animationCallbacks();
  15211. module.restore.conditions();
  15212. module.remove.animating();
  15213. },
  15214. queue: function(animation) {
  15215. module.debug('Queueing animation of', animation);
  15216. module.queuing = true;
  15217. $module
  15218. .one(animationEnd + '.queue' + eventNamespace, function() {
  15219. module.queuing = false;
  15220. module.repaint();
  15221. module.animate.apply(this, settings);
  15222. })
  15223. ;
  15224. },
  15225. complete: function (event) {
  15226. if(event && event.target === element) {
  15227. event.stopPropagation();
  15228. }
  15229. module.debug('Animation complete', settings.animation);
  15230. module.remove.completeCallback();
  15231. module.remove.failSafe();
  15232. if(!module.is.looping()) {
  15233. if( module.is.outward() ) {
  15234. module.verbose('Animation is outward, hiding element');
  15235. module.restore.conditions();
  15236. module.hide();
  15237. }
  15238. else if( module.is.inward() ) {
  15239. module.verbose('Animation is outward, showing element');
  15240. module.restore.conditions();
  15241. module.show();
  15242. }
  15243. else {
  15244. module.verbose('Static animation completed');
  15245. module.restore.conditions();
  15246. settings.onComplete.call(element);
  15247. }
  15248. }
  15249. },
  15250. force: {
  15251. visible: function() {
  15252. var
  15253. style = $module.attr('style'),
  15254. userStyle = module.get.userStyle(style),
  15255. displayType = module.get.displayType(),
  15256. overrideStyle = userStyle + 'display: ' + displayType + ' !important;',
  15257. inlineDisplay = $module[0].style.display,
  15258. mustStayHidden = !displayType || (inlineDisplay === 'none' && settings.skipInlineHidden) || $module[0].tagName.match(/(script|link|style)/i)
  15259. ;
  15260. if (mustStayHidden){
  15261. module.remove.transition();
  15262. return false;
  15263. }
  15264. module.verbose('Overriding default display to show element', displayType);
  15265. $module
  15266. .attr('style', overrideStyle)
  15267. ;
  15268. return true;
  15269. },
  15270. hidden: function() {
  15271. var
  15272. style = $module.attr('style'),
  15273. currentDisplay = $module.css('display'),
  15274. emptyStyle = (style === undefined || style === '')
  15275. ;
  15276. if(currentDisplay !== 'none' && !module.is.hidden()) {
  15277. module.verbose('Overriding default display to hide element');
  15278. $module
  15279. .css('display', 'none')
  15280. ;
  15281. }
  15282. else if(emptyStyle) {
  15283. $module
  15284. .removeAttr('style')
  15285. ;
  15286. }
  15287. }
  15288. },
  15289. has: {
  15290. direction: function(animation) {
  15291. var
  15292. hasDirection = false
  15293. ;
  15294. animation = animation || settings.animation;
  15295. if(typeof animation === 'string') {
  15296. animation = animation.split(' ');
  15297. $.each(animation, function(index, word){
  15298. if(word === className.inward || word === className.outward) {
  15299. hasDirection = true;
  15300. }
  15301. });
  15302. }
  15303. return hasDirection;
  15304. },
  15305. inlineDisplay: function() {
  15306. var
  15307. style = $module.attr('style') || ''
  15308. ;
  15309. return Array.isArray(style.match(/display.*?;/, ''));
  15310. }
  15311. },
  15312. set: {
  15313. animating: function(animation) {
  15314. // remove previous callbacks
  15315. module.remove.completeCallback();
  15316. // determine exact animation
  15317. animation = animation || settings.animation;
  15318. var animationClass = module.get.animationClass(animation);
  15319. // save animation class in cache to restore class names
  15320. module.save.animation(animationClass);
  15321. if(module.force.visible()) {
  15322. module.remove.hidden();
  15323. module.remove.direction();
  15324. module.start.animation(animationClass);
  15325. }
  15326. },
  15327. duration: function(animationName, duration) {
  15328. duration = duration || settings.duration;
  15329. duration = (typeof duration == 'number')
  15330. ? duration + 'ms'
  15331. : duration
  15332. ;
  15333. if(duration || duration === 0) {
  15334. module.verbose('Setting animation duration', duration);
  15335. $module
  15336. .css({
  15337. 'animation-duration': duration
  15338. })
  15339. ;
  15340. }
  15341. },
  15342. direction: function(direction) {
  15343. direction = direction || module.get.direction();
  15344. if(direction == className.inward) {
  15345. module.set.inward();
  15346. }
  15347. else {
  15348. module.set.outward();
  15349. }
  15350. },
  15351. looping: function() {
  15352. module.debug('Transition set to loop');
  15353. $module
  15354. .addClass(className.looping)
  15355. ;
  15356. },
  15357. hidden: function() {
  15358. $module
  15359. .addClass(className.transition)
  15360. .addClass(className.hidden)
  15361. ;
  15362. },
  15363. inward: function() {
  15364. module.debug('Setting direction to inward');
  15365. $module
  15366. .removeClass(className.outward)
  15367. .addClass(className.inward)
  15368. ;
  15369. },
  15370. outward: function() {
  15371. module.debug('Setting direction to outward');
  15372. $module
  15373. .removeClass(className.inward)
  15374. .addClass(className.outward)
  15375. ;
  15376. },
  15377. visible: function() {
  15378. $module
  15379. .addClass(className.transition)
  15380. .addClass(className.visible)
  15381. ;
  15382. }
  15383. },
  15384. start: {
  15385. animation: function(animationClass) {
  15386. animationClass = animationClass || module.get.animationClass();
  15387. module.debug('Starting tween', animationClass);
  15388. $module
  15389. .addClass(animationClass)
  15390. .one(animationEnd + '.complete' + eventNamespace, module.complete)
  15391. ;
  15392. if(settings.useFailSafe) {
  15393. module.add.failSafe();
  15394. }
  15395. module.set.duration(settings.duration);
  15396. settings.onStart.call(element);
  15397. }
  15398. },
  15399. save: {
  15400. animation: function(animation) {
  15401. if(!module.cache) {
  15402. module.cache = {};
  15403. }
  15404. module.cache.animation = animation;
  15405. },
  15406. displayType: function(displayType) {
  15407. if(displayType !== 'none') {
  15408. $module.data(metadata.displayType, displayType);
  15409. }
  15410. },
  15411. transitionExists: function(animation, exists) {
  15412. $.fn.transition.exists[animation] = exists;
  15413. module.verbose('Saving existence of transition', animation, exists);
  15414. }
  15415. },
  15416. restore: {
  15417. conditions: function() {
  15418. var
  15419. animation = module.get.currentAnimation()
  15420. ;
  15421. if(animation) {
  15422. $module
  15423. .removeClass(animation)
  15424. ;
  15425. module.verbose('Removing animation class', module.cache);
  15426. }
  15427. module.remove.duration();
  15428. }
  15429. },
  15430. add: {
  15431. failSafe: function() {
  15432. var
  15433. duration = module.get.duration()
  15434. ;
  15435. module.timer = setTimeout(function() {
  15436. $module.triggerHandler(animationEnd);
  15437. }, duration + settings.failSafeDelay);
  15438. module.verbose('Adding fail safe timer', module.timer);
  15439. }
  15440. },
  15441. remove: {
  15442. animating: function() {
  15443. $module.removeClass(className.animating);
  15444. },
  15445. animationCallbacks: function() {
  15446. module.remove.queueCallback();
  15447. module.remove.completeCallback();
  15448. },
  15449. queueCallback: function() {
  15450. $module.off('.queue' + eventNamespace);
  15451. },
  15452. completeCallback: function() {
  15453. $module.off('.complete' + eventNamespace);
  15454. },
  15455. display: function() {
  15456. $module.css('display', '');
  15457. },
  15458. direction: function() {
  15459. $module
  15460. .removeClass(className.inward)
  15461. .removeClass(className.outward)
  15462. ;
  15463. },
  15464. duration: function() {
  15465. $module
  15466. .css('animation-duration', '')
  15467. ;
  15468. },
  15469. failSafe: function() {
  15470. module.verbose('Removing fail safe timer', module.timer);
  15471. if(module.timer) {
  15472. clearTimeout(module.timer);
  15473. }
  15474. },
  15475. hidden: function() {
  15476. $module.removeClass(className.hidden);
  15477. },
  15478. visible: function() {
  15479. $module.removeClass(className.visible);
  15480. },
  15481. looping: function() {
  15482. module.debug('Transitions are no longer looping');
  15483. if( module.is.looping() ) {
  15484. module.reset();
  15485. $module
  15486. .removeClass(className.looping)
  15487. ;
  15488. }
  15489. },
  15490. transition: function() {
  15491. $module
  15492. .removeClass(className.transition)
  15493. .removeClass(className.visible)
  15494. .removeClass(className.hidden)
  15495. ;
  15496. }
  15497. },
  15498. get: {
  15499. settings: function(animation, duration, onComplete) {
  15500. // single settings object
  15501. if(typeof animation == 'object') {
  15502. return $.extend(true, {}, $.fn.transition.settings, animation);
  15503. }
  15504. // all arguments provided
  15505. else if(typeof onComplete == 'function') {
  15506. return $.extend({}, $.fn.transition.settings, {
  15507. animation : animation,
  15508. onComplete : onComplete,
  15509. duration : duration
  15510. });
  15511. }
  15512. // only duration provided
  15513. else if(typeof duration == 'string' || typeof duration == 'number') {
  15514. return $.extend({}, $.fn.transition.settings, {
  15515. animation : animation,
  15516. duration : duration
  15517. });
  15518. }
  15519. // duration is actually settings object
  15520. else if(typeof duration == 'object') {
  15521. return $.extend({}, $.fn.transition.settings, duration, {
  15522. animation : animation
  15523. });
  15524. }
  15525. // duration is actually callback
  15526. else if(typeof duration == 'function') {
  15527. return $.extend({}, $.fn.transition.settings, {
  15528. animation : animation,
  15529. onComplete : duration
  15530. });
  15531. }
  15532. // only animation provided
  15533. else {
  15534. return $.extend({}, $.fn.transition.settings, {
  15535. animation : animation
  15536. });
  15537. }
  15538. },
  15539. animationClass: function(animation) {
  15540. var
  15541. animationClass = animation || settings.animation,
  15542. directionClass = (module.can.transition() && !module.has.direction())
  15543. ? module.get.direction() + ' '
  15544. : ''
  15545. ;
  15546. return className.animating + ' '
  15547. + className.transition + ' '
  15548. + directionClass
  15549. + animationClass
  15550. ;
  15551. },
  15552. currentAnimation: function() {
  15553. return (module.cache && module.cache.animation !== undefined)
  15554. ? module.cache.animation
  15555. : false
  15556. ;
  15557. },
  15558. currentDirection: function() {
  15559. return module.is.inward()
  15560. ? className.inward
  15561. : className.outward
  15562. ;
  15563. },
  15564. direction: function() {
  15565. return module.is.hidden() || !module.is.visible()
  15566. ? className.inward
  15567. : className.outward
  15568. ;
  15569. },
  15570. animationDirection: function(animation) {
  15571. var
  15572. direction
  15573. ;
  15574. animation = animation || settings.animation;
  15575. if(typeof animation === 'string') {
  15576. animation = animation.split(' ');
  15577. // search animation name for out/in class
  15578. $.each(animation, function(index, word){
  15579. if(word === className.inward) {
  15580. direction = className.inward;
  15581. }
  15582. else if(word === className.outward) {
  15583. direction = className.outward;
  15584. }
  15585. });
  15586. }
  15587. // return found direction
  15588. if(direction) {
  15589. return direction;
  15590. }
  15591. return false;
  15592. },
  15593. duration: function(duration) {
  15594. duration = duration || settings.duration;
  15595. if(duration === false) {
  15596. duration = $module.css('animation-duration') || 0;
  15597. }
  15598. return (typeof duration === 'string')
  15599. ? (duration.indexOf('ms') > -1)
  15600. ? parseFloat(duration)
  15601. : parseFloat(duration) * 1000
  15602. : duration
  15603. ;
  15604. },
  15605. displayType: function(shouldDetermine) {
  15606. shouldDetermine = (shouldDetermine !== undefined)
  15607. ? shouldDetermine
  15608. : true
  15609. ;
  15610. if(settings.displayType) {
  15611. return settings.displayType;
  15612. }
  15613. if(shouldDetermine && $module.data(metadata.displayType) === undefined) {
  15614. var currentDisplay = $module.css('display');
  15615. if(currentDisplay === '' || currentDisplay === 'none'){
  15616. // create fake element to determine display state
  15617. module.can.transition(true);
  15618. } else {
  15619. module.save.displayType(currentDisplay);
  15620. }
  15621. }
  15622. return $module.data(metadata.displayType);
  15623. },
  15624. userStyle: function(style) {
  15625. style = style || $module.attr('style') || '';
  15626. return style.replace(/display.*?;/, '');
  15627. },
  15628. transitionExists: function(animation) {
  15629. return $.fn.transition.exists[animation];
  15630. },
  15631. animationStartEvent: function() {
  15632. var
  15633. element = document.createElement('div'),
  15634. animations = {
  15635. 'animation' :'animationstart',
  15636. 'OAnimation' :'oAnimationStart',
  15637. 'MozAnimation' :'mozAnimationStart',
  15638. 'WebkitAnimation' :'webkitAnimationStart'
  15639. },
  15640. animation
  15641. ;
  15642. for(animation in animations){
  15643. if( element.style[animation] !== undefined ){
  15644. return animations[animation];
  15645. }
  15646. }
  15647. return false;
  15648. },
  15649. animationEndEvent: function() {
  15650. var
  15651. element = document.createElement('div'),
  15652. animations = {
  15653. 'animation' :'animationend',
  15654. 'OAnimation' :'oAnimationEnd',
  15655. 'MozAnimation' :'mozAnimationEnd',
  15656. 'WebkitAnimation' :'webkitAnimationEnd'
  15657. },
  15658. animation
  15659. ;
  15660. for(animation in animations){
  15661. if( element.style[animation] !== undefined ){
  15662. return animations[animation];
  15663. }
  15664. }
  15665. return false;
  15666. }
  15667. },
  15668. can: {
  15669. transition: function(forced) {
  15670. var
  15671. animation = settings.animation,
  15672. transitionExists = module.get.transitionExists(animation),
  15673. displayType = module.get.displayType(false),
  15674. elementClass,
  15675. tagName,
  15676. $clone,
  15677. currentAnimation,
  15678. inAnimation,
  15679. directionExists
  15680. ;
  15681. if( transitionExists === undefined || forced) {
  15682. module.verbose('Determining whether animation exists');
  15683. elementClass = $module.attr('class');
  15684. tagName = $module.prop('tagName');
  15685. $clone = $('<' + tagName + ' />').addClass( elementClass ).insertAfter($module);
  15686. currentAnimation = $clone
  15687. .addClass(animation)
  15688. .removeClass(className.inward)
  15689. .removeClass(className.outward)
  15690. .addClass(className.animating)
  15691. .addClass(className.transition)
  15692. .css('animationName')
  15693. ;
  15694. inAnimation = $clone
  15695. .addClass(className.inward)
  15696. .css('animationName')
  15697. ;
  15698. if(!displayType) {
  15699. displayType = $clone
  15700. .attr('class', elementClass)
  15701. .removeAttr('style')
  15702. .removeClass(className.hidden)
  15703. .removeClass(className.visible)
  15704. .show()
  15705. .css('display')
  15706. ;
  15707. module.verbose('Determining final display state', displayType);
  15708. module.save.displayType(displayType);
  15709. }
  15710. $clone.remove();
  15711. if(currentAnimation != inAnimation) {
  15712. module.debug('Direction exists for animation', animation);
  15713. directionExists = true;
  15714. }
  15715. else if(currentAnimation == 'none' || !currentAnimation) {
  15716. module.debug('No animation defined in css', animation);
  15717. return;
  15718. }
  15719. else {
  15720. module.debug('Static animation found', animation, displayType);
  15721. directionExists = false;
  15722. }
  15723. module.save.transitionExists(animation, directionExists);
  15724. }
  15725. return (transitionExists !== undefined)
  15726. ? transitionExists
  15727. : directionExists
  15728. ;
  15729. },
  15730. animate: function() {
  15731. // can transition does not return a value if animation does not exist
  15732. return (module.can.transition() !== undefined);
  15733. }
  15734. },
  15735. is: {
  15736. animating: function() {
  15737. return $module.hasClass(className.animating);
  15738. },
  15739. inward: function() {
  15740. return $module.hasClass(className.inward);
  15741. },
  15742. outward: function() {
  15743. return $module.hasClass(className.outward);
  15744. },
  15745. looping: function() {
  15746. return $module.hasClass(className.looping);
  15747. },
  15748. occurring: function(animation) {
  15749. animation = animation || settings.animation;
  15750. animation = '.' + animation.replace(' ', '.');
  15751. return ( $module.filter(animation).length > 0 );
  15752. },
  15753. visible: function() {
  15754. return $module.is(':visible');
  15755. },
  15756. hidden: function() {
  15757. return $module.css('visibility') === 'hidden';
  15758. },
  15759. supported: function() {
  15760. return(animationEnd !== false);
  15761. }
  15762. },
  15763. hide: function() {
  15764. module.verbose('Hiding element');
  15765. if( module.is.animating() ) {
  15766. module.reset();
  15767. }
  15768. element.blur(); // IE will trigger focus change if element is not blurred before hiding
  15769. module.remove.display();
  15770. module.remove.visible();
  15771. if($.isFunction(settings.onBeforeHide)){
  15772. settings.onBeforeHide.call(element,function(){
  15773. module.hideNow();
  15774. });
  15775. } else {
  15776. module.hideNow();
  15777. }
  15778. },
  15779. hideNow: function() {
  15780. module.set.hidden();
  15781. module.force.hidden();
  15782. settings.onHide.call(element);
  15783. settings.onComplete.call(element);
  15784. // module.repaint();
  15785. },
  15786. show: function(display) {
  15787. module.verbose('Showing element', display);
  15788. if(module.force.visible()) {
  15789. module.remove.hidden();
  15790. module.set.visible();
  15791. settings.onShow.call(element);
  15792. settings.onComplete.call(element);
  15793. // module.repaint();
  15794. }
  15795. },
  15796. toggle: function() {
  15797. if( module.is.visible() ) {
  15798. module.hide();
  15799. }
  15800. else {
  15801. module.show();
  15802. }
  15803. },
  15804. stop: function() {
  15805. module.debug('Stopping current animation');
  15806. $module.triggerHandler(animationEnd);
  15807. },
  15808. stopAll: function() {
  15809. module.debug('Stopping all animation');
  15810. module.remove.queueCallback();
  15811. $module.triggerHandler(animationEnd);
  15812. },
  15813. clear: {
  15814. queue: function() {
  15815. module.debug('Clearing animation queue');
  15816. module.remove.queueCallback();
  15817. }
  15818. },
  15819. enable: function() {
  15820. module.verbose('Starting animation');
  15821. $module.removeClass(className.disabled);
  15822. },
  15823. disable: function() {
  15824. module.debug('Stopping animation');
  15825. $module.addClass(className.disabled);
  15826. },
  15827. setting: function(name, value) {
  15828. module.debug('Changing setting', name, value);
  15829. if( $.isPlainObject(name) ) {
  15830. $.extend(true, settings, name);
  15831. }
  15832. else if(value !== undefined) {
  15833. if($.isPlainObject(settings[name])) {
  15834. $.extend(true, settings[name], value);
  15835. }
  15836. else {
  15837. settings[name] = value;
  15838. }
  15839. }
  15840. else {
  15841. return settings[name];
  15842. }
  15843. },
  15844. internal: function(name, value) {
  15845. if( $.isPlainObject(name) ) {
  15846. $.extend(true, module, name);
  15847. }
  15848. else if(value !== undefined) {
  15849. module[name] = value;
  15850. }
  15851. else {
  15852. return module[name];
  15853. }
  15854. },
  15855. debug: function() {
  15856. if(!settings.silent && settings.debug) {
  15857. if(settings.performance) {
  15858. module.performance.log(arguments);
  15859. }
  15860. else {
  15861. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  15862. module.debug.apply(console, arguments);
  15863. }
  15864. }
  15865. },
  15866. verbose: function() {
  15867. if(!settings.silent && settings.verbose && settings.debug) {
  15868. if(settings.performance) {
  15869. module.performance.log(arguments);
  15870. }
  15871. else {
  15872. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  15873. module.verbose.apply(console, arguments);
  15874. }
  15875. }
  15876. },
  15877. error: function() {
  15878. if(!settings.silent) {
  15879. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  15880. module.error.apply(console, arguments);
  15881. }
  15882. },
  15883. performance: {
  15884. log: function(message) {
  15885. var
  15886. currentTime,
  15887. executionTime,
  15888. previousTime
  15889. ;
  15890. if(settings.performance) {
  15891. currentTime = new Date().getTime();
  15892. previousTime = time || currentTime;
  15893. executionTime = currentTime - previousTime;
  15894. time = currentTime;
  15895. performance.push({
  15896. 'Name' : message[0],
  15897. 'Arguments' : [].slice.call(message, 1) || '',
  15898. 'Element' : element,
  15899. 'Execution Time' : executionTime
  15900. });
  15901. }
  15902. clearTimeout(module.performance.timer);
  15903. module.performance.timer = setTimeout(module.performance.display, 500);
  15904. },
  15905. display: function() {
  15906. var
  15907. title = settings.name + ':',
  15908. totalTime = 0
  15909. ;
  15910. time = false;
  15911. clearTimeout(module.performance.timer);
  15912. $.each(performance, function(index, data) {
  15913. totalTime += data['Execution Time'];
  15914. });
  15915. title += ' ' + totalTime + 'ms';
  15916. if(moduleSelector) {
  15917. title += ' \'' + moduleSelector + '\'';
  15918. }
  15919. if($allModules.length > 1) {
  15920. title += ' ' + '(' + $allModules.length + ')';
  15921. }
  15922. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  15923. console.groupCollapsed(title);
  15924. if(console.table) {
  15925. console.table(performance);
  15926. }
  15927. else {
  15928. $.each(performance, function(index, data) {
  15929. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  15930. });
  15931. }
  15932. console.groupEnd();
  15933. }
  15934. performance = [];
  15935. }
  15936. },
  15937. // modified for transition to return invoke success
  15938. invoke: function(query, passedArguments, context) {
  15939. var
  15940. object = instance,
  15941. maxDepth,
  15942. found,
  15943. response
  15944. ;
  15945. passedArguments = passedArguments || queryArguments;
  15946. context = element || context;
  15947. if(typeof query == 'string' && object !== undefined) {
  15948. query = query.split(/[\. ]/);
  15949. maxDepth = query.length - 1;
  15950. $.each(query, function(depth, value) {
  15951. var camelCaseValue = (depth != maxDepth)
  15952. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  15953. : query
  15954. ;
  15955. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  15956. object = object[camelCaseValue];
  15957. }
  15958. else if( object[camelCaseValue] !== undefined ) {
  15959. found = object[camelCaseValue];
  15960. return false;
  15961. }
  15962. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  15963. object = object[value];
  15964. }
  15965. else if( object[value] !== undefined ) {
  15966. found = object[value];
  15967. return false;
  15968. }
  15969. else {
  15970. return false;
  15971. }
  15972. });
  15973. }
  15974. if ( $.isFunction( found ) ) {
  15975. response = found.apply(context, passedArguments);
  15976. }
  15977. else if(found !== undefined) {
  15978. response = found;
  15979. }
  15980. if(Array.isArray(returnedValue)) {
  15981. returnedValue.push(response);
  15982. }
  15983. else if(returnedValue !== undefined) {
  15984. returnedValue = [returnedValue, response];
  15985. }
  15986. else if(response !== undefined) {
  15987. returnedValue = response;
  15988. }
  15989. return (found !== undefined)
  15990. ? found
  15991. : false
  15992. ;
  15993. }
  15994. };
  15995. module.initialize();
  15996. })
  15997. ;
  15998. return (returnedValue !== undefined)
  15999. ? returnedValue
  16000. : this
  16001. ;
  16002. };
  16003. // Records if CSS transition is available
  16004. $.fn.transition.exists = {};
  16005. $.fn.transition.settings = {
  16006. // module info
  16007. name : 'Transition',
  16008. // hide all output from this component regardless of other settings
  16009. silent : false,
  16010. // debug content outputted to console
  16011. debug : false,
  16012. // verbose debug output
  16013. verbose : false,
  16014. // performance data output
  16015. performance : true,
  16016. // event namespace
  16017. namespace : 'transition',
  16018. // delay between animations in group
  16019. interval : 0,
  16020. // whether group animations should be reversed
  16021. reverse : 'auto',
  16022. // animation callback event
  16023. onStart : function() {},
  16024. onComplete : function() {},
  16025. onShow : function() {},
  16026. onHide : function() {},
  16027. // whether timeout should be used to ensure callback fires in cases animationend does not
  16028. useFailSafe : true,
  16029. // delay in ms for fail safe
  16030. failSafeDelay : 100,
  16031. // whether EXACT animation can occur twice in a row
  16032. allowRepeats : false,
  16033. // Override final display type on visible
  16034. displayType : false,
  16035. // animation duration
  16036. animation : 'fade',
  16037. duration : false,
  16038. // new animations will occur after previous ones
  16039. queue : true,
  16040. // whether initially inline hidden objects should be skipped for transition
  16041. skipInlineHidden: false,
  16042. metadata : {
  16043. displayType: 'display'
  16044. },
  16045. className : {
  16046. animating : 'animating',
  16047. disabled : 'disabled',
  16048. hidden : 'hidden',
  16049. inward : 'in',
  16050. loading : 'loading',
  16051. looping : 'looping',
  16052. outward : 'out',
  16053. transition : 'transition',
  16054. visible : 'visible'
  16055. },
  16056. // possible errors
  16057. error: {
  16058. noAnimation : 'Element is no longer attached to DOM. Unable to animate. Use silent setting to surpress this warning in production.',
  16059. repeated : 'That animation is already occurring, cancelling repeated animation',
  16060. method : 'The method you called is not defined',
  16061. support : 'This browser does not support CSS animations'
  16062. }
  16063. };
  16064. })( jQuery, window, document );