12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955 |
- /*!
- * Bootstrap-select v1.13.9 (https://developer.snapappointments.com/bootstrap-select)
- *
- * Copyright 2012-2019 SnapAppointments, LLC
- * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
- */
- (function (root, factory) {
- if (root === undefined && window !== undefined) root = window;
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module unless amdModuleId is set
- define(["jquery"], function (a0) {
- return (factory(a0));
- });
- } else if (typeof module === 'object' && module.exports) {
- // Node. Does not work with strict CommonJS, but
- // only CommonJS-like environments that support module.exports,
- // like Node.
- module.exports = factory(require("jquery"));
- } else {
- factory(root["jQuery"]);
- }
- }(this, function (jQuery) {
- (function ($) {
- 'use strict';
- var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];
- var uriAttrs = [
- 'background',
- 'cite',
- 'href',
- 'itemtype',
- 'longdesc',
- 'poster',
- 'src',
- 'xlink:href'
- ];
- var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
- var DefaultWhitelist = {
- // Global attributes allowed on any supplied element below.
- '*': ['class', 'dir', 'id', 'lang', 'role', 'tabindex', 'style', ARIA_ATTRIBUTE_PATTERN],
- a: ['target', 'href', 'title', 'rel'],
- area: [],
- b: [],
- br: [],
- col: [],
- code: [],
- div: [],
- em: [],
- hr: [],
- h1: [],
- h2: [],
- h3: [],
- h4: [],
- h5: [],
- h6: [],
- i: [],
- img: ['src', 'alt', 'title', 'width', 'height'],
- li: [],
- ol: [],
- p: [],
- pre: [],
- s: [],
- small: [],
- span: [],
- sub: [],
- sup: [],
- strong: [],
- u: [],
- ul: []
- }
- /**
- * A pattern that recognizes a commonly useful subset of URLs that are safe.
- *
- * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
- */
- var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;
- /**
- * A pattern that matches safe data URLs. Only matches image, video and audio types.
- *
- * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
- */
- var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
- function allowedAttribute (attr, allowedAttributeList) {
- var attrName = attr.nodeName.toLowerCase()
- if ($.inArray(attrName, allowedAttributeList) !== -1) {
- if ($.inArray(attrName, uriAttrs) !== -1) {
- return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
- }
- return true
- }
- var regExp = $(allowedAttributeList).filter(function (index, value) {
- return value instanceof RegExp
- })
- // Check if a regular expression validates the attribute.
- for (var i = 0, l = regExp.length; i < l; i++) {
- if (attrName.match(regExp[i])) {
- return true
- }
- }
- return false
- }
- function sanitizeHtml (unsafeElements, whiteList, sanitizeFn) {
- if (sanitizeFn && typeof sanitizeFn === 'function') {
- return sanitizeFn(unsafeElements);
- }
- var whitelistKeys = Object.keys(whiteList);
- for (var i = 0, len = unsafeElements.length; i < len; i++) {
- var elements = unsafeElements[i].querySelectorAll('*');
- for (var j = 0, len2 = elements.length; j < len2; j++) {
- var el = elements[j];
- var elName = el.nodeName.toLowerCase();
- if (whitelistKeys.indexOf(elName) === -1) {
- el.parentNode.removeChild(el);
- continue;
- }
- var attributeList = [].slice.call(el.attributes);
- var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);
- for (var k = 0, len3 = attributeList.length; k < len3; k++) {
- var attr = attributeList[k];
- if (!allowedAttribute(attr, whitelistedAttributes)) {
- el.removeAttribute(attr.nodeName);
- }
- }
- }
- }
- }
- // Polyfill for browsers with no classList support
- // Remove in v2
- if (!('classList' in document.createElement('_'))) {
- (function (view) {
- if (!('Element' in view)) return;
- var classListProp = 'classList',
- protoProp = 'prototype',
- elemCtrProto = view.Element[protoProp],
- objCtr = Object,
- classListGetter = function () {
- var $elem = $(this);
- return {
- add: function (classes) {
- classes = Array.prototype.slice.call(arguments).join(' ');
- return $elem.addClass(classes);
- },
- remove: function (classes) {
- classes = Array.prototype.slice.call(arguments).join(' ');
- return $elem.removeClass(classes);
- },
- toggle: function (classes, force) {
- return $elem.toggleClass(classes, force);
- },
- contains: function (classes) {
- return $elem.hasClass(classes);
- }
- }
- };
- if (objCtr.defineProperty) {
- var classListPropDesc = {
- get: classListGetter,
- enumerable: true,
- configurable: true
- };
- try {
- objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
- } catch (ex) { // IE 8 doesn't support enumerable:true
- // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
- // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
- if (ex.number === undefined || ex.number === -0x7FF5EC54) {
- classListPropDesc.enumerable = false;
- objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
- }
- }
- } else if (objCtr[protoProp].__defineGetter__) {
- elemCtrProto.__defineGetter__(classListProp, classListGetter);
- }
- }(window));
- }
- var testElement = document.createElement('_');
- testElement.classList.add('c1', 'c2');
- if (!testElement.classList.contains('c2')) {
- var _add = DOMTokenList.prototype.add,
- _remove = DOMTokenList.prototype.remove;
- DOMTokenList.prototype.add = function () {
- Array.prototype.forEach.call(arguments, _add.bind(this));
- }
- DOMTokenList.prototype.remove = function () {
- Array.prototype.forEach.call(arguments, _remove.bind(this));
- }
- }
- testElement.classList.toggle('c3', false);
- // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
- // support the second argument.
- if (testElement.classList.contains('c3')) {
- var _toggle = DOMTokenList.prototype.toggle;
- DOMTokenList.prototype.toggle = function (token, force) {
- if (1 in arguments && !this.contains(token) === !force) {
- return force;
- } else {
- return _toggle.call(this, token);
- }
- };
- }
- testElement = null;
- // shallow array comparison
- function isEqual (array1, array2) {
- return array1.length === array2.length && array1.every(function (element, index) {
- return element === array2[index];
- });
- };
- // <editor-fold desc="Shims">
- if (!String.prototype.startsWith) {
- (function () {
- 'use strict';
- var defineProperty = (function () {
- try {
- var object = {};
- var $defineProperty = Object.defineProperty;
- var result = $defineProperty(object, object, object) && $defineProperty;
- } catch (error) {
- }
- return result;
- }());
- var toString = {}.toString;
- var startsWith = function (search) {
- if (this == null) {
- throw new TypeError();
- }
- var string = String(this);
- if (search && toString.call(search) == '[object RegExp]') {
- throw new TypeError();
- }
- var stringLength = string.length;
- var searchString = String(search);
- var searchLength = searchString.length;
- var position = arguments.length > 1 ? arguments[1] : undefined;
- var pos = position ? Number(position) : 0;
- if (pos != pos) {
- pos = 0;
- }
- var start = Math.min(Math.max(pos, 0), stringLength);
- if (searchLength + start > stringLength) {
- return false;
- }
- var index = -1;
- while (++index < searchLength) {
- if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
- return false;
- }
- }
- return true;
- };
- if (defineProperty) {
- defineProperty(String.prototype, 'startsWith', {
- 'value': startsWith,
- 'configurable': true,
- 'writable': true
- });
- } else {
- String.prototype.startsWith = startsWith;
- }
- }());
- }
- if (!Object.keys) {
- Object.keys = function (
- o, // object
- k, // key
- r // result array
- ) {
- // initialize object and result
- r = [];
- // iterate over object keys
- for (k in o) {
- // fill result array with non-prototypical keys
- r.hasOwnProperty.call(o, k) && r.push(k);
- }
- // return result
- return r;
- };
- }
- if (HTMLSelectElement && !HTMLSelectElement.prototype.hasOwnProperty('selectedOptions')) {
- Object.defineProperty(HTMLSelectElement.prototype, 'selectedOptions', {
- get: function () {
- return this.querySelectorAll(':checked');
- }
- });
- }
- // much faster than $.val()
- function getSelectValues (select) {
- var result = [];
- var options = select.selectedOptions;
- var opt;
- if (select.multiple) {
- for (var i = 0, len = options.length; i < len; i++) {
- opt = options[i];
- result.push(opt.value || opt.text);
- }
- } else {
- result = select.value;
- }
- return result;
- }
- // set data-selected on select element if the value has been programmatically selected
- // prior to initialization of bootstrap-select
- // * consider removing or replacing an alternative method *
- var valHooks = {
- useDefault: false,
- _set: $.valHooks.select.set
- };
- $.valHooks.select.set = function (elem, value) {
- if (value && !valHooks.useDefault) $(elem).data('selected', true);
- return valHooks._set.apply(this, arguments);
- };
- var changedArguments = null;
- var EventIsSupported = (function () {
- try {
- new Event('change');
- return true;
- } catch (e) {
- return false;
- }
- })();
- $.fn.triggerNative = function (eventName) {
- var el = this[0],
- event;
- if (el.dispatchEvent) { // for modern browsers & IE9+
- if (EventIsSupported) {
- // For modern browsers
- event = new Event(eventName, {
- bubbles: true
- });
- } else {
- // For IE since it doesn't support Event constructor
- event = document.createEvent('Event');
- event.initEvent(eventName, true, false);
- }
- el.dispatchEvent(event);
- } else if (el.fireEvent) { // for IE8
- event = document.createEventObject();
- event.eventType = eventName;
- el.fireEvent('on' + eventName, event);
- } else {
- // fall back to jQuery.trigger
- this.trigger(eventName);
- }
- };
- // </editor-fold>
- function stringSearch (li, searchString, method, normalize) {
- var stringTypes = [
- 'display',
- 'subtext',
- 'tokens'
- ],
- searchSuccess = false;
- for (var i = 0; i < stringTypes.length; i++) {
- var stringType = stringTypes[i],
- string = li[stringType];
- if (string) {
- string = string.toString();
- // Strip HTML tags. This isn't perfect, but it's much faster than any other method
- if (stringType === 'display') {
- string = string.replace(/<[^>]+>/g, '');
- }
- if (normalize) string = normalizeToBase(string);
- string = string.toUpperCase();
- if (method === 'contains') {
- searchSuccess = string.indexOf(searchString) >= 0;
- } else {
- searchSuccess = string.startsWith(searchString);
- }
- if (searchSuccess) break;
- }
- }
- return searchSuccess;
- }
- function toInteger (value) {
- return parseInt(value, 10) || 0;
- }
- // Borrowed from Lodash (_.deburr)
- /** Used to map Latin Unicode letters to basic Latin letters. */
- var deburredLetters = {
- // Latin-1 Supplement block.
- '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
- '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
- '\xc7': 'C', '\xe7': 'c',
- '\xd0': 'D', '\xf0': 'd',
- '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
- '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
- '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
- '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
- '\xd1': 'N', '\xf1': 'n',
- '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
- '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
- '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
- '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
- '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
- '\xc6': 'Ae', '\xe6': 'ae',
- '\xde': 'Th', '\xfe': 'th',
- '\xdf': 'ss',
- // Latin Extended-A block.
- '\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
- '\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
- '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
- '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
- '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
- '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
- '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
- '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
- '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
- '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
- '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
- '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
- '\u0134': 'J', '\u0135': 'j',
- '\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
- '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
- '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
- '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
- '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
- '\u014c': 'O', '\u014e': 'O', '\u0150': 'O',
- '\u014d': 'o', '\u014f': 'o', '\u0151': 'o',
- '\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
- '\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
- '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
- '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's',
- '\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
- '\u0163': 't', '\u0165': 't', '\u0167': 't',
- '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
- '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
- '\u0174': 'W', '\u0175': 'w',
- '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
- '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z',
- '\u017a': 'z', '\u017c': 'z', '\u017e': 'z',
- '\u0132': 'IJ', '\u0133': 'ij',
- '\u0152': 'Oe', '\u0153': 'oe',
- '\u0149': "'n", '\u017f': 's'
- };
- /** Used to match Latin Unicode letters (excluding mathematical operators). */
- var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
- /** Used to compose unicode character classes. */
- var rsComboMarksRange = '\\u0300-\\u036f',
- reComboHalfMarksRange = '\\ufe20-\\ufe2f',
- rsComboSymbolsRange = '\\u20d0-\\u20ff',
- rsComboMarksExtendedRange = '\\u1ab0-\\u1aff',
- rsComboMarksSupplementRange = '\\u1dc0-\\u1dff',
- rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange;
- /** Used to compose unicode capture groups. */
- var rsCombo = '[' + rsComboRange + ']';
- /**
- * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
- * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
- */
- var reComboMark = RegExp(rsCombo, 'g');
- function deburrLetter (key) {
- return deburredLetters[key];
- };
- function normalizeToBase (string) {
- string = string.toString();
- return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
- }
- // List of HTML entities for escaping.
- var escapeMap = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
- };
- escapeMap[String.fromCharCode(96)] = '`';
- // Functions for escaping and unescaping strings to/from HTML interpolation.
- var createEscaper = function (map) {
- var escaper = function (match) {
- return map[match];
- };
- // Regexes for identifying a key that needs to be escaped.
- var source = '(?:' + Object.keys(map).join('|') + ')';
- var testRegexp = RegExp(source);
- var replaceRegexp = RegExp(source, 'g');
- return function (string) {
- string = string == null ? '' : '' + string;
- return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
- };
- };
- var htmlEscape = createEscaper(escapeMap);
- /**
- * ------------------------------------------------------------------------
- * Constants
- * ------------------------------------------------------------------------
- */
- var keyCodeMap = {
- 32: ' ',
- 48: '0',
- 49: '1',
- 50: '2',
- 51: '3',
- 52: '4',
- 53: '5',
- 54: '6',
- 55: '7',
- 56: '8',
- 57: '9',
- 59: ';',
- 65: 'A',
- 66: 'B',
- 67: 'C',
- 68: 'D',
- 69: 'E',
- 70: 'F',
- 71: 'G',
- 72: 'H',
- 73: 'I',
- 74: 'J',
- 75: 'K',
- 76: 'L',
- 77: 'M',
- 78: 'N',
- 79: 'O',
- 80: 'P',
- 81: 'Q',
- 82: 'R',
- 83: 'S',
- 84: 'T',
- 85: 'U',
- 86: 'V',
- 87: 'W',
- 88: 'X',
- 89: 'Y',
- 90: 'Z',
- 96: '0',
- 97: '1',
- 98: '2',
- 99: '3',
- 100: '4',
- 101: '5',
- 102: '6',
- 103: '7',
- 104: '8',
- 105: '9'
- };
- var keyCodes = {
- ESCAPE: 27, // KeyboardEvent.which value for Escape (Esc) key
- ENTER: 13, // KeyboardEvent.which value for Enter key
- SPACE: 32, // KeyboardEvent.which value for space key
- TAB: 9, // KeyboardEvent.which value for tab key
- ARROW_UP: 38, // KeyboardEvent.which value for up arrow key
- ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key
- }
- var version = {
- success: false,
- major: '3'
- };
- try {
- version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.');
- version.major = version.full[0];
- version.success = true;
- } catch (err) {
- // do nothing
- }
- var selectId = 0;
- var EVENT_KEY = '.bs.select';
- var classNames = {
- DISABLED: 'disabled',
- DIVIDER: 'divider',
- SHOW: 'open',
- DROPUP: 'dropup',
- MENU: 'dropdown-menu',
- MENURIGHT: 'dropdown-menu-right',
- MENULEFT: 'dropdown-menu-left',
- // to-do: replace with more advanced template/customization options
- BUTTONCLASS: 'btn-default',
- POPOVERHEADER: 'popover-title',
- ICONBASE: 'glyphicon',
- TICKICON: 'glyphicon-ok'
- }
- var Selector = {
- MENU: '.' + classNames.MENU
- }
- var elementTemplates = {
- span: document.createElement('span'),
- i: document.createElement('i'),
- subtext: document.createElement('small'),
- a: document.createElement('a'),
- li: document.createElement('li'),
- whitespace: document.createTextNode('\u00A0'),
- fragment: document.createDocumentFragment()
- }
- elementTemplates.a.setAttribute('role', 'option');
- elementTemplates.subtext.className = 'text-muted';
- elementTemplates.text = elementTemplates.span.cloneNode(false);
- elementTemplates.text.className = 'text';
- elementTemplates.checkMark = elementTemplates.span.cloneNode(false);
- var REGEXP_ARROW = new RegExp(keyCodes.ARROW_UP + '|' + keyCodes.ARROW_DOWN);
- var REGEXP_TAB_OR_ESCAPE = new RegExp('^' + keyCodes.TAB + '$|' + keyCodes.ESCAPE);
- var generateOption = {
- li: function (content, classes, optgroup) {
- var li = elementTemplates.li.cloneNode(false);
- if (content) {
- if (content.nodeType === 1 || content.nodeType === 11) {
- li.appendChild(content);
- } else {
- li.innerHTML = content;
- }
- }
- if (typeof classes !== 'undefined' && classes !== '') li.className = classes;
- if (typeof optgroup !== 'undefined' && optgroup !== null) li.classList.add('optgroup-' + optgroup);
- return li;
- },
- a: function (text, classes, inline) {
- var a = elementTemplates.a.cloneNode(true);
- if (text) {
- if (text.nodeType === 11) {
- a.appendChild(text);
- } else {
- a.insertAdjacentHTML('beforeend', text);
- }
- }
- if (typeof classes !== 'undefined' && classes !== '') a.className = classes;
- if (version.major === '4') a.classList.add('dropdown-item');
- if (inline) a.setAttribute('style', inline);
- return a;
- },
- text: function (options, useFragment) {
- var textElement = elementTemplates.text.cloneNode(false),
- subtextElement,
- iconElement;
- if (options.content) {
- textElement.innerHTML = options.content;
- } else {
- textElement.textContent = options.text;
- if (options.icon) {
- var whitespace = elementTemplates.whitespace.cloneNode(false);
- // need to use <i> for icons in the button to prevent a breaking change
- // note: switch to span in next major release
- iconElement = (useFragment === true ? elementTemplates.i : elementTemplates.span).cloneNode(false);
- iconElement.className = options.iconBase + ' ' + options.icon;
- elementTemplates.fragment.appendChild(iconElement);
- elementTemplates.fragment.appendChild(whitespace);
- }
- if (options.subtext) {
- subtextElement = elementTemplates.subtext.cloneNode(false);
- subtextElement.textContent = options.subtext;
- textElement.appendChild(subtextElement);
- }
- }
- if (useFragment === true) {
- while (textElement.childNodes.length > 0) {
- elementTemplates.fragment.appendChild(textElement.childNodes[0]);
- }
- } else {
- elementTemplates.fragment.appendChild(textElement);
- }
- return elementTemplates.fragment;
- },
- label: function (options) {
- var textElement = elementTemplates.text.cloneNode(false),
- subtextElement,
- iconElement;
- textElement.innerHTML = options.label;
- if (options.icon) {
- var whitespace = elementTemplates.whitespace.cloneNode(false);
- iconElement = elementTemplates.span.cloneNode(false);
- iconElement.className = options.iconBase + ' ' + options.icon;
- elementTemplates.fragment.appendChild(iconElement);
- elementTemplates.fragment.appendChild(whitespace);
- }
- if (options.subtext) {
- subtextElement = elementTemplates.subtext.cloneNode(false);
- subtextElement.textContent = options.subtext;
- textElement.appendChild(subtextElement);
- }
- elementTemplates.fragment.appendChild(textElement);
- return elementTemplates.fragment;
- }
- }
- var Selectpicker = function (element, options) {
- var that = this;
- // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
- if (!valHooks.useDefault) {
- $.valHooks.select.set = valHooks._set;
- valHooks.useDefault = true;
- }
- this.$element = $(element);
- this.$newElement = null;
- this.$button = null;
- this.$menu = null;
- this.options = options;
- this.selectpicker = {
- main: {},
- current: {}, // current changes if a search is in progress
- search: {},
- view: {},
- keydown: {
- keyHistory: '',
- resetKeyHistory: {
- start: function () {
- return setTimeout(function () {
- that.selectpicker.keydown.keyHistory = '';
- }, 800);
- }
- }
- }
- };
- // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a
- // data-attribute)
- if (this.options.title === null) {
- this.options.title = this.$element.attr('title');
- }
- // Format window padding
- var winPad = this.options.windowPadding;
- if (typeof winPad === 'number') {
- this.options.windowPadding = [winPad, winPad, winPad, winPad];
- }
- // Expose public methods
- this.val = Selectpicker.prototype.val;
- this.render = Selectpicker.prototype.render;
- this.refresh = Selectpicker.prototype.refresh;
- this.setStyle = Selectpicker.prototype.setStyle;
- this.selectAll = Selectpicker.prototype.selectAll;
- this.deselectAll = Selectpicker.prototype.deselectAll;
- this.destroy = Selectpicker.prototype.destroy;
- this.remove = Selectpicker.prototype.remove;
- this.show = Selectpicker.prototype.show;
- this.hide = Selectpicker.prototype.hide;
- this.init();
- };
- Selectpicker.VERSION = '1.13.9';
- // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
- Selectpicker.DEFAULTS = {
- noneSelectedText: 'Nothing selected',
- noneResultsText: 'No results matched {0}',
- countSelectedText: function (numSelected, numTotal) {
- return (numSelected == 1) ? '{0} item selected' : '{0} items selected';
- },
- maxOptionsText: function (numAll, numGroup) {
- return [
- (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
- (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
- ];
- },
- selectAllText: 'Select All',
- deselectAllText: 'Deselect All',
- doneButton: false,
- doneButtonText: 'Close',
- multipleSeparator: ', ',
- styleBase: 'btn',
- style: classNames.BUTTONCLASS,
- size: 'auto',
- title: null,
- selectedTextFormat: 'values',
- width: false,
- container: false,
- hideDisabled: false,
- showSubtext: false,
- showIcon: true,
- showContent: true,
- dropupAuto: true,
- header: false,
- liveSearch: false,
- liveSearchPlaceholder: null,
- liveSearchNormalize: false,
- liveSearchStyle: 'contains',
- actionsBox: false,
- iconBase: classNames.ICONBASE,
- tickIcon: classNames.TICKICON,
- showTick: false,
- template: {
- caret: '<span class="caret"></span>'
- },
- maxOptions: false,
- mobile: false,
- selectOnTab: false,
- dropdownAlignRight: false,
- windowPadding: 0,
- virtualScroll: 600,
- display: false,
- sanitize: true,
- sanitizeFn: null,
- whiteList: DefaultWhitelist
- };
- Selectpicker.prototype = {
- constructor: Selectpicker,
- init: function () {
- var that = this,
- id = this.$element.attr('id');
- this.selectId = selectId++;
- this.$element[0].classList.add('bs-select-hidden');
- this.multiple = this.$element.prop('multiple');
- this.autofocus = this.$element.prop('autofocus');
- this.options.showTick = this.$element[0].classList.contains('show-tick');
- this.$newElement = this.createDropdown();
- this.$element
- .after(this.$newElement)
- .prependTo(this.$newElement);
- this.$button = this.$newElement.children('button');
- this.$menu = this.$newElement.children(Selector.MENU);
- this.$menuInner = this.$menu.children('.inner');
- this.$searchbox = this.$menu.find('input');
- this.$element[0].classList.remove('bs-select-hidden');
- if (this.options.dropdownAlignRight === true) this.$menu[0].classList.add(classNames.MENURIGHT);
- if (typeof id !== 'undefined') {
- this.$button.attr('data-id', id);
- }
- this.checkDisabled();
- this.clickListener();
- if (this.options.liveSearch) this.liveSearchListener();
- this.setStyle();
- this.render();
- this.setWidth();
- if (this.options.container) {
- this.selectPosition();
- } else {
- this.$element.on('hide' + EVENT_KEY, function () {
- if (that.isVirtual()) {
- // empty menu on close
- var menuInner = that.$menuInner[0],
- emptyMenu = menuInner.firstChild.cloneNode(false);
- // replace the existing UL with an empty one - this is faster than $.empty() or innerHTML = ''
- menuInner.replaceChild(emptyMenu, menuInner.firstChild);
- menuInner.scrollTop = 0;
- }
- });
- }
- this.$menu.data('this', this);
- this.$newElement.data('this', this);
- if (this.options.mobile) this.mobile();
- this.$newElement.on({
- 'hide.bs.dropdown': function (e) {
- that.$menuInner.attr('aria-expanded', false);
- that.$element.trigger('hide' + EVENT_KEY, e);
- },
- 'hidden.bs.dropdown': function (e) {
- that.$element.trigger('hidden' + EVENT_KEY, e);
- },
- 'show.bs.dropdown': function (e) {
- that.$menuInner.attr('aria-expanded', true);
- that.$element.trigger('show' + EVENT_KEY, e);
- },
- 'shown.bs.dropdown': function (e) {
- that.$element.trigger('shown' + EVENT_KEY, e);
- }
- });
- if (that.$element[0].hasAttribute('required')) {
- this.$element.on('invalid' + EVENT_KEY, function () {
- that.$button[0].classList.add('bs-invalid');
- that.$element
- .on('shown' + EVENT_KEY + '.invalid', function () {
- that.$element
- .val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened
- .off('shown' + EVENT_KEY + '.invalid');
- })
- .on('rendered' + EVENT_KEY, function () {
- // if select is no longer invalid, remove the bs-invalid class
- if (this.validity.valid) that.$button[0].classList.remove('bs-invalid');
- that.$element.off('rendered' + EVENT_KEY);
- });
- that.$button.on('blur' + EVENT_KEY, function () {
- that.$element.trigger('focus').trigger('blur');
- that.$button.off('blur' + EVENT_KEY);
- });
- });
- }
- setTimeout(function () {
- that.createLi();
- that.$element.trigger('loaded' + EVENT_KEY);
- });
- },
- createDropdown: function () {
- // Options
- // If we are multiple or showTick option is set, then add the show-tick class
- var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
- inputGroup = '',
- autofocus = this.autofocus ? ' autofocus' : '';
- if (version.major < 4 && this.$element.parent().hasClass('input-group')) {
- inputGroup = ' input-group-btn';
- }
- // Elements
- var drop,
- header = '',
- searchbox = '',
- actionsbox = '',
- donebutton = '';
- if (this.options.header) {
- header =
- '<div class="' + classNames.POPOVERHEADER + '">' +
- '<button type="button" class="close" aria-hidden="true">×</button>' +
- this.options.header +
- '</div>';
- }
- if (this.options.liveSearch) {
- searchbox =
- '<div class="bs-searchbox">' +
- '<input type="text" class="form-control" autocomplete="off"' +
- (
- this.options.liveSearchPlaceholder === null ? ''
- :
- ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"'
- ) +
- ' role="textbox" aria-label="Search">' +
- '</div>';
- }
- if (this.multiple && this.options.actionsBox) {
- actionsbox =
- '<div class="bs-actionsbox">' +
- '<div class="btn-group btn-group-sm btn-block">' +
- '<button type="button" class="actions-btn bs-select-all btn ' + classNames.BUTTONCLASS + '">' +
- this.options.selectAllText +
- '</button>' +
- '<button type="button" class="actions-btn bs-deselect-all btn ' + classNames.BUTTONCLASS + '">' +
- this.options.deselectAllText +
- '</button>' +
- '</div>' +
- '</div>';
- }
- if (this.multiple && this.options.doneButton) {
- donebutton =
- '<div class="bs-donebutton">' +
- '<div class="btn-group btn-block">' +
- '<button type="button" class="btn btn-sm ' + classNames.BUTTONCLASS + '">' +
- this.options.doneButtonText +
- '</button>' +
- '</div>' +
- '</div>';
- }
- drop =
- '<div class="dropdown bootstrap-select' + showTick + inputGroup + '">' +
- '<button type="button" class="' + this.options.styleBase + ' dropdown-toggle" ' + (this.options.display === 'static' ? 'data-display="static"' : '') + 'data-toggle="dropdown"' + autofocus + ' role="button">' +
- '<div class="filter-option">' +
- '<div class="filter-option-inner">' +
- '<div class="filter-option-inner-inner"></div>' +
- '</div> ' +
- '</div>' +
- (
- version.major === '4' ? ''
- :
- '<span class="bs-caret">' +
- this.options.template.caret +
- '</span>'
- ) +
- '</button>' +
- '<div class="' + classNames.MENU + ' ' + (version.major === '4' ? '' : classNames.SHOW) + '" role="combobox">' +
- header +
- searchbox +
- actionsbox +
- '<div class="inner ' + classNames.SHOW + '" role="listbox" aria-expanded="false" tabindex="-1">' +
- '<ul class="' + classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '') + '">' +
- '</ul>' +
- '</div>' +
- donebutton +
- '</div>' +
- '</div>';
- return $(drop);
- },
- setPositionData: function () {
- this.selectpicker.view.canHighlight = [];
- for (var i = 0; i < this.selectpicker.current.data.length; i++) {
- var li = this.selectpicker.current.data[i],
- canHighlight = true;
- if (li.type === 'divider') {
- canHighlight = false;
- li.height = this.sizeInfo.dividerHeight;
- } else if (li.type === 'optgroup-label') {
- canHighlight = false;
- li.height = this.sizeInfo.dropdownHeaderHeight;
- } else {
- li.height = this.sizeInfo.liHeight;
- }
- if (li.disabled) canHighlight = false;
- this.selectpicker.view.canHighlight.push(canHighlight);
- li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height;
- }
- },
- isVirtual: function () {
- return (this.options.virtualScroll !== false) && (this.selectpicker.main.elements.length >= this.options.virtualScroll) || this.options.virtualScroll === true;
- },
- createView: function (isSearching, scrollTop) {
- scrollTop = scrollTop || 0;
- var that = this;
- this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main;
- var active = [];
- var selected;
- var prevActive;
- this.setPositionData();
- scroll(scrollTop, true);
- this.$menuInner.off('scroll.createView').on('scroll.createView', function (e, updateValue) {
- if (!that.noScroll) scroll(this.scrollTop, updateValue);
- that.noScroll = false;
- });
- function scroll (scrollTop, init) {
- var size = that.selectpicker.current.elements.length,
- chunks = [],
- chunkSize,
- chunkCount,
- firstChunk,
- lastChunk,
- currentChunk,
- prevPositions,
- positionIsDifferent,
- previousElements,
- menuIsDifferent = true,
- isVirtual = that.isVirtual();
- that.selectpicker.view.scrollTop = scrollTop;
- if (isVirtual === true) {
- // if an option that is encountered that is wider than the current menu width, update the menu width accordingly
- if (that.sizeInfo.hasScrollBar && that.$menu[0].offsetWidth > that.sizeInfo.totalMenuWidth) {
- that.sizeInfo.menuWidth = that.$menu[0].offsetWidth;
- that.sizeInfo.totalMenuWidth = that.sizeInfo.menuWidth + that.sizeInfo.scrollBarWidth;
- that.$menu.css('min-width', that.sizeInfo.menuWidth);
- }
- }
- chunkSize = Math.ceil(that.sizeInfo.menuInnerHeight / that.sizeInfo.liHeight * 1.5); // number of options in a chunk
- chunkCount = Math.round(size / chunkSize) || 1; // number of chunks
- for (var i = 0; i < chunkCount; i++) {
- var endOfChunk = (i + 1) * chunkSize;
- if (i === chunkCount - 1) {
- endOfChunk = size;
- }
- chunks[i] = [
- (i) * chunkSize + (!i ? 0 : 1),
- endOfChunk
- ];
- if (!size) break;
- if (currentChunk === undefined && scrollTop <= that.selectpicker.current.data[endOfChunk - 1].position - that.sizeInfo.menuInnerHeight) {
- currentChunk = i;
- }
- }
- if (currentChunk === undefined) currentChunk = 0;
- prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1];
- // always display previous, current, and next chunks
- firstChunk = Math.max(0, currentChunk - 1);
- lastChunk = Math.min(chunkCount - 1, currentChunk + 1);
- that.selectpicker.view.position0 = isVirtual === false ? 0 : (Math.max(0, chunks[firstChunk][0]) || 0);
- that.selectpicker.view.position1 = isVirtual === false ? size : (Math.min(size, chunks[lastChunk][1]) || 0);
- positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1;
- if (that.activeIndex !== undefined) {
- prevActive = that.selectpicker.main.elements[that.prevActiveIndex];
- active = that.selectpicker.main.elements[that.activeIndex];
- selected = that.selectpicker.main.elements[that.selectedIndex];
- if (init) {
- if (that.activeIndex !== that.selectedIndex && active && active.length) {
- active.classList.remove('active');
- if (active.firstChild) active.firstChild.classList.remove('active');
- }
- that.activeIndex = undefined;
- }
- if (that.activeIndex && that.activeIndex !== that.selectedIndex && selected && selected.length) {
- selected.classList.remove('active');
- if (selected.firstChild) selected.firstChild.classList.remove('active');
- }
- }
- if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex && prevActive && prevActive.length) {
- prevActive.classList.remove('active');
- if (prevActive.firstChild) prevActive.firstChild.classList.remove('active');
- }
- if (init || positionIsDifferent) {
- previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : [];
- if (isVirtual === false) {
- that.selectpicker.view.visibleElements = that.selectpicker.current.elements;
- } else {
- that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1);
- }
- that.setOptionStatus();
- // if searching, check to make sure the list has actually been updated before updating DOM
- // this prevents unnecessary repaints
- if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements);
- // if virtual scroll is disabled and not searching,
- // menu should never need to be updated more than once
- if ((init || isVirtual === true) && menuIsDifferent) {
- var menuInner = that.$menuInner[0],
- menuFragment = document.createDocumentFragment(),
- emptyMenu = menuInner.firstChild.cloneNode(false),
- marginTop,
- marginBottom,
- elements = that.selectpicker.view.visibleElements,
- toSanitize = [];
- // replace the existing UL with an empty one - this is faster than $.empty()
- menuInner.replaceChild(emptyMenu, menuInner.firstChild);
- for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) {
- var element = elements[i],
- elText,
- elementData;
- if (that.options.sanitize) {
- elText = element.lastChild;
- if (elText) {
- elementData = that.selectpicker.current.data[i + that.selectpicker.view.position0];
- if (elementData && elementData.content && !elementData.sanitized) {
- toSanitize.push(elText);
- elementData.sanitized = true;
- }
- }
- }
- menuFragment.appendChild(element);
- }
- if (that.options.sanitize && toSanitize.length) {
- sanitizeHtml(toSanitize, that.options.whiteList, that.options.sanitizeFn);
- }
- if (isVirtual === true) {
- marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position);
- marginBottom = (that.selectpicker.view.position1 > size - 1 ? 0 : that.selectpicker.current.data[size - 1].position - that.selectpicker.current.data[that.selectpicker.view.position1 - 1].position);
- menuInner.firstChild.style.marginTop = marginTop + 'px';
- menuInner.firstChild.style.marginBottom = marginBottom + 'px';
- }
- menuInner.firstChild.appendChild(menuFragment);
- }
- }
- that.prevActiveIndex = that.activeIndex;
- if (!that.options.liveSearch) {
- that.$menuInner.trigger('focus');
- } else if (isSearching && init) {
- var index = 0,
- newActive;
- if (!that.selectpicker.view.canHighlight[index]) {
- index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true);
- }
- newActive = that.selectpicker.view.visibleElements[index];
- if (that.selectpicker.view.currentActive) {
- that.selectpicker.view.currentActive.classList.remove('active');
- if (that.selectpicker.view.currentActive.firstChild) that.selectpicker.view.currentActive.firstChild.classList.remove('active');
- }
- if (newActive) {
- newActive.classList.add('active');
- if (newActive.firstChild) newActive.firstChild.classList.add('active');
- }
- that.activeIndex = (that.selectpicker.current.data[index] || {}).index;
- }
- }
- $(window)
- .off('resize' + EVENT_KEY + '.' + this.selectId + '.createView')
- .on('resize' + EVENT_KEY + '.' + this.selectId + '.createView', function () {
- var isActive = that.$newElement.hasClass(classNames.SHOW);
- if (isActive) scroll(that.$menuInner[0].scrollTop);
- });
- },
- setPlaceholder: function () {
- var updateIndex = false;
- if (this.options.title && !this.multiple) {
- if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option');
- // this option doesn't create a new <li> element, but does add a new option at the start,
- // so startIndex should increase to prevent having to check every option for the bs-title-option class
- updateIndex = true;
- var element = this.$element[0],
- isSelected = false,
- titleNotAppended = !this.selectpicker.view.titleOption.parentNode;
- if (titleNotAppended) {
- // Use native JS to prepend option (faster)
- this.selectpicker.view.titleOption.className = 'bs-title-option';
- this.selectpicker.view.titleOption.value = '';
- // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
- // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
- // if so, the select will have the data-selected attribute
- var $opt = $(element.options[element.selectedIndex]);
- isSelected = $opt.attr('selected') === undefined && this.$element.data('selected') === undefined;
- }
- if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) {
- element.insertBefore(this.selectpicker.view.titleOption, element.firstChild);
- }
- // Set selected *after* appending to select,
- // otherwise the option doesn't get selected in IE
- // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11
- if (isSelected) element.selectedIndex = 0;
- }
- return updateIndex;
- },
- createLi: function () {
- var that = this,
- iconBase = this.options.iconBase,
- optionSelector = ':not([hidden]):not([data-hidden="true"])',
- mainElements = [],
- mainData = [],
- widestOptionLength = 0,
- optID = 0,
- startIndex = this.setPlaceholder() ? 1 : 0; // append the titleOption if necessary and skip the first option in the loop
- if (this.options.hideDisabled) optionSelector += ':not(:disabled)';
- if ((that.options.showTick || that.multiple) && !elementTemplates.checkMark.parentNode) {
- elementTemplates.checkMark.className = iconBase + ' ' + that.options.tickIcon + ' check-mark';
- elementTemplates.a.appendChild(elementTemplates.checkMark);
- }
- var selectOptions = this.$element[0].querySelectorAll('select > *' + optionSelector);
- function addDivider (config) {
- var previousData = mainData[mainData.length - 1];
- // ensure optgroup doesn't create back-to-back dividers
- if (
- previousData &&
- previousData.type === 'divider' &&
- (previousData.optID || config.optID)
- ) {
- return;
- }
- config = config || {};
- config.type = 'divider';
- mainElements.push(
- generateOption.li(
- false,
- classNames.DIVIDER,
- (config.optID ? config.optID + 'div' : undefined)
- )
- );
- mainData.push(config);
- }
- function addOption (option, config) {
- config = config || {};
- config.divider = option.getAttribute('data-divider') === 'true';
- if (config.divider) {
- addDivider({
- optID: config.optID
- });
- } else {
- var liIndex = mainData.length,
- cssText = option.style.cssText,
- inlineStyle = cssText ? htmlEscape(cssText) : '',
- optionClass = (option.className || '') + (config.optgroupClass || '');
- if (config.optID) optionClass = 'opt ' + optionClass;
- config.text = option.textContent;
- config.content = option.getAttribute('data-content');
- config.tokens = option.getAttribute('data-tokens');
- config.subtext = option.getAttribute('data-subtext');
- config.icon = option.getAttribute('data-icon');
- config.iconBase = iconBase;
- var textElement = generateOption.text(config);
- mainElements.push(
- generateOption.li(
- generateOption.a(
- textElement,
- optionClass,
- inlineStyle
- ),
- '',
- config.optID
- )
- );
- option.liIndex = liIndex;
- config.display = config.content || config.text;
- config.type = 'option';
- config.index = liIndex;
- config.option = option;
- config.disabled = config.disabled || option.disabled;
- mainData.push(config);
- var combinedLength = 0;
- // count the number of characters in the option - not perfect, but should work in most cases
- if (config.display) combinedLength += config.display.length;
- if (config.subtext) combinedLength += config.subtext.length;
- // if there is an icon, ensure this option's width is checked
- if (config.icon) combinedLength += 1;
- if (combinedLength > widestOptionLength) {
- widestOptionLength = combinedLength;
- // guess which option is the widest
- // use this when calculating menu width
- // not perfect, but it's fast, and the width will be updating accordingly when scrolling
- that.selectpicker.view.widestOption = mainElements[mainElements.length - 1];
- }
- }
- }
- function addOptgroup (index, selectOptions) {
- var optgroup = selectOptions[index],
- previous = selectOptions[index - 1],
- next = selectOptions[index + 1],
- options = optgroup.querySelectorAll('option' + optionSelector);
- if (!options.length) return;
- var config = {
- label: htmlEscape(optgroup.label),
- subtext: optgroup.getAttribute('data-subtext'),
- icon: optgroup.getAttribute('data-icon'),
- iconBase: iconBase
- },
- optgroupClass = ' ' + (optgroup.className || ''),
- headerIndex,
- lastIndex;
- optID++;
- if (previous) {
- addDivider({ optID: optID });
- }
- var labelElement = generateOption.label(config);
- mainElements.push(
- generateOption.li(labelElement, 'dropdown-header' + optgroupClass, optID)
- );
- mainData.push({
- display: config.label,
- subtext: config.subtext,
- type: 'optgroup-label',
- optID: optID
- });
- for (var j = 0, len = options.length; j < len; j++) {
- var option = options[j];
- if (j === 0) {
- headerIndex = mainData.length - 1;
- lastIndex = headerIndex + len;
- }
- addOption(option, {
- headerIndex: headerIndex,
- lastIndex: lastIndex,
- optID: optID,
- optgroupClass: optgroupClass,
- disabled: optgroup.disabled
- });
- }
- if (next) {
- addDivider({ optID: optID });
- }
- }
- for (var len = selectOptions.length; startIndex < len; startIndex++) {
- var item = selectOptions[startIndex];
- if (item.tagName !== 'OPTGROUP') {
- addOption(item, {});
- } else {
- addOptgroup(startIndex, selectOptions);
- }
- }
- this.selectpicker.main.elements = mainElements;
- this.selectpicker.main.data = mainData;
- this.selectpicker.current = this.selectpicker.main;
- },
- findLis: function () {
- return this.$menuInner.find('.inner > li');
- },
- render: function () {
- // ensure titleOption is appended and selected (if necessary) before getting selectedOptions
- this.setPlaceholder();
- var that = this,
- selectedOptions = this.$element[0].selectedOptions,
- selectedCount = selectedOptions.length,
- button = this.$button[0],
- buttonInner = button.querySelector('.filter-option-inner-inner'),
- multipleSeparator = document.createTextNode(this.options.multipleSeparator),
- titleFragment = elementTemplates.fragment.cloneNode(false),
- showCount,
- countMax,
- hasContent = false;
- this.togglePlaceholder();
- this.tabIndex();
- if (this.options.selectedTextFormat === 'static') {
- titleFragment = generateOption.text({ text: this.options.title }, true);
- } else {
- showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 1;
- // determine if the number of selected options will be shown (showCount === true)
- if (showCount) {
- countMax = this.options.selectedTextFormat.split('>');
- showCount = (countMax.length > 1 && selectedCount > countMax[1]) || (countMax.length === 1 && selectedCount >= 2);
- }
- // only loop through all selected options if the count won't be shown
- if (showCount === false) {
- for (var selectedIndex = 0; selectedIndex < selectedCount; selectedIndex++) {
- if (selectedIndex < 50) {
- var option = selectedOptions[selectedIndex],
- titleOptions = {},
- thisData = {
- content: option.getAttribute('data-content'),
- subtext: option.getAttribute('data-subtext'),
- icon: option.getAttribute('data-icon')
- };
- if (this.multiple && selectedIndex > 0) {
- titleFragment.appendChild(multipleSeparator.cloneNode(false));
- }
- if (option.title) {
- titleOptions.text = option.title;
- } else if (thisData.content && that.options.showContent) {
- titleOptions.content = thisData.content.toString();
- hasContent = true;
- } else {
- if (that.options.showIcon) {
- titleOptions.icon = thisData.icon;
- titleOptions.iconBase = this.options.iconBase;
- }
- if (that.options.showSubtext && !that.multiple && thisData.subtext) titleOptions.subtext = ' ' + thisData.subtext;
- titleOptions.text = option.textContent.trim();
- }
- titleFragment.appendChild(generateOption.text(titleOptions, true));
- } else {
- break;
- }
- }
- // add ellipsis
- if (selectedCount > 49) {
- titleFragment.appendChild(document.createTextNode('...'));
- }
- } else {
- var optionSelector = ':not([hidden]):not([data-hidden="true"]):not([data-divider="true"])';
- if (this.options.hideDisabled) optionSelector += ':not(:disabled)';
- // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc.
- var totalCount = this.$element[0].querySelectorAll('select > option' + optionSelector + ', optgroup' + optionSelector + ' option' + optionSelector).length,
- tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedCount, totalCount) : this.options.countSelectedText;
- titleFragment = generateOption.text({
- text: tr8nText.replace('{0}', selectedCount.toString()).replace('{1}', totalCount.toString())
- }, true);
- }
- }
- if (this.options.title == undefined) {
- // use .attr to ensure undefined is returned if title attribute is not set
- this.options.title = this.$element.attr('title');
- }
- // If the select doesn't have a title, then use the default, or if nothing is set at all, use noneSelectedText
- if (!titleFragment.childNodes.length) {
- titleFragment = generateOption.text({
- text: typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText
- }, true);
- }
- // strip all HTML tags and trim the result, then unescape any escaped tags
- button.title = titleFragment.textContent.replace(/<[^>]*>?/g, '').trim();
- if (this.options.sanitize && hasContent) {
- sanitizeHtml([titleFragment], that.options.whiteList, that.options.sanitizeFn);
- }
- buttonInner.innerHTML = '';
- buttonInner.appendChild(titleFragment);
- if (version.major < 4 && this.$newElement[0].classList.contains('bs3-has-addon')) {
- var filterExpand = button.querySelector('.filter-expand'),
- clone = buttonInner.cloneNode(true);
- clone.className = 'filter-expand';
- if (filterExpand) {
- button.replaceChild(clone, filterExpand);
- } else {
- button.appendChild(clone);
- }
- }
- this.$element.trigger('rendered' + EVENT_KEY);
- },
- /**
- * @param [style]
- * @param [status]
- */
- setStyle: function (newStyle, status) {
- var button = this.$button[0],
- newElement = this.$newElement[0],
- style = this.options.style.trim(),
- buttonClass;
- if (this.$element.attr('class')) {
- this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi, ''));
- }
- if (version.major < 4) {
- newElement.classList.add('bs3');
- if (newElement.parentNode.classList.contains('input-group') &&
- (newElement.previousElementSibling || newElement.nextElementSibling) &&
- (newElement.previousElementSibling || newElement.nextElementSibling).classList.contains('input-group-addon')
- ) {
- newElement.classList.add('bs3-has-addon');
- }
- }
- if (newStyle) {
- buttonClass = newStyle.trim();
- } else {
- buttonClass = style;
- }
- if (status == 'add') {
- if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
- } else if (status == 'remove') {
- if (buttonClass) button.classList.remove.apply(button.classList, buttonClass.split(' '));
- } else {
- if (style) button.classList.remove.apply(button.classList, style.split(' '));
- if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
- }
- },
- liHeight: function (refresh) {
- if (!refresh && (this.options.size === false || this.sizeInfo)) return;
- if (!this.sizeInfo) this.sizeInfo = {};
- var newElement = document.createElement('div'),
- menu = document.createElement('div'),
- menuInner = document.createElement('div'),
- menuInnerInner = document.createElement('ul'),
- divider = document.createElement('li'),
- dropdownHeader = document.createElement('li'),
- li = document.createElement('li'),
- a = document.createElement('a'),
- text = document.createElement('span'),
- header = this.options.header && this.$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null,
- search = this.options.liveSearch ? document.createElement('div') : null,
- actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
- doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null,
- firstOption = this.$element.find('option')[0];
- this.sizeInfo.selectWidth = this.$newElement[0].offsetWidth;
- text.className = 'text';
- a.className = 'dropdown-item ' + (firstOption ? firstOption.className : '');
- newElement.className = this.$menu[0].parentNode.className + ' ' + classNames.SHOW;
- newElement.style.width = this.sizeInfo.selectWidth + 'px';
- if (this.options.width === 'auto') menu.style.minWidth = 0;
- menu.className = classNames.MENU + ' ' + classNames.SHOW;
- menuInner.className = 'inner ' + classNames.SHOW;
- menuInnerInner.className = classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '');
- divider.className = classNames.DIVIDER;
- dropdownHeader.className = 'dropdown-header';
- text.appendChild(document.createTextNode('\u200b'));
- a.appendChild(text);
- li.appendChild(a);
- dropdownHeader.appendChild(text.cloneNode(true));
- if (this.selectpicker.view.widestOption) {
- menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true));
- }
- menuInnerInner.appendChild(li);
- menuInnerInner.appendChild(divider);
- menuInnerInner.appendChild(dropdownHeader);
- if (header) menu.appendChild(header);
- if (search) {
- var input = document.createElement('input');
- search.className = 'bs-searchbox';
- input.className = 'form-control';
- search.appendChild(input);
- menu.appendChild(search);
- }
- if (actions) menu.appendChild(actions);
- menuInner.appendChild(menuInnerInner);
- menu.appendChild(menuInner);
- if (doneButton) menu.appendChild(doneButton);
- newElement.appendChild(menu);
- document.body.appendChild(newElement);
- var liHeight = li.offsetHeight,
- dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0,
- headerHeight = header ? header.offsetHeight : 0,
- searchHeight = search ? search.offsetHeight : 0,
- actionsHeight = actions ? actions.offsetHeight : 0,
- doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
- dividerHeight = $(divider).outerHeight(true),
- // fall back to jQuery if getComputedStyle is not supported
- menuStyle = window.getComputedStyle ? window.getComputedStyle(menu) : false,
- menuWidth = menu.offsetWidth,
- $menu = menuStyle ? null : $(menu),
- menuPadding = {
- vert: toInteger(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +
- toInteger(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +
- toInteger(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +
- toInteger(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),
- horiz: toInteger(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) +
- toInteger(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) +
- toInteger(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) +
- toInteger(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth'))
- },
- menuExtras = {
- vert: menuPadding.vert +
- toInteger(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) +
- toInteger(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2,
- horiz: menuPadding.horiz +
- toInteger(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) +
- toInteger(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2
- },
- scrollBarWidth;
- menuInner.style.overflowY = 'scroll';
- scrollBarWidth = menu.offsetWidth - menuWidth;
- document.body.removeChild(newElement);
- this.sizeInfo.liHeight = liHeight;
- this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight;
- this.sizeInfo.headerHeight = headerHeight;
- this.sizeInfo.searchHeight = searchHeight;
- this.sizeInfo.actionsHeight = actionsHeight;
- this.sizeInfo.doneButtonHeight = doneButtonHeight;
- this.sizeInfo.dividerHeight = dividerHeight;
- this.sizeInfo.menuPadding = menuPadding;
- this.sizeInfo.menuExtras = menuExtras;
- this.sizeInfo.menuWidth = menuWidth;
- this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth;
- this.sizeInfo.scrollBarWidth = scrollBarWidth;
- this.sizeInfo.selectHeight = this.$newElement[0].offsetHeight;
- this.setPositionData();
- },
- getSelectPosition: function () {
- var that = this,
- $window = $(window),
- pos = that.$newElement.offset(),
- $container = $(that.options.container),
- containerPos;
- if (that.options.container && $container.length && !$container.is('body')) {
- containerPos = $container.offset();
- containerPos.top += parseInt($container.css('borderTopWidth'));
- containerPos.left += parseInt($container.css('borderLeftWidth'));
- } else {
- containerPos = { top: 0, left: 0 };
- }
- var winPad = that.options.windowPadding;
- this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();
- this.sizeInfo.selectOffsetBot = $window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo.selectHeight - containerPos.top - winPad[2];
- this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();
- this.sizeInfo.selectOffsetRight = $window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo.selectWidth - containerPos.left - winPad[1];
- this.sizeInfo.selectOffsetTop -= winPad[0];
- this.sizeInfo.selectOffsetLeft -= winPad[3];
- },
- setMenuSize: function (isAuto) {
- this.getSelectPosition();
- var selectWidth = this.sizeInfo.selectWidth,
- liHeight = this.sizeInfo.liHeight,
- headerHeight = this.sizeInfo.headerHeight,
- searchHeight = this.sizeInfo.searchHeight,
- actionsHeight = this.sizeInfo.actionsHeight,
- doneButtonHeight = this.sizeInfo.doneButtonHeight,
- divHeight = this.sizeInfo.dividerHeight,
- menuPadding = this.sizeInfo.menuPadding,
- menuInnerHeight,
- menuHeight,
- divLength = 0,
- minHeight,
- _minHeight,
- maxHeight,
- menuInnerMinHeight,
- estimate;
- if (this.options.dropupAuto) {
- // Get the estimated height of the menu without scrollbars.
- // This is useful for smaller menus, where there might be plenty of room
- // below the button without setting dropup, but we can't know
- // the exact height of the menu until createView is called later
- estimate = liHeight * this.selectpicker.current.elements.length + menuPadding.vert;
- this.$newElement.toggleClass(classNames.DROPUP, this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot);
- }
- if (this.options.size === 'auto') {
- _minHeight = this.selectpicker.current.elements.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0;
- menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert;
- minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
- menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0);
- if (this.$newElement.hasClass(classNames.DROPUP)) {
- menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert;
- }
- maxHeight = menuHeight;
- menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert;
- } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
- for (var i = 0; i < this.options.size; i++) {
- if (this.selectpicker.current.data[i].type === 'divider') divLength++;
- }
- menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;
- menuInnerHeight = menuHeight - menuPadding.vert;
- maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
- minHeight = menuInnerMinHeight = '';
- }
- if (this.options.dropdownAlignRight === 'auto') {
- this.$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.sizeInfo.totalMenuWidth - selectWidth));
- }
- this.$menu.css({
- 'max-height': maxHeight + 'px',
- 'overflow': 'hidden',
- 'min-height': minHeight + 'px'
- });
- this.$menuInner.css({
- 'max-height': menuInnerHeight + 'px',
- 'overflow-y': 'auto',
- 'min-height': menuInnerMinHeight + 'px'
- });
- // ensure menuInnerHeight is always a positive number to prevent issues calculating chunkSize in createView
- this.sizeInfo.menuInnerHeight = Math.max(menuInnerHeight, 1);
- if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) {
- this.sizeInfo.hasScrollBar = true;
- this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth;
- this.$menu.css('min-width', this.sizeInfo.totalMenuWidth);
- }
- if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update();
- },
- setSize: function (refresh) {
- this.liHeight(refresh);
- if (this.options.header) this.$menu.css('padding-top', 0);
- if (this.options.size === false) return;
- var that = this,
- $window = $(window),
- selectedIndex,
- offset = 0;
- this.setMenuSize();
- if (this.options.liveSearch) {
- this.$searchbox
- .off('input.setMenuSize propertychange.setMenuSize')
- .on('input.setMenuSize propertychange.setMenuSize', function () {
- return that.setMenuSize();
- });
- }
- if (this.options.size === 'auto') {
- $window
- .off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize')
- .on('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize', function () {
- return that.setMenuSize();
- });
- } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
- $window.off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize');
- }
- if (refresh) {
- offset = this.$menuInner[0].scrollTop;
- } else if (!that.multiple) {
- var element = that.$element[0];
- selectedIndex = (element.options[element.selectedIndex] || {}).liIndex;
- if (typeof selectedIndex === 'number' && that.options.size !== false) {
- offset = that.sizeInfo.liHeight * selectedIndex;
- offset = offset - (that.sizeInfo.menuInnerHeight / 2) + (that.sizeInfo.liHeight / 2);
- }
- }
- that.createView(false, offset);
- },
- setWidth: function () {
- var that = this;
- if (this.options.width === 'auto') {
- requestAnimationFrame(function () {
- that.$menu.css('min-width', '0');
- that.$element.on('loaded' + EVENT_KEY, function () {
- that.liHeight();
- that.setMenuSize();
- // Get correct width if element is hidden
- var $selectClone = that.$newElement.clone().appendTo('body'),
- btnWidth = $selectClone.css('width', 'auto').children('button').outerWidth();
- $selectClone.remove();
- // Set width to whatever's larger, button title or longest option
- that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth);
- that.$newElement.css('width', that.sizeInfo.selectWidth + 'px');
- });
- });
- } else if (this.options.width === 'fit') {
- // Remove inline min-width so width can be changed from 'auto'
- this.$menu.css('min-width', '');
- this.$newElement.css('width', '').addClass('fit-width');
- } else if (this.options.width) {
- // Remove inline min-width so width can be changed from 'auto'
- this.$menu.css('min-width', '');
- this.$newElement.css('width', this.options.width);
- } else {
- // Remove inline min-width/width so width can be changed
- this.$menu.css('min-width', '');
- this.$newElement.css('width', '');
- }
- // Remove fit-width class if width is changed programmatically
- if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
- this.$newElement[0].classList.remove('fit-width');
- }
- },
- selectPosition: function () {
- this.$bsContainer = $('<div class="bs-container" />');
- var that = this,
- $container = $(this.options.container),
- pos,
- containerPos,
- actualHeight,
- getPlacement = function ($element) {
- var containerPosition = {},
- // fall back to dropdown's default display setting if display is not manually set
- display = that.options.display || (
- // Bootstrap 3 doesn't have $.fn.dropdown.Constructor.Default
- $.fn.dropdown.Constructor.Default ? $.fn.dropdown.Constructor.Default.display
- : false
- );
- that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, $element.hasClass(classNames.DROPUP));
- pos = $element.offset();
- if (!$container.is('body')) {
- containerPos = $container.offset();
- containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();
- containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();
- } else {
- containerPos = { top: 0, left: 0 };
- }
- actualHeight = $element.hasClass(classNames.DROPUP) ? 0 : $element[0].offsetHeight;
- // Bootstrap 4+ uses Popper for menu positioning
- if (version.major < 4 || display === 'static') {
- containerPosition.top = pos.top - containerPos.top + actualHeight;
- containerPosition.left = pos.left - containerPos.left;
- }
- containerPosition.width = $element[0].offsetWidth;
- that.$bsContainer.css(containerPosition);
- };
- this.$button.on('click.bs.dropdown.data-api', function () {
- if (that.isDisabled()) {
- return;
- }
- getPlacement(that.$newElement);
- that.$bsContainer
- .appendTo(that.options.container)
- .toggleClass(classNames.SHOW, !that.$button.hasClass(classNames.SHOW))
- .append(that.$menu);
- });
- $(window)
- .off('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId)
- .on('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId, function () {
- var isActive = that.$newElement.hasClass(classNames.SHOW);
- if (isActive) getPlacement(that.$newElement);
- });
- this.$element.on('hide' + EVENT_KEY, function () {
- that.$menu.data('height', that.$menu.height());
- that.$bsContainer.detach();
- });
- },
- setOptionStatus: function () {
- var that = this;
- that.noScroll = false;
- if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) {
- for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) {
- var liData = that.selectpicker.current.data[i + that.selectpicker.view.position0],
- option = liData.option;
- if (option) {
- that.setDisabled(
- liData.index,
- liData.disabled
- );
- that.setSelected(
- liData.index,
- option.selected
- );
- }
- }
- }
- },
- /**
- * @param {number} index - the index of the option that is being changed
- * @param {boolean} selected - true if the option is being selected, false if being deselected
- */
- setSelected: function (index, selected) {
- var li = this.selectpicker.main.elements[index],
- liData = this.selectpicker.main.data[index],
- activeIndexIsSet = this.activeIndex !== undefined,
- thisIsActive = this.activeIndex === index,
- prevActive,
- a,
- // if current option is already active
- // OR
- // if the current option is being selected, it's NOT multiple, and
- // activeIndex is undefined:
- // - when the menu is first being opened, OR
- // - after a search has been performed, OR
- // - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeIndex)
- keepActive = thisIsActive || (selected && !this.multiple && !activeIndexIsSet);
- liData.selected = selected;
- a = li.firstChild;
- if (selected) {
- this.selectedIndex = index;
- }
- li.classList.toggle('selected', selected);
- li.classList.toggle('active', keepActive);
- if (keepActive) {
- this.selectpicker.view.currentActive = li;
- this.activeIndex = index;
- }
- if (a) {
- a.classList.toggle('selected', selected);
- a.classList.toggle('active', keepActive);
- a.setAttribute('aria-selected', selected);
- }
- if (!keepActive) {
- if (!activeIndexIsSet && selected && this.prevActiveIndex !== undefined) {
- prevActive = this.selectpicker.main.elements[this.prevActiveIndex];
- prevActive.classList.remove('active');
- if (prevActive.firstChild) {
- prevActive.firstChild.classList.remove('active');
- }
- }
- }
- },
- /**
- * @param {number} index - the index of the option that is being disabled
- * @param {boolean} disabled - true if the option is being disabled, false if being enabled
- */
- setDisabled: function (index, disabled) {
- var li = this.selectpicker.main.elements[index],
- a;
- this.selectpicker.main.data[index].disabled = disabled;
- a = li.firstChild;
- li.classList.toggle(classNames.DISABLED, disabled);
- if (a) {
- if (version.major === '4') a.classList.toggle(classNames.DISABLED, disabled);
- a.setAttribute('aria-disabled', disabled);
- if (disabled) {
- a.setAttribute('tabindex', -1);
- } else {
- a.setAttribute('tabindex', 0);
- }
- }
- },
- isDisabled: function () {
- return this.$element[0].disabled;
- },
- checkDisabled: function () {
- var that = this;
- if (this.isDisabled()) {
- this.$newElement[0].classList.add(classNames.DISABLED);
- this.$button.addClass(classNames.DISABLED).attr('tabindex', -1).attr('aria-disabled', true);
- } else {
- if (this.$button[0].classList.contains(classNames.DISABLED)) {
- this.$newElement[0].classList.remove(classNames.DISABLED);
- this.$button.removeClass(classNames.DISABLED).attr('aria-disabled', false);
- }
- if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) {
- this.$button.removeAttr('tabindex');
- }
- }
- this.$button.on('click', function () {
- return !that.isDisabled();
- });
- },
- togglePlaceholder: function () {
- // much faster than calling $.val()
- var element = this.$element[0],
- selectedIndex = element.selectedIndex,
- nothingSelected = selectedIndex === -1;
- if (!nothingSelected && !element.options[selectedIndex].value) nothingSelected = true;
- this.$button.toggleClass('bs-placeholder', nothingSelected);
- },
- tabIndex: function () {
- if (this.$element.data('tabindex') !== this.$element.attr('tabindex') &&
- (this.$element.attr('tabindex') !== -98 && this.$element.attr('tabindex') !== '-98')) {
- this.$element.data('tabindex', this.$element.attr('tabindex'));
- this.$button.attr('tabindex', this.$element.data('tabindex'));
- }
- this.$element.attr('tabindex', -98);
- },
- clickListener: function () {
- var that = this,
- $document = $(document);
- $document.data('spaceSelect', false);
- this.$button.on('keyup', function (e) {
- if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {
- e.preventDefault();
- $document.data('spaceSelect', false);
- }
- });
- this.$newElement.on('show.bs.dropdown', function () {
- if (version.major > 3 && !that.dropdown) {
- that.dropdown = that.$button.data('bs.dropdown');
- that.dropdown._menu = that.$menu[0];
- }
- });
- this.$button.on('click.bs.dropdown.data-api', function () {
- if (!that.$newElement.hasClass(classNames.SHOW)) {
- that.setSize();
- }
- });
- function setFocus () {
- if (that.options.liveSearch) {
- that.$searchbox.trigger('focus');
- } else {
- that.$menuInner.trigger('focus');
- }
- }
- function checkPopperExists () {
- if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state.isCreated) {
- setFocus();
- } else {
- requestAnimationFrame(checkPopperExists);
- }
- }
- this.$element.on('shown' + EVENT_KEY, function () {
- if (that.$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) {
- that.$menuInner[0].scrollTop = that.selectpicker.view.scrollTop;
- }
- if (version.major > 3) {
- requestAnimationFrame(checkPopperExists);
- } else {
- setFocus();
- }
- });
- this.$menuInner.on('click', 'li a', function (e, retainActive) {
- var $this = $(this),
- position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
- clickedData = that.selectpicker.current.data[$this.parent().index() + position0],
- clickedIndex = clickedData.index,
- prevValue = getSelectValues(that.$element[0]),
- prevIndex = that.$element.prop('selectedIndex'),
- triggerChange = true;
- // Don't close on multi choice menu
- if (that.multiple && that.options.maxOptions !== 1) {
- e.stopPropagation();
- }
- e.preventDefault();
- // Don't run if the select is disabled
- if (!that.isDisabled() && !$this.parent().hasClass(classNames.DISABLED)) {
- var $options = that.$element.find('option'),
- option = clickedData.option,
- $option = $(option),
- state = option.selected,
- $optgroup = $option.parent('optgroup'),
- $optgroupOptions = $optgroup.find('option'),
- maxOptions = that.options.maxOptions,
- maxOptionsGrp = $optgroup.data('maxOptions') || false;
- if (clickedIndex === that.activeIndex) retainActive = true;
- if (!retainActive) {
- that.prevActiveIndex = that.activeIndex;
- that.activeIndex = undefined;
- }
- if (!that.multiple) { // Deselect all others if not multi select box
- $options.prop('selected', false);
- option.selected = true;
- that.setSelected(clickedIndex, true);
- } else { // Toggle the one we have chosen if we are multi select.
- option.selected = !state;
- that.setSelected(clickedIndex, !state);
- $this.trigger('blur');
- if (maxOptions !== false || maxOptionsGrp !== false) {
- var maxReached = maxOptions < $options.filter(':selected').length,
- maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;
- if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
- if (maxOptions && maxOptions == 1) {
- $options.prop('selected', false);
- $option.prop('selected', true);
- for (var i = 0; i < $options.length; i++) {
- that.setSelected(i, false);
- }
- that.setSelected(clickedIndex, true);
- } else if (maxOptionsGrp && maxOptionsGrp == 1) {
- $optgroup.find('option:selected').prop('selected', false);
- $option.prop('selected', true);
- for (var i = 0; i < $optgroupOptions.length; i++) {
- var option = $optgroupOptions[i];
- that.setSelected($options.index(option), false);
- }
- that.setSelected(clickedIndex, true);
- } else {
- var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
- maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
- maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
- maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
- $notify = $('<div class="notify"></div>');
- // If {var} is set in array, replace it
- /** @deprecated */
- if (maxOptionsArr[2]) {
- maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
- maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
- }
- $option.prop('selected', false);
- that.$menu.append($notify);
- if (maxOptions && maxReached) {
- $notify.append($('<div>' + maxTxt + '</div>'));
- triggerChange = false;
- that.$element.trigger('maxReached' + EVENT_KEY);
- }
- if (maxOptionsGrp && maxReachedGrp) {
- $notify.append($('<div>' + maxTxtGrp + '</div>'));
- triggerChange = false;
- that.$element.trigger('maxReachedGrp' + EVENT_KEY);
- }
- setTimeout(function () {
- that.setSelected(clickedIndex, false);
- }, 10);
- $notify.delay(750).fadeOut(300, function () {
- $(this).remove();
- });
- }
- }
- }
- }
- if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
- that.$button.trigger('focus');
- } else if (that.options.liveSearch) {
- that.$searchbox.trigger('focus');
- }
- // Trigger select 'change'
- if (triggerChange) {
- if ((prevValue != getSelectValues(that.$element[0]) && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) {
- // $option.prop('selected') is current option state (selected/unselected). prevValue is the value of the select prior to being changed.
- changedArguments = [option.index, $option.prop('selected'), prevValue];
- that.$element
- .triggerNative('change');
- }
- }
- }
- });
- this.$menu.on('click', 'li.' + classNames.DISABLED + ' a, .' + classNames.POPOVERHEADER + ', .' + classNames.POPOVERHEADER + ' :not(.close)', function (e) {
- if (e.currentTarget == this) {
- e.preventDefault();
- e.stopPropagation();
- if (that.options.liveSearch && !$(e.target).hasClass('close')) {
- that.$searchbox.trigger('focus');
- } else {
- that.$button.trigger('focus');
- }
- }
- });
- this.$menuInner.on('click', '.divider, .dropdown-header', function (e) {
- e.preventDefault();
- e.stopPropagation();
- if (that.options.liveSearch) {
- that.$searchbox.trigger('focus');
- } else {
- that.$button.trigger('focus');
- }
- });
- this.$menu.on('click', '.' + classNames.POPOVERHEADER + ' .close', function () {
- that.$button.trigger('click');
- });
- this.$searchbox.on('click', function (e) {
- e.stopPropagation();
- });
- this.$menu.on('click', '.actions-btn', function (e) {
- if (that.options.liveSearch) {
- that.$searchbox.trigger('focus');
- } else {
- that.$button.trigger('focus');
- }
- e.preventDefault();
- e.stopPropagation();
- if ($(this).hasClass('bs-select-all')) {
- that.selectAll();
- } else {
- that.deselectAll();
- }
- });
- this.$element
- .on('change' + EVENT_KEY, function () {
- that.render();
- that.$element.trigger('changed' + EVENT_KEY, changedArguments);
- changedArguments = null;
- })
- .on('focus' + EVENT_KEY, function () {
- if (!that.options.mobile) that.$button.trigger('focus');
- });
- },
- liveSearchListener: function () {
- var that = this,
- noResults = document.createElement('li');
- this.$button.on('click.bs.dropdown.data-api', function () {
- if (!!that.$searchbox.val()) {
- that.$searchbox.val('');
- }
- });
- this.$searchbox.on('click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api', function (e) {
- e.stopPropagation();
- });
- this.$searchbox.on('input propertychange', function () {
- var searchValue = that.$searchbox.val();
- that.selectpicker.search.elements = [];
- that.selectpicker.search.data = [];
- if (searchValue) {
- var i,
- searchMatch = [],
- q = searchValue.toUpperCase(),
- cache = {},
- cacheArr = [],
- searchStyle = that._searchStyle(),
- normalizeSearch = that.options.liveSearchNormalize;
- if (normalizeSearch) q = normalizeToBase(q);
- that._$lisSelected = that.$menuInner.find('.selected');
- for (var i = 0; i < that.selectpicker.main.data.length; i++) {
- var li = that.selectpicker.main.data[i];
- if (!cache[i]) {
- cache[i] = stringSearch(li, q, searchStyle, normalizeSearch);
- }
- if (cache[i] && li.headerIndex !== undefined && cacheArr.indexOf(li.headerIndex) === -1) {
- if (li.headerIndex > 0) {
- cache[li.headerIndex - 1] = true;
- cacheArr.push(li.headerIndex - 1);
- }
- cache[li.headerIndex] = true;
- cacheArr.push(li.headerIndex);
- cache[li.lastIndex + 1] = true;
- }
- if (cache[i] && li.type !== 'optgroup-label') cacheArr.push(i);
- }
- for (var i = 0, cacheLen = cacheArr.length; i < cacheLen; i++) {
- var index = cacheArr[i],
- prevIndex = cacheArr[i - 1],
- li = that.selectpicker.main.data[index],
- liPrev = that.selectpicker.main.data[prevIndex];
- if (li.type !== 'divider' || (li.type === 'divider' && liPrev && liPrev.type !== 'divider' && cacheLen - 1 !== i)) {
- that.selectpicker.search.data.push(li);
- searchMatch.push(that.selectpicker.main.elements[index]);
- }
- }
- that.activeIndex = undefined;
- that.noScroll = true;
- that.$menuInner.scrollTop(0);
- that.selectpicker.search.elements = searchMatch;
- that.createView(true);
- if (!searchMatch.length) {
- noResults.className = 'no-results';
- noResults.innerHTML = that.options.noneResultsText.replace('{0}', '"' + htmlEscape(searchValue) + '"');
- that.$menuInner[0].firstChild.appendChild(noResults);
- }
- } else {
- that.$menuInner.scrollTop(0);
- that.createView(false);
- }
- });
- },
- _searchStyle: function () {
- return this.options.liveSearchStyle || 'contains';
- },
- val: function (value) {
- if (typeof value !== 'undefined') {
- var prevValue = getSelectValues(this.$element[0]);
- changedArguments = [null, null, prevValue];
- this.$element
- .val(value)
- .trigger('changed' + EVENT_KEY, changedArguments);
- this.render();
- changedArguments = null;
- return this.$element;
- } else {
- return this.$element.val();
- }
- },
- changeAll: function (status) {
- if (!this.multiple) return;
- if (typeof status === 'undefined') status = true;
- var element = this.$element[0],
- previousSelected = 0,
- currentSelected = 0,
- prevValue = getSelectValues(element);
- element.classList.add('bs-select-hidden');
- for (var i = 0, len = this.selectpicker.current.elements.length; i < len; i++) {
- var liData = this.selectpicker.current.data[i],
- option = liData.option;
- if (option && !liData.disabled && liData.type !== 'divider') {
- if (liData.selected) previousSelected++;
- option.selected = status;
- if (status) currentSelected++;
- }
- }
- element.classList.remove('bs-select-hidden');
- if (previousSelected === currentSelected) return;
- this.setOptionStatus();
- this.togglePlaceholder();
- changedArguments = [null, null, prevValue];
- this.$element
- .triggerNative('change');
- },
- selectAll: function () {
- return this.changeAll(true);
- },
- deselectAll: function () {
- return this.changeAll(false);
- },
- toggle: function (e) {
- e = e || window.event;
- if (e) e.stopPropagation();
- this.$button.trigger('click.bs.dropdown.data-api');
- },
- keydown: function (e) {
- var $this = $(this),
- isToggle = $this.hasClass('dropdown-toggle'),
- $parent = isToggle ? $this.closest('.dropdown') : $this.closest(Selector.MENU),
- that = $parent.data('this'),
- $items = that.findLis(),
- index,
- isActive,
- liActive,
- activeLi,
- offset,
- updateScroll = false,
- downOnTab = e.which === keyCodes.TAB && !isToggle && !that.options.selectOnTab,
- isArrowKey = REGEXP_ARROW.test(e.which) || downOnTab,
- scrollTop = that.$menuInner[0].scrollTop,
- isVirtual = that.isVirtual(),
- position0 = isVirtual === true ? that.selectpicker.view.position0 : 0;
- isActive = that.$newElement.hasClass(classNames.SHOW);
- if (
- !isActive &&
- (
- isArrowKey ||
- (e.which >= 48 && e.which <= 57) ||
- (e.which >= 96 && e.which <= 105) ||
- (e.which >= 65 && e.which <= 90)
- )
- ) {
- that.$button.trigger('click.bs.dropdown.data-api');
- if (that.options.liveSearch) {
- that.$searchbox.trigger('focus');
- return;
- }
- }
- if (e.which === keyCodes.ESCAPE && isActive) {
- e.preventDefault();
- that.$button.trigger('click.bs.dropdown.data-api').trigger('focus');
- }
- if (isArrowKey) { // if up or down
- if (!$items.length) return;
- // $items.index/.filter is too slow with a large list and no virtual scroll
- index = isVirtual === true ? $items.index($items.filter('.active')) : that.activeIndex;
- if (index === undefined) index = -1;
- if (index !== -1) {
- liActive = that.selectpicker.current.elements[index + position0];
- liActive.classList.remove('active');
- if (liActive.firstChild) liActive.firstChild.classList.remove('active');
- }
- if (e.which === keyCodes.ARROW_UP) { // up
- if (index !== -1) index--;
- if (index + position0 < 0) index += $items.length;
- if (!that.selectpicker.view.canHighlight[index + position0]) {
- index = that.selectpicker.view.canHighlight.slice(0, index + position0).lastIndexOf(true) - position0;
- if (index === -1) index = $items.length - 1;
- }
- } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
- index++;
- if (index + position0 >= that.selectpicker.view.canHighlight.length) index = 0;
- if (!that.selectpicker.view.canHighlight[index + position0]) {
- index = index + 1 + that.selectpicker.view.canHighlight.slice(index + position0 + 1).indexOf(true);
- }
- }
- e.preventDefault();
- var liActiveIndex = position0 + index;
- if (e.which === keyCodes.ARROW_UP) { // up
- // scroll to bottom and highlight last option
- if (position0 === 0 && index === $items.length - 1) {
- that.$menuInner[0].scrollTop = that.$menuInner[0].scrollHeight;
- liActiveIndex = that.selectpicker.current.elements.length - 1;
- } else {
- activeLi = that.selectpicker.current.data[liActiveIndex];
- offset = activeLi.position - activeLi.height;
- updateScroll = offset < scrollTop;
- }
- } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
- // scroll to top and highlight first option
- if (index === 0) {
- that.$menuInner[0].scrollTop = 0;
- liActiveIndex = 0;
- } else {
- activeLi = that.selectpicker.current.data[liActiveIndex];
- offset = activeLi.position - that.sizeInfo.menuInnerHeight;
- updateScroll = offset > scrollTop;
- }
- }
- liActive = that.selectpicker.current.elements[liActiveIndex];
- if (liActive) {
- liActive.classList.add('active');
- if (liActive.firstChild) liActive.firstChild.classList.add('active');
- }
- that.activeIndex = that.selectpicker.current.data[liActiveIndex].index;
- that.selectpicker.view.currentActive = liActive;
- if (updateScroll) that.$menuInner[0].scrollTop = offset;
- if (that.options.liveSearch) {
- that.$searchbox.trigger('focus');
- } else {
- $this.trigger('focus');
- }
- } else if (
- (!$this.is('input') && !REGEXP_TAB_OR_ESCAPE.test(e.which)) ||
- (e.which === keyCodes.SPACE && that.selectpicker.keydown.keyHistory)
- ) {
- var searchMatch,
- matches = [],
- keyHistory;
- e.preventDefault();
- that.selectpicker.keydown.keyHistory += keyCodeMap[e.which];
- if (that.selectpicker.keydown.resetKeyHistory.cancel) clearTimeout(that.selectpicker.keydown.resetKeyHistory.cancel);
- that.selectpicker.keydown.resetKeyHistory.cancel = that.selectpicker.keydown.resetKeyHistory.start();
- keyHistory = that.selectpicker.keydown.keyHistory;
- // if all letters are the same, set keyHistory to just the first character when searching
- if (/^(.)\1+$/.test(keyHistory)) {
- keyHistory = keyHistory.charAt(0);
- }
- // find matches
- for (var i = 0; i < that.selectpicker.current.data.length; i++) {
- var li = that.selectpicker.current.data[i],
- hasMatch;
- hasMatch = stringSearch(li, keyHistory, 'startsWith', true);
- if (hasMatch && that.selectpicker.view.canHighlight[i]) {
- matches.push(li.index);
- }
- }
- if (matches.length) {
- var matchIndex = 0;
- $items.removeClass('active').find('a').removeClass('active');
- // either only one key has been pressed or they are all the same key
- if (keyHistory.length === 1) {
- matchIndex = matches.indexOf(that.activeIndex);
- if (matchIndex === -1 || matchIndex === matches.length - 1) {
- matchIndex = 0;
- } else {
- matchIndex++;
- }
- }
- searchMatch = matches[matchIndex];
- activeLi = that.selectpicker.main.data[searchMatch];
- if (scrollTop - activeLi.position > 0) {
- offset = activeLi.position - activeLi.height;
- updateScroll = true;
- } else {
- offset = activeLi.position - that.sizeInfo.menuInnerHeight;
- // if the option is already visible at the current scroll position, just keep it the same
- updateScroll = activeLi.position > scrollTop + that.sizeInfo.menuInnerHeight;
- }
- liActive = that.selectpicker.main.elements[searchMatch];
- liActive.classList.add('active');
- if (liActive.firstChild) liActive.firstChild.classList.add('active');
- that.activeIndex = matches[matchIndex];
- liActive.firstChild.focus();
- if (updateScroll) that.$menuInner[0].scrollTop = offset;
- $this.trigger('focus');
- }
- }
- // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu.
- if (
- isActive &&
- (
- (e.which === keyCodes.SPACE && !that.selectpicker.keydown.keyHistory) ||
- e.which === keyCodes.ENTER ||
- (e.which === keyCodes.TAB && that.options.selectOnTab)
- )
- ) {
- if (e.which !== keyCodes.SPACE) e.preventDefault();
- if (!that.options.liveSearch || e.which !== keyCodes.SPACE) {
- that.$menuInner.find('.active a').trigger('click', true); // retain active class
- $this.trigger('focus');
- if (!that.options.liveSearch) {
- // Prevent screen from scrolling if the user hits the spacebar
- e.preventDefault();
- // Fixes spacebar selection of dropdown items in FF & IE
- $(document).data('spaceSelect', true);
- }
- }
- }
- },
- mobile: function () {
- this.$element[0].classList.add('mobile-device');
- },
- refresh: function () {
- // update options if data attributes have been changed
- var config = $.extend({}, this.options, this.$element.data());
- this.options = config;
- this.checkDisabled();
- this.setStyle();
- this.render();
- this.createLi();
- this.setWidth();
- this.setSize(true);
- this.$element.trigger('refreshed' + EVENT_KEY);
- },
- hide: function () {
- this.$newElement.hide();
- },
- show: function () {
- this.$newElement.show();
- },
- remove: function () {
- this.$newElement.remove();
- this.$element.remove();
- },
- destroy: function () {
- this.$newElement.before(this.$element).remove();
- if (this.$bsContainer) {
- this.$bsContainer.remove();
- } else {
- this.$menu.remove();
- }
- this.$element
- .off(EVENT_KEY)
- .removeData('selectpicker')
- .removeClass('bs-select-hidden selectpicker');
- $(window).off(EVENT_KEY + '.' + this.selectId);
- }
- };
- // SELECTPICKER PLUGIN DEFINITION
- // ==============================
- function Plugin (option) {
- // get the args of the outer function..
- var args = arguments;
- // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
- // to get lost/corrupted in android 2.3 and IE9 #715 #775
- var _option = option;
- [].shift.apply(args);
- // if the version was not set successfully
- if (!version.success) {
- // try to retreive it again
- try {
- version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.');
- } catch (err) {
- // fall back to use BootstrapVersion if set
- if (Selectpicker.BootstrapVersion) {
- version.full = Selectpicker.BootstrapVersion.split(' ')[0].split('.');
- } else {
- version.full = [version.major, '0', '0'];
- console.warn(
- 'There was an issue retrieving Bootstrap\'s version. ' +
- 'Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. ' +
- 'If loading Bootstrap asynchronously, the version may need to be manually specified via $.fn.selectpicker.Constructor.BootstrapVersion.',
- err
- );
- }
- }
- version.major = version.full[0];
- version.success = true;
- }
- if (version.major === '4') {
- // some defaults need to be changed if using Bootstrap 4
- // check to see if they have already been manually changed before forcing them to update
- var toUpdate = [];
- if (Selectpicker.DEFAULTS.style === classNames.BUTTONCLASS) toUpdate.push({ name: 'style', className: 'BUTTONCLASS' });
- if (Selectpicker.DEFAULTS.iconBase === classNames.ICONBASE) toUpdate.push({ name: 'iconBase', className: 'ICONBASE' });
- if (Selectpicker.DEFAULTS.tickIcon === classNames.TICKICON) toUpdate.push({ name: 'tickIcon', className: 'TICKICON' });
- classNames.DIVIDER = 'dropdown-divider';
- classNames.SHOW = 'show';
- classNames.BUTTONCLASS = 'btn-light';
- classNames.POPOVERHEADER = 'popover-header';
- classNames.ICONBASE = '';
- classNames.TICKICON = 'bs-ok-default';
- for (var i = 0; i < toUpdate.length; i++) {
- var option = toUpdate[i];
- Selectpicker.DEFAULTS[option.name] = classNames[option.className];
- }
- }
- var value;
- var chain = this.each(function () {
- var $this = $(this);
- if ($this.is('select')) {
- var data = $this.data('selectpicker'),
- options = typeof _option == 'object' && _option;
- if (!data) {
- var dataAttributes = $this.data();
- for (var dataAttr in dataAttributes) {
- if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
- delete dataAttributes[dataAttr];
- }
- }
- var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, dataAttributes, options);
- config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), dataAttributes.template, options.template);
- $this.data('selectpicker', (data = new Selectpicker(this, config)));
- } else if (options) {
- for (var i in options) {
- if (options.hasOwnProperty(i)) {
- data.options[i] = options[i];
- }
- }
- }
- if (typeof _option == 'string') {
- if (data[_option] instanceof Function) {
- value = data[_option].apply(data, args);
- } else {
- value = data.options[_option];
- }
- }
- }
- });
- if (typeof value !== 'undefined') {
- // noinspection JSUnusedAssignment
- return value;
- } else {
- return chain;
- }
- }
- var old = $.fn.selectpicker;
- $.fn.selectpicker = Plugin;
- $.fn.selectpicker.Constructor = Selectpicker;
- // SELECTPICKER NO CONFLICT
- // ========================
- $.fn.selectpicker.noConflict = function () {
- $.fn.selectpicker = old;
- return this;
- };
- $(document)
- .off('keydown.bs.dropdown.data-api')
- .on('keydown' + EVENT_KEY, '.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input', Selectpicker.prototype.keydown)
- .on('focusin.modal', '.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input', function (e) {
- e.stopPropagation();
- });
- // SELECTPICKER DATA-API
- // =====================
- $(window).on('load' + EVENT_KEY + '.data-api', function () {
- $('.selectpicker').each(function () {
- var $selectpicker = $(this);
- Plugin.call($selectpicker, $selectpicker.data());
- })
- });
- })(jQuery);
- }));
- /******************************************************************************/
- // https://github.com/jackmoore/autosize
- (function (global, factory) {
- if (typeof define === "function" && define.amd) {
- define(['module', 'exports'], factory);
- } else if (typeof exports !== "undefined") {
- factory(module, exports);
- } else {
- var mod = {
- exports: {}
- };
- factory(mod, mod.exports);
- global.autosize = mod.exports;
- }
- })(this, function (module, exports) {
- 'use strict';
- var map = typeof Map === "function" ? new Map() : function () {
- var keys = [];
- var values = [];
- return {
- has: function has(key) {
- return keys.indexOf(key) > -1;
- },
- get: function get(key) {
- return values[keys.indexOf(key)];
- },
- set: function set(key, value) {
- if (keys.indexOf(key) === -1) {
- keys.push(key);
- values.push(value);
- }
- },
- delete: function _delete(key) {
- var index = keys.indexOf(key);
- if (index > -1) {
- keys.splice(index, 1);
- values.splice(index, 1);
- }
- }
- };
- }();
- var createEvent = function createEvent(name) {
- return new Event(name, { bubbles: true });
- };
- try {
- new Event('test');
- } catch (e) {
- // IE does not support 'new Event()'
- createEvent = function createEvent(name) {
- var evt = document.createEvent('Event');
- evt.initEvent(name, true, false);
- return evt;
- };
- }
- function assign(ta) {
- if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return;
- var heightOffset = null;
- var clientWidth = null;
- var cachedHeight = null;
- function init() {
- var style = window.getComputedStyle(ta, null);
- if (style.resize === 'vertical') {
- ta.style.resize = 'none';
- } else if (style.resize === 'both') {
- ta.style.resize = 'horizontal';
- }
- if (style.boxSizing === 'content-box') {
- heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
- } else {
- heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
- }
- // Fix when a textarea is not on document body and heightOffset is Not a Number
- if (isNaN(heightOffset)) {
- heightOffset = 0;
- }
- update();
- }
- function changeOverflow(value) {
- {
- // Chrome/Safari-specific fix:
- // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
- // made available by removing the scrollbar. The following forces the necessary text reflow.
- var width = ta.style.width;
- ta.style.width = '0px';
- // Force reflow:
- /* jshint ignore:start */
- ta.offsetWidth;
- /* jshint ignore:end */
- ta.style.width = width;
- }
- ta.style.overflowY = value;
- }
- function getParentOverflows(el) {
- var arr = [];
- while (el && el.parentNode && el.parentNode instanceof Element) {
- if (el.parentNode.scrollTop) {
- arr.push({
- node: el.parentNode,
- scrollTop: el.parentNode.scrollTop
- });
- }
- el = el.parentNode;
- }
- return arr;
- }
- function resize() {
- if (ta.scrollHeight === 0) {
- // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
- return;
- }
- var overflows = getParentOverflows(ta);
- var docTop = document.documentElement && document.documentElement.scrollTop; // Needed for Mobile IE (ticket #240)
- ta.style.height = '';
- ta.style.height = ta.scrollHeight + heightOffset + 'px';
- // used to check if an update is actually necessary on window.resize
- clientWidth = ta.clientWidth;
- // prevents scroll-position jumping
- overflows.forEach(function (el) {
- el.node.scrollTop = el.scrollTop;
- });
- if (docTop) {
- document.documentElement.scrollTop = docTop;
- }
- }
- function update() {
- resize();
- var styleHeight = Math.round(parseFloat(ta.style.height));
- var computed = window.getComputedStyle(ta, null);
- // Using offsetHeight as a replacement for computed.height in IE, because IE does not account use of border-box
- var actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(computed.height)) : ta.offsetHeight;
- // The actual height not matching the style height (set via the resize method) indicates that
- // the max-height has been exceeded, in which case the overflow should be allowed.
- if (actualHeight < styleHeight) {
- if (computed.overflowY === 'hidden') {
- changeOverflow('scroll');
- resize();
- actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
- }
- } else {
- // Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
- if (computed.overflowY !== 'hidden') {
- changeOverflow('hidden');
- resize();
- actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
- }
- }
- if (cachedHeight !== actualHeight) {
- cachedHeight = actualHeight;
- var evt = createEvent('autosize:resized');
- try {
- ta.dispatchEvent(evt);
- } catch (err) {
- // Firefox will throw an error on dispatchEvent for a detached element
- // https://bugzilla.mozilla.org/show_bug.cgi?id=889376
- }
- }
- }
- var pageResize = function pageResize() {
- if (ta.clientWidth !== clientWidth) {
- update();
- }
- };
- var destroy = function (style) {
- window.removeEventListener('resize', pageResize, false);
- ta.removeEventListener('input', update, false);
- ta.removeEventListener('keyup', update, false);
- ta.removeEventListener('autosize:destroy', destroy, false);
- ta.removeEventListener('autosize:update', update, false);
- Object.keys(style).forEach(function (key) {
- ta.style[key] = style[key];
- });
- map.delete(ta);
- }.bind(ta, {
- height: ta.style.height,
- resize: ta.style.resize,
- overflowY: ta.style.overflowY,
- overflowX: ta.style.overflowX,
- wordWrap: ta.style.wordWrap
- });
- ta.addEventListener('autosize:destroy', destroy, false);
- // IE9 does not fire onpropertychange or oninput for deletions,
- // so binding to onkeyup to catch most of those events.
- // There is no way that I know of to detect something like 'cut' in IE9.
- if ('onpropertychange' in ta && 'oninput' in ta) {
- ta.addEventListener('keyup', update, false);
- }
- window.addEventListener('resize', pageResize, false);
- ta.addEventListener('input', update, false);
- ta.addEventListener('autosize:update', update, false);
- ta.style.overflowX = 'hidden';
- ta.style.wordWrap = 'break-word';
- map.set(ta, {
- destroy: destroy,
- update: update
- });
- init();
- }
- function destroy(ta) {
- var methods = map.get(ta);
- if (methods) {
- methods.destroy();
- }
- }
- function update(ta) {
- var methods = map.get(ta);
- if (methods) {
- methods.update();
- }
- }
- var autosize = null;
- // Do nothing in Node.js environment and IE8 (or lower)
- if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
- autosize = function autosize(el) {
- return el;
- };
- autosize.destroy = function (el) {
- return el;
- };
- autosize.update = function (el) {
- return el;
- };
- } else {
- autosize = function autosize(el, options) {
- if (el) {
- Array.prototype.forEach.call(el.length ? el : [el], function (x) {
- return assign(x, options);
- });
- }
- return el;
- };
- autosize.destroy = function (el) {
- if (el) {
- Array.prototype.forEach.call(el.length ? el : [el], destroy);
- }
- return el;
- };
- autosize.update = function (el) {
- if (el) {
- Array.prototype.forEach.call(el.length ? el : [el], update);
- }
- return el;
- };
- }
- exports.default = autosize;
- module.exports = exports['default'];
- });
- /******************************************************************************/
- /**!
- * Sortable 1.10.0-rc3
- * @author RubaXa <trash@rubaxa.org>
- * @author owenm <owen23355@gmail.com>
- * @license MIT
- */
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global = global || self, global.Sortable = factory());
- }(this, function () { 'use strict';
- function _typeof(obj) {
- if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
- _typeof = function (obj) {
- return typeof obj;
- };
- } else {
- _typeof = function (obj) {
- return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
- };
- }
- return _typeof(obj);
- }
- function _defineProperty(obj, key, value) {
- if (key in obj) {
- Object.defineProperty(obj, key, {
- value: value,
- enumerable: true,
- configurable: true,
- writable: true
- });
- } else {
- obj[key] = value;
- }
- return obj;
- }
- function _extends() {
- _extends = Object.assign || function (target) {
- for (var i = 1; i < arguments.length; i++) {
- var source = arguments[i];
- for (var key in source) {
- if (Object.prototype.hasOwnProperty.call(source, key)) {
- target[key] = source[key];
- }
- }
- }
- return target;
- };
- return _extends.apply(this, arguments);
- }
- function _objectSpread(target) {
- for (var i = 1; i < arguments.length; i++) {
- var source = arguments[i] != null ? arguments[i] : {};
- var ownKeys = Object.keys(source);
- if (typeof Object.getOwnPropertySymbols === 'function') {
- ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
- }));
- }
- ownKeys.forEach(function (key) {
- _defineProperty(target, key, source[key]);
- });
- }
- return target;
- }
- function _objectWithoutPropertiesLoose(source, excluded) {
- if (source == null) return {};
- var target = {};
- var sourceKeys = Object.keys(source);
- var key, i;
- for (i = 0; i < sourceKeys.length; i++) {
- key = sourceKeys[i];
- if (excluded.indexOf(key) >= 0) continue;
- target[key] = source[key];
- }
- return target;
- }
- function _objectWithoutProperties(source, excluded) {
- if (source == null) return {};
- var target = _objectWithoutPropertiesLoose(source, excluded);
- var key, i;
- if (Object.getOwnPropertySymbols) {
- var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
- for (i = 0; i < sourceSymbolKeys.length; i++) {
- key = sourceSymbolKeys[i];
- if (excluded.indexOf(key) >= 0) continue;
- if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
- target[key] = source[key];
- }
- }
- return target;
- }
- function _toConsumableArray(arr) {
- return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
- }
- function _arrayWithoutHoles(arr) {
- if (Array.isArray(arr)) {
- for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
- return arr2;
- }
- }
- function _iterableToArray(iter) {
- if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
- }
- function _nonIterableSpread() {
- throw new TypeError("Invalid attempt to spread non-iterable instance");
- }
- var version = "1.10.0-rc3";
- function userAgent(pattern) {
- return !!
- /*@__PURE__*/
- navigator.userAgent.match(pattern);
- }
- var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
- var Edge = userAgent(/Edge/i);
- var FireFox = userAgent(/firefox/i);
- var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
- var IOS = userAgent(/iP(ad|od|hone)/i);
- var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
- var captureMode = {
- capture: false,
- passive: false
- };
- function on(el, event, fn) {
- el.addEventListener(event, fn, !IE11OrLess && captureMode);
- }
- function off(el, event, fn) {
- el.removeEventListener(event, fn, !IE11OrLess && captureMode);
- }
- function matches(
- /**HTMLElement*/
- el,
- /**String*/
- selector) {
- if (!selector) return;
- selector[0] === '>' && (selector = selector.substring(1));
- if (el) {
- try {
- if (el.matches) {
- return el.matches(selector);
- } else if (el.msMatchesSelector) {
- return el.msMatchesSelector(selector);
- } else if (el.webkitMatchesSelector) {
- return el.webkitMatchesSelector(selector);
- }
- } catch (_) {
- return false;
- }
- }
- return false;
- }
- function getParentOrHost(el) {
- return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
- }
- function closest(
- /**HTMLElement*/
- el,
- /**String*/
- selector,
- /**HTMLElement*/
- ctx, includeCTX) {
- if (el) {
- ctx = ctx || document;
- do {
- if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
- return el;
- }
- if (el === ctx) break;
- /* jshint boss:true */
- } while (el = getParentOrHost(el));
- }
- return null;
- }
- var R_SPACE = /\s+/g;
- function toggleClass(el, name, state) {
- if (el && name) {
- if (el.classList) {
- el.classList[state ? 'add' : 'remove'](name);
- } else {
- var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
- el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
- }
- }
- }
- function css(el, prop, val) {
- var style = el && el.style;
- if (style) {
- if (val === void 0) {
- if (document.defaultView && document.defaultView.getComputedStyle) {
- val = document.defaultView.getComputedStyle(el, '');
- } else if (el.currentStyle) {
- val = el.currentStyle;
- }
- return prop === void 0 ? val : val[prop];
- } else {
- if (!(prop in style) && prop.indexOf('webkit') === -1) {
- prop = '-webkit-' + prop;
- }
- style[prop] = val + (typeof val === 'string' ? '' : 'px');
- }
- }
- }
- function matrix(el, selfOnly) {
- var appliedTransforms = '';
- do {
- var transform = css(el, 'transform');
- if (transform && transform !== 'none') {
- appliedTransforms = transform + ' ' + appliedTransforms;
- }
- /* jshint boss:true */
- } while (!selfOnly && (el = el.parentNode));
- var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix;
- /*jshint -W056 */
- return matrixFn && new matrixFn(appliedTransforms);
- }
- function find(ctx, tagName, iterator) {
- if (ctx) {
- var list = ctx.getElementsByTagName(tagName),
- i = 0,
- n = list.length;
- if (iterator) {
- for (; i < n; i++) {
- iterator(list[i], i);
- }
- }
- return list;
- }
- return [];
- }
- function getWindowScrollingElement() {
- if (IE11OrLess) {
- return document.documentElement;
- } else {
- return document.scrollingElement;
- }
- }
- /**
- * Returns the "bounding client rect" of given element
- * @param {HTMLElement} el The element whose boundingClientRect is wanted
- * @param {[Boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container
- * @param {[Boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr
- * @param {[Boolean]} undoScale Whether the container's scale() should be undone
- * @param {[HTMLElement]} container The parent the element will be placed in
- * @return {Object} The boundingClientRect of el, with specified adjustments
- */
- function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
- if (!el.getBoundingClientRect && el !== window) return;
- var elRect, top, left, bottom, right, height, width;
- if (el !== window && el !== getWindowScrollingElement()) {
- elRect = el.getBoundingClientRect();
- top = elRect.top;
- left = elRect.left;
- bottom = elRect.bottom;
- right = elRect.right;
- height = elRect.height;
- width = elRect.width;
- } else {
- top = 0;
- left = 0;
- bottom = window.innerHeight;
- right = window.innerWidth;
- height = window.innerHeight;
- width = window.innerWidth;
- }
- if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
- // Adjust for translate()
- container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
- // Not needed on <= IE11
- if (!IE11OrLess) {
- do {
- if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
- var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container
- top -= containerRect.top + parseInt(css(container, 'border-top-width'));
- left -= containerRect.left + parseInt(css(container, 'border-left-width'));
- bottom = top + elRect.height;
- right = left + elRect.width;
- break;
- }
- /* jshint boss:true */
- } while (container = container.parentNode);
- }
- }
- if (undoScale && el !== window) {
- // Adjust for scale()
- var elMatrix = matrix(container || el),
- scaleX = elMatrix && elMatrix.a,
- scaleY = elMatrix && elMatrix.d;
- if (elMatrix) {
- top /= scaleY;
- left /= scaleX;
- width /= scaleX;
- height /= scaleY;
- bottom = top + height;
- right = left + width;
- }
- }
- return {
- top: top,
- left: left,
- bottom: bottom,
- right: right,
- width: width,
- height: height
- };
- }
- /**
- * Checks if a side of an element is scrolled past a side of its parents
- * @param {HTMLElement} el The element who's side being scrolled out of view is in question
- * @param {[DOMRect]} rect Optional rect of el to use
- * @param {String} elSide Side of the element in question ('top', 'left', 'right', 'bottom')
- * @param {String} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom')
- * @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element
- */
- function isScrolledPast(el, rect, elSide, parentSide) {
- var parent = getParentAutoScrollElement(el, true),
- elSideVal = (rect ? rect : getRect(el))[elSide];
- /* jshint boss:true */
- while (parent) {
- var parentSideVal = getRect(parent)[parentSide],
- visible = void 0;
- if (parentSide === 'top' || parentSide === 'left') {
- visible = elSideVal >= parentSideVal;
- } else {
- visible = elSideVal <= parentSideVal;
- }
- if (!visible) return parent;
- if (parent === getWindowScrollingElement()) break;
- parent = getParentAutoScrollElement(parent, false);
- }
- return false;
- }
- /**
- * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
- * and non-draggable elements
- * @param {HTMLElement} el The parent element
- * @param {Number} childNum The index of the child
- * @param {Object} options Parent Sortable's options
- * @return {HTMLElement} The child at index childNum, or null if not found
- */
- function getChild(el, childNum, options) {
- var currentChild = 0,
- i = 0,
- children = el.children;
- while (i < children.length) {
- if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && children[i] !== Sortable.dragged && closest(children[i], options.draggable, el, false)) {
- if (currentChild === childNum) {
- return children[i];
- }
- currentChild++;
- }
- i++;
- }
- return null;
- }
- /**
- * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
- * @param {HTMLElement} el Parent element
- * @param {selector} selector Any other elements that should be ignored
- * @return {HTMLElement} The last child, ignoring ghostEl
- */
- function lastChild(el, selector) {
- var last = el.lastElementChild;
- while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
- last = last.previousElementSibling;
- }
- return last || null;
- }
- /**
- * Returns the index of an element within its parent for a selected set of
- * elements
- * @param {HTMLElement} el
- * @param {selector} selector
- * @return {number}
- */
- function index(el, selector) {
- var index = 0;
- if (!el || !el.parentNode) {
- return -1;
- }
- /* jshint boss:true */
- while (el = el.previousElementSibling) {
- if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
- index++;
- }
- }
- return index;
- }
- /**
- * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
- * The value is returned in real pixels.
- * @param {HTMLElement} el
- * @return {Array} Offsets in the format of [left, top]
- */
- function getRelativeScrollOffset(el) {
- var offsetLeft = 0,
- offsetTop = 0,
- winScroller = getWindowScrollingElement();
- if (el) {
- do {
- var elMatrix = matrix(el),
- scaleX = elMatrix.a,
- scaleY = elMatrix.d;
- offsetLeft += el.scrollLeft * scaleX;
- offsetTop += el.scrollTop * scaleY;
- } while (el !== winScroller && (el = el.parentNode));
- }
- return [offsetLeft, offsetTop];
- }
- /**
- * Returns the index of the object within the given array
- * @param {Array} arr Array that may or may not hold the object
- * @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
- * @return {Number} The index of the object in the array, or -1
- */
- function indexOfObject(arr, obj) {
- for (var i in arr) {
- if (!arr.hasOwnProperty(i)) continue;
- for (var key in obj) {
- if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
- }
- }
- return -1;
- }
- function getParentAutoScrollElement(el, includeSelf) {
- // skip to window
- if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
- var elem = el;
- var gotSelf = false;
- do {
- // we don't need to get elem css if it isn't even overflowing in the first place (performance)
- if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
- var elemCSS = css(elem);
- if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
- if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
- if (gotSelf || includeSelf) return elem;
- gotSelf = true;
- }
- }
- /* jshint boss:true */
- } while (elem = elem.parentNode);
- return getWindowScrollingElement();
- }
- function extend(dst, src) {
- if (dst && src) {
- for (var key in src) {
- if (src.hasOwnProperty(key)) {
- dst[key] = src[key];
- }
- }
- }
- return dst;
- }
- function isRectEqual(rect1, rect2) {
- return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
- }
- var _throttleTimeout;
- function throttle(callback, ms) {
- return function () {
- if (!_throttleTimeout) {
- var args = arguments,
- _this = this;
- if (args.length === 1) {
- callback.call(_this, args[0]);
- } else {
- callback.apply(_this, args);
- }
- _throttleTimeout = setTimeout(function () {
- _throttleTimeout = void 0;
- }, ms);
- }
- };
- }
- function cancelThrottle() {
- clearTimeout(_throttleTimeout);
- _throttleTimeout = void 0;
- }
- function scrollBy(el, x, y) {
- el.scrollLeft += x;
- el.scrollTop += y;
- }
- function clone(el) {
- var Polymer = window.Polymer;
- var $ = window.jQuery || window.Zepto;
- if (Polymer && Polymer.dom) {
- return Polymer.dom(el).cloneNode(true);
- } else if ($) {
- return $(el).clone(true)[0];
- } else {
- return el.cloneNode(true);
- }
- }
- function setRect(el, rect) {
- css(el, 'position', 'absolute');
- css(el, 'top', rect.top);
- css(el, 'left', rect.left);
- css(el, 'width', rect.width);
- css(el, 'height', rect.height);
- }
- function unsetRect(el) {
- css(el, 'position', '');
- css(el, 'top', '');
- css(el, 'left', '');
- css(el, 'width', '');
- css(el, 'height', '');
- }
- var expando = 'Sortable' + new Date().getTime();
- function AnimationStateManager() {
- var animationStates = [],
- animationCallbackId;
- return {
- captureAnimationState: function captureAnimationState() {
- animationStates = [];
- if (!this.options.animation) return;
- var children = [].slice.call(this.el.children);
- children.forEach(function (child) {
- if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
- animationStates.push({
- target: child,
- rect: getRect(child)
- });
- var fromRect = getRect(child); // If animating: compensate for current animation
- if (child.thisAnimationDuration) {
- var childMatrix = matrix(child, true);
- if (childMatrix) {
- fromRect.top -= childMatrix.f;
- fromRect.left -= childMatrix.e;
- }
- }
- child.fromRect = fromRect;
- });
- },
- addAnimationState: function addAnimationState(state) {
- animationStates.push(state);
- },
- removeAnimationState: function removeAnimationState(target) {
- animationStates.splice(indexOfObject(animationStates, {
- target: target
- }), 1);
- },
- animateAll: function animateAll(callback) {
- var _this = this;
- if (!this.options.animation) {
- clearTimeout(animationCallbackId);
- if (typeof callback === 'function') callback();
- return;
- }
- var animating = false,
- animationTime = 0;
- animationStates.forEach(function (state) {
- var time = 0,
- target = state.target,
- fromRect = target.fromRect,
- toRect = getRect(target),
- prevFromRect = target.prevFromRect,
- prevToRect = target.prevToRect,
- animatingRect = state.rect,
- targetMatrix = matrix(target, true);
- if (targetMatrix) {
- // Compensate for current animation
- toRect.top -= targetMatrix.f;
- toRect.left -= targetMatrix.e;
- }
- target.toRect = toRect; // If element is scrolled out of view: Do not animate
- if ((isScrolledPast(target, toRect, 'bottom', 'top') || isScrolledPast(target, toRect, 'top', 'bottom') || isScrolledPast(target, toRect, 'right', 'left') || isScrolledPast(target, toRect, 'left', 'right')) && (isScrolledPast(target, animatingRect, 'bottom', 'top') || isScrolledPast(target, animatingRect, 'top', 'bottom') || isScrolledPast(target, animatingRect, 'right', 'left') || isScrolledPast(target, animatingRect, 'left', 'right')) && (isScrolledPast(target, fromRect, 'bottom', 'top') || isScrolledPast(target, fromRect, 'top', 'bottom') || isScrolledPast(target, fromRect, 'right', 'left') || isScrolledPast(target, fromRect, 'left', 'right'))) return;
- if (target.thisAnimationDuration) {
- // Could also check if animatingRect is between fromRect and toRect
- if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
- (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
- // If returning to same place as started from animation and on same axis
- time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
- }
- } // if fromRect != toRect: animate
- if (!isRectEqual(toRect, fromRect)) {
- target.prevFromRect = fromRect;
- target.prevToRect = toRect;
- if (!time) {
- time = _this.options.animation;
- }
- _this.animate(target, animatingRect, time);
- }
- if (time) {
- animating = true;
- animationTime = Math.max(animationTime, time);
- clearTimeout(target.animationResetTimer);
- target.animationResetTimer = setTimeout(function () {
- target.animationTime = 0;
- target.prevFromRect = null;
- target.fromRect = null;
- target.prevToRect = null;
- target.thisAnimationDuration = null;
- }, time);
- target.thisAnimationDuration = time;
- }
- });
- clearTimeout(animationCallbackId);
- if (!animating) {
- if (typeof callback === 'function') callback();
- } else {
- animationCallbackId = setTimeout(function () {
- if (typeof callback === 'function') callback();
- }, animationTime);
- }
- animationStates = [];
- },
- animate: function animate(target, prev, duration) {
- if (duration) {
- css(target, 'transition', '');
- css(target, 'transform', '');
- var currentRect = getRect(target),
- elMatrix = matrix(this.el),
- scaleX = elMatrix && elMatrix.a,
- scaleY = elMatrix && elMatrix.d,
- translateX = (prev.left - currentRect.left) / (scaleX || 1),
- translateY = (prev.top - currentRect.top) / (scaleY || 1);
- target.animatingX = !!translateX;
- target.animatingY = !!translateY;
- css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
- repaint(target); // repaint
- css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
- css(target, 'transform', 'translate3d(0,0,0)');
- typeof target.animated === 'number' && clearTimeout(target.animated);
- target.animated = setTimeout(function () {
- css(target, 'transition', '');
- css(target, 'transform', '');
- target.animated = false;
- target.animatingX = false;
- target.animatingY = false;
- }, duration);
- }
- }
- };
- }
- function repaint(target) {
- return target.offsetWidth;
- }
- function calculateRealTime(animatingRect, fromRect, toRect, options) {
- return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
- }
- var plugins = [];
- var defaults = {
- initializeByDefault: true
- };
- var PluginManager = {
- mount: function mount(plugin) {
- // Set default static properties
- for (var option in defaults) {
- if (defaults.hasOwnProperty(option) && !(option in plugin)) {
- plugin[option] = defaults[option];
- }
- }
- plugins.push(plugin);
- },
- pluginEvent: function pluginEvent(eventName, sortable, evt) {
- var _this = this;
- this.eventCanceled = false;
- var eventNameGlobal = eventName + 'Global';
- plugins.forEach(function (plugin) {
- if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable
- if (sortable[plugin.pluginName][eventNameGlobal]) {
- _this.eventCanceled = !!sortable[plugin.pluginName][eventNameGlobal](_objectSpread({
- sortable: sortable
- }, evt));
- } // Only fire plugin event if plugin is enabled in this sortable,
- // and plugin has event defined
- if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
- _this.eventCanceled = _this.eventCanceled || !!sortable[plugin.pluginName][eventName](_objectSpread({
- sortable: sortable
- }, evt));
- }
- });
- },
- initializePlugins: function initializePlugins(sortable, el, defaults) {
- plugins.forEach(function (plugin) {
- var pluginName = plugin.pluginName;
- if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
- var initialized = new plugin(sortable, el);
- initialized.sortable = sortable;
- sortable[pluginName] = initialized; // Add default options from plugin
- _extends(defaults, initialized.options);
- });
- for (var option in sortable.options) {
- if (!sortable.options.hasOwnProperty(option)) continue;
- var modified = this.modifyOption(sortable, option, sortable.options[option]);
- if (typeof modified !== 'undefined') {
- sortable.options[option] = modified;
- }
- }
- },
- getEventOptions: function getEventOptions(name, sortable) {
- var eventOptions = {};
- plugins.forEach(function (plugin) {
- if (typeof plugin.eventOptions !== 'function') return;
- _extends(eventOptions, plugin.eventOptions.call(sortable, name));
- });
- return eventOptions;
- },
- modifyOption: function modifyOption(sortable, name, value) {
- var modifiedValue;
- plugins.forEach(function (plugin) {
- // Plugin must exist on the Sortable
- if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
- if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
- modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
- }
- });
- return modifiedValue;
- }
- };
- function dispatchEvent(_ref) {
- var sortable = _ref.sortable,
- rootEl = _ref.rootEl,
- name = _ref.name,
- targetEl = _ref.targetEl,
- cloneEl = _ref.cloneEl,
- toEl = _ref.toEl,
- fromEl = _ref.fromEl,
- oldIndex = _ref.oldIndex,
- newIndex = _ref.newIndex,
- oldDraggableIndex = _ref.oldDraggableIndex,
- newDraggableIndex = _ref.newDraggableIndex,
- originalEvent = _ref.originalEvent,
- putSortable = _ref.putSortable,
- eventOptions = _ref.eventOptions;
- sortable = sortable || rootEl[expando];
- var evt,
- options = sortable.options,
- onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature
- if (window.CustomEvent && !IE11OrLess && !Edge) {
- evt = new CustomEvent(name, {
- bubbles: true,
- cancelable: true
- });
- } else {
- evt = document.createEvent('Event');
- evt.initEvent(name, true, true);
- }
- evt.to = toEl || rootEl;
- evt.from = fromEl || rootEl;
- evt.item = targetEl || rootEl;
- evt.clone = cloneEl;
- evt.oldIndex = oldIndex;
- evt.newIndex = newIndex;
- evt.oldDraggableIndex = oldDraggableIndex;
- evt.newDraggableIndex = newDraggableIndex;
- evt.originalEvent = originalEvent;
- evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
- var allEventOptions = _objectSpread({}, eventOptions, PluginManager.getEventOptions(name, sortable));
- for (var option in allEventOptions) {
- evt[option] = allEventOptions[option];
- }
- if (rootEl) {
- rootEl.dispatchEvent(evt);
- }
- if (options[onName]) {
- options[onName].call(sortable, evt);
- }
- }
- var pluginEvent = function pluginEvent(eventName, sortable) {
- var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
- originalEvent = _ref.evt,
- data = _objectWithoutProperties(_ref, ["evt"]);
- PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread({
- dragEl: dragEl,
- parentEl: parentEl,
- ghostEl: ghostEl,
- rootEl: rootEl,
- nextEl: nextEl,
- lastDownEl: lastDownEl,
- cloneEl: cloneEl,
- cloneHidden: cloneHidden,
- dragStarted: moved,
- putSortable: putSortable,
- activeSortable: Sortable.active,
- originalEvent: originalEvent,
- oldIndex: oldIndex,
- oldDraggableIndex: oldDraggableIndex,
- newIndex: newIndex,
- newDraggableIndex: newDraggableIndex,
- hideGhostForTarget: _hideGhostForTarget,
- unhideGhostForTarget: _unhideGhostForTarget,
- cloneNowHidden: function cloneNowHidden() {
- cloneHidden = true;
- },
- cloneNowShown: function cloneNowShown() {
- cloneHidden = false;
- },
- dispatchSortableEvent: function dispatchSortableEvent(name) {
- _dispatchEvent({
- sortable: sortable,
- name: name,
- originalEvent: originalEvent
- });
- }
- }, data));
- };
- function _dispatchEvent(info) {
- dispatchEvent(_objectSpread({
- putSortable: putSortable,
- cloneEl: cloneEl,
- targetEl: dragEl,
- rootEl: rootEl,
- oldIndex: oldIndex,
- oldDraggableIndex: oldDraggableIndex,
- newIndex: newIndex,
- newDraggableIndex: newDraggableIndex
- }, info));
- }
- if (typeof window === "undefined" || !window.document) {
- throw new Error("Sortable.js requires a window with a document");
- }
- var dragEl,
- parentEl,
- ghostEl,
- rootEl,
- nextEl,
- lastDownEl,
- cloneEl,
- cloneHidden,
- oldIndex,
- newIndex,
- oldDraggableIndex,
- newDraggableIndex,
- activeGroup,
- putSortable,
- awaitingDragStarted = false,
- ignoreNextClick = false,
- sortables = [],
- tapEvt,
- touchEvt,
- moved,
- lastTarget,
- lastDirection,
- pastFirstInvertThresh = false,
- isCircumstantialInvert = false,
- targetMoveDistance,
- // For positioning ghost absolutely
- ghostRelativeParent,
- ghostRelativeParentInitialScroll = [],
- // (left, top)
- _silent = false,
- savedInputChecked = [];
- /** @const */
- var PositionGhostAbsolutely = IOS,
- CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
- // This will not pass for IE9, because IE9 DnD only works on anchors
- supportDraggable = !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
- supportCssPointerEvents = function () {
- // false when <= IE11
- if (IE11OrLess) {
- return false;
- }
- var el = document.createElement('x');
- el.style.cssText = 'pointer-events:auto';
- return el.style.pointerEvents === 'auto';
- }(),
- _detectDirection = function _detectDirection(el, options) {
- var elCSS = css(el),
- elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
- child1 = getChild(el, 0, options),
- child2 = getChild(el, 1, options),
- firstChildCSS = child1 && css(child1),
- secondChildCSS = child2 && css(child2),
- firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
- secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
- if (elCSS.display === 'flex') {
- return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
- }
- if (elCSS.display === 'grid') {
- return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
- }
- if (child1 && firstChildCSS["float"] !== 'none') {
- var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
- return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
- }
- return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
- },
- _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
- var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
- dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
- dragElOppLength = vertical ? dragRect.width : dragRect.height,
- targetS1Opp = vertical ? targetRect.left : targetRect.top,
- targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
- targetOppLength = vertical ? targetRect.width : targetRect.height;
- return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
- },
- /**
- * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
- * @param {Number} x X position
- * @param {Number} y Y position
- * @return {HTMLElement} Element of the first found nearest Sortable
- */
- _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
- var ret;
- sortables.some(function (sortable) {
- if (lastChild(sortable)) return;
- var rect = getRect(sortable),
- threshold = sortable[expando].options.emptyInsertThreshold,
- insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
- insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
- if (threshold && insideHorizontally && insideVertically) {
- return ret = sortable;
- }
- });
- return ret;
- },
- _prepareGroup = function _prepareGroup(options) {
- function toFn(value, pull) {
- return function (to, from, dragEl, evt) {
- var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
- if (value == null && (pull || sameGroup)) {
- // Default pull value
- // Default pull and put value if same group
- return true;
- } else if (value == null || value === false) {
- return false;
- } else if (pull && value === 'clone') {
- return value;
- } else if (typeof value === 'function') {
- return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
- } else {
- var otherGroup = (pull ? to : from).options.group.name;
- return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
- }
- };
- }
- var group = {};
- var originalGroup = options.group;
- if (!originalGroup || _typeof(originalGroup) != 'object') {
- originalGroup = {
- name: originalGroup
- };
- }
- group.name = originalGroup.name;
- group.checkPull = toFn(originalGroup.pull, true);
- group.checkPut = toFn(originalGroup.put);
- group.revertClone = originalGroup.revertClone;
- options.group = group;
- },
- _hideGhostForTarget = function _hideGhostForTarget() {
- if (!supportCssPointerEvents && ghostEl) {
- css(ghostEl, 'display', 'none');
- }
- },
- _unhideGhostForTarget = function _unhideGhostForTarget() {
- if (!supportCssPointerEvents && ghostEl) {
- css(ghostEl, 'display', '');
- }
- }; // #1184 fix - Prevent click event on fallback if dragged but item not changed position
- document.addEventListener('click', function (evt) {
- if (ignoreNextClick) {
- evt.preventDefault();
- evt.stopPropagation && evt.stopPropagation();
- evt.stopImmediatePropagation && evt.stopImmediatePropagation();
- ignoreNextClick = false;
- return false;
- }
- }, true);
- var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
- if (dragEl) {
- evt = evt.touches ? evt.touches[0] : evt;
- var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
- if (nearest) {
- // Create imitation event
- var event = {};
- for (var i in evt) {
- if (evt.hasOwnProperty(i)) {
- event[i] = evt[i];
- }
- }
- event.target = event.rootEl = nearest;
- event.preventDefault = void 0;
- event.stopPropagation = void 0;
- nearest[expando]._onDragOver(event);
- }
- }
- };
- var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
- if (dragEl) {
- dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
- }
- };
- /**
- * @class Sortable
- * @param {HTMLElement} el
- * @param {Object} [options]
- */
- function Sortable(el, options) {
- if (!(el && el.nodeType && el.nodeType === 1)) {
- throw "Sortable: el must be an HTMLElement, not ".concat({}.toString.call(el));
- }
- this.el = el; // root element
- this.options = options = _extends({}, options); // Export instance
- el[expando] = this;
- var defaults = {
- group: null,
- sort: true,
- disabled: false,
- store: null,
- handle: null,
- draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
- swapThreshold: 1,
- // percentage; 0 <= x <= 1
- invertSwap: false,
- // invert always
- invertedSwapThreshold: null,
- // will be set to same as swapThreshold if default
- removeCloneOnHide: true,
- direction: function direction() {
- return _detectDirection(el, this.options);
- },
- ghostClass: 'sortable-ghost',
- chosenClass: 'sortable-chosen',
- dragClass: 'sortable-drag',
- ignore: 'a, img',
- filter: null,
- preventOnFilter: true,
- animation: 0,
- easing: null,
- setData: function setData(dataTransfer, dragEl) {
- dataTransfer.setData('Text', dragEl.textContent);
- },
- dropBubble: false,
- dragoverBubble: false,
- dataIdAttr: 'data-id',
- delay: 0,
- delayOnTouchOnly: false,
- touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
- forceFallback: false,
- fallbackClass: 'sortable-fallback',
- fallbackOnBody: false,
- fallbackTolerance: 0,
- fallbackOffset: {
- x: 0,
- y: 0
- },
- supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window,
- emptyInsertThreshold: 5
- };
- PluginManager.initializePlugins(this, el, defaults); // Set default options
- for (var name in defaults) {
- !(name in options) && (options[name] = defaults[name]);
- }
- _prepareGroup(options); // Bind all private methods
- for (var fn in this) {
- if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
- this[fn] = this[fn].bind(this);
- }
- } // Setup drag mode
- this.nativeDraggable = options.forceFallback ? false : supportDraggable;
- if (this.nativeDraggable) {
- // Touch start threshold cannot be greater than the native dragstart threshold
- this.options.touchStartThreshold = 1;
- } // Bind events
- if (options.supportPointer) {
- on(el, 'pointerdown', this._onTapStart);
- } else {
- on(el, 'mousedown', this._onTapStart);
- on(el, 'touchstart', this._onTapStart);
- }
- if (this.nativeDraggable) {
- on(el, 'dragover', this);
- on(el, 'dragenter', this);
- }
- sortables.push(this.el); // Restore sorting
- options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager
- _extends(this, AnimationStateManager());
- }
- Sortable.prototype =
- /** @lends Sortable.prototype */
- {
- constructor: Sortable,
- _isOutsideThisEl: function _isOutsideThisEl(target) {
- if (!this.el.contains(target) && target !== this.el) {
- lastTarget = null;
- }
- },
- _getDirection: function _getDirection(evt, target) {
- return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
- },
- _onTapStart: function _onTapStart(
- /** Event|TouchEvent */
- evt) {
- if (!evt.cancelable) return;
- var _this = this,
- el = this.el,
- options = this.options,
- preventOnFilter = options.preventOnFilter,
- type = evt.type,
- touch = evt.touches && evt.touches[0],
- target = (touch || evt).target,
- originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
- filter = options.filter;
- _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
- if (dragEl) {
- return;
- }
- if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
- return; // only left button and enabled
- } // cancel dnd if original target is content editable
- if (originalTarget.isContentEditable) {
- return;
- }
- target = closest(target, options.draggable, el, false);
- if (target && target.animated) {
- return;
- }
- if (lastDownEl === target) {
- // Ignoring duplicate down
- return;
- } // Get the index of the dragged element within its parent
- oldIndex = index(target);
- oldDraggableIndex = index(target, options.draggable); // Check filter
- if (typeof filter === 'function') {
- if (filter.call(this, evt, target, this)) {
- _dispatchEvent({
- sortable: _this,
- rootEl: originalTarget,
- name: 'filter',
- targetEl: target,
- toEl: el,
- fromEl: el
- });
- pluginEvent('filter', _this, {
- evt: evt
- });
- preventOnFilter && evt.cancelable && evt.preventDefault();
- return; // cancel dnd
- }
- } else if (filter) {
- filter = filter.split(',').some(function (criteria) {
- criteria = closest(originalTarget, criteria.trim(), el, false);
- if (criteria) {
- _dispatchEvent({
- sortable: _this,
- rootEl: criteria,
- name: 'filter',
- targetEl: target,
- fromEl: el,
- toEl: el
- });
- pluginEvent('filter', _this, {
- evt: evt
- });
- return true;
- }
- });
- if (filter) {
- preventOnFilter && evt.cancelable && evt.preventDefault();
- return; // cancel dnd
- }
- }
- if (options.handle && !closest(originalTarget, options.handle, el, false)) {
- return;
- } // Prepare
- this._prepareDragStart(evt, touch, target);
- },
- _prepareDragStart: function _prepareDragStart(
- /** Event */
- evt,
- /** Touch */
- touch,
- /** HTMLElement */
- target) {
- var _this = this,
- el = _this.el,
- options = _this.options,
- ownerDocument = el.ownerDocument,
- dragStartFn;
- if (target && !dragEl && target.parentNode === el) {
- rootEl = el;
- dragEl = target;
- parentEl = dragEl.parentNode;
- nextEl = dragEl.nextSibling;
- lastDownEl = target;
- activeGroup = options.group;
- Sortable.dragged = dragEl;
- tapEvt = {
- target: dragEl,
- clientX: (touch || evt).clientX,
- clientY: (touch || evt).clientY
- };
- this._lastX = (touch || evt).clientX;
- this._lastY = (touch || evt).clientY;
- dragEl.style['will-change'] = 'all';
- dragStartFn = function dragStartFn() {
- pluginEvent('delayEnded', _this, {
- evt: evt
- });
- if (Sortable.eventCanceled) {
- _this._onDrop();
- return;
- } // Delayed drag has been triggered
- // we can re-enable the events: touchmove/mousemove
- _this._disableDelayedDragEvents();
- if (!FireFox && _this.nativeDraggable) {
- dragEl.draggable = true;
- } // Bind the events: dragstart/dragend
- _this._triggerDragStart(evt, touch); // Drag start event
- _dispatchEvent({
- sortable: _this,
- name: 'choose',
- originalEvent: evt
- }); // Chosen item
- toggleClass(dragEl, options.chosenClass, true);
- }; // Disable "draggable"
- options.ignore.split(',').forEach(function (criteria) {
- find(dragEl, criteria.trim(), _disableDraggable);
- });
- on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
- on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
- on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
- on(ownerDocument, 'mouseup', _this._onDrop);
- on(ownerDocument, 'touchend', _this._onDrop);
- on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)
- if (FireFox && this.nativeDraggable) {
- this.options.touchStartThreshold = 4;
- dragEl.draggable = true;
- }
- pluginEvent('delayStart', this, {
- evt: evt
- }); // Delay is impossible for native DnD in Edge or IE
- if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
- if (Sortable.eventCanceled) {
- this._onDrop();
- return;
- } // If the user moves the pointer or let go the click or touch
- // before the delay has been reached:
- // disable the delayed drag
- on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
- on(ownerDocument, 'touchend', _this._disableDelayedDrag);
- on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
- on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
- on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
- options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
- _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
- } else {
- dragStartFn();
- }
- }
- },
- _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
- /** TouchEvent|PointerEvent **/
- e) {
- var touch = e.touches ? e.touches[0] : e;
- if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
- this._disableDelayedDrag();
- }
- },
- _disableDelayedDrag: function _disableDelayedDrag() {
- dragEl && _disableDraggable(dragEl);
- clearTimeout(this._dragStartTimer);
- this._disableDelayedDragEvents();
- },
- _disableDelayedDragEvents: function _disableDelayedDragEvents() {
- var ownerDocument = this.el.ownerDocument;
- off(ownerDocument, 'mouseup', this._disableDelayedDrag);
- off(ownerDocument, 'touchend', this._disableDelayedDrag);
- off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
- off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
- off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
- off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
- },
- _triggerDragStart: function _triggerDragStart(
- /** Event */
- evt,
- /** Touch */
- touch) {
- touch = touch || evt.pointerType == 'touch' && evt;
- if (!this.nativeDraggable || touch) {
- if (this.options.supportPointer) {
- on(document, 'pointermove', this._onTouchMove);
- } else if (touch) {
- on(document, 'touchmove', this._onTouchMove);
- } else {
- on(document, 'mousemove', this._onTouchMove);
- }
- } else {
- on(dragEl, 'dragend', this);
- on(rootEl, 'dragstart', this._onDragStart);
- }
- try {
- if (document.selection) {
- // Timeout neccessary for IE9
- _nextTick(function () {
- document.selection.empty();
- });
- } else {
- window.getSelection().removeAllRanges();
- }
- } catch (err) {}
- },
- _dragStarted: function _dragStarted(fallback, evt) {
- awaitingDragStarted = false;
- if (rootEl && dragEl) {
- pluginEvent('dragStarted', this, {
- evt: evt
- });
- if (this.nativeDraggable) {
- on(document, 'dragover', _checkOutsideTargetEl);
- }
- var options = this.options; // Apply effect
- !fallback && toggleClass(dragEl, options.dragClass, false);
- toggleClass(dragEl, options.ghostClass, true);
- Sortable.active = this;
- fallback && this._appendGhost(); // Drag start event
- _dispatchEvent({
- sortable: this,
- name: 'start',
- originalEvent: evt
- });
- } else {
- this._nulling();
- }
- },
- _emulateDragOver: function _emulateDragOver() {
- if (touchEvt) {
- this._lastX = touchEvt.clientX;
- this._lastY = touchEvt.clientY;
- _hideGhostForTarget();
- var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
- var parent = target;
- while (target && target.shadowRoot) {
- target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
- if (target === parent) break;
- parent = target;
- }
- dragEl.parentNode[expando]._isOutsideThisEl(target);
- if (parent) {
- do {
- if (parent[expando]) {
- var inserted = void 0;
- inserted = parent[expando]._onDragOver({
- clientX: touchEvt.clientX,
- clientY: touchEvt.clientY,
- target: target,
- rootEl: parent
- });
- if (inserted && !this.options.dragoverBubble) {
- break;
- }
- }
- target = parent; // store last element
- }
- /* jshint boss:true */
- while (parent = parent.parentNode);
- }
- _unhideGhostForTarget();
- }
- },
- _onTouchMove: function _onTouchMove(
- /**TouchEvent*/
- evt) {
- if (tapEvt) {
- var options = this.options,
- fallbackTolerance = options.fallbackTolerance,
- fallbackOffset = options.fallbackOffset,
- touch = evt.touches ? evt.touches[0] : evt,
- ghostMatrix = ghostEl && matrix(ghostEl),
- scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
- scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
- relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
- dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
- dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1),
- translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; // only set the status to dragging, when we are actually dragging
- if (!Sortable.active && !awaitingDragStarted) {
- if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
- return;
- }
- this._onDragStart(evt, true);
- }
- touchEvt = touch;
- css(ghostEl, 'webkitTransform', translate3d);
- css(ghostEl, 'mozTransform', translate3d);
- css(ghostEl, 'msTransform', translate3d);
- css(ghostEl, 'transform', translate3d);
- evt.cancelable && evt.preventDefault();
- }
- },
- _appendGhost: function _appendGhost() {
- // Bug if using scale(): https://stackoverflow.com/questions/2637058
- // Not being adjusted for
- if (!ghostEl) {
- var container = this.options.fallbackOnBody ? document.body : rootEl,
- rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
- options = this.options; // Position absolutely
- if (PositionGhostAbsolutely) {
- // Get relatively positioned parent
- ghostRelativeParent = container;
- while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
- ghostRelativeParent = ghostRelativeParent.parentNode;
- }
- if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
- if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
- rect.top += ghostRelativeParent.scrollTop;
- rect.left += ghostRelativeParent.scrollLeft;
- } else {
- ghostRelativeParent = getWindowScrollingElement();
- }
- ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
- }
- ghostEl = dragEl.cloneNode(true);
- toggleClass(ghostEl, options.ghostClass, false);
- toggleClass(ghostEl, options.fallbackClass, true);
- toggleClass(ghostEl, options.dragClass, true);
- css(ghostEl, 'transition', '');
- css(ghostEl, 'transform', '');
- css(ghostEl, 'box-sizing', 'border-box');
- css(ghostEl, 'margin', 0);
- css(ghostEl, 'top', rect.top);
- css(ghostEl, 'left', rect.left);
- css(ghostEl, 'width', rect.width);
- css(ghostEl, 'height', rect.height);
- css(ghostEl, 'opacity', '0.8');
- css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
- css(ghostEl, 'zIndex', '100000');
- css(ghostEl, 'pointerEvents', 'none');
- Sortable.ghost = ghostEl;
- container.appendChild(ghostEl);
- }
- },
- _onDragStart: function _onDragStart(
- /**Event*/
- evt,
- /**boolean*/
- fallback) {
- var _this = this;
- var dataTransfer = evt.dataTransfer;
- var options = _this.options;
- pluginEvent('dragStart', this, {
- evt: evt
- });
- if (Sortable.eventCanceled) {
- this._onDrop();
- return;
- }
- pluginEvent('setupClone', this);
- if (!Sortable.eventCanceled) {
- cloneEl = clone(dragEl);
- cloneEl.draggable = false;
- cloneEl.style['will-change'] = '';
- this._hideClone();
- toggleClass(cloneEl, this.options.chosenClass, false);
- Sortable.clone = cloneEl;
- } // #1143: IFrame support workaround
- _this.cloneId = _nextTick(function () {
- pluginEvent('clone', _this);
- if (Sortable.eventCanceled) return;
- if (!_this.options.removeCloneOnHide) {
- rootEl.insertBefore(cloneEl, dragEl);
- }
- _this._hideClone();
- _dispatchEvent({
- sortable: _this,
- name: 'clone'
- });
- });
- !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events
- if (fallback) {
- ignoreNextClick = true;
- _this._loopId = setInterval(_this._emulateDragOver, 50);
- } else {
- // Undo what was set in _prepareDragStart before drag started
- off(document, 'mouseup', _this._onDrop);
- off(document, 'touchend', _this._onDrop);
- off(document, 'touchcancel', _this._onDrop);
- if (dataTransfer) {
- dataTransfer.effectAllowed = 'move';
- options.setData && options.setData.call(_this, dataTransfer, dragEl);
- }
- on(document, 'drop', _this); // #1276 fix:
- css(dragEl, 'transform', 'translateZ(0)');
- }
- awaitingDragStarted = true;
- _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
- on(document, 'selectstart', _this);
- moved = true;
- if (Safari) {
- css(document.body, 'user-select', 'none');
- }
- },
- // Returns true - if no further action is needed (either inserted or another condition)
- _onDragOver: function _onDragOver(
- /**Event*/
- evt) {
- var el = this.el,
- target = evt.target,
- dragRect,
- targetRect,
- revert,
- options = this.options,
- group = options.group,
- activeSortable = Sortable.active,
- isOwner = activeGroup === group,
- canSort = options.sort,
- fromSortable = putSortable || activeSortable,
- vertical,
- _this = this,
- completedFired = false;
- if (_silent) return;
- function dragOverEvent(name, extra) {
- pluginEvent(name, _this, _objectSpread({
- evt: evt,
- isOwner: isOwner,
- axis: vertical ? 'vertical' : 'horizontal',
- revert: revert,
- dragRect: dragRect,
- targetRect: targetRect,
- canSort: canSort,
- fromSortable: fromSortable,
- target: target,
- completed: completed,
- onMove: function onMove(target, after) {
- return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
- },
- changed: changed
- }, extra));
- } // Capture animation state
- function capture() {
- dragOverEvent('dragOverAnimationCapture');
- _this.captureAnimationState();
- if (_this !== fromSortable) {
- fromSortable.captureAnimationState();
- }
- } // Return invocation when dragEl is inserted (or completed)
- function completed(insertion) {
- dragOverEvent('dragOverCompleted', {
- insertion: insertion
- });
- if (insertion) {
- // Clones must be hidden before folding animation to capture dragRectAbsolute properly
- if (isOwner) {
- activeSortable._hideClone();
- } else {
- activeSortable._showClone(_this);
- }
- if (_this !== fromSortable) {
- // Set ghost class to new sortable's ghost class
- toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
- toggleClass(dragEl, options.ghostClass, true);
- }
- if (putSortable !== _this && _this !== Sortable.active) {
- putSortable = _this;
- } else if (_this === Sortable.active && putSortable) {
- putSortable = null;
- } // Animation
- if (fromSortable === _this) {
- _this._ignoreWhileAnimating = target;
- }
- _this.animateAll(function () {
- dragOverEvent('dragOverAnimationComplete');
- _this._ignoreWhileAnimating = null;
- });
- if (_this !== fromSortable) {
- fromSortable.animateAll();
- fromSortable._ignoreWhileAnimating = null;
- }
- } // Null lastTarget if it is not inside a previously swapped element
- if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
- lastTarget = null;
- } // no bubbling and not fallback
- if (!options.dragoverBubble && !evt.rootEl && target !== document) {
- dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted
- !insertion && nearestEmptyInsertDetectEvent(evt);
- }
- !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
- return completedFired = true;
- } // Call when dragEl has been inserted
- function changed() {
- newIndex = index(dragEl);
- newDraggableIndex = index(dragEl, options.draggable);
- _dispatchEvent({
- sortable: _this,
- name: 'change',
- toEl: el,
- newIndex: newIndex,
- newDraggableIndex: newDraggableIndex,
- originalEvent: evt
- });
- }
- if (evt.preventDefault !== void 0) {
- evt.cancelable && evt.preventDefault();
- }
- target = closest(target, options.draggable, el, true);
- dragOverEvent('dragOver');
- if (Sortable.eventCanceled) return completedFired;
- if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
- return completed(false);
- }
- ignoreNextClick = false;
- if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
- : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
- vertical = this._getDirection(evt, target) === 'vertical';
- dragRect = getRect(dragEl);
- dragOverEvent('dragOverValid');
- if (Sortable.eventCanceled) return completedFired;
- if (revert) {
- parentEl = rootEl; // actualization
- capture();
- this._hideClone();
- dragOverEvent('revert');
- if (!Sortable.eventCanceled) {
- if (nextEl) {
- rootEl.insertBefore(dragEl, nextEl);
- } else {
- rootEl.appendChild(dragEl);
- }
- }
- return completed(true);
- }
- var elLastChild = lastChild(el, options.draggable);
- if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
- // If already at end of list: Do not insert
- if (elLastChild === dragEl) {
- return completed(false);
- } // assign target only if condition is true
- if (elLastChild && el === evt.target) {
- target = elLastChild;
- }
- if (target) {
- targetRect = getRect(target);
- }
- if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
- capture();
- el.appendChild(dragEl);
- parentEl = el; // actualization
- changed();
- return completed(true);
- }
- } else if (target.parentNode === el) {
- targetRect = getRect(target);
- var direction = 0,
- targetBeforeFirstSwap,
- differentLevel = dragEl.parentNode !== el,
- differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
- side1 = vertical ? 'top' : 'left',
- scrolledPastTop = isScrolledPast(target, null, 'top', 'top') || isScrolledPast(dragEl, null, 'top', 'top'),
- scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
- if (lastTarget !== target) {
- targetBeforeFirstSwap = targetRect[side1];
- pastFirstInvertThresh = false;
- isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
- }
- direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
- var sibling;
- if (direction !== 0) {
- // Check if target is beside dragEl in respective direction (ignoring hidden elements)
- var dragIndex = index(dragEl);
- do {
- dragIndex -= direction;
- sibling = parentEl.children[dragIndex];
- } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
- } // If dragEl is already beside target: Do not insert
- if (direction === 0 || sibling === target) {
- return completed(false);
- }
- lastTarget = target;
- lastDirection = direction;
- var nextSibling = target.nextElementSibling,
- after = false;
- after = direction === 1;
- var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
- if (moveVector !== false) {
- if (moveVector === 1 || moveVector === -1) {
- after = moveVector === 1;
- }
- _silent = true;
- setTimeout(_unsilent, 30);
- capture();
- if (after && !nextSibling) {
- el.appendChild(dragEl);
- } else {
- target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
- } // Undo chrome's scroll adjustment (has no effect on other browsers)
- if (scrolledPastTop) {
- scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
- }
- parentEl = dragEl.parentNode; // actualization
- // must be done before animation
- if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
- targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
- }
- changed();
- return completed(true);
- }
- }
- if (el.contains(dragEl)) {
- return completed(false);
- }
- }
- return false;
- },
- _ignoreWhileAnimating: null,
- _offMoveEvents: function _offMoveEvents() {
- off(document, 'mousemove', this._onTouchMove);
- off(document, 'touchmove', this._onTouchMove);
- off(document, 'pointermove', this._onTouchMove);
- off(document, 'dragover', nearestEmptyInsertDetectEvent);
- off(document, 'mousemove', nearestEmptyInsertDetectEvent);
- off(document, 'touchmove', nearestEmptyInsertDetectEvent);
- },
- _offUpEvents: function _offUpEvents() {
- var ownerDocument = this.el.ownerDocument;
- off(ownerDocument, 'mouseup', this._onDrop);
- off(ownerDocument, 'touchend', this._onDrop);
- off(ownerDocument, 'pointerup', this._onDrop);
- off(ownerDocument, 'touchcancel', this._onDrop);
- off(document, 'selectstart', this);
- },
- _onDrop: function _onDrop(
- /**Event*/
- evt) {
- var el = this.el,
- options = this.options; // Get the index of the dragged element within its parent
- newIndex = index(dragEl);
- newDraggableIndex = index(dragEl, options.draggable);
- pluginEvent('drop', this, {
- evt: evt
- }); // Get again after plugin event
- newIndex = index(dragEl);
- newDraggableIndex = index(dragEl, options.draggable);
- if (Sortable.eventCanceled) {
- this._nulling();
- return;
- }
- awaitingDragStarted = false;
- isCircumstantialInvert = false;
- pastFirstInvertThresh = false;
- clearInterval(this._loopId);
- clearTimeout(this._dragStartTimer);
- _cancelNextTick(this.cloneId);
- _cancelNextTick(this._dragStartId); // Unbind events
- if (this.nativeDraggable) {
- off(document, 'drop', this);
- off(el, 'dragstart', this._onDragStart);
- }
- this._offMoveEvents();
- this._offUpEvents();
- if (Safari) {
- css(document.body, 'user-select', '');
- }
- if (evt) {
- if (moved) {
- evt.cancelable && evt.preventDefault();
- !options.dropBubble && evt.stopPropagation();
- }
- ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
- if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
- // Remove clone(s)
- cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
- }
- if (dragEl) {
- if (this.nativeDraggable) {
- off(dragEl, 'dragend', this);
- }
- _disableDraggable(dragEl);
- dragEl.style['will-change'] = ''; // Remove classes
- // ghostClass is added in dragStarted
- if (moved && !awaitingDragStarted) {
- toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
- }
- toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event
- _dispatchEvent({
- sortable: this,
- name: 'unchoose',
- toEl: parentEl,
- newIndex: null,
- newDraggableIndex: null,
- originalEvent: evt
- });
- if (rootEl !== parentEl) {
- if (newIndex >= 0) {
- // Add event
- _dispatchEvent({
- rootEl: parentEl,
- name: 'add',
- toEl: parentEl,
- fromEl: rootEl,
- originalEvent: evt
- }); // Remove event
- _dispatchEvent({
- sortable: this,
- name: 'remove',
- toEl: parentEl,
- originalEvent: evt
- }); // drag from one list and drop into another
- _dispatchEvent({
- rootEl: parentEl,
- name: 'sort',
- toEl: parentEl,
- fromEl: rootEl,
- originalEvent: evt
- });
- _dispatchEvent({
- sortable: this,
- name: 'sort',
- toEl: parentEl,
- originalEvent: evt
- });
- }
- putSortable && putSortable.save();
- } else {
- if (newIndex !== oldIndex) {
- if (newIndex >= 0) {
- // drag & drop within the same list
- _dispatchEvent({
- sortable: this,
- name: 'update',
- toEl: parentEl,
- originalEvent: evt
- });
- _dispatchEvent({
- sortable: this,
- name: 'sort',
- toEl: parentEl,
- originalEvent: evt
- });
- }
- }
- }
- if (Sortable.active) {
- /* jshint eqnull:true */
- if (newIndex == null || newIndex === -1) {
- newIndex = oldIndex;
- newDraggableIndex = oldDraggableIndex;
- }
- _dispatchEvent({
- sortable: this,
- name: 'end',
- toEl: parentEl,
- originalEvent: evt
- }); // Save sorting
- this.save();
- }
- }
- }
- this._nulling();
- },
- _nulling: function _nulling() {
- pluginEvent('nulling', this);
- rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
- savedInputChecked.forEach(function (el) {
- el.checked = true;
- });
- savedInputChecked.length = 0;
- },
- handleEvent: function handleEvent(
- /**Event*/
- evt) {
- switch (evt.type) {
- case 'drop':
- case 'dragend':
- this._onDrop(evt);
- break;
- case 'dragenter':
- case 'dragover':
- if (dragEl) {
- this._onDragOver(evt);
- _globalDragOver(evt);
- }
- break;
- case 'selectstart':
- evt.preventDefault();
- break;
- }
- },
- /**
- * Serializes the item into an array of string.
- * @returns {String[]}
- */
- toArray: function toArray() {
- var order = [],
- el,
- children = this.el.children,
- i = 0,
- n = children.length,
- options = this.options;
- for (; i < n; i++) {
- el = children[i];
- if (closest(el, options.draggable, this.el, false)) {
- order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
- }
- }
- return order;
- },
- /**
- * Sorts the elements according to the array.
- * @param {String[]} order order of the items
- */
- sort: function sort(order) {
- var items = {},
- rootEl = this.el;
- this.toArray().forEach(function (id, i) {
- var el = rootEl.children[i];
- if (closest(el, this.options.draggable, rootEl, false)) {
- items[id] = el;
- }
- }, this);
- order.forEach(function (id) {
- if (items[id]) {
- rootEl.removeChild(items[id]);
- rootEl.appendChild(items[id]);
- }
- });
- },
- /**
- * Save the current sorting
- */
- save: function save() {
- var store = this.options.store;
- store && store.set && store.set(this);
- },
- /**
- * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
- * @param {HTMLElement} el
- * @param {String} [selector] default: options.draggable
- * @returns {HTMLElement|null}
- */
- closest: function closest$1(el, selector) {
- return closest(el, selector || this.options.draggable, this.el, false);
- },
- /**
- * Set/get option
- * @param {string} name
- * @param {*} [value]
- * @returns {*}
- */
- option: function option(name, value) {
- var options = this.options;
- if (value === void 0) {
- return options[name];
- } else {
- var modifiedValue = PluginManager.modifyOption(this, name, value);
- if (typeof modifiedValue !== 'undefined') {
- options[name] = modifiedValue;
- } else {
- options[name] = value;
- }
- if (name === 'group') {
- _prepareGroup(options);
- }
- }
- },
- /**
- * Destroy
- */
- destroy: function destroy() {
- pluginEvent('destroy', this);
- var el = this.el;
- el[expando] = null;
- off(el, 'mousedown', this._onTapStart);
- off(el, 'touchstart', this._onTapStart);
- off(el, 'pointerdown', this._onTapStart);
- if (this.nativeDraggable) {
- off(el, 'dragover', this);
- off(el, 'dragenter', this);
- } // Remove draggable attributes
- Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
- el.removeAttribute('draggable');
- });
- this._onDrop();
- sortables.splice(sortables.indexOf(this.el), 1);
- this.el = el = null;
- },
- _hideClone: function _hideClone() {
- if (!cloneHidden) {
- pluginEvent('hideClone', this);
- if (Sortable.eventCanceled) return;
- css(cloneEl, 'display', 'none');
- if (this.options.removeCloneOnHide && cloneEl.parentNode) {
- cloneEl.parentNode.removeChild(cloneEl);
- }
- cloneHidden = true;
- }
- },
- _showClone: function _showClone(putSortable) {
- if (putSortable.lastPutMode !== 'clone') {
- this._hideClone();
- return;
- }
- if (cloneHidden) {
- pluginEvent('showClone', this);
- if (Sortable.eventCanceled) return; // show clone at dragEl or original position
- if (rootEl.contains(dragEl) && !this.options.group.revertClone) {
- rootEl.insertBefore(cloneEl, dragEl);
- } else if (nextEl) {
- rootEl.insertBefore(cloneEl, nextEl);
- } else {
- rootEl.appendChild(cloneEl);
- }
- if (this.options.group.revertClone) {
- this._animate(dragEl, cloneEl);
- }
- css(cloneEl, 'display', '');
- cloneHidden = false;
- }
- }
- };
- function _globalDragOver(
- /**Event*/
- evt) {
- if (evt.dataTransfer) {
- evt.dataTransfer.dropEffect = 'move';
- }
- evt.cancelable && evt.preventDefault();
- }
- function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
- var evt,
- sortable = fromEl[expando],
- onMoveFn = sortable.options.onMove,
- retVal; // Support for new CustomEvent feature
- if (window.CustomEvent && !IE11OrLess && !Edge) {
- evt = new CustomEvent('move', {
- bubbles: true,
- cancelable: true
- });
- } else {
- evt = document.createEvent('Event');
- evt.initEvent('move', true, true);
- }
- evt.to = toEl;
- evt.from = fromEl;
- evt.dragged = dragEl;
- evt.draggedRect = dragRect;
- evt.related = targetEl || toEl;
- evt.relatedRect = targetRect || getRect(toEl);
- evt.willInsertAfter = willInsertAfter;
- evt.originalEvent = originalEvent;
- fromEl.dispatchEvent(evt);
- if (onMoveFn) {
- retVal = onMoveFn.call(sortable, evt, originalEvent);
- }
- return retVal;
- }
- function _disableDraggable(el) {
- el.draggable = false;
- }
- function _unsilent() {
- _silent = false;
- }
- function _ghostIsLast(evt, vertical, sortable) {
- var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
- var spacer = 10;
- return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
- }
- function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
- var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
- targetLength = vertical ? targetRect.height : targetRect.width,
- targetS1 = vertical ? targetRect.top : targetRect.left,
- targetS2 = vertical ? targetRect.bottom : targetRect.right,
- invert = false;
- if (!invertSwap) {
- // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
- if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
- // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
- // check if past first invert threshold on side opposite of lastDirection
- if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
- // past first invert threshold, do not restrict inverted threshold to dragEl shadow
- pastFirstInvertThresh = true;
- }
- if (!pastFirstInvertThresh) {
- // dragEl shadow (target move distance shadow)
- if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
- : mouseOnAxis > targetS2 - targetMoveDistance) {
- return -lastDirection;
- }
- } else {
- invert = true;
- }
- } else {
- // Regular
- if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
- return _getInsertDirection(target);
- }
- }
- }
- invert = invert || invertSwap;
- if (invert) {
- // Invert of regular
- if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
- return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
- }
- }
- return 0;
- }
- /**
- * Gets the direction dragEl must be swapped relative to target in order to make it
- * seem that dragEl has been "inserted" into that element's position
- * @param {HTMLElement} target The target whose position dragEl is being inserted at
- * @return {Number} Direction dragEl must be swapped
- */
- function _getInsertDirection(target) {
- if (index(dragEl) < index(target)) {
- return 1;
- } else {
- return -1;
- }
- }
- /**
- * Generate id
- * @param {HTMLElement} el
- * @returns {String}
- * @private
- */
- function _generateId(el) {
- var str = el.tagName + el.className + el.src + el.href + el.textContent,
- i = str.length,
- sum = 0;
- while (i--) {
- sum += str.charCodeAt(i);
- }
- return sum.toString(36);
- }
- function _saveInputCheckedState(root) {
- savedInputChecked.length = 0;
- var inputs = root.getElementsByTagName('input');
- var idx = inputs.length;
- while (idx--) {
- var _el = inputs[idx];
- _el.checked && savedInputChecked.push(_el);
- }
- }
- function _nextTick(fn) {
- return setTimeout(fn, 0);
- }
- function _cancelNextTick(id) {
- return clearTimeout(id);
- } // Fixed #973:
- on(document, 'touchmove', function (evt) {
- if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
- evt.preventDefault();
- }
- }); // Export utils
- Sortable.utils = {
- on: on,
- off: off,
- css: css,
- find: find,
- is: function is(el, selector) {
- return !!closest(el, selector, el, false);
- },
- extend: extend,
- throttle: throttle,
- closest: closest,
- toggleClass: toggleClass,
- clone: clone,
- index: index,
- nextTick: _nextTick,
- cancelNextTick: _cancelNextTick,
- detectDirection: _detectDirection,
- getChild: getChild
- };
- /**
- * Mount a plugin to Sortable
- * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted
- */
- Sortable.mount = function () {
- for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
- plugins[_key] = arguments[_key];
- }
- if (plugins[0].constructor === Array) plugins = plugins[0];
- plugins.forEach(function (plugin) {
- if (!plugin.prototype || !plugin.prototype.constructor) {
- throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(el));
- }
- if (plugin.utils) Sortable.utils = _objectSpread({}, Sortable.utils, plugin.utils);
- PluginManager.mount(plugin);
- });
- };
- /**
- * Create sortable instance
- * @param {HTMLElement} el
- * @param {Object} [options]
- */
- Sortable.create = function (el, options) {
- return new Sortable(el, options);
- }; // Export
- Sortable.version = version;
- var autoScrolls = [],
- scrollEl,
- scrollRootEl,
- scrolling = false,
- lastAutoScrollX,
- lastAutoScrollY,
- touchEvt$1,
- pointerElemChangedInterval;
- function AutoScrollPlugin() {
- function AutoScroll() {
- this.options = {
- scroll: true,
- scrollSensitivity: 30,
- scrollSpeed: 10,
- bubbleScroll: true
- }; // Bind all private methods
- for (var fn in this) {
- if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
- this[fn] = this[fn].bind(this);
- }
- }
- }
- AutoScroll.prototype = {
- dragStarted: function dragStarted(_ref) {
- var originalEvent = _ref.originalEvent;
- if (this.sortable.nativeDraggable) {
- on(document, 'dragover', this._handleAutoScroll);
- } else {
- if (this.sortable.options.supportPointer) {
- on(document, 'pointermove', this._handleFallbackAutoScroll);
- } else if (originalEvent.touches) {
- on(document, 'touchmove', this._handleFallbackAutoScroll);
- } else {
- on(document, 'mousemove', this._handleFallbackAutoScroll);
- }
- }
- },
- dragOverCompleted: function dragOverCompleted(_ref2) {
- var originalEvent = _ref2.originalEvent;
- // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
- if (!this.sortable.options.dragOverBubble && !originalEvent.rootEl) {
- this._handleAutoScroll(originalEvent);
- }
- },
- drop: function drop() {
- if (this.sortable.nativeDraggable) {
- off(document, 'dragover', this._handleAutoScroll);
- } else {
- off(document, 'pointermove', this._handleFallbackAutoScroll);
- off(document, 'touchmove', this._handleFallbackAutoScroll);
- off(document, 'mousemove', this._handleFallbackAutoScroll);
- }
- clearPointerElemChangedInterval();
- clearAutoScrolls();
- cancelThrottle();
- },
- nulling: function nulling() {
- touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
- autoScrolls.length = 0;
- },
- _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
- this._handleAutoScroll(evt, true);
- },
- _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
- var _this = this;
- var x = evt.clientX,
- y = evt.clientY,
- elem = document.elementFromPoint(x, y);
- touchEvt$1 = evt; // IE does not seem to have native autoscroll,
- // Edge's autoscroll seems too conditional,
- // MACOS Safari does not have autoscroll,
- // Firefox and Chrome are good
- if (fallback || Edge || IE11OrLess || Safari) {
- autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change
- var ogElemScroller = getParentAutoScrollElement(elem, true);
- if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
- pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour
- pointerElemChangedInterval = setInterval(function () {
- var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
- if (newElem !== ogElemScroller) {
- ogElemScroller = newElem;
- clearAutoScrolls();
- }
- autoScroll(evt, _this.options, newElem, fallback);
- }, 10);
- lastAutoScrollX = x;
- lastAutoScrollY = y;
- }
- } else {
- // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
- if (!this.sortable.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
- clearAutoScrolls();
- return;
- }
- autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
- }
- }
- };
- return _extends(AutoScroll, {
- pluginName: 'scroll',
- initializeByDefault: true
- });
- }
- function clearAutoScrolls() {
- autoScrolls.forEach(function (autoScroll) {
- clearInterval(autoScroll.pid);
- });
- autoScrolls = [];
- }
- function clearPointerElemChangedInterval() {
- clearInterval(pointerElemChangedInterval);
- }
- var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
- // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
- if (!options.scroll) return;
- var sens = options.scrollSensitivity,
- speed = options.scrollSpeed,
- winScroller = getWindowScrollingElement();
- var scrollThisInstance = false,
- scrollCustomFn; // New scroll root, set scrollEl
- if (scrollRootEl !== rootEl) {
- scrollRootEl = rootEl;
- clearAutoScrolls();
- scrollEl = options.scroll;
- scrollCustomFn = options.scrollFn;
- if (scrollEl === true) {
- scrollEl = getParentAutoScrollElement(rootEl, true);
- }
- }
- var layersOut = 0;
- var currentParent = scrollEl;
- do {
- var el = currentParent,
- rect = getRect(el),
- top = rect.top,
- bottom = rect.bottom,
- left = rect.left,
- right = rect.right,
- width = rect.width,
- height = rect.height,
- canScrollX = void 0,
- canScrollY = void 0,
- scrollWidth = el.scrollWidth,
- scrollHeight = el.scrollHeight,
- elCSS = css(el),
- scrollPosX = el.scrollLeft,
- scrollPosY = el.scrollTop;
- if (el === winScroller) {
- canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
- canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
- } else {
- canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
- canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
- }
- var vx = canScrollX && (Math.abs(right - evt.clientX) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - evt.clientX) <= sens && !!scrollPosX);
- var vy = canScrollY && (Math.abs(bottom - evt.clientY) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - evt.clientY) <= sens && !!scrollPosY);
- if (!autoScrolls[layersOut]) {
- for (var i = 0; i <= layersOut; i++) {
- if (!autoScrolls[i]) {
- autoScrolls[i] = {};
- }
- }
- }
- if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
- autoScrolls[layersOut].el = el;
- autoScrolls[layersOut].vx = vx;
- autoScrolls[layersOut].vy = vy;
- clearInterval(autoScrolls[layersOut].pid);
- if (vx != 0 || vy != 0) {
- scrollThisInstance = true;
- /* jshint loopfunc:true */
- autoScrolls[layersOut].pid = setInterval(function () {
- // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
- if (isFallback && this.layer === 0) {
- Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
- }
- var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
- var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
- if (typeof scrollCustomFn === 'function') {
- if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
- return;
- }
- }
- scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
- }.bind({
- layer: layersOut
- }), 24);
- }
- }
- layersOut++;
- } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
- scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
- }, 30);
- var drop = function drop(_ref) {
- var originalEvent = _ref.originalEvent,
- putSortable = _ref.putSortable,
- dragEl = _ref.dragEl,
- activeSortable = _ref.activeSortable,
- dispatchSortableEvent = _ref.dispatchSortableEvent,
- hideGhostForTarget = _ref.hideGhostForTarget,
- unhideGhostForTarget = _ref.unhideGhostForTarget;
- var toSortable = putSortable || activeSortable;
- hideGhostForTarget();
- var target = document.elementFromPoint(originalEvent.clientX, originalEvent.clientY);
- unhideGhostForTarget();
- if (toSortable && !toSortable.el.contains(target)) {
- dispatchSortableEvent('spill');
- this.onSpill(dragEl);
- }
- };
- function Revert() {}
- Revert.prototype = {
- startIndex: null,
- dragStart: function dragStart(_ref2) {
- var oldDraggableIndex = _ref2.oldDraggableIndex;
- this.startIndex = oldDraggableIndex;
- },
- onSpill: function onSpill(dragEl) {
- this.sortable.captureAnimationState();
- var nextSibling = getChild(this.sortable.el, this.startIndex, this.sortable.options);
- if (nextSibling) {
- this.sortable.el.insertBefore(dragEl, nextSibling);
- } else {
- this.sortable.el.appendChild(dragEl);
- }
- this.sortable.animateAll();
- },
- drop: drop
- };
- _extends(Revert, {
- pluginName: 'revertOnSpill'
- });
- function Remove() {}
- Remove.prototype = {
- onSpill: function onSpill(dragEl) {
- this.sortable.captureAnimationState();
- dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
- this.sortable.animateAll();
- },
- drop: drop
- };
- _extends(Remove, {
- pluginName: 'removeOnSpill'
- });
- var lastSwapEl;
- function SwapPlugin() {
- function Swap() {
- this.options = {
- swapClass: 'sortable-swap-highlight'
- };
- }
- Swap.prototype = {
- dragStart: function dragStart(_ref) {
- var dragEl = _ref.dragEl;
- lastSwapEl = dragEl;
- },
- dragOverValid: function dragOverValid(_ref2) {
- var completed = _ref2.completed,
- target = _ref2.target,
- onMove = _ref2.onMove,
- activeSortable = _ref2.activeSortable,
- changed = _ref2.changed;
- if (!activeSortable.options.swap) return;
- var el = this.sortable.el,
- options = this.sortable.options;
- if (target && target !== el) {
- var prevSwapEl = lastSwapEl;
- if (onMove(target) !== false) {
- toggleClass(target, options.swapClass, true);
- lastSwapEl = target;
- } else {
- lastSwapEl = null;
- }
- if (prevSwapEl && prevSwapEl !== lastSwapEl) {
- toggleClass(prevSwapEl, options.swapClass, false);
- }
- }
- changed();
- return completed(true);
- },
- drop: function drop(_ref3) {
- var activeSortable = _ref3.activeSortable,
- putSortable = _ref3.putSortable,
- dragEl = _ref3.dragEl;
- var toSortable = putSortable || this.sortable;
- var options = this.sortable.options;
- lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
- if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
- if (dragEl !== lastSwapEl) {
- toSortable.captureAnimationState();
- if (toSortable !== activeSortable) activeSortable.captureAnimationState();
- swapNodes(dragEl, lastSwapEl);
- toSortable.animateAll();
- if (toSortable !== activeSortable) activeSortable.animateAll();
- }
- }
- },
- nulling: function nulling() {
- lastSwapEl = null;
- }
- };
- return _extends(Swap, {
- pluginName: 'swap',
- eventOptions: function eventOptions() {
- return {
- swapItem: lastSwapEl
- };
- }
- });
- }
- function swapNodes(n1, n2) {
- var p1 = n1.parentNode,
- p2 = n2.parentNode,
- i1,
- i2;
- if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
- i1 = index(n1);
- i2 = index(n2);
- if (p1.isEqualNode(p2) && i1 < i2) {
- i2++;
- }
- p1.insertBefore(n2, p1.children[i1]);
- p2.insertBefore(n1, p2.children[i2]);
- }
- var multiDragElements = [],
- multiDragClones = [],
- lastMultiDragSelect,
- // for selection with modifier key down (SHIFT)
- multiDragSortable,
- initialFolding = false,
- // Initial multi-drag fold when drag started
- folding = false,
- // Folding any other time
- dragStarted = false,
- dragEl$1,
- clonesFromRect,
- clonesHidden;
- function MultiDragPlugin() {
- function MultiDrag(sortable) {
- // Bind all private methods
- for (var fn in this) {
- if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
- this[fn] = this[fn].bind(this);
- }
- }
- if (sortable.options.supportPointer) {
- on(document, 'pointerup', this._deselectMultiDrag);
- } else {
- on(document, 'mouseup', this._deselectMultiDrag);
- on(document, 'touchend', this._deselectMultiDrag);
- }
- on(document, 'keydown', this._checkKeyDown);
- on(document, 'keyup', this._checkKeyUp);
- this.options = {
- selectedClass: 'sortable-selected',
- multiDragKey: null,
- setData: function setData(dataTransfer, dragEl) {
- var data = '';
- if (multiDragElements.length && multiDragSortable === sortable) {
- multiDragElements.forEach(function (multiDragElement, i) {
- data += (!i ? '' : ', ') + multiDragElement.textContent;
- });
- } else {
- data = dragEl.textContent;
- }
- dataTransfer.setData('Text', data);
- }
- };
- }
- MultiDrag.prototype = {
- multiDragKeyDown: false,
- isMultiDrag: false,
- delayStartGlobal: function delayStartGlobal(_ref) {
- var dragged = _ref.dragEl;
- dragEl$1 = dragged;
- },
- delayEnded: function delayEnded() {
- this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
- },
- setupClone: function setupClone(_ref2) {
- var sortable = _ref2.sortable;
- if (!this.isMultiDrag) return;
- for (var _i = 0; _i < multiDragElements.length; _i++) {
- multiDragClones.push(clone(multiDragElements[_i]));
- multiDragClones[_i].sortableIndex = multiDragElements[_i].sortableIndex;
- multiDragClones[_i].draggable = false;
- multiDragClones[_i].style['will-change'] = '';
- toggleClass(multiDragClones[_i], sortable.options.selectedClass, false);
- multiDragElements[_i] === dragEl$1 && toggleClass(multiDragClones[_i], sortable.options.chosenClass, false);
- }
- sortable._hideClone();
- return true;
- },
- clone: function clone(_ref3) {
- var sortable = _ref3.sortable,
- rootEl = _ref3.rootEl,
- dispatchSortableEvent = _ref3.dispatchSortableEvent;
- if (!this.isMultiDrag) return;
- if (!sortable.options.removeCloneOnHide) {
- if (multiDragElements.length && multiDragSortable === sortable) {
- insertMultiDragClones(true, rootEl);
- dispatchSortableEvent('clone');
- return true;
- }
- }
- },
- showClone: function showClone(_ref4) {
- var cloneNowShown = _ref4.cloneNowShown,
- rootEl = _ref4.rootEl;
- if (!this.isMultiDrag) return;
- insertMultiDragClones(false, rootEl);
- multiDragClones.forEach(function (clone) {
- css(clone, 'display', '');
- });
- cloneNowShown();
- clonesHidden = false;
- return true;
- },
- hideClone: function hideClone(_ref5) {
- var sortable = _ref5.sortable,
- cloneNowHidden = _ref5.cloneNowHidden;
- if (!this.isMultiDrag) return;
- multiDragClones.forEach(function (clone) {
- css(clone, 'display', 'none');
- if (sortable.options.removeCloneOnHide && clone.parentNode) {
- clone.parentNode.removeChild(clone);
- }
- });
- cloneNowHidden();
- clonesHidden = true;
- return true;
- },
- dragStartGlobal: function dragStartGlobal(_ref6) {
- var sortable = _ref6.sortable;
- if (!this.isMultiDrag && multiDragSortable) {
- multiDragSortable.multiDrag._deselectMultiDrag();
- }
- multiDragElements.forEach(function (multiDragElement) {
- multiDragElement.sortableIndex = index(multiDragElement);
- }); // Sort multi-drag elements
- multiDragElements = multiDragElements.sort(function (a, b) {
- return a.sortableIndex - b.sortableIndex;
- });
- dragStarted = true;
- },
- dragStarted: function dragStarted(_ref7) {
- var sortable = _ref7.sortable;
- if (!this.isMultiDrag) return;
- if (sortable.options.sort) {
- // Capture rects,
- // hide multi drag elements (by positioning them absolute),
- // set multi drag elements rects to dragRect,
- // show multi drag elements,
- // animate to rects,
- // unset rects & remove from DOM
- sortable.captureAnimationState();
- if (sortable.options.animation) {
- multiDragElements.forEach(function (multiDragElement) {
- if (multiDragElement === dragEl$1) return;
- css(multiDragElement, 'position', 'absolute');
- });
- var dragRect = getRect(dragEl$1, false, true, true);
- multiDragElements.forEach(function (multiDragElement) {
- if (multiDragElement === dragEl$1) return;
- setRect(multiDragElement, dragRect);
- });
- folding = true;
- initialFolding = true;
- }
- }
- sortable.animateAll(function () {
- folding = false;
- initialFolding = false;
- if (sortable.options.animation) {
- multiDragElements.forEach(function (multiDragElement) {
- unsetRect(multiDragElement);
- });
- } // Remove all auxiliary multidrag items from el, if sorting enabled
- if (sortable.options.sort) {
- removeMultiDragElements();
- }
- });
- },
- dragOver: function dragOver(_ref8) {
- var target = _ref8.target,
- completed = _ref8.completed;
- if (folding && ~multiDragElements.indexOf(target)) {
- return completed(false);
- }
- },
- revert: function revert(_ref9) {
- var fromSortable = _ref9.fromSortable,
- rootEl = _ref9.rootEl,
- sortable = _ref9.sortable,
- dragRect = _ref9.dragRect;
- if (multiDragElements.length > 1) {
- // Setup unfold animation
- multiDragElements.forEach(function (multiDragElement) {
- sortable.addAnimationState({
- target: multiDragElement,
- rect: folding ? getRect(multiDragElement) : dragRect
- });
- unsetRect(multiDragElement);
- multiDragElement.fromRect = dragRect;
- fromSortable.removeAnimationState(multiDragElement);
- });
- folding = false;
- insertMultiDragElements(!sortable.options.removeCloneOnHide, rootEl);
- }
- },
- dragOverCompleted: function dragOverCompleted(_ref10) {
- var sortable = _ref10.sortable,
- isOwner = _ref10.isOwner,
- insertion = _ref10.insertion,
- activeSortable = _ref10.activeSortable,
- parentEl = _ref10.parentEl,
- putSortable = _ref10.putSortable;
- var options = sortable.options;
- if (insertion) {
- // Clones must be hidden before folding animation to capture dragRectAbsolute properly
- if (isOwner) {
- activeSortable._hideClone();
- }
- initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location
- if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
- // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
- var dragRectAbsolute = getRect(dragEl$1, false, true, true);
- multiDragElements.forEach(function (multiDragElement) {
- if (multiDragElement === dragEl$1) return;
- setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
- // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
- parentEl.appendChild(multiDragElement);
- });
- folding = true;
- } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
- if (!isOwner) {
- // Only remove if not folding (folding will remove them anyways)
- if (!folding) {
- removeMultiDragElements();
- }
- if (multiDragElements.length > 1) {
- var clonesHiddenBefore = clonesHidden;
- activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden
- if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
- multiDragClones.forEach(function (clone) {
- activeSortable.addAnimationState({
- target: clone,
- rect: clonesFromRect
- });
- clone.fromRect = clonesFromRect;
- clone.thisAnimationDuration = null;
- });
- }
- } else {
- activeSortable._showClone(sortable);
- }
- }
- }
- },
- dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
- var dragRect = _ref11.dragRect,
- isOwner = _ref11.isOwner,
- activeSortable = _ref11.activeSortable;
- multiDragElements.forEach(function (multiDragElement) {
- multiDragElement.thisAnimationDuration = null;
- });
- if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
- clonesFromRect = _extends({}, dragRect);
- var dragMatrix = matrix(dragEl$1, true);
- clonesFromRect.top -= dragMatrix.f;
- clonesFromRect.left -= dragMatrix.e;
- }
- },
- dragOverAnimationComplete: function dragOverAnimationComplete() {
- if (folding) {
- folding = false;
- removeMultiDragElements();
- }
- },
- drop: function drop(_ref12) {
- var evt = _ref12.originalEvent,
- rootEl = _ref12.rootEl,
- parentEl = _ref12.parentEl,
- sortable = _ref12.sortable,
- dispatchSortableEvent = _ref12.dispatchSortableEvent,
- oldIndex = _ref12.oldIndex,
- putSortable = _ref12.putSortable;
- var toSortable = putSortable || this.sortable;
- if (!evt) return;
- var options = sortable.options,
- children = parentEl.children; // Multi-drag selection
- if (!dragStarted) {
- if (options.multiDragKey && !this.multiDragKeyDown) {
- this._deselectMultiDrag();
- }
- toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
- if (!~multiDragElements.indexOf(dragEl$1)) {
- multiDragElements.push(dragEl$1);
- dispatchEvent({
- sortable: sortable,
- rootEl: rootEl,
- name: 'select',
- targetEl: dragEl$1,
- originalEvt: evt
- }); // Modifier activated, select from last to dragEl
- if ((!options.multiDragKey || this.multiDragKeyDown) && evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
- var lastIndex = index(lastMultiDragSelect),
- currentIndex = index(dragEl$1);
- if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
- // Must include lastMultiDragSelect (select it), in case modified selection from no selection
- // (but previous selection existed)
- var n, _i2;
- if (currentIndex > lastIndex) {
- _i2 = lastIndex;
- n = currentIndex;
- } else {
- _i2 = currentIndex;
- n = lastIndex + 1;
- }
- for (; _i2 < n; _i2++) {
- if (~multiDragElements.indexOf(children[_i2])) continue;
- toggleClass(children[_i2], options.selectedClass, true);
- multiDragElements.push(children[_i2]);
- dispatchEvent({
- sortable: sortable,
- rootEl: rootEl,
- name: 'select',
- targetEl: children[_i2],
- originalEvt: evt
- });
- }
- }
- } else {
- lastMultiDragSelect = dragEl$1;
- }
- multiDragSortable = toSortable;
- } else {
- multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
- lastMultiDragSelect = null;
- dispatchEvent({
- sortable: sortable,
- rootEl: rootEl,
- name: 'deselect',
- targetEl: dragEl$1,
- originalEvt: evt
- });
- }
- } // Multi-drag drop
- if (dragStarted && this.isMultiDrag) {
- // Do not "unfold" after around dragEl if reverted
- if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
- var dragRect = getRect(dragEl$1),
- multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
- if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
- toSortable.captureAnimationState();
- if (!initialFolding) {
- if (options.animation) {
- dragEl$1.fromRect = dragRect;
- multiDragElements.forEach(function (multiDragElement) {
- multiDragElement.thisAnimationDuration = null;
- if (multiDragElement !== dragEl$1) {
- var rect = folding ? getRect(multiDragElement) : dragRect;
- multiDragElement.fromRect = rect; // Prepare unfold animation
- toSortable.addAnimationState({
- target: multiDragElement,
- rect: rect
- });
- }
- });
- } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
- // properly they must all be removed
- removeMultiDragElements();
- multiDragElements.forEach(function (multiDragElement) {
- if (children[multiDragIndex]) {
- parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
- } else {
- parentEl.appendChild(multiDragElement);
- }
- multiDragIndex++;
- }); // If initial folding is done, the elements may have changed position because they are now
- // unfolding around dragEl, even though dragEl may not have his index changed, so update event
- // must be fired here as Sortable will not.
- if (oldIndex === index(dragEl$1)) {
- var update = false;
- multiDragElements.forEach(function (multiDragElement) {
- if (multiDragElement.sortableIndex !== index(multiDragElement)) {
- update = true;
- return;
- }
- });
- if (update) {
- dispatchSortableEvent('update');
- }
- }
- } // Must be done after capturing individual rects (scroll bar)
- multiDragElements.forEach(function (multiDragElement) {
- unsetRect(multiDragElement);
- });
- toSortable.animateAll();
- }
- multiDragSortable = toSortable;
- } // Remove clones if necessary
- if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
- multiDragClones.forEach(function (clone) {
- clone.parentNode && clone.parentNode.removeChild(clone);
- });
- }
- },
- nullingGlobal: function nullingGlobal() {
- this.isMultiDrag = dragStarted = false;
- multiDragClones.length = 0;
- },
- destroy: function destroy() {
- this._deselectMultiDrag();
- off(document, 'pointerup', this._deselectMultiDrag);
- off(document, 'mouseup', this._deselectMultiDrag);
- off(document, 'touchend', this._deselectMultiDrag);
- off(document, 'keydown', this._checkKeyDown);
- off(document, 'keyup', this._checkKeyUp);
- },
- _deselectMultiDrag: function _deselectMultiDrag(evt) {
- if (dragStarted) return; // Only deselect if selection is in this sortable
- if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable
- if (evt && closest(evt.target, this.sortable.options.draggable, this.sortable.el, false)) return; // Only deselect if left click
- if (evt && evt.button !== 0) return;
- while (multiDragElements.length) {
- var el = multiDragElements[0];
- toggleClass(el, this.sortable.options.selectedClass, false);
- multiDragElements.shift();
- dispatchEvent({
- sortable: this.sortable,
- rootEl: this.sortable.el,
- name: 'deselect',
- targetEl: el,
- originalEvt: evt
- });
- }
- },
- _checkKeyDown: function _checkKeyDown(evt) {
- if (evt.key === this.sortable.options.multiDragKey) {
- this.multiDragKeyDown = true;
- }
- },
- _checkKeyUp: function _checkKeyUp(evt) {
- if (evt.key === this.sortable.options.multiDragKey) {
- this.multiDragKeyDown = false;
- }
- }
- };
- return _extends(MultiDrag, {
- // Static methods & properties
- pluginName: 'multiDrag',
- utils: {
- /**
- * Selects the provided multi-drag item
- * @param {HTMLElement} el The element to be selected
- */
- select: function select(el) {
- var sortable = el.parentNode[expando];
- if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
- if (multiDragSortable && multiDragSortable !== sortable) {
- multiDragSortable.multiDrag._deselectMultiDrag();
- multiDragSortable = sortable;
- }
- toggleClass(el, sortable.options.selectedClass, true);
- multiDragElements.push(el);
- },
- /**
- * Deselects the provided multi-drag item
- * @param {HTMLElement} el The element to be deselected
- */
- deselect: function deselect(el) {
- var sortable = el.parentNode[expando],
- index = multiDragElements.indexOf(el);
- if (!sortable || !sortable.options.multiDrag || !~index) return;
- toggleClass(el, sortable.options.selectedClass, false);
- multiDragElements.splice(index, 1);
- }
- },
- eventOptions: function eventOptions() {
- var _this = this;
- var oldIndicies = [],
- newIndicies = [];
- multiDragElements.forEach(function (multiDragElement) {
- oldIndicies.push({
- multiDragElement: multiDragElement,
- index: multiDragElement.sortableIndex
- }); // multiDragElements will already be sorted if folding
- var newIndex;
- if (folding && multiDragElement !== dragEl$1) {
- newIndex = -1;
- } else if (folding) {
- newIndex = index(multiDragElement, ':not(.' + _this.options.selectedClass + ')');
- } else {
- newIndex = index(multiDragElement);
- }
- newIndicies.push({
- multiDragElement: multiDragElement,
- index: newIndex
- });
- });
- return {
- items: _toConsumableArray(multiDragElements),
- clones: [].concat(multiDragClones),
- oldIndicies: oldIndicies,
- newIndicies: newIndicies
- };
- },
- optionListeners: {
- multiDragKey: function multiDragKey(key) {
- key = key.toLowerCase();
- if (key === 'ctrl') {
- key = 'Control';
- } else if (key.length > 1) {
- key = key.charAt(0).toUpperCase() + key.substr(1);
- }
- return key;
- }
- }
- });
- }
- function insertMultiDragElements(clonesInserted, rootEl) {
- multiDragElements.forEach(function (multiDragElement) {
- var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
- if (target) {
- rootEl.insertBefore(multiDragElement, target);
- } else {
- rootEl.appendChild(multiDragElement);
- }
- });
- }
- /**
- * Insert multi-drag clones
- * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted
- * @param {HTMLElement} rootEl
- */
- function insertMultiDragClones(elementsInserted, rootEl) {
- multiDragClones.forEach(function (clone) {
- var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
- if (target) {
- rootEl.insertBefore(clone, target);
- } else {
- rootEl.appendChild(clone);
- }
- });
- }
- function removeMultiDragElements() {
- multiDragElements.forEach(function (multiDragElement) {
- if (multiDragElement === dragEl$1) return;
- multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
- });
- }
- Sortable.mount(new AutoScrollPlugin());
- Sortable.mount(Remove, Revert);
- Sortable.mount(new SwapPlugin());
- Sortable.mount(new MultiDragPlugin());
- return Sortable;
- }));
- /******************************************************************************/
- (function(window, $) {
- var fave = function(window, $) {
- // Private
- var FormDataWasChanged = false;
- function IsDebugMode() {
- return window.fave_debug && window.fave_debug === true;
- };
- function GetModalAlertTmpl(title, message, error) {
- return '<div class="alert alert-' + (!error?'success':'danger') + ' alert-dismissible fade show" role="alert"><strong>' + title + '</strong> ' + message + '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button></div>';
- };
- function ShowSystemMsg(title, message, error) {
- var modal_alert_place = $('.modal.show .sys-messages');
- if(!modal_alert_place.length) {
- modal_alert_place = $('form.alert-here .sys-messages');
- }
- if(modal_alert_place.length) {
- modal_alert_place.html(GetModalAlertTmpl(title, message, error));
- } else {
- ShowSystemMsgModal(title, message, error);
- }
- };
- function ShowSystemMsgModal(title, message, error) {
- $('#sys-modal-system-message-placeholder').html('');
- var html = '<div class="modal fade" id="sys-modal-system-message" tabindex="-1" role="dialog" aria-labelledby="sysModalSystemMessageLabel" aria-hidden="true"> \
- <div class="modal-dialog modal-dialog-centered" role="document"> \
- <div class="modal-content"> \
- <div class="modal-header"> \
- <h5 class="modal-title" id="sysModalSystemMessageLabel">' + title + '</h5> \
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"> \
- <span aria-hidden="true">×</span> \
- </button> \
- </div> \
- <div class="modal-body text-left">' + message + '</div> \
- <div class="modal-footer"> \
- <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> \
- </div> \
- </div> \
- </div> \
- </div>';
- $('#sys-modal-system-message-placeholder').html(html);
- $('#sys-modal-system-message').modal({
- backdrop: 'static',
- keyboard: true,
- show: false,
- });
- $('#sys-modal-system-message').on('hidden.bs.modal', function(e) {
- $('#sys-modal-system-message-placeholder').html('');
- });
- $('#sys-modal-system-message').modal('show');
- };
- function AjaxEval(data) {
- try {
- eval(data);
- } catch(e) {
- if(e instanceof SyntaxError) {
- console.log(data);
- console.log('Error: JavaScript code eval error', e.message);
- }
- }
- };
- function AjaxDone(data) {
- AjaxEval(data);
- };
- function AjaxFail(data, status, error) {
- if(status.toLowerCase() === "error" && error.toLowerCase() === "not found") {
- AjaxEval(data);
- } else {
- console.log('Error: data sending error, page will be reloaded', data, status, error);
- setTimeout(function() {
- window.location.reload(false);
- }, 1000);
- }
- };
- function FormToAjax(form) {
- form.submit(function(e) {
- if(form.hasClass('loading')) {
- e.preventDefault();
- return;
- }
- // Block send button
- form.addClass('loading').addClass('alert-here');
- var button = form.find('button[type=submit]');
- button.addClass('progress-bar-striped')
- .addClass('progress-bar-animated');
- // Another button
- if(button.attr('data-target') != '') {
- $('#' + button.attr('data-target')).addClass('progress-bar-striped')
- .addClass('progress-bar-animated');
- }
- // Clear form messages
- form.find('.sys-messages').html('');
- $.ajax({
- type: "POST",
- url: form.attr('action'),
- data: form.serialize()
- }).done(function(data) {
- FormDataWasChanged = false;
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- }).always(function() {
- // Add delay for one second
- setTimeout(function() {
- form.removeClass('loading').removeClass('alert-here');
- button.removeClass('progress-bar-striped')
- .removeClass('progress-bar-animated');
- // Another button
- if(button.attr('data-target') != '') {
- $('#' + button.attr('data-target'))
- .removeClass('progress-bar-striped')
- .removeClass('progress-bar-animated');
- }
- }, 100);
- });
- // Prevent submit action
- e.preventDefault();
- });
- // Bind to another button
- var button = form.find('button[type=submit]');
- if(button.attr('data-target') != '') {
- $('#' + button.attr('data-target')).click(function() {
- button.click();
- });
- }
- // Mark body if any data in form was changed
- if(form.hasClass('prev-data-lost')) {
- form.find('input, textarea, select').on('input', function() {
- if(!FormDataWasChanged) {
- if(!$(this).hasClass('ignore-lost-data')) {
- FormDataWasChanged = true;
- }
- }
- });
- }
- };
- function PreventDataLost() {
- if(!FormDataWasChanged) {
- FormDataWasChanged = true;
- }
- };
- function FormDataIsChanged() {
- return FormDataWasChanged;
- }
- function HtmlDecode(value) {
- var doc = new DOMParser().parseFromString(value, "text/html");
- return doc.documentElement.textContent;
- };
- function HtmlFixEditorHtml(value) {
- newValue = value;
- newValue = newValue.replace(/ /gi, '');
- return newValue;
- };
- function AllFormsToAjax() {
- $('form').each(function() {
- FormToAjax($(this));
- });
- };
- function BindWindowBeforeUnload() {
- // Prevent page reload if data was changed
- $(window).bind('beforeunload', function(){
- if(FormDataWasChanged) {
- return 'Some data was changed and not saved. Are you sure want to leave page?';
- }
- });
- };
- function MakeTextAreasAutoSized() {
- autosize($('textarea.autosize'));
- };
- function MakeTextAreasWysiwyg() {
- $('textarea.wysiwyg').each(function() {
- var area = $(this)[0];
- var area_id = area.id;
- var area_name = area.name;
- var area_html = area.innerHTML;
- // Wrap editro by additional DIV and remove target textarea
- $(area).wrap('<div id="' + area_id + '_wysiwyg" class="form-control wysiwyg" style="height:auto;padding:0px"></div>').remove();
- var wysiwyg = document.getElementById(area_id + '_wysiwyg');
- wysiwyg.id = area_id;
- // Create and init editor
- var editor = window.pell.init({
- element: wysiwyg,
- onChange: function(html) {
- area.innerHTML = HtmlFixEditorHtml(html);
- $(area).val(HtmlFixEditorHtml(html));
- if(!FormDataWasChanged) {
- FormDataWasChanged = true;
- }
- },
- defaultParagraphSeparator: 'p',
- styleWithCSS: false,
- actions: [
- 'paragraph',
- 'heading1',
- 'heading2',
- 'bold',
- 'italic',
- 'underline',
- 'strikethrough',
- 'ulist',
- 'olist',
- 'link',
- {
- name: 'htmlcode',
- icon: 'HTML',
- title: 'HTML Source',
- result: function(edt, ctn, btn) {
- var jedt = $(edt);
- var jctn = $(ctn);
- var jbtn = $(btn);
- if(!jbtn.hasClass('pell-button-html-pressed')) {
- jbtn.addClass('pell-button-html-pressed');
- jedt.addClass('pell-html-mode');
- jedt.find('.pell-actionbar .pell-button').prop('disabled', true);
- jbtn.prop('disabled', false);
- setTimeout(function() {
- jedt.find('textarea.form-control').focus();
- }, 0);
- } else {
- jbtn.removeClass('pell-button-html-pressed');
- jedt.removeClass('pell-html-mode');
- jedt.find('.pell-actionbar .pell-button').prop('disabled', false);
- var srcValue = jedt.find('textarea.form-control').val();
- ctn.innerHTML = HtmlFixEditorHtml(srcValue);
- $(ctn).val(HtmlFixEditorHtml(srcValue));
- setTimeout(function() {
- jctn.focus();
- }, 0);
- }
- },
- },
- ],
- classes: {
- actionbar: 'pell-actionbar',
- button: 'pell-button',
- content: 'pell-content',
- selected: 'pell-button-selected'
- }
- });
- editor.onfocusin = function() {
- $(wysiwyg).addClass('focused');
- };
- editor.onfocusout = function() {
- $(wysiwyg).find('.pell-actionbar button.pell-button-selected').removeClass('pell-button-selected');
- $(wysiwyg).removeClass('focused');
- };
- // Re-add textarea
- $(wysiwyg).append('<textarea class="form-control" id="' + area_id + '_wysiwyg' + '" name="' + area_name + '" style="display:none"></textarea>');
- area = document.getElementById(area_id + '_wysiwyg');
- // Prevent data lost if HTML was changed
- $(area).on('input', function() {
- if(!FormDataWasChanged) {
- FormDataWasChanged = true;
- }
- });
- // Copy HTML to textarea and editor
- area.innerHTML = HtmlFixEditorHtml(HtmlDecode(area_html));
- $(area).val(HtmlFixEditorHtml(HtmlDecode(area_html)));
- editor.content.innerHTML = HtmlFixEditorHtml(HtmlDecode(area_html));
- });
- };
- function MakeTextAreasTmplEditor() {
- var IgnoreDataLost = true;
- $('textarea.tmpl-editor').each(function() {
- var targetTextArea = $(this)[0];
- var targetFileExt = $(this).data('emode');
- var targetEditorMode = 'text/html';
- if(targetFileExt == 'js') {
- targetEditorMode = 'javascript';
- } else if(targetFileExt == 'css') {
- targetEditorMode = 'css';
- }
- CodeMirror.fromTextArea(targetTextArea, {
- lineNumbers: true,
- lineWrapping: true,
- viewportMargin: Infinity,
- mode: targetEditorMode,
- }).on('change', function(editor){
- targetTextArea.value = editor.getValue();
- if(!IgnoreDataLost) {
- if(!FormDataWasChanged) {
- FormDataWasChanged = true;
- }
- }
- });
- });
- IgnoreDataLost = false;
- };
- function MakeTextAreasNotReactOnTab() {
- $('textarea.use-tab-key').each(function() {
- $(this).keydown(function(e) {
- if(e.keyCode === 9) {
- var start = this.selectionStart;
- var end = this.selectionEnd;
- var $this = $(this);
- var value = $this.val();
- $this.val(value.substring(0, start) + "\t" + value.substring(end));
- this.selectionStart = this.selectionEnd = start + 1;
- e.preventDefault();
- if(!FormDataWasChanged) {
- FormDataWasChanged = true;
- }
- }
- });
- });
- };
- function Initialize() {
- // Check if jQuery was loaded
- if(typeof $ == 'function') {
- AllFormsToAjax();
- BindWindowBeforeUnload();
- MakeTextAreasAutoSized();
- MakeTextAreasWysiwyg();
- MakeTextAreasTmplEditor();
- MakeTextAreasNotReactOnTab();
- } else {
- console.log('Error: jQuery is not loaded!');
- }
- };
- // Initialize
- if(window.addEventListener) {
- // W3C standard
- window.addEventListener('load', Initialize, false);
- } else if(window.attachEvent) {
- // Microsoft
- window.attachEvent('onload', Initialize);
- };
- // Public
- return {
- ShowMsgSuccess: function(title, message) {
- ShowSystemMsg(title, message, false);
- },
- ShowMsgError: function(title, message) {
- ShowSystemMsg(title, message, true);
- },
- FormDataWasChanged: function() {
- PreventDataLost();
- },
- ModalUserProfile: function() {
- var html = '<div class="modal fade" id="sys-modal-user-settings" tabindex="-1" role="dialog" aria-labelledby="sysModalUserSettingsLabel" aria-hidden="true"> \
- <div class="modal-dialog modal-dialog-centered" role="document"> \
- <div class="modal-content"> \
- <form class="form-user-settings" action="/cp/" method="post" autocomplete="off"> \
- <input type="hidden" name="action" value="index-user-update-profile"> \
- <div class="modal-header"> \
- <h5 class="modal-title" id="sysModalUserSettingsLabel">My profile</h5> \
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"> \
- <span aria-hidden="true">×</span> \
- </button> \
- </div> \
- <div class="modal-body text-left"> \
- <div class="form-group"> \
- <label for="first_name">First name</label> \
- <input type="text" class="form-control" id="first_name" name="first_name" value="' + window.CurrentUserProfileData.first_name + '" placeholder="User first name" autocomplete="off"> \
- </div> \
- <div class="form-group"> \
- <label for="last_name">Last name</label> \
- <input type="text" class="form-control" id="last_name" name="last_name" value="' + window.CurrentUserProfileData.last_name + '" placeholder="User last name" autocomplete="off"> \
- </div> \
- <div class="form-group"> \
- <label for="email">Email</label> \
- <input type="email" class="form-control" id="email" name="email" value="' + window.CurrentUserProfileData.email + '" placeholder="User email" autocomplete="off" required> \
- </div> \
- <div class="form-group"> \
- <label for="password">New password</label> \
- <input type="password" class="form-control" id="password" aria-describedby="passwordHelp" name="password" value="" placeholder="User new password" autocomplete="off"> \
- <small id="passwordHelp" class="form-text text-muted">Leave this field empty if you don\'t want change your password</small> \
- </div> \
- <div class="sys-messages"></div> \
- </div> \
- <div class="modal-footer"> \
- <button type="submit" class="btn btn-primary">Save</button> \
- <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> \
- </div> \
- </form> \
- </div> \
- </div> \
- </div>';
- $('#sys-modal-user-settings-placeholder').html(html);
- $("#sys-modal-user-settings").modal({
- backdrop: 'static',
- keyboard: false,
- show: false,
- });
- $('#sys-modal-user-settings').on('hidden.bs.modal', function(e) {
- $('#sys-modal-user-settings-placeholder').html('');
- });
- FormToAjax($('#sys-modal-user-settings form'));
- $("#sys-modal-user-settings").modal('show');
- },
- ShopProductsAdd: function() {
- var selText = $('#lbl_attributes option:selected').text();
- var selValue = $('#lbl_attributes').val();
- if(selValue == '0') { return; }
- $('#lbl_attributes')[0].selectedIndex = 0;
- $('#lbl_attributes').selectpicker('refresh');
- if($('#prod_attr_' + selValue).length > 0) { return; }
- $('#list').append('<div class="form-group" id="prod_attr_' + selValue + '"><div><b>' + selText + '</b></div><div class="position-relative"><select class="form-control" name="value.' + selValue + '" autocomplete="off" required disabled><option value="0">Loading values...</option></select><button type="button" class="btn btn-danger btn-dynamic-remove" onclick="fave.ShopProductsRemove(this);" disabled>×</button></div></div>');
- PreventDataLost();
- $.ajax({
- type: 'POST',
- url: '/cp/',
- data: {
- action: 'shop-get-attribute-values',
- id: selValue
- }
- }).done(function(data) {
- try {
- eval(data);
- } catch(e) {
- if(e instanceof SyntaxError) {
- console.log(data);
- console.log('Error: JavaScript code eval error', e.message);
- }
- }
- }).fail(function(xhr, status, error) {
- $('#prod_attr_' + selValue).remove();
- try {
- eval(xhr.responseText);
- } catch(e) {
- if(e instanceof SyntaxError) {
- console.log(xhr.responseText);
- console.log('Error: JavaScript code eval error', e.message);
- }
- }
- });
- },
- ShopProductsRemove: function(button) {
- $(button).parent().parent().remove();
- PreventDataLost();
- },
- ShopAttributesAdd: function() {
- $('#list').append('<div class="form-group position-relative"><input class="form-control" type="text" name="value.0" value="" placeholder="" autocomplete="off" required><button type="button" class="btn btn-danger btn-dynamic-remove" onclick="fave.ShopAttributesRemove(this);">×</button></div>');
- PreventDataLost();
- setTimeout(function() {
- $('#list input').last().focus();
- }, 100);
- },
- ShopAttributesRemove: function(button) {
- $(button).parent().remove();
- PreventDataLost();
- },
- ShopProductsUploadImage: function(action_name, product_id, input_id) {
- var file_el = $('#' + input_id)[0];
- if(!file_el.files) return;
- if(file_el.files.length <= 0) return;
- $('#img-upload-block input').prop('disabled', true);
- $('#upload-msg').css('display', 'block');
- var fd = new FormData();
- fd.append('action', action_name);
- fd.append('id', product_id);
- fd.append('count', file_el.files.length);
- for(var i = 0; i < file_el.files.length; i++) {
- fd.append('file_' + i, file_el.files[i]);
- }
- $.ajax({
- url: '/cp/',
- method: 'POST',
- type: 'POST',
- data: fd,
- contentType: false,
- processData: false
- }).done(function(data) {
- try {
- eval(data);
- } catch(e) {
- if(e instanceof SyntaxError) {
- console.log(data);
- console.log('Error: JavaScript code eval error', e.message);
- }
- }
- }).fail(function(xhr, status, error) {
- try {
- eval(xhr.responseText);
- } catch(e) {
- if(e instanceof SyntaxError) {
- console.log(xhr.responseText);
- console.log('Error: JavaScript code eval error', e.message);
- }
- }
- }).always(function() {
- file_el.value = '';
- $('#img-upload-block input').prop('disabled', false);
- $('#upload-msg').css('display', 'none');
- });
- },
- ShopProductsDeleteImage: function(button, product_id, filename) {
- if($(button).hasClass('in-progress')) return;
- $(button).addClass('in-progress');
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'shop-upload-delete',
- id: product_id,
- file: filename,
- }
- }).done(function(data) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- });
- },
- ShopProductsDuplicateBase: function(button, product_id, attach) {
- if($(button).hasClass('in-progress')) return;
- if(FormDataIsChanged()) {
- fave.ShowMsgError('Warning!', 'Something was changed, save changes before duplicate product', true);
- return;
- }
- $(button).addClass('in-progress');
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'shop-duplicate',
- id: product_id,
- attach: attach,
- }
- }).done(function(data) {
- try {
- eval(data);
- } catch(e) {
- if(e instanceof SyntaxError) {
- console.log(data);
- console.log('Error: JavaScript code eval error', e.message);
- }
- }
- }).fail(function(xhr, status, error) {
- try {
- eval(xhr.responseText);
- } catch(e) {
- if(e instanceof SyntaxError) {
- console.log(xhr.responseText);
- console.log('Error: JavaScript code eval error', e.message);
- }
- }
- }).always(function() {
- $(button).removeClass('in-progress');
- });
- },
- ShopProductsDuplicate: function(button, product_id) {
- fave.ShopProductsDuplicateBase(button, product_id, 0);
- },
- ShopProductsDuplicateWithAttach: function(button, product_id) {
- fave.ShopProductsDuplicateBase(button, product_id, 1);
- },
- ShopProductsRetryImage: function(img, id) {
- var target = $('#' + id);
- var src = target.attr('src');
- target.attr('src', '/assets/cp/img-load.gif');
- setTimeout(function() {
- target.attr('src', src);
- }, 1000);
- },
- ActionLogout: function(message) {
- if(confirm(message)) {
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'index-user-logout',
- }
- }).done(function(data) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- });
- }
- },
- ActionDataTableDelete: function(object, action, id, message) {
- if(confirm(message)) {
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: action,
- id: id,
- }
- }).done(function(data) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- });
- }
- },
- ActionRestoreThemeFile: function(action_name, file_name, message) {
- if(confirm(message)) {
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: action_name,
- file: file_name,
- }
- }).done(function(data) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- });
- }
- return false;
- },
- ShopProductsImageReorder: function(action, orderData) {
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: action,
- data: JSON.stringify(orderData),
- },
- }).done(function(data) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- });
- },
- ShopAttachProduct: function(product_id) {
- var html = '<div class="modal fade" id="sys-modal-shop-product-attach" tabindex="-1" role="dialog" aria-labelledby="sysModalShopProductLabel" aria-hidden="true"> \
- <div class="modal-dialog modal-dialog-centered" role="document"> \
- <div class="modal-content"> \
- <div class="modal-header"> \
- <h5 class="modal-title" id="sysModalShopProductLabel">Attach product</h5> \
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"> \
- <span aria-hidden="true">×</span> \
- </button> \
- </div> \
- <div class="modal-body text-left"> \
- <div class="form-group"> \
- <input type="text" class="form-control" name="product-name" value="" placeholder="Type product name here..." readonly autocomplete="off"> \
- </div> \
- <div class="form-group" style="margin-bottom:0px;"> \
- <div class="products-list"></div> \
- </div> \
- </div> \
- <div class="modal-footer"> \
- <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> \
- </div> \
- </div> \
- </div> \
- </div>';
- $('#sys-modal-shop-product-attach-placeholder').html(html);
- $("#sys-modal-shop-product-attach").modal({
- backdrop: 'static',
- keyboard: true,
- show: false,
- });
- $('#sys-modal-shop-product-attach').on('hidden.bs.modal', function(e) {
- $('#sys-modal-shop-product-attach-placeholder').html('');
- });
- $("#sys-modal-shop-product-attach").modal('show');
- setTimeout(function() {
- var SearchInput = $('#sys-modal-shop-product-attach input[name="product-name"]');
- SearchInput.keyup(function() {
- if(true || this.value != '') {
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'shop-attach-product-search',
- words: this.value,
- id: product_id,
- }
- }).done(function(data) {
- if($('#sys-modal-shop-product-attach').length > 0) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }
- }).fail(function(xhr, status, error) {
- if(false) {
- if($('#sys-modal-shop-product-attach').length > 0) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- }
- }
- });
- }
- });
- SearchInput.attr("readonly", false);
- SearchInput.keyup();
- SearchInput.focus();
- }, 500);
- },
- ShopAttachProductTo: function(parent_id, product_id) {
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'shop-attach-product-to',
- parent_id: parent_id,
- product_id: product_id,
- }
- }).done(function(data) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- });
- },
- ShopSetOrderStatus: function(object, id, status, message) {
- if(confirm(message)) {
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'shop-order-set-status',
- id: id,
- status: status,
- }
- }).done(function(data) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }).fail(function(xhr, status, error) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- });
- }
- },
- FilesManagerDialog: function() {
- var html = '<div class="modal fade" id="sys-modal-files-manager" tabindex="-1" role="dialog" aria-labelledby="sysModalFilesManagerLabel" aria-hidden="true"> \
- <div class="modal-dialog modal-dialog-centered" role="document"> \
- <div class="modal-content"> \
- <input type="hidden" name="path" value="/"> \
- <div class="modal-header"> \
- <h5 class="modal-title" id="sysModalFilesManagerLabel">Files manager</h5> \
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"> \
- <span aria-hidden="true">×</span> \
- </button> \
- </div> \
- <div class="modal-body text-left"> \
- <div class="dialog-path alert alert-secondary"><span class="text-dotted">/</span></div> \
- <div class="dialog-data"></div> \
- </div> \
- <div class="modal-footer"> \
- <input class="form-control" type="file" id="fmfiles" name="fmfiles" onchange="fave.FilesManagerUploadFile();" style="font-size:12px;background-color:#28a745;border-color:#28a745;color:#fff;cursor:pointer;" multiple=""> \
- <button type="button" class="btn btn-primary folder" onclick="fave.FilesManagerNewFolderClick();" disabled>New folder</button> \
- <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> \
- </div> \
- </div> \
- </div> \
- </div>';
- $('#sys-modal-files-manager-placeholder').html(html);
- $("#sys-modal-files-manager").modal({
- backdrop: 'static',
- keyboard: true,
- show: false,
- });
- $('#sys-modal-files-manager').on('hidden.bs.modal', function(e) {
- $('#sys-modal-files-manager-placeholder').html('');
- });
- $("#sys-modal-files-manager").modal('show');
- setTimeout(function() {
- fave.FilesManagerLoadData('/');
- }, 500);
- },
- FilesManagerSetPath: function(path) {
- $('#sys-modal-files-manager input[name=path]').val(path);
- $('#sys-modal-files-manager .dialog-path span').html(path);
- },
- FilesManagerGetPath: function() {
- return $('#sys-modal-files-manager input[name=path]').val();
- },
- FilesManagerRemoveFolder: function(filename, msg) {
- if(!confirm(msg)) {
- return;
- }
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'files-remove-folder',
- file: filename,
- }
- }).done(function(data) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }
- }).fail(function(xhr, status, error) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- }
- });
- },
- FilesManagerRemoveFile: function(filename, msg) {
- if(!confirm(msg)) {
- return;
- }
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'files-remove-file',
- file: filename,
- }
- }).done(function(data) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }
- }).fail(function(xhr, status, error) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- }
- });
- },
- FilesManagerLoadData: function(path) {
- fave.FilesManagerEnableDisableButtons(true);
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'files-list',
- path: path,
- }
- }).done(function(data) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }
- }).fail(function(xhr, status, error) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- }
- });
- },
- FilesManagerLoadDataUp: function(path) {
- newPath = path.replace(/\/$/i, '');
- newPath = newPath.replace(/[^\/]+$/i, '');
- fave.FilesManagerLoadData(newPath);
- },
- FilesManagerEnableDisableButtons: function(disabled) {
- $('#sys-modal-files-manager #fmfiles').prop('disabled', disabled);
- $('#sys-modal-files-manager button.folder').prop('disabled', disabled);
- },
- FilesManagerUploadFile: function() {
- var file_el = $('#fmfiles')[0];
- if(!file_el.files) return;
- if(file_el.files.length <= 0) return;
- fave.FilesManagerEnableDisableButtons(true);
- var fd = new FormData();
- fd.append('action', 'files-upload');
- fd.append('count', file_el.files.length);
- fd.append('path', fave.FilesManagerGetPath());
- for(var i = 0; i < file_el.files.length; i++) {
- fd.append('file_' + i, file_el.files[i]);
- }
- $.ajax({
- url: '/cp/',
- method: 'POST',
- type: 'POST',
- data: fd,
- contentType: false,
- processData: false
- }).done(function(data) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }
- }).fail(function(xhr, status, error) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- }
- }).always(function() {
- file_el.value = '';
- fave.FilesManagerEnableDisableButtons(false);
- });
- },
- FilesManagerNewFolderClick: function() {
- var folderName = prompt('Please enter new folder name', '');
- if(folderName != null) {
- path = fave.FilesManagerGetPath();
- $.ajax({
- type: "POST",
- url: '/cp/',
- data: {
- action: 'files-mkdir',
- path: path,
- name: folderName,
- }
- }).done(function(data) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('done', data);
- AjaxDone(data);
- }
- }).fail(function(xhr, status, error) {
- if($('#sys-modal-files-manager').length > 0) {
- if(IsDebugMode()) console.log('fail', xhr, status, error);
- AjaxFail(xhr.responseText, status, error);
- }
- });
- }
- },
- };
- }(window, $);
- // Make it public
- window.fave = fave;
- }(window, jQuery));
|